mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-03-12 10:55:30 +00:00
0.0.9
This commit is contained in:
parent
34671d6c3d
commit
026d5fa334
@ -5,7 +5,7 @@ import request from '@/utils/request'
|
||||
* @returns
|
||||
*/
|
||||
export function getAddonLocal(params: Record<string, any>) {
|
||||
return request.get('addon/local', params, {showSuccessMessage: true})
|
||||
return request.get('addon/local', params, { showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -9,6 +9,13 @@ export function login(params: Record<string, any>, app_type: string) {
|
||||
return request.get(`login/${app_type}`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
export function logout() {
|
||||
return request.put('auth/logout', {}, { showErrorMessage: false })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户权限
|
||||
* @returns
|
||||
|
||||
@ -5,7 +5,7 @@ import request from '@/utils/request'
|
||||
* @param addon
|
||||
*/
|
||||
export function cloudBuild() {
|
||||
return request.post('niucloud/build')
|
||||
return request.post('niucloud/build', {}, { timeout: 0 })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -108,6 +108,13 @@ export function getDiyTemplate(params: Record<string, any>) {
|
||||
return request.get(`diy/template`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板页面列表
|
||||
*/
|
||||
export function getDiyTemplatePages(params: Record<string, any>) {
|
||||
return request.get(`diy/template/pages`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义路由列表
|
||||
* @param params
|
||||
@ -152,10 +159,10 @@ export function changeTemplate(params: Record<string, any>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取预览数据
|
||||
* 获取模板页面的应用插件列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getPreviewData(params: Record<string, any>) {
|
||||
return request.put(`diy/preview`, params, {showSuccessMessage: false})
|
||||
export function getApps(params: Record<string, any>) {
|
||||
return request.get(`diy/apps`)
|
||||
}
|
||||
@ -166,6 +166,14 @@ export function getWebConfig() {
|
||||
return request.get('sys/web/website')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取网站设置
|
||||
* @returns
|
||||
*/
|
||||
export function getWebCopyright() {
|
||||
return request.get('sys/web/copyright')
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新网站设置
|
||||
* @param params
|
||||
|
||||
@ -29,7 +29,7 @@ export function upgradeAddon(addon: string = '') {
|
||||
* 执行升级
|
||||
*/
|
||||
export function executeUpgrade() {
|
||||
return request.post('upgrade/execute')
|
||||
return request.post('upgrade/execute', {}, { timeout: 0 })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
BIN
admin/src/app/assets/images/gov_icon.png
Normal file
BIN
admin/src/app/assets/images/gov_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@ -293,6 +293,8 @@ watch(() => showDialog.value, () => {
|
||||
})
|
||||
|
||||
const clearUpgradeTaskFn = () => {
|
||||
active.value = 'content'
|
||||
uploading.value = false
|
||||
upgradeTask.value = null
|
||||
upgradeLog = []
|
||||
flashInterval && clearInterval(flashInterval)
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
{
|
||||
"templatePagePlaceholder": "选择模板",
|
||||
"templatePageEmpty": "无",
|
||||
"changeTemplatePageTips":"切换模板后,当前页面内容将被替换且不被保存,请谨慎操作",
|
||||
"developTitle": "开发环境配置",
|
||||
"wapDomain": "wap域名(WAP_DOMAIN)",
|
||||
"wapDomainPlaceholder": "请输入wap域名",
|
||||
|
||||
@ -1,24 +1,12 @@
|
||||
{
|
||||
"decorate": "装修",
|
||||
"pageDecorate": "页面装修",
|
||||
"changeTemplate": "选择页面",
|
||||
"changePage": "切换",
|
||||
"templateName": "模板名称",
|
||||
"changePage": "设置",
|
||||
"preview": "预览",
|
||||
"hopeBeforeTip": "我希望把",
|
||||
"hopeAfterTip": "切换成其他页面",
|
||||
"changeTemplateTip": "选择",
|
||||
"template": "模板",
|
||||
"changeMyPageTip": "将 微页面 设为",
|
||||
"changeOtherPageTip": "将 其他页面 设为",
|
||||
"createPage": "创建微页面",
|
||||
"myPage": "我的微页面",
|
||||
"refreshPage": "刷新",
|
||||
"placeholderTemplate": "请选择一个模板",
|
||||
"placeholderMyPage": "请选择一个微页面",
|
||||
"placeholderOtherPage": "请选择一个页面",
|
||||
"developTitle": "开发环境配置",
|
||||
"wapDomain": "wap域名(WAP_DOMAIN)",
|
||||
"wapDomainPlaceholder": "请输入wap域名",
|
||||
"settingTips": "点击查看如何配置"
|
||||
"settingTips": "点击查看如何配置",
|
||||
"link": "链接",
|
||||
"copy": "复制",
|
||||
"scanQRCodeOnRight": "扫描右侧二维码查看"
|
||||
}
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
{
|
||||
"title": "页面名称",
|
||||
"typeName": "页面模板",
|
||||
"templateName": "模板名称",
|
||||
"addType": "页面类型",
|
||||
"typeName": "页面类型",
|
||||
"forAddon": "所属插件",
|
||||
"addPageTips": "创建新页面",
|
||||
"pageTypePlaceholder": "请选择页面模板",
|
||||
"pageTypePlaceholder": "请选择页面类型",
|
||||
"nameMax": "名称不能超过12个字符",
|
||||
"emptyTemplate": "空模板",
|
||||
"status": "状态",
|
||||
"updateTime": "更新时间",
|
||||
"use": "使用",
|
||||
|
||||
11
admin/src/app/lang/zh-cn/diy.member.json
Normal file
11
admin/src/app/lang/zh-cn/diy.member.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"decorate": "装修",
|
||||
"preview": "预览",
|
||||
"developTitle": "开发环境配置",
|
||||
"wapDomain": "wap域名(WAP_DOMAIN)",
|
||||
"wapDomainPlaceholder": "请输入wap域名",
|
||||
"settingTips": "点击查看如何配置",
|
||||
"link": "链接",
|
||||
"copy": "复制",
|
||||
"scanQRCodeOnRight": "扫描右侧二维码查看"
|
||||
}
|
||||
@ -1,28 +1,13 @@
|
||||
{
|
||||
"title": "页面名称",
|
||||
"forAddon": "所属插件",
|
||||
"typeName": "页面模板",
|
||||
"addPageTips": "创建新页面",
|
||||
"pageTemplatePlaceholder": "请选择页面模板",
|
||||
"nameMax": "名称不能超过12个字符",
|
||||
"templateName": "模板名称",
|
||||
"empty": "空白",
|
||||
"status": "状态",
|
||||
"updateTime": "更新时间",
|
||||
"use": "使用",
|
||||
"isUse": "使用中",
|
||||
"unused": "未使用",
|
||||
"all": "全部",
|
||||
"basicRoute": "基础页面",
|
||||
"diyPage": "自定义页面",
|
||||
"wapUrl": "wap链接",
|
||||
"weappUrl": "小程序链接",
|
||||
"shareLink": "分享链接",
|
||||
"copy": "复制",
|
||||
"copySuccess": "复制成功",
|
||||
"titlePlaceholder": "请输入页面名称",
|
||||
"addDiyPage": "添加页面",
|
||||
"diyPageDeleteTips": "确定要删除该自定义页面吗?",
|
||||
"promote": "推广",
|
||||
"share": "分享",
|
||||
"shareSet": "分享设置",
|
||||
|
||||
@ -17,5 +17,7 @@
|
||||
"remark": "套餐说明",
|
||||
"reset": "重置",
|
||||
"search": "搜索",
|
||||
"foldText":"展开/折叠"
|
||||
}
|
||||
"foldText":"展开/折叠",
|
||||
"appName": "套餐内含应用",
|
||||
"addonName": "套餐内含插件"
|
||||
}
|
||||
|
||||
@ -27,7 +27,9 @@
|
||||
"keywordsPlaceholder": "网站关键字",
|
||||
"logoPlaceholder": "网站Logo",
|
||||
"descPlaceholder": "网站简介",
|
||||
|
||||
"phonePlaceholder": "客服电话"
|
||||
|
||||
}
|
||||
|
||||
"phonePlaceholder": "客服电话",
|
||||
"app" : "站点应用",
|
||||
"addon" : "站点插件"
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"userRealName": "用户名",
|
||||
"userRealName": "用户真实名称",
|
||||
"lastLoginTime": "最后登录时间",
|
||||
"createTime": "注册时间",
|
||||
"lastLoginIP": "最后登录IP",
|
||||
@ -9,4 +9,4 @@
|
||||
"endDate": "结束时间",
|
||||
"startDate": "开始时间",
|
||||
"loginTime": "最后登录时间"
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,16 +154,12 @@ const formRules = computed(() => {
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
// return /^([a-zA-Z_$])([a-zA-Z0-9_$])*$/.test(val)
|
||||
router_path: [
|
||||
{ required: formData.menu_type != 2, message: t('routePathPlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
view_path: [
|
||||
{ required: formData.menu_type == 1, message: t('viewPathPlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
icon: [
|
||||
{ required: formData.menu_type != 2, message: t('selectIconPlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
api_url: [
|
||||
{ required: formData.menu_type == 2, message: t('authIdPlaceholder'), trigger: 'blur' }
|
||||
]
|
||||
@ -214,7 +210,6 @@ const confirm = async (formEl: FormInstance | undefined) => {
|
||||
loading.value = true
|
||||
|
||||
const data = formData
|
||||
data.api_url = data.api_url ? `${data.api_url}/${formData.methods}` : ''
|
||||
|
||||
save(data).then(res => {
|
||||
loading.value = false
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center mb-[20px]">
|
||||
<span class="text-[20px]"></span>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
<el-button type="primary" class="w-[100px]" @click="addEvent">
|
||||
{{ t('addMenu') }}
|
||||
</el-button>
|
||||
@ -98,10 +98,11 @@ import { getMenus, deleteMenu } from '@/app/api/sys'
|
||||
import { t } from '@/lang'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import EditMenu from '@/app/views/auth/components/edit-menu.vue'
|
||||
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const active = ref('system')
|
||||
const pageName = route.meta.title
|
||||
|
||||
const menusTableData = reactive<Record<string, any>>({
|
||||
loading: true,
|
||||
|
||||
@ -43,7 +43,7 @@ const pageName = route.meta.title
|
||||
const loading = ref(true)
|
||||
|
||||
const formData = reactive<Record<string, string | boolean | any>>({
|
||||
is_open: false,
|
||||
is_open: true,
|
||||
request_url: ''
|
||||
})
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('addonListSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<div ref="addonBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap !cursor-move p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<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 v-show="item.title" class="flex items-center pb-[10px]">
|
||||
<img class="w-[60px] h-[60px] rounded-md" :src="img(item.icon)" />
|
||||
<div class="flex flex-col justify-center ml-[10px] leading-[1]">
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
<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 !cursor-move p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<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>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap !cursor-move p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<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>
|
||||
|
||||
@ -5,8 +5,7 @@
|
||||
<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>
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
@ -17,8 +16,7 @@
|
||||
<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="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable
|
||||
maxlength="15" show-word-limit />
|
||||
<el-input v-model="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" />
|
||||
@ -36,12 +34,10 @@
|
||||
<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="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')"
|
||||
clearable maxlength="30" show-word-limit />
|
||||
<el-input v-model="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] article-slider" :min="12" :max="16" />
|
||||
<el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="16" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.subTitle.color" />
|
||||
@ -53,8 +49,7 @@
|
||||
<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="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable
|
||||
maxlength="8" show-word-limit />
|
||||
<el-input v-model="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" />
|
||||
@ -71,12 +66,10 @@
|
||||
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="40%">
|
||||
|
||||
<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'">
|
||||
<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] mr-[12px] 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-[280px] h-[100px] mr-[12px] 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>
|
||||
@ -98,8 +91,7 @@
|
||||
<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] article-slider" :min="12" :max="20" />
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="20" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.fontWeight">
|
||||
|
||||
@ -7,10 +7,18 @@
|
||||
</el-icon>
|
||||
<span class="pl-[5px]">{{ t('back') }}</span>
|
||||
</div>
|
||||
<div class="text-white ml-[10px] flex items-center">
|
||||
<div class="text-white ml-[10px] mr-[20px] flex items-center">
|
||||
<span class="mr-[5px]"> | {{ t('decorating') }}:{{ diyStore.typeName }}</span>
|
||||
<!--<el-icon class="font-bold"><EditPen /></el-icon>-->
|
||||
</div>
|
||||
|
||||
<div v-if="diyStore.type && diyStore.type != 'DIY_PAGE'">
|
||||
<span class="text-white mr-[10px] text-base">{{ t('templatePagePlaceholder') }}</span>
|
||||
<el-select v-model="template" class="w-[180px]" :placeholder="t('templatePagePlaceholder')" @change="changeTemplatePage">
|
||||
<el-option :label="t('templatePageEmpty')" value="" />
|
||||
<el-option v-for="(item, key) in templatePages" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
<el-button @click="preview()">{{ t('preview') }}</el-button>
|
||||
<el-button @click="save()">{{ t('save') }}</el-button>
|
||||
@ -25,9 +33,7 @@
|
||||
<el-collapse v-model="activeNames" @change="handleChange">
|
||||
<el-collapse-item v-for="(item, key) in component" :key="key" :title="item.title" :name="key">
|
||||
<ul class="flex flex-row flex-wrap">
|
||||
<li v-for="(compItem, compKey) in item.list" :key="compKey"
|
||||
class="w-2/6 text-center cursor-pointer h-[75px]" :title="compItem.title"
|
||||
@click="diyStore.addComponent(compKey, compItem)">
|
||||
<li v-for="(compItem, compKey) in item.list" :key="compKey" class="w-2/6 text-center cursor-pointer h-[75px]" :title="compItem.title" @click="diyStore.addComponent(compKey, compItem)">
|
||||
<icon :name="compItem.icon" size="23px" />
|
||||
<span class="block text-base truncate">{{ compItem.title }}</span>
|
||||
</li>
|
||||
@ -41,43 +47,33 @@
|
||||
<div class="preview-wrap flex-1 relative mt-[20px]">
|
||||
|
||||
<el-scrollbar>
|
||||
<el-button class="page-btn absolute right-[20px]" @click="diyStore.changeCurrentIndex(-99)">{{
|
||||
t('pageSet') }}
|
||||
</el-button>
|
||||
<el-button class="page-btn absolute right-[20px]" @click="diyStore.changeCurrentIndex(-99)">{{ t('pageSet') }}</el-button>
|
||||
<div class="diy-view-wrap w-[375px] shadow-lg mx-auto">
|
||||
<div class="preview-head bg-no-repeat bg-center bg-cover" @click="diyStore.changeCurrentIndex(-99)">
|
||||
<span class="text-base block text-center truncate cursor-pointer h-[64px] leading-[84px]">{{
|
||||
diyStore.global.title }}</span>
|
||||
<span class="text-base block text-center truncate cursor-pointer h-[64px] leading-[84px]">{{ diyStore.global.title }}</span>
|
||||
</div>
|
||||
<div class="preview-block relative">
|
||||
|
||||
<ul
|
||||
class="quick-action absolute text-center -right-[70px] top-[20px] w-[42px] rounded shadow-md">
|
||||
<ul class="quick-action absolute text-center -right-[70px] top-[20px] w-[42px] rounded shadow-md">
|
||||
<el-tooltip effect="light" :content="t('moveUpComponent')" placement="right">
|
||||
<icon name="iconfont-iconjiantoushang" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
|
||||
<icon name="iconfont-iconjiantoushang" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('moveDownComponent')" placement="right">
|
||||
<icon name="iconfont-iconjiantouxia" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
|
||||
<icon name="iconfont-iconjiantouxia" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('copyComponent')" placement="right">
|
||||
<icon name="iconfont-iconcopy-line" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
|
||||
<icon name="iconfont-iconcopy-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('delComponent')" placement="right">
|
||||
<icon name="iconfont-icondelete-line" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
|
||||
<icon name="iconfont-icondelete-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('resetComponent')" placement="right">
|
||||
<icon name="iconfont-iconloader-line" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
|
||||
<icon name="iconfont-iconloader-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
|
||||
</el-tooltip>
|
||||
</ul>
|
||||
|
||||
<!-- 组件预览渲染区域 -->
|
||||
<iframe id="previewIframe" v-show="loadingIframe" :src="wapPreview" frameborder="0"
|
||||
class="preview-iframe w-[375px]"></iframe>
|
||||
<iframe id="previewIframe" v-show="loadingIframe" :src="wapPreview" frameborder="0" class="preview-iframe w-[375px]"></iframe>
|
||||
|
||||
<div v-show="loadingDev" class="preview-iframe w-[375px] pt-[20px] px-[20px]">
|
||||
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
|
||||
@ -101,63 +97,42 @@
|
||||
<el-card class="box-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<span class="title flex-1">{{ diyStore.currentIndex == -99 ? t('pageSet') :
|
||||
diyStore.editComponent.componentTitle }}</span>
|
||||
<div class="tab-wrap flex rounded-[50px] bg-gray-100 text-[14px]"
|
||||
v-if="diyStore.currentComponent">
|
||||
<span class="cursor-pointer rounded-[50px] py-[5px] px-[15px]"
|
||||
:class="{ 'bg-primary text-white': diyStore.editTab == 'content' }"
|
||||
@click="diyStore.editTab = 'content'">{{ t('tabEditContent') }}</span>
|
||||
<span class="cursor-pointer rounded-[50px] py-[5px] px-[15px]"
|
||||
:class="{ 'bg-primary text-white': diyStore.editTab == 'style' }"
|
||||
@click="diyStore.editTab = 'style'">{{ t('tabEditStyle') }}</span>
|
||||
<span class="title flex-1">{{ diyStore.currentIndex == -99 ? t('pageSet') : diyStore.editComponent.componentTitle }}</span>
|
||||
<div class="tab-wrap flex rounded-[50px] bg-gray-100 text-[14px]" v-if="diyStore.currentComponent">
|
||||
<span class="cursor-pointer rounded-[50px] py-[5px] px-[15px]" :class="{ 'bg-primary text-white': diyStore.editTab == 'content' }" @click="diyStore.editTab = 'content'">{{ t('tabEditContent') }}</span>
|
||||
<span class="cursor-pointer rounded-[50px] py-[5px] px-[15px]" :class="{ 'bg-primary text-white': diyStore.editTab == 'style' }" @click="diyStore.editTab = 'style'">{{ t('tabEditStyle') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="edit-component-wrap">
|
||||
|
||||
<component v-if="diyStore.currentComponent" :is="modules[diyStore.currentComponent]"
|
||||
:value="diyStore.value[diyStore.currentIndex]">
|
||||
<component v-if="diyStore.currentComponent" :is="modules[diyStore.currentComponent]" :value="diyStore.value[diyStore.currentIndex]">
|
||||
<template #style>
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('componentStyleTitle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('bottomBgColor')" class="display-block"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageBgColor" show-alpha
|
||||
:predefine="diyStore.predefineColors" />
|
||||
<el-form-item :label="t('bottomBgColor')" class="display-block" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<div class="text-sm text-gray-400">{{ t('bottomBgTips') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('componentBgColor')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.componentBgColor"
|
||||
show-alpha :predefine="diyStore.predefineColors" />
|
||||
<el-form-item :label="t('componentBgColor')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.componentBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginTop')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input
|
||||
size="small" :min="0" class="ml-[10px] horz-blank-slider" />
|
||||
<el-form-item :label="t('marginTop')" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="0" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBottom')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input
|
||||
size="small" class="ml-[10px] horz-blank-slider" />
|
||||
<el-form-item :label="t('marginBottom')" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBoth')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input
|
||||
size="small" class="ml-[10px] horz-blank-slider" />
|
||||
<el-form-item :label="t('marginBoth')" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input
|
||||
size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
<el-form-item :label="t('topRounded')" v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input
|
||||
size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
<el-form-item :label="t('bottomRounded')" v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -166,41 +141,27 @@
|
||||
<div class="edit-attr-item-wrap" v-else>
|
||||
<h3 class="mb-[10px]">{{ t('componentStyleTitle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('bottomBgColor')" class="display-block"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageBgColor" show-alpha
|
||||
:predefine="diyStore.predefineColors" />
|
||||
<el-form-item :label="t('bottomBgColor')" class="display-block" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<div class="text-sm text-gray-400">{{ t('bottomBgTips') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('componentBgColor')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.componentBgColor" show-alpha
|
||||
:predefine="diyStore.predefineColors" />
|
||||
<el-form-item :label="t('componentBgColor')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.componentBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginTop')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small"
|
||||
:min="0" class="ml-[10px] horz-blank-slider" />
|
||||
<el-form-item :label="t('marginTop')" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="0" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBottom')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small"
|
||||
class="ml-[10px] horz-blank-slider" />
|
||||
<el-form-item :label="t('marginBottom')" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBoth')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small"
|
||||
class="ml-[10px] horz-blank-slider" />
|
||||
<el-form-item :label="t('marginBoth')" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input size="small"
|
||||
class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
<el-form-item :label="t('topRounded')" v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')"
|
||||
v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input size="small"
|
||||
class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
<el-form-item :label="t('bottomRounded')" v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -217,15 +178,18 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, toRaw, watch } from 'vue'
|
||||
import { ref, reactive, toRaw, watch, inject } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { addDiyPage, editDiyPage, initPage } from '@/app/api/diy'
|
||||
import { getDiyTemplatePages, addDiyPage, editDiyPage, initPage } from '@/app/api/diy'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const setLayout = inject('setLayout')
|
||||
setLayout('decorate')
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -234,10 +198,12 @@ route.query.id = route.query.id || 0
|
||||
route.query.name = route.query.name || ''
|
||||
route.query.url = route.query.url || '' // 页面路径
|
||||
route.query.type = route.query.type || '' // 页面模板,新页面传入
|
||||
route.query.template = route.query.template || '' // 页面模板名称,新页面传入
|
||||
route.query.title = route.query.title || ''
|
||||
route.query.back = route.query.back || '/website/diy/list'
|
||||
route.query.back = route.query.back || '/site/diy/list'
|
||||
|
||||
const backPath = route.query.back
|
||||
const template = ref('');
|
||||
const oldTemplate = ref('');
|
||||
const wapUrl = ref('')
|
||||
const wapDomain = ref('')
|
||||
const wapPreview = ref('')
|
||||
@ -247,7 +213,6 @@ const loadingDev = ref(false) // 加载开发环境配置
|
||||
const timeIframe = ref(0) // iframe打开时间
|
||||
const difference = ref(0) // 检测页面加载差异,小于1000毫秒,则配置wap端域名
|
||||
|
||||
const backPath = route.query.back
|
||||
const component = ref([])
|
||||
const componentType: string[] = reactive([])
|
||||
const page = ref('')
|
||||
@ -271,6 +236,7 @@ const originData = reactive({
|
||||
const isChange = ref(true) // 数据是否发生变化,true:没变化,false:变化了
|
||||
const goBack = () => {
|
||||
if (isChange.value) {
|
||||
location.href = `${location.origin}${backPath}`;
|
||||
router.push(backPath)
|
||||
} else {
|
||||
// 数据发生变化,弹框提示:确定离开此页面
|
||||
@ -284,7 +250,7 @@ const goBack = () => {
|
||||
autofocus: false
|
||||
}
|
||||
).then(() => {
|
||||
router.push(backPath)
|
||||
location.href = `${location.origin}${backPath}`;
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
@ -300,6 +266,67 @@ for (const [key, value] of Object.entries(modulesFiles)) {
|
||||
modules[name] = value.default
|
||||
}
|
||||
|
||||
// 获取模板页面列表
|
||||
const templatePages: any = reactive({})
|
||||
|
||||
const loadDiyTemplatePages = (type:any)=>{
|
||||
getDiyTemplatePages({
|
||||
type,
|
||||
mode: 'diy'
|
||||
}).then(res => {
|
||||
for (const key in res.data) {
|
||||
templatePages[key] = res.data[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 全局监听自定义数据变化
|
||||
watch(
|
||||
() => template.value,
|
||||
(newValue, oldValue) => {
|
||||
oldTemplate.value = oldValue;
|
||||
}
|
||||
)
|
||||
|
||||
// 切换模板页面
|
||||
const changeTemplatePage = (value:any)=> {
|
||||
// 存在数据则弹框提示确认
|
||||
if(diyStore.value.length) {
|
||||
ElMessageBox.confirm(t('changeTemplatePageTips'), t('warning'), {
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (value) {
|
||||
let data = templatePages[value].data;
|
||||
diyStore.global = data.global;
|
||||
if (data.value.length) {
|
||||
diyStore.value = data.value
|
||||
}
|
||||
} else {
|
||||
// 清空
|
||||
diyStore.init();
|
||||
}
|
||||
if(route.query.title) diyStore.global.title = route.query.title
|
||||
}).catch(() => {
|
||||
// 还原
|
||||
template.value = oldTemplate.value;
|
||||
});
|
||||
}else{
|
||||
if (value) {
|
||||
let data = templatePages[value].data;
|
||||
diyStore.global = data.global;
|
||||
if (data.value.length) {
|
||||
diyStore.value = data.value
|
||||
}
|
||||
} else {
|
||||
// 清空
|
||||
diyStore.init();
|
||||
}
|
||||
if(route.query.title) diyStore.global.title = route.query.title
|
||||
}
|
||||
};
|
||||
|
||||
// 全局监听自定义数据变化
|
||||
watch(
|
||||
() => diyStore,
|
||||
@ -326,7 +353,6 @@ initPage({
|
||||
name: route.query.name,
|
||||
url: route.query.url,
|
||||
type: route.query.type,
|
||||
template: route.query.template,
|
||||
title: route.query.title
|
||||
}).then(async (res) => {
|
||||
const data = res.data
|
||||
@ -393,6 +419,8 @@ initPage({
|
||||
}
|
||||
}
|
||||
|
||||
loadDiyTemplatePages(data.type);
|
||||
|
||||
// 加载预览
|
||||
wapDomain.value = data.domain_url.wap_domain
|
||||
wapUrl.value = data.domain_url.wap_url
|
||||
@ -501,6 +529,8 @@ const save = (callback: any) => {
|
||||
if (isRepeat.value) return
|
||||
isRepeat.value = true
|
||||
|
||||
diyStore.templateName = template.value;
|
||||
|
||||
let data = {
|
||||
id: diyStore.id,
|
||||
name: diyStore.name,
|
||||
@ -522,7 +552,7 @@ const save = (callback: any) => {
|
||||
if (diyStore.id) {
|
||||
isRepeat.value = false // 不刷新
|
||||
} else {
|
||||
router.push(backPath)
|
||||
location.href = `${location.origin}${backPath}`;
|
||||
}
|
||||
if (callback) callback(res.data.id)
|
||||
}
|
||||
@ -566,7 +596,6 @@ const preview = () => {
|
||||
}
|
||||
|
||||
.edit-component-wrap {
|
||||
|
||||
.content-wrap,
|
||||
.style-wrap {
|
||||
.edit-attr-item-wrap {
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] mt-[20px] bg-[#f7f7f7] w-[300px] pt-[80px] pb-[20px]"
|
||||
:class="{ 'cursor-pointer': !item.isDisabledPop }" v-for="(item, key) in page" :key="key">
|
||||
<p class="absolute top-[46px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">
|
||||
{{ item.use_template.title }}</p>
|
||||
<div class="flex flex-wrap mt-[20px] min-w-[1000px]" v-if="page.use_template">
|
||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
||||
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
||||
|
||||
<div v-show="item.use_template.url" class="w-[282px] h-[493px] mx-auto">
|
||||
<iframe :id="'previewIframe_' + key" v-show="item.loadingIframe" class="w-[282px] h-[493px] mx-auto"
|
||||
:src="item.use_template.wapPreview" frameborder="0"></iframe>
|
||||
<div v-show="item.loadingDev" class="w-[282px] h-[493px] mx-auto bg-body pt-[20px] px-[20px]">
|
||||
<div v-show="page.use_template.url" class="w-[320px] h-[550px] mx-auto">
|
||||
<iframe :id="'previewIframe_' + key" v-show="page.loadingIframe" class="w-[320px] h-[550px] mx-auto" :src="page.use_template.wapPreview" frameborder="0"></iframe>
|
||||
<div v-show="page.loadingDev" class="w-[320px] h-[550px] mx-auto bg-body pt-[20px] px-[20px]">
|
||||
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
|
||||
<div class="mb-[20px] flex flex-col">
|
||||
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
|
||||
@ -21,80 +18,50 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="!item.use_template.wapPreview" class="overflow-hidden w-[282px] h-[493px] mx-auto">
|
||||
<img class="max-w-full" v-if="item.use_template.cover" :src="img(item.use_template.cover)" />
|
||||
<div v-show="!page.use_template.wapPreview" class="overflow-hidden w-[320px] h-[550px] mx-auto">
|
||||
<img class="max-w-full" v-if="page.use_template.cover" :src="img(page.use_template.cover)" />
|
||||
</div>
|
||||
|
||||
<p class="text-[12px] text-[#999] mt-[10px] mx-auto truncate text-center w-[250px]">
|
||||
{{ item.use_template.desc }}</p>
|
||||
<div class="popup-wrap absolute inset-x-0 inset-y-0 select-none" :class="{ 'disabled': page.isDisabledPop }"></div>
|
||||
|
||||
<div class="item-hide absolute inset-x-0 inset-y-0 bg-black bg-opacity-50 text-center"
|
||||
:class="{ 'disabled': item.isDisabledPop }">
|
||||
<div
|
||||
class="item-btn-box absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] flex flex-col flex-wrap">
|
||||
<el-button @click="show(key, item)">{{ t('changePage') }}</el-button>
|
||||
<el-button @click="toDecorate(item.use_template)"
|
||||
v-show="item.use_template.mode != 'other' || item.use_template.action == 'decorate'">{{
|
||||
t('decorate') }}
|
||||
</el-button>
|
||||
<el-button @click="toPreview(item.use_template)">{{ t('preview') }}</el-button>
|
||||
</div>
|
||||
|
||||
<div class="w-[500px]">
|
||||
<div class="flex flex-wrap">
|
||||
<diy-link v-model="link" :ignore="['DIY_LINK']" @success="changePage">
|
||||
<el-button type="primary">{{ t('changePage') }}</el-button>
|
||||
</diy-link>
|
||||
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
|
||||
</div>
|
||||
|
||||
<div class="info-wrap">
|
||||
|
||||
<div class="mt-[20px] bg-[#F7F8FA] p-[20px] flex items-center justify-between">
|
||||
<div>
|
||||
<div class="font-bold">{{ t('H5') }}</div>
|
||||
<el-form label-width="40px" class="mt-[5px]">
|
||||
<el-form-item :label="t('link')" v-show="page.use_template.wapPreview" class="mb-[5px]">
|
||||
<el-input readonly :value="page.use_template.wapPreview">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(page.use_template.wapPreview)" class="bg-primary copy">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="text-[#999] text-base">{{ t('scanQRCodeOnRight') }}</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<el-image class="w-[100px] h-[100px] mb-[5px]" :src="wapImage" />
|
||||
<div @click="toPreview()" class="text-primary text-base cursor-pointer">{{ t('preview') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('changeTemplate')" width="400px" :close-on-press-escape="false"
|
||||
:destroy-on-close="true" :close-on-click-modal="false">
|
||||
|
||||
<el-form :model="form" label-width="0px" v-if="formData.type">
|
||||
<el-form-item label="">
|
||||
<div>{{ t('hopeBeforeTip') }}<span class="text-primary px-[5px]">{{ page[formData.type].title
|
||||
}}</span>{{ t('hopeAfterTip') }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="">
|
||||
<el-select v-model="hope" class="w-full">
|
||||
<el-option :label="t('changeTemplateTip') + ' ' + page[formData.type].title + ' ' + t('template')"
|
||||
value="template" />
|
||||
<el-option :label="t('changeMyPageTip') + ' ' + page[formData.type].title" value="diy" />
|
||||
<el-option :label="t('changeOtherPageTip') + ' ' + page[formData.type].title" value="other" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="" v-show="hope == 'template'">
|
||||
<el-select v-model="formData.template" class="w-full">
|
||||
<el-option v-for="(item, key) in page[formData.type].template" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="" v-show="hope == 'diy'">
|
||||
<el-select v-model="formData.id" class="w-full">
|
||||
<el-option v-for="(item, index) in page[formData.type].my_page" :label="item.title" :value="item.id" :key="index" />
|
||||
</el-select>
|
||||
<div class="mt-[10px]">
|
||||
<span class="cursor-pointer text-primary mr-[10px]" @click="toDiyList">{{ t('createPage') }}</span>
|
||||
<span class="cursor-pointer text-primary" @click="refreshMyPage">{{ t('refreshPage') }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="" v-show="hope == 'other'">
|
||||
<el-select v-model="formData.page" class="w-full">
|
||||
<el-option v-for="(item, index) in page[formData.type].other_page" :label="item.title"
|
||||
:value="item.page" :key="index" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -103,22 +70,25 @@ import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getDecoratePage, getDiyList, changeTemplate } from '@/app/api/diy'
|
||||
import { getDecoratePage, changeTemplate } from '@/app/api/diy'
|
||||
import storage from '@/utils/storage'
|
||||
import QRCode from 'qrcode'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
|
||||
const type: any = ref('DIY_INDEX');
|
||||
const page: any = reactive({})
|
||||
const showDialog = ref(false)
|
||||
const router = useRouter()
|
||||
const hope = ref('template')
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const link = ref({
|
||||
name: ''
|
||||
})
|
||||
|
||||
// 添加自定义页面
|
||||
const formData = reactive({
|
||||
type: '',
|
||||
name: '',
|
||||
mode: '',
|
||||
template: '',
|
||||
id: '',
|
||||
parent:'',
|
||||
page: '',
|
||||
title: '',
|
||||
action: ''
|
||||
@ -126,43 +96,41 @@ const formData = reactive({
|
||||
|
||||
// 初始化数据
|
||||
const refreshData = () => {
|
||||
formData.type = ''
|
||||
formData.name = ''
|
||||
formData.mode = ''
|
||||
formData.template = ''
|
||||
formData.id = ''
|
||||
formData.page = ''
|
||||
formData.title = ''
|
||||
formData.action = ''
|
||||
getDecoratePage({}).then(res => {
|
||||
getDecoratePage({
|
||||
type : type.value
|
||||
}).then(res => {
|
||||
for (const key in res.data) {
|
||||
page[key] = res.data[key]
|
||||
}
|
||||
|
||||
for (const key in page) {
|
||||
if (page[key].use_template.url) {
|
||||
page[key].loadingIframe = false // 加载iframe
|
||||
page[key].loadingDev = false // 加载开发环境配置
|
||||
page[key].isDisabledPop = false // 是否禁止打开遮罩层
|
||||
page[key].difference = 0 // 检测页面加载差异,小于1000毫秒,则配置wap端域名
|
||||
link.value.name = page.use_template.name;
|
||||
link.value.title = page.use_template.title;
|
||||
link.value.page = page.use_template.page;
|
||||
link.value.action = page.use_template.action;
|
||||
link.value.parent = page.use_template.parent;
|
||||
|
||||
wapDomain.value = page[key].domain_url.wap_domain
|
||||
page[key].wapUrl = page[key].domain_url.wap_url
|
||||
if (page.use_template.url) {
|
||||
page.loadingIframe = false // 加载iframe
|
||||
page.loadingDev = false // 加载开发环境配置
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
page.difference = 0 // 检测页面加载差异,小于1000毫秒,则配置wap端域名
|
||||
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
// 开发模式情况下,并且未配置wap域名,则获取缓存域名
|
||||
if (wapDomain.value) {
|
||||
page[key].wapUrl = wapDomain.value + '/wap'
|
||||
setDomain(key)
|
||||
}
|
||||
if (storage.get('wap_domain')) {
|
||||
page[key].wapUrl = storage.get('wap_domain')
|
||||
setDomain(key)
|
||||
}
|
||||
wapDomain.value = page.domain_url.wap_domain
|
||||
page.wapUrl = page.domain_url.wap_url
|
||||
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
// 开发模式情况下,并且未配置wap域名,则获取缓存域名
|
||||
if (wapDomain.value) {
|
||||
page.wapUrl = wapDomain.value + '/wap'
|
||||
setDomain()
|
||||
}
|
||||
if (storage.get('wap_domain')) {
|
||||
page.wapUrl = storage.get('wap_domain')
|
||||
setDomain()
|
||||
}
|
||||
|
||||
setDomain(key)
|
||||
}
|
||||
|
||||
setDomain()
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -174,36 +142,32 @@ window.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
for (const key in page) {
|
||||
page[key].loadingDev = false // 禁用开发环境配置
|
||||
page[key].loadingIframe = true // 加载iframe
|
||||
const loadTime = new Date().getTime()
|
||||
page[key].difference = loadTime - page[key].timeIframe
|
||||
page[key].isDisabledPop = false // 是否禁止打开遮罩层
|
||||
}
|
||||
page.loadingDev = false // 禁用开发环境配置
|
||||
page.loadingIframe = true // 加载iframe
|
||||
const loadTime = new Date().getTime()
|
||||
page.difference = loadTime - page.timeIframe
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
}
|
||||
} catch (e) {
|
||||
for (const key in page) {
|
||||
initLoad(key)
|
||||
}
|
||||
initLoad()
|
||||
console.log('后台接受数据错误', e)
|
||||
}
|
||||
}, false)
|
||||
|
||||
// 将数据发送到uniapp
|
||||
const postMessage = (key: string) => {
|
||||
const postMessage = () => {
|
||||
const diyData = JSON.stringify({
|
||||
type: 'appOnReady',
|
||||
message: '加载完成'
|
||||
})
|
||||
if (window['previewIframe_' + key]) window['previewIframe_' + key].contentWindow.postMessage(diyData, '*')
|
||||
if (window['previewIframe_' + type.value]) window['previewIframe_' + type.value].contentWindow.postMessage(diyData, '*')
|
||||
}
|
||||
|
||||
// 初始化加载状态
|
||||
const initLoad = (key: string) => {
|
||||
page[key].loadingDev = true
|
||||
page[key].isDisabledPop = true
|
||||
page[key].loadingIframe = false
|
||||
const initLoad = () => {
|
||||
page.loadingDev = true
|
||||
page.isDisabledPop = true
|
||||
page.loadingIframe = false
|
||||
}
|
||||
|
||||
const saveDomain = () => {
|
||||
@ -215,21 +179,17 @@ const saveDomain = () => {
|
||||
return
|
||||
}
|
||||
const wapUrl = wapDomain.value + '/wap'
|
||||
storage.set({ key: 'wap_domain', data: wapUrl })
|
||||
storage.set({key: 'wap_domain', data: wapUrl})
|
||||
|
||||
for (const key in page) {
|
||||
if (page[key].use_template.url) {
|
||||
page[key].wapUrl = wapUrl
|
||||
setDomain(key)
|
||||
}
|
||||
if (page.use_template.url) {
|
||||
page.wapUrl = wapUrl
|
||||
setDomain()
|
||||
}
|
||||
setTimeout(() => {
|
||||
for (const key in page) {
|
||||
if (page[key].use_template.url) {
|
||||
page[key].loadingIframe = true // 加载iframe
|
||||
page[key].loadingDev = false // 加载开发环境配置
|
||||
page[key].isDisabledPop = false // 是否禁止打开遮罩层
|
||||
}
|
||||
if (page.use_template.url) {
|
||||
page.loadingIframe = true // 加载iframe
|
||||
page.loadingDev = false // 加载开发环境配置
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
}
|
||||
}, 100 * 3)
|
||||
}
|
||||
@ -238,46 +198,29 @@ const settingTips = () => {
|
||||
window.open('https://www.kancloud.cn/niucloud/niucloud-admin-develop/3213393')
|
||||
}
|
||||
|
||||
const setDomain = (key: string) => {
|
||||
page[key].use_template.wapPreview = page[key].wapUrl + page[key].use_template.url
|
||||
page[key].timeIframe = new Date().getTime()
|
||||
postMessage(key)
|
||||
const setDomain = () => {
|
||||
page.use_template.wapPreview = page.wapUrl + page.use_template.url
|
||||
QRCode.toDataURL(page.use_template.wapPreview, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
page.timeIframe = new Date().getTime()
|
||||
postMessage()
|
||||
setTimeout(() => {
|
||||
if (page[key].difference == 0) initLoad(key)
|
||||
if (page.difference == 0) initLoad()
|
||||
}, 1000 * 2)
|
||||
}
|
||||
|
||||
const show = (key: string, data: any) => {
|
||||
// 每次打开时赋值
|
||||
showDialog.value = true
|
||||
|
||||
hope.value = data.use_template.hope
|
||||
formData.type = key
|
||||
formData.name = data.use_template.name
|
||||
formData.mode = data.use_template.mode
|
||||
formData.action = data.use_template.action
|
||||
|
||||
if (hope.value == 'template') {
|
||||
formData.template = data.use_template.template
|
||||
} else if (hope.value == 'diy') {
|
||||
formData.id = data.use_template.id
|
||||
} else if (hope.value == 'other') {
|
||||
formData.page = data.use_template.page
|
||||
formData.title = data.use_template.title
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转去装修
|
||||
const toDecorate = (data: any) => {
|
||||
const toDecorate = () => {
|
||||
const query: any = {
|
||||
back: '/site/diy/index'
|
||||
}
|
||||
if (data.id) {
|
||||
query.id = data.id
|
||||
} else if (data.name) {
|
||||
query.name = data.name
|
||||
} else if (data.url) {
|
||||
query.url = data.url
|
||||
if (page.use_template.id) {
|
||||
query.id = page.use_template.id
|
||||
} else if (page.use_template.type) {
|
||||
query.name = page.use_template.type
|
||||
} else if (page.use_template.url) {
|
||||
query.url = page.use_template.url
|
||||
}
|
||||
const url = router.resolve({
|
||||
path: '/decorate/edit',
|
||||
@ -287,128 +230,30 @@ const toDecorate = (data: any) => {
|
||||
}
|
||||
|
||||
// 跳转去预览
|
||||
const toPreview = (data: any) => {
|
||||
let page = data.page
|
||||
if (data.url) {
|
||||
page = data.url
|
||||
} else if (data.id) {
|
||||
page += '?id=' + data.id
|
||||
const toPreview = () => {
|
||||
let value = page.use_template.page
|
||||
if (page.use_template.url) {
|
||||
value = page.use_template.url
|
||||
} else if (page.use_template.id) {
|
||||
value += '?id=' + page.use_template.id
|
||||
}
|
||||
const url = router.resolve({
|
||||
path: '/preview/wap',
|
||||
query: {
|
||||
page
|
||||
page:value
|
||||
}
|
||||
})
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
// 创建微页面
|
||||
const toDiyList = (data: any) => {
|
||||
const url = router.resolve({
|
||||
path: '/diy/list'
|
||||
})
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
// 刷新我的微页面
|
||||
const refreshMyPage = () => {
|
||||
getDiyList({ type: formData.type }).then((res) => {
|
||||
let isExist = true // 检测选择的微页面是否存在,不存在则清空
|
||||
for (let i = 0; i < res.data.length; i++) {
|
||||
if (formData.id == res.data[i].id) {
|
||||
isExist = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if (isExist) {
|
||||
formData.id = ''
|
||||
}
|
||||
page[formData.type].my_page = {}
|
||||
Object.assign(page[formData.type].my_page, res.data)
|
||||
})
|
||||
}
|
||||
|
||||
watch(
|
||||
() => hope.value,
|
||||
(newValue, oldValue) => {
|
||||
// 选择某个,清空其余
|
||||
if (newValue == 'template') {
|
||||
// 选择模板
|
||||
formData.id = ''
|
||||
formData.page = ''
|
||||
formData.action = 'decorate'
|
||||
formData.name = formData.type
|
||||
} else if (newValue == 'diy') {
|
||||
// 选择微页面
|
||||
formData.mode = 'diy'
|
||||
formData.template = ''
|
||||
formData.page = ''
|
||||
formData.action = 'decorate'
|
||||
formData.name = formData.type
|
||||
} else if (newValue == 'other') {
|
||||
// 选择其他页面
|
||||
formData.mode = 'other'
|
||||
formData.template = ''
|
||||
formData.id = ''
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 监听模板变化
|
||||
watch(
|
||||
() => formData.template,
|
||||
(newValue, oldValue) => {
|
||||
if (newValue) {
|
||||
formData.mode = page[formData.type].template[newValue].mode
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// 监听其他页面
|
||||
watch(
|
||||
() => formData.page,
|
||||
(newValue, oldValue) => {
|
||||
if (newValue) {
|
||||
for (let i = 0; i < page[formData.type].other_page.length; i++) {
|
||||
if (page[formData.type].other_page[i].page == newValue) {
|
||||
formData.name = page[formData.type].other_page[i].name
|
||||
formData.title = page[formData.type].other_page[i].title
|
||||
formData.action = page[formData.type].other_page[i].action
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const isRepeat = ref(false)
|
||||
const save = () => {
|
||||
if (hope.value == 'template') {
|
||||
if (formData.template == '') {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('placeholderTemplate')}`
|
||||
})
|
||||
return
|
||||
}
|
||||
} else if (hope.value == 'diy') {
|
||||
if (formData.id == '') {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('placeholderMyPage')}`
|
||||
})
|
||||
return
|
||||
}
|
||||
} else if (hope.value == 'other') {
|
||||
if (formData.page == '') {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('placeholderOtherPage')}`
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
const changePage = ()=>{
|
||||
formData.type = type.value;
|
||||
formData.name = link.value.name;
|
||||
formData.page = link.value.url;
|
||||
formData.title = link.value.title;
|
||||
formData.action = link.value.action;
|
||||
formData.parent = link.value.parent;
|
||||
|
||||
if (isRepeat.value) return
|
||||
isRepeat.value = true
|
||||
@ -417,39 +262,44 @@ const save = () => {
|
||||
...formData
|
||||
}).then((res) => {
|
||||
isRepeat.value = false
|
||||
showDialog.value = false
|
||||
refreshData()
|
||||
})
|
||||
}
|
||||
|
||||
// 复制
|
||||
const { copy, isSupported, copied } = useClipboard()
|
||||
const copyEvent = (text: string) => {
|
||||
if (!isSupported.value) {
|
||||
ElMessage({
|
||||
message: t('notSupportCopy'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
copy(text)
|
||||
}
|
||||
|
||||
watch(copied, () => {
|
||||
if (copied.value) {
|
||||
ElMessage({
|
||||
message: t('copySuccess'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-item {
|
||||
|
||||
background-image: url(@/app/assets/images/iphone_bg.png);
|
||||
background-color: var(--el-bg-color);
|
||||
background-size: 100%;
|
||||
|
||||
.item-hide {
|
||||
.popup-wrap {
|
||||
display: none;
|
||||
|
||||
.item-btn-box {
|
||||
|
||||
button {
|
||||
height: 35px;
|
||||
width: 100px;
|
||||
|
||||
&~button {
|
||||
margin-top: 15px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.item-hide:not(.disabled) {
|
||||
.popup-wrap:not(.disabled) {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,9 +3,7 @@
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
<el-button type="primary" class="w-[100px]" @click="dialogVisible = true">
|
||||
{{ t('addDiyPage') }}
|
||||
</el-button>
|
||||
<el-button type="primary" class="w-[100px]" @click="dialogVisible = true">{{ t('addDiyPage') }}</el-button>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
@ -13,6 +11,12 @@
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('forAddon')" prop="addon_name">
|
||||
<el-select v-model="diyPageTableData.searchParam.addon_name" :placeholder="t('pageTypePlaceholder')">
|
||||
<el-option :label="t('all')" value="" />
|
||||
<el-option v-for="(item, key) in apps" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="diyPageTableData.searchParam.type" :placeholder="t('pageTypePlaceholder')">
|
||||
<el-option :label="t('all')" value="" />
|
||||
@ -33,26 +37,25 @@
|
||||
</template>
|
||||
|
||||
<el-table-column prop="title" :label="t('title')" min-width="120" />
|
||||
<el-table-column prop="addon_name" :label="t('forAddon')" min-width="80" />
|
||||
<el-table-column prop="type_name" :label="t('typeName')" min-width="80" />
|
||||
<!-- <el-table-column :label="t('status')" min-width="80">-->
|
||||
<!-- <template #default="{ row }">-->
|
||||
<!-- <span v-if="row.type == 'DIY_PAGE'">-</span>-->
|
||||
<!-- <template v-else>-->
|
||||
<!-- <span v-if="row.is_default == 1" class="text-primary">{{ t('isUse') }}</span>-->
|
||||
<!-- <span v-else>{{ t('unused') }}</span>-->
|
||||
<!-- </template>-->
|
||||
<!-- </template>-->
|
||||
<!-- </el-table-column>-->
|
||||
<el-table-column :label="t('status')" min-width="80">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.type == 'DIY_PAGE'">-</span>
|
||||
<template v-else>
|
||||
<span v-if="row.is_default == 1" class="text-primary">{{ t('isUse') }}</span>
|
||||
<span v-else>{{ t('unused') }}</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="update_time" :label="t('updateTime')" min-width="120" />
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="toPreview(row)">{{ t('promote') }}</el-button>
|
||||
<el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{
|
||||
t('shareSet') }}
|
||||
</el-button>
|
||||
<el-button v-if="row.is_default == 0" type="primary" link @click="setUse(row.id)">{{ t('use') }}</el-button>
|
||||
<el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{ t('shareSet') }}</el-button>
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<!-- <el-button v-if="row.type == 'DIY_PAGE' || row.is_default == 0" type="danger" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>-->
|
||||
<el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -71,20 +74,13 @@
|
||||
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12"
|
||||
show-word-limit class="w-full" />
|
||||
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('addType')" prop="type">
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="w-full">
|
||||
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('templateName')" prop="template" v-show="pageTypeData">
|
||||
<el-select v-model="formData.template" class="w-full">
|
||||
<el-option :label="t('emptyTemplate')" value="" />
|
||||
<el-option v-for="(item, key) in pageTypeData" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
@ -106,12 +102,10 @@
|
||||
<span>{{ sharePage }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareTitle')" prop="title">
|
||||
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')"
|
||||
clearable maxlength="30" show-word-limit />
|
||||
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'">
|
||||
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')"
|
||||
type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareImageUrl')" prop="url">
|
||||
<upload-image v-model="shareFormData[tabShareType].url" :limit="1" />
|
||||
@ -132,7 +126,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare } from '@/app/api/diy'
|
||||
import { getApps,getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare, setUseDiyPage } from '@/app/api/diy'
|
||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { getUrl } from '@/app/api/sys'
|
||||
@ -140,13 +134,12 @@ import { getUrl } from '@/app/api/sys'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
const pageType: any = reactive({}) // 页面模板类型
|
||||
const pageType: any = reactive({}) // 页面类型
|
||||
|
||||
// 添加自定义页面
|
||||
const formData = reactive({
|
||||
title: '',
|
||||
type: '',
|
||||
template: ''
|
||||
type: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
@ -161,15 +154,6 @@ const formRules = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const pageTypeData = computed(() => {
|
||||
let data: any = ''
|
||||
formData.template = ''
|
||||
if (formData.type) {
|
||||
data = pageType[formData.type].template
|
||||
}
|
||||
return data
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const dialogVisible = ref(false)
|
||||
const addEvent = async (formEl: FormInstance | undefined) => {
|
||||
@ -178,9 +162,11 @@ const addEvent = async (formEl: FormInstance | undefined) => {
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
dialogVisible.value = false
|
||||
let url = `/decorate/edit?type=${formData.type}&title=${formData.title}`
|
||||
if (formData.template) url += `&template=${formData.template}`
|
||||
router.push(url)
|
||||
const query = { type: formData.type, title: formData.title }
|
||||
router.push({
|
||||
path: '/decorate/edit',
|
||||
query
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -189,15 +175,26 @@ const wapDomain = ref('')
|
||||
const getDomain = async () => {
|
||||
wapDomain.value = (await getUrl()).data.wap_url
|
||||
}
|
||||
|
||||
getDomain()
|
||||
|
||||
// 获取自定义页面模板
|
||||
// 获取自定义页面类型
|
||||
getDiyTemplate({ mode: '' }).then(res => {
|
||||
for (const key in res.data) {
|
||||
pageType[key] = res.data[key]
|
||||
}
|
||||
})
|
||||
|
||||
const apps: any = reactive({}) // 应用插件列表
|
||||
|
||||
getApps({}).then(res=>{
|
||||
if(res.data){
|
||||
for (const key in res.data) {
|
||||
apps[key] = res.data[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const diyPageTableData: any = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
@ -207,7 +204,8 @@ const diyPageTableData: any = reactive({
|
||||
searchParam: {
|
||||
title: '',
|
||||
type: '',
|
||||
mode: ''
|
||||
mode: '',
|
||||
addon_name: ''
|
||||
}
|
||||
})
|
||||
|
||||
@ -242,6 +240,13 @@ const editEvent = (data: any) => {
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
// 设为使用
|
||||
const setUse = (id: any) => {
|
||||
setUseDiyPage({id}).then(() => {
|
||||
loadDiyPageList()
|
||||
})
|
||||
}
|
||||
|
||||
// 删除自定义页面
|
||||
const deleteEvent = (id: number) => {
|
||||
ElMessageBox.confirm(t('diyPageDeleteTips'), t('warning'),
|
||||
@ -265,7 +270,7 @@ const toPreview = (data: any) => {
|
||||
query: {
|
||||
page: data.type_page + '?id=' + data.id
|
||||
}
|
||||
})
|
||||
});
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
@ -283,6 +288,7 @@ const shareFormData = reactive({
|
||||
url: ''
|
||||
}
|
||||
})
|
||||
|
||||
const shareDialogVisible = ref(false)
|
||||
const shareFormRules = computed(() => {
|
||||
return {}
|
||||
@ -329,9 +335,5 @@ const resetForm = (formEl: FormInstance | undefined) => {
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.copy {
|
||||
background: var(--el-color-primary) !important;
|
||||
color: var(--el-color-white) !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
304
admin/src/app/views/diy/member.vue
Normal file
304
admin/src/app/views/diy/member.vue
Normal file
@ -0,0 +1,304 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap mt-[20px] min-w-[1000px]" v-if="page.use_template">
|
||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
||||
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
||||
|
||||
<div v-show="page.use_template.url" class="w-[320px] h-[550px] mx-auto">
|
||||
<iframe :id="'previewIframe_' + key" v-show="page.loadingIframe" class="w-[320px] h-[550px] mx-auto" :src="page.use_template.wapPreview" frameborder="0"></iframe>
|
||||
<div v-show="page.loadingDev" class="w-[320px] h-[550px] mx-auto bg-body pt-[20px] px-[20px]">
|
||||
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
|
||||
<div class="mb-[20px] flex flex-col">
|
||||
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
|
||||
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
|
||||
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="!page.use_template.wapPreview" class="overflow-hidden w-[320px] h-[550px] mx-auto">
|
||||
<img class="max-w-full" v-if="page.use_template.cover" :src="img(page.use_template.cover)" />
|
||||
</div>
|
||||
|
||||
<div class="popup-wrap absolute inset-x-0 inset-y-0 select-none" :class="{ 'disabled': page.isDisabledPop }"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="w-[500px]">
|
||||
<div class="flex flex-wrap">
|
||||
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="mr-[12px]">{{ t('decorate') }}</el-button>
|
||||
</div>
|
||||
|
||||
<div class="info-wrap">
|
||||
|
||||
<div class="mt-[20px] bg-[#F7F8FA] p-[20px] flex items-center justify-between">
|
||||
<div>
|
||||
<div class="font-bold">{{ t('H5') }}</div>
|
||||
<el-form label-width="40px" class="mt-[5px]">
|
||||
<el-form-item :label="t('link')" v-show="page.use_template.wapPreview" class="mb-[5px]">
|
||||
<el-input readonly :value="page.use_template.wapPreview">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(page.use_template.wapPreview)" class="bg-primary copy">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="text-[#999] text-base">{{ t('scanQRCodeOnRight') }}</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<el-image class="w-[100px] h-[100px] mb-[5px]" :src="wapImage" />
|
||||
<div @click="toPreview()" class="text-primary text-base cursor-pointer">{{ t('preview') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getDecoratePage, changeTemplate } from '@/app/api/diy'
|
||||
import storage from '@/utils/storage'
|
||||
import QRCode from 'qrcode'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
|
||||
const type: any = ref('DIY_MEMBER_INDEX');
|
||||
const page: any = reactive({})
|
||||
const router = useRouter()
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const link = ref({
|
||||
name: ''
|
||||
})
|
||||
|
||||
// 添加自定义页面
|
||||
const formData = reactive({
|
||||
type: '',
|
||||
name: '',
|
||||
parent:'',
|
||||
page: '',
|
||||
title: '',
|
||||
action: ''
|
||||
})
|
||||
|
||||
// 初始化数据
|
||||
const refreshData = () => {
|
||||
getDecoratePage({
|
||||
type : type.value
|
||||
}).then(res => {
|
||||
for (const key in res.data) {
|
||||
page[key] = res.data[key]
|
||||
}
|
||||
|
||||
link.value.name = page.use_template.name;
|
||||
link.value.title = page.use_template.title;
|
||||
link.value.page = page.use_template.page;
|
||||
link.value.action = page.use_template.action;
|
||||
link.value.parent = page.use_template.parent;
|
||||
|
||||
if (page.use_template.url) {
|
||||
page.loadingIframe = false // 加载iframe
|
||||
page.loadingDev = false // 加载开发环境配置
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
page.difference = 0 // 检测页面加载差异,小于1000毫秒,则配置wap端域名
|
||||
|
||||
wapDomain.value = page.domain_url.wap_domain
|
||||
page.wapUrl = page.domain_url.wap_url
|
||||
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
// 开发模式情况下,并且未配置wap域名,则获取缓存域名
|
||||
if (wapDomain.value) {
|
||||
page.wapUrl = wapDomain.value + '/wap'
|
||||
setDomain()
|
||||
}
|
||||
if (storage.get('wap_domain')) {
|
||||
page.wapUrl = storage.get('wap_domain')
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
|
||||
setDomain()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
refreshData()
|
||||
|
||||
// 监听 uni-app 端 是否加载完成
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
page.loadingDev = false // 禁用开发环境配置
|
||||
page.loadingIframe = true // 加载iframe
|
||||
const loadTime = new Date().getTime()
|
||||
page.difference = loadTime - page.timeIframe
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
}
|
||||
} catch (e) {
|
||||
initLoad()
|
||||
console.log('后台接受数据错误', e)
|
||||
}
|
||||
}, false)
|
||||
|
||||
// 将数据发送到uniapp
|
||||
const postMessage = () => {
|
||||
const diyData = JSON.stringify({
|
||||
type: 'appOnReady',
|
||||
message: '加载完成'
|
||||
})
|
||||
if (window['previewIframe_' + type.value]) window['previewIframe_' + type.value].contentWindow.postMessage(diyData, '*')
|
||||
}
|
||||
|
||||
// 初始化加载状态
|
||||
const initLoad = () => {
|
||||
page.loadingDev = true
|
||||
page.isDisabledPop = true
|
||||
page.loadingIframe = false
|
||||
}
|
||||
|
||||
const saveDomain = () => {
|
||||
if (wapDomain.value.trim().length == 0) {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('wapDomainPlaceholder')}`,
|
||||
})
|
||||
return
|
||||
}
|
||||
const wapUrl = wapDomain.value + '/wap'
|
||||
storage.set({key: 'wap_domain', data: wapUrl})
|
||||
|
||||
if (page.use_template.url) {
|
||||
page.wapUrl = wapUrl
|
||||
setDomain()
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (page.use_template.url) {
|
||||
page.loadingIframe = true // 加载iframe
|
||||
page.loadingDev = false // 加载开发环境配置
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
}
|
||||
}, 100 * 3)
|
||||
}
|
||||
|
||||
const settingTips = () => {
|
||||
window.open('https://www.kancloud.cn/niucloud/niucloud-admin-develop/3213393')
|
||||
}
|
||||
|
||||
const setDomain = () => {
|
||||
page.use_template.wapPreview = page.wapUrl + page.use_template.url
|
||||
QRCode.toDataURL(page.use_template.wapPreview, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
page.timeIframe = new Date().getTime()
|
||||
postMessage()
|
||||
setTimeout(() => {
|
||||
if (page.difference == 0) initLoad()
|
||||
}, 1000 * 2)
|
||||
}
|
||||
|
||||
// 跳转去装修
|
||||
const toDecorate = () => {
|
||||
const query: any = {
|
||||
back: '/site/diy/member'
|
||||
}
|
||||
if (page.use_template.id) {
|
||||
query.id = page.use_template.id
|
||||
} else if (page.use_template.type) {
|
||||
query.name = page.use_template.type
|
||||
} else if (page.use_template.url) {
|
||||
query.url = page.use_template.url
|
||||
}
|
||||
const url = router.resolve({
|
||||
path: '/decorate/edit',
|
||||
query
|
||||
})
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
// 跳转去预览
|
||||
const toPreview = () => {
|
||||
let value = page.use_template.page
|
||||
if (page.use_template.url) {
|
||||
value = page.use_template.url
|
||||
} else if (page.use_template.id) {
|
||||
value += '?id=' + page.use_template.id
|
||||
}
|
||||
const url = router.resolve({
|
||||
path: '/preview/wap',
|
||||
query: {
|
||||
page:value
|
||||
}
|
||||
})
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
const isRepeat = ref(false)
|
||||
const changePage = ()=>{
|
||||
formData.type = type.value;
|
||||
formData.name = link.value.name;
|
||||
formData.page = link.value.url;
|
||||
formData.title = link.value.title;
|
||||
formData.action = link.value.action;
|
||||
formData.parent = link.value.parent;
|
||||
|
||||
if (isRepeat.value) return
|
||||
isRepeat.value = true
|
||||
|
||||
changeTemplate({
|
||||
...formData
|
||||
}).then((res) => {
|
||||
isRepeat.value = false
|
||||
refreshData()
|
||||
})
|
||||
}
|
||||
|
||||
// 复制
|
||||
const { copy, isSupported, copied } = useClipboard()
|
||||
const copyEvent = (text: string) => {
|
||||
if (!isSupported.value) {
|
||||
ElMessage({
|
||||
message: t('notSupportCopy'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
copy(text)
|
||||
}
|
||||
|
||||
watch(copied, () => {
|
||||
if (copied.value) {
|
||||
ElMessage({
|
||||
message: t('copySuccess'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-item {
|
||||
background-image: url(@/app/assets/images/iphone_bg.png);
|
||||
background-color: var(--el-bg-color);
|
||||
background-size: 100%;
|
||||
|
||||
.popup-wrap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.popup-wrap:not(.disabled) {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,204 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container w-[375px] mx-auto my-[20px] relative">
|
||||
|
||||
<div class="flex h-full" v-show="loading">
|
||||
<iframe v-show="loadingIframe" class="w-[375px] border border-slate-100 bg-gray-100" :src="wapPreview" frameborder="0" id="previewIframe" @load="loadIframe"></iframe>
|
||||
<div v-show="loadingDev" class="w-[375px] border border-slate-100 bg-body pt-[20px] px-[20px]">
|
||||
<div class="font-bold text-xl mb-[40px]">{{t('developTitle')}}</div>
|
||||
<div class="mb-[20px] flex flex-col">
|
||||
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
|
||||
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable/>
|
||||
</div>
|
||||
<el-button type="primary" @click="save">{{ t('confirm') }}</el-button>
|
||||
</div>
|
||||
|
||||
<div class="w-[400px] absolute bg-body top-[10%] -right-[450px]" v-if="loadingIframe">
|
||||
|
||||
<div class="info-wrap mt-[20px]">
|
||||
|
||||
<div class="px-[20px] pb-[10px] font-bold">{{t('h5')}}</div>
|
||||
<el-form label-width="40px" class="px-[20px]">
|
||||
|
||||
<el-form-item :label="t('link')" v-show="wapPreview">
|
||||
<el-input readonly :value="wapPreview">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(wapPreview)" class="bg-primary copy">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label=" " v-show="wapImage">
|
||||
<el-image :src="wapImage"/>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
<div class="px-[20px] pb-[10px] font-bold mt-[40px]">{{t('weapp')}}</div>
|
||||
<el-form label-width="40px" class="px-[20px]">
|
||||
<el-form-item label=" " v-if="weappConfig.qr_code">
|
||||
<el-image class="w-[100px] h-[100px]" :src="img(weappConfig.qr_code)"/>
|
||||
</el-form-item>
|
||||
<el-form-item label=" " v-else>
|
||||
<span class="text-gray-400">{{t('weappNotSet')}}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getWeappConfig } from '@/app/api/weapp'
|
||||
import { getUrl } from '@/app/api/sys'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { img } from '@/utils/common'
|
||||
import QRCode from 'qrcode'
|
||||
import storage from '@/utils/storage'
|
||||
import { getPreviewData } from '@/app/api/diy'
|
||||
|
||||
const wapUrl = ref('')
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const wapPreview = ref('')
|
||||
|
||||
const loading = ref(false)
|
||||
const loadingIframe = ref(false) // 加载iframe
|
||||
const loadingDev = ref(false) // 加载开发环境配置
|
||||
const timeFrame = ref(0)
|
||||
|
||||
let time = new Date().getTime()
|
||||
const route = useRoute()
|
||||
route.query.id = route.query.id || 0
|
||||
route.query.name = route.query.name || ''
|
||||
|
||||
getUrl().then((res: any) => {
|
||||
wapDomain.value = res.data.wap_domain
|
||||
wapUrl.value = res.data.wap_url
|
||||
setDomain()
|
||||
|
||||
// 生产模式禁止
|
||||
if (import.meta.env.MODE == 'production') return
|
||||
|
||||
// env文件配置过wap域名
|
||||
if (wapDomain.value) return
|
||||
|
||||
let wap_domain_storage = storage.get('wap_domain')
|
||||
if (wap_domain_storage) {
|
||||
wapUrl.value = wap_domain_storage
|
||||
setDomain()
|
||||
return
|
||||
}
|
||||
|
||||
timeFrame.value = new Date().getTime()
|
||||
})
|
||||
|
||||
const save = () => {
|
||||
if (wapDomain.value.trim().length == 0) {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('wapDomainPlaceholder')}`
|
||||
})
|
||||
return
|
||||
}
|
||||
wapUrl.value = wapDomain.value + '/wap'
|
||||
setDomain()
|
||||
storage.set({ key: 'wap_domain', data: wapUrl.value })
|
||||
loadingIframe.value = true
|
||||
loadingDev.value = false
|
||||
}
|
||||
|
||||
const setDomain = () => {
|
||||
getPreviewData({
|
||||
id: route.query.id,
|
||||
name: route.query.name
|
||||
}).then((res: any) => {
|
||||
const data = res.data
|
||||
wapPreview.value = `${wapUrl.value}/${data.page}`
|
||||
|
||||
// 开发模式增加站点id
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
const siteId = storage.get('siteId') || 0
|
||||
wapPreview.value += `&site_id=${siteId}`
|
||||
}
|
||||
QRCode.toDataURL(wapPreview.value, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 监听iframe加载事件
|
||||
const loadIframe = () => {
|
||||
if (!wapPreview.value) return
|
||||
const loadTime = new Date().getTime()
|
||||
const difference = loadTime - timeFrame.value
|
||||
// 检测页面加载差异,小于1000毫秒,则配置wap端域名
|
||||
if (difference < 1000) {
|
||||
loadingDev.value = true
|
||||
loadingIframe.value = false
|
||||
wapPreview.value = ''
|
||||
wapImage.value = ''
|
||||
} else {
|
||||
loadingDev.value = false
|
||||
loadingIframe.value = true
|
||||
}
|
||||
loading.value = true
|
||||
}
|
||||
|
||||
const weappConfig = reactive({
|
||||
qr_code: ''
|
||||
})
|
||||
|
||||
const previewMode = ref('weapp')
|
||||
|
||||
// 获取微信配置
|
||||
getWeappConfig().then((res: any) => {
|
||||
if (res.code == 1) {
|
||||
const data = res.data
|
||||
weappConfig.qr_code = data.qr_code
|
||||
}
|
||||
})
|
||||
|
||||
// 复制
|
||||
const { copy, isSupported, copied } = useClipboard()
|
||||
const copyEvent = (text: string) => {
|
||||
if (!isSupported.value) {
|
||||
ElMessage({
|
||||
message: t('notSupportCopy'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
copy(text)
|
||||
}
|
||||
|
||||
watch(copied, () => {
|
||||
if (copied.value) {
|
||||
ElMessage({
|
||||
message: t('copySuccess'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
body {
|
||||
background: #edf0f3;
|
||||
}
|
||||
|
||||
.copy {
|
||||
background: var(--el-color-primary) !important;
|
||||
color: var(--el-color-white) !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@ -264,10 +264,4 @@ const resetForm = (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.copy {
|
||||
background: var(--el-color-primary) !important;
|
||||
color: var(--el-color-white) !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
<el-tabs v-model="activeName" class="demo-tabs mt-[15px]">
|
||||
<el-tab-pane :label="t('navImage')" name="navPicture">
|
||||
<div ref="navItemRef">
|
||||
<div v-for="(item,index) in diyBottomData.list" :key="'a'+index" :data-id="index" class="item-wrap !cursor-move border-2 border-dashed pt-[18px] m-[10px] mb-[15px] relative list-item">
|
||||
<div v-for="(item,index) in diyBottomData.list" :key="'a'+index" :data-id="index" class="item-wrap border-2 border-dashed pt-[18px] m-[10px] mb-[15px] relative list-item">
|
||||
<el-form-item :label="t('navIconOne')">
|
||||
<div class="flex align-center">
|
||||
<div class="flex flex-col justify-center items-center">
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import { ref, reactive, watch, inject } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getWeappConfig } from '@/app/api/weapp'
|
||||
@ -78,6 +78,9 @@ const difference = ref(0) // 检测页面加载差异,小于1000毫秒,则
|
||||
const route = useRoute()
|
||||
route.query.page = route.query.page || '' // 页面路径
|
||||
|
||||
const setLayout = inject('setLayout')
|
||||
setLayout('decorate')
|
||||
|
||||
getUrl().then((res: any) => {
|
||||
wapUrl.value = res.data.wap_url
|
||||
setDomain()
|
||||
@ -118,7 +121,6 @@ const save = () => {
|
||||
const setDomain = () => {
|
||||
if (route.query.page) {
|
||||
wapPreview.value = `${wapUrl.value}${route.query.page}`
|
||||
console.log(wapPreview.value)
|
||||
// errorCorrectionLevel:密度容错率L(低)H(高)
|
||||
QRCode.toDataURL(wapPreview.value, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -29,8 +29,7 @@
|
||||
<el-table v-if="localList[activeName].length" :data="info[activeName]" size="large" class="pt-[5px]">
|
||||
<el-table-column :label="t('appName')" align="left" width="320">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center" @click = "handleTips"
|
||||
:class="{ 'cursor-pointer': row.type == 'app' && Object.keys(row.install_info).length }">
|
||||
<div class="flex items-center cursor-pointer" @click = "handleTips">
|
||||
<el-image class="w-[54px] h-[54px]" :src="row.icon" fit="contain">
|
||||
<template #error>
|
||||
<div class="flex items-center w-full h-full">
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
</div>
|
||||
<img src="@/app/assets/images/tools/app_auth.png" class="w-[256px] h-[128px]" />
|
||||
</div>
|
||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/setting/admin')">
|
||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/admin_menu')">
|
||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||
<span class="text-[16px] text-[#222] font-bold">平台菜单</span>
|
||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||
@ -74,7 +74,7 @@
|
||||
</div>
|
||||
<img src="@/app/assets/images/tools/official_market.png" class="w-[256px] h-[128px]" />
|
||||
</div>
|
||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/setting/site')">
|
||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/site_menu')">
|
||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||
<span class="text-[16px] text-[#222] font-bold">站点菜单</span>
|
||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-container
|
||||
:class="['w-full h-screen bg-page', { 'login-wrap': loginType == 'admin' }, { 'site-login-wrap': loginType == 'site' }]">
|
||||
:class="['w-full h-screen bg-page flex flex-col', { 'login-wrap': loginType == 'admin' }, { 'site-login-wrap': loginType == 'site' }]">
|
||||
<!-- 平台端登录 -->
|
||||
<el-main class="login-main items-center justify-center" v-if="!imgLoading && loginType == 'admin'">
|
||||
<div class="flex rounded-2xl overflow-hidden">
|
||||
@ -86,6 +86,20 @@
|
||||
</div>
|
||||
</el-main>
|
||||
|
||||
<div class="flex items-center justify-center mt-[20px] text-[#999] text-sm pb-10 " v-if="copyright">
|
||||
<a :href="copyright.gov_url" v-if="copyright.gov_record" class="flex" target="_blank">
|
||||
<img src="@/app/assets/images/gov_icon.png" alt="" class="h-[20px] mr-1">
|
||||
<span class="mr-3">公安备案号:{{ copyright.gov_record }}</span>
|
||||
</a>
|
||||
<a href="https://beian.miit.gov.cn/" target="_blank" v-if="copyright.icp">
|
||||
<span class="mr-3">备案号:{{ copyright.icp }}</span>
|
||||
</a>
|
||||
<a :href="copyright.copyright_link" target="_blank">
|
||||
<span class="mr-3" v-if="copyright.company_name">{{ copyright.company_name }}</span>
|
||||
<span class="mr-3" v-if="copyright.copyright_desc">©{{ copyright.copyright_desc }}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 验证组件 -->
|
||||
<verify @success="success" :mode="pop" captchaType="blockPuzzle" :imgSize="{ width: '330px', height: '155px' }"
|
||||
ref="verifyRef"></verify>
|
||||
@ -102,13 +116,18 @@ import storage from '@/utils/storage'
|
||||
import { getLoginConfig } from '@/app/api/auth'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { setWindowTitle, img, getAppType } from '@/utils/common'
|
||||
import { getWebConfig } from '@/app/api/sys'
|
||||
import { getWebConfig, getWebCopyright } from '@/app/api/sys'
|
||||
|
||||
const loading = ref(false)
|
||||
const imgLoading = ref(false)
|
||||
const userStore = useUserStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const copyright = ref(null)
|
||||
|
||||
getWebCopyright().then(({ data }) => {
|
||||
copyright.value = data
|
||||
})
|
||||
|
||||
route.redirectedFrom && (route.query.redirect = route.redirectedFrom.path)
|
||||
|
||||
|
||||
@ -124,13 +124,11 @@ checkPayConfigList()
|
||||
|
||||
// 配置支付宝、微信信息
|
||||
const setConfigInfo = (data:any) => {
|
||||
console.log(data)
|
||||
payConfigData.value[data.channel].pay_type.forEach(element => {
|
||||
if (element.key == data.type) {
|
||||
element.config = data.config
|
||||
}
|
||||
})
|
||||
console.log(payConfigData.value)
|
||||
}
|
||||
|
||||
// 初始化配置信息
|
||||
|
||||
@ -82,7 +82,6 @@ const weappTableData = reactive({
|
||||
last_time: ''
|
||||
}
|
||||
})
|
||||
// const searchFormRef = ref<FormInstance>()
|
||||
|
||||
/**
|
||||
* 获取任务列表
|
||||
@ -105,8 +104,6 @@ const loadWeappTemplateList = (page: number = 1) => {
|
||||
}
|
||||
loadWeappTemplateList()
|
||||
|
||||
// const router = useRouter()
|
||||
|
||||
const showDialog = ref(false)
|
||||
const initialFormData = {
|
||||
id: 0,
|
||||
@ -119,10 +116,10 @@ const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const showEvent = () => {
|
||||
formData.id = 0,
|
||||
formData.desc = '',
|
||||
formData.path = '',
|
||||
formData.version = '',
|
||||
formData.id = 0
|
||||
formData.desc = ''
|
||||
formData.path = ''
|
||||
formData.version = ''
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
@ -134,7 +131,7 @@ const formRules = computed(() => {
|
||||
],
|
||||
path: [
|
||||
{ required: true, validator: validatePass, trigger: 'blur' }
|
||||
],
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
@ -144,34 +141,34 @@ const validatePass = (rule: any, value: any, callback: any) => {
|
||||
}
|
||||
return callback()
|
||||
}
|
||||
const save_type = ref(false)
|
||||
const saveType = ref(false)
|
||||
const addEvent = async (formEl: FormInstance | undefined) => {
|
||||
if (save_type.value || !formEl) return
|
||||
if (saveType.value || !formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
save_type.value = true
|
||||
saveType.value = true
|
||||
const data = formData
|
||||
const save = formData.id > 0 ? editVersion : addVersion
|
||||
save(data).then(res => {
|
||||
save_type.value = false
|
||||
saveType.value = false
|
||||
showDialog.value = false
|
||||
loadWeappTemplateList()
|
||||
}).catch(() => {
|
||||
save_type.value = false
|
||||
saveType.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const editEvent = (item:any) => {
|
||||
formData.id = item.id,
|
||||
formData.desc = item.desc,
|
||||
formData.id = item.id
|
||||
formData.desc = item.desc
|
||||
formData.path = item.path
|
||||
formData.version = item.version
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
const deleteEvent = (id: number) => {
|
||||
const deleteEvent = (id: string) => {
|
||||
ElMessageBox.confirm(t('weappVersionDeleteTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
|
||||
@ -30,7 +30,18 @@
|
||||
|
||||
<el-table-column prop="group_name" :label="t('groupName')" />
|
||||
|
||||
<el-table-column prop="group_desc" :label="t('remark')"></el-table-column>
|
||||
<el-table-column prop="group_name" :label="t('appName')" :show-overflow-tooltip="true">
|
||||
<template #default="{ row }">
|
||||
<el-tag class="mr-1" size="small" v-for="name in row.app_name">{{ name }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="group_name" :label="t('addonName')" :show-overflow-tooltip="true">
|
||||
<template #default="{ row }">
|
||||
<el-tag class="mr-1" size="small" v-for="name in row.addon_name">{{ name }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="create_time" :label="t('createTime')"></el-table-column>
|
||||
<el-table-column prop="group_roles" :label="t('operation')" align="right" fixed="right" width="130">
|
||||
<template #default="{ row }">
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
<div class="w-full">
|
||||
<div class="flex">
|
||||
<div class="w-[60px] h-[60px] mr-[10px] rounded-md overflow-hidden">
|
||||
<el-image :src="img(item.cover)" v-if="item.cover"
|
||||
<el-image :src="img(item.icon)" v-if="item.icon"
|
||||
class="w-full h-full" />
|
||||
<el-image v-else class="w-full h-full">
|
||||
<template #error>
|
||||
@ -63,7 +63,7 @@
|
||||
<div class="w-full">
|
||||
<div class="flex">
|
||||
<div class="w-[60px] h-[60px] mr-[10px] rounded-md overflow-hidden">
|
||||
<el-image :src="img(item.cover)" v-if="item.cover"
|
||||
<el-image :src="img(item.icon)" v-if="item.icon"
|
||||
class="w-full h-full" />
|
||||
<el-image v-else class="w-full h-full">
|
||||
<template #error>
|
||||
@ -125,8 +125,28 @@ const formData: Record<string, any> = ref({
|
||||
addon: []
|
||||
})
|
||||
|
||||
let installAddon = []
|
||||
const getInstalledAddonListFn = async () => {
|
||||
await getInstalledAddonList().then(({ data }) => {
|
||||
const apps: any[] = []
|
||||
const addons: any[] = []
|
||||
|
||||
Object.keys(data).forEach(key => {
|
||||
installAddon.push(key)
|
||||
const item = data[key]
|
||||
item.type == 'addon' ? addons.push(item) : apps.push(item)
|
||||
})
|
||||
|
||||
appList.value = apps
|
||||
addonList.value = addons
|
||||
}).catch()
|
||||
}
|
||||
getInstalledAddonListFn()
|
||||
|
||||
if (route.query.id) {
|
||||
getSiteGroupInfo(route.query.id).then(({ data }) => {
|
||||
data.app = data.app.filter((key: string) => installAddon.includes(key))
|
||||
data.addon = data.addon.filter((key: string) => installAddon.includes(key))
|
||||
formData.value = data
|
||||
loading.value = false
|
||||
}).catch()
|
||||
@ -138,19 +158,6 @@ const back = () => {
|
||||
router.push('/admin/site/group')
|
||||
}
|
||||
|
||||
getInstalledAddonList().then(({ data }) => {
|
||||
const apps: any[] = []
|
||||
const addons: any[] = []
|
||||
|
||||
Object.keys(data).forEach(key => {
|
||||
const item = data[key]
|
||||
item.type == 'addon' ? addons.push(item) : apps.push(item)
|
||||
})
|
||||
|
||||
appList.value = apps
|
||||
addonList.value = addons
|
||||
}).catch()
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
// 表单验证规则
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="main-container" v-loading="loading">
|
||||
<div class="detail-head !mb-[10px]">
|
||||
<div class="left" @click="router.push({ path: '/admin/site/list' })">
|
||||
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
|
||||
@ -43,6 +43,54 @@
|
||||
<el-form-item :label="t('expireTime')">
|
||||
<div class="input-width">{{ formData.expire_time || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('app')">
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="item in formData.site_addons">
|
||||
<div class="flex w-[300px] border border-solid p-[10px] !mr-[10px] !mb-[10px] rounded-md" v-if="item.type == 'app'">
|
||||
<div class="w-[60px] h-[60px] mr-[10px] rounded-md overflow-hidden">
|
||||
<el-image :src="img(item.icon)" v-if="item.icon"
|
||||
class="w-full h-full" />
|
||||
<el-image v-else class="w-full h-full">
|
||||
<template #error>
|
||||
<div class="image-error">
|
||||
<el-icon><icon-picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
<div class="flex-1 w-0 flex flex-col justify-center leading-tight">
|
||||
<div class="font-bold truncate">{{ item.title }}</div>
|
||||
<div class="text-gray-400 mt-[10px] truncate" :title="item.desc">{{ item.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('addon')">
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="item in formData.site_addons">
|
||||
<div class="flex w-[300px] border border-solid p-[10px] !mr-[10px] !mb-[10px] rounded-md" v-if="item.type == 'addon'">
|
||||
<div class="w-[60px] h-[60px] mr-[10px] rounded-md overflow-hidden">
|
||||
<el-image :src="img(item.icon)" v-if="item.icon"
|
||||
class="w-full h-full" />
|
||||
<el-image v-else class="w-full h-full">
|
||||
<template #error>
|
||||
<div class="image-error">
|
||||
<el-icon><icon-picture /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
</div>
|
||||
<div class="flex-1 w-0 flex flex-col justify-center leading-tight">
|
||||
<div class="font-bold truncate">{{ item.title }}</div>
|
||||
<div class="text-gray-400 mt-[10px] truncate" :title="item.desc">{{ item.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
|
||||
</el-form>
|
||||
@ -97,7 +145,8 @@ const initialFormData = {
|
||||
phone: '',
|
||||
group_name: '',
|
||||
status: 0,
|
||||
create_time: 0
|
||||
create_time: 0,
|
||||
site_addons: []
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
:placeholder="t('groupIdPlaceholder')" class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item['group_name']" :value="item['group_id']"
|
||||
v-for="(item, index) in groupList[siteTableData.searchParam.app]" :key="index"/>
|
||||
v-for="(item, index) in groupList.all" :key="index"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="expire_time" :label="t('expireTime')" />
|
||||
<el-table-column :label="t('operation')" min-width="250" align="right" fixed="right">
|
||||
<el-table-column :label="t('operation')" align="right" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="siteInfo(row)">{{ t('info') }}</el-button>
|
||||
</template>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('dictType')" v-if="formData.select_type == 1">
|
||||
<el-form-item :label="t('dictType')" v-if="formData.select_type == 1" prop="dict_type">
|
||||
<el-select class="input-width" :placeholder="t('dictTypePlaceholder')" v-model="formData.dict_type" filterable remote clearable>
|
||||
<el-option :label="item.name" :value="item.key" v-for="item in dicList" :key="item.key" />
|
||||
</el-select>
|
||||
@ -121,7 +121,66 @@ const modelChange = (val:any) => {
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
dict_type: [
|
||||
{ required: true, message: t('dictTypePlaceholder'), trigger: 'change' }
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
console.log(formData.value.select_type)
|
||||
if (formData.value.select_type == 1 && formData.value.dict_type == '') {
|
||||
callback(new Error(t('dictTypePlaceholder')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
addon: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (formData.value.select_type == 2 && formData.value.addon == '') {
|
||||
callback(new Error(t('addonsPlaceholder')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
model: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
console.log(formData.value.model);
|
||||
if (formData.value.select_type == 2 && formData.value.model == '') {
|
||||
callback(new Error(t('associatedModelPlaceholder')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
value_key: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (formData.value.select_type == 2 && formData.value.value_key == '') {
|
||||
callback(new Error(t('remotePullDownValuePlaceholder')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
label_key: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (formData.value.select_type == 2 && formData.value.label_key == '') {
|
||||
callback(new Error(t('remotePullDownLabelPlaceholder')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
<el-table :data="formData.table_column" size="large" ref="tableRef" :key="toggleIndex">
|
||||
<el-table-column align="center" label="操作" width="80">
|
||||
<template #default>
|
||||
<i class="iconfont icontuodong vues-rank cursor-move"></i>
|
||||
<i class="iconfont icontuodong vues-rank"></i>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('columnName')" prop="column_name" min-width="130px" />
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="main-container attachment-container" v-if="systemService">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="main-container attachment-container min-h-[80vh]" v-loading="loading">
|
||||
<el-card class="box-card !border-none" shadow="never" v-if="Object.keys(systemService).length">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{ pageName }}</span>
|
||||
</div>
|
||||
<div class="bg-[#fff] pb-[20px] mb-3">
|
||||
<p class="pt-[20px] pb-[10px] text-sm">{{ t('serverInformation') }}</p>
|
||||
<div class="text-[14px]">
|
||||
<el-table :data="systemService.server" size="large" v-loading="loadingArr.server_load">
|
||||
<el-table :data="systemService.server" size="large">
|
||||
<el-table-column prop="name" :label="t('environment')" align="left" min-width="200" />
|
||||
<el-table-column prop="server" :label="t('version')" align="left" min-width="140" />
|
||||
</el-table>
|
||||
@ -16,7 +16,7 @@
|
||||
<div class="bg-[#fff] pb-[20px] mb-3">
|
||||
<p class="py-[20px] text-sm">{{ t('systemDemand') }}</p>
|
||||
<div class="text-[14px]">
|
||||
<el-table :data="systemService.server_version" size="large" v-loading="loadingArr.server_version_load">
|
||||
<el-table :data="systemService.server_version" size="large">
|
||||
<el-table-column prop="name" :label="t('environment')" align="left" min-width="200" />
|
||||
<el-table-column prop="demand" :label="t('demand')" align="left" min-width="140" />
|
||||
<el-table-column prop="server" :label="t('version')" align="left" min-width="140" />
|
||||
@ -26,7 +26,7 @@
|
||||
<div class="bg-[#fff] pb-[20px] mb-3">
|
||||
<p class="py-[20px] text-sm">{{ t('authorityStatus') }}</p>
|
||||
<div class="text-[14px]">
|
||||
<el-table :data="systemService.system_variables" size="large" v-loading="loadingArr.system_variables_load">
|
||||
<el-table :data="systemService.system_variables" size="large">
|
||||
<el-table-column prop="name" :label="t('name')" align="left" min-width="200" />
|
||||
<el-table-column prop="need" :label="t('demand')" align="left" min-width="140" />
|
||||
<el-table-column :label="t('status')" align="left" min-width="140">
|
||||
@ -46,7 +46,7 @@
|
||||
<div class="bg-[#fff] pb-[20px] mb-3">
|
||||
<p class="py-[20px] text-sm">{{ t('process') }}</p>
|
||||
<div class="text-[14px]">
|
||||
<el-table :data="systemService.process" size="large" v-loading="loadingArr.process_load">
|
||||
<el-table :data="systemService.process" size="large">
|
||||
<el-table-column prop="name" :label="t('name')" align="left" min-width="200" />
|
||||
<el-table-column prop="need" :label="t('demand')" align="left" min-width="140" />
|
||||
<el-table-column :label="t('status')" align="left" min-width="140">
|
||||
@ -75,24 +75,12 @@ import { useRoute } from 'vue-router'
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
|
||||
const systemService = ref([])
|
||||
const loadingArr = reactive({
|
||||
server_load: true,
|
||||
server_version_load: true,
|
||||
system_variables_load: true,
|
||||
process_load: true
|
||||
})
|
||||
const systemService = ref({})
|
||||
let loading = ref(true);
|
||||
const getSystemService = () => {
|
||||
loadingArr.server_load = true
|
||||
loadingArr.server_version_load = true
|
||||
loadingArr.system_variables_load = true
|
||||
loadingArr.process_load = true
|
||||
getSystem().then(res => {
|
||||
systemService.value = res.data
|
||||
loadingArr.server_load = false
|
||||
loadingArr.server_version_load = false
|
||||
loadingArr.system_variables_load = false
|
||||
loadingArr.process_load = false
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
getSystemService()
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="main-container h-[500px] w-full p-5 bg-white" v-loading="loading">
|
||||
<div class="flex flex-wrap px-2 plug-list pb-10">
|
||||
<!-- <div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">-->
|
||||
<!-- <div class="flex flex-col ml-2">-->
|
||||
<!-- <span class="text-sm truncate w-[190px]">{{t('refreshMenu')}}</span>-->
|
||||
<!-- <span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('refreshMenuDesc')">{{t('refreshMenuDesc')}}</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- <span class="plug-item-operate" @click="refreshMenu()">{{t('refresh')}}</span>-->
|
||||
<!-- </div>-->
|
||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
||||
<div class="flex flex-col ml-2">
|
||||
<span class="text-sm truncate w-[190px]">{{t('refreshMenu')}}</span>
|
||||
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('refreshMenuDesc')">{{t('refreshMenuDesc')}}</span>
|
||||
</div>
|
||||
<span class="plug-item-operate" @click="refreshMenu()">{{t('refresh')}}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
||||
<div class="flex flex-col ml-2">
|
||||
|
||||
@ -32,14 +32,12 @@
|
||||
<template v-if="parentLinkName == 'DIY_LINK'">
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyLinkName')">
|
||||
<el-input v-model="selectLink.title" :placeholder="t('diyLinkNamePlaceholder')"
|
||||
class="w-6/12" />
|
||||
<el-input v-model="selectLink.title" :placeholder="t('diyLinkNamePlaceholder')" class="w-6/12" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyLinkUrl')">
|
||||
<el-input v-model="selectLink.url" :placeholder="t('diyLinkUrlPlaceholder')"
|
||||
class="w-6/12" />
|
||||
<el-input v-model="selectLink.url" :placeholder="t('diyLinkUrlPlaceholder')" class="w-6/12" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label=" ">
|
||||
@ -80,6 +78,10 @@ const prop = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ignore:{
|
||||
type:Array,
|
||||
default:[]
|
||||
}
|
||||
})
|
||||
|
||||
@ -109,6 +111,11 @@ const show = () => {
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value)
|
||||
parentLinkName.value = selectLink.value.parent
|
||||
for (let key in link.value){
|
||||
if(link.value[key].name == parentLinkName.value){
|
||||
changeParentLink(link.value[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
showDialog.value = true
|
||||
}
|
||||
@ -116,6 +123,17 @@ const show = () => {
|
||||
getLink({}).then((res: any) => {
|
||||
link.value = res.data
|
||||
|
||||
if(prop.ignore && prop.ignore.length){
|
||||
for (let key in link.value){
|
||||
for(let i=0;i<prop.ignore.length;i++){
|
||||
if(key == prop.ignore[i]){
|
||||
delete link.value[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
childList.value = Object.values(link.value)[0].child_list
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value)
|
||||
@ -149,16 +167,14 @@ const clear = () => {
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
// 自定义链接
|
||||
if (parentLinkName.value === 'DIY_LINK') {
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.name = parentLinkName.value
|
||||
// 自定义链接
|
||||
|
||||
if (!selectLink.value.title) {
|
||||
ElMessage({
|
||||
message: t('diyLinkNameNotEmpty'),
|
||||
type: 'warning'
|
||||
})
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
@ -166,13 +182,24 @@ const save = () => {
|
||||
ElMessage({
|
||||
message: t('diyLinkUrlNotEmpty'),
|
||||
type: 'warning'
|
||||
})
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.name = parentLinkName.value
|
||||
selectLink.value.page = selectLink.value.url;
|
||||
selectLink.value.action = '';
|
||||
|
||||
}else if(parentLinkName.value == 'DIY_PAGE'){
|
||||
// 自定义页面
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.action = 'decorate';
|
||||
}
|
||||
|
||||
value.value = cloneDeep(selectLink.value)
|
||||
showDialog.value = false
|
||||
emit('success')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<div class="content-box relative bg-cover bg-gray-100 border border-dashed border-gray-500"
|
||||
:style="{ backgroundImage: 'url(' + img(value.imageUrl) + ')', width: contentBoxWidth + 'px', height: contentBoxHeight + 'px' }">
|
||||
<div v-for="(item, index) in dragBoxArr" :id="'box_' + index" :key="index"
|
||||
class="area-box cursor-move border border-solid border-[#ccc] w-[100px] h-[100px] absolute top-0 left-0 select-none p-[5px]"
|
||||
class="area-box border border-solid border-[#ccc] w-[100px] h-[100px] absolute top-0 left-0 select-none p-[5px]"
|
||||
:style="{ left: item.left + item.unit, top: item.top + item.unit, width: item.width + item.unit, height: item.height + item.unit }"
|
||||
@mousedown="mouseDown($event, index)">
|
||||
<span>{{ index + 1 }}</span>
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import {computed, ref, watch} from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
@ -21,7 +21,7 @@ const prop = defineProps({
|
||||
type: String,
|
||||
default: '350px'
|
||||
},
|
||||
value: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
@ -39,14 +39,21 @@ const prop = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const value = ref(prop.value)
|
||||
const visible = ref(false)
|
||||
|
||||
watch(visible, () => {
|
||||
if (!visible.value) {
|
||||
value.value = ''
|
||||
const value = computed({
|
||||
get () {
|
||||
return prop.modelValue
|
||||
},
|
||||
set (value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
const visible = ref(false)
|
||||
|
||||
// watch(visible, () => {
|
||||
// if (!visible.value) {
|
||||
// value.value = ''
|
||||
// }
|
||||
// })
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item class="text-center">
|
||||
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')"
|
||||
@confirm="updateAttachmentCategory($event, index)" :value="item.name">
|
||||
@confirm="updateAttachmentCategory($event, index)" v-model="item.name">
|
||||
<span>{{ t('edit') }}</span>
|
||||
</popover-input>
|
||||
</el-dropdown-item>
|
||||
@ -40,7 +40,7 @@
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<!-- 添加分组 -->
|
||||
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')" @confirm="addAttachmentCategory"
|
||||
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')" @confirm="addAttachmentCategory" v-model="attachmentCategoryName"
|
||||
v-if="prop.type != 'icon'">
|
||||
<el-button>{{ t('upload.addAttachmentCategory') }}</el-button>
|
||||
</popover-input>
|
||||
@ -219,6 +219,7 @@ import { debounce, img, getToken } from '@/utils/common'
|
||||
import { ElMessage, UploadFile, UploadFiles, ElMessageBox } from 'element-plus'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const attachmentCategoryName = ref('')
|
||||
const operate = ref(false)
|
||||
const prop = defineProps({
|
||||
// 选择数量限制
|
||||
@ -333,6 +334,7 @@ const addAttachmentCategory = (name: string) => {
|
||||
type: prop.type,
|
||||
name
|
||||
}).then(res => {
|
||||
attachmentCategoryName.value = ''
|
||||
getAttachmentCategoryList(1)
|
||||
}).catch(() => {
|
||||
|
||||
@ -536,6 +538,7 @@ defineExpose({
|
||||
<style lang="scss" scoped>
|
||||
.group-list {
|
||||
.group-item {
|
||||
height: 32px;
|
||||
margin-top: 3px;
|
||||
|
||||
.operate {
|
||||
|
||||
@ -4,6 +4,16 @@ import Language from "./language"
|
||||
import zhCn from "./zh-cn/common.json";
|
||||
import en from "./en/common.json"
|
||||
|
||||
const addonZhCnCommon = import.meta.globEager('@/addon/**/lang/zh-cn/common.json')
|
||||
const addonEnCommon = import.meta.globEager('@/addon/**/lang/en/common.json')
|
||||
|
||||
for (let key in addonZhCnCommon) {
|
||||
Object.assign(zhCn, addonZhCnCommon[key].default)
|
||||
}
|
||||
for (let key in addonEnCommon) {
|
||||
Object.assign(en, addonEnCommon[key].default)
|
||||
}
|
||||
|
||||
//创建实例
|
||||
let i18n = createI18n({
|
||||
datetimeFormats: {},
|
||||
@ -19,4 +29,4 @@ let i18n = createI18n({
|
||||
const language = new Language(i18n);
|
||||
|
||||
export { language };
|
||||
export default i18n;
|
||||
export default i18n;
|
||||
|
||||
@ -2,9 +2,10 @@
|
||||
<el-container class="h-[60px] bg-[#2B303B] layout-admin flex items-center justify-between px-[15px] text-white" >
|
||||
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
||||
<div class="flex items-center text-[14px] leading-[1]">
|
||||
<span class="iconfont icontuodong !text-[25px] cursor-pointer mr-[6px]" @click="toLink('/admin/index')"></span>
|
||||
<span class="iconfont icontuodong !text-[25px] mr-[6px]"></span>
|
||||
<span class="cursor-pointer" @click="toLink('/admin/index')">首页</span>
|
||||
<span class="mx-2 text-[#4F5563] mx-[15px]">|</span>
|
||||
<span class="cursor-pointer" @click="toLink('/admin/setting/website/system','setting_manage')">控制台</span>
|
||||
<span class="cursor-pointer" @click="toLink('/admin/setting/website/system','setting_manage')">配置</span>
|
||||
<span class="mx-2 text-[#4F5563] mx-[15px]">|</span>
|
||||
<span class="cursor-pointer" @click="toLink('/admin/site/list','site_manage')">站点</span>
|
||||
<template v-if="app_debug">
|
||||
|
||||
@ -2,18 +2,12 @@
|
||||
<template v-if="meta.show">
|
||||
<el-sub-menu v-if="routes.children" :index="String(routes.name)">
|
||||
<template #title>
|
||||
<div v-if="meta.icon" class="w-[16px] h-[16px] relative flex items-center">
|
||||
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
|
||||
</div>
|
||||
<span :class="['ml-[10px]']">{{ meta.title }}</span>
|
||||
</template>
|
||||
<menu-item v-for="(route, index) in routes.children" :routes="route" :key="index" />
|
||||
</el-sub-menu>
|
||||
<template v-else>
|
||||
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-if="meta.addon && meta.parent_route && meta.parent_route.addon == ''">
|
||||
<div class="w-[16px] h-[16px] relative flex justify-center">
|
||||
<el-image class="w-[16px] h-[16px] rounded-[50%] overflow-hidden" :src="img(addons[meta.addon].icon)" fit="fill"/>
|
||||
</div>
|
||||
<template #title>
|
||||
<el-tooltip placement="right" effect="light">
|
||||
<template #content>
|
||||
@ -24,9 +18,6 @@
|
||||
</template>
|
||||
</el-menu-item>
|
||||
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })" v-else>
|
||||
<div class="w-[16px] h-[16px] relative flex justify-center">
|
||||
<icon :name="meta.icon" class="absolute top-[50%] -translate-y-[50%]" v-if="meta.icon"/>
|
||||
</div>
|
||||
<template #title>
|
||||
<span :class="[{'text-[15px]': routes.meta.class == 1}, {'text-[14px]': routes.meta.class != 1}, {'ml-[10px]': routes.meta.class == 2, 'ml-[15px]': routes.meta.class == 3}]">{{ meta.title }}</span>
|
||||
</template>
|
||||
|
||||
@ -20,8 +20,8 @@
|
||||
<icon :name="item.meta.icon" class="absolute top-[50%] -translate-y-[50%]" v-else />
|
||||
</div>
|
||||
<template #title>
|
||||
<div class="relative">
|
||||
<span :class="['ml-[10px]']">{{ item.meta.title }}</span>
|
||||
<div class="relative flex-1 w-0">
|
||||
<span class="ml-[10px] w-full truncate">{{ item.meta.short_title || item.meta.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
@ -32,7 +32,7 @@
|
||||
</div>
|
||||
<el-scrollbar v-if="twoMenuData.length" class="two-menu w-[140px]">
|
||||
<div class="w-[140px] h-[64px] flex items-center justify-center text-[16px] border-0 border-b-[1px] border-solid border-[#eee]">{{ route.matched[1].meta.title }}</div>
|
||||
<el-menu :default-active="route.name" :router="true" class="aside-menu" unique-opened="true" :collapse="systemStore.menuIsCollapse">
|
||||
<el-menu :default-active="route.name" :router="true" class="aside-menu" :collapse="systemStore.menuIsCollapse">
|
||||
<menu-item v-for="(route, index) in twoMenuData" :routes="route" :key="index" />
|
||||
</el-menu>
|
||||
<div class="h-[48px]"></div>
|
||||
@ -68,7 +68,7 @@ routers.forEach(item => {
|
||||
item.name = findFirstValidRoute(item.children)
|
||||
}
|
||||
oneMenuData.value.push(item)
|
||||
} else if (item.meta.addon != '' && siteInfo?.apps.length <= 1 && siteInfo?.app[0] == item.meta.addon) {
|
||||
} else if (item.meta.addon != '' && siteInfo?.apps.length <= 1 && siteInfo?.apps[0].key == item.meta.addon) {
|
||||
if (item.children) {
|
||||
item.children.forEach((citem: Record<string, any>) => {
|
||||
citem.path = `${item.path}/${citem.path}`
|
||||
@ -92,7 +92,7 @@ if (siteInfo?.apps.length > 1) {
|
||||
routers.push({
|
||||
path: addonRouters[item.key] ? addonRouters[item.key].path : '',
|
||||
meta: {
|
||||
icon: img(item.icon),
|
||||
icon: addonRouters[item.key]?.meta.icon || 'element-Setting',
|
||||
addon: item.key,
|
||||
title: item.title,
|
||||
app: item.app,
|
||||
@ -116,7 +116,7 @@ watch(route, () => {
|
||||
if (route.meta.addon == '') {
|
||||
oneMenuActive.value = route.matched[1].path
|
||||
twoMenuData.value = route.matched[1].children ?? []
|
||||
} else if (route.meta.addon && route.meta.addon != siteInfo?.app[0]) {
|
||||
} else if (route.meta.addon && route.meta.addon != siteInfo?.apps[0].key) {
|
||||
oneMenuActive.value = '/site/app'
|
||||
twoMenuData.value = route.matched[1].children ?? []
|
||||
} else {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, markRaw, defineAsyncComponent } from 'vue'
|
||||
import { ref, markRaw, defineAsyncComponent, provide } from 'vue'
|
||||
import { getAppType } from '@/utils/common'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
@ -31,6 +31,17 @@ Object.keys(modules).forEach(key => {
|
||||
})
|
||||
|
||||
!layout.value && (layout.value = markRaw(defineAsyncComponent(modules['./default/index.vue'])))
|
||||
|
||||
/**
|
||||
* 监听某些页面需要独立配置布局
|
||||
*/
|
||||
provide('setLayout', (name: any) => {
|
||||
if (siteLayout == name) return
|
||||
siteLayout = name
|
||||
Object.keys(modules).forEach(key => {
|
||||
key.indexOf(name) !== -1 && (layout.value = markRaw(defineAsyncComponent(modules[key])))
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { createRouter, createWebHistory, RouteLocationRaw, RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
import { STATIC_ROUTES, NO_LOGIN_ROUTES, ROOT_ROUTER, ADMIN_ROUTE, HOME_ROUTE, SITE_ROUTE, DECORATE_ROUTER, findFirstValidRoute } from './routers'
|
||||
import { STATIC_ROUTES, NO_LOGIN_ROUTES, ROOT_ROUTER, ADMIN_ROUTE, HOME_ROUTE, SITE_ROUTE, findFirstValidRoute } from './routers'
|
||||
import { language } from '@/lang'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
@ -48,12 +48,17 @@ router.beforeEach(async (to, from, next) => {
|
||||
|
||||
const userStore = useUserStore()
|
||||
const siteInfo = userStore.siteInfo
|
||||
const appType = getAppType()
|
||||
|
||||
if (!siteInfo && getAppType() != 'home') {
|
||||
let title: string = to.meta.title ?? ''
|
||||
|
||||
if (!siteInfo && appType != 'home') {
|
||||
await userStore.getSiteInfo()
|
||||
}
|
||||
|
||||
let title = (to.meta.title ? (to.meta.title + ' - ') : '') + (siteInfo ? siteInfo.site_name : '')
|
||||
if (siteInfo) {
|
||||
title += '-' + siteInfo.site_name
|
||||
}
|
||||
|
||||
// 设置网站标题
|
||||
setWindowTitle(title)
|
||||
@ -66,7 +71,7 @@ router.beforeEach(async (to, from, next) => {
|
||||
if (matched && matched.length && matched[0].path != '/:pathMatch(.*)*') {
|
||||
matched = matched[0].path;
|
||||
} else {
|
||||
matched = getAppType();
|
||||
matched = appType
|
||||
}
|
||||
|
||||
const loginPath = to.path == '/' ? '/admin/login' : `${matched}/login`
|
||||
@ -112,13 +117,6 @@ router.beforeEach(async (to, from, next) => {
|
||||
|
||||
// 添加动态路由
|
||||
userStore.routers.forEach(route => {
|
||||
// 页面装修
|
||||
if (route.path == DECORATE_ROUTER.path) {
|
||||
DECORATE_ROUTER.children = route.children
|
||||
router.addRoute(DECORATE_ROUTER)
|
||||
return
|
||||
}
|
||||
|
||||
if (!route.children) {
|
||||
if (route.meta.app == 'admin') {
|
||||
router.addRoute(ADMIN_ROUTE.children[0].name, route)
|
||||
|
||||
@ -135,7 +135,6 @@ export const SITE_ROUTE: RouteRecordRaw = {
|
||||
]
|
||||
}
|
||||
|
||||
// 装修路由
|
||||
export const DECORATE_ROUTER: RouteRecordRaw = {
|
||||
path: '/decorate',
|
||||
component: Decorate,
|
||||
|
||||
@ -182,9 +182,15 @@ const useDiyStore = defineStore('diy', {
|
||||
delete component.type;
|
||||
delete component.icon;
|
||||
|
||||
// 继承全局属性
|
||||
let template = cloneDeep(this.global.template);
|
||||
Object.assign(component, template);
|
||||
if(component.template){
|
||||
// 按照组件初始的属性加载
|
||||
Object.assign(component, component.template);
|
||||
delete component.template;
|
||||
}else{
|
||||
// 默认继承全局属性
|
||||
let template = cloneDeep(this.global.template);
|
||||
Object.assign(component, template);
|
||||
}
|
||||
|
||||
if (!this.checkComponentIsAdd(component)) return;
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { getToken, setToken, removeToken, getAppType } from '@/utils/common'
|
||||
import { login, getAuthMenus, getSiteInfo } from '@/app/api/auth'
|
||||
import { login, logout, getAuthMenus, getSiteInfo } from '@/app/api/auth'
|
||||
import storage from '@/utils/storage'
|
||||
import router from '@/router'
|
||||
import { formatRouters, findFirstValidRoute } from '@/router/routers'
|
||||
@ -58,12 +58,14 @@ const useSystemStore = defineStore('user', {
|
||||
})
|
||||
},
|
||||
logout() {
|
||||
if (!this.token) return
|
||||
this.token = ''
|
||||
this.userInfo = {}
|
||||
this.siteInfo = {}
|
||||
removeToken()
|
||||
storage.remove(['userinfo', 'siteId', 'siteInfo'])
|
||||
this.routers = []
|
||||
logout()
|
||||
// 清除tabbar
|
||||
useTabbarStore().clearTab()
|
||||
const login = getAppType() == 'admin' ? '/admin/login' : '/site/login'
|
||||
|
||||
@ -172,7 +172,7 @@ select:-webkit-autofill {
|
||||
// 温馨提示样式
|
||||
.warm-prompt {
|
||||
background-color: var(--el-color-primary-light-9) !important;
|
||||
.el-icon, p {
|
||||
.el-icon,p,li{
|
||||
color: var(--el-color-primary-light-3);
|
||||
}
|
||||
.el-alert__content{
|
||||
@ -185,7 +185,7 @@ html.dark {
|
||||
.el-icon, p {
|
||||
color: var(--el-color-primary-dark-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.app-item {
|
||||
background: #f7f7f7;
|
||||
@ -193,7 +193,7 @@ html.dark {
|
||||
html.dark {
|
||||
.app-item {
|
||||
background: #191a23;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 详情的头部
|
||||
@ -245,15 +245,15 @@ html.dark {
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
// 滚动条
|
||||
.el-scrollbar__bar.is-vertical{
|
||||
width: 10px !important;
|
||||
}
|
||||
.el-scrollbar__bar.is-vertical .el-scrollbar__thumb{
|
||||
background-color: #8b8b8b !important;
|
||||
opacity: 1 !important;
|
||||
width: 9px !important;
|
||||
}
|
||||
.el-scrollbar__bar.is-vertical .el-scrollbar__thumb:hover{
|
||||
background-color: #636363 !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
//.el-scrollbar__bar.is-vertical{
|
||||
// width: 10px !important;
|
||||
//}
|
||||
//.el-scrollbar__bar.is-vertical .el-scrollbar__thumb{
|
||||
// background-color: #8b8b8b !important;
|
||||
// opacity: 1 !important;
|
||||
// width: 9px !important;
|
||||
//}
|
||||
//.el-scrollbar__bar.is-vertical .el-scrollbar__thumb:hover{
|
||||
// background-color: #636363 !important;
|
||||
// opacity: 1 !important;
|
||||
//}
|
||||
|
||||
@ -28,7 +28,7 @@ class Request {
|
||||
baseURL: import.meta.env.VITE_APP_BASE_URL.substr(-1) == '/' ? import.meta.env.VITE_APP_BASE_URL : `${import.meta.env.VITE_APP_BASE_URL}/`,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded;',
|
||||
'Content-Type': 'application/json',
|
||||
'lang': storage.get('lang') ?? 'zh-cn'
|
||||
}
|
||||
});
|
||||
@ -176,9 +176,6 @@ class Request {
|
||||
case 401:
|
||||
useUserStore().logout()
|
||||
break;
|
||||
case 400:
|
||||
useUserStore().logout()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ class ExceptionHandle extends Handle
|
||||
return fail($e->getMessage());
|
||||
} else if($e instanceof UnexpectedValueException){
|
||||
return fail($e->getMessage(), [], 401);
|
||||
}else if($e instanceof AuthException || $e instanceof AdminException){
|
||||
}else if($e instanceof AuthException){
|
||||
return fail($e->getMessage(), [], $e->getCode() ?: 400);
|
||||
}else if($e instanceof ServerException){
|
||||
return fail($e->getMessage(), http_code:$e->getCode());
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
namespace app\adminapi\controller\diy;
|
||||
|
||||
use app\dict\diy\PagesDict;
|
||||
use app\service\admin\diy\DiyService;
|
||||
use core\base\BaseAdminController;
|
||||
use Exception;
|
||||
@ -34,9 +35,10 @@ class Diy extends BaseAdminController
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
["type", ""],
|
||||
['mode', '']
|
||||
[ "title", "" ],
|
||||
[ "type", "" ],
|
||||
[ 'mode', '' ],
|
||||
[ 'addon_name', '' ]
|
||||
]);
|
||||
return success((new DiyService())->getPage($data));
|
||||
}
|
||||
@ -51,9 +53,9 @@ class Diy extends BaseAdminController
|
||||
public function getList()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
["type", ""],
|
||||
['mode', '']
|
||||
[ "title", "" ],
|
||||
[ "type", "" ],
|
||||
[ 'mode', '' ]
|
||||
]);
|
||||
return success((new DiyService())->getList($data));
|
||||
}
|
||||
@ -75,19 +77,19 @@ class Diy extends BaseAdminController
|
||||
public function add()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
["name", ""],
|
||||
["type", ""],
|
||||
['template', ''],
|
||||
['mode', 'diy'], // 页面展示模式,diy:自定义,fixed:固定
|
||||
["value", ""],
|
||||
['is_default', 0],
|
||||
['is_change', '']
|
||||
[ "title", "" ],
|
||||
[ "name", "" ],
|
||||
[ "type", "" ],
|
||||
[ 'template', '' ],
|
||||
[ 'mode', 'diy' ], // 页面展示模式,diy:自定义,fixed:固定
|
||||
[ "value", "" ],
|
||||
[ 'is_default', 0 ],
|
||||
[ 'is_change', '' ]
|
||||
]);
|
||||
|
||||
$this->validate($data, 'app\validate\diy\Diy.add');
|
||||
$id = (new DiyService())->add($data);
|
||||
return success('ADD_SUCCESS', ['id' => $id]);
|
||||
return success('ADD_SUCCESS', [ 'id' => $id ]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,10 +100,10 @@ class Diy extends BaseAdminController
|
||||
public function edit($id)
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
["name", ""],
|
||||
["value", ""],
|
||||
['is_change', '']
|
||||
[ "title", "" ],
|
||||
[ "name", "" ],
|
||||
[ "value", "" ],
|
||||
[ 'is_change', '' ]
|
||||
]);
|
||||
$this->validate($data, 'app\validate\diy\Diy.edit');
|
||||
(new DiyService())->edit($id, $data);
|
||||
@ -138,11 +140,10 @@ class Diy extends BaseAdminController
|
||||
public function getPageInit()
|
||||
{
|
||||
$params = $this->request->params([
|
||||
['id', ""],
|
||||
["name", ""],
|
||||
["type", ""],
|
||||
['template', ''],
|
||||
["title", ""],
|
||||
[ 'id', "" ],
|
||||
[ "name", "" ],
|
||||
[ "type", "" ],
|
||||
[ "title", "" ],
|
||||
]);
|
||||
|
||||
$diy_service = new DiyService();
|
||||
@ -165,9 +166,9 @@ class Diy extends BaseAdminController
|
||||
public function getTemplate()
|
||||
{
|
||||
$params = $this->request->params([
|
||||
['type', ""], // 页面类型模板
|
||||
['action', ''], // 页面是否装修标识,为空标识不装修,decorate:装修
|
||||
['mode', ''] // 页面展示模式,diy:自定义,fixed:固定
|
||||
[ 'type', '' ], // 页面类型模板
|
||||
[ 'action', '' ], // 页面是否装修标识,为空标识不装修,decorate:装修
|
||||
[ 'mode', '' ] // 页面展示模式,diy:自定义,fixed:固定
|
||||
]);
|
||||
$diy_service = new DiyService();
|
||||
return success($diy_service->getTemplate($params));
|
||||
@ -181,7 +182,7 @@ class Diy extends BaseAdminController
|
||||
public function modifyShare(int $id)
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["share", ""],
|
||||
[ "share", "" ],
|
||||
]);
|
||||
(new DiyService())->modifyShare($id, $data);
|
||||
return success('MODIFY_SUCCESS');
|
||||
@ -192,7 +193,10 @@ class Diy extends BaseAdminController
|
||||
*/
|
||||
public function getDecoratePage()
|
||||
{
|
||||
return success((new DiyService())->getDecoratePage());
|
||||
$params = $this->request->params([
|
||||
[ 'type', '' ],
|
||||
]);
|
||||
return success((new DiyService())->getDecoratePage($params));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -201,28 +205,37 @@ class Diy extends BaseAdminController
|
||||
public function changeTemplate()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
[ "id", "" ],
|
||||
[ 'type', '' ], // 页面类型
|
||||
[ 'name', '' ], // 页面名称标识
|
||||
[ 'mode', '' ], // 页面展示模式,diy:自定义,fixed:固定,other:其他页面
|
||||
[ 'template', '' ], // 模板名称
|
||||
[ 'page', '' ], // 页面路由
|
||||
[ 'title', '' ], // 页面标题
|
||||
[ 'name', '' ], // 链接名称标识
|
||||
[ 'parent', '' ], // 链接父级名称标识
|
||||
[ 'page', '' ], // 链接路由
|
||||
[ 'title', '' ], // 链接标题
|
||||
[ 'action', '' ] // 是否存在操作,decorate 表示支持装修
|
||||
]);
|
||||
return success(( new DiyService() )->changeTemplate($data));
|
||||
(new DiyService())->changeTemplate($data);
|
||||
return success('MODIFY_SUCCESS');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面预览数据
|
||||
* 获取模板页面列表
|
||||
* @return Response
|
||||
*/
|
||||
public function getPreviewData()
|
||||
public function getTemplatePages()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["id", ""],
|
||||
['name', '']
|
||||
$params = $this->request->params([
|
||||
[ 'type', '' ],
|
||||
[ 'mode', '' ]
|
||||
]);
|
||||
$res = (new DiyService())->getPreviewData($data);
|
||||
return success($res);
|
||||
$pages = PagesDict::getPages($params);
|
||||
return success($pages);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板页面的应用插件列表
|
||||
* @return Response
|
||||
*/
|
||||
public function getApps()
|
||||
{
|
||||
return success((new DiyService())->getApps());
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,8 @@ class DiyRoute extends BaseAdminController
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
[ 'title', '' ],
|
||||
[ 'addon_name', '' ]
|
||||
]);
|
||||
return success((new DiyRouteService())->getList($data));
|
||||
}
|
||||
@ -62,15 +63,15 @@ class DiyRoute extends BaseAdminController
|
||||
public function add()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
["name", ""],
|
||||
["page", ""],
|
||||
["share", ""],
|
||||
["is_share", ""]
|
||||
[ "title", "" ],
|
||||
[ "name", "" ],
|
||||
[ "page", "" ],
|
||||
[ "share", "" ],
|
||||
[ "is_share", "" ]
|
||||
]);
|
||||
$this->validate($data, 'app\validate\diy\DiyRoute.add');
|
||||
$id = (new DiyRouteService())->add($data);
|
||||
return success('ADD_SUCCESS', ['id' => $id]);
|
||||
return success('ADD_SUCCESS', [ 'id' => $id ]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,11 +82,11 @@ class DiyRoute extends BaseAdminController
|
||||
public function edit($id)
|
||||
{
|
||||
$data = $this->request->params([
|
||||
["title", ""],
|
||||
["name", ""],
|
||||
["page", ""],
|
||||
["share", ""],
|
||||
["is_share", ""]
|
||||
[ "title", "" ],
|
||||
[ "name", "" ],
|
||||
[ "page", "" ],
|
||||
[ "share", "" ],
|
||||
[ "is_share", "" ]
|
||||
]);
|
||||
$this->validate($data, 'app\validate\diy\DiyRoute.edit');
|
||||
(new DiyRouteService())->edit($id, $data);
|
||||
@ -109,12 +110,12 @@ class DiyRoute extends BaseAdminController
|
||||
public function modifyShare()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
['share', ''],
|
||||
['title', ''],
|
||||
['name', ''],
|
||||
['page', ''],
|
||||
['is_share', 0],
|
||||
['sort', 0]
|
||||
[ 'share', '' ],
|
||||
[ 'title', '' ],
|
||||
[ 'name', '' ],
|
||||
[ 'page', '' ],
|
||||
[ 'is_share', 0 ],
|
||||
[ 'sort', 0 ]
|
||||
]);
|
||||
(new DiyRouteService())->modifyShare($data);
|
||||
return success('MODIFY_SUCCESS');
|
||||
|
||||
@ -11,12 +11,15 @@
|
||||
|
||||
namespace app\adminapi\controller\login;
|
||||
|
||||
use addon\vipcard\app\service\core\CoreOrderRefundService;
|
||||
use app\service\admin\auth\ConfigService;
|
||||
use app\service\admin\auth\LoginService;
|
||||
use app\service\admin\upgrade\UpgradeService;
|
||||
use app\service\core\addon\CoreAddonDevelopBuildService;
|
||||
use app\service\core\menu\CoreMenuService;
|
||||
use app\service\core\upload\CoreFileService;
|
||||
use core\base\BaseAdminController;
|
||||
use think\facade\Db;
|
||||
use think\Response;
|
||||
|
||||
class Login extends BaseAdminController
|
||||
@ -64,7 +67,9 @@ class Login extends BaseAdminController
|
||||
}
|
||||
|
||||
public function test(){
|
||||
(new CoreMenuService())->refreshAddonMenu('shop');
|
||||
// (new CoreMenuService())->refreshAddonMenu('shop');
|
||||
// (new CoreAddonDevelopBuildService())->build('shop');
|
||||
// (new CoreFileService())->driver(0);
|
||||
dd((new CoreOrderRefundService())->refundSuccess('20240118393625662873600'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ class Site extends BaseAdminController
|
||||
['create_time', []],
|
||||
['expire_time', []],
|
||||
['app', ''],
|
||||
// ['']
|
||||
]);
|
||||
return success((new SiteService())->getPage($data));
|
||||
}
|
||||
|
||||
@ -56,6 +56,9 @@ Route::group('diy', function() {
|
||||
// 获取页面模板
|
||||
Route::get('template', 'diy.Diy/getTemplate');
|
||||
|
||||
// 获取模板页面列表
|
||||
Route::get('template/pages', 'diy.Diy/getTemplatePages');
|
||||
|
||||
// 自定义路由列表
|
||||
Route::get('route', 'diy.DiyRoute/lists');
|
||||
|
||||
@ -68,6 +71,9 @@ Route::group('diy', function() {
|
||||
// 编辑自定义页面分享内容
|
||||
Route::put('diy/share', 'diy.Diy/modifyShare');
|
||||
|
||||
// 获取模板页面的应用插件列表
|
||||
Route::get('apps', 'diy.Diy/getApps');
|
||||
|
||||
/***************************************************** 配置相关 *****************************************************/
|
||||
|
||||
// 底部导航查询
|
||||
|
||||
@ -218,4 +218,6 @@ Route::group('sys', function () {
|
||||
//系统环境(不效验登录状态)
|
||||
Route::group('sys', function () {
|
||||
Route::get('web/website', 'sys.Config/getWebsite');
|
||||
// 获取版权信息
|
||||
Route::get('web/copyright', 'sys.Config/getCopyright');
|
||||
});
|
||||
|
||||
@ -34,6 +34,22 @@ class ComponentDict
|
||||
'support_page' => [], // 支持页面
|
||||
'uses' => 0, // 最大添加数量
|
||||
'sort' => 10001,
|
||||
// 组件属性
|
||||
'template' => [
|
||||
"textColor" => "#303133", // 文字颜色
|
||||
"pageBgColor" => "", // 底部背景颜色
|
||||
"componentBgColor" => '', // 组件背景颜色
|
||||
"topRounded" => 0, // 组件上圆角
|
||||
"bottomRounded" => 0, // 组件下圆角
|
||||
"elementBgColor" => '', // 元素背景颜色
|
||||
"topElementRounded" => 0,// 元素上圆角
|
||||
"bottomElementRounded" => 0, // 元素下圆角
|
||||
"margin" => [
|
||||
"top" => 0, // 上边距
|
||||
"bottom" => 0, // 下边距
|
||||
"both" => 0 // 左右边距
|
||||
],
|
||||
],
|
||||
'value' => [
|
||||
"style" => "style-1",
|
||||
"styleName" => "风格1",
|
||||
@ -60,15 +76,15 @@ class ComponentDict
|
||||
"name" => ""
|
||||
],
|
||||
"color" => "#999999"
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
'ImageAds' => [
|
||||
'title' => '图片广告',
|
||||
'icon' => 'iconfont-icontupianguanggao1',
|
||||
'path' => 'edit-image-ads', // 编辑组件属性
|
||||
'support_page' => [], // 支持页面
|
||||
'uses' => 0, // 最大添加数量
|
||||
'path' => 'edit-image-ads',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10002,
|
||||
'value' => [
|
||||
"imageHeight" => 180,
|
||||
@ -279,7 +295,7 @@ class ComponentDict
|
||||
],
|
||||
],
|
||||
];
|
||||
return ( new DictLoader("UniappComponent") )->load($system_components);
|
||||
return (new DictLoader("UniappComponent"))->load($system_components);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ use core\dict\DictLoader;
|
||||
|
||||
/**
|
||||
* 页面数据
|
||||
* Class TemplateDict
|
||||
* Class PagesDict
|
||||
* @package app\dict\diy
|
||||
*/
|
||||
class PagesDict
|
||||
|
||||
@ -41,29 +41,45 @@ class TemplateDict
|
||||
]
|
||||
];
|
||||
|
||||
$pages = ( new DictLoader("UniappTemplate") )->load($system_pages);
|
||||
if (!empty($params[ 'type' ])) {
|
||||
$temp = [];
|
||||
foreach ($params[ 'type' ] as $k => $v) {
|
||||
if (!empty($pages[ $v ])) {
|
||||
$temp[ $v ] = $pages[ $v ];
|
||||
// 查询存在模板页面的应用插件列表
|
||||
if (!empty($params[ 'query' ]) && $params[ 'query' ] == 'addon') {
|
||||
$system = [
|
||||
'app' => [
|
||||
'title' => '系统',
|
||||
'key' => 'app',
|
||||
'list' => $system_pages
|
||||
]
|
||||
];
|
||||
$addon = (new DictLoader("UniappTemplate"))->load($params);
|
||||
$app = array_merge($system, $addon);
|
||||
return $app;
|
||||
} else {
|
||||
// 查询应用插件下的模板页面数据
|
||||
$pages = (new DictLoader("UniappTemplate"))->load($system_pages);
|
||||
if (!empty($params[ 'type' ])) {
|
||||
$temp = [];
|
||||
foreach ($params[ 'type' ] as $k => $v) {
|
||||
if (!empty($pages[ $v ])) {
|
||||
$temp[ $v ] = $pages[ $v ];
|
||||
}
|
||||
}
|
||||
return $temp;
|
||||
}
|
||||
return $temp;
|
||||
}
|
||||
|
||||
if (!empty($params[ 'action' ])) {
|
||||
$temp = [];
|
||||
foreach ($pages as $k => $v) {
|
||||
if (isset($v[ 'action' ]) && $params[ 'action' ] == $v[ 'action' ]) {
|
||||
$temp[ $k ] = $v;
|
||||
if (!empty($params[ 'action' ])) {
|
||||
$temp = [];
|
||||
foreach ($pages as $k => $v) {
|
||||
if (isset($v[ 'action' ]) && $params[ 'action' ] == $v[ 'action' ]) {
|
||||
$temp[ $k ] = $v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $temp;
|
||||
}
|
||||
return $temp;
|
||||
}
|
||||
|
||||
return $pages;
|
||||
return $pages;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ return
|
||||
'router_path' => 'user',
|
||||
'view_path' => 'site/user',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'sort' => 90,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
@ -157,7 +157,7 @@ return
|
||||
'router_path' => 'user_info',
|
||||
'view_path' => 'site/user_info',
|
||||
'methods' => 'get',
|
||||
'sort' => 99,
|
||||
'sort' => 80,
|
||||
'status' => 1,
|
||||
'is_show' => 0,
|
||||
],
|
||||
@ -188,7 +188,7 @@ return
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '站点套餐',
|
||||
'menu_name' => '站点套餐编辑',
|
||||
'menu_key' => 'site_group_edit',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'element-PriceTag',
|
||||
@ -564,153 +564,138 @@ return
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '系统菜单',
|
||||
'menu_key' => 'system_setting',
|
||||
'menu_type' => 0,
|
||||
'icon' => 'element-Setting',
|
||||
'api_url' => '',
|
||||
'router_path' => 'setting',
|
||||
'view_path' => '',
|
||||
'methods' => '',
|
||||
'menu_name' => '平台菜单',
|
||||
'menu_key' => 'platform_menu',
|
||||
'menu_type' => 1,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => 'admin_menu',
|
||||
'view_path' => 'auth/menu',
|
||||
'methods' => 'get',
|
||||
'sort' => 49,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '平台菜单',
|
||||
'menu_key' => 'platform_menu',
|
||||
'menu_type' => 1,
|
||||
'menu_name' => '新增',
|
||||
'menu_key' => 'auth_menu_add',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => 'admin',
|
||||
'view_path' => 'auth/menu',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'post',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '新增',
|
||||
'menu_key' => 'auth_menu_add',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'post',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '编辑',
|
||||
'menu_key' => 'auth_menu_update',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'put',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '删除',
|
||||
'menu_key' => 'auth_menu_del',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'delete',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '详情',
|
||||
'menu_key' => 'auth_menu_info',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'get',
|
||||
'sort' => 0,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'menu_name' => '站点菜单',
|
||||
'menu_key' => 'site_menu',
|
||||
'menu_type' => 1,
|
||||
'menu_name' => '编辑',
|
||||
'menu_key' => 'auth_menu_update',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => 'site',
|
||||
'view_path' => 'auth/site_menu',
|
||||
'methods' => 'get',
|
||||
'sort' => 90,
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'put',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '新增',
|
||||
'menu_key' => 'auth_site_menu_add',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'post',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '编辑',
|
||||
'menu_key' => 'auth_site_menu_update',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'put',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '删除',
|
||||
'menu_key' => 'auth_site_menu_del',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'delete',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '详情',
|
||||
'menu_key' => 'auth_site_menu_info',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'get',
|
||||
'sort' => 0,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
],
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
'menu_name' => '删除',
|
||||
'menu_key' => 'auth_menu_del',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'delete',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '详情',
|
||||
'menu_key' => 'auth_menu_info',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'get',
|
||||
'sort' => 0,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'menu_name' => '站点菜单',
|
||||
'menu_key' => 'site_menu',
|
||||
'menu_type' => 1,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => 'site_menu',
|
||||
'view_path' => 'auth/site_menu',
|
||||
'methods' => 'get',
|
||||
'sort' => 48,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '新增',
|
||||
'menu_key' => 'auth_site_menu_add',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'post',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '编辑',
|
||||
'menu_key' => 'auth_site_menu_update',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'put',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '删除',
|
||||
'menu_key' => 'auth_site_menu_del',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'delete',
|
||||
'sort' => 1,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '详情',
|
||||
'menu_key' => 'auth_site_menu_info',
|
||||
'menu_type' => 2,
|
||||
'icon' => '',
|
||||
'api_url' => 'sys/menu/<menu_key>',
|
||||
'router_path' => '',
|
||||
'view_path' => '',
|
||||
'methods' => 'get',
|
||||
'sort' => 0,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'menu_name' => '计划任务',
|
||||
|
||||
@ -16,8 +16,8 @@ return
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
[
|
||||
'menu_name' => '页面装修',
|
||||
'menu_key' => 'diy_page_decorate',
|
||||
'menu_name' => '启动页',
|
||||
'menu_key' => 'diy_page_decorate_index',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'element-House',
|
||||
'api_url' => '',
|
||||
@ -28,6 +28,19 @@ return
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '个人中心',
|
||||
'menu_key' => 'diy_page_decorate_member_index',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-iconhuiyuanliebiao', // element-House
|
||||
'api_url' => '',
|
||||
'router_path' => 'member',
|
||||
'view_path' => 'diy/member',
|
||||
'methods' => '',
|
||||
'sort' => 99,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '保存',
|
||||
'menu_key' => 'diy_page_update',
|
||||
@ -852,7 +865,19 @@ return
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
|
||||
],
|
||||
[
|
||||
'menu_name' => '版权设置',
|
||||
'menu_key' => 'setting_copyright',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-iconbanquan1',
|
||||
'api_url' => 'sys/config/copyright',
|
||||
'router_path' => 'copyright',
|
||||
'view_path' => 'setting/copyright',
|
||||
'methods' => 'get',
|
||||
'sort' => 90,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
[
|
||||
'menu_name' => '协议管理',
|
||||
@ -1146,7 +1171,20 @@ return
|
||||
'sort' => 99,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
]
|
||||
],
|
||||
[
|
||||
'menu_name' => '存储设置',
|
||||
'menu_key' => 'setting_storage',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'element-FolderChecked',
|
||||
'api_url' => 'sys/storage',
|
||||
'router_path' => 'storage',
|
||||
'view_path' => 'setting/storage',
|
||||
'methods' => 'get',
|
||||
'sort' => 30,
|
||||
'status' => 1,
|
||||
'is_show' => 1
|
||||
],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
|
||||
namespace app\dict\sys;
|
||||
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 协议相关枚举类
|
||||
* Class AgreementDict
|
||||
@ -18,10 +20,6 @@ namespace app\dict\sys;
|
||||
*/
|
||||
class AgreementDict
|
||||
{
|
||||
//服务协议
|
||||
const SERVICE = 'service';
|
||||
//隐私协议
|
||||
const PRIVACY = 'privacy';
|
||||
|
||||
/**
|
||||
* 获取协议类型
|
||||
@ -29,10 +27,18 @@ class AgreementDict
|
||||
*/
|
||||
public static function getType()
|
||||
{
|
||||
return [
|
||||
self::SERVICE => get_lang('dict_agreement.service'),//服务协议,
|
||||
self::PRIVACY => get_lang('dict_agreement.privacy'),//隐私协议
|
||||
$data = [
|
||||
'service' => get_lang('dict_agreement.service'),//服务协议,
|
||||
'privacy' => get_lang('dict_agreement.privacy'),//隐私协议
|
||||
];
|
||||
$addon_data = event("AgreementType");
|
||||
Log::write("检测数据");
|
||||
Log::write($addon_data);
|
||||
foreach ($addon_data as $k => $v)
|
||||
{
|
||||
$data = array_merge($data, $v);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@ -46,6 +46,8 @@ $system_event = [
|
||||
'AppManage' => [
|
||||
'app\listener\system\AppManageListener'
|
||||
],
|
||||
//协议类型加载
|
||||
'AgreementType' => [],
|
||||
//站点首页加载
|
||||
'SiteIndex' => [
|
||||
'app\listener\system\SiteIndexListener'
|
||||
|
||||
@ -675,7 +675,7 @@ CREATE TABLE `sys_menu` (
|
||||
`router_path` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '菜单路由地址 前端使用',
|
||||
`view_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '菜单文件地址',
|
||||
`methods` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '提交方式POST GET PUT DELETE',
|
||||
`sort` tinyint(4) NOT NULL DEFAULT 1 COMMENT '排序',
|
||||
`sort` int NOT NULL DEFAULT 1 COMMENT '排序',
|
||||
`status` tinyint(3) UNSIGNED NOT NULL DEFAULT 1 COMMENT '正常,禁用(禁用后不允许访问)',
|
||||
`is_show` tinyint(4) NOT NULL DEFAULT 1 COMMENT '是否显示',
|
||||
`create_time` int(11) NOT NULL DEFAULT 0,
|
||||
@ -732,8 +732,8 @@ CREATE TABLE `sys_notice_sms_log` (
|
||||
`sms_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '发送关键字(注册、找回密码)',
|
||||
`key` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '发送关键字(注册、找回密码)',
|
||||
`template_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
|
||||
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '发送内容',
|
||||
`params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '数据参数',
|
||||
`content` text NOT NULL COMMENT '发送内容',
|
||||
`params` text NOT NULL COMMENT '数据参数',
|
||||
`status` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'sending' COMMENT '发送状态:sending-发送中;success-发送成功;fail-发送失败',
|
||||
`result` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '短信结果',
|
||||
`create_time` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间',
|
||||
@ -800,7 +800,7 @@ CREATE TABLE `sys_user_log` (
|
||||
`uid` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '管理员id',
|
||||
`username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '管理员姓名',
|
||||
`url` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '链接',
|
||||
`params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '参数',
|
||||
`params` longtext DEFAULT NULL COMMENT '参数',
|
||||
`type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '请求方式',
|
||||
`create_time` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '操作时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
|
||||
@ -52,6 +52,10 @@ return [
|
||||
'UNIAPP_DIR_NOT_EXIST' => '未找到uni-app源码所在目录, <a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3213544" target="blank">点击查看相关手册</a>',
|
||||
'OPEN_BASEDIR_ERROR' => '请关闭防跨站攻击, 具体操作方法<a style="text-decoration: underline;" href="https://www.kancloud.cn/niucloud/niucloud-admin-develop/3213393" target="blank">点击查看相关手册</a>',
|
||||
'ADDON_DOWNLOAD_VERSION_EMPTY' => '该插件还没有发布过版本',
|
||||
'ADDON_IS_NOT_EXIST' => '插件不存在',
|
||||
'ADDON_KEY_IS_EXIST' => '已存在相同插件标识的应用',
|
||||
'ADDON_IS_INSTALLED_NOT_ALLOW_DEL' => '已安装的插件不允许删除',
|
||||
'ADDON_ZIP_ERROR' => '插件压缩失败',
|
||||
//登录注册重置账号....
|
||||
|
||||
'LOGIN_SUCCESS' => '登录成功',
|
||||
@ -241,7 +245,6 @@ return [
|
||||
// 授权相关
|
||||
'AUTH_NOT_EXISTS' => '未获取到授权信息',
|
||||
|
||||
|
||||
/********************************************************* home端专用 **************************************/
|
||||
'USER_ROLE_NOT_HAS_SITE' => '当前登录用户下没有此项站点',
|
||||
|
||||
|
||||
@ -207,7 +207,7 @@ return [
|
||||
'component_type_basic' => '基础组件',
|
||||
|
||||
'system_title' => '系统',
|
||||
'system_link' => '系统页面',
|
||||
'system_link' => '启动页',
|
||||
'system_link_index' => '首页',
|
||||
|
||||
'member_link' => '会员页面',
|
||||
|
||||
@ -41,6 +41,29 @@ class Diy extends BaseModel
|
||||
*/
|
||||
protected $name = 'diy_page';
|
||||
|
||||
/**
|
||||
* 状态字段转化:所属插件名称
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getAddonNameAttr($value, $data)
|
||||
{
|
||||
$addon_name = '';
|
||||
$template = TemplateDict::getTemplate([
|
||||
'query' => 'addon'
|
||||
]);
|
||||
foreach ($template as $k => $v) {
|
||||
foreach ($v[ 'list' ] as $ck => $cv) {
|
||||
if ($ck == $data[ 'type' ]) {
|
||||
$addon_name = $v[ 'title' ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $addon_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态字段转化
|
||||
* @param $value
|
||||
@ -108,6 +131,28 @@ class Diy extends BaseModel
|
||||
return $data[ 'share' ] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索器:自定义页面标识
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchAddonNameAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$list = [];
|
||||
$template = TemplateDict::getTemplate([
|
||||
'query' => 'addon'
|
||||
]);
|
||||
foreach ($template as $k => $v) {
|
||||
if ($k == $value) {
|
||||
$list = array_keys($v[ 'list' ]);
|
||||
}
|
||||
}
|
||||
$query->where("type", 'in', $list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索器:自定义页面
|
||||
* @param $query
|
||||
@ -121,7 +166,6 @@ class Diy extends BaseModel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 搜索器:自定义页面名称
|
||||
* @param $query
|
||||
|
||||
@ -49,12 +49,26 @@ class SiteGroup extends BaseModel
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getGroupRolesDataAttr($value, $data)
|
||||
public function getAppNameAttr($value, $data)
|
||||
{
|
||||
if (empty($data['addon']))
|
||||
if (empty($data['app']))
|
||||
return [];
|
||||
return (new Addon())->where([['key', 'in', $data['addon']]])->select();
|
||||
return (new Addon())->where([['key', 'in', $data['app']]])->column('title');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联插件
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return array
|
||||
*/
|
||||
public function getAddonNameAttr($value, $data)
|
||||
{
|
||||
if (empty($data['app']))
|
||||
return [];
|
||||
return (new Addon())->where([['key', 'in', $data['addon']]])->column('title');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键字搜索
|
||||
* @param $query
|
||||
|
||||
@ -64,7 +64,7 @@ class LoginService extends BaseAdminService
|
||||
|
||||
$user_service = new UserService();
|
||||
$userinfo = $user_service->getUserInfoByUsername($username);
|
||||
if (empty($userinfo)) return false;
|
||||
if ($userinfo->isEmpty()) return false;
|
||||
|
||||
if (!check_password($password, $userinfo->password)) return false;
|
||||
|
||||
|
||||
@ -43,12 +43,16 @@ class DiyRouteService extends BaseAdminService
|
||||
if (!empty($v[ 'child_list' ])) {
|
||||
foreach ($v[ 'child_list' ] as $ck => $cv) {
|
||||
if (!empty($cv[ 'url' ])) {
|
||||
if (empty($where[ 'title' ]) || ( !empty($where[ 'title' ]) && str_contains($cv['title'], $where['title']))) {
|
||||
if (empty($where[ 'title' ]) || (!empty($where[ 'title' ]) && str_contains($cv[ 'title' ], $where[ 'title' ]))) {
|
||||
$diy_route_list[] = [
|
||||
'key' => $v[ 'key' ] ?? '',
|
||||
'addon_title' => $v[ 'addon_title' ] ?? '',
|
||||
'title' => $cv[ 'title' ],
|
||||
'name' => $cv[ 'name' ],
|
||||
'parent' => $k,
|
||||
'page' => $cv[ 'url' ],
|
||||
'is_share' => $cv[ 'is_share' ],
|
||||
'action' => $cv[ 'action' ] ?? '',
|
||||
'sort' => ++$sort
|
||||
];
|
||||
}
|
||||
@ -149,4 +153,4 @@ class DiyRouteService extends BaseAdminService
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ use app\dict\diy\PagesDict;
|
||||
use app\dict\diy\TemplateDict;
|
||||
use app\model\diy\Diy;
|
||||
use app\service\admin\sys\SystemService;
|
||||
use app\service\core\addon\CoreAddonService;
|
||||
use core\base\BaseAdminService;
|
||||
use core\exception\AdminException;
|
||||
use Exception;
|
||||
@ -49,7 +50,7 @@ class DiyService extends BaseAdminService
|
||||
$where[] = [ 'site_id', '=', $this->site_id ];
|
||||
$field = 'id,site_id,title,name,template,type,mode,is_default,share,visit_count,create_time,update_time';
|
||||
$order = "update_time desc";
|
||||
$search_model = $this->model->where([ [ 'site_id', '=', $this->site_id ] ])->withSearch([ "title", "type", 'mode' ], $where)->field($field)->order($order)->append([ 'type_name' ]);
|
||||
$search_model = $this->model->where([ [ 'site_id', '=', $this->site_id ] ])->withSearch([ "title", "type", 'mode', 'addon_name' ], $where)->field($field)->order($order)->append([ 'type_name', 'type_page', 'addon_name' ]);
|
||||
return $this->pageQuery($search_model);
|
||||
}
|
||||
|
||||
@ -161,7 +162,7 @@ class DiyService extends BaseAdminService
|
||||
$this->model->where([ [ 'id', '=', $id ], [ 'site_id', '=', $this->site_id ] ])->update([ 'is_default' => 1, 'update_time' => time() ]);
|
||||
Db::commit();
|
||||
return true;
|
||||
} catch ( Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
Db::rollback();
|
||||
throw new AdminException($e->getMessage());
|
||||
}
|
||||
@ -185,8 +186,35 @@ class DiyService extends BaseAdminService
|
||||
$data = $this->getInfoByName($params[ 'name' ]);
|
||||
}
|
||||
|
||||
if (!empty($params[ 'name' ])) {
|
||||
|
||||
// 查询启动页配置
|
||||
$diy_config_service = new DiyConfigService();
|
||||
$start_up_page = $diy_config_service->getStartUpPageConfig($params[ 'name' ]);
|
||||
if (!empty($start_up_page)) {
|
||||
if ($start_up_page[ 'parent' ] == 'DIY_PAGE') {
|
||||
$id = str_replace('/app/pages/index/diy?id=', '', $start_up_page[ 'page' ]);
|
||||
$data = $this->getInfo($id);
|
||||
if (!empty($data)) {
|
||||
$params[ 'name' ] = $data[ 'name' ];
|
||||
$params[ 'type' ] = $data[ 'type' ];
|
||||
}
|
||||
} else {
|
||||
foreach ($template as $k => $v) {
|
||||
if ($start_up_page[ 'page' ] == $v[ 'page' ]) {
|
||||
$data = $this->getInfoByName($k);
|
||||
$params[ 'name' ] = $k;
|
||||
$params[ 'type' ] = $k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($data)) {
|
||||
// 编辑赋值
|
||||
|
||||
if (isset($template[ $data[ 'type' ] ])) {
|
||||
$page = $template[ $data[ 'type' ] ];
|
||||
$data[ 'type_name' ] = $page[ 'title' ];
|
||||
@ -195,11 +223,11 @@ class DiyService extends BaseAdminService
|
||||
} else {
|
||||
|
||||
// 新页面赋值
|
||||
$title = $params[ 'title' ] ?: '页面' . $time;
|
||||
$type = $params[ 'type' ] ?: 'DIY_PAGE';
|
||||
$title = $params[ 'title' ] ? : '页面' . $time;
|
||||
$type = $params[ 'type' ] ? : 'DIY_PAGE';
|
||||
$name = $type == 'DIY_PAGE' ? 'DIY_PAGE_RANDOM_' . $time : $type;
|
||||
$type_name = '';
|
||||
$template_name = $params[ 'template' ] ?? ''; // 页面模板名称
|
||||
$template_name = ''; // 页面模板名称
|
||||
$page_route = ''; // 页面路径
|
||||
$mode = 'diy'; // 页面模式,diy:自定义,fixed:固定
|
||||
$value = '';
|
||||
@ -233,14 +261,6 @@ class DiyService extends BaseAdminService
|
||||
$is_default = 1;
|
||||
}
|
||||
|
||||
if (!empty($params[ 'template' ])) {
|
||||
$page_template = $page[ 'template' ][ $params[ 'template' ] ];
|
||||
$mode = $page_template[ 'mode' ];
|
||||
$page_data = $page_template[ 'data' ];
|
||||
$page_data[ 'global' ][ 'title' ] = $title;
|
||||
$value = json_encode($page_data, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$data = [
|
||||
@ -256,8 +276,12 @@ class DiyService extends BaseAdminService
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
$data[ 'component' ] = $this->getComponentList($data[ 'type' ]);
|
||||
$data[ 'domain_url' ] = ( new SystemService() )->getUrl();
|
||||
$data[ 'domain_url' ] = (new SystemService())->getUrl();
|
||||
|
||||
// 查询已安装的有效的应用
|
||||
$data[ 'addon_list' ] = (new CoreAddonService())->getInstallAddonList();
|
||||
return $data;
|
||||
}
|
||||
|
||||
@ -274,13 +298,13 @@ class DiyService extends BaseAdminService
|
||||
$sort_arr = [];
|
||||
foreach ($v[ 'list' ] as $ck => $cv) {
|
||||
$support_page = $cv[ 'support_page' ];
|
||||
if (!( count($support_page) == 0 || in_array($name, $support_page) )) {
|
||||
if (!(count($support_page) == 0 || in_array($name, $support_page))) {
|
||||
unset($data[ $k ][ 'list' ][ $ck ]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$sort_arr [] = $cv[ 'sort' ];
|
||||
unset($data[$k]['list'][$ck]['sort'], $data[$k]['list'][$ck]['support_page']);
|
||||
unset($data[ $k ][ 'list' ][ $ck ][ 'sort' ], $data[ $k ][ 'list' ][ $ck ][ 'support_page' ]);
|
||||
}
|
||||
array_multisort($sort_arr, SORT_ASC, $data[ $k ][ 'list' ]); //排序,根据 sort 排序
|
||||
}
|
||||
@ -314,7 +338,7 @@ class DiyService extends BaseAdminService
|
||||
$link[ $k ][ 'child_list' ][] = [
|
||||
'name' => $cv[ 'name' ],
|
||||
'title' => $cv[ 'title' ],
|
||||
'url' => '/pages/index/diy?id=' . $cv[ 'id' ]
|
||||
'url' => '/app/pages/index/diy?id=' . $cv[ 'id' ]
|
||||
];
|
||||
}
|
||||
|
||||
@ -368,7 +392,7 @@ class DiyService extends BaseAdminService
|
||||
public function getPageData($type, $name)
|
||||
{
|
||||
$pages = PagesDict::getPages([ 'type' => $type ]);
|
||||
return $pages[$name] ?? [];
|
||||
return $pages[ $name ] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -391,269 +415,117 @@ class DiyService extends BaseAdminService
|
||||
|
||||
/**
|
||||
* 获取页面装修列表
|
||||
* @param $params
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public function getDecoratePage()
|
||||
public function getDecoratePage($params)
|
||||
{
|
||||
|
||||
// 查询可装修的页面
|
||||
$template = $this->getTemplate([ 'action' => 'decorate', 'type' => [ 'DIY_INDEX', 'DIY_MEMBER_INDEX' ] ]);
|
||||
$specific_page = array_column($template, 'page');
|
||||
// 查询当前装修的页面信息
|
||||
$template = $this->getTemplate([ 'action' => 'decorate', 'type' => [ $params[ 'type' ] ] ])[ $params[ 'type' ] ];
|
||||
|
||||
// 查询其他页面,排除特定页面
|
||||
$other_page = ( new DiyRouteService() )->getList();
|
||||
foreach ($other_page as $ck => $cv) {
|
||||
if (in_array(substr($cv[ 'page' ], 1), $specific_page) || $cv[ 'is_share' ] == 0) {
|
||||
unset($other_page[ $ck ]);
|
||||
}
|
||||
}
|
||||
$other_page = array_values($other_page);
|
||||
$template[ 'domain_url' ] = (new SystemService())->getUrl();
|
||||
|
||||
// 查询默认页面数据
|
||||
$default_page_data = $this->getFirstPageData($params[ 'type' ]);
|
||||
|
||||
// 查询其他页面,排除特定页面(不能分享的页面)
|
||||
$other_page = (new DiyRouteService())->getList();
|
||||
|
||||
$use_template = [
|
||||
'type' => $params[ 'type' ], // 页面类型标识
|
||||
'name' => '', // 链接标识
|
||||
'parent' => '', // 链接标识
|
||||
'title' => $default_page_data[ 'title' ], // 模板名称
|
||||
'cover' => $default_page_data[ 'cover' ], // 封面图
|
||||
'url' => '', // 自定义页面链接,实时预览效果
|
||||
'page' => $template[ 'page' ], // 页面地址
|
||||
'action' => $template[ 'action' ] // 是否存在操作,decorate 表示支持装修
|
||||
];
|
||||
|
||||
// 查询启动页配置
|
||||
$diy_config_service = new DiyConfigService();
|
||||
$start_up_page = $diy_config_service->getStartUpPageConfig($params[ 'type' ]);
|
||||
|
||||
// 遍历查询页面数据,使用了那套模板
|
||||
foreach ($template as $k => $v) {
|
||||
// 查询页面数据
|
||||
$info = $this->getInfoByName($params[ 'type' ]);
|
||||
|
||||
$template[ $k ][ 'domain_url' ] = ( new SystemService() )->getUrl();
|
||||
if (!empty($start_up_page)) {
|
||||
$use_template[ 'title' ] = $start_up_page[ 'title' ] ?? '';
|
||||
$use_template[ 'name' ] = $start_up_page[ 'name' ] ?? '';
|
||||
$use_template[ 'page' ] = $start_up_page[ 'page' ] ?? '';
|
||||
$use_template[ 'action' ] = $start_up_page[ 'action' ] ?? '';
|
||||
$use_template[ 'url' ] = $use_template[ 'page' ];
|
||||
$use_template[ 'parent' ] = $start_up_page[ 'parent' ] ?? '';
|
||||
} elseif (!empty($info)) {
|
||||
$use_template[ 'id' ] = $info[ 'id' ];
|
||||
$use_template[ 'title' ] = $info[ 'title' ];
|
||||
|
||||
// 查询我的微页面
|
||||
$template[ $k ][ 'my_page' ] = $this->getList([ 'type' => $k ], 'id,title,name,template,type,is_default,mode');
|
||||
|
||||
// 查询其他页面,排除特定页面
|
||||
$template[ $k ][ 'other_page' ] = $other_page;
|
||||
|
||||
// 查询默认页面数据
|
||||
$default_page_data = $this->getFirstPageData($k);
|
||||
$use_template = [
|
||||
'id' => 0,
|
||||
'name' => $k,
|
||||
'title' => $default_page_data[ 'title' ], // 模板名称
|
||||
'template' => $default_page_data[ 'template' ], // 模板标识
|
||||
'cover' => $default_page_data[ 'cover' ], // 封面图
|
||||
'preview' => $default_page_data[ 'preview' ], // 预览图
|
||||
'desc' => $default_page_data[ 'desc' ], // 模板描述
|
||||
'mode' => $default_page_data[ 'mode' ], // 页面模式:diy:自定义,fixed:固定
|
||||
'hope' => 'template', // 默认选中 模板
|
||||
'url' => '', // 自定义页面链接,实时预览效果
|
||||
'page' => $v[ 'page' ], // 页面地址
|
||||
'action' => '' // 是否存在操作,decorate 表示支持装修
|
||||
];
|
||||
|
||||
// 查询启动页配置
|
||||
$start_up_page = $diy_config_service->getStartUpPageConfig($k);
|
||||
if (!empty($start_up_page)) {
|
||||
$use_template[ 'name' ] = $k;
|
||||
if ($start_up_page[ 'mode' ] == 'other') {
|
||||
if (empty($start_up_page[ 'name' ])) {
|
||||
// 查询页面的名称标识
|
||||
foreach ($other_page as $ck => $cv) {
|
||||
if ($cv[ 'page' ] == $start_up_page[ 'page' ]) {
|
||||
$use_template[ 'name' ] = $cv['name'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$use_template[ 'hope' ] = $start_up_page[ 'mode' ];
|
||||
$use_template[ 'mode' ] = $start_up_page[ 'mode' ];
|
||||
$use_template[ 'page' ] = $start_up_page[ 'page' ];
|
||||
$use_template[ 'action' ] = $start_up_page[ 'action' ] ?? '';
|
||||
if ($use_template[ 'hope' ] == 'other') {
|
||||
// 其他页面没有预览图
|
||||
$use_template[ 'url' ] = $use_template[ 'page' ];
|
||||
$use_template[ 'cover' ] = ''; // 默认图
|
||||
$use_template[ 'template' ] = '';
|
||||
$use_template[ 'desc' ] = '将 ' . $start_up_page[ 'title' ] . ' 设为首页';
|
||||
// 查询链接的名称标识
|
||||
foreach ($other_page as $ck => $cv) {
|
||||
if ($cv[ 'page' ] == $use_template[ 'page' ]) {
|
||||
$use_template[ 'name' ] = $cv[ 'name' ];
|
||||
$use_template[ 'parent' ] = $cv[ 'parent' ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 查询模板页面数据
|
||||
$page_data = $this->getPageData($params[ 'type' ], $info[ 'template' ]);
|
||||
if (!empty($page_data)) {
|
||||
$use_template[ 'url' ] = $template[ 'page' ] . '?id=' . $info[ 'id' ];
|
||||
// $use_template[ 'cover' ] = $page_data[ 'cover' ]; // 默认图
|
||||
} else {
|
||||
|
||||
// 查询页面数据
|
||||
$info = $this->getInfoByName($k);
|
||||
|
||||
if (!empty($info)) {
|
||||
$use_template[ 'id' ] = $info[ 'id' ];
|
||||
$use_template[ 'name' ] = $info[ 'name' ];
|
||||
$use_template[ 'title' ] = $info[ 'title' ];
|
||||
$use_template[ 'template' ] = $info[ 'template' ];
|
||||
$use_template[ 'mode' ] = $info[ 'mode' ];
|
||||
$use_template[ 'hope' ] = $info[ 'mode' ] == 'fixed' ? 'template' : $info[ 'mode' ];
|
||||
$use_template[ 'preview' ] = ''; // 默认图
|
||||
$use_template[ 'desc' ] = '通过自定义装修的页面';
|
||||
|
||||
// 查询模板页面数
|
||||
$page_data = $this->getPageData($k, $use_template[ 'template' ]);
|
||||
if (!empty($page_data)) {
|
||||
if ($info[ 'is_change' ] == 1) {
|
||||
// 修改过模板,预览实际内容
|
||||
$use_template[ 'url' ] = $v[ 'page' ] . '?id=' . $info[ 'id' ];
|
||||
} else {
|
||||
$use_template[ 'cover' ] = $page_data[ 'cover' ]; // 默认图
|
||||
$use_template[ 'desc' ] = $page_data[ 'desc' ];
|
||||
if (empty($page_data[ 'cover' ])) {
|
||||
$use_template[ 'url' ] = $v[ 'page' ] . '?id=' . $info[ 'id' ];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 自定义页面,实时预览效果
|
||||
$use_template[ 'url' ] = '/app/pages/index/diy?id=' . $info[ 'id' ];
|
||||
// 清空模板信息
|
||||
$use_template[ 'cover' ] = ''; // 默认图
|
||||
$use_template[ 'template' ] = '';
|
||||
$use_template[ 'mode' ] = 'diy';
|
||||
$use_template[ 'hope' ] = $use_template[ 'mode' ];
|
||||
}
|
||||
}
|
||||
// 自定义页面,实时预览效果
|
||||
$use_template[ 'url' ] = '/app/pages/index/diy?id=' . $info[ 'id' ];
|
||||
// 清空模板信息
|
||||
$use_template[ 'cover' ] = ''; // 默认图
|
||||
}
|
||||
|
||||
// 如果没有预览图,并且没有地址,则赋值
|
||||
if (empty($use_template[ 'cover' ]) && empty($use_template[ 'url' ])) {
|
||||
$use_template[ 'url' ] = $v[ 'page' ];
|
||||
}
|
||||
|
||||
$template[ $k ][ 'use_template' ] = $use_template;
|
||||
}
|
||||
|
||||
// 如果没有预览图,并且没有地址,则赋值默认页面地址
|
||||
if (empty($use_template[ 'cover' ]) && empty($use_template[ 'url' ])) {
|
||||
$use_template[ 'url' ] = $template[ 'page' ];
|
||||
}
|
||||
|
||||
$template[ 'use_template' ] = $use_template;
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置启动页
|
||||
* @param array $params
|
||||
* @return \app\model\sys\SysConfig|bool|\think\Model
|
||||
*/
|
||||
public function changeTemplate(array $params = [])
|
||||
{
|
||||
|
||||
$info = [];
|
||||
if ($params[ 'mode' ] == 'diy') {
|
||||
// 自定义页面
|
||||
|
||||
// 查询
|
||||
if (!empty($params[ 'id' ])) {
|
||||
// 使用了微页面
|
||||
$info = $this->getInfo($params[ 'id' ]);
|
||||
if (!empty($info)) {
|
||||
// 状态 变为 使用中
|
||||
$this->setUse($info[ 'id' ]);
|
||||
}
|
||||
} elseif ($params[ 'template' ]) {
|
||||
|
||||
// 查询表中未修改的模板数据
|
||||
$field = 'id,title,type';
|
||||
$condition = [
|
||||
[ 'site_id', '=', $this->site_id ],
|
||||
[ 'type', '=', $params[ 'type' ] ],
|
||||
[ 'template', '=', $params[ 'template' ] ],
|
||||
[ 'mode', '=', $params[ 'mode' ] ],
|
||||
[ 'is_change', '=', 0 ]
|
||||
];
|
||||
$info = $this->model->field($field)->where($condition)->findOrEmpty()->toArray();
|
||||
if (!empty($info)) {
|
||||
// 状态 变为 使用中
|
||||
$this->setUse($info[ 'id' ]);
|
||||
} else {
|
||||
// 新增 数据
|
||||
|
||||
// 查询模板信息
|
||||
$page_data = $this->getPageData($params[ 'type' ], $params[ 'template' ]);
|
||||
|
||||
$data = [
|
||||
'title' => $page_data[ 'title' ],
|
||||
'name' => $params[ 'type' ],
|
||||
'type' => $params[ 'type' ],
|
||||
'value' => json_encode($page_data[ 'data' ], JSON_UNESCAPED_UNICODE),
|
||||
'template' => $params[ 'template' ],
|
||||
'mode' => $params[ 'mode' ]
|
||||
];
|
||||
$res = $this->add($data);
|
||||
$this->setUse($res);
|
||||
$info = $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$page_template = TemplateDict::getTemplate([ 'type' => [ $info[ 'type' ] ] ])[ $info[ 'type' ] ];
|
||||
$info[ 'page' ] = $page_template[ 'page' ];
|
||||
|
||||
} elseif ($params[ 'mode' ] == 'fixed') {
|
||||
// 固定模板
|
||||
|
||||
// 查询模板信息
|
||||
$page_data = $this->getPageData($params[ 'type' ], $params[ 'template' ]);
|
||||
|
||||
// 检查表里是否存在数据
|
||||
$field = 'id,title,type';
|
||||
$condition = [
|
||||
[ 'type', '=', $params[ 'type' ] ],
|
||||
[ 'template', '=', $params[ 'template' ] ],
|
||||
[ 'mode', '=', $params[ 'mode' ] ]
|
||||
];
|
||||
$info = $this->model->field($field)->where($condition)->findOrEmpty()->toArray();
|
||||
if (!empty($info)) {
|
||||
// 状态 变为 使用中
|
||||
$this->setUse($info[ 'id' ]);
|
||||
} else {
|
||||
// 新增 数据
|
||||
$data = [
|
||||
'title' => $page_data[ 'title' ],
|
||||
'name' => $params[ 'type' ],
|
||||
'type' => $params[ 'type' ],
|
||||
'value' => json_encode($page_data[ 'data' ], JSON_UNESCAPED_UNICODE),
|
||||
'template' => $params[ 'template' ],
|
||||
'mode' => $params[ 'mode' ]
|
||||
];
|
||||
$res = $this->add($data);
|
||||
$this->setUse($res);
|
||||
$info = $data;
|
||||
}
|
||||
|
||||
$page_template = TemplateDict::getTemplate([ 'type' => [ $info[ 'type' ] ] ])[ $info[ 'type' ] ];
|
||||
$info[ 'page' ] = $page_template[ 'page' ];
|
||||
|
||||
} else if ($params[ 'mode' ] == 'other') {
|
||||
// 其他页面
|
||||
$info[ 'title' ] = $params[ 'title' ];
|
||||
$info[ 'page' ] = $params[ 'page' ];
|
||||
}
|
||||
|
||||
// 设置启动页
|
||||
$start_up_page_data = [
|
||||
'type' => $params[ 'type' ], // 页面类型
|
||||
'name' => $params[ 'name' ], // 页面名称标识
|
||||
'mode' => $params[ 'mode' ], // 模式:diy:自定义页面,fixed:模板,other:其他页面
|
||||
'title' => $info[ 'title' ],
|
||||
'page' => $info[ 'page' ],
|
||||
'action' => $params[ 'action' ]
|
||||
'name' => $params[ 'name' ], // 链接名称标识
|
||||
'parent' => $params[ 'parent' ], // 链接父级名称标识
|
||||
'page' => $params[ 'page' ], // 链接路由
|
||||
'title' => $params[ 'title' ], // 链接标题
|
||||
'action' => $params[ 'action' ] // 是否存在操作,decorate 表示支持装修
|
||||
];
|
||||
$diy_config_service = new DiyConfigService();
|
||||
$diy_config_service->setStartUpPageConfig($start_up_page_data);
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面预览数据
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getPreviewData(array $params = [])
|
||||
{
|
||||
$info = [];
|
||||
if (!empty($params[ 'id' ])) {
|
||||
$info = $this->getInfo($params[ 'id' ]);
|
||||
} elseif (!empty($params[ 'name' ])) {
|
||||
$info = $this->getInfoByName($params[ 'name' ]);
|
||||
}
|
||||
|
||||
$res = [
|
||||
'page' => $this->getTemplate([ 'type' => 'DIY_PAGE' ])[ 'DIY_PAGE' ][ 'page' ]
|
||||
];
|
||||
|
||||
if (!empty($info)) {
|
||||
if ($info[ 'is_default' ] == 1) {
|
||||
$template = $this->getTemplate([ 'type' => $info[ 'type' ] ])[ $info[ 'type' ] ];
|
||||
$res[ 'page' ] = $template[ 'page' ] . '?id=' . $info[ 'id' ];
|
||||
}
|
||||
}
|
||||
|
||||
$res = $diy_config_service->setStartUpPageConfig($start_up_page_data);
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板页面的应用插件列表
|
||||
* @return array
|
||||
*/
|
||||
public function getApps()
|
||||
{
|
||||
$page_template = TemplateDict::getTemplate([
|
||||
'query' => 'addon'
|
||||
]);
|
||||
return $page_template;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -326,11 +326,11 @@ class ServiceGenerator extends BaseGenerator
|
||||
$search_field = implode(',', $search_field);
|
||||
if(empty($with))
|
||||
{
|
||||
$content.= '$this->model->where([ [' ." 'site_id' ". ',"=", $this->site_id ] ])->withSearch(['."'$search_field'".'], $where)->field('.'$field'.')->order('.'$order'.')';
|
||||
$content.= '$this->model->where([ [' ." 'site_id' ". ',"=", $this->site_id ] ])->withSearch(['."'$search_field'".'], $where)->field('.'$field'.')->order('.'$order'.');';
|
||||
|
||||
}else{
|
||||
$with = implode(',', $with);
|
||||
$content.= '$this->model->where([ [' ." 'site_id' ". ',"=", $this->site_id ] ])->withSearch(['."'$search_field'".'], $where)->with('."'$with'".')->field('.'$field'.')->order('.'$order'.')';
|
||||
$content.= '$this->model->where([ [' ." 'site_id' ". ',"=", $this->site_id ] ])->withSearch(['."'$search_field'".'], $where)->with('."'$with'".')->field('.'$field'.')->order('.'$order'.');';
|
||||
}
|
||||
|
||||
return $content;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-[20px]">{{pageName}}</span>
|
||||
<span class="text-lg">{{pageName}}</span>
|
||||
<el-button type="primary" @click="addEvent">
|
||||
{{ t('add{UCASE_NAME}') }}
|
||||
</el-button>
|
||||
|
||||
@ -49,7 +49,7 @@ class SiteGroupService extends BaseAdminService
|
||||
public function getPage(array $where = [])
|
||||
{
|
||||
$field = 'group_id, group_name, group_desc, app, addon, create_time, update_time';
|
||||
$search_model = $this->model->withSearch(['keywords'],$where)->field($field)->order('create_time desc');
|
||||
$search_model = $this->model->withSearch(['keywords'],$where)->field($field)->append(['app_name', 'addon_name'])->order('create_time desc');
|
||||
$list = $this->pageQuery($search_model);
|
||||
return $list;
|
||||
}
|
||||
|
||||
@ -83,7 +83,7 @@ class SiteService extends BaseAdminService
|
||||
$info = $this->model->where([ [ 'site_id', '=', $site_id ] ])->with([ 'groupName' ])->field($field)->append([ 'status_name' ])->findOrEmpty()->toArray();
|
||||
if (!empty($info)) {
|
||||
$site_addons = (new CoreSiteService())->getAddonKeysBySiteId($site_id);
|
||||
$info['site_addons'] = (new Addon())->where([ ['key', 'in', $site_addons]])->field('key,title,desc,icon')->select()->toArray();
|
||||
$info['site_addons'] = (new Addon())->where([ ['key', 'in', $site_addons]])->field('key,title,desc,icon,type')->select()->toArray();
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ class ConfigService extends BaseAdminService
|
||||
*/
|
||||
public function getCopyright()
|
||||
{
|
||||
return (new CoreSysConfigService())->getCopyright();
|
||||
return (new CoreSysConfigService())->getCopyright($this->site_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,7 +59,7 @@ class ConfigService extends BaseAdminService
|
||||
'copyright_link' => $value['copyright_link'],
|
||||
'copyright_desc' => $value['copyright_desc']
|
||||
];
|
||||
return $this->core_config_service->setConfig(0,'COPYRIGHT', $data);
|
||||
return $this->core_config_service->setConfig($this->site_id,'COPYRIGHT', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -141,10 +141,19 @@ class SystemService extends BaseAdminService
|
||||
$secret = uniqid('', true);
|
||||
$file = root_path('runtime') . $secret . '.job';
|
||||
try {
|
||||
CheckJob::invoke([ 'file' => $file ]);
|
||||
CheckJob::dispatch([ 'file' => $file ]);
|
||||
} catch ( Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
// $timeout = 0;
|
||||
// while($timeout < 5){
|
||||
// if (file_exists($file)) {
|
||||
// @unlink($file);
|
||||
// return true;
|
||||
// }
|
||||
// $timeout++;
|
||||
// sleep(1);
|
||||
// }
|
||||
sleep(3);
|
||||
if (file_exists($file)) {
|
||||
@unlink($file);
|
||||
|
||||
@ -52,7 +52,7 @@ class StorageConfigService extends BaseAdminService
|
||||
$info = (new CoreConfigService())->getConfig($this->site_id, 'STORAGE');
|
||||
if(empty($info))
|
||||
{
|
||||
$config_type = ['default' => ''];//初始化
|
||||
$config_type = ['default' => StorageDict::LOCAL];//初始化
|
||||
}else
|
||||
$config_type = $info['value'];
|
||||
|
||||
@ -113,4 +113,4 @@ class StorageConfigService extends BaseAdminService
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,4 +31,13 @@ class DiyConfigService extends BaseApiService
|
||||
return (new CoreDiyConfigService())->getBottomConfig($this->site_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启动页配置
|
||||
* @return array
|
||||
*/
|
||||
public function getStartUpPageConfig($type)
|
||||
{
|
||||
return (new CoreDiyConfigService())->getStartUpPageConfig($this->site_id, $type);
|
||||
}
|
||||
|
||||
}
|
||||
@ -12,6 +12,7 @@
|
||||
namespace app\service\api\diy;
|
||||
|
||||
use app\dict\diy\PagesDict;
|
||||
use app\dict\diy\TemplateDict;
|
||||
use app\model\diy\Diy;
|
||||
use core\base\BaseApiService;
|
||||
|
||||
@ -36,40 +37,57 @@ class DiyService extends BaseApiService
|
||||
*/
|
||||
public function getInfo(array $params = [])
|
||||
{
|
||||
$condition = [
|
||||
[ 'site_id', '=', $this->site_id ]
|
||||
];
|
||||
if (!empty($params[ 'id' ])) {
|
||||
$condition[] = [ 'id', '=', $params[ 'id' ] ];
|
||||
} elseif (!empty($params[ 'name' ])) {
|
||||
$condition[] = [ 'name', '=', $params[ 'name' ] ];
|
||||
$condition[] = [ 'is_default', '=', 1 ];
|
||||
$start_up_page = [];
|
||||
$page_template = [];
|
||||
|
||||
if (!empty($params[ 'name' ])) {
|
||||
|
||||
// 查询启动页
|
||||
$diy_config_service = new DiyConfigService();
|
||||
$start_up_page = $diy_config_service->getStartUpPageConfig($params[ 'name' ]);
|
||||
|
||||
$page_template = TemplateDict::getTemplate([ 'type' => [ $params[ 'name' ] ] ])[ $params[ 'name' ] ];
|
||||
}
|
||||
|
||||
$field = 'id,site_id,title,name,type,template, mode,value,is_default,share,visit_count';
|
||||
if (!empty($start_up_page) && !empty($page_template) && !empty($start_up_page[ 'page' ]) && $start_up_page[ 'page' ] != $page_template[ 'page' ]) {
|
||||
$info = $start_up_page;
|
||||
return $info;
|
||||
} else {
|
||||
$condition = [
|
||||
[ 'site_id', '=', $this->site_id ]
|
||||
];
|
||||
if (!empty($params[ 'id' ])) {
|
||||
$condition[] = [ 'id', '=', $params[ 'id' ] ];
|
||||
} elseif (!empty($params[ 'name' ])) {
|
||||
$condition[] = [ 'name', '=', $params[ 'name' ] ];
|
||||
$condition[] = [ 'is_default', '=', 1 ];
|
||||
}
|
||||
|
||||
$info = $this->model->field($field)->where($condition)->findOrEmpty()->toArray();
|
||||
if (empty($info)) {
|
||||
// 查询默认页面数据
|
||||
if (!empty($params[ 'name' ])) {
|
||||
$page_data = $this->getFirstPageData($params[ 'name' ]);
|
||||
if (!empty($page_data)) {
|
||||
$info = [
|
||||
'site_id' => $this->site_id,
|
||||
'title' => $page_data[ 'title' ],
|
||||
'name' => $page_data[ 'type' ],
|
||||
'type' => $page_data[ 'type' ],
|
||||
'template' => $page_data[ 'template' ],
|
||||
'mode' => $page_data[ 'mode' ],
|
||||
'value' => json_encode($page_data[ 'data' ], JSON_UNESCAPED_UNICODE),
|
||||
'is_default' => 1,
|
||||
'share' => '',
|
||||
'visit_count' => 0
|
||||
];
|
||||
$field = 'id,site_id,title,name,type,template, mode,value,is_default,share,visit_count';
|
||||
|
||||
$info = $this->model->field($field)->where($condition)->findOrEmpty()->toArray();
|
||||
if (empty($info)) {
|
||||
// 查询默认页面数据
|
||||
if (!empty($params[ 'name' ])) {
|
||||
$page_data = $this->getFirstPageData($params[ 'name' ]);
|
||||
if (!empty($page_data)) {
|
||||
$info = [
|
||||
'site_id' => $this->site_id,
|
||||
'title' => $page_data[ 'title' ],
|
||||
'name' => $page_data[ 'type' ],
|
||||
'type' => $page_data[ 'type' ],
|
||||
'template' => $page_data[ 'template' ],
|
||||
'mode' => $page_data[ 'mode' ],
|
||||
'value' => json_encode($page_data[ 'data' ], JSON_UNESCAPED_UNICODE),
|
||||
'is_default' => 1,
|
||||
'share' => '',
|
||||
'visit_count' => 0
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -36,7 +36,7 @@ class ConfigService extends BaseApiService
|
||||
*/
|
||||
public function getCopyright()
|
||||
{
|
||||
return (new CoreSysConfigService())->getCopyright();
|
||||
return (new CoreSysConfigService())->getCopyright($this->site_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -47,30 +47,20 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
{
|
||||
$this->addon = $addon;
|
||||
$this->addon_path = root_path() . 'addon' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR;
|
||||
$this->build_path = runtime_path() . 'build' . DIRECTORY_SEPARATOR . $addon . DIRECTORY_SEPARATOR;
|
||||
|
||||
if (!is_dir($this->addon_path)) throw new AddonException('ADDON_IS_NOT_EXIST');//当前目录中不存在此项插件
|
||||
|
||||
if (is_dir($this->build_path)) {
|
||||
del_target_dir($this->build_path, true);
|
||||
} else {
|
||||
dir_mkdir($this->build_path);
|
||||
}
|
||||
|
||||
// 拷贝插件文件
|
||||
dir_copy($this->addon_path, $this->build_path, exclude_dirs:['admin', 'uni-app', 'web']);
|
||||
|
||||
$this->admin();
|
||||
$this->uniapp();
|
||||
$this->buildUniappPagesJson();
|
||||
$this->web();
|
||||
$this->resource();
|
||||
$this->menu('admin');
|
||||
$this->menu('site');
|
||||
|
||||
$zip_file = runtime_path() . 'build' . DIRECTORY_SEPARATOR . $addon . '.zip';
|
||||
$zip_file = runtime_path() . $addon . '.zip';
|
||||
if (file_exists($zip_file)) unlink($zip_file);
|
||||
(new CoreAddonDevelopDownloadService(''))->compressToZip($this->build_path, $zip_file);
|
||||
// 删除打包文件
|
||||
del_target_dir($this->build_path, true);
|
||||
(new CoreAddonDevelopDownloadService(''))->compressToZip($this->addon_path, $zip_file);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -81,7 +71,7 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
* @return \think\response\File
|
||||
*/
|
||||
public function download(string $addon) {
|
||||
$zip_file = runtime_path() . 'build' . DIRECTORY_SEPARATOR . $addon . '.zip';
|
||||
$zip_file = runtime_path() . $addon . '.zip';
|
||||
|
||||
if (!file_exists($zip_file)) throw new AddonException('ADDON_ZIP_ERROR');//下载失败
|
||||
$content = file_get_contents($zip_file);
|
||||
@ -99,21 +89,19 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
*/
|
||||
public function menu(string $app_type) {
|
||||
$where = [ ['app_type', '=', $app_type], ['addon', '=', $this->addon] ];
|
||||
$field = 'menu_name,menu_key,menu_type,icon,api_url,router_path,view_path,methods,sort,status,is_show,parent_key';
|
||||
$field = 'menu_name,menu_key,parent_key,menu_type,icon,api_url,router_path,view_path,methods,sort,status,is_show';
|
||||
$menu = (new SysMenu())->where($where)->field($field)->order('sort', 'desc')->select()->toArray();
|
||||
if (!empty($menu)) {
|
||||
$menu = (new MenuService())->menuToTree($menu, 'menu_key', 'parent_key', 'children');
|
||||
(new SysMenu())->where($where)->update(['source' => MenuDict::SYSTEM]);
|
||||
}
|
||||
|
||||
$build_dict = $this->build_path . 'app' . DIRECTORY_SEPARATOR . 'dict' . DIRECTORY_SEPARATOR . 'menu' . DIRECTORY_SEPARATOR . $app_type . '.php';
|
||||
$addon_dict = $this->addon_path . 'app' . DIRECTORY_SEPARATOR . 'dict' . DIRECTORY_SEPARATOR . 'menu' . DIRECTORY_SEPARATOR . $app_type . '.php';
|
||||
|
||||
$content = '<?php' . PHP_EOL;
|
||||
$content .= 'return [' . PHP_EOL;
|
||||
$content .= $this->arrayFormat($menu);
|
||||
$content .= '];';
|
||||
file_put_contents($build_dict, $content);
|
||||
file_put_contents($addon_dict, $content);
|
||||
|
||||
return true;
|
||||
@ -126,6 +114,7 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
}
|
||||
$content = '';
|
||||
foreach ($array as $k => $v) {
|
||||
if (in_array($k, ['status_name', 'menu_type_name'])) continue;
|
||||
if (is_array($v)) {
|
||||
$content .= $tab;
|
||||
if (is_string($k)) {
|
||||
@ -147,8 +136,12 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
public function admin()
|
||||
{
|
||||
$admin_path = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$build_admin_path = $this->build_path . 'admin' . DIRECTORY_SEPARATOR;
|
||||
dir_copy($admin_path, $build_admin_path);
|
||||
if (!is_dir($admin_path)) return true;
|
||||
|
||||
$addon_admin_path = $this->addon_path . 'admin' . DIRECTORY_SEPARATOR;
|
||||
if (is_dir($addon_admin_path)) del_target_dir($addon_admin_path, true);
|
||||
dir_copy($admin_path, $addon_admin_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -159,8 +152,37 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
public function uniapp()
|
||||
{
|
||||
$uniapp_path = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$build_uniapp_path = $this->build_path . 'uni-app' . DIRECTORY_SEPARATOR;
|
||||
dir_copy($uniapp_path, $build_uniapp_path);
|
||||
if (!is_dir($uniapp_path)) return true;
|
||||
|
||||
$addon_uniapp_path = $this->addon_path . 'uni-app' . DIRECTORY_SEPARATOR;
|
||||
if (is_dir($addon_uniapp_path)) del_target_dir($addon_uniapp_path, true);
|
||||
dir_copy($uniapp_path, $addon_uniapp_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function buildUniappPagesJson() {
|
||||
$pages_json = file_get_contents($this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'pages.json');
|
||||
$code_begin = strtoupper($this->addon) . '_PAGE_BEGIN' . PHP_EOL;
|
||||
$code_end = strtoupper($this->addon) . '_PAGE_END' . PHP_EOL;
|
||||
|
||||
if(strpos($pages_json, $code_begin) !== false && strpos($pages_json, $code_end) !== false)
|
||||
{
|
||||
$pattern = "/\/\/\s+{$code_begin}([\S\s]+)\/\/\s+{$code_end}?/";
|
||||
preg_match($pattern, $pages_json, $match);
|
||||
|
||||
if (!empty($match)) {
|
||||
$addon_pages = $match[1];
|
||||
|
||||
$content = '<?php' . PHP_EOL;
|
||||
$content .= 'return [' . PHP_EOL . " 'pages' => <<<EOT" . PHP_EOL . ' // PAGE_BEGIN' . PHP_EOL;
|
||||
$content .= $addon_pages;
|
||||
$content .= '// PAGE_END' . PHP_EOL . 'EOT' . PHP_EOL . '];';
|
||||
|
||||
if (!is_dir($this->addon_path . 'package')) dir_mkdir($this->addon_path . 'package');
|
||||
file_put_contents($this->addon_path . 'package' . DIRECTORY_SEPARATOR . 'uni-app-pages.php', $content);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -170,6 +192,36 @@ class CoreAddonDevelopBuildService extends BaseCoreService
|
||||
*/
|
||||
public function web()
|
||||
{
|
||||
$web_path = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
if (!is_dir($web_path)) return true;
|
||||
|
||||
$addon_web_path = $this->addon_path . 'web' . DIRECTORY_SEPARATOR;
|
||||
if (is_dir($addon_web_path)) del_target_dir($addon_web_path, true);
|
||||
dir_copy($web_path, $addon_web_path);
|
||||
|
||||
$layout = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'layouts' . DIRECTORY_SEPARATOR . $this->addon;
|
||||
if (is_dir($layout)) {
|
||||
$layout_dir = $addon_web_path . 'layouts' . DIRECTORY_SEPARATOR . $this->addon;
|
||||
if (is_dir($layout_dir)) del_target_dir($layout_dir, true);
|
||||
else dir_mkdir($layout_dir);
|
||||
dir_copy($layout, $layout_dir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打包资源文件
|
||||
* @return true
|
||||
*/
|
||||
public function resource() {
|
||||
$resource_path = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
if (!is_dir($resource_path)) return true;
|
||||
|
||||
$addon_resource_path = $this->addon_path . 'resource' . DIRECTORY_SEPARATOR;
|
||||
if (is_dir($addon_resource_path)) del_target_dir($addon_resource_path, true);
|
||||
dir_copy($resource_path, $addon_resource_path);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,7 +369,7 @@ class CoreAddonDevelopService extends CoreAddonBaseService
|
||||
if (empty($image)) return true;
|
||||
if (check_file_is_remote($image)) {
|
||||
try {
|
||||
(new CoreFetchService())->setRootPath($dir)->setRename($name)->image($image, '', FileDict::LOCAL);
|
||||
(new CoreFetchService())->setRootPath($dir)->setRename($name)->image($image, 0, FileDict::LOCAL);
|
||||
} catch ( UploadFileException $e ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
|
||||
|
||||
// 放入的文件
|
||||
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
|
||||
@ -295,6 +295,12 @@ class CoreAddonInstallService extends CoreAddonBaseService
|
||||
|
||||
// 安装电脑端
|
||||
if (file_exists($from_web_dir)) {
|
||||
// 安装布局文件
|
||||
$layout = $from_web_dir . 'layouts';
|
||||
if (is_dir($layout)) {
|
||||
dir_copy($layout, $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'layouts');
|
||||
del_target_dir($layout, true);
|
||||
}
|
||||
dir_copy($from_web_dir, $to_web_dir, $this->files['web']);
|
||||
}
|
||||
|
||||
@ -575,7 +581,8 @@ class CoreAddonInstallService extends CoreAddonBaseService
|
||||
{
|
||||
// 将要删除的根目录
|
||||
$to_admin_dir = $this->root_path . 'admin' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_web_dir = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_web_layouts = $this->root_path . 'web' . DIRECTORY_SEPARATOR . 'layouts' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_wap_dir = $this->root_path . 'uni-app' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
$to_resource_dir = public_path() . 'addon' . DIRECTORY_SEPARATOR . $this->addon . DIRECTORY_SEPARATOR;
|
||||
|
||||
@ -586,6 +593,7 @@ class CoreAddonInstallService extends CoreAddonBaseService
|
||||
|
||||
// 卸载pc端
|
||||
if (is_dir($to_web_dir)) del_target_dir($to_web_dir, true);
|
||||
if (is_dir($to_web_layouts)) del_target_dir($to_web_layouts, true);
|
||||
|
||||
// 卸载手机端
|
||||
if (is_dir($to_wap_dir)) del_target_dir($to_wap_dir, true);
|
||||
|
||||
@ -33,7 +33,7 @@ trait WapTrait
|
||||
$content = "<template>\n";
|
||||
$content .= " <view class=\"diy-group\" id=\"componentList\">\n";
|
||||
$content .= " <view v-for=\"(component, index) in data.value\" :key=\"component.id\"\n";
|
||||
$content .= " @click=\"diyStore.changeCurrentIndex(index, component)\" class=\"draggable-element relative cursor-move\"\n";
|
||||
$content .= " @click=\"diyStore.changeCurrentIndex(index, component)\" class=\"draggable-element relative\"\n";
|
||||
$content .= " :class=\"{ selected: diyStore.currentIndex == index,decorate : diyStore.mode == 'decorate' }\" :style=\"component.pageStyle\">\n";
|
||||
|
||||
$root_path = $compile_path . str_replace('/', DIRECTORY_SEPARATOR, 'app/components/diy'); // 系统自定义组件根目录
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export default [
|
||||
{
|
||||
path: "/{key}/hello_world/index",
|
||||
component: () => import('~/{key}/pages/hello_world/index.vue')
|
||||
component: () => import('~/addon/{key}/pages/hello_world/index.vue')
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { getHelloWorld } from '@/{key}/api/hello_world'
|
||||
import { getHelloWorld } from '@/addon/{key}/api/hello_world'
|
||||
|
||||
const hello_world_text = ref('');
|
||||
|
||||
@ -12,4 +12,4 @@ getHelloWorld().then(res => {
|
||||
hello_world_text.value = res.data;
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -31,9 +31,8 @@ class CoreDiyConfigService extends BaseCoreService
|
||||
*/
|
||||
public function getBottomConfig(int $site_id)
|
||||
{
|
||||
$info = ( new CoreConfigService() )->getConfig($site_id, ConfigKeyDict::DIY_BOTTOM)[ 'value' ] ?? [];
|
||||
$info = (new CoreConfigService())->getConfig($site_id, ConfigKeyDict::DIY_BOTTOM)[ 'value' ] ?? [];
|
||||
if (empty($info)) {
|
||||
|
||||
$info = [
|
||||
'backgroundColor' => '#ffffff',
|
||||
'textColor' => '#606266',
|
||||
@ -76,7 +75,7 @@ class CoreDiyConfigService extends BaseCoreService
|
||||
*/
|
||||
public function setBottomConfig(int $site_id, array $data)
|
||||
{
|
||||
return ( new CoreConfigService() )->setConfig($site_id, ConfigKeyDict::DIY_BOTTOM, $data);
|
||||
return (new CoreConfigService())->setConfig($site_id, ConfigKeyDict::DIY_BOTTOM, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +85,7 @@ class CoreDiyConfigService extends BaseCoreService
|
||||
*/
|
||||
public function setStartUpPageConfig(int $site_id, array $data)
|
||||
{
|
||||
return ( new CoreConfigService() )->setConfig($site_id,'START_UP_PAGE_' . strtoupper($data[ 'type' ]), $data);
|
||||
return (new CoreConfigService())->setConfig($site_id, 'START_UP_PAGE_' . strtoupper($data[ 'type' ]), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +95,7 @@ class CoreDiyConfigService extends BaseCoreService
|
||||
*/
|
||||
public function getStartUpPageConfig(int $site_id, string $type)
|
||||
{
|
||||
$info = ( new CoreConfigService() )->getConfig($site_id, 'START_UP_PAGE_' . strtoupper($type))[ 'value' ] ?? [];
|
||||
$info = (new CoreConfigService())->getConfig($site_id, 'START_UP_PAGE_' . strtoupper($type))[ 'value' ] ?? [];
|
||||
if (!empty($info)) {
|
||||
$info[ 'name' ] = isset($info[ 'name' ]) ? $info[ 'name' ] : '';
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user