mirror of
https://gitee.com/niucloud-team/javashop.git
synced 2026-04-25 11:18:23 +00:00
0.0.2
商城新增功能满减送 排行榜 新人礼 商品数据统计 商城手机端版面全面优化
This commit is contained in:
parent
2a16950fbd
commit
b87c0990e0
4
admin/auto-imports.d.ts
vendored
4
admin/auto-imports.d.ts
vendored
@ -1,7 +1,5 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
export {}
|
||||
declare global {
|
||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
||||
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
|
||||
const ElNotification: typeof import('element-plus/es')['ElNotification']
|
||||
|
||||
}
|
||||
|
||||
14
admin/components.d.ts
vendored
14
admin/components.d.ts
vendored
@ -11,15 +11,9 @@ declare module '@vue/runtime-core' {
|
||||
DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
|
||||
Editor: typeof import('./src/components/editor/index.vue')['default']
|
||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCarousel: typeof import('element-plus/es')['ElCarousel']
|
||||
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
|
||||
ElCascader: typeof import('element-plus/es')['ElCascader']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
@ -34,8 +28,6 @@ declare module '@vue/runtime-core' {
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
@ -46,19 +38,14 @@ declare module '@vue/runtime-core' {
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElLink: typeof import('element-plus/es')['ElLink']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElOptionGroup: typeof import('element-plus/es')['ElOptionGroup']
|
||||
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElRate: typeof import('element-plus/es')['ElRate']
|
||||
ElResult: typeof import('element-plus/es')['ElResult']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
@ -67,7 +54,6 @@ declare module '@vue/runtime-core' {
|
||||
ElStatistic: typeof import('element-plus/es')['ElStatistic']
|
||||
ElStep: typeof import('element-plus/es')['ElStep']
|
||||
ElSteps: typeof import('element-plus/es')['ElSteps']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"menuTypeButton": "按钮",
|
||||
"menuDeleteTips": "删除菜单会删除当前菜单以及该菜单下所有子菜单,是否确认删除?",
|
||||
"initializeMenu":"重置菜单",
|
||||
"initializeMenuTipsOne":"重置菜单会将应用或插件的menu目录下的菜单配置文件中,菜单配置更新到数据库一般用做开发者修改了menu菜单配置文件后,同步到数据库操作。",
|
||||
"initializeMenuTipsOne":"重置菜单会将应用或插件的dict目录下的菜单配置文件中,菜单配置更新到数据库一般用做开发者修改了dict菜单配置文件后,同步到数据库操作。",
|
||||
"initializeMenuTipsTwo":"如果用户手动调整过以下菜单项,通常允许进行本项操作,操作会重置为原始菜单。 请谨慎使用!",
|
||||
"addMenu": "添加菜单",
|
||||
"updateMenu": "编辑菜单",
|
||||
|
||||
@ -28,5 +28,6 @@
|
||||
"manager": "用户",
|
||||
"managerPlaceholder": "请选择用户",
|
||||
"managerTips": "选择或者新增用户作为管理员",
|
||||
"newAddManager": "新增用户"
|
||||
}
|
||||
"newAddManager": "新增用户",
|
||||
"userDeleteTips": "是否要删除该管理员?"
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"preview": "预览图",
|
||||
"copy": "复制",
|
||||
"clickVisit": "点击访问",
|
||||
"PCDomainName": "pc域名",
|
||||
"pCDomainName": "pc域名",
|
||||
"newInfo": "最新消息",
|
||||
"isOpen": "是否开启"
|
||||
}
|
||||
|
||||
@ -20,5 +20,6 @@
|
||||
"customMenu": "自定义菜单",
|
||||
"wechatTemplate": "模板消息",
|
||||
"menusEmptyTips": "空菜单,不能保存与发布。",
|
||||
"reply": "自动回复"
|
||||
"reply": "自动回复",
|
||||
"menuUrlErrorTips": "请输入完整的网页链接,如https://www.baidu.com"
|
||||
}
|
||||
|
||||
@ -62,6 +62,8 @@
|
||||
"imageUpload": "图片上传",
|
||||
"imageSet": "图片设置",
|
||||
"imageAdsTips": "建议上传尺寸相同的图片,推荐尺寸750*350",
|
||||
"imageAdsSameScreenTips": "开启沉浸式样式,请确保该图片广告组件在页面中位于最顶端;为保证体验,请不要开导航栏;沉浸式样式仅在微信小程序中生效。",
|
||||
"sameScreen": "沉浸式",
|
||||
"addImageAd": "添加图片",
|
||||
"imageUrlTip": "请上传图片",
|
||||
"imageHeight": "图片高度",
|
||||
@ -86,6 +88,7 @@
|
||||
"graphicNavShowStyle": "展示风格",
|
||||
"graphicNavStyleFixed": "固定显示",
|
||||
"graphicNavStyleSingleSlide": "单行滑动",
|
||||
"graphicNavStyleMultiLine": "多行滑动",
|
||||
"graphicNavStylePageSlide": "分页滑动",
|
||||
"graphicNavRowCount": "每行数量",
|
||||
"graphicNavPageCount": "显示方式",
|
||||
@ -104,6 +107,9 @@
|
||||
"styleSet": "风格设置",
|
||||
"titleStyle": "标题样式",
|
||||
"selectStyle": "风格选择",
|
||||
"activeCubeBlockBtnText": "按钮文字",
|
||||
"btnTextItalics": "斜体",
|
||||
"btnTextNormal": "常规",
|
||||
"styleLabel": "风格",
|
||||
"styleShowTips": "风格 1 2 3,仅在小程序中展示",
|
||||
"titleContent": "标题内容",
|
||||
@ -198,8 +204,17 @@
|
||||
"carouselSearchShowWayStatic": "正常显示",
|
||||
"carouselSearchShowWayFixed": "滚动至顶部固定",
|
||||
"carouselSearchFixedBgColor": "置顶背景",
|
||||
"carouselSearchStyleSelect": "风格选择",
|
||||
"carouselSearchSet": "搜索设置",
|
||||
"carouselSearchSubTitle": "副标题",
|
||||
"carouselSearchSubTitleStyle": "副标题样式",
|
||||
"carouselSearchPositionStyle": "定位样式",
|
||||
"carouselSearchSubTitlePlaceholder": "请输入副标题内容",
|
||||
"carouselSearchText": "搜索内容",
|
||||
"carouselSearchTextColor": "文字颜色",
|
||||
"carouselSearchBgColor": "背景颜色",
|
||||
"carouselSearchBtnColor": "按钮颜色",
|
||||
"carouselSearchBtnBgColor": "按钮背景色",
|
||||
"carouselSearchHotWordSet": "搜索热词",
|
||||
"carouselSearchHotWordInterval": "显示时间 / 秒",
|
||||
"carouselSearchHotWordText": "内容",
|
||||
@ -222,6 +237,7 @@
|
||||
"carouselSearchSwiperInterval": "切换间隔 / 秒",
|
||||
"carouselSearchSwiperTips": "建议上传尺寸相同的图片,推荐尺寸750*350;鼠标拖拽可调整图片顺序",
|
||||
"carouselSearchTabStyle": "选项卡样式",
|
||||
"carouselSearchStyle": "搜索框样式",
|
||||
"noColor": "常规颜色",
|
||||
"selectColor": "选中颜色",
|
||||
"fixedNoColor": "下滑常规颜色",
|
||||
@ -231,6 +247,7 @@
|
||||
"carouselSearchSwiperStyle": "轮播样式",
|
||||
"carouselSearchSwiperIndicatorStyle1": "样式1",
|
||||
"carouselSearchSwiperIndicatorStyle2": "样式2",
|
||||
"carouselSearchSwiperIndicatorStyle3": "样式3",
|
||||
"carouselSearchSwiperIndicatorAlign": "显示位置",
|
||||
"alignLeft": "居左",
|
||||
"alignCenter": "居中",
|
||||
@ -256,5 +273,13 @@
|
||||
"rollTopStatusBarTextColor": "滚动后标题颜色",
|
||||
"topStatusBarSearchName": "搜索内容",
|
||||
"topStatusBarSearchNamePlaceholder": "请输入搜索关键词",
|
||||
"settingTips": "点击查看如何配置"
|
||||
"settingTips": "点击查看如何配置",
|
||||
"pictureShowBlockOne": "模块一",
|
||||
"pictureShowBlockTwo": "模块二",
|
||||
"subTitleTextColor": "标题颜色",
|
||||
"pictureShowBgColor": "背景颜色",
|
||||
"pictureShowBtnText": "按钮文字",
|
||||
"pictureShowBtnColor": "文字颜色",
|
||||
"pictureShowBtnBgColor": "背景颜色",
|
||||
"pictureShowBlockStyle": "模块样式"
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
"titlePlaceholder": "请输入页面名称",
|
||||
"addDiyPage": "添加页面",
|
||||
"diyPageDeleteTips": "确定要删除该自定义页面吗?",
|
||||
"diyPageCopyTips": "确定要复制该自定义页面吗?",
|
||||
"preview": "预览",
|
||||
"share": "分享",
|
||||
"shareSet": "分享设置",
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
{
|
||||
"title": "插件名称",
|
||||
"key": "插件标识"
|
||||
"key": "插件标识",
|
||||
"type": "插件类型",
|
||||
"app": "应用",
|
||||
"addon": "插件"
|
||||
}
|
||||
291
admin/src/app/lang/zh-cn/diy_form.edit.json
Normal file
291
admin/src/app/lang/zh-cn/diy_form.edit.json
Normal file
@ -0,0 +1,291 @@
|
||||
{
|
||||
"templatePagePlaceholder": "选择模板",
|
||||
"templatePageEmpty": "无",
|
||||
"changeTemplatePageTips": "切换模板后,当前页面内容将被替换且不被保存,请谨慎操作",
|
||||
"developTitle": "开发环境配置",
|
||||
"wapDomain": "wap域名(WAP_DOMAIN)",
|
||||
"wapDomainPlaceholder": "请输入wap域名",
|
||||
"pageSet": "页面设置",
|
||||
"tabEditContent": "内容",
|
||||
"tabEditStyle": "样式",
|
||||
"pageStyle": "页面样式",
|
||||
"pageContent": "页面内容",
|
||||
"statusBarContent": "导航栏内容",
|
||||
"statusBarStyle": "导航栏样式",
|
||||
"statusBarSwitchTips": "此处控制当前页面导航栏是否显示",
|
||||
"bottomNavContent": "底部导航内容",
|
||||
"diyPageTitle": "页面名称",
|
||||
"diyPageTitlePlaceholder": "请输入页面名称",
|
||||
"pageTitleTips": "页面名称用于后台显示",
|
||||
"diyTitle": "页面标题",
|
||||
"diyTitlePlaceholder": "请输入页面标题",
|
||||
"titleTips": "页面标题用于前台显示",
|
||||
"pageBgColor": "页面颜色",
|
||||
"bgUrl": "背景图片",
|
||||
"bgHeightScale": "高度比例",
|
||||
"bgHeightScaleTip": "为0时背景高度自适应展示",
|
||||
"marginSet": "边距设置",
|
||||
"componentStyleTitle": "组件样式",
|
||||
"bottomBgColor": "底部背景",
|
||||
"bottomBgTips": "底部背景包含边距和圆角",
|
||||
"componentBgColor": "组件背景色",
|
||||
"componentBgUrl": "组件背景图",
|
||||
"componentBgAlpha": "透明度",
|
||||
"bgGradientAngle": "渐变角度",
|
||||
"topToBottom": "从上到下",
|
||||
"leftToRight": "从左到右",
|
||||
"marginTop": "上边距",
|
||||
"marginBottom": "下边距",
|
||||
"marginBoth": "左右边距",
|
||||
"topRounded": "上圆角",
|
||||
"bottomRounded": "下圆角",
|
||||
"warmPrompt": "温馨提示",
|
||||
"leavePageTitleTips": "确定离开此页面?",
|
||||
"leavePageContentTips": "系统可能不会保存您所做的更改。",
|
||||
"decorating": "正在装修",
|
||||
"preview": "保存并预览",
|
||||
"moveUpComponent": "上移",
|
||||
"moveDownComponent": "下移",
|
||||
"copyComponent": "复制",
|
||||
"delComponent": "删除",
|
||||
"resetComponent": "重置",
|
||||
"tabbar": "底部导航",
|
||||
"tabbarSwitchTips": "此处控制当前页面底部导航菜单是否显示",
|
||||
"link": "链接地址",
|
||||
"delComponentTips": "确认要删除当前组件吗?",
|
||||
"notCopy": "无法复制",
|
||||
"componentCanOnlyAdd": "组件只能添加",
|
||||
"piece": "个",
|
||||
"componentNotMoved": "该组件禁止移动",
|
||||
"resetComponentTips": "确认要重置组件默认数据吗?",
|
||||
"image": "图片上传",
|
||||
"imageUpload": "图片上传",
|
||||
"imageSet": "图片设置",
|
||||
"imageAdsTips": "建议上传尺寸相同的图片,推荐尺寸750*350",
|
||||
"imageAdsSameScreenTips": "开启沉浸式样式,请确保该图片广告组件在页面中位于最顶端;为保证体验,请不要开导航栏;沉浸式样式仅在微信小程序中生效。",
|
||||
"sameScreen": "沉浸式",
|
||||
"addImageAd": "添加图片",
|
||||
"imageUrlTip": "请上传图片",
|
||||
"imageHeight": "图片高度",
|
||||
"imageHeightPlaceholder": "请输入图片高度",
|
||||
"imageHeightRegNum": "图片高度格式错误,请输入数字",
|
||||
"dataSources": "数据来源",
|
||||
"defaultSources": "默认",
|
||||
"manualSelectionSources": "手动选择",
|
||||
"selectPlaceholder": "请选择",
|
||||
"selected": "已选",
|
||||
"graphicNavModeTitle": "导航模式",
|
||||
"layoutMode": "排版模式",
|
||||
"layoutModeHorizontal": "横排",
|
||||
"layoutModeVertical": "竖排",
|
||||
"graphicNavSelectMode": "选择模式",
|
||||
"graphicNavModeGraphic": "图文导航",
|
||||
"graphicNavModeImg": "图片导航",
|
||||
"graphicNavModeText": "文字导航",
|
||||
"graphicNavImageSet": "图片设置",
|
||||
"graphicNavImageSize": "图片大小",
|
||||
"graphicNavAroundRadius": "图片圆角",
|
||||
"graphicNavShowStyle": "展示风格",
|
||||
"graphicNavStyleFixed": "固定显示",
|
||||
"graphicNavStyleSingleSlide": "单行滑动",
|
||||
"graphicNavStyleMultiLine": "多行滑动",
|
||||
"graphicNavStylePageSlide": "分页滑动",
|
||||
"graphicNavRowCount": "每行数量",
|
||||
"graphicNavPageCount": "显示方式",
|
||||
"graphicNavSetLabel": "导航设置",
|
||||
"singleLine": "单行",
|
||||
"multiline": "多行",
|
||||
"graphicNavTips": "建议上传尺寸相同的图片,推荐尺寸60*60",
|
||||
"graphicNavTitle": "标题",
|
||||
"graphicNavTitlePlaceholder": "请输入标题",
|
||||
"subGraphicNavTitle": "副标题",
|
||||
"subGraphicNavTitlePlaceholder": "请输入副标题",
|
||||
"subGraphicNavTitleLink": "副标题链接",
|
||||
"addGraphicNav": "添加导航",
|
||||
"blankHeightSet": "高度设置",
|
||||
"blankHeight": "空白高度",
|
||||
"styleSet": "风格设置",
|
||||
"titleStyle": "标题样式",
|
||||
"selectStyle": "风格选择",
|
||||
"activeCubeBlockBtnText": "按钮文字",
|
||||
"btnTextItalics": "斜体",
|
||||
"btnTextNormal": "常规",
|
||||
"styleLabel": "风格",
|
||||
"styleShowTips": "风格 1 2 3,仅在小程序中展示",
|
||||
"titleContent": "标题内容",
|
||||
"title": "标题名称",
|
||||
"titlePlaceholder": "请输入标题",
|
||||
"textAlign": "对齐方式",
|
||||
"textAlignLeft": "居左",
|
||||
"textAlignCenter": "居中",
|
||||
"textSet": "文字设置",
|
||||
"textFontSize": "文字大小",
|
||||
"textFontWeight": "文字粗细",
|
||||
"fontWeightBold": "加粗",
|
||||
"fontWeightNormal": "常规",
|
||||
"textColor": "文字颜色",
|
||||
"subTitleStyle": "副标题样式",
|
||||
"subTextBgColor": "背景色",
|
||||
"subTitleContent": "标题内容",
|
||||
"subTitle": "副标题",
|
||||
"subTitlePlaceholder": "请输入副标题",
|
||||
"moreContent": "“更多”按钮内容",
|
||||
"more": "文字",
|
||||
"morePlaceholder": "请输入文字",
|
||||
"moreIsShow": "是否显示",
|
||||
"memberStyle": "会员样式",
|
||||
"template": "模板",
|
||||
"imageGap": "图片间隙",
|
||||
"rubikCubeStyle": "魔方样式",
|
||||
"rubikCubeLayout": "魔方布局",
|
||||
"hotArea": "热区",
|
||||
"hotAreaSet": "热区设置",
|
||||
"hotAreaBackground": "热区背景",
|
||||
"addHotArea": "添加热区",
|
||||
"clickSet": "点击设置",
|
||||
"selectedAfterHotArea": "个热区",
|
||||
"hotAreaManage": "热区管理",
|
||||
"selectedHotArea": "请选择热区",
|
||||
"hotAreaLink": "的链接地址",
|
||||
"addonListSet": "应用设置",
|
||||
"addonListTips": "应用选择",
|
||||
"selectAddonTips": "请选择应用",
|
||||
"addonTitle": "应用名称",
|
||||
"addonDesc": "应用描述",
|
||||
"addonIcon": "应用图标",
|
||||
"selectAddon": "选择应用",
|
||||
"addAddon": "添加应用",
|
||||
"show": "显示",
|
||||
"hidden": "隐藏",
|
||||
"goodsCategoryTitle": "商品分类",
|
||||
"customGoods": "手动选择",
|
||||
"goodsNum": "商品数量",
|
||||
"selectCategory": "选择分类",
|
||||
"categoryName": "分类名称",
|
||||
"categoryImage": "分类图片",
|
||||
"selectSource": "选择数据源",
|
||||
"richTextContentSet": "内容设置",
|
||||
"richTextPlaceholder": "请输入富文本内容",
|
||||
"activeCubeBlockContent": "板块内容",
|
||||
"activeCubeTitle": "标题",
|
||||
"activeCubeTitlePlaceholder": "请输入标题",
|
||||
"activeCubeSubTitle": "副标题",
|
||||
"activeCubeSubTitlePlaceholder": "请输入副标题",
|
||||
"activeCubeButton": "按钮",
|
||||
"activeCubeButtonPlaceholder": "请输入按钮文字",
|
||||
"activeCubeButtonColor": "按钮颜色",
|
||||
"activeListFrameColor": "框体颜色",
|
||||
"activeCubeSubTitleTextColor": "文字颜色",
|
||||
"activeCubeSubTitleBgColor": "背景颜色",
|
||||
"activeCubeAddItem": "添加一个板块",
|
||||
"activeCubeBlockStyle": "板块样式",
|
||||
"activeCubeBlockTextFontWeight": "标题粗细",
|
||||
"noticeStyle": "公告风格",
|
||||
"noticeType": "类型",
|
||||
"noticeTypeImg": "图片",
|
||||
"noticeTypeText": "文字",
|
||||
"noticeTypeTextPlaceholder": "请输入公告标题",
|
||||
"noticeTitle": "公告标题",
|
||||
"addNotice": "添加公告",
|
||||
"noticeText": "公告内容",
|
||||
"noticeScrollWay": "滚动方式",
|
||||
"noticeUpDown": "上下滚动",
|
||||
"noticeHorizontal": "横向滚动",
|
||||
"noticeShowType": "点击类型",
|
||||
"noticeShowPopUp": "弹出公告内容",
|
||||
"noticeShowLink": "跳转链接",
|
||||
"dragMouseAdjustOrder": "鼠标拖拽可调整顺序",
|
||||
"noticePlaceholderText": "请输入公告内容",
|
||||
"carouselSearchShowPosition": "显示设置",
|
||||
"carouselSearchOpen": "开启",
|
||||
"carouselSearchClose": "关闭",
|
||||
"carouselSearchBgGradient": "背景渐变",
|
||||
"carouselSearchShowWay": "展示方式",
|
||||
"carouselSearchShowWayStatic": "正常显示",
|
||||
"carouselSearchShowWayFixed": "滚动至顶部固定",
|
||||
"carouselSearchFixedBgColor": "置顶背景",
|
||||
"carouselSearchStyleSelect": "风格选择",
|
||||
"carouselSearchSet": "搜索设置",
|
||||
"carouselSearchSubTitle": "副标题",
|
||||
"carouselSearchSubTitleStyle": "副标题样式",
|
||||
"carouselSearchPositionStyle": "定位样式",
|
||||
"carouselSearchSubTitlePlaceholder": "请输入副标题内容",
|
||||
"carouselSearchText": "搜索内容",
|
||||
"carouselSearchTextColor": "文字颜色",
|
||||
"carouselSearchBgColor": "背景颜色",
|
||||
"carouselSearchBtnColor": "按钮颜色",
|
||||
"carouselSearchBtnBgColor": "按钮背景色",
|
||||
"carouselSearchHotWordSet": "搜索热词",
|
||||
"carouselSearchHotWordInterval": "显示时间 / 秒",
|
||||
"carouselSearchHotWordText": "内容",
|
||||
"carouselSearchHotWordTextPlaceholder": "请输入热词",
|
||||
"carouselSearchAddHotWordItem": "添加一个热词",
|
||||
"carouselSearchLogoTips": "建议尺寸,70px * 30px",
|
||||
"carouselSearchTextTips": "搜索内容是默认展示数据,当添加搜索热词时,搜索内容隐藏; 当没有搜索热词时,搜索内容展示",
|
||||
"carouselSearchPlaceholder": "请输入搜索内容",
|
||||
"carouselSearchTabSet": "选项卡设置",
|
||||
"carouselSearchTabControl": "展示开关",
|
||||
"carouselSearchTabCategoryText": "分类名称",
|
||||
"carouselSearchTabCategoryTextPlaceholder": "请输入分类名称",
|
||||
"carouselSearchAddTabItem": "添加一个选项卡",
|
||||
"selectSourcesDiyPage": "选择微页面",
|
||||
"selectDiyPagePlaceholder": "请选择微页面",
|
||||
"diyPageTypeName": "页面类型",
|
||||
"diyPageForAddon": "所属应用",
|
||||
"carouselSearchSwiperSet": "轮播图设置",
|
||||
"carouselSearchSwiperControl": "展示开关",
|
||||
"carouselSearchSwiperInterval": "切换间隔 / 秒",
|
||||
"carouselSearchSwiperTips": "建议上传尺寸相同的图片,推荐尺寸750*350;鼠标拖拽可调整图片顺序",
|
||||
"carouselSearchTabStyle": "选项卡样式",
|
||||
"carouselSearchStyle": "搜索框样式",
|
||||
"noColor": "常规颜色",
|
||||
"selectColor": "选中颜色",
|
||||
"fixedNoColor": "下滑常规颜色",
|
||||
"fixedSelectColor": "下滑选中颜色",
|
||||
"carouselSearchSwiperIndicatorSet": "指示器设置",
|
||||
"carouselSearchSwiperIndicatorStyle": "指示器样式",
|
||||
"carouselSearchSwiperStyle": "轮播样式",
|
||||
"carouselSearchSwiperIndicatorStyle1": "样式1",
|
||||
"carouselSearchSwiperIndicatorStyle2": "样式2",
|
||||
"carouselSearchSwiperIndicatorStyle3": "样式3",
|
||||
"carouselSearchSwiperIndicatorAlign": "显示位置",
|
||||
"alignLeft": "居左",
|
||||
"alignCenter": "居中",
|
||||
"alignRight": "居右",
|
||||
"horzLineStyle": "线条风格",
|
||||
"horzLineStyleSolid": "实线",
|
||||
"horzLineStyleDashed": "虚线",
|
||||
"horzLineBorderColor": "线条颜色",
|
||||
"horzLineBorderWidth": "线条宽度",
|
||||
"floatBtnBtton": "按钮位置",
|
||||
"floatBtnOffset": "上下偏移",
|
||||
"floatBtnImageSet": "图片设置",
|
||||
"floatBtnImageSize": "图片大小",
|
||||
"floatBtnAroundRadius": "图片圆角",
|
||||
"floatBtnImageSuggest": "建议上传正方形图片",
|
||||
"topStatusBarImg": "图片",
|
||||
"topStatusBarNav": "导航栏",
|
||||
"topStatusBarNavTips": "此处控制当前页面导航栏是否显示",
|
||||
"topStatusBarImgTips": "宽度自适应(最大150px),高度28px",
|
||||
"topStatusBarTextColor": "标题颜色",
|
||||
"topStatusBarBgColor": "头部颜色",
|
||||
"rollTopStatusBarBgColor": "滚动后头部颜色",
|
||||
"rollTopStatusBarTextColor": "滚动后标题颜色",
|
||||
"topStatusBarSearchName": "搜索内容",
|
||||
"topStatusBarSearchNamePlaceholder": "请输入搜索关键词",
|
||||
"settingTips": "点击查看如何配置",
|
||||
"pictureShowBlockOne": "模块一",
|
||||
"pictureShowBlockTwo": "模块二",
|
||||
"subTitleTextColor": "标题颜色",
|
||||
"pictureShowBgColor": "背景颜色",
|
||||
"pictureShowBtnText": "按钮文字",
|
||||
"pictureShowBtnColor": "文字颜色",
|
||||
"pictureShowBtnBgColor": "背景颜色",
|
||||
"pictureShowBlockStyle": "模块样式",
|
||||
|
||||
"defaultValue": "默认值",
|
||||
"defaultValuePlaceholder": "请输入默认值",
|
||||
"formPlaceholder": "提示语",
|
||||
"formPlaceholderTips": "请输入提示语",
|
||||
"isRequired": "是否必填"
|
||||
}
|
||||
34
admin/src/app/lang/zh-cn/diy_form.list.json
Normal file
34
admin/src/app/lang/zh-cn/diy_form.list.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"title": "表单名称",
|
||||
"typeName": "表单类型",
|
||||
"forAddon": "所属应用",
|
||||
"forAddonPlaceholder": "请选择所属应用",
|
||||
"addFormTips": "创建新表单",
|
||||
"formTypePlaceholder": "请选择表单类型",
|
||||
"nameMax": "名称不能超过12个字符",
|
||||
"status": "状态",
|
||||
"updateTime": "更新时间",
|
||||
"statusOn": "启用",
|
||||
"statusOff": "禁用",
|
||||
"all": "全部",
|
||||
"wapUrl": "wap链接",
|
||||
"weappUrl": "小程序链接",
|
||||
"shareLink": "分享链接",
|
||||
"copy": "复制",
|
||||
"copySuccess": "复制成功",
|
||||
"titlePlaceholder": "请输入表单名称",
|
||||
"addDiyForm": "添加表单",
|
||||
"diyFormDeleteTips": "确定要删除该自定义表单吗?",
|
||||
"diyFormCopyTips": "确定要复制该自定义表单吗?",
|
||||
"preview": "预览",
|
||||
"share": "分享",
|
||||
"shareSet": "分享设置",
|
||||
"sharePage": "分享表单",
|
||||
"wechat": "微信公众号",
|
||||
"weapp": "微信小程序",
|
||||
"shareTitle": "分享标题",
|
||||
"shareTitlePlaceholder": "请输入分享标题",
|
||||
"shareDesc": "分享描述",
|
||||
"shareDescPlaceholder": "请输入分享描述",
|
||||
"shareImageUrl": "分享图片"
|
||||
}
|
||||
@ -1,48 +1,50 @@
|
||||
{
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"totalTransfered":"累计提现(元)",
|
||||
"totalCashOuting":"提现中(元)",
|
||||
"transfered":"累计提现",
|
||||
"cashOuting":"提现中",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择",
|
||||
"applyTime":"申请时间",
|
||||
"cashOutStatus":"提现状态",
|
||||
"actualTransferAmount":"实际转账金额",
|
||||
"cashOutCommission":"提现手续费",
|
||||
"applicationForWithdrawalAmount":"申请提现金额",
|
||||
"cashOutMethod":"提现方式",
|
||||
"cashOutAccountType":"会员账户",
|
||||
"memberInfo":"会员信息",
|
||||
"toBeReviewed":"待审核",
|
||||
"toBeTransferred":"待转账",
|
||||
"transferred":"已转账",
|
||||
"turnDown":"拒绝",
|
||||
"transfer": "转账",
|
||||
"detail": "详情",
|
||||
"auditFailure": "审核失败",
|
||||
"successfulAudit": "审核成功",
|
||||
"rejectionAudit": "拒绝审核",
|
||||
"reasonsRefusal": "拒绝理由",
|
||||
"reasonsRefusalPlaceholder": "请输入拒绝理由",
|
||||
"isTransfer": "是否确认转账",
|
||||
"nickname":"会员名称",
|
||||
"headimg":"会员头像",
|
||||
"cashOutDetail":"提现详情",
|
||||
"cashOutMoney": "转账金额",
|
||||
"orderNo": "订单编号",
|
||||
"orderStatus": "订单状态",
|
||||
"orderNoPlaceholder": "请输入订单编号",
|
||||
"createTime": "创建时间",
|
||||
"rechargeMoney": "充值金额",
|
||||
"totalTransfered": "累计提现(元)",
|
||||
"totalCashOuting": "提现中(元)",
|
||||
"transfered": "累计提现",
|
||||
"cashOuting": "提现中",
|
||||
"orderMoney": "订单金额",
|
||||
"member": "买家",
|
||||
"orderFromName": "订单来源",
|
||||
"payTypeName": "支付方式",
|
||||
"startDate": "开始时间",
|
||||
"endDate": "结束时间",
|
||||
"namePlaceholder": "请选择",
|
||||
"applyTime": "申请时间",
|
||||
"cashOutStatus": "提现状态",
|
||||
"actualTransferAmount": "实际转账金额",
|
||||
"cashOutCommission": "提现手续费",
|
||||
"applicationForWithdrawalAmount": "申请提现金额",
|
||||
"cashOutMethod": "提现方式",
|
||||
"cashOutAccountType": "会员账户",
|
||||
"memberInfo": "会员信息",
|
||||
"toBeReviewed": "待审核",
|
||||
"toBeTransferred": "待转账",
|
||||
"transferred": "已转账",
|
||||
"turnDown": "拒绝",
|
||||
"transfer": "转账",
|
||||
"detail": "详情",
|
||||
"auditFailure": "审核失败",
|
||||
"successfulAudit": "审核成功",
|
||||
"rejectionAudit": "拒绝审核",
|
||||
"reasonsRefusal": "拒绝理由",
|
||||
"reasonsRefusalPlaceholder": "请输入拒绝理由",
|
||||
"isTransfer": "是否确认转账",
|
||||
"nickname": "会员名称",
|
||||
"headimg": "会员头像",
|
||||
"cashOutDetail": "提现详情",
|
||||
"cashOutMoney": "转账金额",
|
||||
"auditTime": "审核时间",
|
||||
"transferTime": "转账时间",
|
||||
"memberInfoPlaceholder":"请输入会员名称/会员昵称/手机号",
|
||||
"memberInfoPlaceholder": "请输入会员名称/会员昵称/手机号",
|
||||
"cashOutNumber": "提现单号",
|
||||
"cashOutNumberPlaceholder": "请输入提现单号"
|
||||
|
||||
"cashOutNumberPlaceholder": "请输入提现单号",
|
||||
"alipayAccount": "支付宝账号",
|
||||
"bankName": "银行名称",
|
||||
"bankAccount": "银行卡号"
|
||||
}
|
||||
|
||||
@ -6,5 +6,11 @@
|
||||
"createTime": "申请时间",
|
||||
"refundNoPlaceholder": "请输入退款编号",
|
||||
"startDate": "开始时间",
|
||||
"endDate": "结束时间"
|
||||
"endDate": "结束时间",
|
||||
"outTradeNo": "交易流水号",
|
||||
"refundTypeName": "退款方式",
|
||||
"statusName": "退款状态",
|
||||
"transfer": "转账",
|
||||
"transferType": "转账方式",
|
||||
"voucher": "凭证"
|
||||
}
|
||||
|
||||
@ -4,9 +4,12 @@
|
||||
"isUse": "是否启用",
|
||||
"signPeriod": "签到周期",
|
||||
"signPeriodTip": "请输入签到周期",
|
||||
"signPeriodLimitTips": "签到周期格式错误",
|
||||
"signPeriodMustZeroTips": "签到周期必须大于0",
|
||||
"calendarSign": "日历签到",
|
||||
"periodSign": "周期签到",
|
||||
"daySignAward": "日签奖励",
|
||||
"daySignAwardPlaceholder": "请选择日签奖励",
|
||||
"continueSignAward": "连签奖励",
|
||||
"calendarSignTip": "用户根据日期进行打卡,连续签到一定天数可即可获得连签奖励。",
|
||||
"periodSignTip": "用户在规定的周期内完成签到可以获得奖励;一个周期结束后将进入下一个循环周期。",
|
||||
|
||||
@ -6,13 +6,11 @@
|
||||
"createTime":"注册时间",
|
||||
"lastVisitTime":"最后访问时间",
|
||||
"addMember":"添加会员",
|
||||
"updateMember":"编辑会员",
|
||||
"nickNamePlaceholder":"请输入会员昵称",
|
||||
"mobilePlaceholder":"请输入手机号",
|
||||
"channelPlaceholder":"请选择注册类型",
|
||||
"memberNoPlaceholder":"请选择会员编号",
|
||||
"memberDeleteTips" : "确定要删除该会员吗?",
|
||||
"detail": "详情",
|
||||
"edit": "编辑",
|
||||
"memberDelete":"删除",
|
||||
"adjust":"调整",
|
||||
@ -31,8 +29,8 @@
|
||||
"detaBirth": "出生日期",
|
||||
"sex": "性别",
|
||||
"wxUnionid": "微信unionid",
|
||||
"weappOpenid": "微信用户openid",
|
||||
"wxOpenid": "微信小程openid",
|
||||
"weappOpenid": "微信小程序openid",
|
||||
"wxOpenid": "微信用户openid",
|
||||
"head": "会员头像",
|
||||
"username": "用户名",
|
||||
"usernamePlaceholder": "请输入用户名",
|
||||
@ -44,12 +42,41 @@
|
||||
"mobileHint": "请输入正确的手机号!",
|
||||
"memberLabelTag": "标签",
|
||||
"setLabel": "标签",
|
||||
"notAvailable": "暂无",
|
||||
"memberLabelPlaceholder": "请选择会员标签",
|
||||
"memberInfo":"会员信息",
|
||||
"memberInfoPlaceholder":"请输入会员编号/昵称/手机号",
|
||||
"lock": "锁定",
|
||||
"normal": "正常",
|
||||
"memberLevel": "会员等级",
|
||||
"memberLevelPlaceholder": "请选择会员等级"
|
||||
"memberLevelPlaceholder": "请选择会员等级",
|
||||
"adjustType":"调整类型",
|
||||
"adjustReduceBalance":"减少余额",
|
||||
"adjustAddBalance":"增加余额",
|
||||
"adjustReducePoint":"减少积分",
|
||||
"adjustAddPoint":"增加积分",
|
||||
"adjustBalance":"调整余额",
|
||||
"currBalance":"当前余额",
|
||||
"currPoint":"当前积分",
|
||||
"adjustPlaceholder":"请输入调整数量",
|
||||
"memoPlaceholder":"请输入备注",
|
||||
"adjustBalancePlaceholder":"请输入调整余额",
|
||||
"adjustPointPlaceholder":"请输入调整积分",
|
||||
"adjustBalanceMaxAccountMessage":"调整后余额需大于0",
|
||||
"adjustPointMaxAccountMessage":"调整后积分需大于0",
|
||||
"birthday": "出生日期",
|
||||
"birthdayTip": "请输入出生日期",
|
||||
"headimg": "会员头像",
|
||||
"updateMember": "编辑会员信息",
|
||||
"notAvailable":"暂无",
|
||||
"girlSex":"女",
|
||||
"manSex":"男",
|
||||
"secrecySex":"保密",
|
||||
"detail":"详情",
|
||||
"accumulative":"累计",
|
||||
"money":"可提现余额",
|
||||
"commission":"佣金",
|
||||
"memberNull":"未读取到会员详情信息",
|
||||
"memberLevelUpdate": "修改等级至",
|
||||
"memberLevelUpdateTips": "该操作只会修改会员等级不会发放等级礼包"
|
||||
|
||||
}
|
||||
|
||||
@ -2,5 +2,7 @@
|
||||
"title": "协议标题",
|
||||
"type": "协议类型",
|
||||
"titlePlaceholder": "请输入协议标题",
|
||||
"contentPlaceholder": "请填写协议内容",
|
||||
"contentMaxTips": "协议内容字符数应在5~50000之间",
|
||||
"content": "内容"
|
||||
}
|
||||
@ -1,16 +1,23 @@
|
||||
{
|
||||
"logonMode": "普通注册方式",
|
||||
"isUsername": "账号密码登录",
|
||||
"isMobile": "手机验证码登录",
|
||||
"isAuthRegister": "第三方自动注册",
|
||||
"isBindMobile": "强制绑定手机",
|
||||
"isUsernameTip": "开启之后可以使用账号+密码进行注册和登录",
|
||||
"isMobileTip": "开启之后可以使用手机+验证码进行注册和登录",
|
||||
"isAuthRegisterTip": "开启之后,微信公众号、小程序等等第三方平台可以自动注册会员。方便会员自动登录",
|
||||
"isBindMobileTip": "开启之后,会员通过账号或者第三方注册账户会强制绑定手机号,方便商家进行管理,同时方便会员在不同端口统一账号",
|
||||
"agreement": "政策协议",
|
||||
"agreementTips": "注册时服务协议和隐私协议是否进行展示",
|
||||
"mobileOrUsernameNoEmpty":"普通注册方式至少需启用一种",
|
||||
"commonSetting": "通用设置",
|
||||
"tripartiteSetting": "第三方设置"
|
||||
"commonSetting": "通用设置",
|
||||
"logonMode": "普通注册方式",
|
||||
"isUsername": "账号密码登录",
|
||||
"isUsernameTip": "开启之后可以使用账号+密码进行注册和登录",
|
||||
"isMobile": "手机验证码登录",
|
||||
"isMobileTip": "开启之后可以使用手机+验证码进行注册和登录或者快捷登录/注册",
|
||||
"isBindMobile": "强制绑定手机",
|
||||
"isBindMobileTip": "开启之后,会员注册时会强制绑定手机号,并且在相关页面也会引导会员强制绑定手机账号,否则将影响功能正常使用,方便会员在不同端口统一账号,也方便商家进行管理",
|
||||
"agreement": "政策协议",
|
||||
"agreementTips": "注册时服务协议和隐私协议是否进行展示",
|
||||
"tripartiteSetting": "第三方设置",
|
||||
"isAuthRegister": "自动注册会员",
|
||||
"isAuthRegisterTip": "开启之后,微信公众号、小程序等第三方平台可以自动注册会员或者快捷登录/注册会员,方便会员自动登录",
|
||||
"isForceAccessUserInfo": "强制获取用户信息",
|
||||
"isForceAccessUserInfoTip": "开启之后,将强制获取用户头像、昵称等信息,需要用户同意后,才能注册成功",
|
||||
"mobileOrUsernameNoEmpty": "普通注册方式至少需启用一种",
|
||||
"loginPageSet": "界面设置",
|
||||
"bgUrl": "背景图",
|
||||
"bgUrlPlaceholder": "建议图片尺寸:750*669像素;图片格式:jpg、png、jpeg",
|
||||
"desc": "描述",
|
||||
"descPlaceholder": "请输入描述"
|
||||
}
|
||||
@ -4,8 +4,8 @@
|
||||
"isOpen": "定位开关",
|
||||
"validTime": "定位有效期",
|
||||
"minutes": "分钟",
|
||||
"validTimeTips": "过期后将重新获取定位信息,0为不过期",
|
||||
"validTimeTips": "过期后将重新获取定位信息",
|
||||
"validTimePlaceholder": "请输入定位有效期",
|
||||
"validTimeFormatTips": "格式输入错误",
|
||||
"validTimeNotZeroTips": "定位有效期不能小于0"
|
||||
"validTimeNotZeroTips": "定位有效期不能小于5分钟"
|
||||
}
|
||||
@ -13,9 +13,9 @@
|
||||
"mchId": "商户号",
|
||||
"mchIdPlaceholder": "请输入商户号",
|
||||
"mchIdTips": "微信支付商户号(MCHID)",
|
||||
"mchSecretKey": "API密钥",
|
||||
"mchSecretKeyPlaceholder": "请输入API密钥",
|
||||
"mchSecretKeyTips": "微信支付商户API密钥(paySignKey)",
|
||||
"mchSecretKey": "APIv3密钥",
|
||||
"mchSecretKeyPlaceholder": "请输入APIv3密钥",
|
||||
"mchSecretKeyTips": "微信支付商户APIv3密钥(paySignKey)",
|
||||
"mchSecretCert": "商户私钥",
|
||||
"mchSecretCertPlaceholder": "请上传商户私钥",
|
||||
"mchSecretCertTips": "微信支付API证书(apiclient_key.pem)",
|
||||
@ -57,5 +57,13 @@
|
||||
"collectionNamePlaceholder": "请输入收款账户名称",
|
||||
"collectionBankPlaceholder": "请输入收款银行",
|
||||
"collectionAccountPlaceholder": "请输入收款账号",
|
||||
"collectionDescPlaceholder": "请输入转账说明"
|
||||
"collectionDescPlaceholder": "请输入转账说明",
|
||||
"jsapiDir": "JSAPI支付授权目录",
|
||||
"jsapiDirTips": "需在微信商户号>产品中心>开发配置>支付配置 支付授权目录中添加该链接",
|
||||
"h5Domain": "H5支付域名",
|
||||
"h5DomainTips": "需在微信商户号>产品中心>开发配置>支付配置 H5支付域名中添加该域名",
|
||||
"nativeDomain": "Native支付回调链接",
|
||||
"nativeDomainTips": "需在微信商户号>产品中心>开发配置>支付配置 Native支付回调链接中添加该链接",
|
||||
"wechatpayPublicCert": "微信支付公钥",
|
||||
"wechatpayPublicCertId": "微信支付公钥ID"
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
"mchId": "商户号",
|
||||
"mchIdPlaceholder": "请输入商户号",
|
||||
"mchIdTips": "微信支付商户号(MCHID)",
|
||||
"mchSecretKey": "API密钥",
|
||||
"mchSecretKeyPlaceholder": "请输入API密钥",
|
||||
"mchSecretKeyTips": "微信支付商户API密钥(paySignKey)",
|
||||
"mchSecretKey": "APIv3密钥",
|
||||
"mchSecretKeyPlaceholder": "请输入APIv3密钥",
|
||||
"mchSecretKeyTips": "微信支付商户APIv3密钥(paySignKey)",
|
||||
"mchSecretCert": "商户私钥",
|
||||
"mchSecretCertPlaceholder": "请上传商户私钥",
|
||||
"mchSecretCertTips": "微信支付API证书(apiclient_key.pem)",
|
||||
@ -28,4 +28,4 @@
|
||||
"alipayPublicCertPathTips": "上传alipayCertPublicKey文件",
|
||||
"alipayRootCertPathTips": "上传alipayRootCert文件",
|
||||
"operationTip": "温馨提示:打款设置用于会员提现转账,发放红包等场景"
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,5 +33,6 @@
|
||||
"siteDomain": "站点域名",
|
||||
"siteDomainPlaceholder": "请输入站点域名",
|
||||
"siteDomainTips": "站点域名的配置是针对站点的wap和web端",
|
||||
"siteDomainTipsTwo": "需要将域名配置到您的服务器,同时域名需要解析您的服务器才可生效"
|
||||
"siteDomainTipsTwo": "需要将域名配置到您的服务器,同时域名需要解析您的服务器才可生效",
|
||||
"siteDomainTipsThree": "站点域名不需要加http或者https,末尾不需要加/"
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
"businessHours":"营业时间",
|
||||
"createTime":"创建时间",
|
||||
"expireTime":"到期时间",
|
||||
"siteNamePlaceholder":"请输入站点名称",
|
||||
"siteNamePlaceholder":"请输入站点名称/编号",
|
||||
"createTimePlaceholder":"请输入创建时间",
|
||||
"addSite":"添加站点",
|
||||
"editSite":"编辑站点",
|
||||
@ -52,5 +52,6 @@
|
||||
"siteDomainTipsTwo": "需要将域名配置到您的服务器,同时域名需要解析您的服务器才可生效",
|
||||
"siteDomainTipsThree": "站点域名不需要加http或者https,末尾不需要加/",
|
||||
"toSite": "访问站点",
|
||||
"noPermission": "您没有该站点的管理权限"
|
||||
"noPermission": "您没有该站点的管理权限",
|
||||
"closeSiteTips": "是否要停止该站点?"
|
||||
}
|
||||
|
||||
@ -5,11 +5,11 @@
|
||||
"lastLoginIP": "最后登录IP",
|
||||
"userNamePlaceholder": "请输入账号/用户名",
|
||||
"detail": "详情",
|
||||
"siteNum": "站点数量",
|
||||
"endDate": "结束时间",
|
||||
"startDate": "开始时间",
|
||||
"loginTime": "最后登录时间",
|
||||
"addUser": "添加用户",
|
||||
"updateUser": "编辑用户",
|
||||
"username": "账号",
|
||||
"passwordPlaceholder": "请输入用户密码",
|
||||
"usernamePlaceholder": "请输入用户账号",
|
||||
@ -19,10 +19,12 @@
|
||||
"userCreateSiteLimit": "套餐权限",
|
||||
"siteGroup": "站点套餐",
|
||||
"siteMonth": "站点效期限",
|
||||
"siteNum": "建站数量",
|
||||
"siteNum": "站点数量",
|
||||
"month": "月",
|
||||
"siteMonthPlaceholder": "请输入站点效期限",
|
||||
"siteNumPlaceholder": "请输入建站数量",
|
||||
"siteMonthCannotLtOne": "站点效期限不能小于1",
|
||||
"siteNumCannotLtOne": "建站数量不能小于1"
|
||||
"siteNumCannotLtOne": "建站数量不能小于1",
|
||||
"userDeleteTips": "确定要删除该用户吗?",
|
||||
"createSiteNum": "可创建站点数量"
|
||||
}
|
||||
|
||||
@ -26,5 +26,6 @@
|
||||
"monthPlaceholder": "请输入站点创建有效期限",
|
||||
"numCannotLtZero": "站点创建数量不能小于0",
|
||||
"monthCannotLtZero": "站点创建有效期不能小于0",
|
||||
"createSiteTimeLimitDeleteTips": "确认要删除吗?"
|
||||
"createSiteTimeLimitDeleteTips": "确认要删除吗?",
|
||||
"siteEmpty": "站点不存在"
|
||||
}
|
||||
|
||||
@ -61,6 +61,8 @@
|
||||
"formCheckbox":"复选框",
|
||||
"formDateTime":"日期",
|
||||
"formImageSelect":"图片上传",
|
||||
"formFileSelect":"文件上传",
|
||||
"formVideoSelect":"视频上传",
|
||||
"formEditor":"富文本",
|
||||
"formNumber":"数字框",
|
||||
"pk":"主键",
|
||||
@ -140,4 +142,4 @@
|
||||
"selectType":"下拉类型"
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,5 +29,7 @@
|
||||
"addCron": "添加任务",
|
||||
"cronTimeTips": "任务周期时间不能为空",
|
||||
"cronTipsOne": "启动计划任务方式:",
|
||||
"cronTipsTwo": "1、使用命令启动:php think cron:schedule 如果更改了任务周期、状态、删除任务等操作后,需要重新启动下 php think cron:schedule 确保生效"
|
||||
}
|
||||
"cronTipsTwo": "1、使用命令启动:php think workerman 如果更改了任务周期、状态、删除任务等操作后,需要重新启动下 php think workerman 确保生效",
|
||||
"doOne": "执行一次",
|
||||
"cronLog": "执行日志"
|
||||
}
|
||||
|
||||
17
admin/src/app/lang/zh-cn/tools.schedule_log.json
Normal file
17
admin/src/app/lang/zh-cn/tools.schedule_log.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"id": "日志编号",
|
||||
"name": "任务名称",
|
||||
"key": "key",
|
||||
"class": "调用目标字符串",
|
||||
"executeResult": "日志信息",
|
||||
"status": "执行状态",
|
||||
"executeTime": "执行时间",
|
||||
"info": "详情",
|
||||
"cronInfo": "日志详情",
|
||||
"batchDelete": "批量删除",
|
||||
"clearAll": "清空",
|
||||
"batchEmptySelectedCronLogTips": "请选择要删除的日志",
|
||||
"batchDeleteTips": "确定要删除选中的日志吗?",
|
||||
"clearAllTips": "确定要清空所有日志吗?",
|
||||
"deleteTips": "确定要删除该条日志吗?"
|
||||
}
|
||||
@ -11,21 +11,24 @@
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('title')">
|
||||
<el-input v-model.trim="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="10" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.textLink"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('subTitle')">
|
||||
<el-input v-model.trim="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.subTitle.link"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('title')" v-if="diyStore.editComponent && diyStore.editComponent.titleStyle && diyStore.editComponent.titleStyle.value != 'style-5'">
|
||||
<el-input v-model.trim="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="10" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('image')" v-else>
|
||||
<upload-image v-model="diyStore.editComponent.textImg" :limit="1"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.textLink"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('subTitle')">
|
||||
<el-input v-model.trim="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.subTitle.link"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-dialog v-model="showTitleDialog" :title="t('selectStyle')" width="500px">
|
||||
<el-dialog v-model="showTitleDialog" :title="t('selectStyle')" width="460px">
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="(item,index) in titleStyleList" :key="index">
|
||||
@ -87,15 +90,15 @@
|
||||
<el-input v-model.trim="item.title.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('activeCubeSubTitleTextColor')" v-show="selectBlockStyle.value == 'style-3'">
|
||||
<el-form-item :label="t('activeCubeSubTitleTextColor')" v-show="diyStore.editComponent.blockStyle.value == 'style-3'">
|
||||
<el-color-picker v-model="item.title.textColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('activeCubeSubTitle')" v-if="selectBlockStyle.value != 'style-3'">
|
||||
<el-input v-model.trim="item.subTitle.text" :placeholder="t('activeCubeSubTitlePlaceholder')" clearable :maxlength="(selectBlockStyle.value != 'style-4' ? '6' : '4')" show-word-limit/>
|
||||
<el-form-item :label="t('activeCubeSubTitle')" v-if="diyStore.editComponent.blockStyle.value != 'style-3'">
|
||||
<el-input v-model.trim="item.subTitle.text" :placeholder="t('activeCubeSubTitlePlaceholder')" clearable maxlength="6" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<div v-show="selectBlockStyle.value == 'style-4'">
|
||||
<div v-show="diyStore.editComponent.blockStyle.value == 'style-4'">
|
||||
<el-form-item :label="t('activeCubeSubTitleTextColor')">
|
||||
<el-color-picker v-model="item.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
@ -104,14 +107,15 @@
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('activeListFrameColor')">
|
||||
<el-color-picker v-model="item.listFrame.startColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.listFrame.endColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<div v-show="selectBlockStyle.value != 'style-4' && selectBlockStyle.value != 'style-3'">
|
||||
<el-form-item :label="t('activeListFrameColor')">
|
||||
<el-color-picker v-model="item.listFrame.startColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.listFrame.endColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
|
||||
<div v-show="diyStore.editComponent.blockStyle.value != 'style-4' && diyStore.editComponent.blockStyle.value != 'style-3'">
|
||||
<el-form-item :label="t('activeCubeButton')">
|
||||
<el-input v-model.trim="item.moreTitle.text" :placeholder="t('activeCubeButtonPlaceholder')" clearable maxlength="3" show-word-limit/>
|
||||
</el-form-item>
|
||||
@ -143,7 +147,7 @@
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<div class="edit-attr-item-wrap" v-if="selectTitleStyle.value != 'style-5'">
|
||||
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('textColor')">
|
||||
@ -175,6 +179,18 @@
|
||||
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('activeCubeBlockBtnText')" class="flex">
|
||||
<el-radio-group v-model="diyStore.editComponent.blockStyle.btnText">
|
||||
<el-radio :label="'normal'">{{t('btnTextNormal')}}</el-radio>
|
||||
<el-radio :label="'italics'">{{t('btnTextItalics')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -242,6 +258,8 @@ diyStore.editComponent.list.forEach((item: any) => {
|
||||
const showTitleDialog = ref(false)
|
||||
|
||||
const showTitleStyle = () => {
|
||||
selectTitleStyle.title = diyStore.editComponent.titleStyle.title;
|
||||
selectTitleStyle.value = diyStore.editComponent.titleStyle.value;
|
||||
showTitleDialog.value = true
|
||||
}
|
||||
|
||||
@ -262,6 +280,10 @@ const titleStyleList = reactive([
|
||||
url : 'static/resource/images/diy/active_cube/title_style5.png',
|
||||
title:'风格4',
|
||||
value:'style-4'
|
||||
},{
|
||||
url : 'static/resource/images/diy/active_cube/title_style6.png',
|
||||
title:'风格5',
|
||||
value:'style-5'
|
||||
}
|
||||
])
|
||||
|
||||
@ -278,9 +300,39 @@ const changeTitleStyle = (item:any) => {
|
||||
const confirmTitleStyle = () => {
|
||||
diyStore.editComponent.titleStyle.title = selectTitleStyle.title;
|
||||
diyStore.editComponent.titleStyle.value = selectTitleStyle.value;
|
||||
initTitleStyle(diyStore.editComponent.titleStyle.value);
|
||||
showTitleDialog.value = false
|
||||
}
|
||||
|
||||
const initTitleStyle = (style)=>{
|
||||
if(diyStore.editComponent.titleStyle.value == 'style-1'){
|
||||
diyStore.editComponent.titleColor = "#F91700";
|
||||
diyStore.editComponent.subTitle.textColor = "#FFFFFF";
|
||||
diyStore.editComponent.subTitle.startColor = "#FB792F";
|
||||
diyStore.editComponent.subTitle.endColor = "#F91700";
|
||||
}else if(diyStore.editComponent.titleStyle.value == 'style-2'){
|
||||
diyStore.editComponent.titleColor = "#F91700";
|
||||
diyStore.editComponent.subTitle.textColor = "#FFFFFF";
|
||||
diyStore.editComponent.subTitle.startColor = "#FB792F";
|
||||
diyStore.editComponent.subTitle.endColor = "#F91700";
|
||||
}else if(diyStore.editComponent.titleStyle.value == 'style-3'){
|
||||
diyStore.editComponent.titleColor = "#F91700";
|
||||
diyStore.editComponent.subTitle.textColor = "#FFFFFF";
|
||||
diyStore.editComponent.subTitle.startColor = "#FB792F";
|
||||
diyStore.editComponent.subTitle.endColor = "#F91700";
|
||||
}else if(diyStore.editComponent.titleStyle.value == 'style-4'){
|
||||
diyStore.editComponent.titleColor = "#FFFFFF";
|
||||
diyStore.editComponent.subTitle.textColor = "#333333";
|
||||
diyStore.editComponent.subTitle.startColor = "#FFFFFF";
|
||||
diyStore.editComponent.subTitle.endColor = "#FFFFFF";
|
||||
}else if(diyStore.editComponent.titleStyle.value == 'style-5'){
|
||||
diyStore.editComponent.titleColor = "";
|
||||
diyStore.editComponent.subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.subTitle.startColor = "#FFFFFF";
|
||||
diyStore.editComponent.subTitle.endColor = "#FFFFFF";
|
||||
}
|
||||
}
|
||||
|
||||
// 板块风格样式
|
||||
const showListDialog = ref(false)
|
||||
|
||||
@ -324,9 +376,174 @@ const changeBlockStyle = (item:any) => {
|
||||
const confirmBlockStyle = () => {
|
||||
diyStore.editComponent.blockStyle.title = selectBlockStyle.title;
|
||||
diyStore.editComponent.blockStyle.value = selectBlockStyle.value;
|
||||
initBlockStyle(diyStore.editComponent.blockStyle.value);
|
||||
showListDialog.value = false
|
||||
}
|
||||
|
||||
const initBlockStyle = (style: any)=>{
|
||||
if(style == 'style-1'){
|
||||
diyStore.editComponent.blockStyle.fontWeight = "normal";
|
||||
diyStore.editComponent.blockStyle.btnText = "normal";
|
||||
|
||||
diyStore.editComponent.list[0].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[0].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[0].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[0].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[0].moreTitle.startColor = "#FEA715";
|
||||
diyStore.editComponent.list[0].moreTitle.endColor = "#FE1E00";
|
||||
diyStore.editComponent.list[0].listFrame.startColor = "#FFFAF5";
|
||||
diyStore.editComponent.list[0].listFrame.endColor = "#FFFFFF";
|
||||
|
||||
diyStore.editComponent.list[1].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[1].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[1].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[1].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[1].moreTitle.startColor = "#FFBF50";
|
||||
diyStore.editComponent.list[1].moreTitle.endColor = "#FF9E03";
|
||||
diyStore.editComponent.list[1].listFrame.startColor = "#FFFAF5";
|
||||
diyStore.editComponent.list[1].listFrame.endColor = "#FFFFFF";
|
||||
|
||||
diyStore.editComponent.list[2].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[2].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[2].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[2].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[2].moreTitle.startColor = "#A2E792";
|
||||
diyStore.editComponent.list[2].moreTitle.endColor = "#49CD2D";
|
||||
diyStore.editComponent.list[2].listFrame.startColor = "#FFFAF5";
|
||||
diyStore.editComponent.list[2].listFrame.endColor = "#FFFFFF";
|
||||
|
||||
diyStore.editComponent.list[3].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[3].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[3].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[3].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[3].moreTitle.startColor = "#4AC1FF";
|
||||
diyStore.editComponent.list[3].moreTitle.endColor = "#1D7CFF";
|
||||
diyStore.editComponent.list[3].listFrame.startColor = "#FFFAF5";
|
||||
diyStore.editComponent.list[3].listFrame.endColor = "#FFFFFF";
|
||||
|
||||
}else if(style == 'style-2'){
|
||||
diyStore.editComponent.blockStyle.fontWeight = "normal";
|
||||
diyStore.editComponent.blockStyle.btnText = "normal";
|
||||
|
||||
diyStore.editComponent.blockStyle.fontWeight = "bold";
|
||||
diyStore.editComponent.blockStyle.btnText = "italics";
|
||||
|
||||
diyStore.editComponent.list[0].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[0].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[0].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[0].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[0].moreTitle.startColor = "#FFC051";
|
||||
diyStore.editComponent.list[0].moreTitle.endColor = "#FF9C00";
|
||||
diyStore.editComponent.list[0].listFrame.startColor = "#FFF1DB";
|
||||
diyStore.editComponent.list[0].listFrame.endColor = "#FFFBF4";
|
||||
|
||||
diyStore.editComponent.list[1].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[1].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[1].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[1].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[1].moreTitle.startColor = "#A4E894";
|
||||
diyStore.editComponent.list[1].moreTitle.endColor = "#45CC2A";
|
||||
diyStore.editComponent.list[1].listFrame.startColor = "#E6F6E2";
|
||||
diyStore.editComponent.list[1].listFrame.endColor = "#F5FDF3";
|
||||
|
||||
diyStore.editComponent.list[2].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[2].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[2].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[2].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[2].moreTitle.startColor = "#4BC2FF";
|
||||
diyStore.editComponent.list[2].moreTitle.endColor = "#1F7DFF";
|
||||
diyStore.editComponent.list[2].listFrame.startColor = "#E2F6FF";
|
||||
diyStore.editComponent.list[2].listFrame.endColor = "#F2FAFF";
|
||||
|
||||
diyStore.editComponent.list[3].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[3].subTitle.textColor = "#999999";
|
||||
diyStore.editComponent.list[3].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[3].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[3].moreTitle.startColor = "#FB792F";
|
||||
diyStore.editComponent.list[3].moreTitle.endColor = "#F91700";
|
||||
diyStore.editComponent.list[3].listFrame.startColor = "#FFEAEA";
|
||||
diyStore.editComponent.list[3].listFrame.endColor = "#FFFCFB";
|
||||
}else if(style == 'style-3'){
|
||||
diyStore.editComponent.blockStyle.fontWeight = "normal";
|
||||
diyStore.editComponent.blockStyle.btnText = "normal";
|
||||
|
||||
diyStore.editComponent.list[0].title.textColor = "#FF1128";
|
||||
diyStore.editComponent.list[0].subTitle.textColor = "";
|
||||
diyStore.editComponent.list[0].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[0].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[0].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[0].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[0].listFrame.startColor = "";
|
||||
diyStore.editComponent.list[0].listFrame.endColor = "";
|
||||
|
||||
diyStore.editComponent.list[1].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[1].subTitle.textColor = "";
|
||||
diyStore.editComponent.list[1].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[1].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[1].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[1].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[1].listFrame.startColor = "";
|
||||
diyStore.editComponent.list[1].listFrame.endColor = "";
|
||||
|
||||
diyStore.editComponent.list[2].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[2].subTitle.textColor = "";
|
||||
diyStore.editComponent.list[2].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[2].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[2].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[2].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[2].listFrame.startColor = "";
|
||||
diyStore.editComponent.list[2].listFrame.endColor = "";
|
||||
|
||||
diyStore.editComponent.list[3].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[3].subTitle.textColor = "";
|
||||
diyStore.editComponent.list[3].subTitle.startColor = "";
|
||||
diyStore.editComponent.list[3].subTitle.endColor = "";
|
||||
diyStore.editComponent.list[3].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[3].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[3].listFrame.startColor = "";
|
||||
diyStore.editComponent.list[3].listFrame.endColor = "";
|
||||
}else if(style == 'style-4'){
|
||||
diyStore.editComponent.blockStyle.fontWeight = "bold";
|
||||
diyStore.editComponent.blockStyle.btnText = "normal";
|
||||
|
||||
diyStore.editComponent.list[0].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[0].subTitle.textColor = "#ED6E00";
|
||||
diyStore.editComponent.list[0].subTitle.startColor = "#FFE4D9";
|
||||
diyStore.editComponent.list[0].subTitle.endColor = "#FFE4D9";
|
||||
diyStore.editComponent.list[0].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[0].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[0].listFrame.startColor = "#FFAD4D";
|
||||
diyStore.editComponent.list[0].listFrame.endColor = "#F93D02";
|
||||
|
||||
diyStore.editComponent.list[1].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[1].subTitle.textColor = "#2E59E9";
|
||||
diyStore.editComponent.list[1].subTitle.startColor = "#CAD7F8";
|
||||
diyStore.editComponent.list[1].subTitle.endColor = "#CAD7F8";
|
||||
diyStore.editComponent.list[1].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[1].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[1].listFrame.startColor = "#7CA7F4";
|
||||
diyStore.editComponent.list[1].listFrame.endColor = "#2B56E9";
|
||||
|
||||
diyStore.editComponent.list[2].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[2].subTitle.textColor = "#F62F55";
|
||||
diyStore.editComponent.list[2].subTitle.startColor = "#FCD6D9";
|
||||
diyStore.editComponent.list[2].subTitle.endColor = "#FCD6D9";
|
||||
diyStore.editComponent.list[2].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[2].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[2].listFrame.startColor = "#FF7F48";
|
||||
diyStore.editComponent.list[2].listFrame.endColor = "#EE335B";
|
||||
|
||||
diyStore.editComponent.list[3].title.textColor = "#303133";
|
||||
diyStore.editComponent.list[3].subTitle.textColor = "#139B3C";
|
||||
diyStore.editComponent.list[3].subTitle.startColor = "#D3F1DA";
|
||||
diyStore.editComponent.list[3].subTitle.endColor = "#D3F1DA";
|
||||
diyStore.editComponent.list[3].moreTitle.startColor = "";
|
||||
diyStore.editComponent.list[3].moreTitle.endColor = "";
|
||||
diyStore.editComponent.list[3].listFrame.startColor = "#90D48C";
|
||||
diyStore.editComponent.list[3].listFrame.endColor = "#299F4F";
|
||||
}
|
||||
}
|
||||
|
||||
const addItem = () => {
|
||||
diyStore.editComponent.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
|
||||
@ -26,9 +26,18 @@
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchLogoTips') }}</div>
|
||||
<el-form-item :label="t('selectStyle')" class="flex">
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showSearchStyle">{{ diyStore.editComponent.search.styleName }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchSubTitle')" v-if="diyStore.editComponent.search.style == 'style-2'">
|
||||
<el-input v-model.trim="diyStore.editComponent.search.subTitle.text" :placeholder="t('carouselSearchSubTitlePlaceholder')" clearable maxlength="10" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('logo')">
|
||||
<upload-image v-model="diyStore.editComponent.search.logo" :limit="1" />
|
||||
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchLogoTips') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchText')">
|
||||
<div>
|
||||
@ -39,16 +48,34 @@
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.search.link"/>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<el-dialog v-model="showSearchDialog" :title="t('selectStyle')" width="500px">
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="(item,index) in searchStyleList" :key="index">
|
||||
<div :class="{ 'border-primary': selectSearchStyle.value == item.value }" @click="changeSearchStyle(item)" class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] m-[6px] cursor-pointer border bg-[#eee]">
|
||||
<img :src="img(item.url)" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showSearchDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmSearchStyle">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap mb-[20px]">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchHotWordSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
|
||||
<el-form-item :label="t('carouselSearchHotWordInterval')">
|
||||
<el-slider v-model="diyStore.editComponent.search.hotWord.interval" show-input size="small" class="ml-[10px] horz-blank-slider" :min="1" :max="10"/>
|
||||
<el-slider v-model="diyStore.editComponent.search.hotWord.interval" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
|
||||
</el-form-item>
|
||||
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
|
||||
@ -70,109 +97,148 @@
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
|
||||
<el-collapse v-model="activeNames" @change="handleChange" class="collapse-wrap">
|
||||
<el-collapse-item :title="t('carouselSearchTabSet')" name="tab">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchTabControl')">
|
||||
<el-switch v-model="diyStore.editComponent.tab.control" />
|
||||
</el-form-item>
|
||||
<el-collapse-item :title="t('carouselSearchTabSet')" name="tab">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchTabControl')">
|
||||
<el-switch v-model="diyStore.editComponent.tab.control" />
|
||||
</el-form-item>
|
||||
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
|
||||
|
||||
<div ref="tabBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.tab.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div ref="tabBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.tab.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
|
||||
<el-form-item :label="t('carouselSearchTabCategoryText')">
|
||||
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchTabCategoryTextPlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchTabCategoryText')">
|
||||
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchTabCategoryTextPlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('dataSources')">
|
||||
<el-input v-model="item.diy_title" :placeholder="t('selectDiyPagePlaceholder')" readonly class="select-diy-page-input" @click="diyPageShowDialogOpen(index)">
|
||||
<template #suffix>
|
||||
<div @click.stop="tabClear(index)">
|
||||
<el-icon v-if="item.diy_title">
|
||||
<Close />
|
||||
</el-icon>
|
||||
<el-icon v-else>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('dataSources')">
|
||||
<el-input v-model.trim="item.diy_title" :placeholder="t('selectDiyPagePlaceholder')" readonly class="select-diy-page-input" @click="diyPageShowDialogOpen(index)">
|
||||
<template #suffix>
|
||||
<div @click.stop="tabClear(index)">
|
||||
<el-icon v-if="item.diy_title">
|
||||
<Close />
|
||||
</el-icon>
|
||||
<el-icon v-else>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.tab.list.length > 1" @click="diyStore.editComponent.tab.list.splice(index,1)">
|
||||
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.tab.list.length > 1" @click="diyStore.editComponent.tab.list.splice(index,1)">
|
||||
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<el-button v-show="diyStore.editComponent.tab.list.length < 50" class="w-full" @click="addTabItem">{{ t('carouselSearchAddTabItem') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-button v-show="diyStore.editComponent.tab.list.length < 50" class="w-full" @click="addTabItem">{{ t('carouselSearchAddTabItem') }}</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 选择微页面弹出框 -->
|
||||
<el-dialog v-model="diyPageShowDialog" :title="t('selectSourcesDiyPage')" width="1000px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-table :data="diyPageTable.data" ref="diyPageTableRef" size="large" v-loading="diyPageTable.loading" height="490px" @current-change="handleCurrentDiyPageChange" row-key="id" highlight-current-row>
|
||||
<template #empty>
|
||||
<span>{{ !diyPageTable.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column prop="page_title" :label="t('diyPageTitle')" min-width="120" />
|
||||
<el-table-column prop="addon_name" :label="t('diyPageTypeName')" min-width="80" />
|
||||
<el-table-column prop="type_name" :label="t('diyPageForAddon')" min-width="80" />
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="diyPageTable.page" v-model:page-size="diyPageTable.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="diyPageTable.total"
|
||||
@size-change="loadDiyPageList" @current-change="loadDiyPageList" />
|
||||
</div>
|
||||
<div class="flex items-center justify-end mt-[15px]">
|
||||
<el-button type="primary" @click="saveDiyPageId">{{ t('confirm') }}</el-button>
|
||||
<el-button @click="diyPageShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 选择微页面弹出框 -->
|
||||
<el-dialog v-model="diyPageShowDialog" :title="t('selectSourcesDiyPage')" width="1000px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-table :data="diyPageTable.data" ref="diyPageTableRef" size="large" v-loading="diyPageTable.loading" height="490px" @current-change="handleCurrentDiyPageChange" row-key="id" highlight-current-row>
|
||||
<template #empty>
|
||||
<span>{{ !diyPageTable.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column prop="page_title" :label="t('diyPageTitle')" min-width="120" />
|
||||
<el-table-column prop="addon_name" :label="t('diyPageTypeName')" min-width="80" />
|
||||
<el-table-column prop="type_name" :label="t('diyPageForAddon')" min-width="80" />
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="diyPageTable.page" v-model:page-size="diyPageTable.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="diyPageTable.total"
|
||||
@size-change="loadDiyPageList" @current-change="loadDiyPageList" />
|
||||
</div>
|
||||
<div class="flex items-center justify-end mt-[15px]">
|
||||
<el-button type="primary" @click="saveDiyPageId">{{ t('confirm') }}</el-button>
|
||||
<el-button @click="diyPageShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('carouselSearchSwiperSet')" name="swiper">
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
</el-form>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item :title="t('carouselSearchSwiperSet')" name="swiper">
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchSwiperControl')">
|
||||
<el-switch v-model="diyStore.editComponent.swiper.control" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchSwiperInterval')">
|
||||
<el-slider v-model="diyStore.editComponent.swiper.interval" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('carouselSearchSwiperControl')">
|
||||
<el-switch v-model="diyStore.editComponent.swiper.control" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchSwiperInterval')">
|
||||
<el-slider v-model="diyStore.editComponent.swiper.interval" show-input size="small" class="ml-[10px] horz-blank-slider" :min="1" :max="10"/>
|
||||
</el-form-item>
|
||||
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchSwiperTips') }}</div>
|
||||
|
||||
<div class="text-sm text-gray-400 mb-[10px]">{{ t('carouselSearchSwiperTips') }}</div>
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.swiper.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
|
||||
</el-form-item>
|
||||
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.swiper.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
|
||||
</el-form-item>
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.swiper.list.length > 1" @click="diyStore.editComponent.swiper.list.splice(index,1)">
|
||||
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.swiper.list.length > 1" @click="diyStore.editComponent.swiper.list.splice(index,1)">
|
||||
<icon name="element CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<el-button v-show="diyStore.editComponent.swiper.list.length < 10" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
|
||||
|
||||
<el-button v-show="diyStore.editComponent.swiper.list.length < 10" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
|
||||
|
||||
</el-form>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-form>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
<div class="edit-attr-item-wrap" v-if="diyStore.editComponent.search.style == 'style-2'">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchPositionStyle') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchTextColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.positionColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap" v-if="diyStore.editComponent.search.style == 'style-2'">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchSubTitleStyle') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchTextColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.subTitle.startColor" :predefine="diyStore.predefineColors" show-alpha/>
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.search.subTitle.endColor" :predefine="diyStore.predefineColors" show-alpha/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchStyle') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchTextColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.color" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.bgColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchBtnColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.btnColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchBtnBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.search.btnBgColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchTabStyle') }}</h3>
|
||||
@ -199,13 +265,14 @@
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.swiperStyle">
|
||||
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.swiper.topRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
<el-slider v-model="diyStore.editComponent.swiper.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.swiper.bottomRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
<el-slider v-model="diyStore.editComponent.swiper.bottomRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -217,6 +284,7 @@
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
|
||||
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
|
||||
@ -248,7 +316,7 @@ import useDiyStore from '@/stores/modules/diy'
|
||||
import { ref, reactive, watch, onMounted, nextTick } from 'vue'
|
||||
import { ElTable } from 'element-plus'
|
||||
import Sortable from 'sortablejs'
|
||||
import { range } from 'lodash-es'
|
||||
import { range,cloneDeep } from 'lodash-es'
|
||||
|
||||
import { getDiyPageListByCarouselSearch } from '@/app/api/diy'
|
||||
|
||||
@ -280,17 +348,59 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
// }
|
||||
});
|
||||
|
||||
diyStore.value[index].swiper.list.forEach((item: any) => {
|
||||
if(item.imageUrl == ''){
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
});
|
||||
if(diyStore.value[index].swiper.control){
|
||||
diyStore.value[index].swiper.list.forEach((item: any) => {
|
||||
if(item.imageUrl == ''){
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/************** 搜索框样式选择-start ********************/
|
||||
const selectSearchStyle = reactive({
|
||||
title: diyStore.editComponent.search.styleName,
|
||||
value: diyStore.editComponent.search.style
|
||||
})
|
||||
|
||||
const showSearchDialog = ref(false)
|
||||
|
||||
const showSearchStyle = () => {
|
||||
showSearchDialog.value = true
|
||||
selectSearchStyle.title = diyStore.editComponent.search.styleName;
|
||||
selectSearchStyle.value = diyStore.editComponent.search.style;
|
||||
}
|
||||
|
||||
const changeSearchStyle = (item:any) => {
|
||||
selectSearchStyle.title = item.title;
|
||||
selectSearchStyle.value = item.value;
|
||||
}
|
||||
|
||||
const confirmSearchStyle = () => {
|
||||
diyStore.editComponent.search.styleName = selectSearchStyle.title;
|
||||
diyStore.editComponent.search.style = selectSearchStyle.value;
|
||||
showSearchDialog.value = false
|
||||
}
|
||||
|
||||
const searchStyleList = reactive([
|
||||
{
|
||||
url: 'static/resource/images/diy/carousel_search/style_1.png',
|
||||
title: '风格1',
|
||||
value: 'style-1'
|
||||
},
|
||||
{
|
||||
url: 'static/resource/images/diy/carousel_search/style_2.png',
|
||||
title: '风格2',
|
||||
value: 'style-2'
|
||||
}
|
||||
])
|
||||
|
||||
/************** 搜索框样式选择-end ********************/
|
||||
|
||||
diyStore.editComponent.search.hotWord.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
@ -427,6 +537,8 @@ const loadDiyPageList = (page: number = 1) => {
|
||||
newData.push(data[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newData = cloneDeep(data); // 添加
|
||||
}
|
||||
if (isExistCount) {
|
||||
res.data.total = res.data.total - isExistCount;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<div class="content-wrap float-btn" v-show="diyStore.editTab == 'content'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
|
||||
<!-- <h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('selectStyle')" class="flex">
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showCouponStyle">{{ diyStore.editComponent.styleName }}</span>
|
||||
@ -27,7 +27,7 @@
|
||||
</span>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
</el-dialog> -->
|
||||
<h3 class="mb-[10px]">{{ t('floatBtnBtton') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('floatBtnBtton')">
|
||||
@ -41,7 +41,7 @@
|
||||
</ul>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('floatBtnOffset')">
|
||||
<el-slider v-model="diyStore.editComponent.offset" show-input size="small" class="ml-[10px] horz-blank-slider" :max="100"/>
|
||||
<el-slider v-model="diyStore.editComponent.offset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -49,10 +49,10 @@
|
||||
<h3 class="mb-[10px]">{{ t('floatBtnImageSet') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('floatBtnImageSize')">
|
||||
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] horz-blank-slider" :min="30" :max="100"/>
|
||||
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="30" :max="100"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('floatBtnAroundRadius')">
|
||||
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] graphic-nav-slider" :max="50"/>
|
||||
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
|
||||
</el-form-item>
|
||||
|
||||
<div class="text-[12px] text-[#999] mb-[15px] mt-[5px]">{{t('floatBtnImageSuggest')}}</div>
|
||||
@ -94,7 +94,7 @@ import { img } from '@/utils/common'
|
||||
import { range } from 'lodash-es'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['pageBgColor','marginTop','marginBottom','marginBoth'] // 忽略公共属性
|
||||
diyStore.editComponent.ignore = ['pageBgColor','marginTop','marginBottom','marginBoth','componentBgUrl'] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
@ -121,18 +121,18 @@ const showCouponStyle = () => {
|
||||
selectCouponStyle.title = diyStore.editComponent.styleName;
|
||||
selectCouponStyle.value = diyStore.editComponent.style;
|
||||
}
|
||||
const couponStyleList = reactive([
|
||||
{
|
||||
url: 'addon/shop/diy/goods_coupon/style-1.png',
|
||||
title: '风格1',
|
||||
value: 'style-1'
|
||||
},
|
||||
{
|
||||
url: 'addon/shop/diy/goods_coupon/style-2.png',
|
||||
title: '风格2',
|
||||
value: 'style-2'
|
||||
}
|
||||
])
|
||||
// const couponStyleList = reactive([
|
||||
// {
|
||||
// url: 'addon/shop/diy/goods_coupon/style-1.png',
|
||||
// title: '风格1',
|
||||
// value: 'style-1'
|
||||
// },
|
||||
// {
|
||||
// url: 'addon/shop/diy/goods_coupon/style-2.png',
|
||||
// title: '风格2',
|
||||
// value: 'style-2'
|
||||
// }
|
||||
// ])
|
||||
//风格点击
|
||||
const changeCouponStyle = (item:any) => {
|
||||
selectCouponStyle.title = item.title;
|
||||
@ -174,7 +174,7 @@ const templateList = ref([
|
||||
}
|
||||
])
|
||||
|
||||
let selectTemplate = ref({})
|
||||
const selectTemplate = ref({})
|
||||
templateList.value.forEach((item) => {
|
||||
if (item.className == diyStore.editComponent.bottomPosition) {
|
||||
selectTemplate.value = item
|
||||
@ -222,5 +222,5 @@ defineExpose({})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
||||
</style>
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
<el-form-item :label="t('graphicNavShowStyle')">
|
||||
<el-radio-group v-model="diyStore.editComponent.showStyle" @change="changeShowStyle">
|
||||
<el-radio :label="'fixed'">{{t('graphicNavStyleFixed')}}</el-radio>
|
||||
<el-radio :label="'singleSlide'">{{t('graphicNavStyleSingleSlide')}}</el-radio>
|
||||
<el-radio :label="'singleSlide'">{{diyStore.editComponent.pageCount == 2 ? t('graphicNavStyleMultiLine') : t('graphicNavStyleSingleSlide')}}</el-radio>
|
||||
<el-radio :label="'pageSlide'">{{t('graphicNavStylePageSlide')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
@ -45,7 +45,6 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</view>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="edit-attr-item-wrap">
|
||||
@ -74,7 +73,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addGraphicNav">{{ t('addGraphicNav') }}</el-button>
|
||||
<el-button v-show="diyStore.editComponent.list.length < 50" class="w-full" @click="addGraphicNav">{{ t('addGraphicNav') }}</el-button>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
@ -86,10 +85,10 @@
|
||||
<h3 class="mb-[10px]">{{ t('graphicNavImageSet') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('graphicNavImageSize')">
|
||||
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] graphic-nav-slider" :min="20" :max="60"/>
|
||||
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="20" :max="60"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('graphicNavAroundRadius')">
|
||||
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] graphic-nav-slider" :max="50"/>
|
||||
<el-slider v-model="diyStore.editComponent.aroundRadius" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -97,7 +96,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('textSet') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.font.size" show-input size="small" class="ml-[10px] graphic-nav-slider" :min="12" :max="16"/>
|
||||
<el-slider v-model="diyStore.editComponent.font.size" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.font.weight">
|
||||
@ -111,6 +110,31 @@
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="edit-attr-item-wrap" v-show="diyStore.editComponent.showStyle == 'pageSlide' && diyStore.editComponent.layout == 'horizontal'">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperIndicatorSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchSwiperIndicatorStyle')">
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
|
||||
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('carouselSearchSwiperIndicatorStyle3') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorAlign">
|
||||
<el-radio label="left">{{ t('alignLeft') }}</el-radio>
|
||||
<el-radio label="center">{{ t('alignCenter') }}</el-radio>
|
||||
<el-radio label="right">{{ t('alignRight') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('noColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('selectColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorActiveColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
@ -130,7 +154,6 @@ import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
@ -215,19 +238,12 @@ const changePageCount = (value:any)=>{
|
||||
}else if(value == '2'){
|
||||
diyStore.editComponent.showStyle = 'fixed';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.graphic-nav-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.edit-graphic-nav {
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('blankHeightSet') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('blankHeight')">
|
||||
<el-slider v-model="diyStore.editComponent.height" show-input size="small" max="200" class="ml-[10px] horz-blank-slider"/>
|
||||
<el-slider v-model="diyStore.editComponent.height" show-input size="small" max="200" class="ml-[10px] diy-nav-slider"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -31,11 +31,4 @@ defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.horz-blank-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<el-color-picker v-model="diyStore.editComponent.borderColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('horzLineBorderWidth')">
|
||||
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small" class="ml-[10px] horz-blank-slider" :min="1" :max="10"/>
|
||||
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -40,11 +40,4 @@ defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.horz-blank-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -38,7 +38,7 @@ import useDiyStore from '@/stores/modules/diy'
|
||||
import { img } from '@/utils/common'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
|
||||
@ -4,6 +4,11 @@
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('imageSet') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
|
||||
<el-form-item :label="t('sameScreen')" v-if="diyStore.currentIndex == 0">
|
||||
<el-switch v-model="diyStore.editComponent.isSameScreen" />
|
||||
<div class="text-sm text-gray-400 leading-[1.4]">{{ t('imageAdsSameScreenTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('imageHeight')" class="display-block">
|
||||
<el-input v-model.trim="diyStore.editComponent.imageHeight" :placeholder="t('imageHeightPlaceholder')" clearable maxlength="10" @blur="blurImageHeight">
|
||||
@ -52,7 +57,7 @@ import { range } from 'lodash-es'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
@ -124,7 +129,7 @@ const handleHeight = (isCalcHeight:boolean = false)=> {
|
||||
}
|
||||
|
||||
const blurImageHeight = () => {
|
||||
diyStore.editComponent.imageHeight = parseInt(diyStore.editComponent.imageHeight)
|
||||
diyStore.editComponent.imageHeight = diyStore.editComponent.imageHeight ? parseInt(diyStore.editComponent.imageHeight) : 0
|
||||
}
|
||||
|
||||
const imageBoxRef = ref()
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
@ -12,11 +13,11 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="500px">
|
||||
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="660px">
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="(item,index) in styleList" :key="index">
|
||||
<div :class="{ 'border-primary': selectStyle.value == item.value }" @click="changeStyle(item)" class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50">
|
||||
<div :class="{ 'border-primary': selectStyle.value == item.value, '!mr-[0]': [(index+1)%3] == 0 }" @click="changeStyle(item)" class="flex my-[5px] items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50">
|
||||
<img :src="img(item.url)" />
|
||||
</div>
|
||||
</template>
|
||||
@ -80,6 +81,16 @@ const styleList = reactive([
|
||||
url: 'static/resource/images/diy/member/member_level_style3.jpg',
|
||||
title: '风格3',
|
||||
value: 'style-3'
|
||||
},
|
||||
{
|
||||
url: 'static/resource/images/diy/member/member_level_style4.png',
|
||||
title: '风格4',
|
||||
value: 'style-4'
|
||||
},
|
||||
{
|
||||
url: 'static/resource/images/diy/member/member_level_style5.png',
|
||||
title: '风格5',
|
||||
value: 'style-5'
|
||||
}
|
||||
])
|
||||
|
||||
@ -91,9 +102,31 @@ const changeStyle = (item:any) => {
|
||||
const confirmStyle = () => {
|
||||
diyStore.editComponent.styleName = selectStyle.title;
|
||||
diyStore.editComponent.style = selectStyle.value;
|
||||
initStyle(diyStore.editComponent.style);
|
||||
showDialog.value = false
|
||||
}
|
||||
|
||||
|
||||
const initStyle = (style: any) => {
|
||||
if (style == 'style-1') {
|
||||
diyStore.editComponent.bottomRounded = 0;
|
||||
diyStore.editComponent.topRounded = 12;
|
||||
} else if (style == 'style-2') {
|
||||
diyStore.editComponent.bottomRounded = 0;
|
||||
diyStore.editComponent.topRounded = 12;
|
||||
} else if (style == 'style-3') {
|
||||
diyStore.editComponent.bottomRounded = 12;
|
||||
diyStore.editComponent.topRounded = 12;
|
||||
} else if (style == 'style-4') {
|
||||
diyStore.editComponent.bottomRounded = 12;
|
||||
diyStore.editComponent.topRounded = 12;
|
||||
} else if (style == 'style-5') {
|
||||
diyStore.editComponent.bottomRounded = 12;
|
||||
diyStore.editComponent.topRounded = 12;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
@ -11,14 +11,14 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<div class="flex items-center flex-wrap py-[8px] px-[10px] bg-[#f4f3f7] rounded mb-[18px] mx-[18px]" v-show="diyStore.editComponent.noticeType == 'img'">
|
||||
<div :class="['mr-[10px] rounded cursor-pointer', {'border-[1px] border-solid border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_1' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<div :class="['mr-[10px] rounded cursor-pointer border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_1' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<img src="@/app/assets/images/diy/notice/style_1.png" :class="['h-[28px] px-[10px] py-[5px]']" @click="changeStyle('style_1')"/>
|
||||
</div>
|
||||
|
||||
<div :class="['mr-[10px] rounded cursor-pointer w-[100px]', {'border-[1px] border-solid border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_2' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<div :class="['mr-[10px] rounded cursor-pointer w-[100px] border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_2' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<img src="@/app/assets/images/diy/notice/style_2.png" class="px-[10px] py-[5px]" @click="changeStyle('style_2')"/>
|
||||
</div>
|
||||
<div @click.stop="diyStore.editComponent.imgType = 'diy'" :class="['mr-[10px] rounded cursor-pointer diy-upload-img', {'border-[1px] border-solid border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
|
||||
<div @click.stop="diyStore.editComponent.imgType = 'diy'" :class="['mr-[10px] rounded cursor-pointer diy-upload-img border-[1px] border-solid', {'border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
|
||||
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1"/>
|
||||
</div>
|
||||
</div>
|
||||
@ -80,7 +80,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('textSet') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="20"/>
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="20"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.fontWeight">
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bgHeightScale')">
|
||||
<el-slider v-model="diyStore.global.bgHeightScale" show-input size="small" class="ml-[10px] horz-blank-slider"/>
|
||||
<el-slider v-model="diyStore.global.bgHeightScale" show-input size="small" class="ml-[10px] diy-nav-slider"/>
|
||||
</el-form-item>
|
||||
<div class="text-sm text-gray-400 ml-[80px] mb-[10px]">{{ t('bgHeightScaleTip') }}</div>
|
||||
<el-form-item :label="t('bgUrl')">
|
||||
@ -133,7 +133,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('marginSet') }}</h3>
|
||||
<el-form label-width="115px" class="px-[10px]">
|
||||
<el-form-item :label="t('marginBoth')">
|
||||
<el-slider v-model="diyStore.global.template.margin.both" show-input size="small" @input="inputBoth" class="ml-[10px] horz-blank-slider"/>
|
||||
<el-slider v-model="diyStore.global.template.margin.both" show-input size="small" @input="inputBoth" class="ml-[10px] diy-nav-slider"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
156
admin/src/app/views/diy/components/edit-picture-show.vue
Normal file
156
admin/src/app/views/diy/components/edit-picture-show.vue
Normal file
@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('pictureShowBlockOne') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="diyStore.editComponent.moduleOne.head.textImg" :limit="1"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subTitle')">
|
||||
<el-input v-model.trim="diyStore.editComponent.moduleOne.head.subText" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subTitleTextColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleOne.head.subTextColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleOne.listFrame.startColor" show-alpha />
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleOne.listFrame.endColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<div v-for="(item,index) in diyStore.editComponent.moduleOne.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBtnText')">
|
||||
<el-input v-model.trim="item.btnTitle.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBtnColor')">
|
||||
<el-color-picker v-model="item.btnTitle.color" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBtnBgColor')">
|
||||
<el-color-picker v-model="item.btnTitle.startColor" show-alpha />
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.btnTitle.endColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('pictureShowBlockTwo') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="diyStore.editComponent.moduleTwo.head.textImg" :limit="1"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('subTitle')">
|
||||
<el-input v-model.trim="diyStore.editComponent.moduleTwo.head.subText" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subTitleTextColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleTwo.head.subTextColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleTwo.listFrame.startColor" show-alpha />
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleTwo.listFrame.endColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<div v-for="(item,index) in diyStore.editComponent.moduleTwo.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBtnText')">
|
||||
<el-input v-model.trim="item.btnTitle.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBtnColor')">
|
||||
<el-color-picker v-model="item.btnTitle.color" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('pictureShowBtnBgColor')">
|
||||
<el-color-picker v-model="item.btnTitle.startColor" show-alpha />
|
||||
<icon name="iconfont iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.btnTitle.endColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('pictureShowBlockStyle') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('topRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.moduleRounded.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.moduleRounded.bottomRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { img } from '@/utils/common'
|
||||
import { ref, reactive } from 'vue'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
diyStore.value[index].moduleOne.list.forEach((item: any) => {
|
||||
if (item.imageUrl === '') {
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
})
|
||||
|
||||
diyStore.value[index].moduleTwo.list.forEach((item: any) => {
|
||||
if (item.imageUrl === '') {
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@ -54,13 +54,13 @@
|
||||
<h3 class="mb-[10px]">{{ t('rubikCubeStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('imageGap')">
|
||||
<el-slider v-model="diyStore.editComponent.imageGap" show-input size="small" class="ml-[10px] horz-blank-slider" :max="30"/>
|
||||
<el-slider v-model="diyStore.editComponent.imageGap" show-input size="small" class="ml-[10px] diy-nav-slider" :max="30"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50"/>
|
||||
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50"/>
|
||||
<el-slider v-model="diyStore.editComponent.bottomElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
<el-input v-model.trim="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="16" />
|
||||
<el-slider v-model="diyStore.editComponent.subTitle.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="16" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.subTitle.color" />
|
||||
@ -91,7 +91,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="30" />
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="30" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.fontWeight">
|
||||
|
||||
@ -54,12 +54,12 @@
|
||||
<el-button class="page-btn absolute right-[20px]" @click="diyStore.changeCurrentIndex(-99)">{{ t('pageSet') }}</el-button>
|
||||
<div class="diy-view-wrap w-[375px] shadow-lg mx-auto">
|
||||
<div class="preview-head bg-no-repeat bg-center bg-cover cursor-pointer h-[64px]" :class="[diyStore.global.topStatusBar.style]" :style="{backgroundColor :diyStore.global.topStatusBar.bgColor}" @click="diyStore.changeCurrentIndex(-99)">
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-1'" class="content-wrap">
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-1' && diyStore.global.topStatusBar.isShow" class="content-wrap">
|
||||
<div class="title-wrap" :style="{ fontSize: '14px', color: diyStore.global.topStatusBar.textColor, textAlign: diyStore.global.topStatusBar.textAlign }">
|
||||
{{ diyStore.global.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-2'" class="content-wrap">
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-2' && diyStore.global.topStatusBar.isShow" class="content-wrap">
|
||||
<div class="title-wrap" :style="{ color: diyStore.global.topStatusBar.textColor }">
|
||||
<div class="h-[28px] max-w-[150px] mr-[8px]" v-if="diyStore.global.topStatusBar.imgUrl">
|
||||
<img class="max-w-[100%] max-h-[100%]" :src="img(diyStore.global.topStatusBar.imgUrl)" mode="heightFix" />
|
||||
@ -67,16 +67,16 @@
|
||||
<div :style="{ color: diyStore.global.topStatusBar.textColor }">{{ diyStore.global.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-3'" class="content-wrap">
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-3' && diyStore.global.topStatusBar.isShow" class="content-wrap">
|
||||
<div class="title-wrap" v-if="diyStore.global.topStatusBar.imgUrl">
|
||||
<img class="max-w-[100%] max-h-[100%]" :src="img(diyStore.global.topStatusBar.imgUrl)" />
|
||||
</div>
|
||||
<div class="search">
|
||||
<span class="iconfont iconsousuo absolute left-[10px]"></span>
|
||||
<span class="text-[14px]">{{diyStore.global.topStatusBar.inputPlaceholder}}</span>
|
||||
<span class="nc-iconfont nc-icon-sousuo-duanV6xx1 !text-[12px] absolute left-[10px]"></span>
|
||||
<span class="text-[12px]">{{diyStore.global.topStatusBar.inputPlaceholder}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-4'" class="content-wrap">
|
||||
<div v-if="diyStore.global.topStatusBar.style == 'style-4' && diyStore.global.topStatusBar.isShow" class="content-wrap">
|
||||
<span class="iconfont iconxiazai19 !text-[14px]" :style="{ color: diyStore.global.topStatusBar.textColor }"></span>
|
||||
<div class="title-wrap" :style="{ color: diyStore.global.topStatusBar.textColor }">我的位置</div>
|
||||
<span class="iconfont iconxiangyoujiantou !text-[12px]" :style="{ color: diyStore.global.topStatusBar.textColor }"></span>
|
||||
@ -109,7 +109,7 @@
|
||||
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
|
||||
<div class="mb-[20px] flex flex-col">
|
||||
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
|
||||
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
<el-input v-model.trim="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
</div>
|
||||
<el-button type="primary" @click="saveWapDomain">{{ t('confirm') }}</el-button>
|
||||
<el-button type="primary" @click="settingTips()" plain>{{ t('settingTips') }}</el-button>
|
||||
@ -165,7 +165,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('componentBgAlpha')" v-if="diyStore.editComponent.ignore.indexOf('componentBgUrl') == -1 && diyStore.editComponent.componentBgUrl">
|
||||
<el-slider v-model="diyStore.editComponent.componentBgAlpha" show-input size="small" :min="0" :max="10" class="ml-[10px] horz-blank-slider" />
|
||||
<el-slider v-model="diyStore.editComponent.componentBgAlpha" show-input size="small" :min="0" :max="10" class="ml-[10px] diy-nav-slider" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('componentBgColor')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
@ -182,19 +182,19 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('marginTop')" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="-100" class="ml-[10px] horz-blank-slider" />
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="-100" class="ml-[10px] diy-nav-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBottom')" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] diy-nav-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBoth')" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] diy-nav-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')" v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="100" />
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')" v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="100" />
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -237,6 +237,8 @@ route.query.type = route.query.type || '' // 页面模板,新页面传入
|
||||
route.query.title = route.query.title || ''
|
||||
route.query.back = route.query.back || '/site/diy/list'
|
||||
|
||||
console.log('route',route.path)
|
||||
|
||||
const backPath = route.query.back
|
||||
const template = ref('');
|
||||
const oldTemplate = ref('');
|
||||
@ -298,6 +300,9 @@ const modulesFiles = import.meta.glob('./components/*.vue', { eager: true })
|
||||
const addonModulesFiles = import.meta.glob('@/addon/**/views/diy/components/*.vue', { eager: true })
|
||||
addonModulesFiles && Object.assign(modulesFiles, addonModulesFiles)
|
||||
|
||||
// todo 考虑用一个编辑页面实现,方便后期维护,根据路由判断,是微页面还是系统表单
|
||||
// todo 系统表单可以使用自定义组件,微页面不能用系统表单组件
|
||||
|
||||
const modules = {}
|
||||
for (const [key, value] of Object.entries(modulesFiles)) {
|
||||
const moduleName = key.split('/').pop()
|
||||
@ -337,15 +342,14 @@ const changeTemplatePage = (value:any)=> {
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
diyStore.changeCurrentIndex(-99)
|
||||
diyStore.init(); // 清空
|
||||
if (value) {
|
||||
let data = templatePages[value].data;
|
||||
let data = cloneDeep(templatePages[value].data);
|
||||
diyStore.global = data.global;
|
||||
if (data.value.length) {
|
||||
diyStore.value = data.value
|
||||
}
|
||||
} else {
|
||||
// 清空
|
||||
diyStore.init();
|
||||
if (route.query.title) diyStore.global.title = diyStore.typeName
|
||||
}
|
||||
}).catch(() => {
|
||||
@ -353,15 +357,14 @@ const changeTemplatePage = (value:any)=> {
|
||||
template.value = oldTemplate.value;
|
||||
});
|
||||
} else {
|
||||
diyStore.init(); // 清空
|
||||
if (value) {
|
||||
let data = templatePages[value].data;
|
||||
let data = cloneDeep(templatePages[value].data);
|
||||
diyStore.global = data.global;
|
||||
if (data.value.length) {
|
||||
diyStore.value = data.value
|
||||
}
|
||||
} else {
|
||||
// 清空
|
||||
diyStore.init();
|
||||
if (route.query.title) diyStore.global.title = diyStore.typeName
|
||||
}
|
||||
}
|
||||
@ -681,6 +684,11 @@ const settingTips = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
.diy-nav-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.full-container {
|
||||
@ -793,6 +801,7 @@ const settingTips = () => {
|
||||
align-items: center;
|
||||
margin-right: 105px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
span {
|
||||
overflow: hidden; //超出的文本隐藏
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
|
||||
<div class="mb-[20px] flex flex-col">
|
||||
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
|
||||
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
<el-input v-model.trim="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<div class="w-[700px]">
|
||||
<div class="flex flex-wrap">
|
||||
<diy-link v-model="link" :ignore="['DIY_LINK']" @success="changePage">
|
||||
<diy-link v-model="link" :ignore="['DIY_LINK','DIY_JUMP_OTHER_APPLET','DIY_MAKE_PHONE_CALL']" @success="changePage">
|
||||
<el-button type="primary">{{ t('changePage') }}</el-button>
|
||||
</diy-link>
|
||||
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
|
||||
@ -80,7 +80,7 @@ const page: any = reactive({})
|
||||
const router = useRouter()
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const link = ref({
|
||||
const link: any = ref({
|
||||
name: ''
|
||||
})
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="diyPageTableData.searchParam" ref="searchFormDiyPageRef">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
<el-input v-model.trim="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('forAddon')" prop="addon_name">
|
||||
<el-select v-model="diyPageTableData.searchParam.addon_name" :placeholder="t('forAddonPlaceholder')" @change="handleSelectAddonChange">
|
||||
@ -57,6 +57,7 @@
|
||||
<el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{ t('shareSet') }}</el-button>
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<el-button v-if="row.is_default == 0 || row.type == 'DIY_PAGE'" type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
|
||||
<el-button type="primary" link @click="copyEvent(row.id)">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@ -70,14 +71,14 @@
|
||||
</el-card>
|
||||
|
||||
<!--添加页面-->
|
||||
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="25%">
|
||||
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="350px">
|
||||
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
||||
<el-input v-model.trim="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" show-word-limit class="w-full" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="w-full">
|
||||
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')" class="!w-full">
|
||||
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@ -102,10 +103,10 @@
|
||||
<span>{{ sharePage }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareTitle')" prop="title">
|
||||
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
<el-input v-model.trim="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'">
|
||||
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
<el-input v-model.trim="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareImageUrl')" prop="url">
|
||||
<upload-image v-model="shareFormData[tabShareType].url" :limit="1" />
|
||||
@ -129,6 +130,7 @@ import { t } from '@/lang'
|
||||
import { getApps,getDiyPageList, deleteDiyPage, getDiyTemplate, editDiyPageShare, setUseDiyPage } from '@/app/api/diy'
|
||||
import { ElMessageBox, FormInstance } from 'element-plus'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { setTablePageStorage,getTablePageStorage } from "@/utils/common";
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -234,12 +236,13 @@ const loadDiyPageList = (page: number = 1) => {
|
||||
diyPageTableData.loading = false
|
||||
diyPageTableData.data = res.data.data
|
||||
diyPageTableData.total = res.data.total
|
||||
setTablePageStorage(diyPageTableData.page, diyPageTableData.limit, diyPageTableData.searchParam);
|
||||
}).catch(() => {
|
||||
diyPageTableData.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
loadDiyPageList()
|
||||
loadDiyPageList(getTablePageStorage(diyPageTableData.searchParam).page);
|
||||
|
||||
// 编辑自定义页面
|
||||
const editEvent = (data: any) => {
|
||||
@ -256,6 +259,30 @@ const setUse = (id: any) => {
|
||||
loadDiyPageList()
|
||||
})
|
||||
}
|
||||
const repeat = ref(false)
|
||||
|
||||
// 复制页面
|
||||
const copyEvent = (id: any) => {
|
||||
ElMessageBox.confirm(t('diyPageCopyTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
if (repeat.value) return
|
||||
repeat.value = true
|
||||
|
||||
copyDiy({id: id}).then((res: any) => {
|
||||
if (res.code == 1) {
|
||||
loadDiyPageList()
|
||||
}
|
||||
repeat.value = false
|
||||
}).catch(err => {
|
||||
repeat.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 删除自定义页面
|
||||
const deleteEvent = (id: number) => {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<div class="font-bold text-xl mb-[40px]">{{ t('developTitle') }}</div>
|
||||
<div class="mb-[20px] flex flex-col">
|
||||
<text class="mb-[10px]">{{ t('wapDomain') }}</text>
|
||||
<el-input v-model="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
<el-input v-model.trim="wapDomain" :placeholder="t('wapDomainPlaceholder')" clearable />
|
||||
</div>
|
||||
<div class="flex">
|
||||
<el-button type="primary" @click="saveDomain()">{{ t('confirm') }}</el-button>
|
||||
@ -105,7 +105,7 @@ const page: any = reactive({})
|
||||
const router = useRouter()
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const link = ref({
|
||||
const link: any = ref({
|
||||
name: ''
|
||||
})
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="diyRouteTableData.searchParam" ref="searchFormDiyRouteRef">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyRouteTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
<el-input v-model.trim="diyRouteTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('forAddon')" prop="addon_name">
|
||||
<el-select v-model="diyRouteTableData.searchParam.addon_name" :placeholder="t('forAddonPlaceholder')">
|
||||
@ -54,7 +54,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="diyRouteTableData.page" v-model:page-size="diyRouteTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="diyRouteTableData.total" @size-change="loadDiyRouteList()" @current-change="loadDiyRouteList" />
|
||||
<el-pagination v-model:current-page="diyRouteTableData.page" v-model:page-size="diyRouteTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="diyRouteTableData.total" @size-change="getDiyRouteListFn" @current-change="loadDiyRouteList" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
@ -70,10 +70,10 @@
|
||||
<span>{{ sharePage }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareTitle')" prop="title">
|
||||
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
<el-input v-model.trim="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'">
|
||||
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
<el-input v-model.trim="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareImageUrl')" prop="url">
|
||||
<upload-image v-model="shareFormData[tabShareType].url" :limit="1" />
|
||||
@ -99,6 +99,7 @@ import { ElMessage, FormInstance } from 'element-plus'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { getUrl } from '@/app/api/sys'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -121,6 +122,8 @@ const diyRouteTableData = reactive({
|
||||
}
|
||||
})
|
||||
|
||||
const diyRouteList: any = ref([])
|
||||
|
||||
const wapDomain = ref('')
|
||||
const getDomain = async () => {
|
||||
wapDomain.value = (await getUrl()).data.wap_url
|
||||
@ -130,42 +133,60 @@ getDomain()
|
||||
|
||||
const apps: any = reactive({}) // 应用插件列表
|
||||
|
||||
getDiyRouteAppList().then(res=>{
|
||||
if(res.data){
|
||||
getDiyRouteAppList().then(res=> {
|
||||
if (res.data) {
|
||||
for (const key in res.data) {
|
||||
apps[key] = res.data[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const getDiyRouteListFn = () => {
|
||||
getDiyRouteList({}).then(res => {
|
||||
diyRouteTableData.loading = false
|
||||
diyRouteList.value = cloneDeep(res.data)
|
||||
loadDiyRouteList(diyRouteTableData.page)
|
||||
}).catch(() => {
|
||||
diyRouteTableData.loading = false
|
||||
});
|
||||
}
|
||||
|
||||
getDiyRouteListFn();
|
||||
|
||||
/**
|
||||
* 获取自定义路由列表
|
||||
*/
|
||||
const loadDiyRouteList = (page: number = 1) => {
|
||||
diyRouteTableData.loading = true
|
||||
diyRouteTableData.page = page
|
||||
|
||||
getDiyRouteList({
|
||||
page: diyRouteTableData.page,
|
||||
limit: diyRouteTableData.limit,
|
||||
...diyRouteTableData.searchParam
|
||||
}).then(res => {
|
||||
diyRouteTableData.loading = false
|
||||
const tempData = cloneDeep(diyRouteList.value)
|
||||
const data: any = [];
|
||||
|
||||
const len = Math.ceil(res.data.length / diyRouteTableData.limit)
|
||||
const data = JSON.parse(JSON.stringify(res.data))
|
||||
const dataGather = []
|
||||
for (let i = 0; i < len; i++) {
|
||||
dataGather[i] = data.splice(0, diyRouteTableData.limit)
|
||||
// 筛选条件
|
||||
for (let i = 0; i < tempData.length; i++) {
|
||||
let isAdd = true;
|
||||
if (diyRouteTableData.searchParam.title && tempData[i].title.indexOf(diyRouteTableData.searchParam.title) == -1) {
|
||||
isAdd = false;
|
||||
}
|
||||
diyRouteTableData.data = dataGather[diyRouteTableData.page - 1]
|
||||
|
||||
diyRouteTableData.total = res.data.length
|
||||
}).catch(() => {
|
||||
diyRouteTableData.loading = false
|
||||
})
|
||||
if (diyRouteTableData.searchParam.addon_name && tempData[i].addon_info && tempData[i].addon_info.key != diyRouteTableData.searchParam.addon_name) {
|
||||
isAdd = false;
|
||||
}
|
||||
|
||||
if (isAdd) {
|
||||
data.push(tempData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
diyRouteTableData.total = data.length
|
||||
const len = Math.ceil(data.length / diyRouteTableData.limit)
|
||||
const dataGather = []
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
dataGather[i] = data.splice(0, diyRouteTableData.limit)
|
||||
}
|
||||
diyRouteTableData.data = dataGather[diyRouteTableData.page - 1]
|
||||
}
|
||||
loadDiyRouteList()
|
||||
|
||||
// 获取自定义页面模板
|
||||
getDiyTemplate({}).then(res => {
|
||||
@ -232,7 +253,7 @@ const openShare = async (row: any) => {
|
||||
name: row.name
|
||||
})).data
|
||||
|
||||
if (info && info.title) {
|
||||
if (info.title) {
|
||||
row.id = info.id
|
||||
row.title = info.title
|
||||
row.name = info.name
|
||||
@ -273,7 +294,7 @@ const shareEvent = async (formEl: FormInstance | undefined) => {
|
||||
share: JSON.stringify(shareFormData),
|
||||
...diyRouteData
|
||||
}).then(() => {
|
||||
loadDiyRouteList()
|
||||
getDiyRouteListFn()
|
||||
shareDialogVisible.value = false
|
||||
}).catch(() => {
|
||||
})
|
||||
@ -284,7 +305,7 @@ const shareEvent = async (formEl: FormInstance | undefined) => {
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
loadDiyRouteList()
|
||||
getDiyRouteListFn()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -17,7 +17,13 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="key" :label="t('key')" min-width="80"/>
|
||||
<el-table-column prop="key" :label="t('key')" min-width="120"/>
|
||||
|
||||
<el-table-column :label="t('type')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.info.type === 'app' ? t('app') : t('addon') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
|
||||
<template #default="{ row }">
|
||||
@ -42,6 +48,7 @@
|
||||
import { t } from '@/lang'
|
||||
import { getDiyBottomList } from '@/app/api/diy'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -64,7 +71,7 @@
|
||||
bottomNavTableData.loading = false
|
||||
|
||||
const len = Math.ceil(res.data.length / bottomNavTableData.limit)
|
||||
const data = JSON.parse(JSON.stringify(res.data))
|
||||
const data = cloneDeep(res.data)
|
||||
const dataGather = []
|
||||
for (let i = 0; i < len; i++) {
|
||||
dataGather[i] = data.splice(0, bottomNavTableData.limit)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="card !border-none" shadow="never">
|
||||
<el-page-header :content="pageName" :icon="ArrowLeft" @back="$router.back()" />
|
||||
<el-page-header :content="pageName" :icon="ArrowLeft" @back="back()" />
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card mt-[15px] !border-none" shadow="never" v-loading="loading">
|
||||
@ -31,7 +31,7 @@
|
||||
<el-tabs v-model="activeName" class="demo-tabs mt-[15px]">
|
||||
<el-tab-pane :label="t('navImage')" name="navPicture">
|
||||
<div ref="navItemRef">
|
||||
<div v-for="(item,index) in diyBottomData.value.list" :key="'a'+index" :data-id="index" class="item-wrap border-2 border-dashed pt-[18px] m-[10px] mb-[15px] relative list-item">
|
||||
<div v-for="(item,index) in diyBottomData.value.list" :key="'a'+index" :data-id="index" class="item-wrap border-2 border-dashed pt-[18px] m-[10px] mb-[15px] relative list-item" :class="{ 'not-sort': useDrag }">
|
||||
<el-form-item :label="t('navIconOne')">
|
||||
<div class="flex align-center">
|
||||
<div class="flex flex-col justify-center items-center">
|
||||
@ -45,10 +45,10 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('navTitleOne')">
|
||||
<el-input class="!w-[215px]" v-model="item.text" :placeholder="t('titleContent')" maxlength="5" show-word-limit />
|
||||
<el-input class="!w-[215px]" v-model.trim="item.text" :placeholder="t('titleContent')" maxlength="5" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('navLinkOne')">
|
||||
<diy-link v-model="item.link"/>
|
||||
<diy-link v-model="item.link" @confirm="diyLinkFn" />
|
||||
</el-form-item>
|
||||
<el-icon class="close-icon cursor-pointer -top-[11px] -right-[8px]" @click="deleteNav(index)">
|
||||
<CircleCloseFilled />
|
||||
@ -69,21 +69,21 @@
|
||||
<el-form-item :label="t('textColor')">
|
||||
<div class="flex align-center">
|
||||
<el-color-picker v-model="diyBottomData.value.textColor" />
|
||||
<el-input class="ml-[10px]" v-model="diyBottomData.value.textColor" disabled />
|
||||
<el-input class="ml-[10px]" v-model.trim="diyBottomData.value.textColor" disabled />
|
||||
<el-button class="ml-[10px]" type="primary" @click="diyBottomData.value.textColor = '#333333'">{{ t('reset') }}</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textSelectColor')">
|
||||
<div class="flex align-center">
|
||||
<el-color-picker v-model="diyBottomData.value.textHoverColor" />
|
||||
<el-input class="ml-[10px]" v-model="diyBottomData.value.textHoverColor" disabled />
|
||||
<el-input class="ml-[10px]" v-model.trim="diyBottomData.value.textHoverColor" disabled />
|
||||
<el-button class="ml-[10px]" type="primary" @click="diyBottomData.value.textHoverColor = '#333333'">{{ t('reset') }}</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('backgroundColor')">
|
||||
<div class="flex align-center">
|
||||
<el-color-picker v-model="diyBottomData.value.backgroundColor" />
|
||||
<el-input class="ml-[10px]" v-model="diyBottomData.value.backgroundColor" disabled />
|
||||
<el-input class="ml-[10px]" v-model.trim="diyBottomData.value.backgroundColor" disabled />
|
||||
<el-button class="ml-[10px]" type="primary" @click="diyBottomData.value.backgroundColor = '#FFFFFF'">{{ t('reset') }}</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
@ -238,6 +238,7 @@ onMounted(() => {
|
||||
const sortable = Sortable.create(navItemRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
filter: '.not-sort', // 过滤.not-sort的元素
|
||||
onEnd: event => {
|
||||
const temp = diyBottomData.value.list[event.oldIndex!]
|
||||
diyBottomData.value.list.splice(event.oldIndex!, 1)
|
||||
@ -253,6 +254,10 @@ onMounted(() => {
|
||||
})
|
||||
})
|
||||
|
||||
const useDrag = ref(false)
|
||||
const diyLinkFn = (val) => {
|
||||
useDrag.value = val
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.close-icon {
|
||||
|
||||
406
admin/src/app/views/member/components/detail-member.vue
Normal file
406
admin/src/app/views/member/components/detail-member.vue
Normal file
@ -0,0 +1,406 @@
|
||||
<template>
|
||||
<el-drawer v-model="showDialog" :title="popTitle" direction="rtl" :before-close="handleClose" class="member-detail-drawer">
|
||||
<div class="main-container" v-loading="loading">
|
||||
<div class="bg-page py-[20px] pr-[30px] relative flex">
|
||||
<div class="member-info w-[250px]">
|
||||
<div class="flex items-center">
|
||||
<div class="text-[14px] min-w-[110px] text-right mr-[20px]">{{ t('headimg') }}</div>
|
||||
<div class="flex items-end text-[14px]">
|
||||
<div class="w-[50px] h-[50px] flex items-center justify-center">
|
||||
<img class="max-w-[50px] max-h-[50px] inline-block" v-if="formData.headimg" :src="img(formData.headimg)" alt="">
|
||||
<img class="max-w-[50px] max-h-[50px] inline-block rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
</div>
|
||||
<el-icon @click="editMemberInfo('headimg')" class="-bottom-[2px] -right-[4px] cursor-pointer">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center mt-[20px]">
|
||||
<span class="text-[14px] min-w-[110px] text-right mr-[20px]">UID</span>
|
||||
<span class="member-info-item text-[14px] text-[#666666] font-bold w-[150px]">
|
||||
{{ formData.member_no || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-between">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="formData.point">
|
||||
<template #title>
|
||||
<div style="display: inline-flex; align-items: center">
|
||||
<span class="text-[14px]">
|
||||
{{ t('point') }}
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="t('adjust')" placement="top">
|
||||
<el-icon @click="adjustPoint(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" :content="t('detail')" placement="top">
|
||||
<el-icon @click="infoPoint(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-secondary">
|
||||
<span>{{ t('accumulative') }}</span>
|
||||
<span class="green ml-1">
|
||||
{{ formData.point_get }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="formData.balance">
|
||||
<template #title>
|
||||
<div style="display: inline-flex; align-items: center">
|
||||
<span class="text-[14px]">
|
||||
{{ t('balance') }}
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="t('adjust')" placement="top">
|
||||
<el-icon @click="adjustBalance(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" :content="t('detail')" placement="top">
|
||||
<el-icon @click="infoBalance(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-secondary">
|
||||
<span>{{ t('accumulative') }}</span>
|
||||
<span class="red ml-1">
|
||||
{{ formData.balance_get }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="formData.growth">
|
||||
<template #title>
|
||||
<div style="display: inline-flex; align-items: center">
|
||||
<span class="text-[14px]">
|
||||
{{ t('growth') }}
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="t('detail')" placement="top">
|
||||
<el-icon @click="infoGrowth(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</div>
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="formData.money" title="New transactions today">
|
||||
<template #title>
|
||||
<div style="display: inline-flex; align-items: center">
|
||||
<span class="text-[14px]">
|
||||
{{ t("money") }}
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="t('detail')" placement="top">
|
||||
<el-icon @click="infoBalance(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-secondary">
|
||||
<span>{{ t('accumulative') }}</span>
|
||||
<span class="green ml-1">
|
||||
{{ formData.money_get }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="formData.commission" title="New transactions today">
|
||||
<template #title>
|
||||
<div style="display: inline-flex; align-items: center ">
|
||||
<span class="text-[14px]">
|
||||
{{ t("commission") }}
|
||||
</span>
|
||||
<el-tooltip effect="dark" :content="t('detail')" placement="top">
|
||||
<el-icon @click="infoCommission(formData)" class="ml-2 cursor-pointer" :size="12">
|
||||
<View />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-secondary">
|
||||
<span>{{ t('accumulative') }}</span>
|
||||
<span class="green ml-1">
|
||||
{{ formData.commission_get }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap mt-[20px]">
|
||||
<div class="flex items-center w-[33.3%] mt-[15px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('urserName') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.username || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('nickname') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.nickname || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('mobile') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.mobile || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('memberLevel') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.member_level_name || t('notAvailable') }}<el-icon @click="editMemberInfo('member_level')" class="-bottom-[2px] -right-[4px] cursor-pointer">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('memberLabel') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.member_label_name&&formData.member_label_name.toString() || t('notAvailable') }}<el-icon @click="editMemberInfo('member_label')" class="-bottom-[2px] -right-[4px] cursor-pointer">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('birthday') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.birthday || t('notAvailable') }}<el-icon @click="editMemberInfo('birthday')" class="-bottom-[2px] -right-[4px] cursor-pointer">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('sex') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.sex == 1 && t('manSex') || formData.sex == 2 && t('girlSex') || t('secrecySex') }}<el-icon @click="editMemberInfo('sex')" class="-bottom-[2px] -right-[4px] cursor-pointer">
|
||||
<EditPen color="#273CE2" />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('wxUnionid') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.wx_unionid || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('weappOpenid') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.weapp_openid || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('wxOpenid') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.wx_openid || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('registeredSource') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.register_channel_name || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('createTime') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.create_time || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex mt-[15px] w-[33.3%] break-all leading-[21px]">
|
||||
<span class="text-[14px] w-[130px] text-right flex-shrink-0 mr-[20px]">{{ t('lastVisitTime') }}</span>
|
||||
<span class="text-[14px] text-[#666666]">
|
||||
{{ formData.last_visit_time || t('notAvailable') }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<point-edit ref="pointDialog" @complete="getMemberInfoFn" />
|
||||
<balance-edit ref="balanceDialog" @complete="getMemberInfoFn" />
|
||||
<edit-member ref="editMemberDialog" @complete="getMemberInfoFn()" />
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { addMember, getMemberList, getMemberNo, getMemberInfo } from '@/app/api/member'
|
||||
import { FormInstance, ElMessage } from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { img, filterNumber } from '@/utils/common'
|
||||
import PointEdit from '@/app/views/member/components/member-point-edit.vue'
|
||||
import BalanceEdit from '@/app/views/member/components/member-balance-edit.vue'
|
||||
import EditMember from '@/app/views/member/components/edit-member.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
const repeat = ref(false)
|
||||
let popTitle: string = '会员详情'
|
||||
let memberNo: string = ''
|
||||
let id = '';
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const emit = defineEmits(['load'])
|
||||
|
||||
const nickname_name_input = ref(true)
|
||||
const password_input = ref(true)
|
||||
const password_copy_input = ref(true)
|
||||
|
||||
const handleClose = (done: () => void) => {
|
||||
showDialog.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
member_id: '',
|
||||
nickname: '',
|
||||
member_no: '',
|
||||
init_member_no: '',
|
||||
mobile: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const pointDialog: Record<string, any> | null = ref(null)
|
||||
const balanceDialog: Record<string, any> | null = ref(null)
|
||||
const editMemberDialog: Record<string, any> | null = ref(null)
|
||||
|
||||
/**
|
||||
* 修改会员信息
|
||||
*/
|
||||
const editMemberInfo = (type: any) => {
|
||||
const data = ref({
|
||||
type,
|
||||
id,
|
||||
data: formData
|
||||
})
|
||||
editMemberDialog.value.setDialogType(data.value)
|
||||
editMemberDialog.value.showDialog = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整积分
|
||||
*/
|
||||
const adjustPoint = (data: any) => {
|
||||
pointDialog.value.setFormData(data)
|
||||
pointDialog.value.showDialog = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整余额
|
||||
*/
|
||||
const adjustBalance = (data: any) => {
|
||||
balanceDialog.value.setFormData(data)
|
||||
balanceDialog.value.showDialog = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 积分详情
|
||||
*/
|
||||
const infoPoint = () => {
|
||||
router.push(`/member/point?id=${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额详情
|
||||
*/
|
||||
const infoBalance = () => {
|
||||
router.push(`/member/balance?id=${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 成长值明细
|
||||
*/
|
||||
const infoGrowth = () => {
|
||||
router.push(`/member/growth?id=${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 佣金详情
|
||||
*/
|
||||
const infoCommission = () => {
|
||||
router.push(`/member/commission?id=${id}`)
|
||||
}
|
||||
|
||||
const getMemberInfoFn = async (bool=false) => {
|
||||
loading.value = true
|
||||
if (id) {
|
||||
const data = await (await getMemberInfo(id)).data
|
||||
if (!data || Object.keys(data).length == 0) {
|
||||
ElMessage.error(t('memberNull'))
|
||||
setTimeout(() => {
|
||||
router.go(-1)
|
||||
}, 2000)
|
||||
return false
|
||||
}
|
||||
|
||||
Object.keys(data).forEach((item) => {
|
||||
formData[item] = data[item]
|
||||
})
|
||||
|
||||
if (formData?.member_label_array && Object.keys(formData.member_label_array)?.length) {
|
||||
formData.member_label = Object.values(formData.member_label_array).map((item: any, index) => {
|
||||
return item.label_id
|
||||
})
|
||||
|
||||
formData.member_label_name = Object.values(formData.member_label_array).map((item: any, index) => {
|
||||
return item.label_name
|
||||
})
|
||||
}
|
||||
loading.value = false
|
||||
} else {
|
||||
loading.value = false
|
||||
}
|
||||
if(!bool){
|
||||
emit('load');
|
||||
}
|
||||
}
|
||||
|
||||
const setFormData = async (row: any = null) => {
|
||||
id = row.id;
|
||||
Object.assign(formData, initialFormData)
|
||||
getMemberInfoFn(true);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog,
|
||||
setFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.member-detail-drawer{
|
||||
width: 1000px !important;
|
||||
}
|
||||
</style>
|
||||
@ -6,19 +6,19 @@
|
||||
<h3 class="panel-title !text-sm">{{ t('commonSetting') }}</h3>
|
||||
|
||||
<el-form-item :label="t('logonMode')" prop="type">
|
||||
<el-checkbox v-model="formData.is_username" :label="t('isUsername')" @change="switchChange($event, 'is_username')" />
|
||||
<div class="form-tip">{{ t('isUsernameTip') }}</div>
|
||||
<el-checkbox v-model="formData.is_mobile" :label="t('isMobile')" @change="switchChange($event, 'is_mobile')" />
|
||||
<el-checkbox v-model="formData.is_username" :true-value="1" :false-value="0" :label="t('isUsername')" />
|
||||
<div class="form-tip mb-[10px]">{{ t('isUsernameTip') }}</div>
|
||||
<el-checkbox v-model="formData.is_mobile" :true-value="1" :false-value="0" :label="t('isMobile')" />
|
||||
<div class="form-tip">{{ t('isMobileTip') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('isBindMobile')" prop="formData.is_bind_mobile">
|
||||
<el-switch v-model="formData.is_bind_mobile" @change="switchChange($event, 'is_bind_mobile')" />
|
||||
<el-switch v-model="formData.is_bind_mobile" :active-value="1" :inactive-value="0" />
|
||||
<div class="form-tip">{{ t('isBindMobileTip') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('agreement')" prop="formData.agreement_show">
|
||||
<el-switch v-model="formData.agreement_show" @change="switchChange($event, 'agreement_show')" />
|
||||
<el-switch v-model="formData.agreement_show" :active-value="1" :inactive-value="0" />
|
||||
<div class="form-tip">{{ t('agreementTips') }}</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
@ -27,9 +27,28 @@
|
||||
<h3 class="panel-title !text-sm">{{ t('tripartiteSetting') }}</h3>
|
||||
|
||||
<el-form-item :label="t('isAuthRegister')" prop="formData.is_auth_register">
|
||||
<el-switch v-model="formData.is_auth_register" @change="switchChange($event, 'is_auth_register')" />
|
||||
<el-switch v-model="formData.is_auth_register" :active-value="1" :inactive-value="0" />
|
||||
<div class="form-tip">{{ t('isAuthRegisterTip') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('isForceAccessUserInfo')" prop="formData.is_force_access_user_info" v-show="formData.is_auth_register == 1">
|
||||
<el-switch v-model="formData.is_force_access_user_info" :active-value="1" :inactive-value="0" />
|
||||
<div class="form-tip">{{ t('isForceAccessUserInfoTip') }}</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card mt-[15px] !border-none" shadow="never">
|
||||
<h3 class="panel-title !text-sm">{{ t('loginPageSet') }}</h3>
|
||||
<el-form-item :label="t('bgUrl')">
|
||||
<div>
|
||||
<upload-image v-model="formData.bg_url" />
|
||||
<p class="text-[12px] text-[#a9a9a9]">{{ t('bgUrlPlaceholder') }}</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('desc')">
|
||||
<el-input v-model.trim="formData.desc" :placeholder="t('descPlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
</el-card>
|
||||
</el-form>
|
||||
|
||||
@ -47,59 +66,57 @@ import { t } from '@/lang'
|
||||
import { getLoginConfig, setLoginConfig } from '@/app/api/member'
|
||||
import { FormInstance } from 'element-plus'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
|
||||
const loading = ref(true)
|
||||
const ruleFormRef = ref<FormInstance>()
|
||||
const formData = reactive<Record<string, number | boolean>>({
|
||||
const formData:any = reactive({
|
||||
is_username: 0,
|
||||
is_mobile: 0,
|
||||
is_auth_register: 0,
|
||||
is_force_access_user_info: 0,
|
||||
is_bind_mobile: 0,
|
||||
agreement_show: 0
|
||||
agreement_show: 0,
|
||||
bg_url: '',
|
||||
logo: '',
|
||||
desc: ''
|
||||
})
|
||||
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
type: [
|
||||
{
|
||||
required: true,
|
||||
trigger: 'change',
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (!formData.is_mobile && !formData.is_username) {
|
||||
callback(new Error(t('mobileOrUsernameNoEmpty')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
// type: [
|
||||
// {
|
||||
// required: true,
|
||||
// trigger: 'change',
|
||||
// validator: (rule: any, value: any, callback: any) => {
|
||||
// if (!formData.is_mobile && !formData.is_username) {
|
||||
// callback(new Error(t('mobileOrUsernameNoEmpty')))
|
||||
// } else {
|
||||
// callback()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
}
|
||||
})
|
||||
|
||||
const setFormData = async (id: number = 0) => {
|
||||
const setFormData = async () => {
|
||||
const data = await (await getLoginConfig()).data
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = Boolean(Number(data[key]))
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
loading.value = false
|
||||
}
|
||||
setFormData()
|
||||
|
||||
const switchChange = (val, key) => {
|
||||
formData[key] = val
|
||||
}
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
await formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
const save = JSON.parse(JSON.stringify(formData))
|
||||
Object.keys(save).forEach((key) => {
|
||||
save[key] = Number(save[key])
|
||||
})
|
||||
const save = cloneDeep(formData)
|
||||
|
||||
setLoginConfig(save).then(() => {
|
||||
loading.value = false
|
||||
|
||||
@ -88,7 +88,8 @@
|
||||
"detectionLoginOperation": "确定",
|
||||
"detectionLoginContent": "已检测到有其他账号登录,需要刷新后才能继续操作。",
|
||||
"detectionLoginTip": "提示",
|
||||
"layoutStyle": "布局风格"
|
||||
"layoutStyle": "布局风格",
|
||||
"tab": "开启标签栏"
|
||||
},
|
||||
"axios": {
|
||||
"unknownError": "未知错误",
|
||||
@ -176,18 +177,5 @@
|
||||
"write": "可写",
|
||||
"cloudbuildSuccess": "编译完成",
|
||||
"showDialogCloseTips": "编译任务尚未完成,关闭将取消编译,是否要继续关闭?"
|
||||
},
|
||||
"generateNumber": "请输入数字",
|
||||
"generateEmail": "请输入正确的邮箱",
|
||||
"generateIdCard": "请输入正确的身份证号",
|
||||
"generateMobile": "请输入正确的手机号",
|
||||
"generateNumberOrFloat": "只能输入整数或小数",
|
||||
"generateMax": "最大输入字符不能超出",
|
||||
"generateMin": "输入字符不能小于",
|
||||
"generateUnit": "位",
|
||||
"startDate": "开始时间",
|
||||
"endDate": "结束时间",
|
||||
"newcomerNumberColor": "数字颜色",
|
||||
"newcomerNumberBg": "数字背景色",
|
||||
"newcomerOtherColor": "文字颜色"
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,6 @@ import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { ADMIN_ROUTE,findFirstValidRoute } from "@/router/routers"
|
||||
import { img, isUrl } from '@/utils/common'
|
||||
import { getWebsite } from '@/app/api/sys'
|
||||
import menuItem from './menu-item.vue'
|
||||
|
||||
const route = useRoute()
|
||||
@ -79,17 +78,6 @@ watch(route, () => {
|
||||
oneMenuActive.value = route.matched[1].name == ADMIN_ROUTE.children[0].name ? route.matched[2].name : route.matched[1].name
|
||||
}, { immediate: true })
|
||||
|
||||
// const logoShow = ref<boolean>(false)
|
||||
// const getWebsiteFn = ()=>{
|
||||
// getWebsite().then((res:any)=>{
|
||||
// logoUrl.value = res.data.icon
|
||||
// console.log(res)
|
||||
// logoShow.value = true
|
||||
// }).catch(()=>{
|
||||
// logoShow.value = true
|
||||
// })
|
||||
// }
|
||||
// getWebsiteFn()
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, computed } from 'vue'
|
||||
import menuItem from './menu-item.vue'
|
||||
import { CollectionTag } from '@element-plus/icons-vue'
|
||||
|
||||
@ -17,8 +17,6 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import menuItem from './menu-item.vue'
|
||||
import storage from '@/utils/storage'
|
||||
import { img } from '@/utils/common'
|
||||
|
||||
const logo = ref('@/app/assets/images/login_logo.png')
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
@ -18,6 +18,17 @@
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 布局风格 -->
|
||||
<div class="setting-item mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.layoutStyle') }}</div>
|
||||
<div class="flex mt-[10px] layout-style flex-wrap">
|
||||
<div class="relative w-[125px] h-[100px] border mr-[10px] mb-[10px] hover:border-primary"
|
||||
:class="{ 'border-primary': currLayout == item.key }" v-for="(item, index) in layouts"
|
||||
@click="handleSetLayout(item.key)">
|
||||
<img :src="item.image" alt="" class="w-full h-full">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
@ -31,6 +42,12 @@ import { setThemeColor, img } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
import Storage from '@/utils/storage'
|
||||
|
||||
const layouts = ref([
|
||||
{ key: 'admin', image: img('static/resource/images/system/layout_bussiness.png') },
|
||||
{ key: 'admin_simplicity', image: img('static/resource/images/system/layout_darkside.png') }
|
||||
])
|
||||
const currLayout = ref(Storage.get('admin_layout') || 'admin')
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
@ -67,6 +84,11 @@ const theme = computed({
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
const handleSetLayout = (key: string) => {
|
||||
Storage.set({ key: 'admin_layout', data: key })
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<div>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" :src="userStore.userInfo.head_img ? img(userStore.userInfo.head_img) : ''"/>
|
||||
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
@ -93,10 +94,10 @@ const getUserInfoFn = ()=>{
|
||||
userInfoEditRef.value?.open()
|
||||
}
|
||||
// 修改密码 --- start
|
||||
let changePasswordDialog = ref(false)
|
||||
const changePasswordDialog = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
// 提交信息
|
||||
let saveInfo = reactive({
|
||||
const saveInfo = reactive({
|
||||
original_password: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
@ -137,7 +138,6 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 修改密码 --- end
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
65
admin/src/layout/admin_simplicity/components/aside/index.vue
Normal file
65
admin/src/layout/admin_simplicity/components/aside/index.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<el-aside class="layout-aside dark w-auto">
|
||||
<side class="hidden-xs-only slide" />
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import side from './side.vue'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
const systemStore = useSystemStore()
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
watch(route, () => {
|
||||
systemStore.$patch(state => {
|
||||
state.menuDrawer = false
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.layout-aside {
|
||||
//--side-dark-color: #141414;
|
||||
//background-color: var(--side-dark-color, var(--el-bg-color));
|
||||
|
||||
&.bright {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
li {
|
||||
background-color: #F5F7F9;
|
||||
|
||||
&.is-active:not(.is-opened) {
|
||||
position: relative;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
//background-color: var(--el-menu-active-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slide {
|
||||
border-right: 1px solid var(--el-border-color-extra-light);
|
||||
}
|
||||
}
|
||||
|
||||
.aside-drawer {
|
||||
.el-drawer__body {
|
||||
padding: 0px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<template v-if="meta.show">
|
||||
<el-sub-menu v-if="meta.type == 0 && routes.children" :index="String(routes.name)">
|
||||
<template #title>
|
||||
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
|
||||
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
|
||||
</div>
|
||||
<span class="ml-[10px]">{{ meta.title }}</span>
|
||||
</template>
|
||||
<menu-item v-for="(route, index) in routes.children" :routes="route" :key="index" :level="props.level + 1" />
|
||||
</el-sub-menu>
|
||||
<template v-else>
|
||||
<el-menu-item :index="String(routes.name)" @click="router.push({ name: routes.name })">
|
||||
<div class="w-[16px] h-[16px] relative flex items-center" v-if="props.level == 1">
|
||||
<icon v-if="meta.icon" :name="meta.icon" class="absolute !w-auto" />
|
||||
</div>
|
||||
<template #title>
|
||||
<span class="ml-[10px]">{{ meta.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { img } from '@/utils/common'
|
||||
import menuItem from './menu-item.vue'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
const routers = useUserStore().routers
|
||||
const props = defineProps({
|
||||
routes: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
level: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
const systemStore = useSystemStore()
|
||||
const meta = computed(() => props.routes.meta)
|
||||
|
||||
const addons = computed(() => {
|
||||
const addons:Record<string, any> = {}
|
||||
userStore.siteInfo?.apps.forEach((item: any) => { addons[item.key] = item })
|
||||
userStore.siteInfo?.site_addons.forEach((item: any) => { addons[item.key] = item })
|
||||
return addons
|
||||
})
|
||||
|
||||
const systemAddonKeys = computed(() => {
|
||||
return userStore.siteInfo?.site_addons.map((item: any) => item.key)
|
||||
})
|
||||
|
||||
const addonRouters: Record<string, any> = {}
|
||||
routers.forEach(item => {
|
||||
item.original_name = item.name
|
||||
if (item.meta.addon) {
|
||||
addonRouters[item.meta.addon] = item
|
||||
}
|
||||
})
|
||||
|
||||
const addonsMenus = ref(null)
|
||||
|
||||
watch(route, () => {
|
||||
if (props.routes.name != 'addon_list') return
|
||||
|
||||
if (systemAddonKeys.value.includes(route.meta.addon) && addonRouters[route.meta.addon]) {
|
||||
addonsMenus.value = addonRouters[route.meta.addon]
|
||||
} else {
|
||||
addonsMenus.value = null
|
||||
}
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-sub-menu{
|
||||
.el-icon{
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
125
admin/src/layout/admin_simplicity/components/aside/side.vue
Normal file
125
admin/src/layout/admin_simplicity/components/aside/side.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<el-container class="h-screen flex flex-col">
|
||||
<el-main class="menu-wrap">
|
||||
<el-header class="logo-wrap flex items-center justify-center h-[64px] w-[var(--aside-width)]">
|
||||
<div class="flex justify-center items-center h-[64px] w-full px-[10px]" v-if="Object.keys(website).length">
|
||||
<el-image :src="img(website.icon)" class="w-[44px] h-[44px] rounded-[50%]" @error="website.icon = img('static/resource/images/niucloud_icon.jpg')"></el-image>
|
||||
<div class="flex-1 w-0 overflow-text truncate ml-[10px] text-white" v-if="!systemStore.menuIsCollapse">
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
:content="website.site_name"
|
||||
placement="top"
|
||||
>
|
||||
{{ website.site_name }}
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</el-header>
|
||||
<el-scrollbar class="menu-scrollbar flex-1 h-0">
|
||||
<el-menu :default-active="route.name" :router="true" :unique-opened="false" :collapse="systemStore.menuIsCollapse" background-color="#1f2531" text-color="#fff" active-text-color="#fff">
|
||||
<menu-item v-for="(route, index) in menuData" :routes="route" :key="index" />
|
||||
</el-menu>
|
||||
<div class="h-[48px]"></div>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import menuItem from './menu-item.vue'
|
||||
import { img, isUrl } from '@/utils/common'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
|
||||
const systemStore = useSystemStore()
|
||||
const userStore = useUserStore()
|
||||
const route = useRoute()
|
||||
const siteInfo = userStore.siteInfo
|
||||
const routers = userStore.routers
|
||||
const addonIndexRoute = userStore.addonIndexRoute
|
||||
const menuData = ref<Record<string, any>[]>([])
|
||||
const addonRouters: Record<string, any> = {}
|
||||
const website = computed(() => {
|
||||
return systemStore.website
|
||||
})
|
||||
|
||||
routers.forEach(item => {
|
||||
item.original_name = item.name
|
||||
if (item.meta.addon == '') {
|
||||
if (item.children && item.children.length) {
|
||||
item.name = findFirstValidRoute(item.children)
|
||||
}
|
||||
menuData.value.push(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.original_name = citem.name
|
||||
if (citem.children && citem.children.length) {
|
||||
citem.name = findFirstValidRoute(citem.children)
|
||||
}
|
||||
})
|
||||
menuData.value.unshift(...item.children)
|
||||
} else {
|
||||
menuData.value.unshift(item)
|
||||
}
|
||||
} else {
|
||||
addonRouters[item.meta.addon] = item
|
||||
}
|
||||
})
|
||||
|
||||
// 多应用时将应用插入菜单
|
||||
if (siteInfo?.apps.length > 1) {
|
||||
const routers:Record<string, any>[] = []
|
||||
siteInfo?.apps.forEach((item: Record<string, any>) => {
|
||||
if (addonRouters[item.key]) {
|
||||
addonRouters[item.key].name = addonIndexRoute[item.key]
|
||||
routers.push(addonRouters[item.key])
|
||||
}
|
||||
})
|
||||
menuData.value.unshift(...routers)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.logo-wrap {
|
||||
background: #1f2531;
|
||||
transition: transform getCssVar('transition-duration');
|
||||
}
|
||||
:root{
|
||||
--aside-width: 200px;
|
||||
}
|
||||
.menu-wrap {
|
||||
padding: 0!important;
|
||||
background: #1f2531;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.el-menu {
|
||||
border-right: 0!important;
|
||||
|
||||
&:not(.el-menu--collapse) {
|
||||
width: var(--aside-width);
|
||||
}
|
||||
|
||||
.el-menu-item, .el-sub-menu__title {
|
||||
--el-menu-item-height: 40px;
|
||||
}
|
||||
|
||||
.el-sub-menu .el-menu-item {
|
||||
--el-menu-sub-item-height: 40px;
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
background: var(--el-color-primary);
|
||||
}
|
||||
|
||||
&.el-menu--inline {
|
||||
background: #282e3a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
140
admin/src/layout/admin_simplicity/components/header/index.vue
Normal file
140
admin/src/layout/admin_simplicity/components/header/index.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<el-container class="h-[64px] layout-admin flex items-center justify-between px-[15px]" >
|
||||
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
||||
<div class="left-panel flex items-center text-[14px] leading-[1]">
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleMenuCollapse">
|
||||
<icon name="element Expand" v-if="systemStore.menuIsCollapse" />
|
||||
<icon name="element Fold" v-else />
|
||||
</div>
|
||||
<!-- 刷新当前页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" @click="refreshRouter">
|
||||
<icon name="element Refresh" />
|
||||
</div>
|
||||
<!-- 面包屑导航 -->
|
||||
<div class="flex items-center h-full pl-[10px] hidden-xs-only">
|
||||
<el-breadcrumb separator="/">
|
||||
<el-breadcrumb-item v-for="(route, index) in breadcrumb" :key="index">{{route.meta.title }}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<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 />
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" v-model="comparisonToken">
|
||||
<input type="hidden" v-model="comparisonSiteId">
|
||||
|
||||
<el-dialog v-model="detectionLoginDialog" :title="t('layout.detectionLoginTip')" width="30%" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
||||
<span>{{ t('layout.detectionLoginContent') }}</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="detectionLoginFn">{{ t('layout.detectionLoginOperation') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('indexTemplate')" width="550px" :destroy-on-close="true" >
|
||||
<div class="flex flex-wrap">
|
||||
<div v-for="(items, index) in indexList" :key="index" v-if="index_path == ''">
|
||||
<div @click="index_path = items.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="items.is_use == 1 ? 'bg-primary text-[#fff]' : '' ">
|
||||
<span >{{ items.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(itemTo, indexTo) in indexList" :key="indexTo" v-else>
|
||||
<div @click="index_path = itemTo.view_path" class="index-item py-[5px] px-[10px] mr-[10px] rounded-[3px] cursor-pointer" :class="index_path == itemTo.view_path ? 'bg-primary text-[#fff]' : '' ">
|
||||
<span >{{ itemTo.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="submitIndex">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
import userInfo from './user-info.vue'
|
||||
import layoutSetting from './layout-setting.vue'
|
||||
import useSystemStore from "@/stores/modules/system";
|
||||
|
||||
const route = useRoute()
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
// 检测登录 start
|
||||
const detectionLoginDialog = ref(false)
|
||||
const comparisonToken = ref('')
|
||||
const comparisonSiteId = ref('')
|
||||
if (storage.get('comparisonTokenStorage')) {
|
||||
comparisonToken.value = storage.get('comparisonTokenStorage')
|
||||
}
|
||||
if (storage.get('comparisonSiteIdStorage')) {
|
||||
comparisonSiteId.value = storage.get('comparisonSiteIdStorage')
|
||||
}
|
||||
// 监听标签页面切换
|
||||
document.addEventListener('visibilitychange', e => {
|
||||
if (document.visibilityState === 'visible' && (comparisonSiteId.value != storage.get('siteId') || comparisonToken.value != storage.get('token'))) {
|
||||
detectionLoginDialog.value = true
|
||||
}
|
||||
})
|
||||
|
||||
systemStore.toggleMenuCollapse(storage.get('menuiscollapse') || false)
|
||||
|
||||
const detectionLoginFn = () => {
|
||||
detectionLoginDialog.value = false
|
||||
location.reload()
|
||||
}
|
||||
// 检测登录 end
|
||||
|
||||
// 刷新路由
|
||||
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
|
||||
})
|
||||
storage.set({ key: 'currHeadMenuName', data: "" })
|
||||
|
||||
const toggleMenuCollapse = () => {
|
||||
systemStore.toggleMenuCollapse(!systemStore.menuIsCollapse)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.layout-header{
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
border-bottom: 1px solid #e8e9eb;
|
||||
}
|
||||
.navbar-item {
|
||||
padding: 0 8px;
|
||||
}
|
||||
.index-item {
|
||||
border: 1px solid;
|
||||
border-color: var(--el-color-primary);
|
||||
&:hover {
|
||||
color: #fff;
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="flex">
|
||||
<icon name="element Setting" @click="drawer = true" />
|
||||
|
||||
<el-drawer v-model="drawer" :title="t('layout.layoutSetting')" size="300px">
|
||||
<el-scrollbar>
|
||||
<!-- 黑暗模式 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.darkMode') }}</div>
|
||||
<div>
|
||||
<el-switch v-model="dark" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 主题颜色 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.themeColor') }}</div>
|
||||
<div>
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 布局风格 -->
|
||||
<div class="setting-item mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.layoutStyle') }}</div>
|
||||
<div class="flex mt-[10px] layout-style flex-wrap">
|
||||
<div class="relative w-[125px] h-[100px] border mr-[10px] mb-[10px] hover:border-primary"
|
||||
:class="{ 'border-primary': currLayout == item.key }" v-for="(item, index) in layouts"
|
||||
@click="handleSetLayout(item.key)">
|
||||
<img :src="item.image" alt="" class="w-full h-full">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor, img } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
import Storage from '@/utils/storage'
|
||||
|
||||
const layouts = ref([
|
||||
{ key: 'admin', image: img('static/resource/images/system/layout_bussiness.png') },
|
||||
{ key: 'admin_simplicity', image: img('static/resource/images/system/layout_darkside.png') }
|
||||
])
|
||||
const currLayout = ref(Storage.get('admin_layout') || 'admin')
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
const isDark = useDark()
|
||||
const toggleDark = useToggle(isDark)
|
||||
|
||||
const dark = computed({
|
||||
get() {
|
||||
return systemStore.dark
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('dark', val)
|
||||
toggleDark(val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
const sidebar = computed({
|
||||
get() {
|
||||
return systemStore.sidebar
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('sidebar', val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get() {
|
||||
return systemStore.theme
|
||||
},
|
||||
set(val) {
|
||||
systemStore.setTheme('theme', val)
|
||||
setThemeColor(systemStore.theme, systemStore.dark ? 'dark' : 'light')
|
||||
}
|
||||
})
|
||||
|
||||
const handleSetLayout = (key: string) => {
|
||||
Storage.set({ key: 'admin_layout', data: key })
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-drawer__header) {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.layout-style {
|
||||
&>div:nth-child(2n+2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<el-dropdown @command="switchLang" :tabindex="1">
|
||||
<icon name="iconfont iconfanyi" />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="zh-cn" :disabled="systemStore.lang == 'zh-cn'">简体中文</el-dropdown-item>
|
||||
<el-dropdown-item command="en" :disabled="systemStore.lang == 'en'">English</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { language } from '@/lang'
|
||||
import { useRoute } from 'vue-router'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const route = useRoute()
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
const switchLang = (command: string) => {
|
||||
systemStore.$patch((state) => {
|
||||
state.lang = command
|
||||
storage.set({ key: 'lang', data: command })
|
||||
})
|
||||
language.loadLocaleMessages(route.path, systemStore.lang)
|
||||
location.reload()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="getUserInfoFn">
|
||||
<!-- <router-link to="/user/center"> -->
|
||||
<div class="flex items-center leading-[1] py-[5px]">
|
||||
<span class="iconfont iconshezhi1 ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||
<span class="text-[14px]">账号设置</span>
|
||||
</div>
|
||||
<!-- </router-link> -->
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<router-link to="/tools/authorize">
|
||||
<div class="flex items-center leading-[1] py-[5px]">
|
||||
<span class="iconfont iconshouquanxinxi2 ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||
<span class="text-[14px]">授权信息</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="changePasswordDialog=true">
|
||||
<div class="flex items-center leading-[1] py-[5px]">
|
||||
<span class="iconfont iconxiugai ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||
<span class="text-[14px]">修改密码</span>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout">
|
||||
<div class="flex items-center leading-[1] py-[5px]">
|
||||
<span class="iconfont icontuichudenglu ml-[4px] !text-[14px] mr-[10px]"></span>
|
||||
<span class="text-[14px]">退出登录</span>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-dialog v-model="changePasswordDialog" width="450px" title="修改密码">
|
||||
<div>
|
||||
<el-form :model="saveInfo" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
||||
<el-form-item :label="t('originalPassword')" prop="original_password">
|
||||
<el-input v-model="saveInfo.original_password" type="password" :placeholder="t('originalPasswordPlaceholder')" clearable class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('newPassword')" prop="password">
|
||||
<el-input v-model="saveInfo.password" type="password" :placeholder="t('passwordPlaceholder')" clearable class="input-width" />
|
||||
<div class="form-tip">{{t('passwordTip')}}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('passwordCopy')" prop="password_copy">
|
||||
<el-input v-model="saveInfo.password_copy" type="password" :placeholder="t('passwordPlaceholder')" clearable class="input-width" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="changePasswordDialog = false">{{t('cancel')}}</el-button>
|
||||
<el-button type="primary" @click="submitForm(formRef)">{{t('save')}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<user-info-edit ref="userInfoEditRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { setUserInfo } from '@/app/api/personal'
|
||||
import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import userInfoEdit from '@/app/components/user-info-edit/index.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const clickEvent = (command: string) => {
|
||||
switch (command) {
|
||||
case 'logout':
|
||||
userStore.logout()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const logout = () => {
|
||||
userStore.logout();
|
||||
}
|
||||
const userInfoEditRef = ref(null)
|
||||
const getUserInfoFn = ()=>{
|
||||
userInfoEditRef.value?.open()
|
||||
}
|
||||
// 修改密码 --- start
|
||||
const changePasswordDialog = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
// 提交信息
|
||||
const saveInfo = reactive({
|
||||
original_password: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
});
|
||||
// 表单验证规则
|
||||
const formRules = reactive<FormRules>({
|
||||
original_password: [
|
||||
{ required: true, message: t("originalPasswordPlaceholder"), trigger: "blur" },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: t("passwordPlaceholder"), trigger: "blur" },
|
||||
],
|
||||
password_copy: [
|
||||
{ required: true, message: t("passwordPlaceholder"), trigger: "blur" },
|
||||
]
|
||||
});
|
||||
const submitForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.validate((valid) => {
|
||||
if (valid) {
|
||||
let msg = "";
|
||||
if (saveInfo.password && !saveInfo.original_password) msg = t('originalPasswordHint');
|
||||
if (saveInfo.password && saveInfo.original_password && !saveInfo.password_copy) msg = t('newPasswordHint');
|
||||
if (saveInfo.password && saveInfo.original_password && saveInfo.password_copy && saveInfo.password != saveInfo.password_copy) msg = t('doubleCipherHint');
|
||||
if (msg) {
|
||||
ElNotification({
|
||||
type: 'error',
|
||||
message: msg,
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
setUserInfo(saveInfo).then((res: any) => {
|
||||
changePasswordDialog.value = false;
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-popper .el-dropdown-menu{
|
||||
width: 150px;
|
||||
}
|
||||
</style>
|
||||
136
admin/src/layout/admin_simplicity/components/tabs.vue
Normal file
136
admin/src/layout/admin_simplicity/components/tabs.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="tab-wrap w-full px-[16px]">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.path" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.path" :key="index">
|
||||
<template #label>
|
||||
<el-dropdown trigger="contextmenu" placement="bottom-start">
|
||||
<span :class="{ 'text-primary': route.path == tab.path }" class="tab-name">{{ tab.title }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.path)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.path)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.path)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, onMounted } from 'vue'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const tabbarStore = useTabbarStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
onMounted(() => {
|
||||
tabbarStore.addTab(route)
|
||||
})
|
||||
|
||||
watch(route, (nval: any) => {
|
||||
tabbarStore.addTab(nval)
|
||||
})
|
||||
|
||||
/**
|
||||
* 添加tab
|
||||
* @param content
|
||||
*/
|
||||
const tabClick = (content: any) => {
|
||||
const tabRoute = tabbarStore.tabs[content.props.name]
|
||||
router.push({ path: tabRoute.path, query: tabRoute.query })
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除tab
|
||||
* @param content
|
||||
*/
|
||||
const removeTab = (content: any) => {
|
||||
if (route.path == content) {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
router.push({ path: tabs[tabs.indexOf(content) - 1] })
|
||||
}
|
||||
tabbarStore.removeTab(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭左侧
|
||||
* @param path
|
||||
*/
|
||||
const closeLeft = (path: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) - 1; i >= 0; i--) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭右侧
|
||||
* @param path
|
||||
*/
|
||||
const closeRight = (path: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) + 1; i < tabs.length; i++) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭其他
|
||||
* @param path
|
||||
*/
|
||||
const closeOther = (path: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
tabs.forEach((key: string) => { key != path && delete tabbarStore.tabs[key] })
|
||||
router.push({ path })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-tabs) {
|
||||
.el-tabs--border-card {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-tabs__header {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.el-tabs__nav-wrap {
|
||||
margin-bottom: 0;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.el-tabs__content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
display: inline-flex !important;
|
||||
padding: 0 20px !important;
|
||||
align-items: center;
|
||||
|
||||
.tab-name:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-tabs__active-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-tabs__item.is-active {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
41
admin/src/layout/admin_simplicity/index.vue
Normal file
41
admin/src/layout/admin_simplicity/index.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div class="flex w-full h-screen">
|
||||
<!-- 左侧边栏 -->
|
||||
<layout-aside></layout-aside>
|
||||
<!-- 左侧边栏 end -->
|
||||
|
||||
<el-container>
|
||||
<!-- 顶部 -->
|
||||
<el-header>
|
||||
<layout-header></layout-header>
|
||||
</el-header>
|
||||
<!-- 顶部 end -->
|
||||
|
||||
<!-- 主体 -->
|
||||
<el-main class="h-full p-0 bg-page">
|
||||
<el-scrollbar>
|
||||
<div class="p-[15px]">
|
||||
<router-view v-slot="{ Component, route }" v-if="appStore.routeRefreshTag">
|
||||
<keep-alive :include="tabbarStore.tabNames">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
<!-- 主体 end -->
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const tabbarStore = useTabbarStore()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -49,7 +49,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import menuItem from './menu-item.vue'
|
||||
import { img, isUrl } from '@/utils/common'
|
||||
import { img } from '@/utils/common'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-container :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" >
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<el-col :span="10">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 左侧菜单折叠 -->
|
||||
<!-- <div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleMenuCollapse">
|
||||
@ -20,8 +20,30 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="14">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<div class="flex items-center flex-shrink-0 hidden-xs-only">
|
||||
<el-dropdown trigger="hover" :hide-on-click="false" popper-class="site-info-wrap" class="mr-[8px]">
|
||||
<!-- 状态 -->
|
||||
<div class="mx-[8px] bg-[#f6f6f6] border-[1px] border-solid border-[#eee] rounded-[4px] px-[9px] py-[6px] flex items-center">
|
||||
<span class="mr-[6px] text-[12px] !text-[#333]">{{siteInfo.site_name}}</span>
|
||||
<span class="!text-[10px] text-[#f56c6c]" :class="{'!text-[#67c23a]': siteInfo.status == 1, '!text-[#f56c6c]': siteInfo.status == 3}">{{ siteInfo.status_name }}</span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<!-- 站点id -->
|
||||
<div class="text-[14px]">站点编号:{{siteInfo.site_id}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<!-- 到期时间 -->
|
||||
<div v-if="siteInfo.expire_time == 0" class="text-[14px]">到期时间:永久</div>
|
||||
<div v-else class="text-[14px]">到期时间:{{ siteInfo.expire_time }}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<!-- 预览 只有站点时展示-->
|
||||
<i class="iconfont iconicon_huojian1 cursor-pointer px-[8px]" :title="t('visitWap')" @click="toPreview"></i>
|
||||
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
|
||||
@ -65,8 +87,9 @@ import layoutSetting from './layout-setting.vue'
|
||||
import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute,useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
@ -78,6 +101,11 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const userStore = useUserStore()
|
||||
const siteInfo:any = computed(() => {
|
||||
return userStore.siteInfo
|
||||
})
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
@ -154,7 +182,7 @@ const toPreview = () => {
|
||||
const url = router.resolve({
|
||||
path: '/preview/wap',
|
||||
query: {
|
||||
page:'/'
|
||||
page: '/'
|
||||
}
|
||||
})
|
||||
window.open(url.href)
|
||||
@ -182,5 +210,10 @@ const toPreview = () => {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dropdown-menu__item) {
|
||||
&:focus {
|
||||
background-color: transparent !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,6 +18,13 @@
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 标签栏 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.tab') }}</div>
|
||||
<div>
|
||||
<el-switch v-model="tab" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
@ -29,6 +36,7 @@ import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
import storage from "@/utils/storage";
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
@ -47,6 +55,18 @@ const dark = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const tab = computed({
|
||||
get () {
|
||||
return systemStore.tab
|
||||
},
|
||||
set (val) {
|
||||
systemStore.$patch((state) => {
|
||||
state.tab = val
|
||||
storage.set({ key: 'tab', data: val })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get () {
|
||||
return systemStore.theme
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<div>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" :src="userStore.userInfo.head_img ? img(userStore.userInfo.head_img) : ''"/>
|
||||
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
@ -95,10 +96,10 @@ const getUserInfoFn = ()=>{
|
||||
userInfoEditRef.value?.open()
|
||||
}
|
||||
// 修改密码 --- start
|
||||
let changePasswordDialog = ref(false)
|
||||
const changePasswordDialog = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
// 提交信息
|
||||
let saveInfo = reactive({
|
||||
const saveInfo = reactive({
|
||||
original_password: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
@ -139,7 +140,6 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 修改密码 --- end
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="tab-wrap w-full px-[16px]">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.path" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.path" :key="index">
|
||||
<div class="tab-wrap w-full px-[16px]" v-show="systemStore.tab">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.name" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.name" :key="index">
|
||||
<template #label>
|
||||
<el-dropdown trigger="contextmenu" placement="bottom-start">
|
||||
<span :class="{ 'text-primary': route.path == tab.path }" class="tab-name">{{ tab.title }}</span>
|
||||
<span :class="{ 'text-primary': route.name == tab.name }" class="tab-name">{{ tab.title }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.path)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.path)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.path)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.name)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.name)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.name)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@ -22,10 +22,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { watch, onMounted } from 'vue'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const tabbarStore = useTabbarStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@ -43,7 +45,7 @@ watch(route, (nval: any) => {
|
||||
*/
|
||||
const tabClick = (content: any) => {
|
||||
const tabRoute = tabbarStore.tabs[content.props.name]
|
||||
router.push({ path: tabRoute.path, query: tabRoute.query })
|
||||
router.push({ name: tabRoute.name, query: tabRoute.query })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,45 +53,49 @@ const tabClick = (content: any) => {
|
||||
* @param content
|
||||
*/
|
||||
const removeTab = (content: any) => {
|
||||
if (route.path == content) {
|
||||
if (route.name == content) {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
router.push({ path: tabs[tabs.indexOf(content) - 1] })
|
||||
if (tabs.indexOf(content) == 0) {
|
||||
router.push({ name: tabs[1] })
|
||||
} else {
|
||||
router.push({ name: tabs[tabs.indexOf(content) - 1] })
|
||||
}
|
||||
}
|
||||
tabbarStore.removeTab(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭左侧
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeLeft = (path: string) => {
|
||||
const closeLeft = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) - 1; i >= 0; i--) {
|
||||
for (let i = tabs.indexOf(name) - 1; i >= 0; i--) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭右侧
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeRight = (path: string) => {
|
||||
const closeRight = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) + 1; i < tabs.length; i++) {
|
||||
for (let i = tabs.indexOf(name) + 1; i < tabs.length; i++) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭其他
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeOther = (path: string) => {
|
||||
const closeOther = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
tabs.forEach((key: string) => { key != path && delete tabbarStore.tabs[key] })
|
||||
router.push({ path })
|
||||
tabs.forEach((key: string) => { key != name && delete tabbarStore.tabs[key] })
|
||||
router.push({ name })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
</el-header>
|
||||
<!-- 顶部 end -->
|
||||
|
||||
<layout-tab />
|
||||
|
||||
<!-- 主体 -->
|
||||
<el-main class="h-full p-0 bg-page">
|
||||
<el-scrollbar>
|
||||
@ -32,6 +34,7 @@
|
||||
import { computed } from 'vue'
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import layoutTab from './components/tabs.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import menuItem from './menu-item.vue'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-container :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" >
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<el-col :span="10">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 左侧菜单折叠 -->
|
||||
<div class="hidden-sm-and-up navbar-item flex items-center h-full cursor-pointer" @click="toggleMenuCollapse">
|
||||
@ -20,8 +20,30 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="14">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<div class="flex items-center flex-shrink-0 hidden-xs-only">
|
||||
<el-dropdown trigger="hover" :hide-on-click="false" popper-class="site-info-wrap" class="mr-[8px]">
|
||||
<!-- 状态 -->
|
||||
<div class="mx-[8px] bg-[#f6f6f6] border-[1px] border-solid border-[#eee] rounded-[4px] px-[9px] py-[6px] flex items-center">
|
||||
<span class="mr-[6px] text-[12px] !text-[#333]">{{siteInfo.site_name}}</span>
|
||||
<span class="!text-[10px] text-[#f56c6c]" :class="{'!text-[#67c23a]': siteInfo.status == 1, '!text-[#f56c6c]': siteInfo.status == 3}">{{ siteInfo.status_name }}</span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<!-- 站点id -->
|
||||
<div class="text-[14px]">站点编号:{{siteInfo.site_id}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<!-- 到期时间 -->
|
||||
<div v-if="siteInfo.expire_time == 0" class="text-[14px]">到期时间:永久</div>
|
||||
<div v-else class="text-[14px]">到期时间:{{ siteInfo.expire_time }}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<!-- 预览 只有站点时展示-->
|
||||
<i class="iconfont iconicon_huojian1 cursor-pointer px-[8px]" :title="t('visitWap')" @click="toPreview"></i>
|
||||
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
|
||||
@ -65,8 +87,9 @@ import layoutSetting from './layout-setting.vue'
|
||||
import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute,useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
@ -78,6 +101,11 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const userStore = useUserStore()
|
||||
const siteInfo:any = computed(() => {
|
||||
return userStore.siteInfo
|
||||
})
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
@ -182,5 +210,11 @@ const toPreview = () => {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
:deep(.el-dropdown-menu__item) {
|
||||
&:focus {
|
||||
background-color: transparent !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -18,6 +18,13 @@
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 标签栏 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.tab') }}</div>
|
||||
<div>
|
||||
<el-switch v-model="tab" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
@ -29,6 +36,7 @@ import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
import storage from "@/utils/storage";
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
@ -47,6 +55,18 @@ const dark = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const tab = computed({
|
||||
get () {
|
||||
return systemStore.tab
|
||||
},
|
||||
set (val) {
|
||||
systemStore.$patch((state) => {
|
||||
state.tab = val
|
||||
storage.set({ key: 'tab', data: val })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get () {
|
||||
return systemStore.theme
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<div>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" :src="userStore.userInfo.head_img ? img(userStore.userInfo.head_img) : ''"/>
|
||||
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
@ -66,7 +67,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { setUserInfo } from '@/app/api/personal'
|
||||
@ -95,10 +96,10 @@ const getUserInfoFn = ()=>{
|
||||
userInfoEditRef.value?.open()
|
||||
}
|
||||
// 修改密码 --- start
|
||||
let changePasswordDialog = ref(false)
|
||||
const changePasswordDialog = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
// 提交信息
|
||||
let saveInfo = reactive({
|
||||
const saveInfo = reactive({
|
||||
original_password: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
@ -139,7 +140,6 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 修改密码 --- end
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="tab-wrap w-full px-[16px]">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.path" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.path" :key="index">
|
||||
<div class="tab-wrap w-full px-[16px]" v-show="systemStore.tab">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.name" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.name" :key="index">
|
||||
<template #label>
|
||||
<el-dropdown trigger="contextmenu" placement="bottom-start">
|
||||
<span :class="{ 'text-primary': route.path == tab.path }" class="tab-name">{{ tab.title }}</span>
|
||||
<span :class="{ 'text-primary': route.name == tab.name }" class="tab-name">{{ tab.title }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.path)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.path)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.path)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.name)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.name)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.name)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@ -22,10 +22,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { watch, onMounted } from 'vue'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const tabbarStore = useTabbarStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@ -43,7 +45,7 @@ watch(route, (nval: any) => {
|
||||
*/
|
||||
const tabClick = (content: any) => {
|
||||
const tabRoute = tabbarStore.tabs[content.props.name]
|
||||
router.push({ path: tabRoute.path, query: tabRoute.query })
|
||||
router.push({ name: tabRoute.name, query: tabRoute.query })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,45 +53,49 @@ const tabClick = (content: any) => {
|
||||
* @param content
|
||||
*/
|
||||
const removeTab = (content: any) => {
|
||||
if (route.path == content) {
|
||||
if (route.name == content) {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
router.push({ path: tabs[tabs.indexOf(content) - 1] })
|
||||
if (tabs.indexOf(content) == 0) {
|
||||
router.push({ name: tabs[1] })
|
||||
} else {
|
||||
router.push({ name: tabs[tabs.indexOf(content) - 1] })
|
||||
}
|
||||
}
|
||||
tabbarStore.removeTab(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭左侧
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeLeft = (path: string) => {
|
||||
const closeLeft = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) - 1; i >= 0; i--) {
|
||||
for (let i = tabs.indexOf(name) - 1; i >= 0; i--) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭右侧
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeRight = (path: string) => {
|
||||
const closeRight = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) + 1; i < tabs.length; i++) {
|
||||
for (let i = tabs.indexOf(name) + 1; i < tabs.length; i++) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭其他
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeOther = (path: string) => {
|
||||
const closeOther = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
tabs.forEach((key: string) => { key != path && delete tabbarStore.tabs[key] })
|
||||
router.push({ path })
|
||||
tabs.forEach((key: string) => { key != name && delete tabbarStore.tabs[key] })
|
||||
router.push({ name })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
</el-header>
|
||||
<!-- 顶部 end -->
|
||||
|
||||
<layout-tab />
|
||||
|
||||
<!-- 主体 -->
|
||||
<el-main class="h-full p-0 bg-page">
|
||||
<el-scrollbar>
|
||||
@ -32,6 +34,7 @@
|
||||
import { computed } from 'vue'
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import layoutTab from './components/tabs.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
@ -25,11 +25,11 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRoute } from 'vue-router'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import menuItem from './menu-item.vue'
|
||||
import { img, isUrl } from '@/utils/common'
|
||||
import { img } from '@/utils/common'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
|
||||
const systemStore = useSystemStore()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-container :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" >
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<el-col :span="10">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 左侧菜单折叠 -->
|
||||
<div class="hidden-sm-and-up navbar-item flex items-center h-full cursor-pointer" @click="toggleMenuCollapse">
|
||||
@ -20,8 +20,30 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="14">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<div class="flex items-center flex-shrink-0 hidden-xs-only">
|
||||
<el-dropdown trigger="hover" :hide-on-click="false" popper-class="site-info-wrap" class="mr-[8px]">
|
||||
<!-- 状态 -->
|
||||
<div class="mx-[8px] bg-[#f6f6f6] border-[1px] border-solid border-[#eee] rounded-[4px] px-[9px] py-[6px] flex items-center">
|
||||
<span class="mr-[6px] text-[12px] !text-[#333]">{{siteInfo.site_name}}</span>
|
||||
<span class="!text-[10px] text-[#f56c6c]" :class="{'!text-[#67c23a]': siteInfo.status == 1, '!text-[#f56c6c]': siteInfo.status == 3}">{{ siteInfo.status_name }}</span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<!-- 站点id -->
|
||||
<div class="text-[14px]">站点编号:{{siteInfo.site_id}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<!-- 到期时间 -->
|
||||
<div v-if="siteInfo.expire_time == 0" class="text-[14px]">到期时间:永久</div>
|
||||
<div v-else class="text-[14px]">到期时间:{{ siteInfo.expire_time }}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<!-- 预览 只有站点时展示-->
|
||||
<i class="iconfont iconicon_huojian1 cursor-pointer px-[8px]" :title="t('visitWap')" @click="toPreview"></i>
|
||||
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
|
||||
@ -65,8 +87,9 @@ import layoutSetting from './layout-setting.vue'
|
||||
import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute,useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
@ -78,6 +101,11 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const userStore = useUserStore()
|
||||
const siteInfo:any = computed(() => {
|
||||
return userStore.siteInfo
|
||||
})
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
@ -181,5 +209,10 @@ const toPreview = () => {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dropdown-menu__item) {
|
||||
&:focus {
|
||||
background-color: transparent !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,6 +18,13 @@
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 标签栏 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.tab') }}</div>
|
||||
<div>
|
||||
<el-switch v-model="tab" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
@ -29,6 +36,7 @@ import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
import storage from "@/utils/storage";
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
@ -47,6 +55,18 @@ const dark = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const tab = computed({
|
||||
get () {
|
||||
return systemStore.tab
|
||||
},
|
||||
set (val) {
|
||||
systemStore.$patch((state) => {
|
||||
state.tab = val
|
||||
storage.set({ key: 'tab', data: val })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get () {
|
||||
return systemStore.theme
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<div>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" :src="userStore.userInfo.head_img ? img(userStore.userInfo.head_img) : ''"/>
|
||||
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
@ -66,7 +67,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { setUserInfo } from '@/app/api/personal'
|
||||
@ -95,10 +96,10 @@ const getUserInfoFn = ()=>{
|
||||
userInfoEditRef.value?.open()
|
||||
}
|
||||
// 修改密码 --- start
|
||||
let changePasswordDialog = ref(false)
|
||||
const changePasswordDialog = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
// 提交信息
|
||||
let saveInfo = reactive({
|
||||
const saveInfo = reactive({
|
||||
original_password: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
@ -139,7 +140,6 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 修改密码 --- end
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="tab-wrap w-full px-[16px]">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.path" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.path" :key="index">
|
||||
<div class="tab-wrap w-full px-[16px]" v-show="systemStore.tab">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.name" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.name" :key="index">
|
||||
<template #label>
|
||||
<el-dropdown trigger="contextmenu" placement="bottom-start">
|
||||
<span :class="{ 'text-primary': route.path == tab.path }" class="tab-name">{{ tab.title }}</span>
|
||||
<span :class="{ 'text-primary': route.name == tab.name }" class="tab-name">{{ tab.title }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.path)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.path)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.path)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.name)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.name)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.name)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@ -22,10 +22,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { watch, onMounted } from 'vue'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const tabbarStore = useTabbarStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@ -43,7 +45,7 @@ watch(route, (nval: any) => {
|
||||
*/
|
||||
const tabClick = (content: any) => {
|
||||
const tabRoute = tabbarStore.tabs[content.props.name]
|
||||
router.push({ path: tabRoute.path, query: tabRoute.query })
|
||||
router.push({ name: tabRoute.name, query: tabRoute.query })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,9 +53,13 @@ const tabClick = (content: any) => {
|
||||
* @param content
|
||||
*/
|
||||
const removeTab = (content: any) => {
|
||||
if (route.path == content) {
|
||||
if (route.name == content) {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
router.push({ path: tabs[tabs.indexOf(content) - 1] })
|
||||
if (tabs.indexOf(content) == 0) {
|
||||
router.push({ name: tabs[1] })
|
||||
} else {
|
||||
router.push({ name: tabs[tabs.indexOf(content) - 1] })
|
||||
}
|
||||
}
|
||||
tabbarStore.removeTab(content)
|
||||
}
|
||||
@ -62,34 +68,34 @@ const removeTab = (content: any) => {
|
||||
* 关闭左侧
|
||||
* @param path
|
||||
*/
|
||||
const closeLeft = (path: string) => {
|
||||
const closeLeft = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) - 1; i >= 0; i--) {
|
||||
for (let i = tabs.indexOf(name) - 1; i >= 0; i--) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭右侧
|
||||
* @param path
|
||||
*/
|
||||
const closeRight = (path: string) => {
|
||||
const closeRight = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) + 1; i < tabs.length; i++) {
|
||||
for (let i = tabs.indexOf(name) + 1; i < tabs.length; i++) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭其他
|
||||
* @param path
|
||||
*/
|
||||
const closeOther = (path: string) => {
|
||||
const closeOther = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
tabs.forEach((key: string) => { key != path && delete tabbarStore.tabs[key] })
|
||||
router.push({ path })
|
||||
tabs.forEach((key: string) => { key != name && delete tabbarStore.tabs[key] })
|
||||
router.push({ name })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
</el-header>
|
||||
<!-- 顶部 end -->
|
||||
|
||||
<layout-tab />
|
||||
|
||||
<!-- 主体 -->
|
||||
<el-main class="h-full p-0 bg-page">
|
||||
<el-scrollbar>
|
||||
@ -32,6 +34,7 @@
|
||||
import { computed } from 'vue'
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import layoutTab from './components/tabs.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
@ -7,6 +7,7 @@ import { ref, markRaw, defineAsyncComponent, provide } from 'vue'
|
||||
import { getAppType } from '@/utils/common'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import Storage from '@/utils/storage'
|
||||
|
||||
const sysLayout = import.meta.glob('./*/index.vue')
|
||||
const addonLayout = import.meta.glob('@/addon/**/layout/index.vue')
|
||||
@ -15,7 +16,7 @@ const modules = Object.assign(sysLayout, addonLayout)
|
||||
let siteLayout = 'default'
|
||||
switch (getAppType()) {
|
||||
case 'admin':
|
||||
siteLayout = 'admin'
|
||||
siteLayout = Storage.get('admin_layout') || 'admin'
|
||||
break
|
||||
default:
|
||||
const siteInfo = useUserStore().siteInfo
|
||||
|
||||
@ -61,6 +61,7 @@ import useUserStore from '@/stores/modules/user'
|
||||
import { img, isUrl } from '@/utils/common'
|
||||
import { findFirstValidRoute } from '@/router/routers'
|
||||
import menuItem from './menu-item.vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -141,11 +142,11 @@ watch(route, () => {
|
||||
}, { immediate: true })
|
||||
|
||||
// 让二级菜单默认展开
|
||||
let menuOption = ref([])
|
||||
const menuOption = ref([])
|
||||
watch(twoMenuData.value, () => {
|
||||
menuOption.value = [];
|
||||
if(twoMenuData.value && Object.values(twoMenuData.value).length){
|
||||
let data = JSON.parse(JSON.stringify(twoMenuData.value));
|
||||
let data = cloneDeep(twoMenuData.value);
|
||||
for(let key in data){
|
||||
menuOption.value.push(data[key].name);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-container :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" >
|
||||
<el-row class="w-100 h-full w-full">
|
||||
<el-col :span="12">
|
||||
<el-col :span="10">
|
||||
<div class="left-panel h-full flex items-center">
|
||||
<!-- 左侧菜单折叠 -->
|
||||
<!-- <div class="navbar-item flex items-center h-full cursor-pointer" @click="toggleMenuCollapse">
|
||||
@ -20,8 +20,30 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-col :span="14">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<div class="flex items-center flex-shrink-0 hidden-xs-only">
|
||||
<el-dropdown trigger="hover" :hide-on-click="false" popper-class="site-info-wrap" class="mr-[8px]">
|
||||
<!-- 状态 -->
|
||||
<div class="mx-[8px] bg-[#f6f6f6] border-[1px] border-solid border-[#eee] rounded-[4px] px-[9px] py-[6px] flex items-center">
|
||||
<span class="mr-[6px] text-[12px] !text-[#333]">{{siteInfo.site_name}}</span>
|
||||
<span class="!text-[10px] text-[#f56c6c]" :class="{'!text-[#67c23a]': siteInfo.status == 1, '!text-[#f56c6c]': siteInfo.status == 3}">{{ siteInfo.status_name }}</span>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<!-- 站点id -->
|
||||
<div class="text-[14px]">站点编号:{{siteInfo.site_id}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<!-- 到期时间 -->
|
||||
<div v-if="siteInfo.expire_time == 0" class="text-[14px]">到期时间:永久</div>
|
||||
<div v-else class="text-[14px]">到期时间:{{ siteInfo.expire_time }}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<!-- 预览 只有站点时展示-->
|
||||
<i class="iconfont iconicon_huojian1 cursor-pointer px-[8px]" :title="t('visitWap')" @click="toPreview"></i>
|
||||
<i class="iconfont iconlingdang-xianxing cursor-pointer px-[8px]" :title="t('newInfo')" v-if="appType == 'site'"></i>
|
||||
@ -65,8 +87,9 @@ import layoutSetting from './layout-setting.vue'
|
||||
import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute,useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
@ -78,6 +101,11 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const userStore = useUserStore()
|
||||
const siteInfo:any = computed(() => {
|
||||
return userStore.siteInfo
|
||||
})
|
||||
|
||||
const dark = computed(() => {
|
||||
return systemStore.dark
|
||||
})
|
||||
@ -181,5 +209,10 @@ const toPreview = () => {
|
||||
background-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-dropdown-menu__item) {
|
||||
&:focus {
|
||||
background-color: transparent !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -18,6 +18,13 @@
|
||||
<el-color-picker v-model="theme" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 标签栏 -->
|
||||
<div class="setting-item flex items-center justify-between mb-[10px]">
|
||||
<div class="title text-base text-tx-secondary">{{ t('layout.tab') }}</div>
|
||||
<div>
|
||||
<el-switch v-model="tab" :active-value="true" :inactive-value="false" />
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-drawer>
|
||||
</div>
|
||||
@ -29,6 +36,7 @@ import useSystemStore from '@/stores/modules/system'
|
||||
import { useDark, useToggle } from '@vueuse/core'
|
||||
import { setThemeColor } from '@/utils/common'
|
||||
import { t } from '@/lang'
|
||||
import storage from "@/utils/storage";
|
||||
|
||||
const drawer = ref(false)
|
||||
const systemStore = useSystemStore()
|
||||
@ -47,6 +55,18 @@ const dark = computed({
|
||||
}
|
||||
})
|
||||
|
||||
const tab = computed({
|
||||
get () {
|
||||
return systemStore.tab
|
||||
},
|
||||
set (val) {
|
||||
systemStore.$patch((state) => {
|
||||
state.tab = val
|
||||
storage.set({ key: 'tab', data: val })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const theme = computed({
|
||||
get () {
|
||||
return systemStore.theme
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
<div>
|
||||
<el-dropdown @command="clickEvent" :tabindex="1">
|
||||
<div class="userinfo flex h-full items-center">
|
||||
<el-avatar :size="25" :icon="UserFilled" :src="userStore.userInfo.head_img ? img(userStore.userInfo.head_img) : ''"/>
|
||||
<el-avatar v-if="userStore.userInfo.head_img" :size="25" :icon="UserFilled" :src="img(userStore.userInfo.head_img)"/>
|
||||
<img v-else src="@/app/assets/images/member_head.png" class="w-[25px] rounded-full" />
|
||||
<div class="user-name pl-[8px]">{{ userStore.userInfo.username }}</div>
|
||||
<icon name="element ArrowDown" class="ml-[5px]" />
|
||||
</div>
|
||||
@ -66,7 +67,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { UserFilled } from '@element-plus/icons-vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { FormInstance, FormRules, ElNotification } from 'element-plus'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { setUserInfo } from '@/app/api/personal'
|
||||
@ -95,10 +96,10 @@ const getUserInfoFn = ()=>{
|
||||
userInfoEditRef.value?.open()
|
||||
}
|
||||
// 修改密码 --- start
|
||||
let changePasswordDialog = ref(false)
|
||||
const changePasswordDialog = ref(false)
|
||||
const formRef = ref<FormInstance>();
|
||||
// 提交信息
|
||||
let saveInfo = reactive({
|
||||
const saveInfo = reactive({
|
||||
original_password: '',
|
||||
password: '',
|
||||
password_copy: ''
|
||||
@ -139,7 +140,6 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 修改密码 --- end
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="tab-wrap w-full px-[16px]">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.path" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.path" :key="index">
|
||||
<div class="tab-wrap w-full px-[16px]" v-show="systemStore.tab">
|
||||
<el-tabs :closable="tabbarStore.tabLength > 1" :model-value="route.name" @tab-click="tabClick" @tab-remove="removeTab">
|
||||
<el-tab-pane v-for="(tab, key, index) in tabbarStore.tabs" :name="tab.name" :key="index">
|
||||
<template #label>
|
||||
<el-dropdown trigger="contextmenu" placement="bottom-start">
|
||||
<span :class="{ 'text-primary': route.path == tab.path }" class="tab-name">{{ tab.title }}</span>
|
||||
<span :class="{ 'text-primary': route.name == tab.name }" class="tab-name">{{ tab.title }}</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.path)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.path)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.path)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Back" :disabled="index == 0" @click="closeLeft(tab.name)">{{t('tabs.closeLeft') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Right" :disabled="index == (tabbarStore.tabLength - 1)" @click="closeRight(tab.name)">{{t('tabs.closeRight') }}</el-dropdown-item>
|
||||
<el-dropdown-item icon="Close" :disabled="tabbarStore.tabLength == 1" @click="closeOther(tab.name)">{{t('tabs.closeOther') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@ -22,10 +22,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { watch, onMounted } from 'vue'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const tabbarStore = useTabbarStore()
|
||||
const systemStore = useSystemStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@ -43,7 +45,7 @@ watch(route, (nval: any) => {
|
||||
*/
|
||||
const tabClick = (content: any) => {
|
||||
const tabRoute = tabbarStore.tabs[content.props.name]
|
||||
router.push({ path: tabRoute.path, query: tabRoute.query })
|
||||
router.push({ name: tabRoute.name, query: tabRoute.query })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,45 +53,49 @@ const tabClick = (content: any) => {
|
||||
* @param content
|
||||
*/
|
||||
const removeTab = (content: any) => {
|
||||
if (route.path == content) {
|
||||
if (route.name == content) {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
router.push({ path: tabs[tabs.indexOf(content) - 1] })
|
||||
if (tabs.indexOf(content) == 0) {
|
||||
router.push({ name: tabs[1] })
|
||||
} else {
|
||||
router.push({ name: tabs[tabs.indexOf(content) - 1] })
|
||||
}
|
||||
}
|
||||
tabbarStore.removeTab(content)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭左侧
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeLeft = (path: string) => {
|
||||
const closeLeft = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) - 1; i >= 0; i--) {
|
||||
for (let i = tabs.indexOf(name) - 1; i >= 0; i--) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭右侧
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeRight = (path: string) => {
|
||||
const closeRight = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
for (let i = tabs.indexOf(path) + 1; i < tabs.length; i++) {
|
||||
for (let i = tabs.indexOf(name) + 1; i < tabs.length; i++) {
|
||||
delete tabbarStore.tabs[tabs[i]]
|
||||
}
|
||||
router.push({ path })
|
||||
router.push({ name })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭其他
|
||||
* @param path
|
||||
* @param name
|
||||
*/
|
||||
const closeOther = (path: string) => {
|
||||
const closeOther = (name: string) => {
|
||||
const tabs = Object.keys(tabbarStore.tabs)
|
||||
tabs.forEach((key: string) => { key != path && delete tabbarStore.tabs[key] })
|
||||
router.push({ path })
|
||||
tabs.forEach((key: string) => { key != name && delete tabbarStore.tabs[key] })
|
||||
router.push({ name })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
</el-header>
|
||||
<!-- 顶部 end -->
|
||||
|
||||
<layout-tab />
|
||||
|
||||
<!-- 主体 -->
|
||||
<el-main class="h-full p-0 bg-page">
|
||||
<el-scrollbar>
|
||||
@ -32,6 +34,7 @@
|
||||
import { computed } from 'vue'
|
||||
import layoutHeader from './components/header/index.vue'
|
||||
import layoutAside from './components/aside/index.vue'
|
||||
import layoutTab from './components/tabs.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
|
||||
@ -13,7 +13,8 @@ interface System {
|
||||
sidebarStyle: string,
|
||||
currHeadMenuName: any,
|
||||
website: Object,
|
||||
layoutConfig: Object
|
||||
layoutConfig: Object,
|
||||
tab: Boolean
|
||||
}
|
||||
|
||||
const theme = storage.get('theme') ?? {}
|
||||
@ -30,7 +31,8 @@ const useSystemStore = defineStore('system', {
|
||||
sidebarStyle: theme.sidebarStyle ?? 'threeType',
|
||||
currHeadMenuName: '',
|
||||
website: {},
|
||||
layoutConfig: {}
|
||||
layoutConfig: {},
|
||||
tab: storage.get('tab') ?? false
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import type { RouteLocationNormalizedLoaded, RouteRecordName } from 'vue-router'
|
||||
|
||||
interface Tabbar {
|
||||
curr: string,
|
||||
tabs: {
|
||||
[key: string]: any
|
||||
[key: RouteRecordName]: any
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,11 +18,11 @@ const useTabbarStore = defineStore('tabbar', {
|
||||
actions: {
|
||||
addTab(roter: RouteLocationNormalizedLoaded) {
|
||||
if (roter.meta && roter.meta.type != 1) return
|
||||
if (this.tabs[roter.path]) {
|
||||
this.tabs[roter.path].query = roter.query || {}
|
||||
if (this.tabs[roter.name]) {
|
||||
this.tabs[roter.name].query = roter.query || {}
|
||||
return
|
||||
}
|
||||
this.tabs[roter.path] = {
|
||||
this.tabs[roter.name] = {
|
||||
path: roter.path,
|
||||
title: roter.meta ? roter.meta.title : '',
|
||||
name: roter.name,
|
||||
@ -48,4 +48,4 @@ const useTabbarStore = defineStore('tabbar', {
|
||||
}
|
||||
})
|
||||
|
||||
export default useTabbarStore
|
||||
export default useTabbarStore
|
||||
|
||||
@ -1,2 +1 @@
|
||||
@import "addon/o2o/iconfont.css";
|
||||
@import "addon/tourism/iconfont.css";
|
||||
// addon iconfont
|
||||
@ -1,38 +0,0 @@
|
||||
@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";
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "tourism"; /* Project id 4137250 */
|
||||
src: url('//at.alicdn.com/t/c/font_4137250_st1ha9l0k1e.woff2?t=1687685028672') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4137250_st1ha9l0k1e.woff?t=1687685028672') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4137250_st1ha9l0k1e.ttf?t=1687685028672') format('truetype');
|
||||
}
|
||||
|
||||
.tourism {
|
||||
font-family: "tourism" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.tourism-icon-feiji:before {
|
||||
content: "\e600";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou:before {
|
||||
content: "\e6a9";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyouchanpin:before {
|
||||
content: "\e63b";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou1:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou2:before {
|
||||
content: "\e601";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou3:before {
|
||||
content: "\e60c";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyoubaochedingdan:before {
|
||||
content: "\e612";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou4:before {
|
||||
content: "\e653";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou5:before {
|
||||
content: "\e610";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyouguanguang:before {
|
||||
content: "\e87e";
|
||||
}
|
||||
|
||||
.tourism-icon-lvyou6:before {
|
||||
content: "\e642";
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
{
|
||||
"id": "4137250",
|
||||
"name": "旅游业",
|
||||
"font_family": "tourism",
|
||||
"css_prefix_text": "tourism-icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "1443",
|
||||
"name": "飞机",
|
||||
"font_class": "feiji",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
},
|
||||
{
|
||||
"icon_id": "446824",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou",
|
||||
"unicode": "e6a9",
|
||||
"unicode_decimal": 59049
|
||||
},
|
||||
{
|
||||
"icon_id": "1167173",
|
||||
"name": "旅游产品",
|
||||
"font_class": "lvyouchanpin",
|
||||
"unicode": "e63b",
|
||||
"unicode_decimal": 58939
|
||||
},
|
||||
{
|
||||
"icon_id": "1354920",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou1",
|
||||
"unicode": "e623",
|
||||
"unicode_decimal": 58915
|
||||
},
|
||||
{
|
||||
"icon_id": "1505555",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou2",
|
||||
"unicode": "e601",
|
||||
"unicode_decimal": 58881
|
||||
},
|
||||
{
|
||||
"icon_id": "2121726",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou3",
|
||||
"unicode": "e60c",
|
||||
"unicode_decimal": 58892
|
||||
},
|
||||
{
|
||||
"icon_id": "2357494",
|
||||
"name": "旅游包车订单",
|
||||
"font_class": "lvyoubaochedingdan",
|
||||
"unicode": "e612",
|
||||
"unicode_decimal": 58898
|
||||
},
|
||||
{
|
||||
"icon_id": "3944019",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou4",
|
||||
"unicode": "e653",
|
||||
"unicode_decimal": 58963
|
||||
},
|
||||
{
|
||||
"icon_id": "4838220",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou5",
|
||||
"unicode": "e610",
|
||||
"unicode_decimal": 58896
|
||||
},
|
||||
{
|
||||
"icon_id": "7444178",
|
||||
"name": "旅游观光",
|
||||
"font_class": "lvyouguanguang",
|
||||
"unicode": "e87e",
|
||||
"unicode_decimal": 59518
|
||||
},
|
||||
{
|
||||
"icon_id": "9748082",
|
||||
"name": "旅游",
|
||||
"font_class": "lvyou6",
|
||||
"unicode": "e642",
|
||||
"unicode_decimal": 58946
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3883393 */
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_dha1lk9gv4.woff2?t=1720083366330') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_dha1lk9gv4.woff?t=1720083366330') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_dha1lk9gv4.ttf?t=1720083366330') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_xso0134odj.woff2?t=1732777083024') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_xso0134odj.woff?t=1732777083024') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_xso0134odj.ttf?t=1732777083024') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,106 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconshujutongji:before {
|
||||
content: "\e835";
|
||||
}
|
||||
|
||||
.iconshangpinguanli1:before {
|
||||
content: "\e837";
|
||||
}
|
||||
|
||||
.icondingdanguanli:before {
|
||||
content: "\e838";
|
||||
}
|
||||
|
||||
.icona-tupianzhanbopc302:before {
|
||||
content: "\e83c";
|
||||
}
|
||||
|
||||
.icona-jingxuantuijianpc302:before {
|
||||
content: "\e83d";
|
||||
}
|
||||
|
||||
.icona-jingxuantuijianpc30-12:before {
|
||||
content: "\e83e";
|
||||
}
|
||||
|
||||
.icona-baokuantuijianpc30:before {
|
||||
content: "\e836";
|
||||
}
|
||||
|
||||
.icona-shangpintuijianpc30:before {
|
||||
content: "\e839";
|
||||
}
|
||||
|
||||
.icona-paihangbangpc30:before {
|
||||
content: "\e83a";
|
||||
}
|
||||
|
||||
.icona-xinrenzhuanxiangpc30:before {
|
||||
content: "\e83b";
|
||||
}
|
||||
|
||||
.icona-lipinkatupianpc30:before {
|
||||
content: "\e82c";
|
||||
}
|
||||
|
||||
.icona-lipinkayouxiaoqipc30:before {
|
||||
content: "\e82d";
|
||||
}
|
||||
|
||||
.icona-lipinkazhufuyupc30:before {
|
||||
content: "\e833";
|
||||
}
|
||||
|
||||
.icona-lipinkamingchengpc30:before {
|
||||
content: "\e834";
|
||||
}
|
||||
|
||||
.iconshezhiV6xx:before {
|
||||
content: "\e82e";
|
||||
}
|
||||
|
||||
.iconshezhiV6xx-2:before {
|
||||
content: "\e82f";
|
||||
}
|
||||
|
||||
.iconshezhiV6xx-1:before {
|
||||
content: "\e830";
|
||||
}
|
||||
|
||||
.iconshezhiV6xx1:before {
|
||||
content: "\e831";
|
||||
}
|
||||
|
||||
.iconshezhi-1V6xx:before {
|
||||
content: "\e832";
|
||||
}
|
||||
|
||||
.icondiduiqi1:before {
|
||||
content: "\e7b0";
|
||||
}
|
||||
|
||||
.icondingduiqi1:before {
|
||||
content: "\e827";
|
||||
}
|
||||
|
||||
.iconchuizhijuzhong1:before {
|
||||
content: "\e828";
|
||||
}
|
||||
|
||||
.iconzuoduiqi1:before {
|
||||
content: "\e829";
|
||||
}
|
||||
|
||||
.iconshuipingjuzhong1:before {
|
||||
content: "\e82a";
|
||||
}
|
||||
|
||||
.iconyouduiqi1:before {
|
||||
content: "\e82b";
|
||||
}
|
||||
|
||||
.iconxiaochengxu2:before {
|
||||
content: "\e63d";
|
||||
}
|
||||
@ -1113,10 +1213,6 @@
|
||||
content: "\e628";
|
||||
}
|
||||
|
||||
.icongouwuche1:before {
|
||||
content: "\e680";
|
||||
}
|
||||
|
||||
.icongonggao:before {
|
||||
content: "\e629";
|
||||
}
|
||||
@ -2198,7 +2294,7 @@
|
||||
}
|
||||
|
||||
.iconwenhao:before {
|
||||
content: "\e890";
|
||||
content: "\f1e3";
|
||||
}
|
||||
|
||||
.iconmofang-liangzuoliangyou:before {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -14,13 +14,6 @@
|
||||
<name>niucloud-addon</name>
|
||||
<description>niucloud 应用管理模块</description>
|
||||
<modules>
|
||||
<module>tour</module>
|
||||
<module>sms-email</module>
|
||||
<module>recharge</module>
|
||||
<module>cms</module>
|
||||
<module>shop</module>
|
||||
<module>shop_giftcard</module>
|
||||
<module>shop_fenxiao</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user