This commit is contained in:
wangchen147 2024-03-08 16:06:29 +08:00
parent b8fa07a257
commit f7288afe80
802 changed files with 4780 additions and 4066 deletions

18
admin/src/app/api/pc.ts Normal file
View File

@ -0,0 +1,18 @@
import request from '@/utils/request'
/**
* pc配置
* @returns
*/
export function getPcConfig() {
return request.get('channel/pc/config')
}
/**
* h5配置
* @param params
* @returns
*/
export function setPcConfig(params: Record<string, any>) {
return request.put('channel/pc/config', params, {showSuccessMessage: true})
}

View File

@ -4,5 +4,6 @@
"copy": "复制",
"clickVisit": "点击访问",
"PCDomainName": "pc域名",
"newInfo": "最新消息"
}
"newInfo": "最新消息",
"isOpen": "是否开启"
}

View File

@ -1,123 +0,0 @@
{
"developTitle": "开发环境配置",
"wapDomain": "wap域名WAP_DOMAIN",
"wapDomainPlaceholder": "请输入wap域名",
"pageSet": "页面设置",
"tabEditContent": "内容",
"tabEditStyle": "样式",
"pageStyle": "页面样式",
"pageContent": "页面内容",
"pageName": "页面名称",
"pageNamePlaceholder": "请输入页面名称",
"pageBgColor": "页面颜色",
"bgUrl": "背景图片",
"marginSet": "边距设置",
"componentStyleTitle": "组件样式",
"bottomBgColor": "底部背景",
"bottomBgTips": "底部背景包含边距和圆角",
"componentBgColor": "组件背景",
"marginTop": "上边距",
"marginBottom": "下边距",
"marginBoth": "左右边距",
"topRounded": "上圆角",
"bottomRounded": "下圆角",
"warmPrompt": "温馨提示",
"leavePageTitleTips": "确定离开此页面?",
"leavePageContentTips": "系统可能不会保存您所做的更改。",
"decorating": "正在装修",
"moveUpComponent": "上移",
"moveDownComponent": "下移",
"copyComponent": "复制",
"delComponent": "删除",
"resetComponent": "重置",
"tabbar": "底部导航",
"tabbarSwitchTips": "此处控制当前页面底部导航菜单是否显示",
"link": "链接地址",
"delComponentTips": "确定要删除吗?",
"notCopy": "无法复制",
"componentCanOnlyAdd": "组件只能添加",
"piece": "个",
"resetComponentTips": "确认要重置组件默认数据吗?",
"image": "图片上传",
"imageUpload": "图片上传",
"imageSet": "图片设置",
"imageAdsTips": "建议上传尺寸相同的图片推荐尺寸750*350",
"addImageAd": "添加图片",
"imageUrlTip": "请上传图片",
"imageHeight": "图片高度",
"imageHeightPlaceholder": "请输入图片高度",
"imageHeightRegNum": "图片高度格式错误,请输入数字",
"articleData": "文章数据",
"articleStyle": "文章样式",
"articleBgColor": "文章背景",
"dataSources": "数据来源",
"defaultSources": "默认",
"manualSelectionSources": "手动选择",
"articleNum": "文章数量",
"selectPlaceholder": "请选择",
"selectArticleTips": "文章选择",
"articleTitle": "标题",
"articleImage": "封面",
"articleCategoryName": "栏目",
"articleSummary": "摘要",
"selected": "已选",
"selectArticleTip": "请选择文章",
"graphicNavModeTitle": "导航模式",
"layoutMode": "排版模式",
"layoutModeHorizontal": "横排",
"layoutModeVertical": "竖排",
"graphicNavSelectMode": "选择模式",
"graphicNavModeGraphic": "图文导航",
"graphicNavModeImg": "图片导航",
"graphicNavModeText": "文字导航",
"graphicNavImageSet": "图片设置",
"graphicNavImageSize": "图片大小",
"graphicNavAroundRadius": "图片圆角",
"graphicNavShowStyle": "展示风格",
"graphicNavStyleFixed": "固定显示",
"graphicNavStyleSingleSlide": "单行滑动",
"graphicNavStylePageSlide": "分页滑动",
"graphicNavRowCount": "每行数量",
"graphicNavPageCount": "每行数量",
"graphicNavSetLabel": "导航设置",
"line": "行",
"graphicNavTips": "建议上传尺寸相同的图片推荐尺寸60*60",
"graphicNavTitle": "标题",
"graphicNavTitlePlaceholder": "请输入标题",
"addGraphicNav": "添加导航",
"blankHeightSet": "高度设置",
"blankHeight": "空白高度",
"styleSet": "风格设置",
"titleStyle": "标题样式",
"selectStyle": "风格选择",
"titleContent": "标题内容",
"title": "标题名称",
"titlePlaceholder": "请输入标题",
"textAlign": "对齐方式",
"textAlignLeft": "居左",
"textAlignCenter": "居中",
"textSet": "文字设置",
"textFontSize": "文字大小",
"textFontWeight": "文字粗细",
"fontWeightBold": "加粗",
"fontWeightNormal": "常规",
"textColor": "文字颜色",
"subTitleContent": "标题内容",
"subTitle": "副标题",
"subTitlePlaceholder": "请输入副标题",
"moreContent": "“更多”按钮内容",
"more": "文字",
"morePlaceholder": "请输入文字",
"moreIsShow": "是否显示",
"memberStyle": "会员样式",
"template": "模板",
"imageGap": "图片间隙",
"rubikCubeStyle": "魔方样式",
"hotArea": "热区",
"hotAreaSet": "热区设置",
"addHotArea": "添加热区",
"selectedAfterHotArea": "个热区",
"hotAreaManage": "热区管理",
"selectedHotArea": "请选择热区",
"hotAreaLink": "的链接地址"
}

View File

@ -51,21 +51,11 @@
"imageHeight": "图片高度",
"imageHeightPlaceholder": "请输入图片高度",
"imageHeightRegNum": "图片高度格式错误,请输入数字",
"articleData": "文章数据",
"articleStyle": "文章样式",
"articleBgColor": "文章背景",
"dataSources": "数据来源",
"defaultSources": "默认",
"manualSelectionSources": "手动选择",
"articleNum": "文章数量",
"selectPlaceholder": "请选择",
"selectArticleTips": "文章选择",
"articleTitle": "标题",
"articleImage": "封面",
"articleCategoryName": "栏目",
"articleSummary": "摘要",
"selected": "已选",
"selectArticleTip": "请选择文章",
"graphicNavModeTitle": "导航模式",
"layoutMode": "排版模式",
"layoutModeHorizontal": "横排",
@ -139,54 +129,13 @@
"addonIcon": "应用图标",
"selectAddon": "选择应用",
"addAddon": "添加应用",
"travel": "旅游",
"tickets": "门票",
"hotel": "酒店",
"travelNum": "线路数量",
"ticketsNum": "景点数量",
"hotelNum": "酒店数量",
"serve": "项目",
"serveNum": "项目数量",
"card": "卡项",
"cardNum": "卡项数量",
"isSet": "会员设置",
"isMemberCode": "会员码",
"show": "显示",
"hideen": "隐藏",
"nicknameStyle": "昵称样式",
"UIDStyle": "UID样式",
"accountStyle": "积分/余额样式",
"accountNumberColor": "数值颜色",
"accountNumberWeight": "数值粗细",
"hidden": "隐藏",
"goodsCategoryTitle":"商品分类",
"customGoods":"手动选择",
"goodsNum":"商品数量",
"selectCategory":"选择分类",
"categoryName": "分类名称",
"categoryImage": "分类图片",
"selectSource": "选择数据源",
"goodsSelectPopupSelectGoodsButton": "选择商品",
"goodsSelectPopupSelect": "已选",
"goodsSelectPopupPiece": "个",
"goodsSelectPopupSelectGoodsDialog": "商品选择",
"goodsSelectPopupAllGoods": "全部商品",
"goodsSelectPopupSelectedGoods": "已选商品",
"goodsSelectPopupGoodsName": "商品名称",
"goodsSelectPopupGoodsNamePlaceholder": "请输入商品名称",
"goodsSelectPopupGoodsCategory": "商品分类",
"goodsSelectPopupGoodsCategoryPlaceholder": "全部",
"goodsSelectPopupGoodsType": "商品类型",
"goodsSelectPopupGoodsTypePlaceholder": "请选择商品类型",
"goodsSelectPopupGoodsInfo": "商品",
"goodsSelectPopupPrice": "价格",
"goodsSelectPopupStock": "库存",
"goodsSelectPopupBeforeTip": "已选择",
"goodsSelectPopupAfterTip": "个商品",
"goodsSelectPopupClearGoods": "取消选择",
"goodsSelectPopupGoodsMinTip": "所选商品数量不能少于",
"goodsSelectPopupGoodsMaxTip": "所选商品数量不能超过",
"confirm": "确定",
"cancel": "取消"
"selectSource": "选择数据源"
}

View File

@ -1,7 +1,7 @@
{
"title": "页面名称",
"typeName": "页面类型",
"forAddon": "所属插件",
"forAddon": "所属应用",
"addPageTips": "创建新页面",
"pageTypePlaceholder": "请选择页面类型",
"nameMax": "名称不能超过12个字符",
@ -19,7 +19,7 @@
"titlePlaceholder": "请输入页面名称",
"addDiyPage": "添加页面",
"diyPageDeleteTips": "确定要删除该自定义页面吗?",
"promote": "推广",
"preview": "预览",
"share": "分享",
"shareSet": "分享设置",
"sharePage": "分享页面",

View File

@ -8,7 +8,6 @@
"copy": "复制",
"copySuccess": "复制成功",
"titlePlaceholder": "请输入页面名称",
"promote": "推广",
"share": "分享",
"shareSet": "分享设置",
"sharePage": "分享页面",

View File

@ -1,13 +1,13 @@
{
"registerChannel":"注册来源",
"nickname":"会员称",
"nickname":"会员称",
"memberNo":"会员编号",
"mobile":"手机号",
"createTime":"注册时间",
"lastVisitTime":"最后访问时间",
"addMember":"添加会员",
"updateMember":"编辑会员",
"nickNamePlaceholder":"请输入会员称",
"nickNamePlaceholder":"请输入会员称",
"mobilePlaceholder":"请输入手机号",
"channelPlaceholder":"请选择注册类型",
"memberNoPlaceholder":"请选择会员编号",

View File

@ -34,7 +34,7 @@
"essentialInfo": "基本信息",
"accountInfo": "账户信息",
"urserName": "用户名",
"nickname":"会员称",
"nickname":"会员称",
"registeredSource": "注册来源",
"lastVisitTime":"最后登录时间",
"point": "积分",

View File

@ -27,9 +27,12 @@
"keywordsPlaceholder": "网站关键字",
"logoPlaceholder": "网站Logo",
"descPlaceholder": "网站简介",
"phonePlaceholder": "客服电话",
"app" : "站点应用",
"addon" : "站点插件"
"addon" : "站点插件",
"siteDomain": "站点域名",
"siteDomainPlaceholder": "请输入站点域名",
"siteDomainTips": "站点域名的配置是针对站点的wap和web端",
"siteDomainTipsTwo": "配置的站点域名需要先配置域名解析",
"siteDomainTipsThree": "配置的站点域名需配置隐性解析到域名:"
}

View File

@ -12,7 +12,6 @@
"addSite":"添加站点",
"editSite":"编辑站点",
"updateSite":"编辑站点",
"siteDeleteTips":"确定要删除该站点吗?",
"statusExpire":"已到期",
"phone":"客服电话",
"groupIdPlaceholder":"请选择套餐",
@ -45,5 +44,11 @@
"managerPlaceholder": "请选择站点管理员",
"newAddManager": "新增管理员",
"edit": "编辑",
"siteDeleteTips": "确定要删除该站点吗?该操作将删除该站点和站点相关数据,该操作无法退回,确定要继续删除吗?"
"siteDeleteTips": "确定要删除该站点吗?该操作将删除该站点和站点相关数据,该操作无法退回,确定要继续删除吗?",
"siteDomain": "站点域名",
"siteDomainPlaceholder": "请输入站点域名",
"siteDomainTips": "站点域名的配置是针对站点的wap和web端",
"siteDomainTipsTwo": "配置的站点域名需要先配置域名解析",
"siteDomainTipsThree": "配置的站点域名需配置隐性解析到域名:",
"toSite": "访问站点"
}

View File

