This commit is contained in:
全栈小学生 2025-04-19 10:40:44 +08:00
parent 8fa97dd4a7
commit 6f941fab4d
190 changed files with 8330 additions and 5510 deletions

View File

@ -14,7 +14,7 @@ export function getAliappConfig() {
* @returns
*/
export function setAliappConfig(params: Record<string, any>) {
return request.put('aliapp/config', params, {showSuccessMessage: true})
return request.put('aliapp/config', params, { showSuccessMessage: true })
}
/**

View File

@ -6,7 +6,7 @@ import request from '@/utils/request'
* @param app_type
*/
export function login(params: Record<string, any>, app_type: string) {
return request.get(`login/${app_type}`, {params})
return request.get(`login/${ app_type }`, { params })
}
/**
@ -21,7 +21,7 @@ export function logout() {
* @returns
*/
export function getAuthMenus(params: Record<string, any>) {
return request.get('auth/authmenu', {params})
return request.get('auth/authmenu', { params })
}
/**

View File

@ -8,7 +8,7 @@ import request from '@/utils/request'
* @returns
*/
export function getDiyPageList(params: Record<string, any>) {
return request.get(`diy/diy`, {params})
return request.get(`diy/diy`, { params })
}
/**
@ -17,7 +17,7 @@ export function getDiyPageList(params: Record<string, any>) {
* @returns
*/
export function getDiyPageListByCarouselSearch(params: Record<string, any>) {
return request.get(`diy/carousel_search`, {params})
return request.get(`diy/carousel_search`, { params })
}
/**
@ -26,7 +26,7 @@ export function getDiyPageListByCarouselSearch(params: Record<string, any>) {
* @returns
*/
export function getDiyList(params: Record<string, any>) {
return request.get(`diy/list`, {params})
return request.get(`diy/list`, { params })
}
/**
@ -35,7 +35,7 @@ export function getDiyList(params: Record<string, any>) {
* @returns
*/
export function getDiyPageInfo(id: number) {
return request.get(`diy/diy/${id}`);
return request.get(`diy/diy/${ id }`);
}
/**
@ -44,7 +44,7 @@ export function getDiyPageInfo(id: number) {
* @returns
*/
export function addDiyPage(params: Record<string, any>) {
return request.post('diy/diy', params, {showSuccessMessage: true})
return request.post('diy/diy', params, { showSuccessMessage: true })
}
/**
@ -52,7 +52,7 @@ export function addDiyPage(params: Record<string, any>) {
* @param params
*/
export function editDiyPage(params: Record<string, any>) {
return request.put(`diy/diy/${params.id}`, params, {showSuccessMessage: true})
return request.put(`diy/diy/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -60,7 +60,7 @@ export function editDiyPage(params: Record<string, any>) {
* @param params
*/
export function setUseDiyPage(params: Record<string, any>) {
return request.put(`diy/use/${params.id}`, params, {showSuccessMessage: true})
return request.put(`diy/use/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -68,7 +68,7 @@ export function setUseDiyPage(params: Record<string, any>) {
* @param params
*/
export function editDiyPageShare(params: Record<string, any>) {
return request.put(`diy/diy/share`, params, {showSuccessMessage: true})
return request.put(`diy/diy/share`, params, { showSuccessMessage: true })
}
/**
@ -77,35 +77,35 @@ export function editDiyPageShare(params: Record<string, any>) {
* @returns
*/
export function deleteDiyPage(id: number) {
return request.delete(`diy/diy/${id}`, {showSuccessMessage: true})
return request.delete(`diy/diy/${ id }`, { showSuccessMessage: true })
}
/**
*
*/
export function initPage(params: Record<string, any>) {
return request.get(`diy/init`, {params})
return request.get(`diy/init`, { params })
}
/**
*
*/
export function getLink(params: Record<string, any>) {
return request.get(`diy/link`, {params})
return request.get(`diy/link`, { params })
}
/**
*
*/
export function getDiyBottomList(params: Record<string, any>) {
return request.get(`diy/bottom`, {params})
return request.get(`diy/bottom`, { params })
}
/**
*
*/
export function getDiyBottomConfig(params: Record<string, any>) {
return request.get(`diy/bottom/config`, {params})
return request.get(`diy/bottom/config`, { params })
}
/**
@ -114,21 +114,21 @@ export function getDiyBottomConfig(params: Record<string, any>) {
* @returns
*/
export function setDiyBottomConfig(params: Record<string, any>) {
return request.post('diy/bottom', params, {showSuccessMessage: true})
return request.post('diy/bottom', params, { showSuccessMessage: true })
}
/**
*
*/
export function getDiyTemplate(params: Record<string, any>) {
return request.get(`diy/template`, {params})
return request.get(`diy/template`, { params })
}
/**
*
*/
export function getDiyTemplatePages(params: Record<string, any>) {
return request.get(`diy/template/pages`, {params})
return request.get(`diy/template/pages`, { params })
}
/**
@ -137,7 +137,7 @@ export function getDiyTemplatePages(params: Record<string, any>) {
* @returns
*/
export function getDiyRouteList(params: Record<string, any>) {
return request.get(`diy/route`, {params})
return request.get(`diy/route`, { params })
}
/**
@ -145,7 +145,7 @@ export function getDiyRouteList(params: Record<string, any>) {
* @returns
*/
export function getDiyRouteAppList() {
return request.get(`diy/route/apps`)
return request.get(`diy/route/apps`)
}
/**
@ -153,7 +153,7 @@ export function getDiyRouteAppList() {
* @param params
*/
export function getDiyRouteInfo(params: Record<string, any>) {
return request.get(`diy/route/info`, {params});
return request.get(`diy/route/info`, { params });
}
/**
@ -161,7 +161,7 @@ export function getDiyRouteInfo(params: Record<string, any>) {
* @param params
*/
export function editDiyRouteShare(params: Record<string, any>) {
return request.put(`diy/route/share`, params, {showSuccessMessage: true})
return request.put(`diy/route/share`, params, { showSuccessMessage: true })
}
/**
@ -170,7 +170,7 @@ export function editDiyRouteShare(params: Record<string, any>) {
* @returns
*/
export function getDecoratePage(params: Record<string, any>) {
return request.get(`diy/decorate`, {params})
return request.get(`diy/decorate`, { params })
}
/**
@ -179,7 +179,7 @@ export function getDecoratePage(params: Record<string, any>) {
* @returns
*/
export function changeTemplate(params: Record<string, any>) {
return request.put(`diy/change`, params, {showSuccessMessage: true})
return request.put(`diy/change`, params, { showSuccessMessage: true })
}
/**
@ -188,7 +188,7 @@ export function changeTemplate(params: Record<string, any>) {
* @returns
*/
export function getApps(params: Record<string, any>) {
return request.get(`diy/apps`)
return request.get(`diy/apps`)
}
/**
@ -207,7 +207,7 @@ export function copyDiy(params: Record<string, any>) {
* @param params
*/
export function getDefaultTheme(params: Record<string, any>) {
return request.get(`diy/theme/color`, {params})
return request.get(`diy/theme/color`, { params })
}
@ -216,7 +216,7 @@ export function getDefaultTheme(params: Record<string, any>) {
* @param params
*/
export function getDiyTheme(params: Record<string, any>) {
return request.get(`diy/theme`, {params})
return request.get(`diy/theme`, { params })
}
/**
@ -232,7 +232,7 @@ export function addTheme(params: Record<string, any>) {
* @param params
*/
export function editTheme(params: Record<string, any>) {
return request.put(`diy/theme/edit/${params.id}`, params, {showSuccessMessage: true})
return request.put(`diy/theme/edit/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -240,13 +240,13 @@ export function editTheme(params: Record<string, any>) {
* @param params
*/
export function deleteTheme(id: number) {
return request.delete(`diy/theme/delete/${id}`, {showSuccessMessage: true})
return request.delete(`diy/theme/delete/${ id }`, { showSuccessMessage: true })
}
/**
*
*
* @param params
*/
export function setDiyTheme(params: Record<string, any>) {
return request.post(`diy/theme`, params, { showSuccessMessage: true })
}
}

View File

@ -19,6 +19,7 @@ export function getDiyFormPageList(params: Record<string, any>) {
export function getDiyFormList(params: Record<string, any>) {
return request.get(`diy/form/list`, { params })
}
/**
*
* @param params

View File

@ -11,7 +11,7 @@ export function getAuthInfo() {
*
*/
export function setAuthInfo(params: Record<string, any>) {
return request.post('niucloud/authinfo', params, {showSuccessMessage: true})
return request.post('niucloud/authinfo', params, { showSuccessMessage: true })
}
/**
@ -43,7 +43,7 @@ export function getModuleVersion() {
* @returns
*/
export function downloadVersion(params: Record<string, any>) {
return request.post(`addon/download/${params.addon}`, params, { showSuccessMessage: true })
return request.post(`addon/download/${ params.addon }`, params, { showSuccessMessage: true })
}
/**
@ -61,3 +61,11 @@ export function getFrameworkNewVersion() {
export function getFrameworkVersionList() {
return request.get(`niucloud/framework/version/list`)
}
/**
* /
* @param params
*/
export function getAppVersionList(params: Record<string, any>) {
return request.get(`niucloud/app_version/list`, { params })
}

View File

@ -7,7 +7,7 @@ import request from '@/utils/request'
* @returns
*/
export function getNoticeList(params: any) {
return request.get('notice/notice', {params})
return request.get('notice/notice', { params })
}
/**
@ -16,7 +16,7 @@ export function getNoticeList(params: any) {
* @returns
*/
export function getNoticeLog(params: any) {
return request.get(`notice/log`, {params})
return request.get(`notice/log`, { params })
}
/**
@ -25,7 +25,7 @@ export function getNoticeLog(params: any) {
* @returns
*/
export function getNoticeInfo(key: string) {
return request.get(`notice/notice/${key}`)
return request.get(`notice/notice/${ key }`)
}
/**
@ -34,7 +34,7 @@ export function getNoticeInfo(key: string) {
* @returns
*/
export function editNoticeStatus(params: Record<string, any>) {
return request.post(`notice/notice/editstatus`, params, {showSuccessMessage: true})
return request.post(`notice/notice/editstatus`, params, { showSuccessMessage: true })
}
/**
@ -43,7 +43,7 @@ export function editNoticeStatus(params: Record<string, any>) {
* @returns
*/
export function editNotice(params: Record<string, any>) {
return request.post(`notice/notice/edit`, params, {showSuccessMessage: true})
return request.post(`notice/notice/edit`, params, { showSuccessMessage: true })
}
/**
@ -60,7 +60,7 @@ export function getSmsList() {
* @returns
*/
export function getSmsInfo(sms_type: string) {
return request.get(`notice/notice/sms/${sms_type}`,)
return request.get(`notice/notice/sms/${ sms_type }`,)
}
/**
@ -68,7 +68,7 @@ export function getSmsInfo(sms_type: string) {
* @param params
*/
export function editSms(params: Record<string, any>) {
return request.put(`notice/notice/sms/${params.sms_type}`, params, {showSuccessMessage: true})
return request.put(`notice/notice/sms/${ params.sms_type }`, params, { showSuccessMessage: true })
}
/**

View File

@ -54,6 +54,14 @@ export function getPayRefundInfo(refund_no: string) {
return request.get(`pay/refund/${refund_no}`)
}
/**
* 退
* @param refund_no
*/
export function getRefundStatus() {
return request.get(`pay/refund/status`)
}
/**
* 退
*/

View File

@ -14,5 +14,5 @@ export function getPcConfig() {
* @returns
*/
export function setPcConfig(params: Record<string, any>) {
return request.put('channel/pc/config', params, {showSuccessMessage: true})
return request.put('channel/pc/config', params, { showSuccessMessage: true })
}

View File

@ -13,6 +13,6 @@ export function getUserInfo() {
* @returns
*/
export function setUserInfo(params: Record<string, any>) {
return request.put(`auth/edit`, params, {showSuccessMessage: true});
return request.put(`auth/edit`, params, { showSuccessMessage: true });
}

View File

@ -6,7 +6,7 @@ import request from '@/utils/request'
* @returns
*/
export function getPosterPageList(params: Record<string, any>) {
return request.get(`sys/poster`, {params})
return request.get(`sys/poster`, { params })
}
/**
@ -15,7 +15,7 @@ export function getPosterPageList(params: Record<string, any>) {
* @returns
*/
export function getPosterList(params: Record<string, any>) {
return request.get(`sys/poster/list`, {params})
return request.get(`sys/poster/list`, { params })
}
/**
@ -24,7 +24,7 @@ export function getPosterList(params: Record<string, any>) {
* @returns
*/
export function getPosterInfo(id: number) {
return request.get(`sys/poster/${id}`);
return request.get(`sys/poster/${ id }`);
}
/**
@ -33,7 +33,7 @@ export function getPosterInfo(id: number) {
* @returns
*/
export function addPoster(params: Record<string, any>) {
return request.post('sys/poster', params, {showErrorMessage: true, showSuccessMessage: true})
return request.post('sys/poster', params, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -42,7 +42,7 @@ export function addPoster(params: Record<string, any>) {
* @returns
*/
export function editPoster(params: Record<string, any>) {
return request.put(`sys/poster/${params.id}`, params, {
return request.put(`sys/poster/${ params.id }`, params, {
showErrorMessage: true,
showSuccessMessage: true
})
@ -54,7 +54,7 @@ export function editPoster(params: Record<string, any>) {
* @returns
*/
export function deletePoster(id: number) {
return request.delete(`sys/poster/${id}`, {showErrorMessage: true, showSuccessMessage: true})
return request.delete(`sys/poster/${ id }`, { showErrorMessage: true, showSuccessMessage: true })
}
/**
@ -62,7 +62,7 @@ export function deletePoster(id: number) {
* @param params
*/
export function modifyPosterStatus(params: Record<string, any>) {
return request.put(`sys/poster/status`, params, {showSuccessMessage: true})
return request.put(`sys/poster/status`, params, { showSuccessMessage: true })
}
/**
@ -70,7 +70,7 @@ export function modifyPosterStatus(params: Record<string, any>) {
* @param params
*/
export function modifyPosterDefault(params: Record<string, any>) {
return request.put(`sys/poster/default`, params, {showSuccessMessage: true})
return request.put(`sys/poster/default`, params, { showSuccessMessage: true })
}
/**
@ -79,7 +79,7 @@ export function modifyPosterDefault(params: Record<string, any>) {
* @returns
*/
export function getPosterType(params: Record<string, any>) {
return request.get(`sys/poster/type`, {params})
return request.get(`sys/poster/type`, { params })
}
/**
@ -88,21 +88,21 @@ export function getPosterType(params: Record<string, any>) {
* @returns
*/
export function getPosterTemplate(params: Record<string, any>) {
return request.get(`sys/poster/template`, {params})
return request.get(`sys/poster/template`, { params })
}
/**
*
*/
export function initPoster(params: Record<string, any>) {
return request.get(`sys/poster/init`, {params})
return request.get(`sys/poster/init`, { params })
}
/**
*
*/
export function getPreviewPoster(params: Record<string, any>) {
return request.get(`sys/poster/preview`, {params})
return request.get(`sys/poster/preview`, { params })
}
/**
@ -111,5 +111,5 @@ export function getPreviewPoster(params: Record<string, any>) {
* @returns
*/
export function getPosterGenerate(params: Record<string, any>) {
return request.get(`sys/poster/generate`, {params, showErrorMessage: false})
}
return request.get(`sys/poster/generate`, { params, showErrorMessage: false })
}

View File

@ -18,7 +18,7 @@ export function getSiteList(params: Record<string, any>) {
* @param site_id
*/
export function getSiteInfo(site_id: number) {
return request.get(`site/site/${site_id}`);
return request.get(`site/site/${ site_id }`);
}
/**
@ -35,7 +35,7 @@ export function addSite(params: Record<string, any>) {
* @param params
*/
export function editSite(params: Record<string, any>) {
return request.put(`site/site/${params.site_id}`, params, { showSuccessMessage: true })
return request.put(`site/site/${ params.site_id }`, params, { showSuccessMessage: true })
}
/**
@ -43,7 +43,7 @@ export function editSite(params: Record<string, any>) {
* @param siteId
*/
export function deleteSite(siteId: number) {
return request.delete(`site/site/${siteId}`)
return request.delete(`site/site/${ siteId }`)
}
/**
@ -51,7 +51,7 @@ export function deleteSite(siteId: number) {
* @param params
*/
export function closeSite(params: Record<string, any>) {
return request.put(`site/closesite/${params.site_id}`, params, { showSuccessMessage: true })
return request.put(`site/closesite/${ params.site_id }`, params, { showSuccessMessage: true })
}
/**
@ -59,7 +59,7 @@ export function closeSite(params: Record<string, any>) {
* @param params
*/
export function openSite(params: Record<string, any>) {
return request.put(`site/opensite/${params.site_id}`, params, { showSuccessMessage: true })
return request.put(`site/opensite/${ params.site_id }`, params, { showSuccessMessage: true })
}
/**
@ -85,7 +85,7 @@ export function getSiteGroupList(params: Record<string, any>) {
* @param groupId
*/
export function getSiteGroupInfo(groupId: number) {
return request.get(`site/group/${groupId}`);
return request.get(`site/group/${ groupId }`);
}
/**
@ -102,7 +102,7 @@ export function addSiteGroup(params: Record<string, any>) {
* @param params
*/
export function editSiteGroup(params: Record<string, any>) {
return request.put(`site/group/${params.group_id}`, params, { showSuccessMessage: true })
return request.put(`site/group/${ params.group_id }`, params, { showSuccessMessage: true })
}
/**
@ -110,7 +110,7 @@ export function editSiteGroup(params: Record<string, any>) {
* @param group_id
*/
export function deleteSiteGroup(group_id: number) {
return request.delete(`site/group/${group_id}`, { showSuccessMessage: true });
return request.delete(`site/group/${ group_id }`, { showSuccessMessage: true });
}
/**
@ -146,7 +146,7 @@ export function getUserList(params: Record<string, any>) {
* @param uid
*/
export function getUserInfo(uid: number) {
return request.get(`site/user/${uid}`);
return request.get(`site/user/${ uid }`);
}
/**
@ -163,7 +163,7 @@ export function addUser(params: Record<string, any>) {
* @param params
*/
export function editUser(params: Record<string, any>) {
return request.put(`site/user/${params.uid}`, params, { showSuccessMessage: true })
return request.put(`site/user/${ params.uid }`, params, { showSuccessMessage: true })
}
/**
@ -172,7 +172,7 @@ export function editUser(params: Record<string, any>) {
* @returns
*/
export function lockUser(uid: number) {
return request.put(`site/user/lock/${uid}`)
return request.put(`site/user/lock/${ uid }`)
}
/**
@ -181,7 +181,7 @@ export function lockUser(uid: number) {
* @returns
*/
export function unlockUser(uid: number) {
return request.put(`site/user/unlock/${uid}`)
return request.put(`site/user/unlock/${ uid }`)
}
/**
@ -190,7 +190,7 @@ export function unlockUser(uid: number) {
* @param uid
*/
export function deleteUser(uid: number) {
return request.delete(`site/user/${uid}`)
return request.delete(`site/user/${ uid }`)
}
/***************************************************** 操作日志 **************************************************/
@ -209,7 +209,7 @@ export function getLogList(params: Record<string, any>) {
* @param id
*/
export function getLogInfo(id: number) {
return request.get(`site/log/${id}`)
return request.get(`site/log/${ id }`)
}
/***************************************************** 账单列表 **************************************************/
@ -228,7 +228,7 @@ export function getAccountList(params: Record<string, any>) {
* @param id
*/
export function getAccountInfo(id: number) {
return request.get(`site/account/${id}`)
return request.get(`site/account/${ id }`)
}
/**

View File

@ -788,3 +788,11 @@ export function deleteExport(id: number) {
export function getWxoplatform() {
return request.get('sys/wxoplatform/config')
}
/**
*
* @returns
*/
export function getQrcode(params: Record<string, any>) {
return request.get(`sys/qrcode`, { params, showErrorMessage: false })
}

View File

@ -6,7 +6,7 @@ import request from '@/utils/request'
* @returns
*/
export function getAddonDevelop(params: Record<string, any>) {
return request.get(`addon_develop`, {params});
return request.get(`addon_develop`, { params });
}
/**
@ -22,7 +22,7 @@ export function getAddontype() {
* @returns
*/
export function getAddonDevelopInfo(key: any) {
return request.get(`addon_develop/${key}`)
return request.get(`addon_develop/${ key }`)
}
/**
@ -30,7 +30,7 @@ export function getAddonDevelopInfo(key: any) {
* @returns
*/
export function getAddonDevelopCheck(key: any) {
return request.get(`addon_develop/check/${key}`)
return request.get(`addon_develop/check/${ key }`)
}
/**
@ -48,7 +48,7 @@ export function getAddonKeyBlackList() {
* @returns
*/
export function addAddonDevelop(key: any, params: Record<string, any>) {
return request.post(`addon_develop/${key}`, params)
return request.post(`addon_develop/${ key }`, params)
}
/**
@ -58,7 +58,7 @@ export function addAddonDevelop(key: any, params: Record<string, any>) {
* @returns
*/
export function editAddonDevelop(key: any, params: Record<string, any>) {
return request.put(`addon_develop/${key}`, params)
return request.put(`addon_develop/${ key }`, params)
}
/**
@ -67,7 +67,7 @@ export function editAddonDevelop(key: any, params: Record<string, any>) {
* @returns
*/
export function deleteAddonDevelop(key: any) {
return request.delete(`addon_develop/${key}`, {showSuccessMessage: true})
return request.delete(`addon_develop/${ key }`, { showSuccessMessage: true })
}
/**
@ -75,7 +75,7 @@ export function deleteAddonDevelop(key: any) {
* @returns
*/
export function addonDevelopBuild(key: any) {
return request.post(`addon_develop/build/${key}`)
return request.post(`addon_develop/build/${ key }`)
}
/**
@ -83,8 +83,9 @@ export function addonDevelopBuild(key: any) {
* @returns
*/
export function addonDevelopDownload(key: any) {
return request.post(`addon_develop/download/${key}`, {})
return request.post(`addon_develop/download/${ key }`, {})
}
/***************************************************** 代码生成 ****************************************************/
/**
@ -93,7 +94,7 @@ export function addonDevelopDownload(key: any) {
* @returns
*/
export function getGenerateTableList(params: Record<string, any>) {
return request.get(`generator/generator`, {params})
return request.get(`generator/generator`, { params })
}
/**
@ -102,7 +103,7 @@ export function getGenerateTableList(params: Record<string, any>) {
* @returns
*/
export function getGenerateTableInfo(id: number) {
return request.get(`generator/generator/${id}`);
return request.get(`generator/generator/${ id }`);
}
/**
@ -111,7 +112,7 @@ export function getGenerateTableInfo(id: number) {
* @returns
*/
export function addGenerateTable(params: Record<string, any>) {
return request.post('generator/generator', params, {showSuccessMessage: true})
return request.post('generator/generator', params, { showSuccessMessage: true })
}
/**
@ -119,7 +120,7 @@ export function addGenerateTable(params: Record<string, any>) {
* @param params
*/
export function editGenerateTable(params: Record<string, any>) {
return request.put(`generator/generator/${params.id}`, params, {showSuccessMessage: true})
return request.put(`generator/generator/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -128,7 +129,7 @@ export function editGenerateTable(params: Record<string, any>) {
* @returns
*/
export function deleteGenerateTable(id: number) {
return request.delete(`generator/generator/${id}`, {showSuccessMessage: true})
return request.delete(`generator/generator/${ id }`, { showSuccessMessage: true })
}
/**
@ -146,7 +147,7 @@ export function generateCreate(params: Record<string, any>) {
* @returns
*/
export function generatePreview(id: number) {
return request.get(`generator/preview/${id}`)
return request.get(`generator/preview/${ id }`)
}
/**
@ -167,26 +168,26 @@ export function getSystem() {
*
*/
export function getGeneratorAllModel(params: any) {
return request.get(`generator/all_model`, {params})
return request.get(`generator/all_model`, { params })
}
/**
*
*/
export function getGeneratorTableColumn(params: any) {
return request.get(`generator/table_column`, {params})
return request.get(`generator/table_column`, { params })
}
/**
*
*/
export function generatorCheckFile(params: Record<string, any>) {
return request.get(`generator/check_file`, {params})
return request.get(`generator/check_file`, { params })
}
/**
*
*/
export function getGeneratorModelTableColumn(params: any) {
return request.get(`generator/model_table_column`, {params})
return request.get(`generator/model_table_column`, { params })
}

View File

@ -6,7 +6,7 @@ import request from '@/utils/request'
* @param addon
*/
export function getUpgradeContent(addon: string = '') {
return request.get(addon ? `upgrade/${addon}` : 'upgrade')
return request.get(addon ? `upgrade/${ addon }` : 'upgrade')
}
/**
@ -21,21 +21,21 @@ export function getUpgradeTask() {
* @param addon
*/
export function upgradeAddon(addon: string = '') {
return request.post(addon ? `upgrade/${addon}` : 'upgrade')
return request.post(addon ? `upgrade/${ addon }` : 'upgrade')
}
/**
*
*/
export function executeUpgrade() {
return request.post('upgrade/execute', {})
return request.post('upgrade/execute', {}, { showErrorMessage: false })
}
/**
*
*/
export function preUpgradeCheck(addon: string = '') {
return request.get(addon ? `upgrade/check/${addon}` : 'upgrade/check')
return request.get(addon ? `upgrade/check/${ addon }` : 'upgrade/check')
}
/**
@ -44,3 +44,88 @@ export function preUpgradeCheck(addon: string = '') {
export function clearUpgradeTask() {
return request.post('upgrade/clear')
}
/**
*
* @param operate
*/
export function upgradeUserOperate(operate: string) {
return request.post(`upgrade/operate/${ operate }`)
}
/**
*
* @param params
* @returns
*/
export function getUpgradeRecords(params: Record<string, any>) {
return request.get(`upgrade/records`, { params })
}
/**
*
* @param params
* @returns
*/
export function getBackupRecords(params: Record<string, any>) {
return request.get(`backup/records`, { params })
}
/**
*
* @param params
*/
export function modifyBackupRemark(params: Record<string, any>) {
return request.put(`backup/remark`, params, { showSuccessMessage: true })
}
/**
*
*/
export function checkDirExist(params: Record<string, any>) {
return request.post('backup/check_dir', params)
}
/**
*
*/
export function checkPermission(params: Record<string, any>) {
return request.post('backup/check_permission', params)
}
/**
*
*/
export function restoreUpgradeBackup(params: Record<string, any>) {
return request.post('backup/restore', params)
}
/**
*
*/
export function deleteRecords(params: Record<string, any>) {
return request.post('backup/delete', params, { showSuccessMessage: true })
}
/**
*
*/
export function manualBackup(params: Record<string, any>) {
return request.post("backup/manual", params)
}
/**
*
* @param params
*/
export function performRecoveryTasks(params: Record<string, any>) {
return request.get("backup/restore_task", params)
}
/**
*
* @param params
*/
export function performBackupTasks(params: Record<string, any>) {
return request.get("backup/task", params)
}

View File

@ -36,7 +36,7 @@ export function addUser(params: Record<string, any>) {
* @param uid
*/
export function deleteUser(uid: number) {
return request.delete(`user/user/${uid}`, { showSuccessMessage: true })
return request.delete(`user/user/${ uid }`, { showSuccessMessage: true })
}
/**
@ -44,7 +44,7 @@ export function deleteUser(uid: number) {
* @param uid
*/
export function editUser(params: Record<string, any>) {
return request.put(`user/user/${params.uid}`, params, { showSuccessMessage: true })
return request.put(`user/user/${ params.uid }`, params, { showSuccessMessage: true })
}
/**

View File

@ -18,7 +18,7 @@ export function getVerifyRecord(params: Record<string, any>) {
* @returns
*/
export function getVerifyDetail(verifyCode: string) {
return request.get(`verify/verify/${verifyCode}`)
return request.get(`verify/verify/${ verifyCode }`)
}
/***************************************************** 核销员 ****************************************************/
@ -64,5 +64,21 @@ export function addVerifier(params: Record<string, any>) {
* @returns
*/
export function deleteVerifier(id: number) {
return request.delete(`verify/verifier/${id}`, { showSuccessMessage: true })
}
return request.delete(`verify/verifier/${ id }`, { showSuccessMessage: true })
}
/**
*
* @returns
*/
export function getVerifyInfo(id: number) {
return request.get(`verify/verifier/${ id }`)
}
/**
*
* @returns
*/
export function editVerifier(params: Record<string, any>) {
return request.post(`verify/verifier/${ params.id }`, params,{ showSuccessMessage: true })
}

View File

@ -33,6 +33,7 @@ export function getTemplateList() {
export function getBatchAcquisition(params: Record<string, any>) {
return request.put('weapp/template/sync', params, { showSuccessMessage: true })
}
/**
*
* @param params
@ -65,7 +66,7 @@ export function getWeappVersionList(params: Record<string, any>) {
* @returns
*/
export function getWeappUploadLog(key: string) {
return request.get(`weapp/upload/${key}`)
return request.get(`weapp/upload/${ key }`)
}
/***************************************************** 管理端 ****************************************************/
@ -103,7 +104,7 @@ export function getVersionList(params: Record<string, any>) {
* @returns
*/
export function getVersionInfo(id: string) {
return request.get(`applet/version/${id}`)
return request.get(`applet/version/${ id }`)
}
/**
@ -112,7 +113,7 @@ export function getVersionInfo(id: string) {
* @returns
*/
export function editVersion(params: Record<string, any>) {
return request.put(`applet/version/${params.id}`, params, { showSuccessMessage: true })
return request.put(`applet/version/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -121,7 +122,7 @@ export function editVersion(params: Record<string, any>) {
* @returns
*/
export function deleteVersion(id: string) {
return request.delete(`applet/version/${id}`)
return request.delete(`applet/version/${ id }`)
}
/**

View File

@ -21,7 +21,7 @@ export function getWechatStatic() {
* @returns
*/
export function editWechatConfig(params: Record<string, any>) {
return request.put('wechat/config', params, {showSuccessMessage: true})
return request.put('wechat/config', params, { showSuccessMessage: true })
}
/**
@ -38,7 +38,7 @@ export function getWechatMenu() {
* @returns
*/
export function editWechatMenu(params: Record<string, any>) {
return request.put('wechat/menu', params, {showSuccessMessage: true})
return request.put('wechat/menu', params, { showSuccessMessage: true })
}
/**
@ -55,7 +55,7 @@ export function getTemplateList() {
* @returns
*/
export function getBatchAcquisition(params: Record<string, any>) {
return request.put('wechat/template/sync', params, {showSuccessMessage: true})
return request.put('wechat/template/sync', params, { showSuccessMessage: true })
}
/**
@ -69,7 +69,7 @@ export function getKeywordsReplyList(params: Record<string, any>) {
*
*/
export function editKeywordsReply(params: Record<string, any>) {
return request.put(`wechat/reply/keywords/${params.id}`, params, { showSuccessMessage: true })
return request.put(`wechat/reply/keywords/${ params.id }`, params, { showSuccessMessage: true })
}
/**
@ -84,14 +84,14 @@ export function addKeywordsReply(params: Record<string, any>) {
* @param id
*/
export function getKeywordsReplyInfo(id: number) {
return request.get(`wechat/reply/keywords/${id}`)
return request.get(`wechat/reply/keywords/${ id }`)
}
/**
*
*/
export function delKeywordsReply(id: number) {
return request.delete(`wechat/reply/keywords/${id}`, { showSuccessMessage: true })
return request.delete(`wechat/reply/keywords/${ id }`, { showSuccessMessage: true })
}
/**

View File

@ -42,8 +42,8 @@ export function getAuthorizationResult(params: Record<string, any>) {
*
* @returns
*/
export function weappCommit() {
return request.post('wxoplatform/weapp/version/commit', {}, { showSuccessMessage: true })
export function weappCommit(params: Record<string, any>) {
return request.post('wxoplatform/weapp/version/commit', params, { showSuccessMessage: true })
}
/**
@ -67,3 +67,11 @@ export function getWeappLastCommitRecord() {
export function siteWeappCommit() {
return request.post('wxoplatform/site/weapp/commit', {}, { showSuccessMessage: true })
}
/**
*
*/
export function getSiteGroupCommitRecord(params: Record<string, any>) {
return request.get('wxoplatform/sitegroup/commit', { params })
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -84,7 +84,6 @@ const active = ref('build')
const cloudBuildCheck = ref<null | AnyObject>(null)
const loading = ref(false)
const terminalRef = ref(null)
const emits = defineEmits(['complete'])
let cloudBuildLog = []
/**
@ -127,7 +126,7 @@ const getCloudBuildLogFn = () => {
data[0].forEach(item => {
if (!cloudBuildLog.includes(item.action)) {
terminalRef.value.pushMessage({ content: `正在执行:${item.action}` })
terminalRef.value.pushMessage({ content: `${item.action}` })
cloudBuildLog.push(item.action)
if (item.code == 0) {

View File

@ -0,0 +1,239 @@
<template>
<el-dialog v-model="dialogVisible" :title="t('gxx')" width="850">
<el-card class="box-card !border-none" shadow="never" >
<div v-loading="loading">
<div class="text-page-title mb-[20px]">历史版本</div>
<div class="time-dialog h-[500px]" style="overflow: auto">
<el-scrollbar>
<el-timeline style="width: 100%" v-if="!loading">
<el-timeline-item v-for="(item, index) in frameworkVersionList" :key="index" placement="left" :color="color">
<div class="relative">
<span class="text-[#333333] text-[14px] absolute">{{ timeSplit(item.release_time)[0] }}</span>
<br />
<span class="text-[#999999] text-[14px] w-[78px] block mt-[10px] absolute text-right">{{ timeSplit(item.release_time)[1] }}</span>
</div>
<el-collapse v-model="activeName" accordion>
<el-collapse-item :name="index">
<template #title>
<span class="text-[#333] text-[14px]"> v{{ item.version_no }} </span>
</template>
<div class="px-[20px] py-[20px] bg-overlay timeline-log-wrap whitespace-pre-wrap rounded-[4px]" style="background: rgba(25, 103, 249, 0.03);" v-if="item['upgrade_log']">
<div v-html="item['upgrade_log']"></div>
</div>
</el-collapse-item>
</el-collapse>
</el-timeline-item>
</el-timeline>
</el-scrollbar>
</div>
</div>
</el-card>
</el-dialog>
</template>
<script lang="ts" setup>
import { computed, ref, defineProps, nextTick } from "vue"
import { t } from "@/lang"
import { getAppVersionList, getFrameworkVersionList } from "@/app/api/module"
const props = defineProps({
upgradeKey: {
type: String,
required: true
}
})
const frameworkVersionList = ref([])
const newVersion: any = computed(() => {
return frameworkVersionList.value.length ? frameworkVersionList.value[0] : null
})
const getAppVersionListFn = () => {
getAppVersionList({ app_key: props.upgradeKey }).then(({ data }) => {
loading.value = false
data.forEach((item: any, index) => {
if (index == 0) {
item.important = 1
} else {
item.important = 0
}
})
frameworkVersionList.value = data
})
}
const getFrameworkVersionListFn = () => {
getFrameworkVersionList().then(({ data }) => {
loading.value = false
data.forEach((item: any, index) => {
if (index == 0) {
item.important = 1
} else {
item.important = 0
}
})
frameworkVersionList.value = data
})
}
const activeName = ref(0)
//
const loading = ref(true)
const dialogVisible = ref(false)
const open = async () => {
nextTick(() => {
if (props.upgradeKey) {
getAppVersionListFn()
} else {
getFrameworkVersionListFn()
}
dialogVisible.value = true
})
}
const timeSplit = (str: string) => {
const [date, time] = str.split(" ")
const [hours, minutes] = time.split(":")
return [date, `${ hours }:${ minutes }`]
}
defineExpose({
open
})
</script>
<style lang="scss" scoped></style>
<style scoped>
.el-timeline-item {
min-height: 75px;
}
.el-timeline-item >>> .el-timeline-item__node--normal {
left: 117px;
width: 18px;
height: 18px;
background: rgba(25, 103, 249, 0.12) !important;
border-radius: 50%;
/* 创建圆形 */
position: relative;
/* 用于定位伪元素 */
}
.el-timeline-item >>> .el-timeline-item__node--normal::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 8px;
/* 中心圆直径 */
height: 8px;
background-color: var(--el-color-primary);
/* 中心圆颜色 */
border-radius: 50%;
/* 中心圆为圆形 */
transform: translate(-50%, -50%);
/* 居中显示 */
}
.el-timeline-item >>> .el-timeline-item__tail {
left: 125px;
border-left-color: #dddddd;
border-left-style: dashed;
margin: 12px 0;
margin-top: 24px;
height: calc(100% - 24px - 12px);
}
.time-dialog >>> .el-dialog__header {
padding: 10px 20px;
height: 25px;
line-height: 25px;
text-align: left;
background: #fff;
border-bottom: solid 1px #e4e7ed;
}
.time-dialog >>> .el-card__body {
padding: 8px;
}
.time-dialog >>> .el-card.is-always-shadow {
box-shadow: none;
}
.time-dialog >>> .el-dialog__headerbtn .el-dialog__close {
color: #666;
}
.time-dialog >>> .el-dialog__headerbtn:hover .el-dialog__close {
color: #666;
}
.time-dialog >>> .el-dialog__headerbtn {
top: 14px;
}
.time-dialog >>> .el-collapse {
margin-left: 119px;
border: none;
margin-top: -22px;
}
.time-dialog >>> .el-collapse-item__header {
border: none;
line-height: 25px;
height: 25px;
position: relative;
z-index: 999;
}
.time-dialog >>> .el-collapse-item__wrap {
border: none;
}
.time-dialog >>> .el-collapse-item__content {
margin-top: 15px;
padding-bottom: 0px !important;
}
.time-dialog >>> .el-timeline-item__node--01 {
width: 18px !important;
height: 18px !important;
left: 117px !important;
}
</style>
<style>
.time-dialog .el-dialog {
margin: 0 auto !important;
max-height: 90%;
overflow: hidden;
top: 5%;
}
.time-dialog .el-dialog {
margin: 0 auto !important;
height: 65%;
overflow: hidden;
top: 10%;
}
.time-dialog .el-dialog__body {
position: absolute;
left: 0;
top: 46px;
bottom: 0;
right: 0;
z-index: 1;
overflow: hidden;
overflow-y: auto;
padding: 10px 20px 0 0;
}
.time-dialog .el-timeline-item__wrapper {
top: -20px !important;
}
.el-scrollbar__bar{
z-index:999;
}
</style>

View File

@ -1,140 +1,252 @@
<template>
<el-dialog v-model="showDialog" :title="t('upgrade.title')" width="850px" :close-on-click-modal="false" :close-on-press-escape="false" :before-close="dialogClose">
<div v-show="active == 'content'">
<div class="h-[60vh] flex flex-col" v-if="upgradeContent">
<template v-if="upgradeContent">
<!-- 检测服务是否到期 -->
<template v-if="step == 1 && upgradeContent.upgrade_version != upgradeContent.last_version">
<div class="text-lg">
本次升级将从<span class="font-bold">{{ upgradeContent.version }}</span>升级到<span class="font-bold">{{ upgradeContent.upgrade_version }}</span>版本
<template v-if="upgradeContent.upgrade_version">
<span>本次升级将从</span>
<span class="font-bold px-[2px]">{{ upgradeContent.version }}</span>
<span>升级到</span>
<span class="font-bold px-[2px]">{{ upgradeContent.upgrade_version }}</span>
<span>版本</span>
</template>
<template v-else>
<span>当前版本</span>
<span class="font-bold px-[2px]">{{ upgradeContent.version }}</span>
</template>
</div>
<div class="mt-[10px]" v-if="upgradeContent.upgrade_version != upgradeContent.last_version">
<el-alert type="info" show-icon>
<div class="mt-[10px]">
<el-alert type="info" show-icon :closable="false">
<template #title>
当前最新版本为{{ upgradeContent.last_version }}您的服务{{ upgradeContent.expire_time ? `已于${upgradeContent.expire_time}到期` : '长期有效' }}如需升级到最新版可在<a class="text-primary" href="https://www.niucloud.com" target="_blank">niucloud-admin官网</a>购买相关服务后再进行升级
<span>当前最新版本为{{ upgradeContent.last_version }}您的服务{{ upgradeContent.expire_time ? `已于${upgradeContent.expire_time}到期` : '长期有效' }}</span>
<span>如需升级到最新版可在<a class="text-primary" href="https://www.niucloud.com" target="_blank">niucloud-admin官网</a>购买相关服务后再进行升级</span>
</template>
</el-alert>
</div>
<el-scrollbar class="flex-1 h-0 mt-[20px]">
<div class="mt-[20px]" v-for="(item, index) in upgradeContent.version_list" :key="index">
<div class="font-bold text-lg">{{ item.version_no }}</div>
<div class="mt-[5px]" v-if="item.release_time">{{ item.release_time }}</div>
<div class="mt-[10px] p-[10px] rounded bg-[#f4f4f5] whitespace-pre-wrap !break-all" v-if="item.upgrade_log" v-html="item.upgrade_log"></div>
</div>
</el-scrollbar>
</div>
<div class="flex justify-end" v-if="upgradeContent.version_list.length">
<el-button type="primary" @click="handleUpgrade" :loading="uploading">{{ t('upgrade.upgradeButton') }}</el-button>
</div>
</div>
</template>
<div v-if="step == 2">
<el-steps :active="numberOfSteps" align-center class="number-of-steps" finish-status="success" process-status="process">
<el-step :title="t('testDirectoryPermissions')" />
<el-step :title="t('backupFiles')" />
<el-step :title="t('startUpgrade')" />
<el-step :title="t('upgradeEnd')" />
</el-steps>
<div class="h-[400px]" style="overflow: auto">
<!-- <div class="time-dialog-wrap mt-[30px]" v-show="active == 'content'">-->
<!-- <el-timeline style="width: 100%">-->
<!-- <el-timeline-item v-for="(item, index) in upgradeContent.version_list" :key="index" placement="left">-->
<!-- <div class="relative">-->
<!-- <span class="text-[#333333] text-[16px] absolute">{{ timeSplit(item.release_time)[0] }}</span>-->
<!-- <br />-->
<!-- <span class="text-[#999999] text-[14px] w-[78px] block mt-[10px] absolute" style="text-align: right"> {{ timeSplit(item.release_time)[1] }}</span>-->
<!-- </div>-->
<!-- <el-collapse v-model="activeName" accordion>-->
<!-- <el-collapse-item :name="index">-->
<!-- <template #title>-->
<!-- <span class="text-[#333] text-[16px]"> v{{ item.version_no }} </span>-->
<!-- </template>-->
<div v-show="active == 'upgrade'">
<div class="h-[60vh] flex flex-col" v-if="upgradeCheck && !upgradeTask">
<el-scrollbar>
<div class="bg-[#fff] my-3" v-if="upgradeCheck.dir">
<p class="pt-[20px] pl-[20px] ">{{ t('upgrade.dirPermission') }}</p>
<div class="px-[20px] pt-[10px] text-[14px] el-table">
<el-row class="py-[10px] items table-head-bg pl-[15px] mb-[10px]">
<el-col :span="12">
<span>{{ t('upgrade.path') }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('upgrade.demand') }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('status') }}</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="item in upgradeCheck.dir.is_readable">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('upgrade.readable') }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="item in upgradeCheck.dir.is_write">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t('upgrade.write') }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status"><el-icon color="green"><Select /></el-icon></span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
<!-- <div class="px-[20px] py-[20px] bg-overlay timeline-log-wrap whitespace-pre-wrap rounded-[4px]" style="background: rgba(25, 103, 249, 0.03);" v-if="item['upgrade_log']">-->
<!-- <div v-html="item['upgrade_log']"></div>-->
<!-- </div>-->
<!-- </el-collapse-item>-->
<!-- </el-collapse>-->
<!-- </el-timeline-item>-->
<!-- </el-timeline>-->
<!-- </div>-->
<!-- 判断文件权限 -->
<div v-show="active == 'upgrade'">
<div class="flex flex-col" v-if="upgradeCheck && !upgradeTask">
<el-scrollbar>
<div class="bg-[#fff] my-3" v-if="upgradeCheck.dir">
<div class="px-[20px] pt-[10px] text-[14px] el-table">
<el-row class="py-[10px] items table-head-bg pl-[15px] mb-[10px]">
<el-col :span="12">
<span>{{ t("upgrade.path") }}</span>
</el-col>
<el-col :span="6">
<span>{{ t("upgrade.demand") }}</span>
</el-col>
<el-col :span="6">
<span>{{ t("status") }}</span>
</el-col>
</el-row>
<div style="height: calc(300px); overflow: auto">
<el-row class="pb-[10px] items pl-[15px]" v-for="item in upgradeCheck.dir.is_readable">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t("upgrade.readable") }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status">
<el-icon color="green">
<Select />
</el-icon>
</span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="item in upgradeCheck.dir.is_write">
<el-col :span="12">
<span>{{ item.dir }}</span>
</el-col>
<el-col :span="6">
<span>{{ t("upgrade.write") }}</span>
</el-col>
<el-col :span="6">
<span v-if="item.status">
<el-icon color="green">
<Select />
</el-icon>
</span>
<span v-else>
<el-icon color="red">
<CloseBold />
</el-icon>
</span>
</el-col>
</el-row>
</div>
</div>
</div>
</el-scrollbar>
</div>
<div class="h-[370px] mt-[30px]" v-show="upgradeTask">
<terminal ref="terminalRef" :context="upgradeTask ? upgradeTask.upgrade.app_key : ''" :init-log="null" :show-header="false" :show-log-time="true" @exec-cmd="onExecCmd" />
</div>
</div>
</el-scrollbar>
</div>
<div class="h-[60vh]" v-show="upgradeTask">
<terminal ref="terminalRef" :context="upgradeTask ? upgradeTask.upgrade.app_key : ''" :init-log="null" :show-header="false" :show-log-time="true" @exec-cmd="onExecCmd"/>
</div>
</div>
<!-- 是否备份选择 -->
<div class="flex flex-col" v-show="active == 'backup'">
<el-scrollbar>
<div class="bg-[#fff] my-3">
<div v-show="active == 'complete'">
<div class="h-[60vh] flex flex-col">
<div class="flex-1 h-0">
<el-result icon="success" :title="t('upgrade.upgradeSuccess')"></el-result>
<el-alert :title="t('upgrade.upgradeCompleteTips')" type="error" :closable="false" />
</div>
<div class="flex justify-end">
<el-button type="default" @click="showDialog = false">{{ t('upgrade.localBuild') }}</el-button>
<el-button type="primary" @click="handleCloudBuild">{{ t('upgrade.cloudBuild') }}</el-button>
<div class="px-[20px] pt-[10px] text-[14px] el-table">
<el-row class="py-[10px] items table-head-bg pl-[15px] mb-[10px]">
<el-col :span="20">
<span>功能操作</span>
</el-col>
<el-col :span="4">
<span>状态</span>
</el-col>
</el-row>
<el-row class="pb-[10px] items pl-[15px]" v-for="item in excludeSteps">
<el-col :span="20">
<span>{{ item.name }}</span>
</el-col>
<el-col :span="4">
<span>
<el-icon color="green">
<Select />
</el-icon>
</span>
</el-col>
</el-row>
</div>
</div>
</el-scrollbar>
</div>
<div class="mt-[50px]" v-show="active == 'complete'">
<el-result icon="success" :title="t('upgrade.upgradeSuccess')"></el-result>
<el-alert :title="t('upgrade.upgradeCompleteTips')" type="error" :closable="false" v-show="upgradeTask && upgradeTask.executed && !upgradeTask.executed.includes('cloudBuild')"/>
</div>
</div>
</div>
</div>
</template>
<template #footer>
<div class="dialog-footer">
<!-- 查看升级内容 -->
<el-button v-if="step == 1 && upgradeContent.version_list.length" @click="step = 2" type="primary">{{ t("upgrade.upgradeButton") }}</el-button>
<template v-if="step == 2">
<!-- <el-button v-if="active == 'content'" @click="showDialog = false">{{ t("return") }}</el-button>-->
<el-button type="primary" :disabled="!is_pass" v-if="active == 'upgrade' && !upgradeTask" @click="() => { active = 'backup'; numberOfSteps = 1 }">{{ t("nextStep") }}</el-button>
<el-button v-if="active == 'backup'" @click="() => { active = 'upgrade'; numberOfSteps = 1 } ">{{ t("prev") }}</el-button>
<el-button type="primary" v-if="active == 'backup'" :loading="uploading" @click="() => { upgradeAddonFn() }">{{ t("nextStep") }}</el-button>
<el-button v-if="active == 'complete'" @click="showDialog = false">{{ t("complete") }}</el-button>
</template>
</div>
</template>
</el-dialog>
<el-dialog v-model="upgradeTipsShowDialog" :title="t('warning')" width="500px" draggable>
<span v-html="t('upgrade.upgradeTips')"></span>
<template #footer>
<div class="flex justify-end">
<el-button @click="upgradeTipsConfirm(true)" type="primary">{{ t('upgrade.knownToKnow') }}</el-button>
<el-button @click="upgradeTipsConfirm()" type="primary" plain>{{ t('upgrade.upgradeButton') }}</el-button>
<el-button @click="upgradeTipsShowDialog = false">{{ t('cancel') }}</el-button>
<el-button @click="upgradeTipsConfirm(true)" type="primary">{{ t("upgrade.knownToKnow") }}</el-button>
<el-button @click="handleUpgrade()" type="primary" plain>{{ t("upgrade.upgradeButton") }}</el-button>
<el-button @click="upgradeTipsShowDialog = false">{{ t("cancel") }}</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="cloudBuildErrorTipsShowDialog" :title="t('warning')" width="500px" draggable :show-close="false">
<span v-html="t('upgrade.cloudBuildErrorTips')"></span>
<template #footer>
<div class="flex justify-end">
<el-button @click="cloudBuildError('local')" type="primary">{{ t("upgrade.localBuild") }}</el-button>
<el-button @click="cloudBuildError('retry')" type="primary">{{ t("upgrade.cloudBuild") }}{{ retrySecond }}S</el-button>
<el-button @click="cloudBuildError('rollback')" type="primary">{{ t("upgrade.rollback") }}</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, h, watch } from 'vue'
import { t } from '@/lang'
import { getVersions } from '@/app/api/auth'
import { getFrameworkNewVersion } from '@/app/api/module'
import { getUpgradeContent, getUpgradeTask, upgradeAddon, executeUpgrade, preUpgradeCheck, clearUpgradeTask } from '@/app/api/upgrade'
import { Terminal, TerminalFlash } from 'vue-web-terminal'
import 'vue-web-terminal/lib/theme/dark.css'
import { AnyObject } from '@/types/global'
import { ElNotification, ElMessage, ElMessageBox } from 'element-plus'
import Storage from '@/utils/storage'
import { ref, h, watch } from "vue"
import { t } from "@/lang"
import { getVersions } from "@/app/api/auth"
import { getFrameworkNewVersion } from "@/app/api/module"
import {
getUpgradeContent,
getUpgradeTask,
upgradeAddon,
executeUpgrade,
preUpgradeCheck,
clearUpgradeTask, upgradeUserOperate
} from "@/app/api/upgrade"
import { Terminal, TerminalFlash } from "vue-web-terminal"
import "vue-web-terminal/lib/theme/dark.css"
import { AnyObject } from "@/types/global"
import { ElNotification, ElMessage, ElMessageBox } from "element-plus"
import Storage from "@/utils/storage"
const showDialog = ref<boolean>(false)
const upgradeContent = ref<null | AnyObject>(null)
const upgradeTask = ref<null | AnyObject>(null)
const active = ref('content')
const active = ref('upgrade')
const step = ref(1)
const upgradeCheck = ref<null | AnyObject>(null)
const uploading = ref(false)
const terminalRef: any = ref(null)
const emits = defineEmits(['complete', 'cloudbuild'])
const emits = defineEmits(["complete", "cloudbuild"])
const upgradeTipsShowDialog = ref<boolean>(false)
let upgradeLog: any = []
let errorLog: any = []
const cloudBuildErrorTipsShowDialog = ref<boolean>(false)
const retrySecond = ref(30)
let retrySecondInterval: any = null
// backupCode backupSql
const excludeSteps: any = ref([
{
name: "备份源码",
code: "backupCode"
},
{
name: "备份数据库",
code: "backupSql"
}
])
/**
* 查询升级任务
*/
@ -142,66 +254,88 @@ const getUpgradeTaskFn = () => {
getUpgradeTask().then(({ data }) => {
if (!data) return
if (!upgradeContent.value) upgradeContent.value = data.upgrade_content
//
if (!showDialog.value) {
showElNotification()
return
}
if (!upgradeTask.value) {
terminalRef.value.execute('clear')
terminalRef.value.execute('开始升级')
terminalRef.value.execute("clear")
terminalRef.value.execute("开始升级")
}
data.log.forEach(item => {
upgradeTask.value = data
data.log.forEach((item) => {
if (!upgradeLog.includes(item)) {
terminalRef.value.pushMessage({content: `正在执行:${item}`})
terminalRef.value.pushMessage({ content: `${ item }` })
upgradeLog.push(item)
}
})
//
if (data.error) {
data.error.forEach(item => {
data.error.forEach((item) => {
if (!errorLog.includes(item)) {
terminalRef.value.pushMessage({ content: item, class: 'error' })
terminalRef.value.pushMessage({ content: item, class: "error" })
errorLog.push(item)
}
})
}
//
if (data.step == 'restoreComplete') {
if (data.step == "restoreComplete") {
flashInterval && clearInterval(flashInterval)
return
}
//
if (data.step == 'upgradeComplete') {
active.value = 'complete'
if (data.step == "upgradeComplete") {
active.value = "complete"
numberOfSteps.value = 4
notificationEl && notificationEl.close()
emits('complete')
emits("complete")
clearUpgradeTask()
return
}
upgradeTask.value = data
numberOfSteps.value = 2
active.value = "upgrade"
executeUpgradeFn()
}).catch()
})
}
getUpgradeTaskFn()
const executeUpgradeFn = () => {
executeUpgrade().then(() => {
getUpgradeTaskFn()
}).catch()
}).catch((err) => {
if (err.message.indexOf('队列') != -1) {
retrySecond.value = 30
retrySecondInterval = setInterval(() => {
retrySecond.value--
if (retrySecond.value == 0) {
cloudBuildError('retry')
}
}, 1000)
cloudBuildErrorTipsShowDialog.value = true
} else {
ElMessage({ message: err.message, type: 'error' })
}
})
}
let notificationEl : any = null
let notificationEl: any = null
/**
* 升级中任务提示
*/
const showElNotification = () => {
notificationEl = ElNotification.success({
title: t('warning'),
title: t("warning"),
dangerouslyUseHTMLString: true,
message: h('div', {}, [
t('upgrade.upgradingTips'),
h('span', { class: 'text-primary cursor-pointer', onClick: elNotificationClick }, [t('upgrade.clickView')])
]),
message: h("div", {}, [t("upgrade.upgradingTips"), h("span", {
class: "text-primary cursor-pointer",
onClick: elNotificationClick
}, [t("upgrade.clickView")])]),
duration: 0,
showClose: false
})
@ -209,13 +343,13 @@ const showElNotification = () => {
const elNotificationClick = () => {
showDialog.value = true
active.value = 'upgrade'
getUpgradeTaskFn()
active.value = "upgrade"
notificationEl && notificationEl.close()
}
const frameworkVersion = ref('')
getVersions().then(res => {
const frameworkVersion = ref("")
getVersions().then((res) => {
frameworkVersion.value = res.data.version.version
})
const newFrameworkVersion = ref("")
@ -226,44 +360,63 @@ getFrameworkNewVersion().then(({ data }) => {
/**
* 执行升级
*/
const handleUpgrade = async () => {
const is_pass = ref(false)
const repeat = ref(false)
const handleUpgrade = async() => {
if (repeat.value) return
repeat.value = true
const appKey = upgradeContent.value?.app.app_key != "niucloud-admin" ? upgradeContent.value?.app.app_key : ""
await preUpgradeCheck(appKey).then(async ({ data }) => {
upgradeCheck.value = data
is_pass.value = data.is_pass
active.value = "upgrade"
!upgradeTask.value ? (numberOfSteps.value = 0) : numberOfSteps.value
upgradeTipsShowDialog.value = false
showDialog.value = true
repeat.value = false
}).catch(() => {
repeat.value = true
})
}
const upgradeAddonFn = () => {
if (!is_pass.value) return
if (uploading.value) return
uploading.value = true
const appKey = upgradeContent.value?.app.app_key != 'niucloud-admin' ? upgradeContent.value?.app.app_key : ''
const appKey = upgradeContent.value?.app.app_key != "niucloud-admin" ? upgradeContent.value?.app.app_key : ""
await preUpgradeCheck(appKey).then(async({ data }) => {
if (data.is_pass) {
await upgradeAddon(appKey).then(() => {
getUpgradeTaskFn()
}).catch(() => {
uploading.value = false
})
} else {
upgradeCheck.value = data
}
}).catch()
if (uploading.value) active.value = 'upgrade'
upgradeAddon(appKey).then(() => {
getUpgradeTaskFn()
}).catch(() => {
uploading.value = false
})
}
const open = (addonKey: string = '') => {
const open = (addonKey: string = "", callback = null) => {
if (upgradeTask.value) {
ElMessage({ message: '已有正在执行中的升级任务', type: 'error' })
ElMessage({ message: "已有正在执行中的升级任务", type: "error" })
showDialog.value = true
if (callback) callback()
} else {
if (addonKey && frameworkVersion.value != newFrameworkVersion.value) {
ElMessage({ message: '存在新版本框架,请先升级框架', type: 'error' })
ElMessage({ message: "存在新版本框架,请先升级框架", type: "error" })
if (callback) callback()
return
}
getUpgradeContent(addonKey).then(({ data }) => {
upgradeContent.value = data
if (Storage.get('upgradeTipsLock')) {
showDialog.value = true
if (Storage.get("upgradeTipsLock")) {
handleUpgrade()
} else {
upgradeTipsShowDialog.value = true
}
}).catch()
if (callback) callback()
}).catch(() => {
if (callback) callback()
})
}
}
@ -273,11 +426,11 @@ const open = (addonKey: string = '') => {
let flashInterval: any = null
const terminalFlash = new TerminalFlash()
const onExecCmd = (key, command, success, failed, name) => {
if (command == '开始升级') {
if (command == "开始升级") {
success(terminalFlash)
const frames = makeIterator(['/', '——', '\\', '|'])
const frames = makeIterator(["/", "——", "\\", "|"])
flashInterval = setInterval(() => {
terminalFlash.flush('> ' + frames.next().value)
terminalFlash.flush("> " + frames.next().value)
}, 150)
}
}
@ -286,7 +439,7 @@ const makeIterator = (array: string[]) => {
var nextIndex = 0
return {
next() {
if ((nextIndex + 1) == array.length) {
if (nextIndex + 1 == array.length) {
nextIndex = 0
}
return { value: array[nextIndex++] }
@ -295,53 +448,78 @@ const makeIterator = (array: string[]) => {
}
const dialogClose = (done: () => {}) => {
if (active.value == 'upgrade' && upgradeTask.value && !upgradeTask.value.error) {
ElMessageBox.confirm(
t('upgrade.showDialogCloseTips'),
t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
if (active.value == "upgrade" && upgradeTask.value && ['upgradeComplete', 'restoreComplete'].includes(upgradeTask.value.step) === false) {
ElMessageBox.confirm(t("upgrade.showDialogCloseTips"), t("warning"), {
confirmButtonText: t("confirm"),
cancelButtonText: t("cancel"),
type: "warning"
}).then(() => {
done()
}).catch(() => { })
})
} else {
done()
}
}
watch(() => showDialog.value, () => {
if (!showDialog.value) {
clearUpgradeTaskFn()
watch(
() => showDialog.value,
() => {
if (!showDialog.value) {
clearUpgradeTaskFn()
}
}
})
)
const clearUpgradeTaskFn = () => {
active.value = 'content'
active.value = "upgrade"
uploading.value = false
upgradeTask.value = null
upgradeLog = []
errorLog = []
numberOfSteps.value = 0
flashInterval && clearInterval(flashInterval)
clearUpgradeTask().then(() => {}).catch()
retrySecondInterval && clearInterval(retrySecondInterval)
clearUpgradeTask().then(() => {
})
}
/**
* 云编译
* 云编译队列不足操作
* @param event
*/
const handleCloudBuild = () => {
showDialog.value = false
emits('cloudbuild')
const cloudBuildError = (event: string) => {
cloudBuildErrorTipsShowDialog.value = false
switch (event) {
case "local":
upgradeUserOperate(event).then(() => {
getUpgradeTaskFn()
})
break
case "retry":
executeUpgradeFn()
retrySecondInterval && clearInterval(retrySecondInterval)
break
case "rollback":
upgradeUserOperate(event).then(() => {
getUpgradeTaskFn()
})
break
}
}
const timeSplit = (str: string) => {
const [date, time] = str.split(" ")
const [hours, minutes] = time.split(":")
return [date, `${ hours }:${ minutes }`]
}
const upgradeTipsConfirm = (isLock: boolean = false) => {
isLock && Storage.set({ key: 'upgradeTipsLock', data: isLock })
isLock && Storage.set({ key: "upgradeTipsLock", data: isLock })
upgradeTipsShowDialog.value = false
!isLock && (showDialog.value = true)
}
const activeName = ref(0)
const numberOfSteps = ref(0)
defineExpose({
open
})
@ -351,7 +529,187 @@ defineExpose({
.table-head-bg {
background-color: var(--el-table-header-bg-color);
}
:deep(.terminal .t-log-box span) {
white-space: pre-wrap;
}
::v-deep .number-of-steps {
.el-step__line {
margin: 0 25px;
background: #dddddd;
}
.el-step__head {
margin-top: 10px;
}
.is-success {
color: var(--el-color-primary);
border-color: var(--el-color-primary);
.el-step__icon {
background: var(--el-color-primary);
box-shadow: 0 0 0 4px var(--el-color-primary-light-9);
i {
color: #fff;
}
}
.el-step__line {
margin: 0 25px;
background: var(--el-color-primary);
}
}
.is-process {
color: var(--el-color-primary);
font-weight: inherit;
// font-size: 18px;
.el-step__icon {
padding: 10px;
border: 1px solid var(--el-color-primary);
box-shadow: 0 0 0 4px var(--el-color-primary-light-9);
}
}
.is-wait {
color: #333;
}
}
</style>
<style scoped>
.el-timeline-item {
min-height: 100px;
}
.el-timeline-item >>> .el-timeline-item__node--normal {
left: 117px;
width: 18px;
height: 18px;
background: rgba(25, 103, 249, 0.12) !important;
border-radius: 50%;
/* 创建圆形 */
position: relative;
/* 用于定位伪元素 */
}
.el-timeline-item >>> .el-timeline-item__node--normal::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 8px;
/* 中心圆直径 */
height: 8px;
background-color: var(--el-color-primary);
/* 中心圆颜色 */
border-radius: 50%;
/* 中心圆为圆形 */
transform: translate(-50%, -50%);
/* 居中显示 */
}
.el-timeline-item >>> .el-timeline-item__tail {
left: 125px;
border-left-color: #dddddd;
border-left-style: dashed;
margin: 12px 0;
margin-top: 24px;
height: calc(100% - 24px - 12px);
}
.time-dialog-wrap >>> .el-dialog__header {
padding: 10px 20px;
height: 25px;
line-height: 25px;
text-align: left;
background: #fff;
border-bottom: solid 1px #e4e7ed;
}
.time-dialog-wrap >>> .el-card__body {
padding: 8px;
}
.time-dialog-wrap >>> .el-card.is-always-shadow {
box-shadow: none;
}
.time-dialog-wrap >>> .el-dialog__headerbtn .el-dialog__close {
color: #666;
}
.time-dialog-wrap >>> .el-dialog__headerbtn:hover .el-dialog__close {
color: #666;
}
.time-dialog-wrap >>> .el-dialog__headerbtn {
top: 14px;
}
.time-dialog-wrap >>> .el-collapse {
margin-left: 119px;
border: none;
margin-top: -22px;
}
.time-dialog-wrap >>> .el-collapse-item__header {
border: none;
line-height: 25px;
height: 25px;
position: relative;
z-index: 999;
}
.time-dialog-wrap >>> .el-collapse-item__wrap {
border: none;
}
.time-dialog-wrap >>> .el-collapse-item__content {
margin-top: 15px;
padding-bottom: 0 !important;
}
.time-dialog-wrap >>> .el-timeline-item__node--01 {
width: 18px !important;
height: 18px !important;
left: 117px !important;
}
</style>
<style>
.time-dialog-wrap .el-dialog {
margin: 0 auto !important;
max-height: 90%;
overflow: hidden;
top: 5%;
}
.time-dialog-wrap .el-dialog {
margin: 0 auto !important;
height: 65%;
overflow: hidden;
top: 10%;
}
.time-dialog-wrap .el-dialog__body {
position: absolute;
left: 0;
top: 46px;
bottom: 0px;
right: 0;
z-index: 1;
overflow: hidden;
overflow-y: auto;
padding: 10px 20px 0 0;
}
.time-dialog-wrap .el-timeline-item__wrapper {
top: -20px !important;
}
</style>

View File

@ -25,11 +25,9 @@ import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { deepClone } from '@/utils/common'
import { getUserInfo, setUserInfo } from '@/app/api/personal'
import { useRouter } from 'vue-router'
import useUserStore from '@/stores/modules/user'
const userStore = useUserStore()
const router = useRouter()
//
const saveInfo: any = reactive({})
const formRef = ref<FormInstance>()

View File

@ -1,19 +1,19 @@
{
"companyName": "授权主体",
"siteAddress": "授权域名",
"contactName": "授权联系人",
"authCode": "授权码",
"authSecret": "授权秘钥",
"createTime": "授权时间",
"expireTime": "到期时间",
"authApp": "授权应用",
"authAppKey": "应用标识",
"siteAddressTips": "授权域名不匹配",
"authCodePlaceholder": "请输入授权码",
"authSecretPlaceholder": "请输入授权秘钥",
"updateCode": "重新绑定",
"notHaveAuth": "还没有授权?去购买",
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
"versionTips":"已经升级到最新版本"
"companyName": "授权主体",
"siteAddress": "授权域名",
"contactName": "授权联系人",
"authCode": "授权码",
"authSecret": "授权秘钥",
"createTime": "授权时间",
"expireTime": "到期时间",
"authApp": "授权应用",
"authAppKey": "应用标识",
"siteAddressTips": "授权域名不匹配",
"authCodePlaceholder": "请输入授权码",
"authSecretPlaceholder": "请输入授权秘钥",
"updateCode": "重新绑定",
"notHaveAuth": "还没有授权?去购买",
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
"versionTips": "已经升级到最新版本"
}

View File

@ -0,0 +1,67 @@
{
"search": "搜索应用名称",
"appName": "应用名/版本信息",
"introduction": "简介",
"type": "类型",
"app": "应用",
"addon": "插件",
"noPlug": "暂无应用",
"install": "安装",
"unload": "卸载",
"installLabel": "已安装",
"uninstalledLabel": "未安装",
"version": "版本",
"title": "名称",
"desc": "简介",
"plugDetail": "插件信息",
"author": "作者",
"detail": "详情",
"addonInstall": "插件安装",
"dirPermission": "目录读写权限",
"path": "路径",
"demand": "要求",
"readable": "可读",
"write": "可写",
"packageManageTool": "包管理工具",
"name": "名称",
"addonInstallSuccess": "插件安装成功",
"envCheck": "环境检查",
"installProgress": "安装进度",
"installComplete": "安装完成",
"localAppText": "插件管理",
"marketAppText": "官方市场",
"installShowDialogCloseTips": "安装任务尚未完成,关闭将取消安装任务,是否要继续关闭?",
"marketDevelopMessage": "官方市场正在开发中!",
"jobError": "任务队列未启动 请在服务端源码部署目录打开终端执行 php think queue:listen",
"conflictFiles": "冲突文件",
"process": "启动进程",
"open": "开启",
"down": "下载",
"addonVersion": "插件版本",
"versionCode": "版本号",
"createTime": "发布时间",
"buyLabel": "已购买",
"installTips": "安装后需手动更新插件引用的依赖和编译各个端口的前端源码",
"localInstall": "本地安装",
"cloudInstall": "一键云安装",
"cloudInstallTips": "云安装可实现一键安装,安装后无需手动更新依赖和编译前端源码",
"installingTips": "有插件正在安装中请等待安装完成之后再进行其他操作,点击查看",
"installPercent": "安装进度",
"downloading": "下载中",
"authTips": "云安装需先绑定授权码如果已有授权请先进行绑定没有授权可到niucloud官网购买云服务之后再进行操作",
"toBind": "绑定授权",
"toNiucloud": "去niucloud官网",
"descriptionLeft": "暂无任何应用,马上去",
"link": "官方应用市场",
"descriptionRight": "逛逛",
"installed-empty": "暂未安装任何应用,请先安装",
"siteAddressTips": "授权域名不匹配",
"authCodePlaceholder": "请输入授权码",
"authSecretPlaceholder": "请输入授权秘钥",
"updateCode": "重新绑定",
"notHaveAuth": "还没有授权?去购买",
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
"addonUninstall": "插件卸载",
"appIdentification": "应用标识",
"tipText": "标识指开发应用或插件的文件夹名称"
}

View File

@ -0,0 +1,18 @@
{
"companyName": "授权主体",
"siteAddress": "授权域名",
"contactName": "授权联系人",
"authCode": "授权码",
"authSecret": "授权秘钥",
"createTime": "授权时间",
"expireTime": "到期时间",
"authApp": "授权应用",
"authAppKey": "应用标识",
"siteAddressTips": "授权域名不匹配",
"authCodePlaceholder": "请输入授权码",
"authSecretPlaceholder": "请输入授权秘钥",
"updateCode": "重新绑定",
"notHaveAuth": "还没有授权?去购买",
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
"versionTips": "已经升级到最新版本"
}

View File

@ -50,7 +50,7 @@
"cashOutInfo":"收款方信息",
"transferCode":"收款码",
"realname":"真实姓名",
"account":"账号",
"account":"收款账号",
"bankRealname":"持卡人姓名",
"remark":"备注",
"remarkPlaceholder":"请输入备注",

View File

@ -1,76 +1,78 @@
{
"search":"搜索应用名称",
"appName":"应用名/版本信息",
"introduction":"简介",
"type":"类型",
"app":"应用",
"addon":"插件",
"noPlug":"暂无应用",
"install":"安装",
"unload":"卸载",
"installLabel":"已安装",
"uninstalledLabel":"未安装",
"version":"版本",
"title":"名称",
"desc":"简介",
"plugDetail": "插件信息",
"author": "作者",
"detail":"详情",
"addonInstall": "插件安装",
"dirPermission": "目录读写权限",
"path": "路径",
"demand": "要求",
"readable": "可读",
"write": "可写",
"packageManageTool": "包管理工具",
"name": "名称",
"addonInstallSuccess": "插件安装成功",
"envCheck": "环境检查",
"installProgress": "安装进度",
"installComplete": "安装完成",
"localAppText":"插件管理",
"marketAppText":"官方市场",
"installShowDialogCloseTips": "安装任务尚未完成,关闭将取消安装任务,是否要继续关闭?",
"marketDevelopMessage":"官方市场正在开发中!",
"jobError": "任务队列未启动 请在服务端源码部署目录打开终端执行 php think queue:listen",
"conflictFiles": "冲突文件",
"process": "启动进程",
"open": "开启",
"down": "下载",
"installDown":"未安装(重新下载)",
"unloadDown":"已安装(重新下载)",
"addonVersion": "插件版本",
"versionCode": "版本号",
"createTime": "发布时间",
"buyLabel": "已购买",
"installTips": "安装后需手动更新插件引用的依赖和编译各个端口的前端源码",
"localInstall":"本地安装",
"cloudInstall": "一键云安装",
"cloudInstallTips": "云安装可实现一键安装,安装后无需手动更新依赖和编译前端源码",
"installingTips": "有插件正在安装中请等待安装完成之后再进行其他操作,点击查看",
"installPercent": "安装进度",
"downloading": "下载中",
"authTips": "云安装需先绑定授权码如果已有授权请先进行绑定没有授权可到niucloud官网购买云服务之后再进行操作",
"toBind": "绑定授权",
"toNiucloud": "去niucloud官网",
"descriptionLeft": "暂无任何应用,马上去",
"buyDescriptionLeft": "您还没有购买过应用,马上去",
"link": "官方应用市场",
"descriptionRight": "逛逛",
"installed-empty": "暂未安装任何应用",
"siteAddressTips": "授权域名不匹配",
"authCodePlaceholder": "请输入授权码",
"authSecretPlaceholder": "请输入授权秘钥",
"updateCode": "重新绑定",
"notHaveAuth": "还没有授权?去购买",
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
"addonUninstall": "插件卸载",
"appIdentification":"应用标识",
"tipText":"标识指开发应用或插件的文件夹名称",
"uninstallTips": "是否要卸载该插件?",
"upgrade": "升级",
"newVersion": "最新版本",
"cloudBuild": "云编译",
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
"deleteAddonTips": "删除插件会把插件目录连同文件全部删除,确定要删除吗?"
"search": "搜索应用名称",
"appName": "应用名/版本信息",
"introduction": "简介",
"type": "类型",
"app": "应用",
"addon": "插件",
"noPlug": "暂无应用",
"install": "安装",
"unload": "卸载",
"installLabel": "已安装",
"uninstalledLabel": "未安装",
"version": "版本",
"title": "名称",
"desc": "简介",
"plugDetail": "插件信息",
"author": "作者",
"detail": "详情",
"addonInstall": "插件安装",
"dirPermission": "目录读写权限",
"path": "路径",
"demand": "要求",
"readable": "可读",
"write": "可写",
"packageManageTool": "包管理工具",
"name": "名称",
"addonInstallSuccess": "插件安装成功",
"envCheck": "环境检查",
"installProgress": "安装进度",
"installComplete": "安装完成",
"localAppText": "插件管理",
"marketAppText": "官方市场",
"installShowDialogCloseTips": "安装任务尚未完成,关闭将取消安装任务,是否要继续关闭?",
"marketDevelopMessage": "官方市场正在开发中!",
"jobError": "任务队列未启动 请在服务端源码部署目录打开终端执行 php think queue:listen",
"conflictFiles": "冲突文件",
"process": "启动进程",
"open": "开启",
"down": "下载",
"installDown": "未安装(重新下载)",
"unloadDown": "已安装(重新下载)",
"addonVersion": "插件版本",
"versionCode": "版本号",
"createTime": "发布时间",
"buyLabel": "已购买",
"recentlyUpdated": "最近更新",
"installTips": "安装后需手动更新插件引用的依赖和编译各个端口的前端源码",
"localInstall": "本地安装",
"cloudInstall": "一键云安装",
"cloudInstallTips": "云安装可实现一键安装,安装后无需手动更新依赖和编译前端源码",
"installingTips": "有插件正在安装中请等待安装完成之后再进行其他操作,点击查看",
"installPercent": "安装进度",
"downloading": "下载中",
"authTips": "云安装需先绑定授权码如果已有授权请先进行绑定没有授权可到niucloud官网购买云服务之后再进行操作",
"toBind": "绑定授权",
"toNiucloud": "去niucloud官网",
"descriptionLeft": "暂无任何应用,马上去",
"buyDescriptionLeft": "您还没有购买过应用,马上去",
"link": "官方应用市场",
"descriptionRight": "逛逛",
"installed-empty": "暂未安装任何应用",
"recentlyUpdatedEmpty": "暂无最近更新应用",
"siteAddressTips": "授权域名不匹配",
"authCodePlaceholder": "请输入授权码",
"authSecretPlaceholder": "请输入授权秘钥",
"updateCode": "重新绑定",
"notHaveAuth": "还没有授权?去购买",
"authInfoTips": "授权码和授权秘钥可在Niucloud官网我的授权 授权详情中查看",
"addonUninstall": "插件卸载",
"appIdentification": "应用标识",
"tipText": "标识指开发应用或插件的文件夹名称",
"uninstallTips": "是否要卸载该插件?",
"upgrade": "一键升级",
"newVersion": "最新版本",
"cloudBuild": "云编译",
"cloudBuildTips": "是否要进行云编译该操作可能会影响到正在访问的客户是否要继续操作?",
"deleteAddonTips": "删除插件会把插件目录连同文件全部删除,确定要删除吗?"
}

View File

@ -29,6 +29,7 @@
"continueSign": "连签天数",
"continueSignFormatError": "连签天数格式错误",
"continueSignBerweenDays": "连签天数为2-365天",
"continueSignMustLessThanSignPeriod": "连签天数不能大于签到周期",
"receiveLimit": "领取限制",
"noLimit": "不限制",
"everyOneLimit": "每人限领",

View File

@ -1,31 +1,31 @@
{
"hotelVerify": "订单核销",
"verifyRecord": "核销记录",
"verifyTime": "核销时间",
"orderNo": "订单编号",
"orderNoPlaceholder": "请输入订单编号",
"OrderInfo": "订单信息",
"buyerInfo": "购买人信息",
"verifyCode": "核销码",
"verifyCodePlaceholder": "请输入核销码",
"verifyer": "核销人",
"startDate": "开始时间",
"endDate": "结束时间",
"mobile": "联系方式",
"searchValueEmptyTips": "请输入搜索内容",
"verify": "核销",
"buyInfo": "预订信息",
"orderRefunding": "该订单正在维权中不能进行核销",
"verifyTips": "是否要核销该订单?",
"toOrder": "查看订单",
"verifyType": "核销类型",
"verifyTypePlaceholder": "请选择核销类型",
"verifier": "核销员",
"createTime":"添加时间",
"addVerifier":"添加核销员",
"verifierDeleteTips":"确定要删除该核销员吗?",
"memberInfo": "会员信息",
"memberIdPlaceholder": "请选择会员",
"member": "会员",
"searchPlaceholder": "请输入会员昵称搜索"
"hotelVerify": "订单核销",
"verifyRecord": "核销记录",
"verifyTime": "核销时间",
"orderNo": "订单编号",
"orderNoPlaceholder": "请输入订单编号",
"OrderInfo": "订单信息",
"buyerInfo": "购买人信息",
"verifyCode": "核销码",
"verifyCodePlaceholder": "请输入核销码",
"verifyer": "核销人",
"startDate": "开始时间",
"endDate": "结束时间",
"mobile": "联系方式",
"searchValueEmptyTips": "请输入搜索内容",
"verify": "核销",
"buyInfo": "预订信息",
"orderRefunding": "该订单正在维权中不能进行核销",
"verifyTips": "是否要核销该订单?",
"toOrder": "查看订单",
"verifyType": "核销类型",
"verifyTypePlaceholder": "请选择核销类型",
"verifier": "核销员",
"createTime": "添加时间",
"addVerifier": "添加核销员",
"verifierDeleteTips": "确定要删除该核销员吗?",
"memberInfo": "会员信息",
"memberIdPlaceholder": "请选择会员",
"member": "会员",
"searchPlaceholder": "请输入会员编号/昵称/手机号"
}

View File

@ -1,32 +1,32 @@
{
"hotelVerify": "订单核销",
"verifyRecord": "核销记录",
"verifyTime": "核销时间",
"orderNo": "订单编号",
"orderNoPlaceholder": "请输入订单编号",
"verifyInfo": "核销信息",
"buyerInfo": "购买人信息",
"verifyCode": "核销码",
"verifyCodePlaceholder": "请输入核销码",
"verifyer": "核销人",
"startDate": "开始时间",
"endDate": "结束时间",
"mobile": "联系方式",
"searchValueEmptyTips": "请输入搜索内容",
"verify": "核销",
"buyInfo": "预订信息",
"orderRefunding": "该订单正在维权中不能进行核销",
"verifyTips": "是否要核销该订单?",
"toOrder": "查看订单",
"verifyType": "核销类型",
"verifyTypePlaceholder": "请选择核销类型",
"verifier": "核销员",
"verifierPlaceholder": "请选择核销员",
"createTime":"添加时间",
"addVerifier":"添加核销员",
"verifierDeleteTips":"确定要删除该核销员吗?",
"memberInfo": "会员信息",
"memberIdPlaceholder": "请选择会员",
"member": "会员",
"searchPlaceholder": "请输入会员昵称搜索"
"hotelVerify": "订单核销",
"verifyRecord": "核销记录",
"verifyTime": "核销时间",
"orderNo": "订单编号",
"orderNoPlaceholder": "请输入订单编号",
"verifyInfo": "核销信息",
"buyerInfo": "购买人信息",
"verifyCode": "核销码",
"verifyCodePlaceholder": "请输入核销码",
"verifyer": "核销人",
"startDate": "开始时间",
"endDate": "结束时间",
"mobile": "联系方式",
"searchValueEmptyTips": "请输入搜索内容",
"verify": "核销",
"buyInfo": "预订信息",
"orderRefunding": "该订单正在维权中不能进行核销",
"verifyTips": "是否要核销该订单?",
"toOrder": "查看订单",
"verifyType": "核销类型",
"verifyTypePlaceholder": "请选择核销类型",
"verifier": "核销员",
"verifierPlaceholder": "请选择核销员",
"createTime": "添加时间",
"addVerifier": "添加核销员",
"verifierDeleteTips": "确定要删除该核销员吗?",
"memberInfo": "会员信息",
"memberIdPlaceholder": "请选择会员",
"member": "会员",
"searchPlaceholder": "请输入会员昵称搜索"
}

View File

@ -3,6 +3,6 @@
"type": "协议类型",
"titlePlaceholder": "请输入协议标题",
"contentPlaceholder": "请填写协议内容",
"contentMaxTips": "协议内容字符数应在5100000之间",
"contentMaxTips": "协议内容字符数应在510000之间",
"content": "内容"
}

View File

@ -1,35 +1,39 @@
{
"websiteInfo":"后台设置",
"contactAddress":"联系地址",
"siteName": "站点名称",
"keywords": "网站关键字",
"logo": "长方形Logo",
"desc": "网站简介",
"province": "省",
"city": "市",
"district": "区/县",
"selectAddress": "请选择地址",
"address": "详细地址",
"phone": "客服电话",
"businessHours": "营业时间",
"contactAddressPlaceholder":"联系地址",
"siteNamePlaceholder": "站点名称",
"keywordsPlaceholder": "网站关键字",
"descPlaceholder": "网站简介",
"addressPlaceholder": "详细地址",
"phonePlaceholder": "客服电话",
"businessHoursPlaceholder": "营业时间",
"businessHoursTips": "例上午9:00-12:00下午2:00-6:00",
"frontEndInfo": "前台设置",
"frontEndName": "前台名称",
"frontEndNamePlaceholder": "请输入前台名称",
"frontEndLogo": "前台Logo",
"icon": "正方形Logo",
"serviceInformation": "服务信息",
"wechatCode": "公众号二维码",
"customerServiceCode": "客服二维码",
"contactsTel": "联系电话",
"contactsTelPlaceholder": "请输入联系电话",
"logoPlaceholder": "建议图片尺寸210*30像素图片格式jpg、png、jpeg。",
"iconPlaceholder": "建议图片尺寸100*100像素图片格式jpg、png、jpeg。"
"websiteInfo": "后台设置",
"contactAddress": "联系地址",
"siteName": "站点名称",
"keywords": "网站关键字",
"logo": "长方形Logo",
"desc": "网站简介",
"province": "省",
"city": "市",
"district": "区/县",
"selectAddress": "请选择地址",
"address": "详细地址",
"phone": "客服电话",
"businessHours": "营业时间",
"contactAddressPlaceholder": "联系地址",
"siteNamePlaceholder": "站点名称",
"keywordsPlaceholder": "网站关键字",
"descPlaceholder": "网站简介",
"addressPlaceholder": "详细地址",
"phonePlaceholder": "客服电话",
"businessHoursPlaceholder": "营业时间",
"businessHoursTips": "例上午9:00-12:00下午2:00-6:00",
"frontEndInfo": "前台设置",
"frontEndName": "前台名称",
"frontEndNamePlaceholder": "请输入前台名称",
"frontEndLogo": "前台Logo",
"icon": "正方形Logo",
"serviceInformation": "服务信息",
"wechatCode": "公众号二维码",
"customerServiceCode": "客服二维码",
"contactsTel": "联系电话",
"contactsTelPlaceholder": "请输入联系电话",
"logoPlaceholder": "建议图片尺寸210*30像素图片格式jpg、png、jpeg。",
"iconPlaceholder": "建议图片尺寸100*100像素图片格式jpg、png、jpeg。",
"siteLoginLogo": "站点登录Logo",
"siteLoginLogoTips": "站点端登录Logo建议图片尺寸132*40像素图片格式jpg、png、jpeg。",
"siteLoginBgImg": "站点登录背景图",
"siteLoginBgImgTips": "站点端登录背景图建议图片尺寸1920*1280像素图片格式jpg、png、jpeg。"
}

View File

@ -28,6 +28,7 @@
"alipayPublicCertPathTips": "上传alipayCertPublicKey文件",
"alipayRootCertPathTips": "上传alipayRootCert文件",
"operationTip": "温馨提示:打款设置用于会员提现转账,发放红包等场景",
"transferTips":"注意:应微信方规定,在2025年1月15日前开通商家转账到零钱服务的商户号可正常使用转账功能,之后开通的不支持使用转账到零钱服务"
"transferTips":"注意:应微信方规定,在2025年1月15日前开通商家转账到零钱服务的商户号可正常使用转账功能,之后开通的不支持使用转账到零钱服务",
"wechatpayPublicCert": "微信支付公钥",
"wechatpayPublicCertId": "微信支付公钥ID"
}

View File

@ -0,0 +1,28 @@
{
"manualBackup": "手动备份",
"manualBackupTips": "即将开始手动备份您的源码和数据库,为确保备份过程中顺利进行以及数据的完整性,建议您暂停所有相关操作,避免因数据写入或修改导致备份不一致,是否确定继续?",
"id": "编号",
"content": "内容",
"currentVersion": "备份版本",
"contentPlaceholder": "请输入内容",
"batchDelete": "批量删除",
"backupDir": "备份路径",
"completeTime": "备份时间",
"restore": "恢复",
"restoreTips": "此操作将恢复备份的源码和数据库,并且覆盖当前数据。为避免意外损失,请确认已了解此操作的影响,并确保已备份重要信息,是否确定继续?",
"deleteTips": "删除记录将会同步删除其备份文件,确定要操作吗?",
"batchEmptySelectedTips": "请选择需要批量删除的记录",
"restoreTitle": "恢复备份",
"backupCompleteTips": "备份成功",
"restoreCompleteTips": "恢复成功",
"showDialogCloseTips": "任务尚未完成,关闭将会造成数据丢失或系统损坏的影响,是否要继续关闭?",
"manualBackupTitle": "手动备份",
"checkDirectoryPermissions": "检测目录权限",
"backupFiles": "备份文件",
"startUpgrade": "开始恢复",
"upgradeEnd": "恢复完成",
"startBackUp": "开始备份",
"backUpEnd": "备份完成",
"remark": "备注",
"remarkEmpty": "无"
}

View File

@ -0,0 +1,8 @@
{
"id": "编号",
"upgradeName": "内容",
"prevVersion": "前一版本",
"currentVersion": "版本",
"upgradeNamePlaceholder": "请输入内容",
"completeTime": "升级时间"
}

View File

@ -1,11 +1,15 @@
{
"groupName": "站点套餐",
"lastTime": "上次同步时间",
"weappVersionUpdate": "小程序同步",
"weappVersionUpdateRecord": "小程序同步记录",
"createTime": "提交时间",
"userVersion": "版本号",
"failReason": "失败原因",
"updateTips": "版本提交成功之后会自动给已授权的小程序进行同步更新,使用该功能必须要启动消息队列",
"seeUpdateRecord": "查看同步记录"
"groupName": "站点套餐",
"lastTime": "上次同步时间",
"weappVersionUpdate": "小程序同步",
"weappVersionUpdateRecord": "小程序同步记录",
"createTime": "提交时间",
"userVersion": "版本号",
"failReason": "失败原因",
"updateTips": " 1、同步小程序时系统通过已绑定的开发小程序同步至微信第三方平台的普通模板库中。\n 2、同步完成后系统将自动为站点套餐下已授权的小程序提交代码。\n 3、一键同步功能支持按所有站点套餐进行批量同步同时也可针对单个站点套餐单独操作。\n 4、使用此功能前请确保已启动消息队列服务。",
"seeUpdateRecord": "查看同步记录",
"commitRecord": "同步记录",
"oneClickSync": "一键同步",
"syncTemplateError": "未能同步到模板库",
"templateID": "模板ID"
}

View File

@ -2,47 +2,31 @@
<!--授权信息-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never" v-if="!loading">
<div class="flex">
<div class="w-[450px] mr-[20px] p-[50px] bg-[var(--el-color-info-light-9)]">
<div class="flex items-center justify-between">
<span class="text-page-title">版本信息</span>
<div class="flex-1 w-0 flex justify-end">
<el-button class="text-[#4C4C4C] w-[78px] h-[32px] !bg-transparent" @click="getFrameworkVersionListFn" v-if="!newVersion || (newVersion && newVersion.version_no == versions)">检测更新</el-button>
<el-button class="text-[#4C4C4C] w-[78px] h-[32px]" type="primary" @click="handleUpgrade" v-else>一键升级</el-button>
<el-button class="text-[#4C4C4C] w-[78px] h-[32px]" type="primary" @click="handleCloudBuild" :loading="cloudBuildRef?.loading">云编译</el-button>
</div>
</div>
<div class="mt-[30px] flex items-center text-[14px] text-[#797979]">
<span>当前版本</span>
<span class="text-[26px] ml-[15px] mr-[10px] text-[#656668]">{{versions}}</span>
<em class="text-[12px]" v-if="!newVersion || (newVersion && newVersion.version_no == versions)">(当前已是最新版本)</em>
<em class="text-[12px] text-[red]" v-else>(最新版本{{ newVersion.version_no }})</em>
</div>
</div>
<div class="flex flex-1 justify-between items-center p-[50px] bg-[var(--el-color-info-light-9)]">
<div>
<div class="text-[#333] text-[18px]">授权信息</div>
<div class="ml-[50px] mt-[40px]">
<div class="flex flex-col">
<div class="flex flex-wrap items-center">
<p class="text-page-title mr-[20px]">授权信息</p>
<span class="text-[14px] text-[#666]">{{ authinfo.company_name || '--' }}</span>
<span class="mr-[6px] text-[14px] text-[#666666] w-[70px] text-right">授权公司</span>
<span class="text-[14px] text-[#333]">{{ authinfo.company_name || "--" }}</span>
</div>
<div class="mt-[46px] ml-[40px] flex flex-wrap">
<span class="text-[14px] mr-[84px]">授权域名<em class="ml-[12px] text-[12px]">{{ authinfo.site_address || '--' }}</em></span>
<span class="text-[14px] flex items-center">
<span>授权码</span>
<em class="ml-[12px] mr-[10px] text-[12px]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : '--' }}</em>
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
<div class="flex flex-wrap items-center mt-[20px]">
<span class="mr-[6px] text-[14px] text-[#666666] w-[70px] text-right">授权域名</span>
<span class="text-[14px] text-[#333]">{{ authinfo.site_address || "--" }}</span>
</div>
<div class="flex flex-wrap items-center mt-[20px]">
<span class="mr-[6px] text-[14px] text-[#666666] w-[70px] text-right">授权码</span>
<span class="text-[14px] text-[#333]">
<span class="mr-[10px]">{{ authinfo.auth_code ? (isCheck ? authinfo.auth_code : hideAuthCode(authinfo.auth_code)) : "--" }}</span>
<el-icon v-if="!isCheck" @click="isCheck = !isCheck" class="text-[12px] cursor-pointer text-[#4383F9]">
<View />
</el-icon>
<el-icon v-else @click="isCheck = !isCheck" class="text-[12px] cursor-pointer">
<Hide />
</el-icon>
<el-icon v-else @click="isCheck = !isCheck" class="text-[12px] cursor-pointer text-[#4383F9]"> <Hide /> </el-icon>
</span>
</div>
</div>
<div class="flex flex-1 flex-wrap justify-end relative">
<el-button class="w-[154px] !h-[48px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
<div class="mt-[60px] mb-[50px]">
<el-button class="w-[150px] !h-[46px] mt-[8px]" type="primary" @click="authCodeApproveFn">授权码认证</el-button>
<el-popover ref="getAuthCodeDialog" placement="bottom-start" :width="478" trigger="click" class="mt-[8px]">
<div class="px-[18px] py-[8px]">
<p class="leading-[32px] text-[14px]">您在官方应用市场购买任意一款应用即可获得授权码输入正确授权码认证通过后即可支持在线升级和其它相关服务</p>
@ -52,7 +36,7 @@
</div>
</div>
<template #reference>
<el-button class="w-[154px] !h-[48px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent" plain type="primary">如何获取授权码?</el-button>
<el-button class="w-[150px] !h-[46px] mt-[8px] !text-[var(--el-color-primary)] hover:!text-[var(--el-color-primary)] !bg-transparent" plain type="primary">如何获取授权码?</el-button>
</template>
</el-popover>
</div>
@ -70,13 +54,13 @@
</el-form-item>
</div>
<div class="text-sm mt-[10px] text-info">{{ t('authInfoTips') }}</div>
<div class="text-sm mt-[10px] text-info">{{ t("authInfoTips") }}</div>
<div class="mt-[20px]">
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" @click="save(formRef)">{{ t('confirm') }}</el-button>
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" @click="save(formRef)">{{ t("confirm") }}</el-button>
</div>
<div class="mt-[10px] text-right">
<el-button type="primary" link @click="market">{{ t('notHaveAuth') }}</el-button>
<el-button type="primary" link @click="market">{{ t("notHaveAuth") }}</el-button>
</div>
</el-card>
</el-form>
@ -84,66 +68,24 @@
</div>
</div>
</el-card>
<el-card class="box-card !border-none " shadow="never" v-if="!loading">
<div class="text-page-title mb-[20px]">历史版本</div>
<el-timeline>
<el-timeline-item :timestamp="item['release_time'] + ' 版本:' + item['version_no']" v-for="(item,index) in frameworkVersionList" type="primary" :hollow="true" placement="top" :key="index">
<div class="mt-[10px] p-[20px] bg-overlay rounded-md timeline-log-wrap whitespace-pre-wrap" v-if="item['upgrade_log']">
<div v-html="item['upgrade_log']"></div>
</div>
</el-timeline-item>
</el-timeline>
</el-card>
<upgrade ref="upgradeRef" @cloudbuild="handleCloudBuild"/>
<cloud-build ref="cloudBuildRef" />
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, computed } from 'vue'
import { t } from '@/lang'
import { getVersions } from '@/app/api/auth'
import { getAuthInfo, setAuthInfo, getFrameworkVersionList } from '@/app/api/module'
import { ElMessageBox, FormInstance, FormRules,ElMessage } from 'element-plus'
import Upgrade from '@/app/components/upgrade/index.vue'
import CloudBuild from '@/app/components/cloud-build/index.vue'
import { cloneDeep } from 'lodash-es'
import { reactive, ref } from "vue"
import { t } from "@/lang"
import { getVersions } from "@/app/api/auth"
import { getAuthInfo, setAuthInfo } from "@/app/api/module"
import { FormInstance, FormRules } from "element-plus"
import { cloneDeep } from "lodash-es"
const upgradeRef = ref<any>(null)
const cloudBuildRef = ref<any>(null)
const getAuthCodeDialog: Record<string, any> | null = ref(null)
const authCodeApproveDialog = ref(false)
const isCheck = ref(false)
const frameworkVersionList = ref([])
const checkVersion = ref(false)
const getFrameworkVersionListFn = () => {
getFrameworkVersionList().then(({ data }) => {
frameworkVersionList.value = data
if (checkVersion.value) {
if (!newVersion.value || (newVersion.value && newVersion.value.version_no == versions.value)) {
ElMessage({
message: t('versionTips'),
type: 'success'
})
}
} else {
checkVersion.value = true
}
})
}
getFrameworkVersionListFn()
const newVersion:any = computed(() => {
return frameworkVersionList.value.length ? frameworkVersionList.value[0] : null
})
const hideAuthCode = (res:any) => {
const hideAuthCode = (res: any) => {
const authCode = cloneDeep(res)
const data = authCode.slice(0, authCode.length / 2) + authCode.slice(authCode.length / 2, authCode.length - 1).replace(/./g, '*')
const data = authCode.slice(0, authCode.length / 2) + authCode.slice(authCode.length / 2, authCode.length - 1).replace(/./g, "*")
return data
}
@ -152,15 +94,15 @@ const authCodeApproveFn = () => {
}
interface AuthInfo {
company_name: string,
site_address: string,
company_name: string
site_address: string
auth_code: string
}
const authinfo = ref<AuthInfo>({
company_name: '',
site_address: '',
auth_code: ''
company_name: "",
site_address: "",
auth_code: ""
})
const loading = ref(true)
const saveLoading = ref(false)
@ -180,25 +122,21 @@ const checkAppMange = () => {
checkAppMange()
const formData = reactive<Record<string, string>>({
auth_code: '',
auth_secret: ''
auth_code: "",
auth_secret: ""
})
const formRef = ref<FormInstance>()
//
const formRules = reactive<FormRules>({
auth_code: [
{ required: true, message: t('authCodePlaceholder'), trigger: 'blur' }
],
auth_secret: [
{ required: true, message: t('authSecretPlaceholder'), trigger: 'blur' }
]
auth_code: [{ required: true, message: t("authCodePlaceholder"), trigger: "blur" }],
auth_secret: [{ required: true, message: t("authSecretPlaceholder"), trigger: "blur" }]
})
const save = async (formEl: FormInstance | undefined) => {
const save = async(formEl: FormInstance | undefined) => {
if (saveLoading.value || !formEl) return
await formEl.validate(async (valid) => {
await formEl.validate(async(valid) => {
if (valid) {
saveLoading.value = true
@ -214,47 +152,16 @@ const save = async (formEl: FormInstance | undefined) => {
}
const market = () => {
window.open('https://www.niucloud.com/app')
window.open("https://www.niucloud.com/app")
}
const versions = ref('')
const versions = ref("")
const getVersionsInfo = () => {
getVersions().then(res => {
getVersions().then((res) => {
versions.value = res.data.version.version
})
}
getVersionsInfo()
/**
* 升级
*/
const handleUpgrade = () => {
if (!authinfo.value.auth_code) {
authCodeApproveFn()
return
}
upgradeRef.value?.open()
}
const handleCloudBuild = () => {
if (!authinfo.value.auth_code) {
authCodeApproveFn()
return
}
if (cloudBuildRef.value.cloudBuildTask) {
cloudBuildRef.value?.open()
return
}
ElMessageBox.confirm(t('cloudBuildTips'), t('warning'),
{
confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'),
type: 'warning'
}
).then(() => {
cloudBuildRef.value?.open()
})
}
</script>
<style lang="scss" scoped></style>

View File

@ -23,7 +23,7 @@
<div class="flex flex-col justify-between w-[180px]">
<div class="text-[14px] flex items-center">
<span class="app-text max-w-[170px]">{{ childItem.title }}</span>
<span class="iconfont iconxiaochengxu2 text-[#00b240] ml-[4px] !text-[14px]"></span>
<!-- <span class="iconfont iconxiaochengxu2 text-[#00b240] ml-[4px] !text-[14px]"></span>-->
</div>
<!-- <el-icon color="#666">
<QuestionFilled />
@ -68,7 +68,6 @@ const getAppList = async () => {
getAppList()
const toLink = (item: any) => {
console.log('tol', item)
if (item.url) {
router.push(item.url)
} else {

View File

@ -0,0 +1,195 @@
<template>
<!--授权信息-->
<div class="main-container">
<el-card class="box-card !border-none" shadow="never" v-if="newVersion">
<div>
<div class="mx-[20px] my-[20px]">
<div class="title text-[18px]">版本信息</div>
<div class="text-[18px] text-center mb-[7px] mt-[40px]">系统当前版本v{{ version }}{{ versionCode }}</div>
<div class="text-center text-[#666] text-[14px]" v-if="!newVersion || (newVersion && newVersion.version_no == version)">
<span>当前已是最新版本无需升级</span>
<span class="text-[14px] text-primary ml-[10px] cursor-pointer" @click="openUpgrade">更新说明</span>
</div>
<div class="text-[#666] text-[14px] text-center" v-else>
当前系统最新版本为 <span class="text-[18px] text-[#FF4D01]">v{{ newVersion.version_no }}</span>
<span class="text-[14px] text-primary ml-[10px]" style="cursor: pointer" @click="openUpgrade">更新说明</span>
</div>
<div class="mt-[30px] flex justify-center items-center">
<el-button class="text-[#4C4C4C] w-[150px] !h-[44px]" type="primary" :loading="loading" @click="handleUpgrade" v-if="!(!newVersion || (newVersion && newVersion.version_no == version))">一键升级</el-button>
<el-button class="text-[#4C4C4C] w-[130px] !h-[44px]" @click="upgradeRecord">升级记录</el-button>
</div>
</div>
</div>
</el-card>
<el-dialog v-model="authCodeApproveDialog" title="授权码认证" width="400px">
<el-form :model="formData" label-width="0" ref="formRef" :rules="formRules" class="page-form">
<el-card class="box-card !border-none" shadow="never">
<el-form-item prop="auth_code">
<el-input v-model.trim="formData.auth_code" :placeholder="t('authCodePlaceholder')" class="input-width" clearable size="large" />
</el-form-item>
<div class="mt-[20px]">
<el-form-item prop="auth_secret">
<el-input v-model.trim="formData.auth_secret" clearable :placeholder="t('authSecretPlaceholder')" class="input-width" size="large" />
</el-form-item>
</div>
<div class="text-sm mt-[10px] text-info">{{ t("authInfoTips") }}</div>
<div class="mt-[20px]">
<el-button type="primary" class="w-full" size="large" :loading="saveLoading" @click="save(formRef)">{{ t("confirm") }}</el-button>
</div>
<div class="mt-[10px] text-right">
<el-button type="primary" link @click="market">{{ t("notHaveAuth") }}</el-button>
</div>
</el-card>
</el-form>
</el-dialog>
<upgrade ref="upgradeRef" />
<upgrade-log ref="upgradeLogRef" />
</div>
</template>
<script lang="ts" setup>
import { ref, computed, reactive } from "vue"
import { t } from "@/lang"
import { getVersions } from "@/app/api/auth"
import { getAuthInfo, getFrameworkVersionList, setAuthInfo } from "@/app/api/module"
import { ElMessage, FormInstance, FormRules } from "element-plus"
import { useRouter } from "vue-router"
import Upgrade from "@/app/components/upgrade/index.vue"
import UpgradeLog from "@/app/components/upgrade-log/index.vue"
const upgradeRef = ref<any>(null)
const upgradeLogRef = ref<any>(null)
const authCodeApproveDialog = ref(false)
const frameworkVersionList = ref([])
const checkVersion = ref(false)
const formData = reactive<Record<string, string>>({
auth_code: '',
auth_secret: ''
})
const formRef = ref<FormInstance>()
//
const formRules = reactive<FormRules>({
auth_code: [{ required: true, message: t('authCodePlaceholder'), trigger: 'blur' }],
auth_secret: [{ required: true, message: t('authSecretPlaceholder'), trigger: 'blur' }]
})
const saveLoading = ref(false)
const save = async(formEl: FormInstance | undefined) => {
if (saveLoading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
saveLoading.value = true
setAuthInfo(formData).then(() => {
saveLoading.value = false
checkAppMange()
}).catch(() => {
saveLoading.value = false
authCodeApproveDialog.value = false
})
}
})
}
const getFrameworkVersionListFn = () => {
getFrameworkVersionList().then(({ data }) => {
frameworkVersionList.value = data
if (checkVersion.value) {
if (!newVersion.value || (newVersion.value && newVersion.value.version_no == version.value)) {
ElMessage({
message: t('versionTips'),
type: 'success'
})
}
} else {
checkVersion.value = true
}
})
}
getFrameworkVersionListFn()
const newVersion: any = computed(() => {
return frameworkVersionList.value.length ? frameworkVersionList.value[0] : null
})
const authCodeApproveFn = () => {
authCodeApproveDialog.value = true
}
const version = ref('')
const versionCode = ref('')
const getVersionsInfo = () => {
getVersions().then((res) => {
version.value = res.data.version.version
versionCode.value = res.data.version.code
})
}
getVersionsInfo()
interface AuthInfo {
company_name: string
site_address: string
auth_code: string
}
const authInfo = ref<AuthInfo>({
company_name: '',
site_address: '',
auth_code: ''
})
const repeat = ref(false)
const loading = ref(false)
/**
* 升级
*/
const handleUpgrade = () => {
if (!authInfo.value.auth_code) {
authCodeApproveFn()
return
}
if (repeat.value) return
repeat.value = true
loading.value = true
upgradeRef.value?.open('', () => {
repeat.value = false
loading.value = false;
})
}
const checkAppMange = () => {
getAuthInfo().then((res) => {
if (res.data.data && res.data.data.length != 0) {
authInfo.value = res.data.data
authCodeApproveDialog.value = false
}
}).catch(() => {
authCodeApproveDialog.value = false
})
}
checkAppMange()
const router = useRouter()
const upgradeRecord = () => {
router.push('/admin/tools/upgrade_records')
}
const openUpgrade = () => {
upgradeLogRef.value?.open()
}
</script>
<style lang="scss" scoped></style>

View File

@ -84,8 +84,8 @@ getMenuList()
//
const refreshMenu = () => {
ElMessageBox.confirm(h('div', null, [
h('p', null, t('initializeMenuTipsOne')),
h('p', null, t('initializeMenuTipsTwo')),
h('p', null, t('initializeMenuTipsOne')),
h('p', null, t('initializeMenuTipsTwo')),
]), t('warning'),
{
confirmButtonText: t('confirm'),
@ -97,8 +97,8 @@ const refreshMenu = () => {
location.reload()
}).catch(() => {
})
}).catch(()=>{})
}).catch(() => {
})
}
/**

View File

@ -132,8 +132,8 @@ getMenuList()
//
const refreshMenu = () => {
ElMessageBox.confirm(h('div', null, [
h('p', null, t('initializeMenuTipsOne')),
h('p', null, t('initializeMenuTipsTwo')),
h('p', null, t('initializeMenuTipsOne')),
h('p', null, t('initializeMenuTipsTwo')),
]), t('warning'),
{
confirmButtonText: t('confirm'),
@ -143,9 +143,10 @@ const refreshMenu = () => {
).then(() => {
menuRefresh({}).then(res => {
location.reload()
}).catch(() => {})
}).catch(()=>{})
}).catch(() => {
})
}).catch(() => {
})
}
/**
* 添加菜单

View File

@ -102,7 +102,6 @@ const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/aliapp')
const active = ref(2)
const qrCode = ref<string>('')
onMounted(async () => {
const res = await getAliappConfig()

View File

@ -116,7 +116,6 @@ const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/weapp')
const active = ref(2)
const qrCode = ref('')
const weappConfig = ref({})
const oplatformConfig = ref({})

View File

@ -106,7 +106,6 @@
import { computed, reactive, ref } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import Test from '@/utils/test'
import SettingList from './setting-list.vue'
import { getWeappPrivacySetting, setWeappPrivacySetting } from '@/app/api/weapp'

View File

@ -50,7 +50,7 @@
</el-form-item>
</el-card>
<el-card class="box-card !border-none mt-[15px]" shadow="never">
<el-card class="box-card !border-none mt-[15px]" shadow="never" v-show="!formData.is_authorization">
<h3 class="panel-title !text-sm">{{ t('theServerSetting') }}</h3>
<el-form-item label="URL">
@ -234,10 +234,10 @@ const formRules = computed(() => {
{ required: !formData.is_authorization, message: t('appSecretPlaceholder'), trigger: 'blur' }
],
token: [
{ required: true, message: t('tokenPlaceholder'), trigger: 'blur' }
{ required: !formData.is_authorization, message: t('tokenPlaceholder'), trigger: 'blur' }
],
encoding_aes_key: [
{ required: true, message: t('encodingAesKeyPlaceholder'), trigger: 'blur' }
{ required: !formData.is_authorization, message: t('encodingAesKeyPlaceholder'), trigger: 'blur' }
]
}
})

View File

@ -1,12 +1,12 @@
<template>
<!--配置教程-->
<div class="main-container">
<div class="main-container">
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="card !border-none" shadow="never">
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
</el-card>
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<el-card class="box-card mt-[15px] !border-none" shadow="never">
<div class="flex">
<div class="min-w-[60px]">
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
@ -51,8 +51,8 @@
</div>
</div>
</div>
</el-card>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>

View File

@ -104,7 +104,6 @@ const router = useRouter()
const pageName = route.meta.title
const activeName = ref('/channel/wechat')
const active = ref(2)
const qrcode = ref('')
const wechatConfig = ref({})
const oplatformConfig = ref({})

View File

@ -24,11 +24,7 @@
</div>
<div class="py-[20px] px-[30px] h-[350px]">
<div v-if="formData.msgtype == 'text'">
<el-input
v-model.trim="formData.text.content" :rows="5" type="textarea" placeholder="" maxlength="600" :show-word-limit="true"
resize="none"
input-style="box-shadow: none;height:300px"
/>
<el-input v-model.trim="formData.text.content" :rows="5" type="textarea" placeholder="" maxlength="600" :show-word-limit="true" resize="none" input-style="box-shadow: none;height:300px" />
</div>
<div v-if="formData.msgtype == 'image'" class="flex w-full h-full justify-center items-center image-media">
<div class="w-full h-full" v-if="formData.image.url">

View File

@ -14,7 +14,9 @@
</upload-media>
</div>
<div class="flex" v-else>
<el-button type="primary" :loading="syncLoading" @click="syncWechatNews">{{ syncLoading ? '同步中' : '同步微信图文'}}</el-button>
<el-button type="primary" :loading="syncLoading" @click="syncWechatNews">
{{ syncLoading ? '同步中' : '同步微信图文' }}
</el-button>
</div>
</el-col>
</el-row>
@ -23,8 +25,10 @@
<!-- 素材管理 -->
<div v-if="attachment.data.length">
<div class="flex flex-wrap" v-if="prop.type != 'news'">
<div class="attachment-item mr-[10px] mb-[10px] w-[120px]" v-for="(item, index) in attachment.data" :key="index" @click="selectedFile = item">
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
<div class="attachment-item mr-[10px] mb-[10px] w-[120px]"
v-for="(item, index) in attachment.data" :key="index" @click="selectedFile = item">
<div
class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
<el-image :src="img(item.value)" fit="contain" v-if="type == 'image'" :preview-src-list="item.image_list" />
<video :src="img(item.value)" v-else-if="type == 'video'"></video>
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60" v-show="selectedFile.id == item.id">
@ -34,12 +38,14 @@
</div>
</div>
<div class="relative" ref="waterfallContainerRef" v-else>
<div ref="waterfallItemRef" class="absolute attachment-item mr-[10px] mb-[10px] w-[280px] rounded-lg overflow-hidden border border-color" v-for="(item, index) in attachment.data"
<div ref="waterfallItemRef"
class="absolute attachment-item mr-[10px] mb-[10px] w-[280px] rounded-lg overflow-hidden border border-color"
v-for="(item, index) in attachment.data"
:style="{ left: listPosition[index] ? listPosition[index].left : '', top: listPosition[index] ? listPosition[index].top : '' }"
:key="index" @click="selectedFile = item">
<div class="relative">
<div class="w-full h-[130px] relative">
<el-image :src="item.value.news_item[0].thumb_url" class="w-full h-full"/>
<el-image :src="item.value.news_item[0].thumb_url" class="w-full h-full" />
<div class="absolute left-0 bottom-0 p-[10px] w-full truncate text-white leading-none" v-if="item.value.news_item.length > 1">
{{ item.value.news_item[0].title }}
</div>
@ -47,18 +53,14 @@
<div v-if="item.value.news_item.length > 1">
<template v-for="(newsItem, newsIndex) in item.value.news_item">
<div class="px-[15px] py-[10px] flex" :class="{'border-b border-color' : newsIndex < item.value.news_item.length - 1 }" v-if="newsIndex > 0">
<div class="flex-1 w-0 truncate">
{{ newsItem.title }}
</div>
<div class="flex-1 w-0 truncate">{{ newsItem.title }}</div>
<div class="w-[50px] h-[50px] ml-[10px]">
<el-image :src="newsItem.thumb_url" class="w-full h-full"/>
<el-image :src="newsItem.thumb_url" class="w-full h-full" />
</div>
</div>
</template>
</div>
<div class="px-[15px] py-[10px]" v-else>
{{ item.value.news_item[0].title }}
</div>
<div class="px-[15px] py-[10px]" v-else>{{ item.value.news_item[0].title }}</div>
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60" v-show="selectedFile.id == item.id">
<icon name="element Select" color="#fff" size="40px" />
</div>
@ -75,9 +77,9 @@
<el-col span="24">
<div class="flex h-full justify-end items-center">
<el-pagination v-model:current-page="attachment.page" :small="true"
v-model:page-size="attachment.limit" :page-sizes="[10, 20, 30, 40, 60]"
layout="total, sizes, prev, pager, next, jumper" :total="attachment.total"
@size-change="getAttachmentList()" @current-change="getAttachmentList" />
v-model:page-size="attachment.limit" :page-sizes="[10, 20, 30, 40, 60]"
layout="total, sizes, prev, pager, next, jumper" :total="attachment.total"
@size-change="getAttachmentList()" @current-change="getAttachmentList" />
</div>
</el-col>
</el-row>
@ -94,118 +96,118 @@
</template>
<script lang="ts" setup>
import { reactive, ref, nextTick } from 'vue'
import { t } from '@/lang'
import UploadMedia from './upload-media.vue'
import { img, debounce } from '@/utils/common'
import { getMediaList, syncNews } from '@/app/api/wechat'
import { reactive, ref, nextTick } from 'vue'
import { t } from '@/lang'
import UploadMedia from './upload-media.vue'
import { img, debounce } from '@/utils/common'
import { getMediaList, syncNews } from '@/app/api/wechat'
const prop = defineProps({
type: {
type: String,
default: 'image'
}
})
const prop = defineProps({
type: {
type: String,
default: 'image'
}
})
const showDialog = ref(false)
const showDialog = ref(false)
const openDialog = () => {
const openDialog = () => {
prop.type == 'news' && waterfall()
showDialog.value = true
}
const attachment: Record<string, any> = reactive({
loading: true,
page: 1,
total: 0,
limit: 10,
data: []
})
/**
* 查询素材
*/
const getAttachmentList = (page: number = 1) => {
attachment.loading = true
attachment.page = page
getMediaList({
page: attachment.page,
limit: attachment.limit,
type: prop.type
}).then(res => {
attachment.data = res.data.data
attachment.total = res.data.total
attachment.loading = false
prop.type == 'news' && waterfall()
showDialog.value = true
}
const attachment: Record<string, any> = reactive({
loading: true,
page: 1,
total: 0,
limit: 10,
data: []
}).catch(() => {
attachment.loading = false
})
}
getAttachmentList()
/**
* 查询素材
*/
const getAttachmentList = (page: number = 1) => {
attachment.loading = true
attachment.page = page
getMediaList({
page: attachment.page,
limit: attachment.limit,
type: prop.type
}).then(res => {
attachment.data = res.data.data
attachment.total = res.data.total
attachment.loading = false
prop.type == 'news' && waterfall()
}).catch(() => {
attachment.loading = false
})
}
getAttachmentList()
const emits = defineEmits(['success'])
const selectedFile: Record<string, any> = ref({})
const emits = defineEmits(['success'])
const selectedFile: Record<string, any> = ref({})
const confirm = () => {
emits('success', selectedFile.value)
}
const confirm = () => {
emits('success', selectedFile.value)
}
const syncLoading = ref(false)
const syncWechatNews = () => {
if (syncLoading.value) return
syncLoading.value = true
const syncLoading = ref(false)
const syncWechatNews = () => {
if (syncLoading.value) return
syncLoading.value = true
syncNews().then(() => {
syncLoading.value = false
getAttachmentList()
}).catch(() => {
syncLoading.value = false
})
}
syncNews().then(() => {
syncLoading.value = false
getAttachmentList()
}).catch(() => {
syncLoading.value = false
})
}
const meta = document.createElement('meta')
meta.content = 'same-origin'
meta.name = 'referrer'
document.getElementsByTagName('head')[0].appendChild(meta)
const meta = document.createElement('meta')
meta.content = 'same-origin'
meta.name = 'referrer'
document.getElementsByTagName('head')[0].appendChild(meta)
//
const waterfallContainerRef = ref(null)
const waterfallItemRef = ref([])
const listPosition = ref([])
const waterfall = debounce(() => {
nextTick(() => {
const containerWidth = waterfallContainerRef.value.clientWidth
const column = parseInt(containerWidth / 292)
const heights = []
const positions = []
//
const waterfallContainerRef = ref(null)
const waterfallItemRef = ref([])
const listPosition = ref([])
const waterfall = debounce(() => {
nextTick(() => {
const containerWidth = waterfallContainerRef.value.clientWidth
const column = parseInt(containerWidth / 292)
const heights = []
const positions = []
waterfallItemRef.value.forEach((item, i) => {
if (i < column) {
const position = {}
position.top = '0px'
if (i % column == 0) {
position.left = item.clientWidth * i + "px"
} else {
position.left = item.clientWidth * i + (i % column * 10) + "px"
}
positions[i] = position
heights[i] = item.clientHeight + 10
waterfallItemRef.value.forEach((item, i) => {
if (i < column) {
const position = {}
position.top = '0px'
if (i % column == 0) {
position.left = item.clientWidth * i + "px"
} else {
let minHeight = Math.min(...heights) //
let minIndex = heights.findIndex(item => item === minHeight) //
let position = {}
position.top = minHeight + 10 + "px"
position.left = positions[minIndex].left
positions[i] = position
heights[minIndex] += item.clientHeight + 10
position.left = item.clientWidth * i + (i % column * 10) + "px"
}
})
listPosition.value = positions
positions[i] = position
heights[i] = item.clientHeight + 10
} else {
let minHeight = Math.min(...heights) //
let minIndex = heights.findIndex(item => item === minHeight) //
let position = {}
position.top = minHeight + 10 + "px"
position.left = positions[minIndex].left
positions[i] = position
heights[minIndex] += item.clientHeight + 10
}
})
}, 800)
listPosition.value = positions
})
}, 800)
//
window.addEventListener('resize', () => waterfall())
//
window.addEventListener('resize', () => waterfall())
</script>
<style lang="scss" scoped>

View File

@ -83,8 +83,7 @@
<el-form-item :label="t('businessDomain')">
<el-input :model-value="wechatStatic.business_domain" placeholder="Please input" class="input-width" :readonly="true">
<template #append>
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
</div>
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}</div>
</template>
</el-input>
</el-form-item>
@ -92,8 +91,7 @@
<el-form-item :label="t('jsSecureDomain')">
<el-input :model-value="wechatStatic.js_secure_domain" placeholder="Please input" class="input-width" :readonly="true">
<template #append>
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
</div>
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}</div>
</template>
</el-input>
</el-form-item>
@ -101,8 +99,7 @@
<el-form-item :label="t('webAuthDomain')">
<el-input :model-value="wechatStatic.web_auth_domain" placeholder="Please input" class="input-width" :readonly="true">
<template #append>
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}
</div>
<div class="cursor-pointer" @click="copyEvent(wechatStatic.business_domain)">{{ t('copy') }}</div>
</template>
</el-input>
</el-form-item>

View File

@ -12,9 +12,7 @@
<span class="flex justify-center items-center block w-[40px] h-[40px] border-[1px] border-primary rounded-[999px] text-primary">1</span>
</div>
<div>
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}--<el-button link type="primary"
@click="linkEvent">{{ t('writingTipsOne2') }}</el-button>, {{ t('writingTipsOne3') }}<span
class="text-primary">URL / Token / EncondingAESKey</span>{{ t('writingTipsOne4') }}</p>
<p class="flex items-center text-[14px]">{{ t('writingTipsOne1') }}--<el-button link type="primary" @click="linkEvent">{{ t('writingTipsOne2') }}</el-button>, {{ t('writingTipsOne3') }}<span class="text-primary">URL / Token / EncondingAESKey</span>{{ t('writingTipsOne4') }}</p>
<div class="w-[100%] mt-[10px]">
<img class="w-[100%]" src="@/app/assets/images/setting/wechat_1.png" />
</div>

View File

@ -83,7 +83,7 @@
import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { getKeywordsReplyInfo, editKeywordsReply, addKeywordsReply } from '@/app/api/wechat'
import { ElMessage, FormInstance, FormRules } from 'element-plus'
import { FormInstance, FormRules } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
import ReplyForm from '@/app/views/channel/wechat/components/reply-form.vue'

View File

@ -110,60 +110,6 @@ const setFormData = async (row: any = null) => {
loading.value = false
}
//
const mobileVerify = (rule: any, value: any, callback: any) => {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error(t('generateMobile')))
} else {
callback()
}
}
//
const idCardVerify = (rule: any, value: any, callback: any) => {
if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
callback(new Error(t('generateIdCard')))
} else {
callback()
}
}
//
const emailVerify = (rule: any, value: any, callback: any) => {
if (value && !/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(value)) {
callback(new Error(t('generateEmail')))
} else {
callback()
}
}
// 1
const minInputVerify = (rule: any, value: any, callback: any) => {
if (value && !/^\d{0,}$/.test(value)) {
callback(new Error(t('generateMin')))
} else {
callback()
}
}
// 150
const maxInputVerify = (rule: any, value: any, callback: any) => {
if (value && !/^\d{0,150}$/.test(value)) {
callback(new Error(t('generateMax')))
} else {
callback()
}
}
//
const numberVerify = (rule: any, value: any, callback: any) => {
if (!Number.isInteger(value)) {
callback(new Error(t('generateNumber')))
} else {
callback()
}
}
defineExpose({
showDialog,
setFormData

View File

@ -27,19 +27,15 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import { getAreaListByPid } from '@/app/api/sys'
import { addMemberAddress } from '@/app/api/member'
import { filterNumber } from '@/utils/common'
import type { FormInstance } from 'element-plus'
import { FormRules } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
const dialogThemeVisible = ref(false)
let confirmRepeat = false
const confirmRepeat = ref(false)
const emit = defineEmits(['confirm'])
/**
* 表单数据
@ -73,35 +69,50 @@ const open = (option:any) => {
const formRef = ref<FormInstance>()
//
const formRules = reactive<FormRules>({
title: [
{ required: true, message: "请输入颜色名称", trigger: 'blur' }
],
value: [
{ required: true, message: "请输入颜色value值", trigger: 'blur' }
],
label: [
{ required: true, message: "请输入颜色key值", trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
const regex = /^[a-zA-Z0-9-]+$/
if (keyArr.indexOf(value) != -1) {
callback('新增颜色key值与已存在颜色key值命名重复请修改命名')
} if (!regex.test(value)) {
callback('颜色key值只能输入字母、数字和连字符')
} else{
callback();
}
},
trigger: 'blur'
}
]
const formRules = computed(() => {
return {
title: [
{ required: true, message: "请输入颜色名称", trigger: 'blur' }
],
value: [
{
required: true,
validator: (rule: any, value: any, callback: any) => {
if (!value) {
callback('请输入颜色value值')
} else{
callback();
}
},
trigger: ['blur', 'change']
}
],
label: [
{ required: true, message: "请输入颜色key值", trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
const regex = /^[a-zA-Z0-9-]+$/
if (keyArr.indexOf(value) != -1) {
callback('新增颜色key值与已存在颜色key值命名重复请修改命名')
} if (!regex.test(value)) {
callback('颜色key值只能输入字母、数字和连字符')
} else{
callback();
}
},
trigger: 'blur'
}
]
}
})
const confirmFn = async (formEl: FormInstance | undefined) => {
if (confirmRepeat || !formEl) return
await formEl.validate(async (valid) => {
if (confirmRepeat.value) return
await formRef.value?.validate(async (valid) => {
if (confirmRepeat.value) return
confirmRepeat.value = true
if (valid) {
confirmRepeat.value = false
emit('confirm', cloneDeep(formData));
dialogThemeVisible.value = false;
}

View File

@ -1,102 +1,109 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showTitleStyle">{{ diyStore.editComponent.titleStyle.title }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
<el-form-item :label="t('title')" v-if="diyStore.editComponent && diyStore.editComponent.titleStyle && diyStore.editComponent.titleStyle.value != 'style-5'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showTitleStyle">{{ diyStore.editComponent.titleStyle.title }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
<el-form-item :label="t('title')" v-if="diyStore.editComponent && diyStore.editComponent.titleStyle && diyStore.editComponent.titleStyle.value != 'style-5'">
<el-input v-model.trim="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('image')" v-else>
<upload-image v-model="diyStore.editComponent.textImg" :limit="1"/>
<upload-image v-model="diyStore.editComponent.textImg" :limit="1" />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.textLink"/>
<diy-link v-model="diyStore.editComponent.textLink" />
</el-form-item>
<el-form-item :label="t('subTitle')">
<el-input v-model.trim="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.subTitle.link"/>
<diy-link v-model="diyStore.editComponent.subTitle.link" />
</el-form-item>
</el-form>
</el-form>
<el-dialog v-model="showTitleDialog" :title="t('selectStyle')" width="460px">
<el-dialog v-model="showTitleDialog" :title="t('selectStyle')" width="460px">
<div class="flex flex-wrap">
<template v-for="(item,index) in titleStyleList" :key="index">
<div :class="{ 'border-primary': selectTitleStyle.value == item.value }" @click="changeTitleStyle(item)" class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]">
<img :src="img(item.url)" />
</div>
</template>
</div>
<div class="flex flex-wrap">
<template v-for="(item,index) in titleStyleList" :key="index">
<div :class="{ 'border-primary': selectTitleStyle.value == item.value }"
@click="changeTitleStyle(item)"
class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]">
<img :src="img(item.url)" />
</div>
</template>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showTitleDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmTitleStyle">{{ t('confirm') }}</el-button>
</span>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="showTitleDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmTitleStyle">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</el-dialog>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('activeCubeBlockContent') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('activeCubeBlockContent') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showBlockStyle">{{ diyStore.editComponent.blockStyle.title }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer"
@click="showBlockStyle">{{ diyStore.editComponent.blockStyle.title }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
<el-dialog v-model="showListDialog" :title="t('selectStyle')" width="600px">
<div class="flex flex-wrap">
<template v-for="(item,index) in blockStyleList" :key="index">
<div :class="{ 'border-primary': selectBlockStyle.value == item.value }" @click="changeBlockStyle(item)" class="flex items-center justify-center overflow-hidden w-[250px] h-[150px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]">
<img :src="img(item.url)" />
</div>
</template>
<el-dialog v-model="showListDialog" :title="t('selectStyle')" width="600px">
<div class="flex flex-wrap">
<template v-for="(item,index) in blockStyleList" :key="index">
<div :class="{ 'border-primary': selectBlockStyle.value == item.value }"
@click="changeBlockStyle(item)"
class="flex items-center justify-center overflow-hidden w-[250px] h-[150px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]">
<img :src="img(item.url)" />
</div>
</template>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showListDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmBlockStyle">{{ t('confirm') }}</el-button>
</span>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="showListDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmBlockStyle">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</el-dialog>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
<div ref="blockBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1"/>
</el-form-item>
<div ref="blockBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id"
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" />
</el-form-item>
<el-form-item :label="t('activeCubeTitle')">
<el-input v-model.trim="item.title.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
</el-form-item>
<el-form-item :label="t('activeCubeTitle')">
<el-input v-model.trim="item.title.text" :placeholder="t('activeCubeTitlePlaceholder')"
clearable maxlength="4" show-word-limit />
</el-form-item>
<el-form-item :label="t('activeCubeSubTitleTextColor')" v-show="diyStore.editComponent.blockStyle.value == 'style-3'">
<el-color-picker v-model="item.title.textColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('activeCubeSubTitle')" v-if="diyStore.editComponent.blockStyle.value != 'style-3'">
<el-input v-model.trim="item.subTitle.text" :placeholder="t('activeCubeSubTitlePlaceholder')" clearable maxlength="6" show-word-limit/>
</el-form-item>
<el-form-item :label="t('activeCubeSubTitle')" v-if="diyStore.editComponent.blockStyle.value != 'style-3'">
<el-input v-model.trim="item.subTitle.text" :placeholder="t('activeCubeSubTitlePlaceholder')" clearable maxlength="6" show-word-limit />
</el-form-item>
<div v-show="diyStore.editComponent.blockStyle.value == 'style-4'">
<el-form-item :label="t('activeCubeSubTitleTextColor')">
@ -104,99 +111,105 @@
</el-form-item>
<el-form-item :label="t('activeCubeSubTitleBgColor')">
<el-color-picker v-model="item.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="item.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</div>
<el-form-item :label="t('activeListFrameColor')">
<el-color-picker v-model="item.listFrame.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.listFrame.endColor" show-alpha :predefine="diyStore.predefineColors"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="item.listFrame.endColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<div v-show="diyStore.editComponent.blockStyle.value != 'style-4' && diyStore.editComponent.blockStyle.value != 'style-3'">
<div
v-show="diyStore.editComponent.blockStyle.value != 'style-4' && diyStore.editComponent.blockStyle.value != 'style-3'">
<el-form-item :label="t('activeCubeButton')">
<el-input v-model.trim="item.moreTitle.text" :placeholder="t('activeCubeButtonPlaceholder')" clearable maxlength="3" show-word-limit/>
<el-input v-model.trim="item.moreTitle.text" :placeholder="t('activeCubeButtonPlaceholder')" clearable maxlength="3" show-word-limit />
</el-form-item>
<el-form-item :label="t('activeCubeButtonColor')">
<el-color-picker v-model="item.moreTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.moreTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="item.moreTitle.endColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="item.link" />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
</div>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.list.length > 1"
@click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
</div>
</div>
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addItem">{{ t('activeCubeAddItem') }}</el-button>
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addItem">
{{ t('activeCubeAddItem') }}
</el-button>
</el-form>
</div>
</el-form>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap" v-if="selectTitleStyle.value != 'style-5'">
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.titleColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-if="selectTitleStyle.value != 'style-5'">
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.titleColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('subTitleStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors"/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('subTitleStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.textColor" show-alpha
:predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="diyStore.editComponent.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('activeCubeBlockStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('activeCubeBlockTextFontWeight')">
<el-radio-group v-model="diyStore.editComponent.blockStyle.fontWeight">
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
</el-radio-group>
</el-form-item>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('activeCubeBlockStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('activeCubeBlockTextFontWeight')">
<el-radio-group v-model="diyStore.editComponent.blockStyle.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('activeCubeBlockBtnText')" class="flex">
<el-radio-group v-model="diyStore.editComponent.blockStyle.btnText">
<el-radio :label="'normal'">{{t('btnTextNormal')}}</el-radio>
<el-radio :label="'italics'">{{t('btnTextItalics')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<el-radio-group v-model="diyStore.editComponent.blockStyle.btnText">
<el-radio :label="'normal'">{{ t('btnTextNormal') }}</el-radio>
<el-radio :label="'italics'">{{ t('btnTextItalics') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -215,7 +228,7 @@ diyStore.editComponent.ignore = [] // 忽略公共属性
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if(diyStore.value[index].text == ''){
if (diyStore.value[index].text == '') {
res.code = false
res.message = t('activeCubeTitlePlaceholder')
return res
@ -232,14 +245,14 @@ diyStore.editComponent.verify = (index: number) => {
res.message = t('activeCubeTitlePlaceholder')
return res
}
if(['style-1','style-2','style-4'].indexOf(diyStore.value[index].blockStyle.value) != -1){
if (['style-1', 'style-2', 'style-4'].indexOf(diyStore.value[index].blockStyle.value) != -1) {
if (item.subTitle.text === '') {
res.code = false
res.message = t('activeCubeSubTitlePlaceholder')
return res
}
}
if(['style-1','style-2'].indexOf(diyStore.value[index].blockStyle.value) != -1){
if (['style-1', 'style-2'].indexOf(diyStore.value[index].blockStyle.value) != -1) {
if (item.moreTitle.text === '') {
res.code = false
res.message = t('activeCubeButtonPlaceholder')
@ -258,33 +271,33 @@ diyStore.editComponent.list.forEach((item: any) => {
const showTitleDialog = ref(false)
const showTitleStyle = () => {
selectTitleStyle.title = diyStore.editComponent.titleStyle.title;
selectTitleStyle.value = diyStore.editComponent.titleStyle.value;
selectTitleStyle.title = diyStore.editComponent.titleStyle.title;
selectTitleStyle.value = diyStore.editComponent.titleStyle.value;
showTitleDialog.value = true
}
const titleStyleList = reactive([
{
url : 'static/resource/images/diy/active_cube/title_style1.png',
title:'风格1',
value:'style-1'
},{
url : 'static/resource/images/diy/active_cube/title_style2.png',
title:'风格2',
value:'style-2'
},{
url : 'static/resource/images/diy/active_cube/title_style3.png',
title:'风格3',
value:'style-3'
},{
url : 'static/resource/images/diy/active_cube/title_style5.png',
title:'风格4',
value:'style-4'
},{
url : 'static/resource/images/diy/active_cube/title_style6.png',
title:'风格5',
value:'style-5'
}
{
url: 'static/resource/images/diy/active_cube/title_style1.png',
title: '风格1',
value: 'style-1'
}, {
url: 'static/resource/images/diy/active_cube/title_style2.png',
title: '风格2',
value: 'style-2'
}, {
url: 'static/resource/images/diy/active_cube/title_style3.png',
title: '风格3',
value: 'style-3'
}, {
url: 'static/resource/images/diy/active_cube/title_style5.png',
title: '风格4',
value: 'style-4'
}, {
url: 'static/resource/images/diy/active_cube/title_style6.png',
title: '风格5',
value: 'style-5'
}
])
const selectTitleStyle = reactive({
@ -292,7 +305,7 @@ const selectTitleStyle = reactive({
value: diyStore.editComponent.titleStyle.value
})
const changeTitleStyle = (item:any) => {
const changeTitleStyle = (item: any) => {
selectTitleStyle.title = item.title;
selectTitleStyle.value = item.value;
}
@ -304,28 +317,28 @@ const confirmTitleStyle = () => {
showTitleDialog.value = false
}
const initTitleStyle = (style)=>{
if(diyStore.editComponent.titleStyle.value == 'style-1'){
const initTitleStyle = (style) => {
if (diyStore.editComponent.titleStyle.value == 'style-1') {
diyStore.editComponent.titleColor = "#F91700";
diyStore.editComponent.subTitle.textColor = "#FFFFFF";
diyStore.editComponent.subTitle.startColor = "#FB792F";
diyStore.editComponent.subTitle.endColor = "#F91700";
}else if(diyStore.editComponent.titleStyle.value == 'style-2'){
} else if (diyStore.editComponent.titleStyle.value == 'style-2') {
diyStore.editComponent.titleColor = "#F91700";
diyStore.editComponent.subTitle.textColor = "#FFFFFF";
diyStore.editComponent.subTitle.startColor = "#FB792F";
diyStore.editComponent.subTitle.endColor = "#F91700";
}else if(diyStore.editComponent.titleStyle.value == 'style-3'){
} else if (diyStore.editComponent.titleStyle.value == 'style-3') {
diyStore.editComponent.titleColor = "#F91700";
diyStore.editComponent.subTitle.textColor = "#FFFFFF";
diyStore.editComponent.subTitle.startColor = "#FB792F";
diyStore.editComponent.subTitle.endColor = "#F91700";
}else if(diyStore.editComponent.titleStyle.value == 'style-4'){
} else if (diyStore.editComponent.titleStyle.value == 'style-4') {
diyStore.editComponent.titleColor = "#FFFFFF";
diyStore.editComponent.subTitle.textColor = "#333333";
diyStore.editComponent.subTitle.startColor = "#FFFFFF";
diyStore.editComponent.subTitle.endColor = "#FFFFFF";
}else if(diyStore.editComponent.titleStyle.value == 'style-5'){
} else if (diyStore.editComponent.titleStyle.value == 'style-5') {
diyStore.editComponent.titleColor = "";
diyStore.editComponent.subTitle.textColor = "#999999";
diyStore.editComponent.subTitle.startColor = "#FFFFFF";
@ -342,24 +355,24 @@ const showBlockStyle = () => {
const blockStyleList = reactive([
{
url : 'static/resource/images/diy/active_cube/block_style1.png',
title:'风格1',
value:'style-1'
url: 'static/resource/images/diy/active_cube/block_style1.png',
title: '风格1',
value: 'style-1'
},
{
url : 'static/resource/images/diy/active_cube/block_style2.png',
title:'风格2',
value:'style-2'
url: 'static/resource/images/diy/active_cube/block_style2.png',
title: '风格2',
value: 'style-2'
},
{
url : 'static/resource/images/diy/active_cube/block_style3.png',
title:'风格3',
value:'style-3'
url: 'static/resource/images/diy/active_cube/block_style3.png',
title: '风格3',
value: 'style-3'
},
{
url : 'static/resource/images/diy/active_cube/block_style4.png',
title:'风格4',
value:'style-4'
url: 'static/resource/images/diy/active_cube/block_style4.png',
title: '风格4',
value: 'style-4'
}
])
@ -368,7 +381,7 @@ const selectBlockStyle = reactive({
value: diyStore.editComponent.blockStyle.value
})
const changeBlockStyle = (item:any) => {
const changeBlockStyle = (item: any) => {
selectBlockStyle.title = item.title;
selectBlockStyle.value = item.value;
}
@ -380,8 +393,8 @@ const confirmBlockStyle = () => {
showListDialog.value = false
}
const initBlockStyle = (style: any)=>{
if(style == 'style-1'){
const initBlockStyle = (style: any) => {
if (style == 'style-1') {
diyStore.editComponent.blockStyle.fontWeight = "normal";
diyStore.editComponent.blockStyle.btnText = "normal";
@ -421,7 +434,7 @@ const initBlockStyle = (style: any)=>{
diyStore.editComponent.list[3].listFrame.startColor = "#FFFAF5";
diyStore.editComponent.list[3].listFrame.endColor = "#FFFFFF";
}else if(style == 'style-2'){
} else if (style == 'style-2') {
diyStore.editComponent.blockStyle.fontWeight = "normal";
diyStore.editComponent.blockStyle.btnText = "normal";
@ -463,7 +476,7 @@ const initBlockStyle = (style: any)=>{
diyStore.editComponent.list[3].moreTitle.endColor = "#F91700";
diyStore.editComponent.list[3].listFrame.startColor = "#FFEAEA";
diyStore.editComponent.list[3].listFrame.endColor = "#FFFCFB";
}else if(style == 'style-3'){
} else if (style == 'style-3') {
diyStore.editComponent.blockStyle.fontWeight = "normal";
diyStore.editComponent.blockStyle.btnText = "normal";
@ -502,7 +515,7 @@ const initBlockStyle = (style: any)=>{
diyStore.editComponent.list[3].moreTitle.endColor = "";
diyStore.editComponent.list[3].listFrame.startColor = "";
diyStore.editComponent.list[3].listFrame.endColor = "";
}else if(style == 'style-4'){
} else if (style == 'style-4') {
diyStore.editComponent.blockStyle.fontWeight = "bold";
diyStore.editComponent.blockStyle.btnText = "normal";
@ -547,24 +560,24 @@ const initBlockStyle = (style: any)=>{
const addItem = () => {
diyStore.editComponent.list.push({
id: diyStore.generateRandom(),
title:{
title:'标题',
title: {
title: '标题',
textColor: "#000000"
},
subTitle:{
text:'副标题',
subTitle: {
text: '副标题',
textColor: "#999999",
startColor:'',
endColor:''
startColor: '',
endColor: ''
},
listFrame: {
startColor: "#4AC1FF",
endColor: "#1D7CFF"
},
moreTitle:{
text:'去看看',
startColor:'#FEA715',
endColor:'#FE1E00'
moreTitle: {
text: '去看看',
startColor: '#FEA715',
endColor: '#FE1E00'
},
imageUrl: '',
link: { name: '' }

View File

@ -1,105 +1,106 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchShowPosition') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchShowWay')">
<el-radio-group v-model="diyStore.editComponent.positionWay">
<el-radio label="static">{{ t('carouselSearchShowWayStatic') }}</el-radio>
<el-radio label="fixed">{{ t('carouselSearchShowWayFixed') }}</el-radio>
</el-radio-group>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchShowPosition') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchShowWay')">
<el-radio-group v-model="diyStore.editComponent.positionWay">
<el-radio label="static">{{ t('carouselSearchShowWayStatic') }}</el-radio>
<el-radio label="fixed">{{ t('carouselSearchShowWayFixed') }}</el-radio>
</el-radio-group>
<div v-if="diyStore.editComponent.positionWay == 'fixed'" class="text-sm text-gray-400 mb-[10px]">滑动页面查看效果</div>
</el-form-item>
<el-form-item :label="t('carouselSearchFixedBgColor')" v-show="diyStore.editComponent.positionWay == 'fixed'">
<el-color-picker v-model="diyStore.editComponent.fixedBgColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form-item>
<el-form-item :label="t('carouselSearchFixedBgColor')" v-show="diyStore.editComponent.positionWay == 'fixed'">
<el-color-picker v-model="diyStore.editComponent.fixedBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('carouselSearchBgGradient')">
<el-radio-group v-model="diyStore.editComponent.bgGradient">
<el-radio :label="true">{{ t('carouselSearchOpen') }}</el-radio>
<el-radio :label="false">{{ t('carouselSearchClose') }}</el-radio>
</el-radio-group>
<el-radio :label="true">{{ t('carouselSearchOpen') }}</el-radio>
<el-radio :label="false">{{ t('carouselSearchClose') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchSet') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showSearchStyle">{{ diyStore.editComponent.search.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchSet') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showSearchStyle">{{ diyStore.editComponent.search.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
<el-form-item :label="t('carouselSearchSubTitle')" v-if="diyStore.editComponent.search.style == 'style-2'">
<el-input v-model.trim="diyStore.editComponent.search.subTitle.text" :placeholder="t('carouselSearchSubTitlePlaceholder')" clearable maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('logo')">
<upload-image v-model="diyStore.editComponent.search.logo" :limit="1" />
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchLogoTips') }}</div>
</el-form-item>
<el-form-item :label="t('carouselSearchText')">
<div>
</el-form-item>
<el-form-item :label="t('logo')">
<upload-image v-model="diyStore.editComponent.search.logo" :limit="1" />
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchLogoTips') }}</div>
</el-form-item>
<el-form-item :label="t('carouselSearchText')">
<div>
<el-input v-model.trim="diyStore.editComponent.search.text" :placeholder="t('carouselSearchPlaceholder')" clearable maxlength="20" show-word-limit />
<p class="text-sm text-gray-400 mt-[10px] leading-[1.5]">{{t('carouselSearchTextTips')}}</p>
<p class="text-sm text-gray-400 mt-[10px] leading-[1.5]">{{ t('carouselSearchTextTips') }}</p>
</div>
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.search.link"/>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.search.link" />
</el-form-item>
</el-form>
<el-dialog v-model="showSearchDialog" :title="t('selectStyle')" width="500px">
<div class="flex flex-wrap">
<template v-for="(item,index) in searchStyleList" :key="index">
<div :class="{ 'border-primary': selectSearchStyle.value == item.value }" @click="changeSearchStyle(item)" class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] m-[6px] cursor-pointer border bg-[#eee]">
<img :src="img(item.url)" />
</div>
</template>
</div>
<div class="flex flex-wrap">
<template v-for="(item,index) in searchStyleList" :key="index">
<div :class="{ 'border-primary': selectSearchStyle.value == item.value }" @click="changeSearchStyle(item)" class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] m-[6px] cursor-pointer border bg-[#eee]">
<img :src="img(item.url)" />
</div>
</template>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showSearchDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmSearchStyle">{{ t('confirm') }}</el-button>
</span>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="showSearchDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmSearchStyle">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</el-dialog>
</div>
<div class="edit-attr-item-wrap mb-[20px]">
<h3 class="mb-[10px]">{{ t('carouselSearchHotWordSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<div class="edit-attr-item-wrap mb-[20px]">
<h3 class="mb-[10px]">{{ t('carouselSearchHotWordSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchHotWordInterval')">
<el-slider v-model="diyStore.editComponent.search.hotWord.interval" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
</el-form-item>
<el-form-item :label="t('carouselSearchHotWordInterval')">
<el-slider v-model="diyStore.editComponent.search.hotWord.interval" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10" />
</el-form-item>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
<div ref="searchHotWordTabBoxRef">
<div v-for="(item,index) in diyStore.editComponent.search.hotWord.list" :key="item.id" class="item-wrap p-[10px] relative border border-dashed border-gray-300 mb-[16px]">
<div ref="searchHotWordTabBoxRef">
<div v-for="(item,index) in diyStore.editComponent.search.hotWord.list" :key="item.id"
class="item-wrap p-[10px] relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('carouselSearchHotWordText')" class="!mb-0">
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchHotWordTextPlaceholder')" clearable maxlength="4" show-word-limit/>
</el-form-item>
<el-form-item :label="t('carouselSearchHotWordText')" class="!mb-0">
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchHotWordTextPlaceholder')" clearable maxlength="4" show-word-limit />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" @click="diyStore.editComponent.search.hotWord.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" @click="diyStore.editComponent.search.hotWord.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
</div>
<el-button v-show="diyStore.editComponent.search.hotWord.list.length < 50" class="w-full" @click="addHotWordItem">{{ t('carouselSearchAddHotWordItem') }}</el-button>
</div>
</div>
<el-button v-show="diyStore.editComponent.search.hotWord.list.length < 50" class="w-full" @click="addHotWordItem">{{ t('carouselSearchAddHotWordItem') }}</el-button>
</div>
</el-form>
</div>
</el-form>
</div>
<el-collapse v-model="activeNames" @change="handleChange" class="collapse-wrap">
<el-collapse v-model="activeNames" @change="handleChange" class="collapse-wrap">
<el-collapse-item :title="t('carouselSearchTabSet')" name="tab">
<div class="edit-attr-item-wrap">
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
@ -113,7 +114,7 @@
<div v-for="(item,index) in diyStore.editComponent.tab.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('carouselSearchTabCategoryText')">
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchTabCategoryTextPlaceholder')" clearable maxlength="4" show-word-limit/>
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchTabCategoryTextPlaceholder')" clearable maxlength="4" show-word-limit />
</el-form-item>
<el-form-item :label="t('dataSources')">
@ -131,8 +132,10 @@
</el-input>
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.tab.list.length > 1" @click="diyStore.editComponent.tab.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.tab.list.length > 1"
@click="diyStore.editComponent.tab.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
</div>
@ -141,7 +144,9 @@
<!-- 选择微页面弹出框 -->
<el-dialog v-model="diyPageShowDialog" :title="t('selectSourcesDiyPage')" width="1000px" :close-on-press-escape="true" :destroy-on-close="true" :close-on-click-modal="false">
<el-table :data="diyPageTable.data" ref="diyPageTableRef" size="large" v-loading="diyPageTable.loading" height="490px" @current-change="handleCurrentDiyPageChange" row-key="id" highlight-current-row>
<el-table :data="diyPageTable.data" ref="diyPageTableRef" size="large"
v-loading="diyPageTable.loading" height="490px"
@current-change="handleCurrentDiyPageChange" row-key="id" highlight-current-row>
<template #empty>
<span>{{ !diyPageTable.loading ? t('emptyData') : '' }}</span>
</template>
@ -150,9 +155,11 @@
<el-table-column prop="type_name" :label="t('diyPageForAddon')" min-width="80" />
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination v-model:current-page="diyPageTable.page" v-model:page-size="diyPageTable.limit"
layout="total, sizes, prev, pager, next, jumper" :total="diyPageTable.total"
@size-change="loadDiyPageList" @current-change="loadDiyPageList" />
<el-pagination v-model:current-page="diyPageTable.page"
v-model:page-size="diyPageTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="diyPageTable.total"
@size-change="loadDiyPageList" @current-change="loadDiyPageList" />
</div>
<div class="flex items-center justify-end mt-[15px]">
<el-button type="primary" @click="saveDiyPageId">{{ t('confirm') }}</el-button>
@ -169,144 +176,151 @@
<el-switch v-model="diyStore.editComponent.swiper.control" />
</el-form-item>
<el-form-item :label="t('carouselSearchSwiperInterval')">
<el-slider v-model="diyStore.editComponent.swiper.interval" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
<el-slider v-model="diyStore.editComponent.swiper.interval" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10" />
</el-form-item>
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchSwiperTips') }}</div>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.swiper.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<div v-for="(item,index) in diyStore.editComponent.swiper.list" :key="item.id"
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.swiper.list.length > 1" @click="diyStore.editComponent.swiper.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.swiper.list.length > 1"
@click="diyStore.editComponent.swiper.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
<diy-link v-model="item.link" />
</el-form-item>
</div>
</div>
<el-button v-show="diyStore.editComponent.swiper.list.length < 10" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
<el-button v-show="diyStore.editComponent.swiper.list.length < 10" class="w-full"
@click="addImageAd">{{ t('addImageAd') }}
</el-button>
</el-form>
</el-collapse-item>
</el-collapse>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap" v-if="diyStore.editComponent.search.style == 'style-2'">
<h3 class="mb-[10px]">{{ t('carouselSearchPositionStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchTextColor')">
<el-color-picker v-model="diyStore.editComponent.search.positionColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
<h3 class="mb-[10px]">{{ t('carouselSearchPositionStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchTextColor')">
<el-color-picker v-model="diyStore.editComponent.search.positionColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-if="diyStore.editComponent.search.style == 'style-2'">
<h3 class="mb-[10px]">{{ t('carouselSearchSubTitleStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchTextColor')">
<el-color-picker v-model="diyStore.editComponent.search.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('carouselSearchBgColor')">
<el-color-picker v-model="diyStore.editComponent.search.subTitle.startColor" :predefine="diyStore.predefineColors" show-alpha/>
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.search.subTitle.endColor" :predefine="diyStore.predefineColors" show-alpha/>
</el-form-item>
</el-form>
</div>
<h3 class="mb-[10px]">{{ t('carouselSearchSubTitleStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchTextColor')">
<el-color-picker v-model="diyStore.editComponent.search.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('carouselSearchBgColor')">
<el-color-picker v-model="diyStore.editComponent.search.subTitle.startColor" :predefine="diyStore.predefineColors" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="diyStore.editComponent.search.subTitle.endColor" :predefine="diyStore.predefineColors" show-alpha />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchTextColor')">
<el-color-picker v-model="diyStore.editComponent.search.color" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('carouselSearchBgColor')">
<el-color-picker v-model="diyStore.editComponent.search.bgColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('carouselSearchBtnColor')">
<el-color-picker v-model="diyStore.editComponent.search.btnColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('carouselSearchBtnBgColor')">
<el-color-picker v-model="diyStore.editComponent.search.btnBgColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
<h3 class="mb-[10px]">{{ t('carouselSearchStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchTextColor')">
<el-color-picker v-model="diyStore.editComponent.search.color" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('carouselSearchBgColor')">
<el-color-picker v-model="diyStore.editComponent.search.bgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('carouselSearchBtnColor')">
<el-color-picker v-model="diyStore.editComponent.search.btnColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('carouselSearchBtnBgColor')">
<el-color-picker v-model="diyStore.editComponent.search.btnBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchTabStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('noColor')">
<el-color-picker v-model="diyStore.editComponent.tab.noColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('selectColor')">
<el-color-picker v-model="diyStore.editComponent.tab.selectColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('fixedNoColor')">
<el-color-picker v-model="diyStore.editComponent.tab.fixedNoColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('fixedSelectColor')">
<el-color-picker v-model="diyStore.editComponent.tab.fixedSelectColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchTabStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('noColor')">
<el-color-picker v-model="diyStore.editComponent.tab.noColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('selectColor')">
<el-color-picker v-model="diyStore.editComponent.tab.selectColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('fixedNoColor')">
<el-color-picker v-model="diyStore.editComponent.tab.fixedNoColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('fixedSelectColor')">
<el-color-picker v-model="diyStore.editComponent.tab.fixedSelectColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchSwiperStyle')" @change="changeSwiperStyle">
<el-radio-group v-model="diyStore.editComponent.swiper.swiperStyle">
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.swiper.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.swiper.bottomRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<el-radio-group v-model="diyStore.editComponent.swiper.swiperStyle">
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.swiper.topRounded" show-input size="small"
class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.swiper.bottomRounded" show-input size="small"
class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperIndicatorSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchSwiperIndicatorStyle')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorAlign">
<el-radio label="left">{{ t('alignLeft') }}</el-radio>
<el-radio label="center">{{ t('alignCenter') }}</el-radio>
<el-radio label="right">{{ t('alignRight') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('selectColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorActiveColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperIndicatorSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchSwiperIndicatorStyle')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorAlign">
<el-radio label="left">{{ t('alignLeft') }}</el-radio>
<el-radio label="center">{{ t('alignCenter') }}</el-radio>
<el-radio label="right">{{ t('alignRight') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('selectColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorActiveColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<!-- <slot name="style"></slot> -->
</div>
<!-- 组件样式 -->
<!-- <slot name="style"></slot> -->
</div>
</template>
@ -317,19 +331,19 @@ import useDiyStore from '@/stores/modules/diy'
import { ref, reactive, watch, onMounted, nextTick } from 'vue'
import { ElTable } from 'element-plus'
import Sortable from 'sortablejs'
import { range,cloneDeep } from 'lodash-es'
import { range, cloneDeep } from 'lodash-es'
import { getDiyPageListByCarouselSearch } from '@/app/api/diy'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['componentBgColor','componentBgUrl','marginTop','marginBottom','topRounded','bottomRounded','pageBgColor','marginBoth'] //
diyStore.editComponent.ignore = ['componentBgColor', 'componentBgUrl', 'marginTop', 'marginBottom', 'topRounded', 'bottomRounded', 'pageBgColor', 'marginBoth'] //
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
diyStore.value[index].search.hotWord.list.forEach((item: any) => {
if(item.text == ''){
if (item.text == '') {
res.code = false
res.message = t('carouselSearchHotWordTextPlaceholder')
return res
@ -337,7 +351,7 @@ diyStore.editComponent.verify = (index: number) => {
});
diyStore.value[index].tab.list.forEach((item: any) => {
if(item.text == ''){
if (item.text == '') {
res.code = false
res.message = t('carouselSearchTabCategoryTextPlaceholder')
return res
@ -349,9 +363,9 @@ diyStore.editComponent.verify = (index: number) => {
// }
});
if(diyStore.value[index].swiper.control){
if (diyStore.value[index].swiper.control) {
diyStore.value[index].swiper.list.forEach((item: any) => {
if(item.imageUrl == ''){
if (item.imageUrl == '') {
res.code = false
res.message = t('imageUrlTip')
return res
@ -376,7 +390,7 @@ const showSearchStyle = () => {
selectSearchStyle.value = diyStore.editComponent.search.style;
}
const changeSearchStyle = (item:any) => {
const changeSearchStyle = (item: any) => {
selectSearchStyle.title = item.title;
selectSearchStyle.value = item.value;
}
@ -415,7 +429,8 @@ diyStore.editComponent.swiper.list.forEach((item: any) => {
})
const activeNames = ref(['tab', 'swiper'])
const handleChange = (val: string[]) => {}
const handleChange = (val: string[]) => {
}
onMounted(() => {
loadDiyPageList()
@ -424,11 +439,11 @@ onMounted(() => {
const addHotWordItem = () => {
diyStore.editComponent.search.hotWord.list.push({
id: diyStore.generateRandom(),
text : '关键词',
text: '关键词',
})
}
const tabClear = (index:any) => {
const tabClear = (index: any) => {
diyStore.editComponent.tab.list[index].diy_id = 0;
diyStore.editComponent.tab.list[index].diy_title = '';
}
@ -436,10 +451,10 @@ const tabClear = (index:any) => {
const addTabItem = () => {
diyStore.editComponent.tab.list.push({
id: diyStore.generateRandom(),
text : '分类名称', // 4
source : 'diy_page', // diy_page
diy_id : '',
diy_title : ''
text: '分类名称', // 4
source: 'diy_page', // diy_page
diy_id: '',
diy_title: ''
})
}
@ -507,8 +522,7 @@ const diyPageTable = reactive({
total: 0,
loading: true,
data: [],
searchParam: {
}
searchParam: {}
})
const diyPageTableRef = ref<InstanceType<typeof ElTable>>()
@ -552,7 +566,7 @@ const loadDiyPageList = (page: number = 1) => {
}
//
let currDiyPage:any = {}
let currDiyPage: any = {}
let currTabIndexForDiyPage = 0;
const handleCurrentDiyPageChange = (val: string | any[]) => {
currDiyPage = val
@ -564,7 +578,7 @@ const saveDiyPageId = () => {
diyPageShowDialog.value = false
}
const diyPageShowDialogOpen = (index:any) => {
const diyPageShowDialogOpen = (index: any) => {
diyPageShowDialog.value = true
currTabIndexForDiyPage = index;
if (currDiyPage) {
@ -593,28 +607,28 @@ const addImageAd = () => {
})
}
const selectImg = (url:string) => {
const selectImg = (url: string) => {
handleHeight(true)
}
const changeSwiperStyle = (value:any) => {
const changeSwiperStyle = (value: any) => {
handleHeight(true)
}
//
const handleHeight = (isCalcHeight:boolean = false)=> {
const handleHeight = (isCalcHeight: boolean = false) => {
diyStore.editComponent.swiper.list.forEach((item: any, index: number) => {
const image = new Image()
image.src = img(item.imageUrl)
image.onload = async () => {
image.onload = async() => {
item.imgWidth = image.width
item.imgHeight = image.height
//
if (isCalcHeight && index == 0) {
const ratio = item.imgHeight / item.imgWidth
if(diyStore.editComponent.swiper.swiperStyle == 'style-1') {
if (diyStore.editComponent.swiper.swiperStyle == 'style-1') {
item.width = 375 * 0.92 // 0.92
}else{
} else {
item.width = 355
}
item.height = item.width * ratio
@ -630,12 +644,13 @@ defineExpose({})
<style lang="scss" scoped></style>
<style lang="scss">
.select-diy-page-input .el-input__inner{
cursor: pointer;
}
.collapse-wrap{
.el-collapse-item__header{
font-size: 16px;
}
}
.select-diy-page-input .el-input__inner {
cursor: pointer;
}
.collapse-wrap {
.el-collapse-item__header {
font-size: 16px;
}
}
</style>

View File

@ -1,8 +1,8 @@
<template>
<!-- 内容 -->
<div class="content-wrap float-btn" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap float-btn" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<div class="edit-attr-item-wrap">
<!-- <h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex">
@ -28,63 +28,68 @@
</template>
</el-dialog> -->
<h3 class="mb-[10px]">{{ t('floatBtnButton') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('floatBtnButton')">
<span>{{ selectTemplate.name }}</span>
<h3 class="mb-[10px]">{{ t('floatBtnButton') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('floatBtnButton')">
<span>{{ selectTemplate.name }}</span>
<ul class="ml-[10px] flex items-center">
<template v-for="(item,i) in templateList" :key="i">
<li v-if="diyStore.editComponent.style==='style-1'||(diyStore.editComponent.style==='style-2'&&i>1)" :class="['w-[50px] h-[32px] flex items-center justify-center border-solid border-[1px] border-[#eee] cursor-pointer', {'border-r-transparent': templateList.length != (i+1)}, (item.className == diyStore.editComponent.bottomPosition) ? '!border-[var(--el-color-primary)]' : '' ]" @click="changeTemplateList(item)">
<li v-if="diyStore.editComponent.style==='style-1'||(diyStore.editComponent.style==='style-2'&&i>1)"
:class="['w-[50px] h-[32px] flex items-center justify-center border-solid border-[1px] border-[#eee] cursor-pointer', {'border-r-transparent': templateList.length != (i+1)}, (item.className == diyStore.editComponent.bottomPosition) ? '!border-[var(--el-color-primary)]' : '' ]"
@click="changeTemplateList(item)">
<span :class="['iconfont !text-[20px]', item.src]"></span>
</li>
</template>
</ul>
</el-form-item>
</el-form-item>
<el-form-item :label="t('floatBtnOffset')">
<el-slider v-model="diyStore.editComponent.offset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100"/>
</el-form-item>
<el-slider v-model="diyStore.editComponent.offset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
</el-form-item>
<el-form-item :label="t('lateralBtnOffset')">
<el-slider v-model="diyStore.editComponent.lateralOffset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="15" :min="-10"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('floatBtnImageSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-slider v-model="diyStore.editComponent.lateralOffset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="15" :min="-10" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('floatBtnImageSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('floatBtnImageSize')">
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="30" :max="100"/>
</el-form-item>
<el-form-item :label="t('floatBtnAroundRadius')">
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
</el-form-item>
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="30" :max="100" />
</el-form-item>
<el-form-item :label="t('floatBtnAroundRadius')">
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<div class="text-[12px] text-[#999] mb-[15px] mt-[5px]">{{t('floatBtnImageSuggest')}}</div>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" />
</el-form-item>
<div class="text-[12px] text-[#999] mb-[15px] mt-[5px]">{{ t('floatBtnImageSuggest') }}</div>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id"
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.list.length > 1"
@click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
</el-form-item>
</div>
</div>
</el-form>
<el-form-item :label="t('link')">
<diy-link v-model="item.link" />
</el-form-item>
</div>
</div>
</el-form>
<el-button v-show="diyStore.editComponent.list.length < 3" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
</div>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -94,10 +99,10 @@ import { t } from '@/lang'
import Sortable from 'sortablejs'
import useDiyStore from '@/stores/modules/diy'
import { img } from '@/utils/common'
import { min, range } from 'lodash-es'
import { range } from 'lodash-es'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['pageBgColor','marginTop','marginBottom','marginBoth','componentBgUrl'] //
diyStore.editComponent.ignore = ['pageBgColor', 'marginTop', 'marginBottom', 'marginBoth', 'componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {
@ -137,7 +142,7 @@ const showCouponStyle = () => {
// }
// ])
//
const changeCouponStyle = (item:any) => {
const changeCouponStyle = (item: any) => {
selectCouponStyle.title = item.title;
selectCouponStyle.value = item.value;
}

View File

@ -1,145 +1,150 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('graphicNavModeTitle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('graphicNavModeTitle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('layoutMode')">
<el-radio-group v-model="diyStore.editComponent.layout">
<el-radio :label="'horizontal'">{{t('layoutModeHorizontal')}}</el-radio>
<el-radio :label="'vertical'">{{t('layoutModeVertical')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('layoutMode')">
<el-radio-group v-model="diyStore.editComponent.layout">
<el-radio :label="'horizontal'">{{ t('layoutModeHorizontal') }}</el-radio>
<el-radio :label="'vertical'">{{ t('layoutModeVertical') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('graphicNavSelectMode')">
<el-radio-group v-model="diyStore.editComponent.mode">
<el-radio :label="'graphic'">{{t('graphicNavModeGraphic')}}</el-radio>
<el-radio :label="'img'">{{t('graphicNavModeImg')}}</el-radio>
<el-radio :label="'text'">{{t('graphicNavModeText')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('graphicNavSelectMode')">
<el-radio-group v-model="diyStore.editComponent.mode">
<el-radio :label="'graphic'">{{ t('graphicNavModeGraphic') }}</el-radio>
<el-radio :label="'img'">{{ t('graphicNavModeImg') }}</el-radio>
<el-radio :label="'text'">{{ t('graphicNavModeText') }}</el-radio>
</el-radio-group>
</el-form-item>
<view v-show="diyStore.editComponent.layout == 'horizontal'">
<view v-show="diyStore.editComponent.layout == 'horizontal'">
<el-form-item :label="t('graphicNavPageCount')">
<el-radio-group v-model="diyStore.editComponent.pageCount" @change="changePageCount">
<el-radio :label="1">{{t('singleLine')}}</el-radio>
<el-radio :label="2">{{t('multiline')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('graphicNavPageCount')">
<el-radio-group v-model="diyStore.editComponent.pageCount" @change="changePageCount">
<el-radio :label="1">{{ t('singleLine') }}</el-radio>
<el-radio :label="2">{{ t('multiline') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('graphicNavShowStyle')">
<el-radio-group v-model="diyStore.editComponent.showStyle" @change="changeShowStyle">
<el-radio :label="'fixed'">{{t('graphicNavStyleFixed')}}</el-radio>
<el-radio :label="'singleSlide'">{{diyStore.editComponent.pageCount == 2 ? t('graphicNavStyleMultiLine') : t('graphicNavStyleSingleSlide')}}</el-radio>
<el-radio :label="'pageSlide'">{{t('graphicNavStylePageSlide')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('graphicNavShowStyle')">
<el-radio-group v-model="diyStore.editComponent.showStyle" @change="changeShowStyle">
<el-radio :label="'fixed'">{{ t('graphicNavStyleFixed') }}</el-radio>
<el-radio :label="'singleSlide'">{{ diyStore.editComponent.pageCount == 2 ? t('graphicNavStyleMultiLine') : t('graphicNavStyleSingleSlide') }}</el-radio>
<el-radio :label="'pageSlide'">{{ t('graphicNavStylePageSlide') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('graphicNavRowCount')">
<el-radio-group v-model="diyStore.editComponent.rowCount">
<el-radio :label="3">3{{t('piece')}}</el-radio>
<el-radio :label="4">4{{t('piece')}}</el-radio>
<el-radio :label="5">5{{t('piece')}}</el-radio>
</el-radio-group>
</el-form-item>
</view>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('graphicNavSetLabel') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('graphicNavRowCount')">
<el-radio-group v-model="diyStore.editComponent.rowCount">
<el-radio :label="3">3{{ t('piece') }}</el-radio>
<el-radio :label="4">4{{ t('piece') }}</el-radio>
<el-radio :label="5">5{{ t('piece') }}</el-radio>
</el-radio-group>
</el-form-item>
</view>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('graphicNavSetLabel') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<p class="text-sm text-gray-400 mb-[10px]">{{ t('graphicNavTips') }}</p>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('graphicNavTips') }}</p>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'img'">
<upload-image v-model="item.imageUrl" :limit="1"/>
</el-form-item>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id"
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'img'">
<upload-image v-model="item.imageUrl" :limit="1" />
</el-form-item>
<el-form-item :label="t('graphicNavTitle')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'text'">
<el-input v-model.trim="item.title" :placeholder="t('graphicNavTitlePlaceholder')" clearable maxlength="20" show-word-limit/>
</el-form-item>
<el-form-item :label="t('graphicNavTitle')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'text'">
<el-input v-model.trim="item.title" :placeholder="t('graphicNavTitlePlaceholder')" clearable maxlength="20" show-word-limit />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.list.length > 1"
@click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
</el-form-item>
</div>
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link" />
</el-form-item>
</div>
</div>
<el-button v-show="diyStore.editComponent.list.length < 50" class="w-full" @click="addGraphicNav">{{ t('addGraphicNav') }}</el-button>
<el-button v-show="diyStore.editComponent.list.length < 50" class="w-full" @click="addGraphicNav">
{{ t('addGraphicNav') }}
</el-button>
</el-form>
</div>
</div>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap" v-show="['graphic','img'].includes(diyStore.editComponent.mode)">
<h3 class="mb-[10px]">{{ t('graphicNavImageSet') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('graphicNavImageSize')">
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="20" :max="60"/>
</el-form-item>
<el-form-item :label="t('graphicNavAroundRadius')">
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="['graphic','text'].includes(diyStore.editComponent.mode)">
<h3 class="mb-[10px]">{{ t('textSet') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.font.size" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16"/>
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.font.weight">
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.font.color" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap" v-show="['graphic','img'].includes(diyStore.editComponent.mode)">
<h3 class="mb-[10px]">{{ t('graphicNavImageSet') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('graphicNavImageSize')">
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="20" :max="60" />
</el-form-item>
<el-form-item :label="t('graphicNavAroundRadius')">
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="['graphic','text'].includes(diyStore.editComponent.mode)">
<h3 class="mb-[10px]">{{ t('textSet') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.font.size" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.font.weight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.font.color" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.showStyle == 'pageSlide' && diyStore.editComponent.layout == 'horizontal'">
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperIndicatorSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchSwiperIndicatorStyle')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorAlign">
<el-radio label="left">{{ t('alignLeft') }}</el-radio>
<el-radio label="center">{{ t('alignCenter') }}</el-radio>
<el-radio label="right">{{ t('alignRight') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('selectColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorActiveColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
</el-form>
</div>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.showStyle == 'pageSlide' && diyStore.editComponent.layout == 'horizontal'">
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperIndicatorSet') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('carouselSearchSwiperIndicatorStyle')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorAlign">
<el-radio label="left">{{ t('alignLeft') }}</el-radio>
<el-radio label="center">{{ t('alignCenter') }}</el-radio>
<el-radio label="right">{{ t('alignRight') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('selectColor')">
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorActiveColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
@ -184,7 +189,7 @@ watch(
diyStore.editComponent.list.forEach((item: any) => {
const image = new Image()
image.src = img(item.imageUrl)
image.onload = async () => {
image.onload = async() => {
item.imgWidth = image.width
item.imgHeight = image.height
}
@ -232,31 +237,31 @@ onMounted(() => {
})
})
const changePageCount = (value:any)=>{
if(value == '1'){
const changePageCount = (value: any) => {
if (value == '1') {
diyStore.editComponent.showStyle = 'singleSlide';
}else if(value == '2'){
} else if (value == '2') {
diyStore.editComponent.showStyle = 'fixed';
}
}
}
defineExpose({})
</script>
<style lang="scss" scoped>
.edit-graphic-nav {
.edit-graphic-nav {
.item-wrap {
.del {
display: none;
}
.item-wrap {
.del {
display: none;
}
&:hover {
.del {
display: block;
}
}
}
}
&:hover {
.del {
display: block;
}
}
}
}
</style>

View File

@ -1,22 +1,22 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('blankHeightSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('blankHeight')">
<el-slider v-model="diyStore.editComponent.height" show-input size="small" max="200" class="ml-[10px] diy-nav-slider"/>
</el-form-item>
</el-form>
</div>
</div>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('blankHeightSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('blankHeight')">
<el-slider v-model="diyStore.editComponent.height" show-input size="small" max="200" class="ml-[10px] diy-nav-slider" />
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>

View File

@ -1,31 +1,32 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('horzLineStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('styleLabel')">
<el-radio-group v-model="diyStore.editComponent.borderStyle">
<el-radio label="solid">{{ t('horzLineStyleSolid') }}</el-radio>
<el-radio label="dashed">{{ t('horzLineStyleDashed') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('horzLineBorderColor')">
<el-color-picker v-model="diyStore.editComponent.borderColor" show-alpha :predefine="diyStore.predefineColors"/>
</el-form-item>
<el-form-item :label="t('horzLineBorderWidth')">
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
</el-form-item>
</el-form>
</div>
</div>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('horzLineStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('styleLabel')">
<el-radio-group v-model="diyStore.editComponent.borderStyle">
<el-radio label="solid">{{ t('horzLineStyleSolid') }}</el-radio>
<el-radio label="dashed">{{ t('horzLineStyleDashed') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('horzLineBorderColor')">
<el-color-picker v-model="diyStore.editComponent.borderColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('horzLineBorderWidth')">
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small"
class="ml-[10px] diy-nav-slider" :min="1" :max="10" />
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -34,7 +35,7 @@ import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['pageBgColor','componentBgColor', 'componentBgUrl', 'topRounded', 'bottomRounded'] //
diyStore.editComponent.ignore = ['pageBgColor', 'componentBgColor', 'componentBgUrl', 'topRounded', 'bottomRounded'] //
defineExpose({})

View File

@ -1,34 +1,34 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('hotAreaSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('hotAreaSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<div ref="imageBoxRef">
<div class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('hotAreaBackground')">
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1" @change="selectImg"/>
</el-form-item>
<div ref="imageBoxRef">
<div class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('hotAreaBackground')">
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1" @change="selectImg" />
</el-form-item>
<el-form-item :label="t('hotAreaSet')">
<heat-map v-model="diyStore.editComponent"/>
</el-form-item>
</div>
</div>
<el-form-item :label="t('hotAreaSet')">
<heat-map v-model="diyStore.editComponent" />
</el-form-item>
</div>
</div>
</el-form>
</div>
</el-form>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -59,7 +59,7 @@ const selectImg = (url: string) => {
const handleHeight = () => {
const image = new Image()
image.src = img(diyStore.editComponent.imageUrl)
image.onload = async () => {
image.onload = async() => {
diyStore.editComponent.imgWidth = image.width
diyStore.editComponent.imgHeight = image.height
}

View File

@ -1,50 +1,54 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('imageSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('sameScreen')" v-if="diyStore.currentIndex == 0">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('imageSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('sameScreen')" v-if="diyStore.currentIndex == 0">
<el-switch v-model="diyStore.editComponent.isSameScreen" />
<div class="text-sm text-gray-400 leading-[1.4]">{{ t('imageAdsSameScreenTips') }}</div>
</el-form-item>
</el-form-item>
<el-form-item :label="t('imageHeight')" class="display-block">
<el-input v-model.trim="diyStore.editComponent.imageHeight" :placeholder="t('imageHeightPlaceholder')" clearable maxlength="10" @blur="blurImageHeight">
<template #append>px</template>
</el-input>
<div class="text-sm text-gray-400 mb-[10px]">{{ t('imageAdsTips') }}</div>
</el-form-item>
<el-form-item :label="t('imageHeight')" class="display-block">
<el-input v-model.trim="diyStore.editComponent.imageHeight" :placeholder="t('imageHeightPlaceholder')" clearable maxlength="10" @blur="blurImageHeight">
<template #append>px</template>
</el-input>
<div class="text-sm text-gray-400 mb-[10px]">{{ t('imageAdsTips') }}</div>
</el-form-item>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
</el-form-item>
<div ref="imageBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.list.length > 1"
@click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
</el-form-item>
</div>
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link" />
</el-form-item>
</div>
</div>
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addImageAd">
{{ t('addImageAd') }}
</el-button>
</el-form>
</div>
</div>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -105,22 +109,22 @@ const addImageAd = () => {
})
}
const selectImg = (url:string) => {
const selectImg = (url: string) => {
handleHeight(true)
}
//
const handleHeight = (isCalcHeight:boolean = false)=> {
const handleHeight = (isCalcHeight: boolean = false) => {
diyStore.editComponent.list.forEach((item: any, index: number) => {
const image = new Image()
image.src = img(item.imageUrl)
image.onload = async () => {
image.onload = async() => {
item.imgWidth = image.width
item.imgHeight = image.height
//
if (isCalcHeight && index == 0) {
const ratio = item.imgHeight / item.imgWidth
item.width = 375 - (diyStore.editComponent.margin.both*2)
item.width = 375 - (diyStore.editComponent.margin.both * 2)
item.height = item.width * ratio
diyStore.editComponent.imageHeight = parseInt(item.height)
}
@ -158,18 +162,18 @@ defineExpose({})
</script>
<style lang="scss" scoped>
.edit-image-ads {
.edit-image-ads {
.item-wrap {
.del {
display: none;
}
.item-wrap {
.del {
display: none;
}
&:hover {
.del {
display: block;
}
}
}
}
&:hover {
.del {
display: block;
}
}
}
}
</style>

View File

@ -1,30 +1,30 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('memberStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('bgUrl')">
<upload-image v-model="diyStore.editComponent.bgUrl" :limit="1"/>
</el-form-item>
</el-form>
</div>
</div>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('memberStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('bgUrl')">
<upload-image v-model="diyStore.editComponent.bgUrl" :limit="1" />
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('memberStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor"/>
</el-form-item>
</el-form>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('memberStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
<script lang="ts" setup>

View File

@ -1,46 +1,49 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
</el-form>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer"
@click="showStyle">{{ diyStore.editComponent.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
</el-form>
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="660px">
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="660px">
<div class="flex flex-wrap">
<template v-for="(item,index) in styleList" :key="index">
<div :class="{ 'border-primary': selectStyle.value == item.value, '!mr-[0]': [(index+1)%3] == 0 }" @click="changeStyle(item)" class="flex my-[5px] items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50">
<img :src="img(item.url)" />
</div>
</template>
</div>
<div class="flex flex-wrap">
<template v-for="(item,index) in styleList" :key="index">
<div
:class="{ 'border-primary': selectStyle.value == item.value, '!mr-[0]': [(index+1)%3] == 0 }"
@click="changeStyle(item)"
class="flex my-[5px] items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50">
<img :src="img(item.url)" />
</div>
</template>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmStyle">{{ t('confirm') }}</el-button>
</span>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="confirmStyle">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</el-dialog>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -50,7 +53,7 @@ import { img } from '@/utils/common'
import { ref, reactive } from 'vue'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['componentBgColor','componentBgUrl'] //
diyStore.editComponent.ignore = ['componentBgColor', 'componentBgUrl'] //
const selectStyle = reactive({
title: diyStore.editComponent.styleName,
@ -94,7 +97,7 @@ const styleList = reactive([
}
])
const changeStyle = (item:any) => {
const changeStyle = (item: any) => {
selectStyle.title = item.title;
selectStyle.value = item.value;
}
@ -108,22 +111,22 @@ const confirmStyle = () => {
const initStyle = (style: any) => {
if (style == 'style-1') {
diyStore.editComponent.bottomRounded = 0;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-2') {
diyStore.editComponent.bottomRounded = 0;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-3') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-4') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-5') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
}
if (style == 'style-1') {
diyStore.editComponent.bottomRounded = 0;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-2') {
diyStore.editComponent.bottomRounded = 0;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-3') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-4') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
} else if (style == 'style-5') {
diyStore.editComponent.bottomRounded = 12;
diyStore.editComponent.topRounded = 12;
}
}

View File

@ -1,101 +1,104 @@
<template>
<!-- 内容 -->
<div class="content-wrap notice-content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('noticeStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('noticeType')">
<el-radio-group v-model="diyStore.editComponent.noticeType">
<el-radio label="img">{{ t('noticeTypeImg') }}</el-radio>
<el-radio label="text">{{ t('noticeTypeText') }}</el-radio>
</el-radio-group>
</el-form-item>
<div class="flex items-center flex-wrap py-[8px] px-[10px] bg-[#f4f3f7] rounded mb-[18px] mx-[18px]" v-show="diyStore.editComponent.noticeType == 'img'">
<div :class="['mr-[10px] rounded cursor-pointer border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_1' && diyStore.editComponent.imgType == 'system'}]">
<img src="@/app/assets/images/diy/notice/style_1.png" :class="['h-[28px] px-[10px] py-[5px]']" @click="changeStyle('style_1')"/>
</div>
<!-- 内容 -->
<div class="content-wrap notice-content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('noticeStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('noticeType')">
<el-radio-group v-model="diyStore.editComponent.noticeType">
<el-radio label="img">{{ t('noticeTypeImg') }}</el-radio>
<el-radio label="text">{{ t('noticeTypeText') }}</el-radio>
</el-radio-group>
</el-form-item>
<div class="flex items-center flex-wrap py-[8px] px-[10px] bg-[#f4f3f7] rounded mb-[18px] mx-[18px]" v-show="diyStore.editComponent.noticeType == 'img'">
<div :class="['mr-[10px] rounded cursor-pointer border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_1' && diyStore.editComponent.imgType == 'system'}]">
<img src="@/app/assets/images/diy/notice/style_1.png" :class="['h-[28px] px-[10px] py-[5px]']" @click="changeStyle('style_1')" />
</div>
<div :class="['mr-[10px] rounded cursor-pointer w-[100px] border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_2' && diyStore.editComponent.imgType == 'system'}]">
<img src="@/app/assets/images/diy/notice/style_2.png" class="px-[10px] py-[5px]" @click="changeStyle('style_2')"/>
</div>
<div @click.stop="diyStore.editComponent.imgType = 'diy'" :class="['mr-[10px] rounded cursor-pointer diy-upload-img border-[1px] border-solid', {'border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1"/>
</div>
</div>
<div :class="['mr-[10px] rounded cursor-pointer w-[100px] border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_2' && diyStore.editComponent.imgType == 'system'}]">
<img src="@/app/assets/images/diy/notice/style_2.png" class="px-[10px] py-[5px]" @click="changeStyle('style_2')" />
</div>
<div @click.stop="diyStore.editComponent.imgType = 'diy'"
:class="['mr-[10px] rounded cursor-pointer diy-upload-img border-[1px] border-solid', {'border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1" />
</div>
</div>
<el-form-item :label="t('noticeTitle')" v-show="diyStore.editComponent.noticeType == 'text'">
<el-input v-model.trim="diyStore.editComponent.noticeTitle" :placeholder="t('titlePlaceholder')" clearable maxlength="20" show-word-limit/>
</el-form-item>
<el-form-item :label="t('noticeTitle')" v-show="diyStore.editComponent.noticeType == 'text'">
<el-input v-model.trim="diyStore.editComponent.noticeTitle" :placeholder="t('titlePlaceholder')" clearable maxlength="20" show-word-limit />
</el-form-item>
</el-form>
</el-form>
</div>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('noticeText') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('noticeText') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('noticeScrollWay')">
<el-radio-group v-model="diyStore.editComponent.scrollWay">
<el-radio label="upDown">{{ t('noticeUpDown') }}</el-radio>
<el-radio label="horizontal">{{ t('noticeHorizontal') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noticeShowType')">
<el-radio-group v-model="diyStore.editComponent.showType">
<el-radio label="popup">{{ t('noticeShowPopUp') }}</el-radio>
<el-radio label="link">{{ t('noticeShowLink') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noticeScrollWay')">
<el-radio-group v-model="diyStore.editComponent.scrollWay">
<el-radio label="upDown">{{ t('noticeUpDown') }}</el-radio>
<el-radio label="horizontal">{{ t('noticeHorizontal') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('noticeShowType')">
<el-radio-group v-model="diyStore.editComponent.showType">
<el-radio label="popup">{{ t('noticeShowPopUp') }}</el-radio>
<el-radio label="link">{{ t('noticeShowLink') }}</el-radio>
</el-radio-group>
</el-form-item>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
<div ref="noticeBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<div ref="noticeBoxRef">
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('noticeText')">
<el-input v-model.trim="item.text" :placeholder="t('noticePlaceholderText')" clearable maxlength="40" show-word-limit/>
</el-form-item>
<el-form-item :label="t('noticeText')">
<el-input v-model.trim="item.text" :placeholder="t('noticePlaceholderText')" clearable maxlength="40" show-word-limit />
</el-form-item>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]"
v-show="diyStore.editComponent.list.length > 1"
@click="diyStore.editComponent.list.splice(index,1)">
<icon name="element CircleCloseFilled" color="#bbb" size="20px" />
</div>
<el-form-item :label="t('link')" v-if="diyStore.editComponent.showType == 'link'">
<diy-link v-model="item.link"/>
</el-form-item>
</div>
</div>
<el-form-item :label="t('link')" v-if="diyStore.editComponent.showType == 'link'">
<diy-link v-model="item.link" />
</el-form-item>
</div>
</div>
<el-button class="w-full" @click="addNotice">{{ t('addNotice') }}</el-button>
<el-button class="w-full" @click="addNotice">{{ t('addNotice') }}</el-button>
</el-form>
</div>
</el-form>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('textSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="20"/>
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor"/>
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('textSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="20" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -105,6 +108,7 @@ import useDiyStore from '@/stores/modules/diy'
import { ref, watch, onMounted, nextTick } from 'vue'
import { range } from 'lodash-es'
import Sortable from 'sortablejs'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
@ -112,8 +116,8 @@ diyStore.editComponent.ignore = [] // 忽略公共属性
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if(diyStore.value[index].noticeType == 'text'){
if(diyStore.value[index].noticeTitle == ''){
if (diyStore.value[index].noticeType == 'text') {
if (diyStore.value[index].noticeTitle == '') {
res.code = false
res.message = t('noticeTypeTextPlaceholder')
return res
@ -134,9 +138,7 @@ diyStore.editComponent.list.forEach((item: any) => {
if (!item.id) item.id = diyStore.generateRandom()
})
const selectStyle = ref(diyStore.editComponent.style)
const changeStyle = (value :any) => {
const changeStyle = (value: any) => {
diyStore.editComponent.systemUrl = value;
diyStore.editComponent.imgType = 'system';
}
@ -144,11 +146,11 @@ const changeStyle = (value :any) => {
watch(
() => diyStore.editComponent.imageUrl,
(newValue, oldValue) => {
if(newValue){
if (newValue) {
diyStore.editComponent.imgType = 'diy';
}else{
changeStyle('style_1');
}
} else {
changeStyle('style_1');
}
}
)
@ -185,26 +187,26 @@ defineExpose({})
</script>
<style lang="scss">
.notice-content-wrap {
.add-notice-width {
width: calc(100% - 20px);
}
.notice-content-wrap {
.add-notice-width {
width: calc(100% - 20px);
}
.diy-upload-img {
.image-wrap {
width: 50px !important;
height: 50px !important;
margin-right: 0 !important;
background: #fff;
}
.diy-upload-img {
.image-wrap {
width: 50px !important;
height: 50px !important;
margin-right: 0 !important;
background: #fff;
}
.content-wrap {
div {
display: none;
}
}
}
}
.content-wrap {
div {
display: none;
}
}
}
}
</style>
<style lang="scss" scoped></style>

View File

@ -1,35 +1,36 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pageContent') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('diyPageTitle')">
<el-input v-model.trim="diyStore.pageTitle" :placeholder="t('diyPageTitlePlaceholder')" clearable maxlength="16" show-word-limit/>
<div class="text-sm text-gray-400">{{ t('pageTitleTips') }}</div>
</el-form-item>
</el-form>
</div>
<!-- 表单布局 页面设置 -->
<slot name="content"></slot>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('statusBarContent') }}</h3>
<h3 class="mb-[10px]">{{ t('pageContent') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('diyPageTitle')">
<el-input v-model.trim="diyStore.pageTitle" :placeholder="t('diyPageTitlePlaceholder')" clearable
maxlength="16" show-word-limit />
<div class="text-sm text-gray-400">{{ t('pageTitleTips') }}</div>
</el-form-item>
</el-form>
</div>
<!-- 表单布局 页面设置 -->
<slot name="content"></slot>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('statusBarContent') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('topStatusBarNav')" class="display-block">
<el-switch v-model="diyStore.global.topStatusBar.isShow"/>
<div class="text-sm text-gray-400">{{ t('statusBarSwitchTips') }}</div>
</el-form-item>
<el-switch v-model="diyStore.global.topStatusBar.isShow" />
<div class="text-sm text-gray-400">{{ t('statusBarSwitchTips') }}</div>
</el-form-item>
<template v-if="diyStore.global.topStatusBar.isShow">
<el-form-item :label="t('diyTitle')">
<el-input v-model.trim="diyStore.global.title" :placeholder="t('diyTitlePlaceholder')" clearable maxlength="12" show-word-limit/>
<el-input v-model.trim="diyStore.global.title" :placeholder="t('diyTitlePlaceholder')" clearable maxlength="12" show-word-limit />
<div class="text-sm text-gray-400">{{ t('titleTips') }}</div>
</el-form-item>
<el-form-item :label="t('selectStyle')" class="display-block">
<div class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{diyStore.global.topStatusBar.styleName}}</span>
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.global.topStatusBar.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
@ -41,7 +42,7 @@
<div class="text-sm text-gray-400 mt-[10px]">{{ t('topStatusBarImgTips') }}</div>
</el-form-item>
<el-form-item :label="t('topStatusBarSearchName')" v-if="'style-3' == diyStore.global.topStatusBar.style">
<el-input v-model.trim="diyStore.global.topStatusBar.inputPlaceholder" :placeholder="t('topStatusBarSearchNamePlaceholder')" clearable maxlength="12" show-word-limit/>
<el-input v-model.trim="diyStore.global.topStatusBar.inputPlaceholder" :placeholder="t('topStatusBarSearchNamePlaceholder')" clearable maxlength="12" show-word-limit />
</el-form-item>
<el-form-item :label="t('textAlign')" v-show="diyStore.global.topStatusBar.style == 'style-1'">
<el-radio-group v-model="diyStore.global.topStatusBar.textAlign">
@ -53,31 +54,35 @@
<diy-link v-model="diyStore.global.topStatusBar.link" />
</el-form-item>
</template>
</el-form>
</div>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('bottomNavContent') }}</h3>
<h3 class="mb-[10px]">{{ t('bottomNavContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('tabbar')" class="display-block">
<el-switch v-model="diyStore.global.bottomTabBarSwitch"/>
<div class="text-sm text-gray-400">{{ t('tabbarSwitchTips') }}</div>
</el-form-item>
</el-form>
</div>
<el-form-item :label="t('tabbar')" class="display-block">
<el-switch v-model="diyStore.global.bottomTabBarSwitch" />
<div class="text-sm text-gray-400">{{ t('tabbarSwitchTips') }}</div>
</el-form-item>
</el-form>
</div>
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="800px">
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="800px">
<div class="flex flex-wrap">
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50"
:class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style1.jpg" />
</div>
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50"
:class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style2.jpg" />
</div>
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mb-[15px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-3' }" @click="selectStyle = 'style-3'">
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mb-[15px] cursor-pointer border bg-gray-50"
:class="{ 'border-primary': selectStyle == 'style-3' }" @click="selectStyle = 'style-3'">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style3.jpg" />
</div>
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-4' }" @click="selectStyle = 'style-4'">
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] cursor-pointer border bg-gray-50"
:class="{ 'border-primary': selectStyle == 'style-4' }" @click="selectStyle = 'style-4'">
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style4.jpg" />
</div>
</div>
@ -90,59 +95,59 @@
</template>
</el-dialog>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pageStyle') }}</h3>
<el-form label-width="115px" class="px-[10px]">
<el-form-item :label="t('pageBgColor')">
<el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('bgGradientAngle')">
<el-radio-group v-model="diyStore.editComponent.pageGradientAngle">
<el-radio label="to bottom">{{ t('topToBottom') }}</el-radio>
<el-radio label="to right">{{ t('leftToRight') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('bgHeightScale')">
<el-slider v-model="diyStore.global.bgHeightScale" show-input size="small" class="ml-[10px] diy-nav-slider"/>
</el-form-item>
<div class="text-sm text-gray-400 ml-[80px] mb-[10px]">{{ t('bgHeightScaleTip') }}</div>
<el-form-item :label="t('bgUrl')">
<upload-image v-model="diyStore.global.bgUrl" :limit="1"/>
</el-form-item>
</el-form>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('statusBarStyle') }}</h3>
<el-form label-width="115px" class="px-[10px]">
<h3 class="mb-[10px]">{{ t('pageStyle') }}</h3>
<el-form label-width="115px" class="px-[10px]">
<el-form-item :label="t('pageBgColor')">
<el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
</el-form-item>
<el-form-item :label="t('bgGradientAngle')">
<el-radio-group v-model="diyStore.editComponent.pageGradientAngle">
<el-radio label="to bottom">{{ t('topToBottom') }}</el-radio>
<el-radio label="to right">{{ t('leftToRight') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('bgHeightScale')">
<el-slider v-model="diyStore.global.bgHeightScale" show-input size="small" class="ml-[10px] diy-nav-slider" />
</el-form-item>
<div class="text-sm text-gray-400 ml-[80px] mb-[10px]">{{ t('bgHeightScaleTip') }}</div>
<el-form-item :label="t('bgUrl')">
<upload-image v-model="diyStore.global.bgUrl" :limit="1" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('statusBarStyle') }}</h3>
<el-form label-width="115px" class="px-[10px]">
<el-form-item :label="t('topStatusBarBgColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.bgColor" show-alpha />
</el-form-item>
<el-form-item :label="t('rollTopStatusBarBgColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.rollBgColor" show-alpha />
</el-form-item>
<el-form-item :label="t('topStatusBarTextColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.textColor" show-alpha />
</el-form-item>
<el-form-item :label="t('rollTopStatusBarTextColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.rollTextColor" show-alpha />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('marginSet') }}</h3>
<el-form label-width="115px" class="px-[10px]">
<el-form-item :label="t('marginBoth')">
<el-slider v-model="diyStore.global.template.margin.both" show-input size="small" @input="inputBoth" class="ml-[10px] diy-nav-slider"/>
</el-form-item>
</el-form>
</div>
</div>
<el-color-picker v-model="diyStore.global.topStatusBar.bgColor" show-alpha />
</el-form-item>
<el-form-item :label="t('rollTopStatusBarBgColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.rollBgColor" show-alpha />
</el-form-item>
<el-form-item :label="t('topStatusBarTextColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.textColor" show-alpha />
</el-form-item>
<el-form-item :label="t('rollTopStatusBarTextColor')" class="display-block">
<el-color-picker v-model="diyStore.global.topStatusBar.rollTextColor" show-alpha />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('marginSet') }}</h3>
<el-form label-width="115px" class="px-[10px]">
<el-form-item :label="t('marginBoth')">
<el-slider v-model="diyStore.global.template.margin.both" show-input size="small" @input="inputBoth" class="ml-[10px] diy-nav-slider" />
</el-form-item>
</el-form>
</div>
</div>
</template>
<script lang="ts" setup>
@ -159,11 +164,11 @@ watch(
//
const image = new Image()
image.src = img(diyStore.global.bgUrl)
image.onload = async () => {
image.onload = async() => {
diyStore.global.imgWidth = image.width
diyStore.global.imgHeight = image.height
}
if(!diyStore.global.bgUrl){
if (!diyStore.global.bgUrl) {
diyStore.global.imgWidth = ''
diyStore.global.imgHeight = ''
}
@ -171,8 +176,8 @@ watch(
)
//
const inputBoth = (value:any)=>{
diyStore.value.forEach((item,index)=>{
const inputBoth = (value: any) => {
diyStore.value.forEach((item, index) => {
item.margin.both = value;
})
@ -192,7 +197,7 @@ const showStyle = () => {
const selectStyle = ref("style-1")
const changeStyle = () => {
switch (selectStyle.value) {
switch (selectStyle.value) {
case 'style-1':
diyStore.global.topStatusBar.styleName = '风格1'
break

View File

@ -1,127 +1,129 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pictureShowBlockOne') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('image')">
<upload-image v-model="diyStore.editComponent.moduleOne.head.textImg" :limit="1"/>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pictureShowBlockOne') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('image')">
<upload-image v-model="diyStore.editComponent.moduleOne.head.textImg" :limit="1" />
</el-form-item>
<el-form-item :label="t('subTitle')">
<el-input v-model.trim="diyStore.editComponent.moduleOne.head.subText" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
<el-input v-model.trim="diyStore.editComponent.moduleOne.head.subText"
:placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
</el-form-item>
<el-form-item :label="t('subTitleTextColor')">
<el-color-picker v-model="diyStore.editComponent.moduleOne.head.subTextColor" show-alpha />
<el-color-picker v-model="diyStore.editComponent.moduleOne.head.subTextColor" show-alpha />
</el-form-item>
<el-form-item :label="t('pictureShowBgColor')">
<el-color-picker v-model="diyStore.editComponent.moduleOne.listFrame.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.moduleOne.listFrame.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="diyStore.editComponent.moduleOne.listFrame.endColor" show-alpha />
</el-form-item>
<div v-for="(item,index) in diyStore.editComponent.moduleOne.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<div v-for="(item,index) in diyStore.editComponent.moduleOne.list" :key="item.id"
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1"/>
<upload-image v-model="item.imageUrl" :limit="1" />
</el-form-item>
<el-form-item :label="t('pictureShowBtnText')">
<el-input v-model.trim="item.btnTitle.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
<el-input v-model.trim="item.btnTitle.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit />
</el-form-item>
<el-form-item :label="t('pictureShowBtnColor')">
<el-color-picker v-model="item.btnTitle.color" show-alpha />
<el-color-picker v-model="item.btnTitle.color" show-alpha />
</el-form-item>
<el-form-item :label="t('pictureShowBtnBgColor')">
<el-color-picker v-model="item.btnTitle.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.btnTitle.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="item.btnTitle.endColor" show-alpha />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
<diy-link v-model="item.link" />
</el-form-item>
</div>
</el-form>
</div>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pictureShowBlockTwo') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pictureShowBlockTwo') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('image')">
<upload-image v-model="diyStore.editComponent.moduleTwo.head.textImg" :limit="1"/>
<upload-image v-model="diyStore.editComponent.moduleTwo.head.textImg" :limit="1" />
</el-form-item>
<el-form-item :label="t('subTitle')">
<el-input v-model.trim="diyStore.editComponent.moduleTwo.head.subText" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
</el-form-item>
<el-form-item :label="t('subTitleTextColor')">
<el-color-picker v-model="diyStore.editComponent.moduleTwo.head.subTextColor" show-alpha />
<el-color-picker v-model="diyStore.editComponent.moduleTwo.head.subTextColor" show-alpha />
</el-form-item>
<el-form-item :label="t('pictureShowBgColor')">
<el-color-picker v-model="diyStore.editComponent.moduleTwo.listFrame.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="diyStore.editComponent.moduleTwo.listFrame.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="diyStore.editComponent.moduleTwo.listFrame.endColor" show-alpha />
</el-form-item>
<div v-for="(item,index) in diyStore.editComponent.moduleTwo.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<div v-for="(item,index) in diyStore.editComponent.moduleTwo.list" :key="item.id"
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1"/>
<upload-image v-model="item.imageUrl" :limit="1" />
</el-form-item>
<el-form-item :label="t('pictureShowBtnText')">
<el-input v-model.trim="item.btnTitle.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
<el-input v-model.trim="item.btnTitle.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit />
</el-form-item>
<el-form-item :label="t('pictureShowBtnColor')">
<el-color-picker v-model="item.btnTitle.color" show-alpha />
<el-color-picker v-model="item.btnTitle.color" show-alpha />
</el-form-item>
<el-form-item :label="t('pictureShowBtnBgColor')">
<el-color-picker v-model="item.btnTitle.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
<el-color-picker v-model="item.btnTitle.startColor" show-alpha />
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]" />
<el-color-picker v-model="item.btnTitle.endColor" show-alpha />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
<diy-link v-model="item.link" />
</el-form-item>
</div>
</el-form>
</div>
</el-form>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('pictureShowBlockStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.moduleRounded.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100"/>
<h3 class="mb-[10px]">{{ t('pictureShowBlockStyle') }}</h3>
<el-form label-width="90px" class="px-[10px]">
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.moduleRounded.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.moduleRounded.bottomRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100"/>
<el-slider v-model="diyStore.editComponent.moduleRounded.bottomRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
</el-form-item>
</el-form>
</div>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import { img } from '@/utils/common'
import { ref, reactive } from 'vue'
const diyStore = useDiyStore()

View File

@ -1,18 +1,18 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('richTextContentSet') }}</h3>
<editor v-model="diyStore.editComponent.html" :height="600" class="editor-width" />
</div>
</div>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('richTextContentSet') }}</h3>
<editor v-model="diyStore.editComponent.html" :height="600" class="editor-width" />
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -27,7 +27,7 @@ diyStore.editComponent.ignore = [] // 忽略公共属性
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if(diyStore.value[index].html == '<p><br></p>'){
if (diyStore.value[index].html == '<p><br></p>') {
res.code = false
res.message = t('richTextPlaceholder')
return res

View File

@ -1,73 +1,75 @@
<template>
<!-- 内容 -->
<div class="content-wrap rubik-cube" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap rubik-cube" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('template')">
<span>{{ selectTemplate.name }}</span>
</el-form-item>
<ul class="selected-template-list">
<li v-for="(item,i) in templateList" :key="i" :class="[(item.className == diyStore.editComponent.mode) ? 'selected' : '' ]" @click="changeTemplateList(i)">
<icon :name="'iconfont ' + item.src" size="16px"/>
</li>
</ul>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('rubikCubeLayout') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('template')">
<span>{{ selectTemplate.name }}</span>
</el-form-item>
<ul class="selected-template-list">
<li v-for="(item,i) in templateList" :key="i"
:class="[(item.className == diyStore.editComponent.mode) ? 'selected' : '' ]"
@click="changeTemplateList(i)">
<icon :name="'iconfont ' + item.src" size="16px" />
</li>
</ul>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('rubikCubeLayout') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<ul class="layout">
<li v-for="(li,i) in selectTemplate.dimensionScale" :key="i" :class="[selectTemplate.className]">
<div class="have-preview-image" v-show="diyStore.editComponent.list[i].imageUrl && diyStore.editComponent.list[i].imageUrl != 'static/resource/images/diy/figure.png'">
<img :src="img(diyStore.editComponent.list[i].imageUrl)"/>
</div>
<div class="empty" :class="[selectTemplate.className]" v-show="!diyStore.editComponent.list[i].imageUrl || diyStore.editComponent.list[i].imageUrl == 'static/resource/images/diy/figure.png'">
<p>{{li.name}}</p>
<p>{{li.desc}}</p>
</div>
</li>
</ul>
<ul class="layout">
<li v-for="(li,i) in selectTemplate.dimensionScale" :key="i" :class="[selectTemplate.className]">
<div class="have-preview-image" v-show="diyStore.editComponent.list[i].imageUrl && diyStore.editComponent.list[i].imageUrl != 'static/resource/images/diy/figure.png'">
<img :src="img(diyStore.editComponent.list[i].imageUrl)" />
</div>
<div class="empty" :class="[selectTemplate.className]" v-show="!diyStore.editComponent.list[i].imageUrl || diyStore.editComponent.list[i].imageUrl == 'static/resource/images/diy/figure.png'">
<p>{{ li.name }}</p>
<p>{{ li.desc }}</p>
</div>
</li>
</ul>
<div v-for="(item) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg"/>
</el-form-item>
<div v-for="(item) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
<el-form-item :label="t('image')">
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="item.link"/>
</el-form-item>
</div>
<el-form-item :label="t('link')">
<diy-link v-model="item.link" />
</el-form-item>
</div>
</el-form>
</el-form>
</div>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('rubikCubeStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('imageGap')">
<el-slider v-model="diyStore.editComponent.imageGap" show-input size="small" class="ml-[10px] diy-nav-slider" :max="30"/>
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('rubikCubeStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('imageGap')">
<el-slider v-model="diyStore.editComponent.imageGap" show-input size="small" class="ml-[10px] diy-nav-slider" :max="30" />
</el-form-item>
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
@ -312,16 +314,16 @@ const changeTemplateList = (v: number) => {
}
}
const selectImg = (url:string) => {
const selectImg = (url: string) => {
handleHeight(true)
}
//
const handleHeight = (isCalcHeight:boolean = false) => {
const handleHeight = (isCalcHeight: boolean = false) => {
diyStore.editComponent.list.forEach((item: any, index: number) => {
const image = new Image()
image.src = img(item.imageUrl)
image.onload = async () => {
image.onload = async() => {
item.imgWidth = image.width
item.imgHeight = image.height
}
@ -332,307 +334,307 @@ defineExpose({})
</script>
<style lang="scss" scoped>
.rubik-cube .selected-template-list {
/*padding-left: 15px;*/
margin-bottom: 20px;
overflow: hidden;
display: flex;
flex-wrap: wrap;
.rubik-cube .selected-template-list {
/*padding-left: 15px;*/
margin-bottom: 20px;
overflow: hidden;
display: flex;
flex-wrap: wrap;
li {
color: #909399;
width: 46px;
height: 32px;
text-align: center;
line-height: 29px;
border: 1px solid #e5e5e5;
cursor: pointer;
background: #ffffff;
box-sizing: border-box;
border-right: 1px transparent solid;
li {
color: #909399;
width: 46px;
height: 32px;
text-align: center;
line-height: 29px;
border: 1px solid #e5e5e5;
cursor: pointer;
background: #ffffff;
box-sizing: border-box;
border-right: 1px transparent solid;
&:last-child {
border-right: 1px solid #e5e5e5;
}
&:last-child {
border-right: 1px solid #e5e5e5;
}
&.selected {
color: var(--el-color-primary);
border-color: var(--el-color-primary);
}
&.selected {
color: var(--el-color-primary);
border-color: var(--el-color-primary);
}
img {
display: inline-block;
}
img {
display: inline-block;
}
div {
font-size: 12px;
}
}
}
div {
font-size: 12px;
}
}
}
.layout {
overflow: hidden;
position: relative;
margin-bottom: 15px;
.layout {
overflow: hidden;
position: relative;
margin-bottom: 15px;
li {
float: left;
color: #909399;
border: 1px solid #e5e5e5;
cursor: pointer;
font-size: 12px;
position: relative;
li {
float: left;
color: #909399;
border: 1px solid #e5e5e5;
cursor: pointer;
font-size: 12px;
position: relative;
div.empty {
left: 0;
text-align: center;
width: 100%;
position: absolute;
top: 50%;
margin-top: -26px;
div.empty {
left: 0;
text-align: center;
width: 100%;
position: absolute;
top: 50%;
margin-top: -26px;
p {
margin: 0;
line-height: 26px;
}
}
p {
margin: 0;
line-height: 26px;
}
}
div.have-preview-image {
box-sizing: border-box;
div.have-preview-image {
box-sizing: border-box;
img {
display: inline-block;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
}
img {
display: inline-block;
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
}
}
// 12
&.row1-of2 {
width: 49.2%;
height: 160px;
border-right: 1px transparent solid;
// 12
&.row1-of2 {
width: 49.2%;
height: 160px;
border-right: 1px transparent solid;
&:last-child {
border-right: 1px solid #e5e5e5;
}
&:last-child {
border-right: 1px solid #e5e5e5;
}
div.empty {
}
div.empty {
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
}
// 13
&.row1-of3 {
width: 32.5%;
height: 100px;
border-right: 1px transparent solid;
// 13
&.row1-of3 {
width: 32.5%;
height: 100px;
border-right: 1px transparent solid;
&:last-child {
border-right: 1px solid #bdf;
}
&:last-child {
border-right: 1px solid #bdf;
}
div.empty {
}
div.empty {
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 100px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 100px;
background: #ffffff;
}
}
// 14
&.row1-of4 {
width: 24.2%;
height: 80px;
border-right: 1px transparent solid;
// 14
&.row1-of4 {
width: 24.2%;
height: 80px;
border-right: 1px transparent solid;
&:last-child {
border-right: 1px solid #bdf;
}
&:last-child {
border-right: 1px solid #bdf;
}
div.empty {
}
div.empty {
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 80px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 80px;
background: #ffffff;
}
}
// 22
&.row2-lt-of2-rt {
width: 49.2%;
height: 160px;
// 22
&.row2-lt-of2-rt {
width: 49.2%;
height: 160px;
&:nth-child(1) {
border-right: 1px transparent solid;
border-bottom: 1px transparent solid;
}
&:nth-child(1) {
border-right: 1px transparent solid;
border-bottom: 1px transparent solid;
}
&:nth-child(2) {
border-bottom: 1px transparent solid;
}
&:nth-child(2) {
border-bottom: 1px transparent solid;
}
&:nth-child(3) {
border-right: 1px transparent solid;
clear: both;
}
&:nth-child(3) {
border-right: 1px transparent solid;
clear: both;
}
div.empty {
}
div.empty {
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
// 12
&.row1-lt-of2-rt {
width: 49.2%;
font-size: 12px;
// 12
&.row1-lt-of2-rt {
width: 49.2%;
font-size: 12px;
&:nth-child(1) {
height: 322px;
border-right: 1px transparent solid;
&:nth-child(1) {
height: 322px;
border-right: 1px transparent solid;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 322px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 322px;
background: #ffffff;
}
}
&:nth-child(2) {
height: 160px;
border-bottom: 1px transparent solid;
&:nth-child(2) {
height: 160px;
border-bottom: 1px transparent solid;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
&:nth-child(3) {
height: 160px;
&:nth-child(3) {
height: 160px;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.empty {
}
}
div.empty {
}
}
// 12
&.row1-tp-of2-bm {
height: 160px;
// 12
&.row1-tp-of2-bm {
height: 160px;
&:nth-child(1) {
width: 99.4%;
border-bottom: 1px transparent solid;
}
&:nth-child(1) {
width: 99.4%;
border-bottom: 1px transparent solid;
}
&:nth-child(2) {
width: 49.2%;
border-right: 1px transparent solid;
}
&:nth-child(2) {
width: 49.2%;
border-right: 1px transparent solid;
}
&:nth-child(3) {
width: 49.2%;
}
&:nth-child(3) {
width: 49.2%;
}
div.empty {
}
div.empty {
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
// 13
&.row1-lt-of1-tp-of2-bm {
&:nth-child(1) {
height: 320px;
width: 49.2%;
border-right: 1px transparent solid;
// 13
&.row1-lt-of1-tp-of2-bm {
&:nth-child(1) {
height: 320px;
width: 49.2%;
border-right: 1px transparent solid;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 320px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 320px;
background: #ffffff;
}
}
&:nth-child(2) {
height: 160px;
width: 49.2%;
border-bottom: 1px transparent solid;
&:nth-child(2) {
height: 160px;
width: 49.2%;
border-bottom: 1px transparent solid;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
&:nth-child(3) {
height: 160px;
width: 24.2%;
border-right: 1px transparent solid;
&:nth-child(3) {
height: 160px;
width: 24.2%;
border-right: 1px transparent solid;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
&:nth-child(4) {
height: 160px;
width: 24.2%;
&:nth-child(4) {
height: 160px;
width: 24.2%;
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
div.empty {
}
}
div.empty {
}
}
}
}
</style>
}
}
</style>

View File

@ -1,114 +1,119 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('styleSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('title')">
<el-input v-model.trim="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.link" />
</el-form-item>
<el-form-item :label="t('textAlign')" v-show="diyStore.editComponent.style == 'style-1'">
<el-radio-group v-model="diyStore.editComponent.textAlign">
<el-radio :label="'left'">{{ t('textAlignLeft') }}</el-radio>
<el-radio :label="'center'">{{ t('textAlignCenter') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('styleSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('selectStyle')" class="flex">
<span class="text-primary flex-1 cursor-pointer"
@click="showStyle">{{ diyStore.editComponent.styleName }}</span>
<el-icon>
<ArrowRight />
</el-icon>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('title')">
<el-input v-model.trim="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.link" />
</el-form-item>
<el-form-item :label="t('textAlign')" v-show="diyStore.editComponent.style == 'style-1'">
<el-radio-group v-model="diyStore.editComponent.textAlign">
<el-radio :label="'left'">{{ t('textAlignLeft') }}</el-radio>
<el-radio :label="'center'">{{ t('textAlignCenter') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.subTitle.control">
<h3 class="mb-[10px]">{{ t('subTitleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('subTitle')">
<el-input v-model.trim="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="30" show-word-limit />
</el-form-item>
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16" />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.color" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.subTitle.control">
<h3 class="mb-[10px]">{{ t('subTitleContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('subTitle')">
<el-input v-model.trim="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="30" show-word-limit />
</el-form-item>
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16" />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.subTitle.color" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.more.control">
<h3 class="mb-[10px]">{{ t('moreContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('more')">
<el-input v-model.trim="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable maxlength="8" show-word-limit />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.more.link" />
</el-form-item>
<el-form-item :label="t('moreIsShow')">
<el-switch v-model="diyStore.editComponent.more.isShow" />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.more.color" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.more.control">
<h3 class="mb-[10px]">{{ t('moreContent') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('more')">
<el-input v-model.trim="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable maxlength="8" show-word-limit />
</el-form-item>
<el-form-item :label="t('link')">
<diy-link v-model="diyStore.editComponent.more.link" />
</el-form-item>
<el-form-item :label="t('moreIsShow')">
<el-switch v-model="diyStore.editComponent.more.isShow" />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.more.color" />
</el-form-item>
</el-form>
</div>
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="620px">
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="620px">
<div class="flex flex-wrap">
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png" />
</div>
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png" />
</div>
</div>
<div class="flex flex-wrap">
<div
class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50"
:class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png" />
</div>
<div
class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] cursor-pointer border bg-gray-50"
:class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png" />
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="changeStyle">{{ t('confirm') }}</el-button>
</span>
</template>
<template #footer>
<span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="changeStyle">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</el-dialog>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="30" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="30" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>

View File

@ -2,8 +2,7 @@
<el-dialog v-model="dialogThemeVisible" title="编辑色调" width="850px" align-center destroy-on-close="true">
<el-form :model="openData" label-width="150px" :rules="formRules">
<el-form-item label="色调名称" prop="title">
<el-input v-model="openData.title" placeholder="请输入色调名称" maxlength="15" class="!w-[250px]"
:disabled="openData.id != ''" />
<el-input v-model="openData.title" placeholder="请输入色调名称" maxlength="15" class="!w-[250px]" :disabled="openData.id != ''" @keydown.enter.native.prevent />
</el-form-item>
</el-form>
@ -19,8 +18,7 @@
<div class="flex items-center">
<el-color-picker v-model="item.value" show-alpha :predefine="diyStore.predefineColors" />
<span class="text-primary cursor-pointer text-[14px] ml-[20px]" @click="editThemeFn(item)">编辑</span>
<span class="text-primary cursor-pointer text-[14px] ml-[8px]"
@click="deleteThemeFn(item)">删除</span>
<span class="text-primary cursor-pointer text-[14px] ml-[8px]" @click="deleteThemeFn(item)">删除</span>
</div>
<div class="form-tip">{{ item.tip }}</div>
</el-form-item>
@ -45,15 +43,15 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import { deepClone, filterNumber } from '@/utils/common'
import { ElMessage } from 'element-plus'
import { cloneDeep } from 'lodash-es'
import addThemeComponent from './add-theme.vue'
import useDiyStore from '@/stores/modules/diy'
import { deleteTheme, addTheme, editTheme } from '@/app/api/diy'
import { addTheme, editTheme } from '@/app/api/diy'
import type { FormInstance } from 'element-plus'
const diyStore = useDiyStore()
const dialogThemeVisible = ref(false)

View File

@ -1,11 +1,11 @@
<template>
<el-dialog v-model="dialogThemeVisible" :title="dialogTitle" width="535px" align-center class="custom-theme-dialog" @close="cancelFn">
<div class="flex flex-col items-baseline">
<div class="flex items-center flex-wrap max-h-[365px] overflow-auto [&>:nth-child(3n)]:mr-0" >
<div class="flex items-center flex-wrap max-h-[365px] overflow-auto [&>:nth-child(3n)]:mr-0">
<div :key="tempIndex" v-for="(tempItem, tempIndex) in themeTemp"
class="flex flex-col border-[1px] border-solid border-[#dcdee2] rounded-[4px] px-[10px] pt-[10px] pb-[15px] mr-[10px] cursor-pointer my-[5px]"
:class="{ '!border-[var(--el-color-primary)]': currTheme.id == tempItem.id }"
@click="themeTempChange(tempItem)">
class="flex flex-col border-[1px] border-solid border-[#dcdee2] rounded-[4px] px-[10px] pt-[10px] pb-[15px] mr-[10px] cursor-pointer my-[5px]"
:class="{ '!border-[var(--el-color-primary)]': currTheme.id == tempItem.id }"
@click="themeTempChange(tempItem)">
<div class="flex justify-between pb-[5px]">
<div class="text-[14px] text-[#666] max-w-[85px] whitespace-nowrap overflow-hidden text-ellipsis" :class="{ '!text-[#333]': currTheme.id == tempItem.id }">{{ tempItem.title }}</div>
<div>
@ -14,7 +14,8 @@
</div>
</div>
<div class="flex">
<div class="w-[70px] h-[54px] pl-[7px] pt-[9px] flex flex-col mr-[4px] rounded-[4px] text-[10px] leading-[1] text-[#fff]" :style="{ backgroundColor: tempItem.theme['--primary-color'] }">
<div class="w-[70px] h-[54px] pl-[7px] pt-[9px] flex flex-col mr-[4px] rounded-[4px] text-[10px] leading-[1] text-[#fff]"
:style="{ backgroundColor: tempItem.theme['--primary-color'] }">
<span>主色调</span>
</div>
<div class="flex flex-col">
@ -43,14 +44,11 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import { setDiyTheme, getDefaultTheme, deleteTheme } from '@/app/api/diy'
import { cloneDeep } from 'lodash-es'
import editTheme from './edit-theme.vue'
import useDiyStore from '@/stores/modules/diy'
import { time } from 'echarts'
const diyStore = useDiyStore()
const editThemeRef = ref()
const dialogThemeVisible = ref(false)
@ -90,7 +88,7 @@ const open = (res: any) => {
}
const dialogTitle = computed(() => {
const name = `选择${currTheme.addon_title}配色`
const name = `选择${ currTheme.addon_title }配色`
return name
})
@ -190,7 +188,7 @@ defineExpose({
</script>
<style lang="scss" scoped>
.secod-color-item {
@apply w-[60px] h-[25px] flex flex-col rounded-[4px] text-[10px] text-[#fff] leading-[1] items-end pt-[8px] pr-[7px];
}
.secod-color-item {
@apply w-[60px] h-[25px] flex flex-col rounded-[4px] text-[10px] text-[#fff] leading-[1] items-end pt-[8px] pr-[7px];
}
</style>

View File

@ -238,8 +238,8 @@ route.query.title = route.query.title || ''
route.query.back = route.query.back || '/site/diy/list'
const backPath = route.query.back
const template = ref('');
const oldTemplate = ref('');
const template = ref('')
const oldTemplate = ref('')
const wapUrl = ref('')
const wapDomain = ref('')
const wapPreview = ref('')
@ -273,7 +273,7 @@ const originData = reactive({
const isChange = ref(true) // truefalse
const goBack = () => {
if (isChange.value) {
location.href = `${location.origin}${backPath}`;
location.href = `${location.origin}${backPath}`
router.push(backPath)
} else {
//
@ -287,7 +287,7 @@ const goBack = () => {
autofocus: false
}
).then(() => {
location.href = `${location.origin}${backPath}`;
location.href = `${location.origin}${backPath}`
}).catch(() => {
})
}
@ -328,7 +328,7 @@ watch(
)
//
const changeTemplatePage = (value:any)=> {
const changeTemplatePage = (value: any) => {
//
if (diyStore.value.length) {
ElMessageBox.confirm(t('changeTemplatePageTips'), t('warning'), {
@ -337,7 +337,7 @@ const changeTemplatePage = (value:any)=> {
type: 'warning'
}).then(() => {
diyStore.changeCurrentIndex(-99)
diyStore.init(); //
diyStore.init() //
if (value) {
let data = cloneDeep(templatePages[value].data);
diyStore.global = data.global;
@ -349,13 +349,13 @@ const changeTemplatePage = (value:any)=> {
}
}).catch(() => {
//
template.value = oldTemplate.value;
template.value = oldTemplate.value
});
} else {
diyStore.init(); //
diyStore.init() //
if (value) {
let data = cloneDeep(templatePages[value].data);
diyStore.global = data.global;
let data = cloneDeep(templatePages[value].data)
diyStore.global = data.global
if (data.value.length) {
diyStore.value = data.value
}
@ -444,7 +444,7 @@ initPage({
}
}
loadDiyTemplatePages(data.type);
loadDiyTemplatePages(data.type)
//
wapDomain.value = data.domain_url.wap_domain

View File

@ -57,14 +57,10 @@
import { reactive, ref, watch, computed } from 'vue'
import { t } from '@/lang'
import { img } from '@/utils/common'
import { setDiyTheme, getDiyTheme, getDefaultTheme } from '@/app/api/diy'
import { useClipboard } from '@vueuse/core'
import { ElMessage, FormInstance } from 'element-plus'
import { ArrowLeft } from '@element-plus/icons-vue'
import { getDiyTheme } from '@/app/api/diy'
import { useRoute } from 'vue-router'
import themeList from './components/theme-list.vue'
import { cloneDeep } from 'lodash-es'
import { tr } from 'element-plus/es/locale'
const route = useRoute()
const pageName = route.meta.title
@ -74,7 +70,7 @@ const data = ref([])
const initData = () => {
loading.value = true;
getDiyTheme().then((res) => {
getDiyTheme({}).then((res) => {
let obj = cloneDeep(res.data);
for(let key in obj){
obj[key].key = key;

View File

@ -1,61 +1,61 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('地址格式')">
<el-radio-group v-model="diyStore.editComponent.addressFormat" class="!block">
<el-radio class="!block" label="province/city/district/address">{{ t('省/市/区/街道/详细地址') }}</el-radio>
<el-radio class="!block" label="province/city/district/street">{{ t('省/市/区/街道(镇)') }}</el-radio>
<el-radio class="!block" label="province/city/district">{{ t('省/市/区(县)') }}</el-radio>
<el-radio class="!block" label="province/city">{{ t('省/市') }}</el-radio>
<el-radio class="!block" label="province">{{ t('省') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('地址格式')">
<el-radio-group v-model="diyStore.editComponent.addressFormat" class="!block">
<el-radio class="!block" label="province/city/district/address">{{ t('省/市/区/街道/详细地址') }}</el-radio>
<el-radio class="!block" label="province/city/district/street">{{ t('省/市/区/街道(镇)') }}</el-radio>
<el-radio class="!block" label="province/city/district">{{ t('省/市/区(县)') }}</el-radio>
<el-radio class="!block" label="province/city">{{ t('省/市') }}</el-radio>
<el-radio class="!block" label="province">{{ t('省') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>会自动将提交的个人信息做加密展示</p>
<p>适用于公开展示收集的数据且不暴露用户隐私</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏地址,仅管理员可查看') }}</div>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>会自动将提交的个人信息做加密展示</p>
<p>适用于公开展示收集的数据且不暴露用户隐私</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" :disabled ="diyStore.editComponent.addressFormat != 'province/city/district/address'" />
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏地址,仅管理员可查看') }}</div>
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref } from 'vue'
import { ref,watch } from 'vue'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
@ -63,9 +63,18 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
return res
const res = { code: true, message: '' }
return res
}
watch(
() => diyStore.editComponent.addressFormat,
(newVal) => {
if (newVal !== 'province/city/district/address') {
diyStore.editComponent.field.privacyProtection = false
}
},
{ immediate: true }
)
defineExpose({})

View File

@ -1,81 +1,81 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('style')">
<el-radio-group v-model="diyStore.editComponent.style">
<el-radio label="style-1">{{ t('defaultSources') }}</el-radio>
<el-radio label="style-2">{{ t('listStyle') }}</el-radio>
<el-radio label="style-3">{{ t('dropDownStyle') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('option')">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('style')">
<el-radio-group v-model="diyStore.editComponent.style">
<el-radio label="style-1">{{ t('defaultSources') }}</el-radio>
<el-radio label="style-2">{{ t('listStyle') }}</el-radio>
<el-radio label="style-3">{{ t('dropDownStyle') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('option')">
<div ref="formCheckboxRef">
<div v-for="(option, index) in diyStore.editComponent.options" :key="option.id" class="option-item flex items-center mb-[15px]">
<el-input v-model="diyStore.editComponent.options[index].text" class="!w-[215px]" :placeholder="t('optionPlaceholder')" maxlength="30" clearable />
<span v-if="diyStore.editComponent.options.length > 1" @click="removeOption(index)" class="cursor-pointer ml-[5px] nc-iconfont nc-icon-shanchu-yuangaizhiV6xx"></span>
</div>
</div>
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">{{ t('addSingleOption') }}</span>
<el-popover :visible="visible" placement="bottom" :width="300">
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200" show-word-limit />
<div class="mt-[10px] text-right">
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
<el-button size="small" type="primary" @click="batchAddOptions">{{ t('confirm') }}</el-button>
</div>
<template #reference>
<span class="text-primary cursor-pointer" @click="visible = true">{{ t('addMultipleOption') }}</span>
</template>
</el-popover>
</el-form-item>
</el-form>
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">{{ t('addSingleOption') }}</span>
<el-popover :visible="visible" placement="bottom" :width="300">
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200" show-word-limit />
<div class="mt-[10px] text-right">
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
<el-button size="small" type="primary" @click="batchAddOptions">{{ t('confirm') }}</el-button>
</div>
<template #reference>
<span class="text-primary cursor-pointer" @click="visible = true">{{ t('addMultipleOption') }}</span>
</template>
</el-popover>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- <el-form label-width="100px" class="px-[10px]">-->
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏内容,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- <el-form label-width="100px" class="px-[10px]">-->
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏内容,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
<!-- </el-form>-->
<!-- </el-form>-->
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref, onMounted, nextTick} from 'vue'
import { ref, onMounted, nextTick } from 'vue'
import useDiyStore from '@/stores/modules/diy'
import Sortable from 'sortablejs'
import { range } from 'lodash-es'
@ -86,84 +86,84 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
let pass = true;
for (let i = 0; i < diyStore.value[index].options.length; i++) {
if (!diyStore.value[index].options[i].text) {
res.code = false;
res.message = t('optionPlaceholder');
pass = false;
break;
}
}
const res = { code: true, message: '' }
let pass = true;
for (let i = 0; i < diyStore.value[index].options.length; i++) {
if (!diyStore.value[index].options[i].text) {
res.code = false;
res.message = t('optionPlaceholder');
pass = false;
break;
}
}
if (!pass) return res;
if (!pass) return res;
let uniqueOptions = uniqueByKey(diyStore.value[index].options, 'text')
if (uniqueOptions.length != diyStore.value[index].options.length) {
res.code = false;
res.message = t('errorTipsOne')
}
return res
let uniqueOptions = uniqueByKey(diyStore.value[index].options, 'text')
if (uniqueOptions.length != diyStore.value[index].options.length) {
res.code = false;
res.message = t('errorTipsOne')
}
return res
}
diyStore.editComponent.options.forEach((item: any) => {
if (!item.id) item.id = diyStore.generateRandom()
if (!item.id) item.id = diyStore.generateRandom()
})
const visible = ref(false)
const optionsValue = ref()
const addOption = () => {
diyStore.editComponent.options.push({
id: diyStore.generateRandom(),
text: '选项' + (diyStore.editComponent.options.length + 1)
});
diyStore.editComponent.options.push({
id: diyStore.generateRandom(),
text: '选项' + (diyStore.editComponent.options.length + 1)
});
};
const removeOption = (index:any) => {
const removeOption = (index: any) => {
diyStore.editComponent.options.splice(index, 1);
}
//
const batchAddOptions = () => {
if (optionsValue.value.trim()) {
const newOptions = optionsValue.value.split(',').map((option: any) => {
return {
id: diyStore.generateRandom(),
text: option.trim()
};
}).filter((option: any) => option.text !== '');
if (optionsValue.value.trim()) {
const newOptions = optionsValue.value.split(',').map((option: any) => {
return {
id: diyStore.generateRandom(),
text: option.trim()
};
}).filter((option: any) => option.text !== '');
//
const uniqueNewOptions = uniqueByKey(newOptions, 'text');
//
const uniqueNewOptions = uniqueByKey(newOptions, 'text');
//
const filteredNewOptions = uniqueNewOptions.filter((newOption: any) =>
!diyStore.editComponent.options.some((existingOption: any) => existingOption.text === newOption.text)
);
//
const filteredNewOptions = uniqueNewOptions.filter((newOption: any) =>
!diyStore.editComponent.options.some((existingOption: any) => existingOption.text === newOption.text)
);
//
if (filteredNewOptions.length > 0) {
diyStore.editComponent.options.push(...filteredNewOptions);
} else {
ElMessage({
message: t('errorTipsTwo'),
type: "error",
});
}
//
if (filteredNewOptions.length > 0) {
diyStore.editComponent.options.push(...filteredNewOptions);
} else {
ElMessage({
message: t('errorTipsTwo'),
type: "error",
});
}
optionsValue.value = '';
visible.value = false;
}
optionsValue.value = '';
visible.value = false;
}
};
//
const uniqueByKey = (arr: any, key: any) => {
const seen = new Set();
return arr.filter((item: any) => {
const serializedKey = JSON.stringify(item[key]);
return seen.has(serializedKey) ? false : seen.add(serializedKey);
});
const seen = new Set();
return arr.filter((item: any) => {
const serializedKey = JSON.stringify(item[key]);
return seen.has(serializedKey) ? false : seen.add(serializedKey);
});
}
const formCheckboxRef = ref()

View File

@ -1,93 +1,98 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('dataFormat')">
<el-radio-group v-model="diyStore.editComponent.dateFormat">
<div class="flex flex-col">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('dataFormat')">
<el-radio-group v-model="diyStore.editComponent.dateFormat">
<div class="flex flex-col">
<el-radio label="YYYY年M月D日">{{ dateFormat.format1 }}</el-radio>
<el-radio label="YYYY-MM-DD">{{ dateFormat.format2 }}</el-radio>
<el-radio label="YYYY/MM/DD">{{ dateFormat.format3 }}</el-radio>
</div>
</el-radio-group>
</el-form-item>
</el-form>
</el-radio-group>
</el-form-item>
</el-form>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('startDate') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.start.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.start.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.start.defaultControl">
<el-radio-group v-model="diyStore.editComponent.start.dateWay">
<el-radio label="current">{{ t('currentDate') }}</el-radio>
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.dateWay == 'diy'">
<el-date-picker v-model="diyStore.editComponent.field.default.start.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('startDataPlaceholder')" @change="startDateChange" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('startDate') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.start.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.start.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.start.defaultControl">
<el-radio-group v-model="diyStore.editComponent.start.dateWay">
<el-radio label="current">{{ t('currentDate') }}</el-radio>
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.dateWay == 'diy'">
<el-date-picker v-model="diyStore.editComponent.field.default.start.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('startDataPlaceholder')" @change="startDateChange" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('endDate') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.end.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.end.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.end.defaultControl">
<el-radio-group v-model="diyStore.editComponent.end.dateWay">
<el-radio label="current">{{ t('currentDate') }}</el-radio>
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.dateWay == 'diy'">
<el-date-picker :disabled-date="disabledEndDate" v-model="diyStore.editComponent.field.default.end.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('endDataPlaceholder')" @change="endDateChange" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('endDate') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.end.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.end.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.end.defaultControl">
<el-radio-group v-model="diyStore.editComponent.end.dateWay">
<el-radio label="current">{{ t('currentDate') }}</el-radio>
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.dateWay == 'diy'">
<el-date-picker :disabled-date="disabledEndDate"
v-model="diyStore.editComponent.field.default.end.date" format="YYYY/MM/DD"
value-format="YYYY-MM-DD" type="date" :placeholder="t('endDataPlaceholder')"
@change="endDateChange" />
</el-form-item>
</el-form>
</div>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -142,7 +147,7 @@ const dateFormat: any = reactive({
})
// -
const disabledEndDate = (time:Date)=>{
const disabledEndDate = (time: Date) => {
let cutoffDate = null
let bool = false
if (diyStore.editComponent.start && diyStore.editComponent.start.defaultControl) {
@ -177,10 +182,10 @@ onMounted(() => {
const hours = String(today.getHours()).padStart(2, '0')
const minutes = String(today.getMinutes()).padStart(2, '0')
dateFormat.format1 = `${year}${month}${day}`
dateFormat.format2 = `${year}-${month}-${day}`
dateFormat.format3 = `${year}/${month}/${day}`
dateFormat.format4 = `${year}-${month}-${day} ${hours}:${minutes}`
dateFormat.format1 = `${ year }${ month }${ day }`
dateFormat.format2 = `${ year }-${ month }-${ day }`
dateFormat.format3 = `${ year }/${ month }/${ day }`
dateFormat.format4 = `${ year }-${ month }-${ day } ${ hours }:${ minutes }`
})
//

View File

@ -1,56 +1,56 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('dataFormat')">
<el-radio-group v-model="diyStore.editComponent.dateFormat" class="!block">
<el-radio class="!block" label="YYYY年M月D日">{{ dateFormat.format1 }}</el-radio>
<el-radio class="!block" label="YYYY-MM-DD">{{ dateFormat.format2 }}</el-radio>
<el-radio class="!block" label="YYYY/MM/DD">{{ dateFormat.format3 }}</el-radio>
<el-radio class="!block" label="YYYY-MM-DD HH:mm">{{ dateFormat.format4 }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.defaultControl"/>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl">
<el-radio-group v-model="diyStore.editComponent.dateWay">
<el-radio label="current">{{ t('currentDate') }}</el-radio>
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl && diyStore.editComponent.dateWay == 'diy'">
<el-date-picker v-if="diyStore.editComponent.dateFormat != 'YYYY-MM-DD HH:mm'" v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('dataPlaceholder')" @change="dateChange"/>
<el-date-picker v-else v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD HH:mm" value-format="YYYY-MM-DD HH:mm" type="datetime" :placeholder="t('dataPlaceholder')" @change="dateChange"/>
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('dataFormat')">
<el-radio-group v-model="diyStore.editComponent.dateFormat" class="!block">
<el-radio class="!block" label="YYYY年M月D日">{{ dateFormat.format1 }}</el-radio>
<el-radio class="!block" label="YYYY-MM-DD">{{ dateFormat.format2 }}</el-radio>
<el-radio class="!block" label="YYYY/MM/DD">{{ dateFormat.format3 }}</el-radio>
<el-radio class="!block" label="YYYY-MM-DD HH:mm">{{ dateFormat.format4 }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl">
<el-radio-group v-model="diyStore.editComponent.dateWay">
<el-radio label="current">{{ t('currentDate') }}</el-radio>
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl && diyStore.editComponent.dateWay == 'diy'">
<el-date-picker v-if="diyStore.editComponent.dateFormat != 'YYYY-MM-DD HH:mm'" v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('dataPlaceholder')" @change="dateChange" />
<el-date-picker v-else v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD HH:mm" value-format="YYYY-MM-DD HH:mm" type="datetime" :placeholder="t('dataPlaceholder')" @change="dateChange" />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref,reactive,watch,onMounted } from 'vue'
import { ref, reactive, onMounted } from 'vue'
import { timeTurnTimeStamp } from '@/utils/common'
import useDiyStore from '@/stores/modules/diy'
@ -64,16 +64,16 @@ diyStore.editComponent.verify = (index: number) => {
}
const dateFormat: any = reactive({
format1: '',
format2: '',
format3: '',
format4: ''
format1: '',
format2: '',
format3: '',
format4: ''
});
onMounted(() => {
//
const today = new Date();
if (!diyStore.editComponent.field.default.date) {
if (!diyStore.editComponent.field.default.date) {
diyStore.editComponent.field.default.date = today.toISOString().split('T')[0];
diyStore.editComponent.field.default.timestamp = today.getTime() / 1000;
}
@ -83,13 +83,13 @@ onMounted(() => {
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
dateFormat.format1 = `${year}${month}${day}`;
dateFormat.format2 = `${year}-${month}-${day}`;
dateFormat.format3 = `${year}/${month}/${day}`;
dateFormat.format4 = `${year}-${month}-${day} ${hours}:${minutes}`;
dateFormat.format1 = `${ year }${ month }${ day }`;
dateFormat.format2 = `${ year }-${ month }-${ day }`;
dateFormat.format3 = `${ year }/${ month }/${ day }`;
dateFormat.format4 = `${ year }-${ month }-${ day } ${ hours }:${ minutes }`;
});
const dateChange = (date: any)=>{
const dateChange = (date: any) => {
diyStore.editComponent.field.default.date = date;
diyStore.editComponent.field.default.timestamp = timeTurnTimeStamp(date);
}

View File

@ -1,30 +1,30 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -38,7 +38,7 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
// todo
return res
}
defineExpose({})

View File

@ -1,31 +1,31 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('限制上传大小')">
<el-input v-model.trim="diyStore.editComponent.limitUploadSize" clearable maxlength="15" />
/MBBit*1024
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('限制上传大小')">
<el-input v-model.trim="diyStore.editComponent.limitUploadSize" clearable maxlength="15" />
/MBBit*1024
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>

View File

@ -1,67 +1,67 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('preventDuplicationTipsOne') }}</p>
<p>{{ t('preventDuplicationTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.unique" />
</el-form-item>
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('privacyProtectionTipsOne') }}</p>
<p>{{ t('privacyProtectionTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsThree') }}</div>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('preventDuplicationTipsOne') }}</p>
<p>{{ t('preventDuplicationTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.unique" />
</el-form-item>
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('privacyProtectionTipsOne') }}</p>
<p>{{ t('privacyProtectionTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsThree') }}</div>
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -75,7 +75,7 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
// todo
return res
}
defineExpose({})

View File

@ -1,13 +1,13 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('imageLimit')">
<el-input v-model.trim="diyStore.editComponent.limit" :placeholder="t('imageLimitPlaceholder')" clearable maxlength="2" />
</el-form-item>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('imageLimit')">
<el-input v-model.trim="diyStore.editComponent.limit" :placeholder="t('imageLimitPlaceholder')" clearable maxlength="2" />
</el-form-item>
<el-form-item :label="t('上传方式')">
<el-checkbox-group v-model="diyStore.editComponent.uploadMode" :min="1">
@ -15,23 +15,23 @@
<el-checkbox label="从相册选择" value="select_from_album" />
</el-checkbox-group>
</el-form-item>
</el-form>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>

View File

@ -1,80 +1,80 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.trim="diyStore.editComponent.field.default" :placeholder="t('defaultValuePlaceholder')" clearable maxlength="18" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.trim="diyStore.editComponent.field.default" :placeholder="t('defaultValuePlaceholder')" clearable maxlength="18" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('preventDuplicationTipsOne') }}</p>
<p>{{ t('preventDuplicationTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.unique" />
</el-form-item>
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏文本,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('preventDuplicationTipsOne') }}</p>
<p>{{ t('preventDuplicationTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.unique" />
</el-form-item>
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏文本,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -87,9 +87,9 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
return res
const res = { code: true, message: '' }
// todo
return res
}
defineExpose({})

View File

@ -1,53 +1,53 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('access')">
<el-radio-group v-model="diyStore.editComponent.mode">
<el-radio class="!mr-[20px]" label="authorized_wechat_location">{{ t('authorizeWeChatLocation') }}</el-radio>
<el-radio label="open_choose_location">{{ t('manuallySelectPositioning') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('access')">
<el-radio-group v-model="diyStore.editComponent.mode">
<el-radio class="!mr-[20px]" label="authorized_wechat_location">{{ t('authorizeWeChatLocation') }}</el-radio>
<el-radio label="open_choose_location">{{ t('manuallySelectPositioning') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('privacyProtectionTipsOne') }}</p>
<p>{{ t('privacyProtectionTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsFour') }}</div>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('privacyProtectionTipsOne') }}</p>
<p>{{ t('privacyProtectionTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsFour') }}</div>
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -61,7 +61,7 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
// todo
return res
}
defineExpose({})

View File

@ -1,67 +1,67 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('preventDuplicationTipsOne') }}</p>
<p>{{ t('preventDuplicationTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.unique" />
</el-form-item>
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('privacyProtectionTipsOne') }}</p>
<p>{{ t('privacyProtectionTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsFive') }}</div>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('preventDuplicationTipsOne') }}</p>
<p>{{ t('preventDuplicationTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.unique" />
</el-form-item>
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>{{ t('privacyProtectionTipsOne') }}</p>
<p>{{ t('privacyProtectionTipsTwo') }}</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsFive') }}</div>
</el-form-item>
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -75,7 +75,7 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
// todo
return res
}
defineExpose({})

View File

@ -1,83 +1,83 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('unit')">
<el-input v-model.trim="diyStore.editComponent.unit" :placeholder="t('unitPlaceholder')" clearable maxlength="5" show-word-limit />
</el-form-item>
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.trim="diyStore.editComponent.field.default" :placeholder="t('defaultValuePlaceholder')" @keyup="filterDigit($event)" clearable maxlength="18" show-word-limit />
</el-form-item>
</el-form>
<el-input v-model.trim="diyStore.editComponent.unit" :placeholder="t('unitPlaceholder')" clearable maxlength="5" show-word-limit />
</el-form-item>
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.trim="diyStore.editComponent.field.default" :placeholder="t('defaultValuePlaceholder')" @keyup="filterDigit($event)" clearable maxlength="18" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<!-- <el-form-item>-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('内容防重复') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>该组件填写的内容不能与已提交的数据重复</p>-->
<!-- <p>极端情况下可能存在延时导致限制失效</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.unique" />-->
<!-- </el-form-item>-->
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏数字,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<el-form label-width="100px" class="px-[10px]">
<!-- <el-form-item>-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('内容防重复') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>该组件填写的内容不能与已提交的数据重复</p>-->
<!-- <p>极端情况下可能存在延时导致限制失效</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.unique" />-->
<!-- </el-form-item>-->
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏数字,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
</el-form>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -92,24 +92,24 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if(diyStore.value[index].field.default){
if (isNaN(diyStore.value[index].field.default) || !regExp.digit.test(diyStore.value[index].field.default)) {
res.code = false;
res.message = t('defaultErrorTips');
} else if (diyStore.value[index].field.default < 0) {
res.code = false;
res.message = t('defaultMustZeroTips')
}
}
return res
if (diyStore.value[index].field.default) {
if (isNaN(diyStore.value[index].field.default) || !regExp.digit.test(diyStore.value[index].field.default)) {
res.code = false;
res.message = t('defaultErrorTips');
} else if (diyStore.value[index].field.default < 0) {
res.code = false;
res.message = t('defaultMustZeroTips')
}
}
return res
}
//
const regExp: any = {
required: /[\S]+/,
number: /^\d{0,10}$/,
digit: /^\d{0,10}(.?\d{0,2})$/,
special: /^\d{0,10}(.?\d{0,3})$/
required: /[\S]+/,
number: /^\d{0,10}$/,
digit: /^\d{0,10}(.?\d{0,2})$/,
special: /^\d{0,10}(.?\d{0,3})$/
}
defineExpose({})

View File

@ -1,189 +1,189 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('style')">
<el-radio-group v-model="diyStore.editComponent.style">
<el-radio label="style-1">{{ t('defaultSources') }}</el-radio>
<el-radio label="style-2">{{ t('listStyle') }}</el-radio>
<el-radio label="style-3">{{ t('dropDownStyle') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('option')">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('style')">
<el-radio-group v-model="diyStore.editComponent.style">
<el-radio label="style-1">{{ t('defaultSources') }}</el-radio>
<el-radio label="style-2">{{ t('listStyle') }}</el-radio>
<el-radio label="style-3">{{ t('dropDownStyle') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('option')">
<div ref="formRadioRef">
<div v-for="(option, index) in diyStore.editComponent.options" :key="option.id" class="option-item flex items-center mb-[15px]">
<el-input v-model="diyStore.editComponent.options[index].text" class="!w-[215px]" :placeholder="t('optionPlaceholder')" clearable maxlength="30" />
<span v-if="diyStore.editComponent.options.length > 1" @click="removeOption(index)" class="cursor-pointer ml-[5px] nc-iconfont nc-icon-shanchu-yuangaizhiV6xx"></span>
</div>
</div>
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">{{ t('addSingleOption') }}</span>
<el-popover :visible="visible" placement="bottom" :width="300">
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200" show-word-limit />
<div class="mt-[10px] text-right">
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
<el-button size="small" type="primary" @click="batchAddOptions">{{ t('confirm') }}</el-button>
</div>
<template #reference>
<span class="text-primary cursor-pointer" @click="visible = true">{{ t('addMultipleOption') }}</span>
</template>
</el-popover>
</el-form-item>
<!-- <el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('逻辑规则') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>支持选择某个选项后显示特定的组件</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<div>
<el-button plain>{{ t('添加字段显示规则') }}</el-button>
<span class="mr-[3px]">1条字段显示规则</span>
<span class="text-primary cursor-pointer" @click="">设置</span>
</div>
</el-form-item> -->
</el-form>
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">{{ t('addSingleOption') }}</span>
<el-popover :visible="visible" placement="bottom" :width="300">
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200" show-word-limit />
<div class="mt-[10px] text-right">
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
<el-button size="small" type="primary" @click="batchAddOptions">{{ t('confirm') }}</el-button>
</div>
<template #reference>
<span class="text-primary cursor-pointer" @click="visible = true">{{ t('addMultipleOption') }}</span>
</template>
</el-popover>
</el-form-item>
<!-- <el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('逻辑规则') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>支持选择某个选项后显示特定的组件</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<div>
<el-button plain>{{ t('添加字段显示规则') }}</el-button>
<span class="mr-[3px]">1条字段显示规则</span>
<span class="text-primary cursor-pointer" @click="">设置</span>
</div>
</el-form-item> -->
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- <el-form label-width="100px" class="px-[10px]">-->
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏内容,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- <el-form label-width="100px" class="px-[10px]">-->
<!-- <el-form-item class="display-block">-->
<!-- <template #label>-->
<!-- <div class="flex items-center">-->
<!-- <span class="mr-[3px]">{{ t('隐私保护') }}</span>-->
<!-- <el-tooltip effect="light" placement="top">-->
<!-- <template #content>-->
<!-- <p>会自动将提交的个人信息做加密展示</p>-->
<!-- <p>适用于公开展示收集的数据且不暴露用户隐私</p>-->
<!-- </template>-->
<!-- <el-icon>-->
<!-- <QuestionFilled color="#999999" />-->
<!-- </el-icon>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<!-- </template>-->
<!-- <el-switch v-model="diyStore.editComponent.field.privacyProtection" />-->
<!-- <div class="text-sm text-gray-400">{{ t('提交后自动隐藏内容,仅管理员可查看') }}</div>-->
<!-- </el-form-item>-->
<!-- </el-form>-->
<!-- </el-form>-->
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref, onMounted, nextTick} from 'vue'
import { ref, onMounted, nextTick } from 'vue'
import useDiyStore from '@/stores/modules/diy'
import Sortable from 'sortablejs'
import { range } from 'lodash-es'
import { FormInstance, ElMessage } from "element-plus";
import { ElMessage } from "element-plus";
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
let pass = true;
for (let i = 0; i < diyStore.value[index].options.length; i++) {
if (!diyStore.value[index].options[i].text) {
res.code = false;
res.message = t('optionPlaceholder');
pass = false;
break;
}
}
const res = { code: true, message: '' }
let pass = true;
for (let i = 0; i < diyStore.value[index].options.length; i++) {
if (!diyStore.value[index].options[i].text) {
res.code = false;
res.message = t('optionPlaceholder');
pass = false;
break;
}
}
if (!pass) return res;
if (!pass) return res;
let uniqueOptions = uniqueByKey(diyStore.value[index].options, 'text')
let uniqueOptions = uniqueByKey(diyStore.value[index].options, 'text')
if (uniqueOptions.length != diyStore.value[index].options.length) {
res.code = false;
res.message = t('errorTipsOne')
}
return res
if (uniqueOptions.length != diyStore.value[index].options.length) {
res.code = false;
res.message = t('errorTipsOne')
}
return res
}
diyStore.editComponent.options.forEach((item: any) => {
if (!item.id) item.id = diyStore.generateRandom()
if (!item.id) item.id = diyStore.generateRandom()
})
const visible = ref(false)
const optionsValue = ref()
const addOption = () => {
diyStore.editComponent.options.push({
id: diyStore.generateRandom(),
text: '选项' + (diyStore.editComponent.options.length + 1)
});
diyStore.editComponent.options.push({
id: diyStore.generateRandom(),
text: '选项' + (diyStore.editComponent.options.length + 1)
});
};
const removeOption = (index:any) => {
const removeOption = (index: any) => {
diyStore.editComponent.options.splice(index, 1);
}
const batchAddOptions = () => {
if (optionsValue.value.trim()) {
const newOptions = optionsValue.value.split(',').map((option: any) => {
return {
id: diyStore.generateRandom(),
text: option.trim()
};
}).filter((option: any) => option.text !== '');
if (optionsValue.value.trim()) {
const newOptions = optionsValue.value.split(',').map((option: any) => {
return {
id: diyStore.generateRandom(),
text: option.trim()
};
}).filter((option: any) => option.text !== '');
//
const uniqueNewOptions = uniqueByKey(newOptions, 'text');
//
const uniqueNewOptions = uniqueByKey(newOptions, 'text');
//
const filteredNewOptions = uniqueNewOptions.filter(newOption =>
!diyStore.editComponent.options.some(existingOption => existingOption.text === newOption.text)
);
//
const filteredNewOptions = uniqueNewOptions.filter(newOption =>
!diyStore.editComponent.options.some(existingOption => existingOption.text === newOption.text)
);
//
if (filteredNewOptions.length > 0) {
diyStore.editComponent.options.push(...filteredNewOptions);
} else {
ElMessage({
message: t('errorTipsTwo'),
type: "warning",
});
}
//
if (filteredNewOptions.length > 0) {
diyStore.editComponent.options.push(...filteredNewOptions);
} else {
ElMessage({
message: t('errorTipsTwo'),
type: "warning",
});
}
optionsValue.value = '';
visible.value = false;
}
optionsValue.value = '';
visible.value = false;
}
};
//
const uniqueByKey = (arr: any, key: any) => {
const seen = new Set();
return arr.filter((item: any) => {
const serializedKey = JSON.stringify(item[key]);
return seen.has(serializedKey) ? false : seen.add(serializedKey);
});
const seen = new Set();
return arr.filter((item: any) => {
const serializedKey = JSON.stringify(item[key]);
return seen.has(serializedKey) ? false : seen.add(serializedKey);
});
}
const formRadioRef = ref()

View File

@ -1,75 +1,79 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('floatBtnButton')" class="display-block">
<el-radio-group v-model="diyStore.editComponent.btnPosition" @change="btnPositionChangeFn">
<el-radio label="follow_content">{{ t('followContent') }}</el-radio>
<el-radio label="hover_screen_bottom">{{ t('hoverScreenBottom') }}</el-radio>
</el-radio-group>
<div class="text-sm text-gray-400 mb-[5px] leading-[1.4]" v-show="diyStore.editComponent.btnPosition == 'follow_content'">{{ t('btnTips') }}</div>
<div class="text-sm text-gray-400 mb-[5px]" v-show="diyStore.editComponent.btnPosition == 'hover_screen_bottom'">{{ t('btnTipsTwo') }}</div>
<el-form-item :label="t('floatBtnButton')" class="display-block">
<el-radio-group v-model="diyStore.editComponent.btnPosition" @change="btnPositionChangeFn">
<el-radio label="follow_content">{{ t('followContent') }}</el-radio>
<el-radio label="hover_screen_bottom">{{ t('hoverScreenBottom') }}</el-radio>
</el-radio-group>
<div class="text-sm text-gray-400 mb-[5px] leading-[1.4]"
v-show="diyStore.editComponent.btnPosition == 'follow_content'">{{ t('btnTips') }}
</div>
<div class="text-sm text-gray-400 mb-[5px]"
v-show="diyStore.editComponent.btnPosition == 'hover_screen_bottom'">{{ t('btnTipsTwo') }}
</div>
<div class="text-sm text-gray-400 mb-[10px] leading-[1.4]">{{ t('btnTipsThree') }}</div>
</el-form-item>
</el-form>
</el-form-item>
</el-form>
</div>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('submitBtn') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('submitBtnName')">
<el-input v-model.trim="diyStore.editComponent.submitBtn.text" :placeholder="t('btnNamePlaceholder')" clearable maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.submitBtn.color" />
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.submitBtn.bgColor" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('submitBtn') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('submitBtnName')">
<el-input v-model.trim="diyStore.editComponent.submitBtn.text" :placeholder="t('btnNamePlaceholder')" clearable maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.submitBtn.color" />
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.submitBtn.bgColor" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('resetBtn') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('carouselSearchTabControl')">
<el-switch v-model="diyStore.editComponent.resetBtn.control" />
</el-form-item>
<el-form-item :label="t('submitBtnName')">
<el-input v-model.trim="diyStore.editComponent.resetBtn.text" :placeholder="t('btnNamePlaceholder')" clearable maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.resetBtn.color" />
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.resetBtn.bgColor" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('resetBtn') }}</h3>
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('carouselSearchTabControl')">
<el-switch v-model="diyStore.editComponent.resetBtn.control" />
</el-form-item>
<el-form-item :label="t('submitBtnName')">
<el-input v-model.trim="diyStore.editComponent.resetBtn.text" :placeholder="t('btnNamePlaceholder')" clearable maxlength="10" show-word-limit />
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.resetBtn.color" />
</el-form-item>
<el-form-item :label="t('subTextBgColor')">
<el-color-picker v-model="diyStore.editComponent.resetBtn.bgColor" />
</el-form-item>
</el-form>
</div>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('btnStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('btnStyle') }}</h3>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('topRounded')">
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
<el-form-item :label="t('bottomRounded')">
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -81,8 +85,8 @@ const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['componentBgUrl'] //
//
const btnPositionChangeFn = (e)=>{
if(e == 'hover_screen_bottom'){
const btnPositionChangeFn = (e) => {
if (e == 'hover_screen_bottom') {
diyStore.editComponent.margin.bottom = 0;
diyStore.editComponent.margin.both = 0;
diyStore.editComponent.margin.top = 0;
@ -91,19 +95,19 @@ const btnPositionChangeFn = (e)=>{
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
if (diyStore.value[index].submitBtn.text == '') {
res.code = false;
res.message = t('submitBtnNamePlaceholder');
return res;
}
if (diyStore.value[index].resetBtn.text == '') {
res.code = false;
res.message = t('resetBtnNamePlaceholder');
return res;
}
const res = { code: true, message: '' }
if (diyStore.value[index].submitBtn.text == '') {
res.code = false;
res.message = t('submitBtnNamePlaceholder');
return res;
}
if (diyStore.value[index].resetBtn.text == '') {
res.code = false;
res.message = t('resetBtnNamePlaceholder');
return res;
}
return res
return res
}
defineExpose({})

View File

@ -1,44 +1,412 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
todo 此处编写表格组件的属性
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('列设置')">
<div ref="imageBoxRef">
<div v-for="(item, index) in diyStore.editComponent.columnList" :key="item.id"
class="border-b-[1px] border-[#e0e0e0] py-1">
<div class="flex items-center justify-between">
<div class="flex">
<span :class="['iconfont', 'ml-[5px]', 'cursor-pointer', getIconClass(item.type)]"></span>
<el-input v-model="item.name" class="input-style" :input-style="{ boxShadow: 'none' }"
:placeholder="t('请输入列名')" />
</div>
<div class="flex">
<span v-if="diyStore.editComponent.columnList.length > 1" @click="removeOption(index)"
class="cursor-pointer ml-[5px] nc-iconfont nc-icon-shanchu-yuangaizhiV6xx"></span>
<span class="cursor-pointer ml-[5px] nc-iconfont nc-icon-xiaV6xx"></span>
</div>
</div>
<div v-if="item.type == 'radio'" class="flex">
<div class="text-[#999] mr-3" >{{ item.options?.length || 0 }}个选项</div>
<span class="text-primary cursor-pointer mr-[10px]" @click="openRadioDialog(item, index)">{{ t('编辑') }}</span>
</div>
<div v-if="item.type == 'date'" class="flex">
<span class="text-primary cursor-pointer mr-[10px]" @click="openRadioDialog(item, index)">{{ t('设置日期格式') }}</span>
</div>
<div v-if="item.type == 'address'" class="flex">
<div class="text-[#999] mr-3">精确到详细地址</div>
<span class="text-primary cursor-pointer mr-[10px]" @click="openRadioDialog(item, index)">{{ t('设置') }}</span>
</div>
</div>
</div>
<el-popover placement="bottom" :width="50" trigger="hover">
<template #reference>
<span class="text-primary cursor-pointer mr-[10px]">{{ t('添加') }}</span>
</template>
<div v-for="(item, index) in columnTypeOptions" :key="index" @click="addOption(item)"
class="cursor-pointer hover:bg-[#d1e1ff] rounded text-center">
<div class="py-1 text-[var(--el-text-color-primary]">{{ item.label }}</div>
</div>
</el-popover>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</el-form-item>
<el-form-item :label="t('是否自增')">
<el-switch v-model="diyStore.editComponent.autoIncrementControl" />
</el-form-item>
<el-form-item :label="t('填写限制')" v-if="diyStore.editComponent.autoIncrementControl">
<div class="flex items-center">
<span>默认显示</span>
<el-input v-model="diyStore.editComponent.writeLimit.default" class="input-short" :placeholder="t('')" />
<span></span>
</div>
<div class="flex items-center my-1">
<span>最少填写</span>
<el-input v-model="diyStore.editComponent.writeLimit.min" class="input-short" :placeholder="t('')" />
<span></span>
</div>
<div class="flex items-center">
<span>最多填写</span>
<el-input v-model="diyStore.editComponent.writeLimit.max" class="input-short" :placeholder="t('')" />
<span></span>
</div>
</el-form-item>
<el-form-item :label="t('按钮名称')" v-if="diyStore.editComponent.autoIncrementControl">
<el-input v-model="diyStore.editComponent.btnText" :placeholder="t('请输入按钮名称')" />
</el-form-item>
</el-form>
<!-- 单选项 -->
<!-- <el-dialog v-model="radioDialogVisible" :title="t('设置单选项')" width="500">
<div v-if="activeColumnTemp.type == 'radio'">
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('选项名称')">
<el-input v-model="activeColumnTemp.name" :input-style="{ boxShadow: 'none' }" />
</el-form-item>
<el-form-item :label="t('设置选项')">
<div ref="radioBoxRef">
<div v-for="(opt, idx) in activeColumnTemp.options" :key="opt.id">
<div class="flex items-center justify-between mb-2">
<div class="flex-1">
<el-input v-model="opt.label" :input-style="{ boxShadow: 'none' }"
:placeholder="t('请输入')" />
</div>
<span v-if="activeColumnTemp.options.length > 1" @click="removeOptionItem(idx)"
class="cursor-pointer ml-[5px] nc-iconfont nc-icon-shanchu-yuangaizhiV6xx"></span>
<span class="cursor-pointer ml-[5px] nc-iconfont nc-icon-iconpaixu1"></span>
</div>
</div>
<span class="text-primary cursor-pointer mr-[10px]" @click="addOptionItem">{{ t('添加选项') }}</span>
<span class="text-primary cursor-pointer mr-[10px]" @click="addOtherOption">{{ t('添加其它项') }}</span>
<el-popover :visible="visible" placement="bottom" :width="300">
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200"
show-word-limit />
<div class="mt-[10px] text-right">
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
<el-button size="small" type="primary" @click="batchAddOptions">{{t('confirm')}}</el-button>
</div>
<template #reference>
<span class="text-primary cursor-pointer"
@click="visible = true">{{ t('addMultipleOption') }}</span>
</template>
</el-popover>
</div>
</el-form-item>
</el-form>
</div>
<div v-else-if="activeColumnTemp.type == 'date'">
<el-form>
<el-form-item :label="t('dataFormat')">
<el-radio-group v-model="activeColumnTemp.dateFormat" class="!block">
<el-radio class="!block" label="YYYY年M月D日">{{ dateFormat.format1 }}</el-radio>
<el-radio class="!block" label="YYYY-MM-DD">{{ dateFormat.format2 }}</el-radio>
<el-radio class="!block" label="YYYY/MM/DD">{{ dateFormat.format3 }}</el-radio>
<el-radio class="!block" label="YYYY-MM-DD HH:mm">{{ dateFormat.format4 }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
<div v-else-if="activeColumnTemp.type == 'address'">
<el-form>
<el-form-item :label="t('地址格式')">
<el-radio-group v-model="activeColumnTemp.addressFormat" class="!block">
<el-radio class="!block" label="province/city/district/address">{{ t('省/市/区/街道/详细地址') }}</el-radio>
<el-radio class="!block" label="province/city/district/street">{{ t('省/市/区/街道(镇)') }}</el-radio>
<el-radio class="!block" label="province/city/district">{{ t('省/市/区(县)') }}</el-radio>
<el-radio class="!block" label="province/city">{{ t('省/市') }}</el-radio>
<el-radio class="!block" label="province">{{ t('省') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="radioDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleDialogConfirm">确定</el-button>
</div>
</template>
</el-dialog> -->
</div>
<div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
</div>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref } from 'vue'
import Sortable from 'sortablejs'
import { ref, watch, onMounted, nextTick ,reactive, computed} from 'vue'
import useDiyStore from '@/stores/modules/diy'
import { range } from 'lodash-es'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = ['componentBgUrl'] //
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
// todo
return res
}
//
const columnTypeOptions = ref([
{ label: '单选项', value: 'radio' },
{ label: '文本', value: 'text' },
{ label: '数字', value: 'number' },
{ label: '手机号', value: 'mobile' },
{ label: '地址', value: 'address' },
{ label: '身份证', value: 'idcard' },
{ label: '性别', value: 'gender' },
{ label: '日期', value: 'date' }
])
const getIconClass = (type:any) => {
switch (type) {
case 'radio':
return 'icona-duihaopc30'
case 'text':
return 'icona-danhangwenben-1pc30'
case 'number':
return 'icona-shuzipc30-1'
case 'mobile':
return 'icona-shoujipc30'
case 'address':
return 'iconbiaotipc'
case 'idcard':
return 'icona-shenfenzhengpc30'
case 'gender':
return 'el-icon-s-opportunity'
case 'date':
return 'icona-riqipc30'
default:
return ''
}
}
const imageBoxRef = ref()
const generateId = () => Date.now().toString(36) + Math.random().toString(36).substr(2, 5)
//
const addOption = (item) => {
const newColumn: any = {
id: generateId(),
name: item.label,
type: item.value, //
value: '' //
}
// options
if (item.value === 'radio') {
newColumn.options = [
{ id: generateId(), label: '选项1' },
{ id: generateId(), label: '选项2' }
]
}
// dateFormat
if (item.value === 'date') {
newColumn.dateFormat = 'YYYY年M月D日' //
}
// addressFormat
if (item.value === 'address') {
newColumn.addressFormat = 'province/city/district/address' //
}
diyStore.editComponent.columnList.push(newColumn)
}
const removeOption = (index: number) => {
diyStore.editComponent.columnList.splice(index, 1)
}
onMounted(() => {
// nextTick(() => {
// if (diyStore.editComponent.columnList.length < 2) return;
// const sortable = Sortable.create(imageBoxRef.value, {
// group: 'item-wrap',
// animation: 200,
// onEnd: event => {
// const temp = diyStore.editComponent.columnList[event.oldIndex!]
// diyStore.editComponent.columnList.splice(event.oldIndex!, 1)
// diyStore.editComponent.columnList.splice(event.newIndex!, 0, temp)
// sortable.sort(
// range(diyStore.editComponent.columnList.length).map(value => {
// return value.toString()
// })
// )
// }
// })
// })
console.log(diyStore.editComponent.columnList);
})
const activeColumn = ref<any>({}) //
const activeColumnTemp = ref<any>({}) //
const activeRadioIndex = ref(0) //
const radioDialogVisible = ref(false)
const radioBoxRef = ref()
const optionsValue = ref('')
const visible = ref(false)
const dateFormat: any = reactive({
format1: '',
format2: '',
format3: '',
format4: ''
});
const openRadioDialog = (item, index) => {
activeRadioIndex.value = index // 便
activeColumn.value = item
activeColumnTemp.value = JSON.parse(JSON.stringify(item)) //
if(item.type == 'radio'){
if (!activeColumnTemp.value.options) activeColumnTemp.value.options = []
radioDialogVisible.value = true
// nextTick(() => initRadioSortable()) //
}else if(item.type == 'date'){
//
const today = new Date();
let year = today.getFullYear();
let month = String(today.getMonth() + 1).padStart(2, '0');
let day = String(today.getDate()).padStart(2, '0');
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
dateFormat.format1 = `${ year }${ month }${ day }`;
dateFormat.format2 = `${ year }-${ month }-${ day }`;
dateFormat.format3 = `${ year }/${ month }/${ day }`;
dateFormat.format4 = `${ year }-${ month }-${ day } ${ hours }:${ minutes }`;
radioDialogVisible.value = true
} else if(item.type == 'address'){
radioDialogVisible.value = true
}
}
//
// const initRadioSortable = () => {
// Sortable.create(radioBoxRef.value, {
// group: 'radio-option-wrap',
// animation: 200,
// draggable: '.drag-radio-item',
// onEnd: event => {
// const options = activeColumnTemp.value.options // temp
// const temp = options[event.oldIndex!]
// options.splice(event.oldIndex!, 1)
// options.splice(event.newIndex!, 0, temp)
// }
// })
// }
const handleDialogConfirm = () => {
console.log(activeColumnTemp.value);
diyStore.editComponent.columnList[activeRadioIndex.value] = JSON.parse(JSON.stringify(activeColumnTemp.value)) //
radioDialogVisible.value = false //
}
const addOptionItem = () => {
const newOption = { id: generateId(), label: '选项' + (activeColumnTemp.value.options.length + 1) }
activeColumnTemp.value.options.push(newOption)
}
const addOtherOption = () => {
const newOption = { id: generateId(), label: '其他' }
activeColumnTemp.value.options.push(newOption)
}
const removeOptionItem = (index: number) => {
activeColumnTemp.value.options.splice(index, 1)
}
//
const uniqueByKey = (arr: any, key: any) => {
const seen = new Set();
return arr.filter((item: any) => {
const serializedKey = JSON.stringify(item[key]);
return seen.has(serializedKey) ? false : seen.add(serializedKey);
});
}
//
const batchAddOptions = () => {
if (optionsValue.value.trim()) {
const newOptions = optionsValue.value.split(',').map((option: any) => {
return {
id: diyStore.generateRandom(),
label: option.trim()
};
}).filter((option: any) => option.label !== '');
//
const uniqueNewOptions = uniqueByKey(newOptions, 'label');
//
const filteredNewOptions = uniqueNewOptions.filter(newOption =>
!activeColumnTemp.value.options.some(existingOption => existingOption.label === newOption.label)
);
//
if (filteredNewOptions.length > 0) {
activeColumnTemp.value.options.push(...filteredNewOptions);
} else {
ElMessage({
message: t('errorTipsTwo'),
type: "warning",
});
}
optionsValue.value = '';
visible.value = false;
}
};
defineExpose({})
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
:deep(.input-style .el-input__wrapper) {
box-shadow: none !important;
}
.input-short{
width: 80px;
margin: 0 10px;
}
</style>

View File

@ -1,66 +1,67 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.trim="diyStore.editComponent.field.default" :placeholder="t('defaultValuePlaceholder')" clearable maxlength="18" show-word-limit />
</el-form-item>
<el-form-item :label="t('rowCount')">
<el-input v-model.trim="diyStore.editComponent.rowCount" :placeholder="t('rowCountPlaceholder')" clearable maxlength="2" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-input v-model.trim="diyStore.editComponent.field.default"
:placeholder="t('defaultValuePlaceholder')" clearable maxlength="18" show-word-limit />
</el-form-item>
<el-form-item :label="t('rowCount')">
<el-input v-model.trim="diyStore.editComponent.rowCount" :placeholder="t('rowCountPlaceholder')" clearable maxlength="2" show-word-limit />
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!--<el-form label-width="100px" class="px-[10px]">
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>会自动将提交的个人信息做加密展示</p>
<p>适用于公开展示收集的数据且不暴露用户隐私</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏文本,仅管理员可查看') }}</div>
</el-form-item>
</el-form>-->
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!--<el-form label-width="100px" class="px-[10px]">
<el-form-item class="display-block">
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
<el-tooltip effect="light" placement="top">
<template #content>
<p>会自动将提交的个人信息做加密展示</p>
<p>适用于公开展示收集的数据且不暴露用户隐私</p>
</template>
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏文本,仅管理员可查看') }}</div>
</el-form-item>
</el-form>-->
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
@ -74,7 +75,7 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// todo
// todo
return res
}
defineExpose({})

View File

@ -1,86 +1,88 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('startTime') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.start.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.start.defaultControl"/>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.start.defaultControl">
<el-radio-group v-model="diyStore.editComponent.start.timeWay">
<el-radio label="current">{{ t('currentTime') }}</el-radio>
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.timeWay == 'diy'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('startTime') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.start.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.start.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.start.defaultControl">
<el-radio-group v-model="diyStore.editComponent.start.timeWay">
<el-radio label="current">{{ t('currentTime') }}</el-radio>
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.timeWay == 'diy'">
<el-time-picker v-model="diyStore.editComponent.field.default.start.date" :placeholder="t('startTimePlaceholder')" format="HH:mm" value-format="HH:mm" @change="startTimePickerChange" />
</el-form-item>
</el-form>
</div>
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('endTime') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.end.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.end.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.end.defaultControl">
<el-radio-group v-model="diyStore.editComponent.end.timeWay">
<el-radio label="current">{{ t('currentTime') }}</el-radio>
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.timeWay == 'diy'">
<el-time-picker :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" v-model="diyStore.editComponent.field.default.end.date" :placeholder="t('endTimePlaceholder')" format="HH:mm" value-format="HH:mm" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('endTime') }}</h3>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.end.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.end.defaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.end.defaultControl">
<el-radio-group v-model="diyStore.editComponent.end.timeWay">
<el-radio label="current">{{ t('currentTime') }}</el-radio>
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.timeWay == 'diy'">
<el-time-picker :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" v-model="diyStore.editComponent.field.default.end.date" :placeholder="t('endTimePlaceholder')" format="HH:mm" value-format="HH:mm" />
</el-form-item>
</el-form>
</div>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<div class="edit-attr-item-wrap">
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('textFontSize')">
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
</el-form-item>
<el-form-item :label="t('textFontWeight')">
<el-radio-group v-model="diyStore.editComponent.fontWeight">
<el-radio :label="'normal'">{{ t('fontWeightNormal') }}</el-radio>
<el-radio :label="'bold'">{{ t('fontWeightBold') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="t('textColor')">
<el-color-picker v-model="diyStore.editComponent.textColor" />
</el-form-item>
</el-form>
</div>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref,onMounted } from 'vue'
import { ref, onMounted } from 'vue'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
@ -96,25 +98,25 @@ diyStore.editComponent.verify = (index: number) => {
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
if(diyStore.editComponent.start.timeWay == 'current'){
starTime = `${hours}:${minutes}`;
if (diyStore.editComponent.start.timeWay == 'current') {
starTime = `${ hours }:${ minutes }`;
}
if(diyStore.editComponent.end.timeWay == 'current'){
endTime = `${hours}:${minutes}`;
if (diyStore.editComponent.end.timeWay == 'current') {
endTime = `${ hours }:${ minutes }`;
}
if(diyStore.editComponent.start.defaultControl && starTime == ''){
if (diyStore.editComponent.start.defaultControl && starTime == '') {
res.code = false
res.message = t('startTimeTips')
return res
}
if(diyStore.editComponent.end.defaultControl && endTime == ''){
if (diyStore.editComponent.end.defaultControl && endTime == '') {
res.code = false
res.message = t('endTimeTips')
return res
}
if(diyStore.editComponent.start.defaultControl && diyStore.editComponent.end.defaultControl && timeInvertSecond(starTime) > timeInvertSecond(endTime)){
if (diyStore.editComponent.start.defaultControl && diyStore.editComponent.end.defaultControl && timeInvertSecond(starTime) > timeInvertSecond(endTime)) {
res.code = false
res.message = t('startEndTimeTips')
return res
@ -122,28 +124,26 @@ diyStore.editComponent.verify = (index: number) => {
return res
}
onMounted(() => {
const today = new Date();
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
if(!diyStore.editComponent.field.default.start.date){
diyStore.editComponent.field.default.start.date = `${hours}:${minutes}`;
diyStore.editComponent.field.default.start.timestamp = timeInvertSecond(`${hours}:${minutes}`);
if (!diyStore.editComponent.field.default.start.date) {
diyStore.editComponent.field.default.start.date = `${ hours }:${ minutes }`;
diyStore.editComponent.field.default.start.timestamp = timeInvertSecond(`${ hours }:${ minutes }`);
}
if(!diyStore.editComponent.field.default.end.date){
if (!diyStore.editComponent.field.default.end.date) {
let endDate = new Date();
endDate.setHours(today.getHours(), today.getMinutes() + 10, 0, 0); // 10
const endHours = String(endDate.getHours()).padStart(2, '0');
const endMinutes = String(endDate.getMinutes()).padStart(2, '0');
diyStore.editComponent.field.default.end.date = `${endHours}:${endMinutes}`;
diyStore.editComponent.field.default.end.timestamp = timeInvertSecond(`${endHours}:${endMinutes}`);
diyStore.editComponent.field.default.end.date = `${ endHours }:${ endMinutes }`;
diyStore.editComponent.field.default.end.timestamp = timeInvertSecond(`${ endHours }:${ endMinutes }`);
}
});
//
const startTimePickerChange = (e) => {
diyStore.editComponent.field.default.start.timestamp = timeInvertSecond(e);
@ -152,24 +152,24 @@ const startTimePickerChange = (e) => {
const date = new Date();
date.setHours(parseInt(startTimeArr[0]), parseInt(startTimeArr[1]), 0, 0);
date.setMinutes(date.getMinutes() + 10);
const updatedEndTime = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
const updatedEndTime = `${ String(date.getHours()).padStart(2, '0') }:${ String(date.getMinutes()).padStart(2, '0') }`;
diyStore.editComponent.field.default.end.date = updatedEndTime;
diyStore.editComponent.field.default.end.timestamp = timeInvertSecond(updatedEndTime);
}
//
const endTimePickerChange = (e)=>{
const endTimePickerChange = (e) => {
diyStore.editComponent.field.default.end.timestamp = timeInvertSecond(e);
}
const disabledHours = () => {
let timeArr = diyStore.editComponent.field.default.start.date.split(":")
return makeRange(0,timeArr[0]);
return makeRange(0, timeArr[0]);
}
const disabledMinutes = (hour: number) => {
let timeArr = diyStore.editComponent.field.default.start.date.split(":")
return makeRange(0,timeArr[1]);
return makeRange(0, timeArr[1]);
}
const makeRange = (start: number, end: number) => {
@ -180,16 +180,16 @@ const makeRange = (start: number, end: number) => {
return result
}
const timeInvertSecond = (time:any)=>{
const timeInvertSecond = (time: any) => {
let arr = time.split(":");
let num = 0;
if(arr[0]){
if (arr[0]) {
num += arr[0] * 60 * 60;
}
if(arr[1]){
if (arr[1]) {
num += arr[1] * 60;
}
if(arr[2]){
if (arr[2]) {
num += arr[2];
}
return num;

View File

@ -1,47 +1,47 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.defaultControl" @change="changeDateDefaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl">
<el-radio-group v-model="diyStore.editComponent.timeWay">
<el-radio label="current">{{ t('currentTime') }}</el-radio>
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl && diyStore.editComponent.timeWay == 'diy'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
<el-form-item :label="t('formPlaceholder')">
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
</el-form-item>
<el-form-item :label="t('defaultValue')">
<el-switch v-model="diyStore.editComponent.defaultControl" @change="changeDateDefaultControl" />
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl">
<el-radio-group v-model="diyStore.editComponent.timeWay">
<el-radio label="current">{{ t('currentTime') }}</el-radio>
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="diyStore.editComponent.defaultControl && diyStore.editComponent.timeWay == 'diy'">
<el-time-picker v-model="diyStore.editComponent.field.default" :placeholder="t('timePlaceholder')" format="HH:mm" value-format="HH:mm" />
</el-form-item>
</el-form>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import { ref,watch,onMounted } from 'vue'
import { ref, watch, onMounted } from 'vue'
import useDiyStore from '@/stores/modules/diy'
const diyStore = useDiyStore()
@ -54,32 +54,32 @@ diyStore.editComponent.verify = (index: number) => {
}
onMounted(() => {
//
if (!diyStore.editComponent.field.default) {
const today = new Date();
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
diyStore.editComponent.field.default = `${hours}:${minutes}`;
}
});
const changeDateDefaultControl = (val: any) => {
if (val) {
const today = new Date();
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
diyStore.editComponent.field.default = `${hours}:${minutes}`;
}
}
watch(
() => diyStore.editComponent.timeWay,
(newVal) => {
//
if (!diyStore.editComponent.field.default) {
const today = new Date();
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
diyStore.editComponent.field.default = `${hours}:${minutes}`;
}
diyStore.editComponent.field.default = `${ hours }:${ minutes }`;
}
});
const changeDateDefaultControl = (val: any) => {
if (val) {
const today = new Date();
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
diyStore.editComponent.field.default = `${ hours }:${ minutes }`;
}
}
watch(
() => diyStore.editComponent.timeWay,
(newVal) => {
const today = new Date();
const hours = String(today.getHours()).padStart(2, '0');
const minutes = String(today.getMinutes()).padStart(2, '0');
diyStore.editComponent.field.default = `${ hours }:${ minutes }`;
}
);
defineExpose({})

View File

@ -1,30 +1,42 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item :label="t('上传方式')">
<el-radio-group v-model="diyStore.editComponent.uploadMode">
<el-radio label="shoot_and_album">{{ t('拍摄和相册') }}</el-radio>
<el-radio label="shoot_only">{{ t('只允许拍摄') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 表单组件 字段内容设置 -->
<slot name="field"></slot>
<el-form label-width="100px" class="px-[10px]">
<el-form-item>
<template #label>
<div class="flex items-center">
<span class="mr-[3px]">{{ t('上传方式') }}</span>
<el-tooltip effect="light" :content="t('拍摄时长限制1分钟从相册上传不限制时长。')" placement="top">
<el-icon>
<QuestionFilled color="#999999" />
</el-icon>
</el-tooltip>
</div>
</template>
<el-radio-group v-model="diyStore.editComponent.uploadMode">
<el-radio label="shoot_and_album">{{ t('拍摄和相册') }}</el-radio>
<el-radio label="shoot_only">{{ t('只允许拍摄') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<!-- 表单组件 其他设置 -->
<slot name="other"></slot>
</div>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 表单组件 字段样式 -->
<slot name="style-field"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</div>
</template>
<script lang="ts" setup>

Some files were not shown because too many files have changed in this diff Show More