@ -4,7 +4,7 @@
<div class="flex">
<div class="bg-[#F3F6FF] mr-[14px] w-[402px] pt-[30px] pl-[32px] pr-[20px] pb-[60px] timeline-log-wrap">
<div class="flex items-center justify-between">
<span class="text-[20px]">版本信息</span>
<span class="text-page-title">版本信息</span>
<div class="flex-1 w-0 flex justify-end">
<el-button class="text-[#4C4C4C] w-[78px] h-[32px] !bg-transparent" @click="getFrameworkVersionListFn" v-if="!newVersion || (newVersion && newVersion.version_no == versions)">检测更新</el-button>
<el-button class="text-[#4C4C4C] w-[78px] h-[32px]" type="primary" @click="handleUpgrade" v-else>一键升级</el-button>
@ -21,7 +21,7 @@
<div class="flex-1 flex justify-between items-center bg-[#F3F6FF] pt-[34px] pl-[30px] pr-[60px] pb-[62px] timeline-log-wrap">
<div class="flex flex-col">
<div class="flex flex-wrap items-center">
<p class="text-[20px] mr-[20px]">授权信息</p>
<p class="text-page-title mr-[20px]">授权信息</p>
<span class="text-[14px] text-[#666]">{{ authinfo.company_name || '--' }}</span>
</div>
<div class="mt-[46px] ml-[40px] flex flex-wrap">
@ -96,7 +96,7 @@
</el-card>
<el-card class="box-card !border-none " shadow="never" v-if="!loading">
<div class="text-[20px] mb-[20px]">历史版本</div>
<div class="text-page-title mb-[20px]">历史版本</div>
<el-timeline>
<el-timeline-item :timestamp="item['release_time'] + ' 版本:' + item['version_no']" v-for="(item,index) in frameworkVersionList" type="primary" :hollow="true" placement="top" :key="index">
<div class="mt-[10px] p-[20px] bg-overlay rounded-md timeline-log-wrap whitespace-pre" v-if="item['upgrade_log']">

View File

@ -2,7 +2,7 @@
<div class="main-container w-full bg-white" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center">
<span class="text-[20px]">应用管理</span>
<span class="text-page-title">应用管理</span>
</div>
<div class="flex flex-wrap plug-list pb-10 plug-large" v-if="appList.length">
<div v-for="(item, index) in appList" :key="index + 'b'">

View File

@ -32,7 +32,7 @@
:render-after-expand="false" />
</el-form-item>
<el-form-item :label="t('routePath')" prop="router_path" v-show="formData.menu_type != 2">
<el-form-item :label="t('routePath')" prop="router_path" v-show="formData.menu_type == 1">
<el-input v-model="formData.router_path" :placeholder="t('routePathPlaceholder')" class="input-width" />
</el-form-item>
@ -155,7 +155,7 @@ const formRules = computed(() => {
}
],
router_path: [
{ required: formData.menu_type != 2, message: t('routePathPlaceholder'), trigger: 'blur' }
{ required: formData.menu_type == 1, message: t('routePathPlaceholder'), trigger: 'blur' }
],
view_path: [
{ required: formData.menu_type == 1, message: t('viewPathPlaceholder'), trigger: 'blur' }

View File

@ -2,7 +2,7 @@
<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]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addMenu') }}
</el-button>

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addMenu') }}
</el-button>

View File

@ -81,7 +81,7 @@
</div> -->
<div class="w-full p-5 bg-white">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ t('title') }}</span>
<span class="text-page-title">{{ t('title') }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/aliapp" />

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container" v-loading="loading">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form">
<el-card class="box-card !border-none" shadow="never">
@ -9,6 +9,10 @@
<img class="w-[500px]" src="@/app/assets/images/channel/preview.png" alt="">
</el-form-item>
<el-form-item :label="t('isOpen')">
<el-switch v-model="formData.is_open"/>
</el-form-item>
<el-form-item :label="t('PCDomainName')">
<el-input :model-value="formData.request_url" class="input-width" :readonly="true">
<template #append>
@ -20,6 +24,12 @@
</el-card>
</el-form>
<div class="fixed-footer-wrap">
<div class="fixed-footer">
<el-button type="primary" :loading="loading" @click="save(formRef)">{{ t('save') }}</el-button>
</div>
</div>
</div>
</template>
@ -30,6 +40,7 @@ import { getUrl } from '@/app/api/sys'
import { useClipboard } from '@vueuse/core'
import { ElMessage, FormInstance } from 'element-plus'
import { useRoute } from 'vue-router'
import { getPcConfig, setPcConfig } from "@/app/api/pc"
const route = useRoute()
const pageName = route.meta.title
@ -50,6 +61,15 @@ getUrl().then(res => {
loading.value = false
})
/**
* 获取pc配置
*/
getPcConfig().then(res => {
Object.assign(formData, res.data)
formData.is_open = Boolean(Number(formData.is_open))
loading.value = false
})
/**
* 复制
*/
@ -78,6 +98,26 @@ watch(copied, () => {
const visitFn = () => {
window.open(formData.request_url)
}
/**
* 保存
*/
const save = async (formEl: FormInstance | undefined) => {
if (loading.value || !formEl) return
await formEl.validate(async (valid) => {
if (valid) {
loading.value = true
const data = { ...formData }
data.is_open = Number(data.is_open)
setPcConfig(data).then(() => {
loading.value = false
}).catch(() => {
loading.value = false
})
}
})
}
</script>
<style lang="scss" scoped>

View File

@ -1,7 +1,7 @@
<template>
<div class="w-full p-5 bg-white">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ t('title') }}</span>
<span class="text-page-title">{{ t('title') }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container min-h-[300px] p-5">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />
@ -23,7 +23,6 @@
<el-table-column prop="status_name" :label="t('status')" align="left">
<template #default="{ row }">
<div>{{ row.status_name }}</div>
<div class="text-error" v-if="row.status == -1">{{ t('failReason') }}{{ row.fail_reason }}</div>
</template>
</el-table-column>
<el-table-column prop="create_time" :label="t('createTime')" align="center" />
@ -34,6 +33,8 @@
<el-button type="primary" link>
{{ t('preview') }}</el-button>
</el-tooltip>
<el-button type="primary" link v-if="row.status == -1" @click="handleFailReason(row)">
{{ t('failReason') }}</el-button>
</div>
</template>
</el-table-column>
@ -66,6 +67,11 @@
</span>
</template>
</el-dialog>
<el-dialog v-model="failReasonDialogVisible" :title="t('failReason')" width="60%">
<el-scrollbar class="h-[60vh] w-full whitespace-pre p-[20px]">
{{ failReason }}
</el-scrollbar>
</el-dialog>
</div>
</template>
@ -248,6 +254,13 @@ const configElMessageBox = () => {
}).catch((action: string) => {
})
}
const failReason = ref('')
const failReasonDialogVisible = ref(false)
const handleFailReason = (data: any) => {
failReason.value = data.fail_reason
failReasonDialogVisible.value = true
}
</script>
<style lang="scss" scoped>

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container p-5">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('weappAccessFlow')" name="/channel/weapp" />

View File

@ -1,7 +1,7 @@
<template>
<div class="w-full p-5 bg-white">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ t('title') }}</span>
<span class="text-page-title">{{ t('title') }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container p-5">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container p-5">
<div class="flex justify-between items-center mb-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
<el-tab-pane :label="t('wechatAccessFlow')" name="/channel/wechat" />
@ -10,7 +10,7 @@
</el-tabs>
<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-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="batchAcquisitionFn">{{ t('batchAcquisition')
}}</el-button>
</div>

View File

@ -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-page-title">{{pageName}}</span>
<el-button type="primary" @click="addEvent">
{{ t('addDict') }}
</el-button>

View File

@ -1,162 +0,0 @@
<template>
<!-- 内容 -->
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
<div class="edit-attr-item-wrap">
<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 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]">
<span class="text-[14px]">{{item.title}}</span>
<span class="text-[12px] text-[#999] mt-[8px]">{{item.desc}}</span>
</div>
</div>
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
</div>
</div>
</div>
<el-button class="w-full" @click="addAddon">{{ t('addAddon') }}</el-button>
</el-form>
</div>
<el-dialog v-model="showDialog" :title="t('addonListTips')" width="600px" :close-on-press-escape="false" :close-on-click-modal="false">
<div>
<el-table :data="addonTableData.data" size="large" v-loading="addonTableData.loading" @current-change="handleCurrentChange" highlight-current-row max-height="500px">
<template #empty>
<span>{{ !addonTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column :label="t('addonIcon')" width="120" align="center">
<template #default="{ row }">
<el-image class="w-[50px] h-[50px]" v-if="row.icon" :src="img(row.icon)" fit="contain"/>
</template>
</el-table-column>
<el-table-column prop="title" :show-overflow-tooltip="true" width="120" :label="t('addonTitle')" />
<el-table-column prop="desc" :show-overflow-tooltip="true" :label="t('addonDesc')" />
</el-table>
</div>
</el-dialog>
</div>
<!-- 样式 -->
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
<!-- 组件样式 -->
<slot name="style"></slot>
</div>
</template>
<script lang="ts" setup>
import { t } from '@/lang'
import useDiyStore from '@/stores/modules/diy'
import { ref, reactive, onMounted, nextTick } from 'vue'
import { img } from '@/utils/common'
import { getWapIndexList } from '@/app/api/sys'
import Sortable from 'sortablejs'
import { range } from 'lodash-es'
const diyStore = useDiyStore()
diyStore.editComponent.ignore = [] //
//
diyStore.editComponent.verify = (index: number) => {
const res = { code: true, message: '' }
// if (diyStore.value[index].list.length === 0) {
// res.code = false;
// res.message = t('selectAddonTips');
// }
return res
}
const showDialog = ref(false)
const addonBoxRef = ref()
onMounted(() => {
nextTick(() => {
const sortable = Sortable.create(addonBoxRef.value, {
group: 'item-wrap',
animation: 200,
onEnd: event => {
const temp = diyStore.editComponent.list[event.oldIndex!]
diyStore.editComponent.list.splice(event.oldIndex!, 1)
diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
sortable.sort(
range(diyStore.editComponent.list.length).map(value => {
return value.toString()
})
)
}
})
})
})
const addonTableData = reactive({
page: 1,
limit: 10,
total: 0,
loading: true,
data: [],
searchParam: {
title: '',
key: '',
}
})
//
const loadAddonList = (page: number = 1) => {
addonTableData.loading = true
addonTableData.page = page
getWapIndexList({
...addonTableData.searchParam
}).then(res => {
addonTableData.loading = false
addonTableData.data = res.data
addonTableData.total = res.data.length
}).catch(() => {
addonTableData.loading = false
})
}
loadAddonList()
const handleCurrentChange = (val:any) => {
const item:any = {
id: diyStore.generateRandom(),
key: '',
title: '',
url: '',
icon: '',
desc: ''
}
for (let k in val) {
item[k] = val[k]
}
diyStore.editComponent.list.push(item)
showDialog.value = false
}
const addAddon = () => {
showDialog.value = true
}
defineExpose({})
</script>
<style lang="scss" scoped>
</style>

View File

@ -32,7 +32,7 @@
<h3 class="mb-[10px]">{{ t('marginSet') }}</h3>
<el-form label-width="80px" class="px-[10px]">
<el-form-item :label="t('marginBoth')">
<el-slider v-model="diyStore.global.template.margin.both" show-input size="small" class="ml-[10px] horz-blank-slider"/>
<el-slider v-model="diyStore.global.template.margin.both" show-input size="small" @input="inputBoth" class="ml-[10px] horz-blank-slider"/>
</el-form-item>
</el-form>
</div>
@ -60,6 +60,15 @@ watch(
}
)
//
const inputBoth = (value:any)=>{
diyStore.value.forEach((item,index)=>{
item.margin.both = value;
})
}
defineExpose({})
</script>

View File

@ -20,11 +20,11 @@
<el-form label-width="80px" class="px-[10px]">
<ul class="layout">
<li v-for="(li,i) in selectTemplate.dimensionScale" :key="i" :class="[selectTemplate.className]" :style="{ width: rubikCubeList[i].widthStyle, height: rubikCubeList[i].imgHeight + 'px' }">
<div class="have-preview-image" v-show="diyStore.editComponent.list[i].imageUrl">
<img class="!w-full !h-full" :src="img(diyStore.editComponent.list[i].imageUrl)"/>
<li v-for="(li,i) in selectTemplate.dimensionScale" :key="i" :class="[selectTemplate.className]">
<div class="have-preview-image" v-show="diyStore.editComponent.list[i].imageUrl && diyStore.editComponent.list[i].imageUrl != 'static/resource/images/diy/figure.png'">
<img :src="img(diyStore.editComponent.list[i].imageUrl)"/>
</div>
<div class="empty" :class="[selectTemplate.className]" v-show="!diyStore.editComponent.list[i].imageUrl">
<div class="empty" :class="[selectTemplate.className]" v-show="!diyStore.editComponent.list[i].imageUrl || diyStore.editComponent.list[i].imageUrl == 'static/resource/images/diy/figure.png'">
<p>{{li.name}}</p>
<p>{{li.desc}}</p>
</div>
@ -267,25 +267,11 @@ const templateList = ref([
}
])
const rubikCubeList = ref([])
const selectTemplate = computed(() => {
let data
templateList.value.forEach((item) => {
if (item.className == diyStore.editComponent.mode) {
data = item
rubikCubeList.value = JSON.parse(JSON.stringify(diyStore.editComponent.list))
if (item.className == 'row2-lt-of2-rt') {
calcFourSquare()
} else if (item.className == 'row1-lt-of2-rt') {
calcRowOneLeftOfTwoRight()
} else if (item.className == 'row1-tp-of2-bm') {
calcRowOneTopOfTwoBottom()
} else if (item.className == 'row1-lt-of1-tp-of2-bm') {
calcRowOneLeftOfOneTopOfTwoBottom()
} else {
calcSingleRow(item.className)
}
}
})
return data
@ -343,152 +329,6 @@ const handleHeight = (isCalcHeight:boolean = false) => {
}
defineExpose({})
/**
* 魔方单行多个平分宽度
* 公式
* 宽度屏幕宽度/2示例375/2=187.5
* 比例原图高/原图宽示例322/690=0.46
* 高度宽度*比例示例187.5*0.46=86.25
*/
const calcSingleRow = (type:any) => {
let maxHeight = 0
let paramsRatio = 2
let paramsWidth = 'calc(100% / 2)'
if (type == 'row1-of3') {
paramsRatio = 3
paramsWidth = 'calc(100% / 3)'
}
if (type == 'row1-of4') {
paramsRatio = 4
paramsWidth = 'calc(100% / 4)'
}
rubikCubeList.value.forEach((item:any, index) => {
const ratio = item.imgHeight / item.imgWidth
const width = 330
item.imgWidth = width / paramsRatio
item.imgHeight = item.imgWidth * ratio
if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item.imgHeight
})
rubikCubeList.value.forEach((item:any, index) => {
item.widthStyle = paramsWidth
item.imgHeight = maxHeight
})
};
/**
* 魔方四方型各占50%
*/
const calcFourSquare = () => {
let maxHeightFirst = 0
let maxHeightTwo = 0
rubikCubeList.value.forEach((item:any, index) => {
const ratio = item.imgHeight / item.imgWidth
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio
//
if (index <= 1) {
if (maxHeightFirst == 0 || maxHeightFirst < item.imgHeight) {
maxHeightFirst = item.imgHeight
}
} else if (index > 1) {
if (maxHeightTwo == 0 || maxHeightTwo < item.imgHeight) {
maxHeightTwo = item.imgHeight
}
}
})
rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth = 'calc(100% / 2)'
item.widthStyle = item.imgWidth
if (index <= 1) {
item.imgHeight = maxHeightFirst
} else if (index > 1) {
item.imgHeight = maxHeightTwo
}
})
}
/**
* 魔方1左2右
*/
const calcRowOneLeftOfTwoRight = () => {
let rightHeight = 0 //
let divide = 'left' // leftright
if (rubikCubeList.value[1].imgWidth === rubikCubeList.value[2].imgWidth) divide = 'right'
rubikCubeList.value.forEach((item:any, index) => {
if (index == 0) {
const ratio = item.imgHeight / item.imgWidth //
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio
rightHeight = item.imgHeight / 2
item.imgWidth += 'px'
} else {
item.imgWidth = rubikCubeList.value[0].imgWidth
item.imgHeight = rightHeight
}
})
}
/**
* 魔方1上2下
*/
const calcRowOneTopOfTwoBottom = () => {
let maxHeight = 0
rubikCubeList.value.forEach((item:any, index) => {
const ratio = item.imgHeight / item.imgWidth //
if (index == 0) {
item.imgWidth = 330
} else if (index > 0) {
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
}
item.imgHeight = item.imgWidth * ratio
//
if (index > 0 && (maxHeight == 0 || maxHeight < item.imgHeight)) {
maxHeight = item.imgHeight
}
})
rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth += 'px'
item.widthStyle = item.imgWidth
if (index > 0) item.imgHeight = maxHeight
})
}
/**
* 魔方1左3右
*/
const calcRowOneLeftOfOneTopOfTwoBottom = () => {
rubikCubeList.value.forEach((item:any, index) => {
//
if (index == 0) {
const ratio = item.imgHeight / item.imgWidth //
item.imgWidth = 330
item.imgWidth = item.imgWidth / 2
item.imgHeight = item.imgWidth * ratio
} else if (index == 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth
item.imgHeight = rubikCubeList.value[0].imgHeight / 2
} else if (index > 1) {
item.imgWidth = rubikCubeList.value[0].imgWidth / 2
item.imgHeight = rubikCubeList.value[1].imgHeight
}
})
rubikCubeList.value.forEach((item:any, index) => {
item.imgWidth += 'px'
})
}
</script>
<style lang="scss" scoped>
@ -675,6 +515,7 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 322px;
background: #ffffff;
}
}
@ -684,9 +525,9 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
border-bottom: 1px transparent solid;
div.have-preview-image {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
@ -697,6 +538,7 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
@ -744,6 +586,7 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 320px;
background: #ffffff;
}
}
@ -756,6 +599,7 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
@ -768,6 +612,7 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}
@ -779,6 +624,7 @@ const calcRowOneLeftOfOneTopOfTwoBottom = () => {
div.have-preview-image {
text-align: center;
height: 100%;
line-height: 160px;
background: #ffffff;
}
}

View File

@ -4,7 +4,7 @@
<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>
<iframe :id="'previewIframe_' + type" 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">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="dialogVisible = true">{{ t('addDiyPage') }}</el-button>
</div>
@ -52,11 +52,11 @@
<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 type="primary" link @click="toPreview(row)">{{ t('preview') }}</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 type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
<el-button v-if="row.is_default == 0 || row.type == 'DIY_PAGE'" type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
</template>
</el-table-column>
@ -163,10 +163,11 @@ const addEvent = async (formEl: FormInstance | undefined) => {
if (valid) {
dialogVisible.value = false
const query = { type: formData.type, title: formData.title }
router.push({
const url = router.resolve({
path: '/decorate/edit',
query
})
window.open(url.href)
}
})
}
@ -350,4 +351,4 @@ const resetForm = (formEl: FormInstance | undefined) => {
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@ -4,7 +4,7 @@
<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>
<iframe :id="'previewIframe_' + type" 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">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{ pageName }}</span>
</div>
<el-table class="mt-[20px]" :data="bottomNavTableData.data" size="large" v-loading="bottomNavTableData.loading">
@ -87,4 +87,4 @@
</script>
<style lang="scss" scoped>
</style>
</style>

View File

@ -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-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">

View File

@ -2,7 +2,7 @@
<el-card class="box-card !border-none" shadow="never" v-loading="payLoading">
<!-- 设置支付配置 -->
<div class="flex justify-between items-center">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<div class="mt-[10px]">

View File

@ -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-page-title">{{pageName}}</span>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t('editPersonal') }}</span>
<span class="text-page-title">{{ t('editPersonal') }}</span>
</div>
<el-card class="box-card !border-none" shadow="never">
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">

View File

@ -23,7 +23,7 @@
<span :class="['mr-[12px] cursor-pointer', {'text-[var(--el-color-primary)]': params.app == ''}]" @click="cutAppFn('')">所有应用</span>
<span :class="['mr-[12px] cursor-pointer', {'text-[var(--el-color-primary)]': params.app == item.key}]" @click="cutAppFn(item.key)" v-for="(item,index) in addonList" :key="index">{{item.title}}</span>
</div>
<el-input v-model="params.keywords" class="!w-[300px] !h-[34px]" placeholder="输入要搜索的站点名称" @keyup.enter.native="query">
<el-input v-model="params.keywords" class="!w-[300px] !h-[34px]" placeholder="输入要搜索的站点名称" @keyup.enter.native="getHomeSiteFn()">
<template #suffix>
<el-icon @click.stop="getHomeSiteFn()" class="cursor-pointer">
<Search />

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t("personal") }}</span>
<span class="text-page-title">{{ t("personal") }}</span>
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t("editPersonal") }}</span>
</div>
<el-card class="box-card !border-none" shadow="never">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t('editPersonal') }}</span>
<span class="text-page-title">{{ t('editPersonal') }}</span>
</div>
<el-card class="box-card !border-none" shadow="never">
<el-form :model="saveInfo" label-width="90px" ref="formRef" class="page-form">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container w-full pt-[64px] bg-white" v-loading="loading">
<div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px]">{{ t('personal') }}</span>
<span class="text-page-title">{{ t('personal') }}</span>
<span class="text-[14px] text-[#999] cursor-pointer" @click="toEditPersonal">{{ t('editPersonal') }}</span>
</div>
<el-card class="box-card !border-none" shadow="never">

View File

@ -2,7 +2,7 @@
<div class="pt-[59px] px-[20px] app-store" v-loading="authLoading">
<div>
<div class="flex justify-between items-center h-[32px] mb-4">
<span class="text-[20px] text-[#222]">{{ t('localAppText') }}</span>
<span class="text-page-title text-[#222]">{{ t('localAppText') }}</span>
<el-input class="!w-[250px]" :placeholder="t('search')" v-model="search_name" @keyup.enter="query">
<template #suffix>
<el-icon class="el-input__icon cursor-pointer" size="14px" @click="query">

View File

@ -1,6 +1,6 @@
<template>
<div class="box-border pt-[64px]">
<div class="text-[20px] text-[#222] mb-[32px] pl-[14px]">工具管理</div>
<div class="text-page-title text-[#222] mb-[32px] pl-[14px]">工具管理</div>
<div class="flex flex-wrap mt-[28px]">
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/addon')">
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">

View File

@ -15,6 +15,7 @@
<el-form :model="form" ref="formRef" :rules="formRules">
<el-form-item prop="username">
<el-input v-model="form.username" :placeholder="t('userPlaceholder')"
autocomplete="off"
@keyup.enter="handleLogin(formRef)" class="h-[40px] input-with-select">
<template #prepend>
<icon name="element-User" />
@ -24,6 +25,7 @@
<el-form-item prop="password">
<el-input v-model="form.password" :placeholder="t('passwordPlaceholder')" type="password"
autocomplete="new-password"
@keyup.enter="handleLogin(formRef)" :show-password="true"
class="h-[40px] input-with-select">
<template #prepend>
@ -57,6 +59,7 @@
<el-form :model="form" ref="formRef" :rules="formRules">
<el-form-item prop="username">
<el-input v-model="form.username" @keyup.enter="handleLogin(formRef)"
autocomplete="off"
class="w-50 m-1 h-[40px]" :placeholder="t('userPlaceholder')">
<template #prefix>
<icon name="element-User" />
@ -66,6 +69,7 @@
<el-form-item prop="password">
<el-input type="password" v-model="form.password" @keyup.enter="handleLogin(formRef)"
autocomplete="new-password"
:show-password="true" class="w-50 m-1 h-[40px]"
:placeholder="t('passwordPlaceholder')">
<template #prefix>

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">

View File

@ -7,7 +7,7 @@
</el-form-item>
<el-form-item :label="t('mobile')" prop="mobile">
<el-input v-model="formData.mobile" clearable :placeholder="t('mobilePlaceholder')" type="number" class="input-width" />
<el-input v-model="formData.mobile" clearable :placeholder="t('mobilePlaceholder')" @keyup="filterNumber($event)" class="input-width" />
</el-form-item>
<el-form-item :label="t('nickname')">
@ -37,6 +37,7 @@ import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addMember, getMemberList, getMemberNo } from '@/app/api/member'
import { filterNumber } from '@/utils/common'
const showDialog = ref(false)
const loading = ref(false)

View File

@ -8,7 +8,7 @@
<el-input v-model="formData.memo" type="textarea" rows="4" clearable :placeholder="t('memoPlaceholder')" class="input-width"/>
</el-form-item>
<el-form-item :label="t('sort')" prop="sort">
<el-input v-model="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" type="number" />
<el-input v-model="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
</el-form-item>
</el-form>
@ -27,6 +27,7 @@ import { ref, reactive, computed } from 'vue'
import { t } from '@/lang'
import type { FormInstance } from 'element-plus'
import { addMemberLabel, updateMemberLabel, getMemberLabelInfo } from '@/app/api/member'
import { filterNumber } from '@/utils/common'
const showDialog = ref(false)
const loading = ref(false)

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
<el-button type="primary" @click="addEvent">{{ t('addMemberLabel') }}</el-button>
</div>

View File

@ -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-page-title">{{ pageName }}</span>
<el-button type="primary" @click="addEvent">{{ t('addMember') }}</el-button>
</div>
@ -48,7 +48,7 @@
<span>{{ !memberTableData.loading ? t('emptyData') : '' }}</span>
</template>
<el-table-column prop="member_no" :label="t('memberNo')" min-width="120" />
<el-table-column prop="nickname" :show-overflow-tooltip="true" :label="t('nickname')" min-width="170">
<el-table-column prop="nickname" :show-overflow-tooltip="true" :label="t('memberInfo')" min-width="170">
<template #default="{ row }">
<div class="flex items-center">
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.headimg" :src="img(row.headimg)" alt="">
@ -69,9 +69,9 @@
<el-table-column prop="balance" :label="t('balance')" min-width="130" align="right" />
<el-table-column prop="member_label" :label="t('lable')" min-width="120" align="center">
<template #default="{ row }">
<div class="flex flex-col items-start">
<div class="flex flex-col items-center">
<div v-for="(item, key) in row.member_label_array" class="my-[3px]" :key="key">
<el-tag class="ml-[13px]" type="info">{{ item.label_name }}</el-tag>
<el-tag type="info">{{ item.label_name }}</el-tag>
</div>
</div>
</template>

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none base-bg !px-[35px]" shadow="never">
<el-row class="flex">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[5px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="ruleFormRef" class="page-form" v-loading="loading">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
</div>
<div class="mt-[20px]">
<el-table :data="agreementTableData.data" size="large" v-loading="agreementTableData.loading">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="ruleFormRef" :rules="rules" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
@ -11,11 +11,11 @@
</el-form-item>
<el-form-item :label="t('cashWithdrawalAmount')" v-if="formData.is_open" prop="min">
<el-input v-model="formData.min" type="number" class="input-width" :placeholder="t('cashWithdrawalAmountPlaceholder')" />
<el-input v-model="formData.min" @keyup="filterDigit($event)" class="input-width" :placeholder="t('cashWithdrawalAmountPlaceholder')" />
</el-form-item>
<el-form-item :label="t('commissionRatio')" v-if="formData.is_open" prop="rate">
<el-input v-model="formData.rate" type="number" class="input-width" :placeholder="t('commissionRatioPlaceholder')" />
<el-input v-model="formData.rate" @keyup="filterDigit($event)" class="input-width" :placeholder="t('commissionRatioPlaceholder')" />
<span class="ml-2">%</span>
</el-form-item>
<el-form-item :label="t('audit')" v-if="formData.is_open" class="items-center">
@ -53,6 +53,7 @@ import { t } from '@/lang'
import { getCashOutConfig, setCashOutConfig, getTransfertype } from '@/app/api/member'
import { FormRules, FormInstance } from 'element-plus'
import { useRoute } from 'vue-router'
import { filterDigit } from '@/utils/common'
const route = useRoute()
const pageName = route.meta.title

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="150px" ref="ruleFormRef" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">

View File

@ -10,7 +10,7 @@
</el-form-item>
<el-form-item :label="t('length')" prop="length">
<el-input v-model="formData.length" :placeholder="t('lengthPlaceholder')" class="input-width" clearable type="number" @change="getMemberNo(ruleFormRef)"/>
<el-input v-model="formData.length" :placeholder="t('lengthPlaceholder')" class="input-width" clearable @keyup="filterNumber($event)" @change="getMemberNo(ruleFormRef)"/>
<div class="form-tip">{{ t('lengthTips') }}</div>
</el-form-item>
@ -32,6 +32,7 @@ import { reactive, ref } from 'vue'
import { t } from '@/lang'
import { getMemberConfig, setMemberConfig } from '@/app/api/member'
import { FormInstance, FormRules } from 'element-plus'
import { filterNumber } from '@/utils/common'
const loading = ref(true)
const ruleFormRef = ref<FormInstance>({})

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container" v-loading="noticeTableData.loading">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-base">{{ t('buyerNotice') }}</h3>

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">

View File

@ -2,7 +2,7 @@
<el-card class="box-card !border-none" shadow="never" v-loading="payLoading">
<!-- 设置支付配置 -->
<div class="flex justify-between items-center" v-if="!payLoading">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
<el-button type="primary" @click="isEdit = true" ref="setConfigBtn">{{ t('setConfig') }}</el-button>
</div>
<el-card class="box-card box-pay-card !border-none mt-[20px]" shadow="never"

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
</div>
<div class="mt-[20px]">
<el-table :data="smsTableData.data" size="large" v-loading="smsTableData.loading">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="recordsTableData.searchParam" ref="searchFormRef">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{pageName}}</span>
</div>
<div class="mt-[16px]">
<el-table :data="storageTableData.data" size="large" v-loading="loading">

View File

@ -1,13 +1,11 @@
<template>
<div class="main-container">
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form"
v-loading="loading">
<el-form :model="formData" label-width="150px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('websiteInfo') }}</h3>
<el-form-item :label="t('siteName')" prop="site_name">
<el-input v-model="formData.site_name" :placeholder="t('siteNamePlaceholder')" class="input-width"
clearable maxlength="20" />
<el-input v-model="formData.site_name" :placeholder="t('siteNamePlaceholder')" class="input-width" clearable maxlength="20" />
</el-form-item>
<el-form-item :label="t('logo')">
@ -25,20 +23,17 @@
</el-form-item>
<el-form-item :label="t('keywords')">
<el-input v-model="formData.keywords" :placeholder="t('keywordsPlaceholder')" class="input-width"
clearable maxlength="20" />
<el-input v-model="formData.keywords" :placeholder="t('keywordsPlaceholder')" class="input-width" clearable maxlength="20" />
</el-form-item>
<el-form-item :label="t('desc')">
<el-input v-model="formData.desc" type="textarea" rows="4" clearable :placeholder="t('descPlaceholder')"
class="input-width" maxlength="100" />
<el-input v-model="formData.desc" type="textarea" rows="4" clearable :placeholder="t('descPlaceholder')" class="input-width" maxlength="100" />
</el-form-item>
</el-card>
<el-card class="box-card !border-none" shadow="never">
<h3 class="panel-title !text-sm">{{ t('frontEndInfo') }}</h3>
<el-form-item :label="t('frontEndName')">
<el-input v-model="formData.front_end_name" :placeholder="t('frontEndNamePlaceholder')"
class="input-width" clearable maxlength="20" />
<el-input v-model="formData.front_end_name" :placeholder="t('frontEndNamePlaceholder')" class="input-width" clearable maxlength="20" />
</el-form-item>
<el-form-item :label="t('frontEndLogo')">
@ -48,8 +43,7 @@
<el-card class="box-card !border-none" shadow="never" v-if="app_type == 'admin'">
<h3 class="panel-title !text-sm">{{ t('serviceInformation') }}</h3>
<el-form-item :label="t('contactsTel')">
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width"
clearable maxlength="20" />
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" />
</el-form-item>
<el-form-item :label="t('wechatCode')">
<upload-image v-model="formData.wechat_code" />

View File

@ -9,7 +9,7 @@
</template>
</el-alert>
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{pageName}}</span>
<span class="text-page-title">{{pageName}}</span>
</div>
<el-form :model="formData" label-width="200px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
<el-card class="box-card !border-none" shadow="never">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{ pageName }}</span>
<el-button type="primary" @click="showEvent">{{ t('addVersion') }}</el-button>
</div>
<div class="mt-[10px]">

View File

@ -1,7 +1,7 @@
<template>
<div class="main-container">
<div class="flex ml-[18px] justify-between items-center mt-[20px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
<el-card class="box-card !border-none mt-[5px]" shadow="never">

View File

@ -21,7 +21,7 @@
</el-form-item> -->
<el-form-item :label="t('manager')" prop="uid">
<el-select v-model="formData.uid" :placeholder="t('managerPlaceholder')" class="input-width" filterable>
<el-select v-model="formData.uid" :placeholder="t('managerPlaceholder')" class="input-width" filterable autocomplete="off">
<el-option :label="t('newAddManager')" :value="0">
<template #default>
<div class="flex items-center">
@ -45,17 +45,17 @@
<div v-show="formData.uid === 0">
<el-form-item :label="t('username')" prop="username">
<el-input v-model="formData.username" clearable :placeholder="t('usernamePlaceholder')"
class="input-width" />
class="input-width" autocomplete="new-password"/>
</el-form-item>
<el-form-item :label="t('password')" prop="password">
<el-input v-model="formData.password" clearable :placeholder="t('passwordPlaceholder')"
class="input-width" :show-password="true" type="password" />
class="input-width" :show-password="true" type="password" autocomplete="new-password"/>
</el-form-item>
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
<el-input v-model="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')"
type="password" :show-password="true" clearable class="input-width" />
type="password" :show-password="true" clearable class="input-width" autocomplete="new-password" />
</el-form-item>
</div>
</div>
@ -73,6 +73,16 @@
</el-form-item>
</div>
<el-form-item :label="t('siteDomain')" prop="site_domain">
<el-input v-model="formData.site_domain" clearable :placeholder="t('siteDomainPlaceholder')"
class="input-width" />
<div>
<p class="text-[12px] text-[#a9a9a9] leading-normal mt-[5px]">{{ t('siteDomainTips') }}</p>
<p class="text-[12px] text-[#a9a9a9] leading-normal mt-[5px]">{{ t('siteDomainTipsTwo') }}</p>
<p class="text-[12px] text-[#a9a9a9] leading-normal mt-[5px]">{{ t('siteDomainTipsThree') }}{{ domain }}</p>
</div>
</el-form-item>
<el-form-item :label="t('expireTime')" prop="expire_time" class="input-width">
<el-date-picker class="flex-1 !flex" v-model="formData.expire_time" clearable type="datetime"
:placeholder="t('expireTimePlaceholder')" />
@ -102,6 +112,7 @@ const loading = ref(true)
const groupList = ref([])
const siteUser = ref([])
const siteType = ref([])
const domain = location.hostname
getAllUserList({}).then(({ data }) => {
siteUser.value = data
}).catch()
@ -121,6 +132,7 @@ const initialFormData = {
password: '',
confirm_password: '',
expire_time: end,
site_domain: '',
group_id: ''
}
const formData: Record<string, any> = reactive({ ...initialFormData })

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{ pageName }}</span>
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addSiteGroup') }}
</el-button>

View File

@ -3,10 +3,15 @@
<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="addEvent">
{{ t('addSite') }}
</el-button>
<span class="text-page-title">{{ pageName }}</span>
<div>
<el-button type="primary" class="w-[100px]" @click="addEvent">
{{ t('addSite') }}
</el-button>
<el-button type="default" class="w-[100px]" @click="toSiteLink">
{{ t('toSite') }}
</el-button>
</div>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
@ -15,6 +20,10 @@
<el-input v-model="siteTableData.searchParam.keywords" :placeholder="t('siteNamePlaceholder')" />
</el-form-item>
<el-form-item :label="t('siteDomain')" prop="site_domain">
<el-input v-model="siteTableData.searchParam.site_domain" :placeholder="t('siteDomainPlaceholder')" />
</el-form-item>
<el-form-item :label="t('app')" prop="app_id">
<el-select v-model="siteTableData.searchParam.app" clearable @change="appChangeFn"
:placeholder="t('appIdPlaceholder')" class="input-width">
@ -92,6 +101,7 @@
</el-table-column>
<el-table-column prop="group_name" :label="t('groupId')" width="150" :show-overflow-tooltip="true" />
<el-table-column prop="site_domain" :label="t('siteDomain')" width="150" :show-overflow-tooltip="true" />
<el-table-column prop="create_time" :label="t('createTime')" width="250"
:show-overflow-tooltip="true" />
<el-table-column prop="expire_time" :label="t('expireTime')" width="250" :show-overflow-tooltip="true">
@ -114,16 +124,11 @@
<el-table-column :label="t('operation')" min-width="250" align="right" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="toSiteLink(row)">
<!-- <a href="javascript:;" title="启动站点" class="iconfont iconicon_huojian"></a>-->
访问站点
</el-button>
<el-button type="primary" link @click="openClose(row.status, row.site_id)"
v-if="row.status == 1 || row.status == 3">{{ row.status == 1 ? t('closeTxt') : t('openTxt')
}}</el-button>
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-button type="primary" link @click="deleteEvent(row)">{{ t('delete') }}</el-button>
<el-button type="primary" link @click="urlEvent(row)">{{ t('url') }}</el-button>
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
</template>
</el-table-column>
@ -143,15 +148,14 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { img } from '@/utils/common'
import { getToken, img } from '@/utils/common'
import { t } from '@/lang'
import { getSiteList, getSiteGroupAll, getStatusList, closeSite, openSite, deleteSite } from '@/app/api/site'
import { ElMessageBox, FormInstance, ElMessage } from 'element-plus'
import { ElMessageBox, FormInstance } from 'element-plus'
import { useRouter, useRoute } from 'vue-router'
import EditSite from '@/app/views/site/components/edit-site.vue'
import { getInstalledAddonList } from '@/app/api/addon'
// import { CollectionTag } from '@element-plus/icons-vue'
// import { deleteMenu } from "@/app/api/sys"
import useUserStore from '@/stores/modules/user'
const route = useRoute()
const pageName = route.meta.title
@ -173,9 +177,9 @@ const siteTableData = reactive({
group_id: '',
app: 'all',
status: '',
site_domain: '',
create_time: [],
expire_time: []
}
})
siteTableData.searchParam.status = route.query.id || ''
@ -264,18 +268,6 @@ const infoEvent = (data: any) => {
router.push({ path: '/admin/site/info', query: { id: data.site_id } })
}
/**
* 站点域名
* @param data
*/
const urlEvent = (data: any) => {
ElMessage({
message: t('siteUrlDevelopMessage'),
grouping: true,
type: 'success'
})
}
/**
* 编辑站点详情
* @param data
@ -289,9 +281,11 @@ const editEvent = (data: any) => {
* 站点登录
* @param data
*/
const toSiteLink = (data: any) => {
window.localStorage.setItem('site.siteId', data.site_id)
window.open(`${location.origin}/site/`)
const toSiteLink = () => {
window.localStorage.setItem('site.token', getToken())
window.localStorage.setItem('site.comparisonTokenStorage', getToken())
window.localStorage.setItem('site.userinfo', JSON.stringify(useUserStore().userInfo))
window.open(`${location.origin}/home/index`)
}
const openClose = (i, site_id) => {

View File

@ -2,7 +2,7 @@
<div class="main-container">
<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-page-title">{{ pageName }}</span>
</div>
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
<el-form :inline="true" :model="userTableData.searchParam" ref="searchFormRef">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[10px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane :label="t('developmentProcess')" name="developmentProcess">

View File

@ -2,7 +2,7 @@
<div class="main-container">
<el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center mb-[10px]">
<span class="text-[20px]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
</div>
<el-tabs v-model="activeName" class="demo-tabs">
<el-tab-pane :label="t('codeGeneration')" name="codeGeneration">

View File

@ -2,7 +2,7 @@
<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>
<span class="text-page-title">{{ pageName }}</span>
</div>
<div class="bg-[#fff] pb-[20px] mb-3">
<p class="pt-[20px] pb-[10px] text-sm">{{ t('serverInformation') }}</p>

View File

@ -2,7 +2,7 @@
<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]">{{ pageName }}</span>
<span class="text-page-title">{{ pageName }}</span>
<el-button type="primary" @click="showEvent">{{ t('addCron') }}</el-button>
</div>
<el-alert class="warm-prompt " type="info">

View File

@ -2,7 +2,7 @@
<div>
<div @click="show">
<slot>
<el-input v-model="value.title" :placeholder="t('linkPlaceholder')" readonly>
<el-input v-model="value.title" :placeholder="t('linkPlaceholder')" readonly class="link-input">
<template #suffix>
<div @click.stop="clear">
<el-icon v-if="value.name">
@ -207,4 +207,8 @@ defineExpose({
})
</script>
<style lang="scss" scoped></style>
<style lang="scss">
.link-input .el-input__inner{
cursor: pointer;
}
</style>

View File

@ -2,18 +2,15 @@
<div>
<div @click="show">
<slot>
<div v-if="value.heatMapData.length">{{ t('selected') }}<span class="text-primary p-[4px]">{{
value.heatMapData.length }}</span>{{ t('selectedAfterHotArea') }}</div>
<div v-else>{{ t('addHotArea') }}</div>
<div v-if="value.heatMapData.length" class="cursor-pointer">{{ t('selected') }}<span class="text-primary p-[4px]">{{ value.heatMapData.length }}</span>{{ t('selectedAfterHotArea') }}</div>
<div v-else class="cursor-pointer">{{ t('addHotArea') }}</div>
</slot>
</div>
<el-dialog v-model="showDialog" :title="t('hotAreaSet')" width="45%" :close-on-press-escape="false"
:destroy-on-close="true" :close-on-click-modal="false">
<el-dialog v-model="showDialog" :title="t('hotAreaSet')" width="810px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
<div class="flex">
<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 class="hot-area-img-wrap content-box relative bg-gray-100 border border-dashed border-gray-500 bg-no-repeat" :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 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 }"
@ -32,16 +29,14 @@
<el-form label-width="80px" class="pl-[20px]">
<h3 class="mb-[10px] text-lg text-black">{{ t('hotAreaManage') }}</h3>
<el-button type="primary" plain size="small" class="mb-[10px]" @click="addArea">{{ t('addHotArea')
}}</el-button>
<el-button type="primary" plain size="small" class="mb-[10px]" @click="addArea">{{ t('addHotArea') }}</el-button>
<div class="overflow-y-auto h-[300px]">
<template v-for="(item, index) in dragBoxArr" :key="index">
<div class="mb-[16px]" v-if="item">
<el-form-item :label="t('hotArea') + (index + 1)">
<div class="flex items-center">
<diy-link v-model="item.link" />
<icon class="del cursor-pointer mx-[10px]" name="element-CircleCloseFilled"
color="#bbb" size="20px" @click="dragBoxArr.splice(index, 1)" />
<icon class="del cursor-pointer mx-[10px]" name="element-CircleCloseFilled" color="#bbb" size="20px" @click="dragBoxArr.splice(index, 1)" />
</div>
</el-form-item>
</div>
@ -85,26 +80,42 @@ const value: any = computed({
}
})
/**
* 公式
* 宽度400
* 比例原图高/原图宽示例466/698=0.66
* 高度宽度*比例示例400*0.66=264
*/
const showDialog = ref(false)
const contentBoxWidth = ref(400)
const contentBoxHeight = ref(400)
const num = ref(4)//
const dragBoxArr: any = reactive([])
const imgRatio = ref(1); //
//
const areaRadio = ref(0.25) //
const areaWidth = ref(100)
const areaHeight = ref(100)
const areaNum = ref(4); //
//
const addArea = () => {
let left = dragBoxArr.length % num.value * 100
let top = Math.floor(dragBoxArr.length / num.value) * 100
if (top >= contentBoxWidth.value) {
let left = dragBoxArr.length % areaNum.value * areaWidth.value
let top = Math.floor(dragBoxArr.length / areaNum.value) * areaHeight.value
let edgeHeight = top + (areaHeight.value / 2)
if (top >= contentBoxHeight.value || edgeHeight >= contentBoxHeight.value) {
top = 0
left = 0
}
dragBoxArr.push({
left: left,
top: top,
width: 100,
height: 100,
left,
top,
width: areaWidth.value,
height: areaHeight.value,
unit: 'px',
link: {
name: ''
@ -530,6 +541,17 @@ const show = () => {
})
return
}
//
imgRatio.value = value.value.imgHeight / value.value.imgWidth;
//
contentBoxHeight.value = Math.floor(contentBoxWidth.value * imgRatio.value);
areaWidth.value = Math.floor(areaRadio.value * contentBoxHeight.value);
areaHeight.value = areaWidth.value;
areaNum.value = Math.floor(contentBoxWidth.value / areaWidth.value)
if (Object.keys(value.value.heatMapData).length) {
dragBoxArr.splice(0, dragBoxArr.length, ...value.value.heatMapData)
} else {
@ -577,6 +599,10 @@ defineExpose({
background-color: rgba(255, 255, 255, 0.7);
}
.hot-area-img-wrap{
background-size: 100%;
}
.box1,
.box2,
.box3,

View File

@ -1,14 +1,14 @@
<template>
<div class="flex border-t border-b main-wrap border-color w-full" :class="scene == 'select' ? 'h-[40vh]' : 'h-full'">
<!-- 分组 -->
<div class="group-wrap w-[180px] p-[15px] h-full border-r border-color flex flex-col">
<el-input v-model="categoryParam.name" class="m-0" :placeholder="t('upload.attachmentCategoryPlaceholder')"
clearable prefix-icon="Search" @input="getAttachmentCategoryList()" />
<div class="group-list flex-1 my-[10px]">
<div class="group-list flex-1 my-[10px] h-0">
<el-scrollbar>
<div class="group-item p-[10px] leading-none text-xs rounded cursor-pointer"
:class="{ active: attachmentParam.cate_id == 0 }" @click="attachmentParam.cate_id = 0">
<div class="group-item p-[10px] leading-none text-xs rounded cursor-pointer" :class="{ active: attachmentParam.cate_id == 0 }" @click="attachmentParam.cate_id = 0">
{{ t('selectPlaceholder') }}
</div>
<div class="group-item px-[10px] text-xs rounded cursor-pointer flex"
@ -24,8 +24,7 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item class="text-center">
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')"
@confirm="updateAttachmentCategory($event, index)" v-model="item.name">
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')" @confirm="updateAttachmentCategory($event, index)" v-model="item.name">
<span>{{ t('edit') }}</span>
</popover-input>
</el-dropdown-item>
@ -40,11 +39,11 @@
</el-scrollbar>
</div>
<!-- 添加分组 -->
<popover-input :placeholder="t('upload.attachmentCategoryPlaceholder')" @confirm="addAttachmentCategory" v-model="attachmentCategoryName"
v-if="prop.type != 'icon'">
<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>
</div>
<!-- 素材 -->
<div class="attachment-list-wrap flex flex-col p-[15px] flex-1 overflow-hidden">
<el-row :gutter="15" class="h-[32px]">
@ -54,11 +53,8 @@
<el-button type="primary">{{ t('upload.upload' + type) }} {{ isOpen }}</el-button>
</el-upload>
<div v-if="scene == 'attachment' && prop.type != 'icon'">
<el-button v-if="operate === false" class="ml-[10px]" type="primary"
@click="operate = true">{{ t('edit') }}
</el-button>
<el-button v-else class="ml-[10px]" type="primary" @click="operate = false">{{ t('complete')
}}</el-button>
<el-button v-if="operate === false" class="ml-[10px]" type="primary" @click="operate = true">{{ t('edit') }}</el-button>
<el-button v-else class="ml-[10px]" type="primary" @click="operate = false">{{ t('complete') }}</el-button>
</div>
</div>
</el-col>
@ -71,38 +67,36 @@
<div class="flex-1 my-[15px] h-0" v-loading="attachment.loading">
<el-scrollbar>
<!-- 选择弹出框 -->
<div class="flex flex-wrap"
v-if="attachment.data.length && (operate === true || scene != 'attachment')">
<div class="attachment-item mr-[10px]" :class="scene == 'select' ? 'w-[100px]' : 'w-[120px]'"
v-for="(item, index) in attachment.data" :key="index">
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center"
:class="scene == 'select' ? 'h-[100px]' : 'h-[120px]'" @click="selectFile(item)">
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'"></el-image>
<video :src="img(item.url)" v-else-if="type == 'video'"></video>
<icon :name="item.url" size="40px" v-else-if="type == 'icon'"></icon>
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60"
v-show="selectedFile[item.att_id]">
<div class="flex flex-wrap" v-if="attachment.data.length && (operate === true || scene != 'attachment')">
<div class="attachment-item mr-[10px]" :class="scene == 'select' ? 'w-[100px]' : 'w-[120px]'" v-for="(item, index) in attachment.data" :key="index">
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center" :class="scene == 'select' ? 'h-[100px]' : 'h-[120px]'" @click="selectFile(item)">
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'"/>
<video :src="img(item.url)" v-else-if="type == 'video'"/>
<icon :name="item.url" size="40px" v-else-if="type == 'icon'"/>
<div class="absolute z-[1] flex items-center justify-center w-full h-full inset-0 bg-black bg-opacity-60" v-show="selectedFile[item.att_id]">
<icon name="element-Select" color="#fff" size="40px" />
<div class="file-box-active absolute z-[1] bottom-0 right-0 w-full h-full">
<span class="absolute bottom-[2px] right-[2px] text-white z-[2] leading-none">{{ getFileIndex(item.att_id) }}</span>
</div>
</div>
</div>
<div class="flex items-center">
<el-tooltip placement="top">
<template #content>{{ item.real_name }}</template>
<div class="truncate my-[10px] cursor-pointer text-base flex-1 text-center">{{
item.real_name }}</div>
<div class="truncate my-[10px] cursor-pointer text-base flex-1 text-center">{{ item.real_name }}</div>
</el-tooltip>
<!-- 图片操作 -->
<el-dropdown :hide-on-click="false" v-if="scene == 'attachment'"
class="attachment-action hidden ">
<el-dropdown :hide-on-click="false" v-if="scene == 'attachment'" class="attachment-action hidden ">
<icon name="element-MoreFilled" class="cursor-pointer ml-[8px]" size="14px" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item class="text-center" @click="previewImage(index)"
v-if="item.att_type == 'image'">
<el-dropdown-item class="text-center" @click="previewImage(index)" v-if="item.att_type == 'image'">
<div class="text-center w-full">{{ t('lookOver') }}</div>
</el-dropdown-item>
<el-dropdown-item class="text-center" @click="previewVideo(index)"
v-if="item.att_type == 'video'">
<el-dropdown-item class="text-center" @click="previewVideo(index)" v-if="item.att_type == 'video'">
<div class="text-center w-full">{{ t('lookOver') }}</div>
</el-dropdown-item>
<el-dropdown-item class="text-center" @click="moveAttachmentEvent(index)">
@ -120,20 +114,16 @@
<!-- 素材管理 -->
<div class="flex flex-wrap" v-else-if="attachment.data.length && operate === false">
<div class="attachment-item mr-[10px] w-[120px]" v-for="(item, index) in attachment.data"
:key="index">
<div
class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'"
:preview-src-list="item.image_list"></el-image>
<div class="attachment-item mr-[10px] w-[120px]" v-for="(item, index) in attachment.data" :key="index">
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'" :preview-src-list="item.image_list"/>
<video :src="img(item.url)" v-else-if="type == 'video'"></video>
<icon :name="item.url" size="40px" v-else-if="type == 'icon'"></icon>
</div>
<div class="flex items-center">
<el-tooltip placement="top">
<template #content>{{ item.real_name }}</template>
<div class="truncate my-[10px] cursor-pointer text-base flex-1 text-center">{{
item.real_name }}</div>
<div class="truncate my-[10px] cursor-pointer text-base flex-1 text-center">{{ item.real_name }}</div>
</el-tooltip>
</div>
</div>
@ -149,10 +139,8 @@
<el-col :span="8" v-if="scene == 'attachment' && operate === true">
<div class="flex items-center">
<el-checkbox v-model="selectAll" :label="t('selectAll')" size="large" />
<el-button class="ml-[15px]" :disabled="batchOperateDisabled"
@click="deleteAttachmentEvent()">{{ t('delete') }}</el-button>
<el-button :disabled="batchOperateDisabled" @click="moveAttachmentEvent()">{{ t('upload.move')
}}</el-button>
<el-button class="ml-[15px]" :disabled="batchOperateDisabled" @click="deleteAttachmentEvent()">{{ t('delete') }}</el-button>
<el-button :disabled="batchOperateDisabled" @click="moveAttachmentEvent()">{{ t('upload.move') }}</el-button>
</div>
</el-col>
<el-col :span="scene == 'attachment' ? 16 : 24">
@ -172,8 +160,7 @@
<el-form label-width="60px">
<el-form-item :label="t('upload.moveTo')" style="margin-bottom: 0;">
<el-select v-model="moveAttachmentData.cateId" class="input-width">
<el-option :label="item.name" :value="item.id" v-for="(item, index) in attachmentCategory.data"
:key="index" />
<el-option :label="item.name" :value="item.id" v-for="(item, index) in attachmentCategory.data" :key="index" />
</el-select>
</el-form-item>
</el-form>
@ -181,19 +168,16 @@
<template #footer>
<span class="dialog-footer">
<el-button @click="moveAttachmentData.visible = false">{{ t('cancel') }}</el-button>
<el-button type="primary" :loading="moveAttachmentData.loading"
@click="moveAttachmentData.confirm()">{{ t('confirm') }}</el-button>
<el-button type="primary" :loading="moveAttachmentData.loading" @click="moveAttachmentData.confirm()">{{ t('confirm') }}</el-button>
</span>
</template>
</el-dialog>
<!-- 图片预览 -->
<el-image-viewer :url-list="previewImageList" v-if="imageViewer.show" @close="imageViewer.show = false"
:initial-index="imageViewer.index" :zoom-rate="1" />
<el-image-viewer :url-list="previewImageList" v-if="imageViewer.show" @close="imageViewer.show = false" :initial-index="imageViewer.index" :zoom-rate="1" />
<!-- 视频预览 -->
<el-dialog v-model="videoViewer.visible" width="50%" align-center :destroy-on-close="true"
custom-class="video-preview">
<el-dialog v-model="videoViewer.visible" width="50%" align-center :destroy-on-close="true" custom-class="video-preview">
<video-player :src="videoViewer.src" width="100%" />
</el-dialog>
@ -241,6 +225,8 @@ const prop = defineProps({
//
const selectedFile: Record<string, any> = reactive({})
const selectedFileIndex:any = reactive([])
const attachmentCategory: Record<string, any> = reactive({
data: []
})
@ -275,8 +261,8 @@ const attachmentParam = reactive({
})
/**
* 查询分组
*/
* 查询分组
*/
const getAttachmentCategoryList = debounce(() => {
const getFn = prop.type == 'icon' ? getIconCategoryList : attachmentCategoryList
getFn({
@ -292,8 +278,8 @@ const getAttachmentCategoryList = debounce(() => {
getAttachmentCategoryList()
/**
* 查询图片
*/
* 查询图片
*/
const getAttachmentList = debounce((page: number = 1) => {
const getFn = prop.type == 'icon' ? getIconList : attachmentList
@ -327,8 +313,8 @@ watch(() => attachmentParam.cate_id, () => {
})
/**
* 添加分组
*/
* 添加分组
*/
const addAttachmentCategory = (name: string) => {
addCategory({
type: prop.type,
@ -342,10 +328,10 @@ const addAttachmentCategory = (name: string) => {
}
/**
* 编辑分组
* @param name
* @param index
*/
* 编辑分组
* @param name
* @param index
*/
const updateAttachmentCategory = (name: string, index: number) => {
updateCategory({
id: attachmentCategory.data[index].id,
@ -358,8 +344,8 @@ const updateAttachmentCategory = (name: string, index: number) => {
}
/**
* 删除分组
*/
* 删除分组
*/
const deleteAttachmentCategory = (index: number) => {
ElMessageBox.confirm(t('upload.deleteCategoryTips'), t('warning'),
{
@ -416,8 +402,8 @@ watch(selectAll, () => {
})
/**
* 清空选中
*/
* 清空选中
*/
const clearSelected = () => {
const keys = Object.keys(toRaw(selectedFile))
if (keys.length) {
@ -429,29 +415,42 @@ const clearSelected = () => {
}
/**
* 选择文件
*/
* 选择文件
*/
const selectFile = (data: any) => {
if (selectedFile[data.att_id]) delete selectedFile[data.att_id]
else if (prop.scene == 'select') {
if (selectedFile[data.att_id]) {
delete selectedFile[data.att_id]
selectedFileIndex.splice(selectedFileIndex.indexOf(data.att_id),1);
} else if (prop.scene == 'select') {
const keys = Object.keys(toRaw(selectedFile))
const length = keys.length
if (prop.limit == 1 && length == prop.limit) {
delete selectedFile[keys[0]]
selectedFileIndex.splice(selectedFileIndex.indexOf(keys[0]),1);
} else if (length >= prop.limit) {
ElMessage.info(t('upload.triggerUpperLimit'))
return
}
selectedFile[data.att_id] = toRaw(data)
selectedFileIndex.push(data.att_id);
} else {
selectedFile[data.att_id] = toRaw(data)
selectedFileIndex.push(data.att_id);
}
}
//
const getFileIndex = (att_id:any)=>{
let index = selectedFileIndex.indexOf(att_id);
if(index == -1) return 0;
return index + 1;
}
/**
* 删除附件
* @param index
*/
* 删除附件
* @param index
*/
const deleteAttachmentEvent = (index: number | null = null) => {
const ids = index === null ? Object.keys(toRaw(selectedFile)) : [attachment.data[index].att_id]
@ -470,13 +469,14 @@ const deleteAttachmentEvent = (index: number | null = null) => {
}
/**
* 移动附件
*/
* 移动附件
*/
const moveAttachmentData: Record<string, any> = reactive({
cateId: '',
loading: false,
visible: false
})
const moveAttachmentEvent = (index: number | null = null) => {
const ids = index === null ? Object.keys(toRaw(selectedFile)) : [attachment.data[index].att_id]
moveAttachmentData.visible = true
@ -501,8 +501,8 @@ watch(selectedFile, () => {
})
/**
* 查看图片
*/
* 查看图片
*/
const imageViewer = reactive({
show: false,
index: 0
@ -519,12 +519,13 @@ const previewImageList = computed(() => {
})
/**
* 视频预览
*/
* 视频预览
*/
const videoViewer = reactive({
visible: false,
src: ''
})
const previewVideo = (index: number) => {
videoViewer.visible = true
videoViewer.src = img(attachment.data[index].url)
@ -570,8 +571,27 @@ defineExpose({
.attachment-wrap {
background: var(--el-border-color-extra-light);
}
}</style>
<style lang="scss">.video-preview {
}
.file-box-active {
&:after {
content: '';
display: block;
position: absolute;
border: 15px solid;
border-bottom-color: var(--el-color-primary);
border-right-color: var(--el-color-primary);
border-top-color: transparent;
border-left-color: transparent;
bottom: 0;
right: 0;
}
span{
font-style: normal;
}
}
</style>
<style lang="scss">
.video-preview {
background: none !important;
box-shadow: none !important;

View File

@ -23,7 +23,8 @@ let i18n = createI18n({
messages: {
"zh-cn": zhCn,
en
}
},
silentFallbackWarn: true
});
const language = new Language(i18n);

View File

@ -1,51 +1,25 @@
<template>
<el-aside :class="['layout-aside w-full ease-in duration-200', { 'bright': !dark }]">
<div v-if="currHeadMenuName == 'setting_manage'" class="pt-[20px] pl-[80px] pr-[70px]">
<div class="flex flex-wrap items-center">
<template v-for="(item,index) in settingMenu" :key="index">
<div
v-if="item.meta.show"
@click="settingMenuFn(item)"
:class="['flex items-center h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[10px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]',{'text-[#fff] !bg-[#000] border-[#000]': menuActive == item.name || menuTwoActive && menuTwoActive == item.name}]">
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[4px] !leading-[14px]" size="14px" :title="item.meta.title"/>
<span class="text-[14px]">{{ item.meta.title }}</span>
</div>
</template>
</div>
<el-tabs v-model="menuActive" class="mt-[20px]" @tab-click="settingHandleClick" v-if="settingTwoMenu.length">
<template v-for="(item,index) in settingTwoMenu" :key="index">
<el-tab-pane :label="item.meta.title" :name="item.name" :path="item.path" v-if="item.meta.show" @click="settingMenuFn(item)"></el-tab-pane>
</template>
</el-tabs>
</div>
<div class="flex flex-wrap items-center pt-[20px] pl-[80px] pr-[70px]" v-if="currHeadMenuName == 'site_manage'">
<template v-for="(item,index) in siteMenu" :key="index">
<div class="flex flex-wrap items-center pt-[20px] pb-[10px] pl-[80px] pr-[70px]"
v-if="twoMenuData.length">
<template v-for="(item,index) in twoMenuData" :key="index">
<div
v-if="item.meta.show"
@click="siteMenuFn(item)"
@click="redirect(item)"
:class="['flex items-center h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[10px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]',{'text-[#fff] !bg-[#000] border-[#000]': menuActive == item.name || menuTwoActive && menuTwoActive == item.name}]">
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[4px] !leading-[14px]" size="14px" :title="item.meta.title"/>
<span class="text-[14px]">{{ item.meta.title }}</span>
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[4px] !leading-[14px]" size="14px"
:title="item.meta.title" />
<span class="text-[14px]">{{ item.meta.short_title || item.meta.title }}</span>
</div>
</template>
</div>
<div class="pt-[20px] pl-[80px] pr-[70px]" v-if="currHeadMenuName == 'tool'">
<div class="flex flex-wrap items-center">
<template v-for="(item,index) in appToolsMenu" :key="index">
<div
v-if="item.meta.show"
@click="toolsMenuFn(item)"
:class="['flex items-center h-[32px] border-[1px] border-solid my-[3px] border-[#E0E0E0] rounded-full px-[10px] mr-[24px] cursor-pointer bg-[#f8f8f8] hover:bg-[#fff]',{'text-[#fff] !bg-[#000] border-[#000]': menuActive == item.name || menuTwoActive && menuTwoActive == item.name}]">
<icon v-if="item.meta.icon" :name="item.meta.icon" class="!w-auto mr-[4px] !leading-[14px]" size="14px" :title="item.meta.title"/>
<span class="text-[14px]">{{ item.meta.title }}</span>
</div>
</template>
</div>
<el-tabs v-model="menuActive" class="mt-[20px]" @tab-click="toolsHandleClick" v-if="appToolsTwoMenu.length">
<template v-for="(item,index) in appToolsTwoMenu" :key="index">
<el-tab-pane :label="item.meta.title" :name="item.name" :path="item.path" v-if="item.meta.show" @click="settingMenuFn(item)"></el-tab-pane>
<!-- 三级菜单 -->
<div class="pt-[20px] pl-[80px] pr-[70px]" v-if="threeMenuData.length">
<el-tabs v-model="menuTwoActive" @tab-click="toolsHandleClick">
<template v-for="(item,index) in threeMenuData" :key="index">
<el-tab-pane :label="item.meta.title" :name="item.name" :path="item.path" v-if="item.meta.show"
@click="settingMenuFn(item)"></el-tab-pane>
</template>
</el-tabs>
</div>
@ -55,206 +29,41 @@
<script lang="ts" setup>
import { watch, ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import side from './side.vue'
import useSystemStore from '@/stores/modules/system'
import useUserStore from '@/stores/modules/user'
import storage from '@/utils/storage'
import { CollectionTag } from '@element-plus/icons-vue'
const userStore = useUserStore()
const route = useRoute()
const systemStore = useSystemStore()
const router = useRouter()
const dark = computed(() => {
return systemStore.dark
})
const currHeadMenuName = computed(()=>{
return systemStore.currHeadMenuName
})
let menuData = JSON.parse(JSON.stringify(userStore.routers));
const route = useRoute()
const router = useRouter()
const menuActive = computed(() => {
return String(route.name)
})
const twoMenuData = ref<Record<string, any>[]>([])
const threeMenuData = ref<Record<string, any>[]>([])
const menuActive = ref('')
const menuTwoActive = ref('')
//
const emit = defineEmits(['complete'])
watch(route, () => {
systemStore.$patch(state => {
state.menuDrawer = false
})
resetFn();
twoMenuData.value = route.matched[1].children ?? []
threeMenuData.value = route.matched[2].children ?? []
menuActive.value = route.matched[2] ? route.matched[2].name : ''
menuTwoActive.value = route.matched[3] ? route.matched[3].name : ''
}, { immediate: true })
let currMenuName = '';
menuData.forEach((item,index) => {
if(item.name == route.name){
currMenuName = item.name;
}else if(item.children && item.children.length){
item.children.forEach((twoItem, twoIndex) => {
if(twoItem.name == route.name){
currMenuName = item.name;
}else if(twoItem.children && twoItem.children.length){
twoItem.children.forEach((threeItem, threeIndex) => {
if(threeItem.name == route.name){
currMenuName = item.name;
//
if(currMenuName == 'setting_manage' && !menuTwoActive.value){
menuTwoActive.value = twoItem.name;
settingTwoMenu.value = twoItem.children;
}
if(currMenuName == 'tool' && !menuTwoActive.value){
menuTwoActive.value = twoItem.name;
appToolsTwoMenu.value = twoItem.children;
}
}
});
}
});
}
});
//
emit('complete')
//
let menuIndexArr = {setting_manage: 'setting_manage', site_manage: 'site_manage', tool:'tool', app_auth:'tool'};
if(Object.keys(menuIndexArr).indexOf(currMenuName) != -1){
systemStore.setHeadMenu(menuIndexArr[currMenuName]);
return false;
}
systemStore.setHeadMenu('');
})
let settingMenu = ref([]);
let settingTwoMenu = ref([]);
let siteMenu = ref([]);
let appToolsMenu = ref([]);
let appToolsTwoMenu = ref([]);
userStore.routers.forEach((item, index) => {
item.meta.class = 1
if (item.children) {
item.children.forEach((subItem, subIndex) => {
subItem.meta.class = 2
if (subItem.children) {
subItem.children.forEach((threeItem, threeIndex) => {
threeItem.meta.class = 3
})
}
})
}
//
if(item.name == 'setting_manage'){
settingMenu.value = item.children;
}
//
if(item.name == 'site_manage'){
siteMenu.value = item.children;
}
//
if(item.name == 'tool'){
appToolsMenu.value = item.children;
}
})
// start
const settingMenuFn = (data)=>{
let obj = '/setting/';
menuTwoActive.value = '';
settingTwoMenu.value = [];
if(data.children){
menuTwoActive.value = data.name;
settingTwoMenu.value = data.children;
obj = obj + data.path + '/' + data.children[0].path;
router.push(obj)
}else{
obj = obj + data.path;
router.push(obj)
}
}
const settingHandleClick = (tab, event: Event) => {
let obj = '/setting/';
settingMenu.value.forEach((item,index)=>{
if(item.children && item.children.length){
item.children.forEach((subItem,subIndex) => {
if(subItem.name == tab.props.name){
obj = obj + item.path + '/' + subItem.path;
router.push(obj)
}
});
}
})
}
// end
// start
const siteMenuFn = (data)=>{
let obj = '/admin/site/';
menuTwoActive.value = '';
if(data.children){
menuTwoActive.value = data.name;
obj = obj + data.path + '/' + data.children[0].path;
router.push(obj)
}else{
obj = obj + data.path;
router.push(obj)
}
}
// end
// start
const toolsMenuFn = (data)=>{
let obj = '/admin/tools/';
menuTwoActive.value = '';
appToolsTwoMenu.value = [];
if(data.children){
menuTwoActive.value = data.name;
appToolsTwoMenu.value = data.children;
obj = obj + data.path + '/' + data.children[0].path;
router.push(obj)
}else{
obj = obj + data.path;
router.push(obj)
/**
* 跳转
* @param data
*/
const redirect = (data: any) => {
if (data.children) {
router.push(data.children[0].path)
} else {
router.push(data.path)
}
}
const toolsHandleClick = (tab, event: Event) => {
let obj = '/tools/';
appToolsMenu.value.forEach((item,index)=>{
if(item.children && item.children.length){
item.children.forEach((subItem,subIndex) => {
if(subItem.name == tab.props.name){
obj = obj + item.path + '/' + subItem.path;
router.push(obj)
}
});
}
})
}
// end
//
const resetFn = ()=>{
menuTwoActive.value= '';
settingTwoMenu.value = [];
}
//
const toLink = (path) => {
router.push({path})
router.push({name: tab.props.name})
}
</script>

View File

@ -3,16 +3,14 @@
<!-- :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] 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="mx-2 text-[#4F5563] mx-[15px]">|</span>
<span class="cursor-pointer" @click="toLink('/admin/site/list','site_manage')">站点</span>
<template v-if="app_debug">
<span class="mx-2 text-[#4F5563] mx-[15px]">|</span>
<span class="cursor-pointer" @click="toLink('/admin/app_manage/app_store','')">应用</span>
<span class="mx-2 text-[#4F5563] mx-[15px]">|</span>
<span class="cursor-pointer" @click="toLink('/admin/app_manage/tools','tool')">开发</span>
<template v-for="(item, index) in oneMenuData">
<template v-if="item.meta.show">
<span class="mx-2 text-[#4F5563] mx-[15px]" v-if="index">|</span>
<span class="cursor-pointer" @click="router.push({ name: item.name })" >
{{ item.meta.short_title || item.meta.title }}
</span>
</template>
</template>
</div>
<div class="right-panel h-full flex items-center justify-end">
@ -20,25 +18,6 @@
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
<icon name="element-Refresh" />
</div>
<!-- 预览 只有站点时展示-->
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
<!-- 切换首页 -->
<div class="navbar-item flex items-center h-full cursor-pointer" v-if="appType == 'site'" @click="checkIndexList">
<icon name="iconfont-iconqiehuan" :title="t('indexSwitch')"/>
</div>
<!-- 切换语言 -->
<!-- <div class="navbar-item flex items-center h-full cursor-pointer">
<switch-lang />
</div> -->
<!-- 切换全屏 -->
<!-- <div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleFullscreen">
<icon name="iconfont-icontuichuquanping" v-if="isFullscreen" />
<icon name="iconfont-iconquanping" v-else />
</div> -->
<!-- 布局设置 -->
<!-- <div class="navbar-item flex items-center h-full cursor-pointer">
<layout-setting />
</div> -->
<!-- 用户信息 -->
<div class="navbar-item flex items-center h-full cursor-pointer">
<user-info />
@ -79,51 +58,38 @@
</template>
<script lang="ts" setup>
import { computed, ref, onMounted, watch } from 'vue'
import layoutSetting from './layout-setting.vue'
import switchLang from './switch-lang.vue'
import userInfo from './user-info.vue'
import { useFullscreen } from '@vueuse/core'
import useSystemStore from '@/stores/modules/system'
import { ref } from 'vue'
import useUserStore from '@/stores/modules/user'
import useAppStore from '@/stores/modules/app'
import { useRoute, useRouter } from 'vue-router'
import { useRouter } from 'vue-router'
import { t } from '@/lang'
import storage from '@/utils/storage'
import { getIndexList, setIndexList, getEnv } from '@/app/api/sys'
import userInfo from './user-info.vue'
import { findFirstValidRoute } from "@/router/routers"
const router = useRouter()
const appType = storage.get('app_type')
const { toggle: toggleFullscreen, isFullscreen } = useFullscreen()
const systemStore = useSystemStore()
const appStore = useAppStore()
const route = useRoute()
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
const userStore = useUserStore()
const routers = userStore.routers
const dark = computed(()=>{
return systemStore.dark
const oneMenuData = ref<Record<string, any>[]>([])
routers.forEach(item => {
item.original_name = item.name
if (item.children && item.children.length) {
item.name = findFirstValidRoute(item.children)
}
oneMenuData.value.push(item)
})
// debug start
let app_debug = ref(true)
const getEnvFn = () => {
getEnv().then(res => {
// app_debug.value = res.data.app_debug;
}).catch(() => {})
}
getEnvFn();
// debug end
// start
const detectionLoginDialog = ref(false)
const comparisonToken = ref('')
const comparisonSiteId = ref('')
if (storage.get('comparisonTokenStorage')) {
comparisonToken.value = storage.get('comparisonTokenStorage')
// storage.remove(['comparisonTokenStorage']);
}
if (storage.get('comparisonSiteIdStorage')) {
comparisonSiteId.value = storage.get('comparisonSiteIdStorage')
// storage.remove(['comparisonSiteIdStorage']);
}
//
document.addEventListener('visibilitychange', e => {
@ -134,65 +100,17 @@ document.addEventListener('visibilitychange', e => {
const detectionLoginFn = () => {
detectionLoginDialog.value = false
location.reload();
location.reload()
}
// end
onMounted(() => {
//
window.onresize = () => {
return (() => {
screenWidth.value = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
})()
}
})
//
const refreshRouter = () => {
if (!appStore.routeRefreshTag) return
appStore.refreshRouterView()
}
//
const breadcrumb = computed(() => {
const matched = route.matched.filter(item => { return item.meta.title })
if (matched[0] && matched[0].path == '/') matched.splice(0, 1)
return matched
})
//
const backFn = () => {
router.go(-1)
}
const indexList = ref();
const showDialog = ref(false)
const checkIndexList = () => {
getIndexList().then(res => {
showDialog.value = true
indexList.value = res.data
for(let i = 0 ; i < indexList.value.length; i ++){
if(indexList.value[i].is_use == 1){
index_path.value = indexList.value[i].view_path
}
}
})
}
const index_path = ref('');
const submitIndex = () => {
setIndexList({
view_path: index_path.value
}).then(() => {
showDialog.value = false
router.go(0)
})
}
storage.set({ key: 'currHeadMenuName', data: ""})
const toLink = (link,type)=>{
// systemStore.setHeadMenu(type);
router.push(link);
}
storage.set({ key: 'currHeadMenuName', data: "" })
</script>
<style lang="scss" scoped>

View File

@ -14,11 +14,12 @@
<el-scrollbar class="h-[calc( 100vh - 64px )]">
<el-menu :default-active="oneMenuActive" :router="true" class="aside-menu" unique-opened="true" :collapse="systemStore.menuIsCollapse">
<template v-for="(item, index) in oneMenuData" :key="index">
<el-menu-item :index="item.path" @click="router.push({ name: item.name })" v-if="item.meta.show">
<el-menu-item :index="item.original_name" @click="router.push({ name: item.name })" v-if="item.meta.show">
<div v-if="item.meta.icon" class="w-[16px] h-[16px] relative flex justify-center">
<el-image class="w-[16px] h-[16px] rounded-[50%] overflow-hidden" :src="item.meta.icon" fit="fill" v-if="isUrl(item.meta.icon)"/>
<icon :name="item.meta.icon" class="absolute top-[50%] -translate-y-[50%]" v-else />
</div>
<div v-else class="w-[16px] h-[16px]"></div>
<template #title>
<div class="relative flex-1 w-0">
<span class="ml-[10px] w-full truncate">{{ item.meta.short_title || item.meta.title }}</span>
@ -63,6 +64,7 @@ const twoMenuData = ref<Record<string, any>[]>([])
const addonRouters: Record<string, any> = {}
routers.forEach(item => {
item.original_name = item.name
if (item.meta.addon == '') {
if (item.children && item.children.length) {
item.name = findFirstValidRoute(item.children)
@ -71,7 +73,7 @@ routers.forEach(item => {
} 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}`
citem.original_name = citem.name
if (citem.children && citem.children.length) {
citem.name = findFirstValidRoute(citem.children)
}
@ -98,29 +100,30 @@ if (siteInfo?.apps.length > 1) {
app: item.app,
show: true
},
original_name: item.key,
name: addonIndexRoute[item.key]
})
})
oneMenuData.value.unshift(...routers)
}
const oneMenuActive = ref(route.matched[1].path)
const oneMenuActive = ref(route.matched[1].name)
watch(route, () => {
//
if (siteInfo?.apps.length > 1) {
twoMenuData.value = route.matched[1].children
oneMenuActive.value = route.matched[1].path
oneMenuActive.value = route.matched[1].name
} else {
//
if (route.meta.addon == '') {
oneMenuActive.value = route.matched[1].path
oneMenuActive.value = route.matched[1].name
twoMenuData.value = route.matched[1].children ?? []
} else if (route.meta.addon && route.meta.addon != siteInfo?.apps[0].key) {
oneMenuActive.value = '/site/app'
twoMenuData.value = route.matched[1].children ?? []
} else {
oneMenuActive.value = route.matched[2].path
oneMenuActive.value = route.matched[2].name
twoMenuData.value = route.matched[2].children ?? []
}
}

View File

@ -101,7 +101,7 @@ document.addEventListener('visibilitychange', e => {
const detectionLoginFn = () => {
detectionLoginDialog.value = false
location.reload()
location.href = `${location.origin}/site/`
}
// end

View File

@ -21,7 +21,7 @@ router.push = (to: RouteLocationRaw) => {
const route = typeof to == 'string' ? urlToRouteRaw(to) : to
if (route.path) {
const paths = route.path.split('/').filter((item: string) => { return item })
route.path = ['admin', 'site', 'decorate', 'home'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
route.path = ['admin', 'site', 'home'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
}
return originPush(route)
}
@ -34,7 +34,7 @@ router.resolve = (to: RouteLocationRaw, currentLocation?: RouteLocationNormalize
const route = typeof to == 'string' ? urlToRouteRaw(to) : to
if (route.path) {
const paths = route.path.split('/').filter((item: string) => { return item })
route.path = ['admin', 'site', 'decorate', 'home'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
route.path = ['admin', 'site', 'home'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
}
return originResolve(route, currentLocation)
}
@ -74,7 +74,7 @@ router.beforeEach(async (to, from, next) => {
matched = appType
}
const loginPath = to.path == '/' ? '/admin/login' : `${matched}/login`
const loginPath = to.path == '/' ? '/admin/login' : `/${matched == '/admin' ? 'admin' : 'site'}/login`
// 判断是否需登录
if (NO_LOGIN_ROUTES.includes(to.path)) {
@ -100,9 +100,10 @@ router.beforeEach(async (to, from, next) => {
// 设置首页路由
let firstRoute: symbol | string | undefined = findFirstValidRoute(userStore.routers)
if (getAppType() != 'admin' && userStore.siteInfo?.apps.length > 1) {
if (getAppType() != 'admin') {
firstRoute = userStore.addonIndexRoute[ userStore.siteInfo?.apps[0].key ]
}
ROOT_ROUTER.redirect = { name: firstRoute }
router.addRoute(ROOT_ROUTER)
@ -133,13 +134,11 @@ router.beforeEach(async (to, from, next) => {
router.addRoute(SITE_ROUTE.name, route)
}
})
next({ path: to.path, query: to.query, replace: true })
next(to)
}
} catch (err) {
console.log(err)
// userStore.logout()
next({ path: loginPath, query: { redirect: to.fullPath } })
}
}

View File

@ -169,7 +169,7 @@ interface Route {
*/
const createRoute = function (route: Route, parentRoute: RouteRecordRaw | null = null): RouteRecordRaw {
const record: RouteRecordRaw = {
path: parentRoute ? route.router_path : route.router_path != 'decorate' ? `/${route.app_type}/${route.router_path}` : `/${route.router_path}`,
path: `/${route.app_type}/${route.router_path}`,
name: route.menu_key,
meta: {
title: route.menu_name,
@ -214,7 +214,7 @@ export function formatRouters(routes: Route[], parentRoute: RouteRecordRaw | nul
*/
export function findFirstValidRoute(routes: RouteRecordRaw[]): string | undefined {
for (const route of routes) {
if (route.meta?.type == 1) {
if (route.meta?.type == 1 && route.meta?.show) {
return route.name as string
}
if (route.children) {

View File

@ -1 +1,2 @@
@import "addon/tourism/iconfont.css";
@import "addon/o2o/iconfont.css";

View File

@ -0,0 +1,38 @@
@font-face {
font-family: "o2o"; /* Project id 4412516 */
src: url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff2?t=1705720131974') format('woff2'),
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff?t=1705720131974') format('woff'),
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.ttf?t=1705720131974') format('truetype');
}
.o2o {
font-family: "o2o" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.o2o-icon-danhanghuadong:before {
content: "\e66f";
}
.o2o-icon-yuanjiao:before {
content: "\e6c0";
}
.o2o-icon-gl-square:before {
content: "\ea92";
}
.o2o-icon-sousuo12:before {
content: "\e699";
}
.o2o-icon-sousuo11:before {
content: "\e6d4";
}
.o2o-icon-jishi:before {
content: "\e600";
}

View File

@ -0,0 +1,51 @@
{
"id": "4412516",
"name": "上门服务",
"font_family": "o2o",
"css_prefix_text": "o2o-icon-",
"description": "",
"glyphs": [
{
"icon_id": "30621139",
"name": "单行滑动",
"font_class": "danhanghuadong",
"unicode": "e66f",
"unicode_decimal": 58991
},
{
"icon_id": "7149037",
"name": "圆角",
"font_class": "yuanjiao",
"unicode": "e6c0",
"unicode_decimal": 59072
},
{
"icon_id": "7594344",
"name": "20gl-square",
"font_class": "gl-square",
"unicode": "ea92",
"unicode_decimal": 60050
},
{
"icon_id": "10133070",
"name": "搜索",
"font_class": "sousuo12",
"unicode": "e699",
"unicode_decimal": 59033
},
{
"icon_id": "14652583",
"name": "搜索",
"font_class": "sousuo11",
"unicode": "e6d4",
"unicode_decimal": 59092
},
{
"icon_id": "6818781",
"name": "技师",
"font_class": "jishi",
"unicode": "e600",
"unicode_decimal": 58880
}
]
}

View File

@ -224,3 +224,63 @@ export function guid(len = 10, firstU = true, radix = null) {
}
return uuid.join('')
}
/**
*
*/
export function moneyFormat(money : string) : string {
return isNaN(parseFloat(money)) ? money : parseFloat(money).toFixed(2)
}
/**
*
* @param {Object} timeStamp
*/
export function timeStampTurnTime(timeStamp, type = "") {
if (timeStamp != undefined && timeStamp != "" && timeStamp > 0) {
var date = new Date();
date.setTime(timeStamp * 1000);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
var second = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if (type) {
if (type == 'yearMonthDay') {
return y + '年' + m + '月' + d + '日';
}
return y + '-' + m + '-' + d;
} else {
return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
}
} else {
return "";
}
}
/**
*
* @param event
*/
export function filterDigit(event:any){
event.target.value = event.target.value.replace(/[^\d\.]/g,'');
event.target.value = event.target.value.replace(/^\./g,'');
event.target.value = event.target.value.replace(/\.{2,}/g,'.');
event.target.value = event.target.value.replace('.','$#$').replace(/\./g,'').replace('$#$','.');
}
/**
*
* @param event
*/
export function filterNumber(event:any){
event.target.value = event.target.value.replace(/[^\d]/g,'');
}

View File

@ -37,7 +37,7 @@ class Storage {
const json: any = window.localStorage.getItem(`${this.prefix}.${key}`)
return JSON.parse(json)
} catch (error) {
return null
return window.localStorage.getItem(`${this.prefix}.${key}`)
}
}

View File

@ -2,8 +2,6 @@
return [
'HELLO_WORLD_LINK' => [
'key' => 'hello_world',
'addon_title' => get_lang('dict_diy.hello_world_title'),
'title' => get_lang('dict_diy.hello_world_link'),
'child_list' => [
[

View File

@ -3,12 +3,12 @@
return [
'DIY_HELLO_WORLD_INDEX' => [
'title' => get_lang('dict_diy.page_hello_world_index'),
'page' => '/hello_world/pages/index',
'page' => '/addon/hello_world/pages/index',
'action' => ''
],
'DIY_HELLO_WORLD_INFO' => [
'title' => get_lang('dict_diy.page_hello_world_info'),
'page' => '/hello_world/pages/info',
'page' => '/addon/hello_world/pages/info',
'action' => ''
],
];

View File

@ -1,17 +1,3 @@
<?php
return [
[
'menu_name' => '插件菜单',
'menu_key' => 'niucloud_hello',
'menu_type' => 1,
'icon' => 'iconfont-iconyingyongshichang',
'api_url' => '',
'router_path' => 'hello_world',
'view_path' => 'hello_world/index',
'methods' => '',
'sort' => 90,
'status' => 1,
'is_show' => 1,
],
];
return [
];

View File

@ -1,36 +1,16 @@
<?php
return [
[
'menu_name' => '插件站点菜单',
'menu_key' => 'niucloud_site_hello',
'menu_type' => 1,
'icon' => 'iconfont-iconyingyongshichang',
'api_url' => '',
'router_path' => 'hello_world',
'view_path' => 'hello_world/site',
'methods' => '',
'sort' => 100,
'status' => 1,
'is_show' => 1,
],
/* [
'menu_name' => '会员列表',
'menu_key' => 'member_list',
'parent_key' => 'member',
'menu_type' => 1,
'icon' => 'iconfont-iconhuiyuanliebiao',
'api_url' => 'member/member',
'router_path' => 'hello_world_member_list',
'view_path' => 'hello_world/member',
'methods' => 'get',
'sort' => 100,
'status' => 1,
'is_show' => 1,
'children' => [
]
],
"delete" => "member" //针对修改系统菜单处理方式可以删除系统菜单设置对应key值也可删除不需要的菜单处理
*/
];
return [
[
'menu_name' => '插件站点菜单',
'menu_key' => 'niucloud_site_hello',
'menu_type' => 1,
'icon' => 'iconfont-iconyingyongshichang',
'api_url' => '',
'router_path' => 'hello_world',
'view_path' => 'hello_world/site',
'methods' => '',
'sort' => 100,
'status' => 1,
'is_show' => 1,
]
];

View File

@ -3,7 +3,7 @@ return [
'pages' => <<<EOT
// PAGE_BEGIN
{
"path": "addon/{{addon_name}}/pages/index",
"path": "hello_world/pages/index",
"style": {
// #ifdef H5
"navigationStyle": "custom",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

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