mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-03-12 10:55:30 +00:00
0.2.0
This commit is contained in:
parent
e77e3bd75c
commit
5955273e1c
@ -22,6 +22,7 @@
|
||||
"rules": {
|
||||
"no-tabs":"off",
|
||||
"indent": [1, 4, { "SwitchCase": 1 }],
|
||||
"eqeqeq":"off"
|
||||
"eqeqeq":"off",
|
||||
"vue/multi-word-component-names": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ const solve = () => {
|
||||
const fc = fs.readFileSync(fn, 'utf-8')
|
||||
let text = new String(fc)
|
||||
text = text.replaceAll('./assets/', '/admin/assets/')
|
||||
text = text.replace('./niucloud.ico', '/admin/niucloud.ico')
|
||||
fs.writeFileSync(fn, text, 'utf8')
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
admin/src/app/assets/images/diy/notice/style_2.png
Normal file
BIN
admin/src/app/assets/images/diy/notice/style_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
@ -18,7 +18,7 @@
|
||||
<el-scrollbar class="flex-1 h-0 mt-[20px]">
|
||||
<div class="mt-[20px]" v-for="(item, index) in upgradeContent.version_list" :key="index">
|
||||
<div class="font-bold text-lg">{{ item.version_no }}</div>
|
||||
<div class="mt-[5px]">{{ item.release_time }}</div>
|
||||
<div class="mt-[5px]" v-if="item.release_time">{{ item.release_time }}</div>
|
||||
<div class="mt-[10px] p-[10px] rounded bg-[#f4f4f5] whitespace-pre" v-if="item.upgrade_log" v-html="item.upgrade_log"></div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
|
||||
@ -14,11 +14,18 @@
|
||||
"pageNamePlaceholder": "请输入页面名称",
|
||||
"pageBgColor": "页面颜色",
|
||||
"bgUrl": "背景图片",
|
||||
"bgHeightScale": "高度比例",
|
||||
"bgHeightScaleTip": "为0时背景高度自适应展示",
|
||||
"marginSet": "边距设置",
|
||||
"componentStyleTitle": "组件样式",
|
||||
"bottomBgColor": "底部背景",
|
||||
"bottomBgTips": "底部背景包含边距和圆角",
|
||||
"componentBgColor": "组件背景",
|
||||
"componentBgColor": "组件背景色",
|
||||
"componentBgUrl": "组件背景图",
|
||||
"componentBgAlpha": "透明度",
|
||||
"bgGradientAngle": "渐变角度",
|
||||
"topToBottom": "从上到下",
|
||||
"leftToRight": "从左到右",
|
||||
"marginTop": "上边距",
|
||||
"marginBottom": "下边距",
|
||||
"marginBoth": "左右边距",
|
||||
@ -41,6 +48,7 @@
|
||||
"notCopy": "无法复制",
|
||||
"componentCanOnlyAdd": "组件只能添加",
|
||||
"piece": "个",
|
||||
"componentNotMoved": "该组件禁止移动",
|
||||
"resetComponentTips": "确认要重置组件默认数据吗?",
|
||||
"image": "图片上传",
|
||||
"imageUpload": "图片上传",
|
||||
@ -72,9 +80,10 @@
|
||||
"graphicNavStyleSingleSlide": "单行滑动",
|
||||
"graphicNavStylePageSlide": "分页滑动",
|
||||
"graphicNavRowCount": "每行数量",
|
||||
"graphicNavPageCount": "每行数量",
|
||||
"graphicNavPageCount": "显示方式",
|
||||
"graphicNavSetLabel": "导航设置",
|
||||
"line": "行",
|
||||
"singleLine": "单行",
|
||||
"multiline": "多行",
|
||||
"graphicNavTips": "建议上传尺寸相同的图片,推荐尺寸60*60",
|
||||
"graphicNavTitle": "标题",
|
||||
"graphicNavTitlePlaceholder": "请输入标题",
|
||||
@ -87,6 +96,7 @@
|
||||
"styleSet": "风格设置",
|
||||
"titleStyle": "标题样式",
|
||||
"selectStyle": "风格选择",
|
||||
"styleLabel": "风格",
|
||||
"titleContent": "标题内容",
|
||||
"title": "标题名称",
|
||||
"titlePlaceholder": "请输入标题",
|
||||
@ -99,7 +109,8 @@
|
||||
"fontWeightBold": "加粗",
|
||||
"fontWeightNormal": "常规",
|
||||
"textColor": "文字颜色",
|
||||
"subTextColor": "副标题颜色",
|
||||
"subTitleStyle": "副标题样式",
|
||||
"subTextBgColor": "背景色",
|
||||
"subTitleContent": "标题内容",
|
||||
"subTitle": "副标题",
|
||||
"subTitlePlaceholder": "请输入副标题",
|
||||
@ -137,5 +148,93 @@
|
||||
"selectCategory":"选择分类",
|
||||
"categoryName": "分类名称",
|
||||
"categoryImage": "分类图片",
|
||||
"selectSource": "选择数据源"
|
||||
"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": "置顶背景",
|
||||
"carouselSearchSet": "搜索设置",
|
||||
"carouselSearchText": "搜索内容",
|
||||
"carouselSearchHotWordSet": "搜索热词",
|
||||
"carouselSearchHotWordInterval": "显示时间 / 秒",
|
||||
"carouselSearchHotWordText": "内容",
|
||||
"carouselSearchHotWordTextPlaceholder": "请输入热词",
|
||||
"carouselSearchAddHotWordItem": "添加一个热词",
|
||||
"carouselSearchLogoTips": "建议尺寸,70px * 30px",
|
||||
"carouselSearchPlaceholder": "请输入搜索内容",
|
||||
"carouselSearchTabSet": "选项卡设置",
|
||||
"carouselSearchTabControl": "展示开关",
|
||||
"carouselSearchTabCategoryText": "分类名称",
|
||||
"carouselSearchTabCategoryTextPlaceholder": "请输入分类名称",
|
||||
"carouselSearchAddTabItem": "添加一个选项卡",
|
||||
"selectSourcesDiyPage": "选择微页面",
|
||||
"selectDiyPagePlaceholder": "请选择微页面",
|
||||
"diyPageTitle": "页面名称",
|
||||
"diyPageTypeName": "页面类型",
|
||||
"diyPageForAddon": "所属应用",
|
||||
"carouselSearchSwiperSet": "轮播图设置",
|
||||
"carouselSearchSwiperControl": "展示开关",
|
||||
"carouselSearchSwiperInterval": "切换间隔 / 秒",
|
||||
"carouselSearchSwiperTips": "建议上传尺寸相同的图片,推荐尺寸750*350;鼠标拖拽可调整图片顺序",
|
||||
"carouselSearchTabStyle": "选项卡样式",
|
||||
"noColor": "常规颜色",
|
||||
"selectColor": "选中颜色",
|
||||
"fixedNoColor": "下滑常规颜色",
|
||||
"fixedSelectColor": "下滑选中颜色",
|
||||
"carouselSearchSwiperIndicatorSet": "指示器设置",
|
||||
"carouselSearchSwiperIndicatorStyle": "指示器样式",
|
||||
"carouselSearchSwiperStyle": "轮播样式",
|
||||
"carouselSearchSwiperIndicatorStyle1": "样式1",
|
||||
"carouselSearchSwiperIndicatorStyle2": "样式2",
|
||||
"carouselSearchSwiperIndicatorAlign": "显示位置",
|
||||
"alignLeft": "居左",
|
||||
"alignCenter": "居中",
|
||||
"alignRight": "居右",
|
||||
"horzLineStyle": "线条风格",
|
||||
"horzLineStyleSolid": "实线",
|
||||
"horzLineStyleDashed": "虚线",
|
||||
"horzLineBorderColor": "线条颜色",
|
||||
"horzLineBorderWidth": "线条宽度",
|
||||
"floatBtnBtton": "按钮位置",
|
||||
"floatBtnOffset": "上下偏移",
|
||||
"floatBtnImageSet": "图片设置",
|
||||
"floatBtnImageSize": "图片大小",
|
||||
"floatBtnAroundRadius": "图片圆角",
|
||||
"floatBtnImageSuggest": "建议上传正方形图片"
|
||||
}
|
||||
@ -28,5 +28,8 @@
|
||||
"visitTimePlaceholder":"请输入访问时间",
|
||||
"createTimePlaceholder":"请输入消息时间",
|
||||
"buyerNotice": "会员消息",
|
||||
"messageKey":"消息模版",
|
||||
"messageInfo":"发送记录详情",
|
||||
"smsType":"短信类型",
|
||||
"sellerNotice":"平台消息"
|
||||
}
|
||||
@ -9,6 +9,7 @@
|
||||
"siteLogo": "店铺LOGO",
|
||||
"expireTime":"到期时间",
|
||||
"groupName": "店铺套餐",
|
||||
"statusExpire":"已到期",
|
||||
"siteNamePlaceholder":"请输入站点名称",
|
||||
"groupIdPlaceholder":"请输入套餐",
|
||||
"addSite":"添加站点",
|
||||
|
||||
@ -15,12 +15,12 @@
|
||||
<h3 class="panel-title !text-sm">{{ t('wechatInfo') }}</h3>
|
||||
|
||||
<el-form-item :label="t('wechatName')" prop="wechat_name">
|
||||
<el-input v-model="formData.wechat_name" :placeholder="t('wechatNamePlaceholder')" class="input-width"
|
||||
<el-input v-model.trim="formData.wechat_name" :placeholder="t('wechatNamePlaceholder')" class="input-width"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('wechatOriginal')" prop="wechat_original">
|
||||
<el-input v-model="formData.wechat_original" :placeholder="t('wechatOriginalPlaceholder')"
|
||||
<el-input v-model.trim="formData.wechat_original" :placeholder="t('wechatOriginalPlaceholder')"
|
||||
class="input-width" clearable />
|
||||
</el-form-item>
|
||||
|
||||
@ -35,13 +35,13 @@
|
||||
<h3 class="panel-title !text-sm">{{ t('wechatDevelopInfo') }}</h3>
|
||||
|
||||
<el-form-item :label="t('wechatAppid')" prop="app_id">
|
||||
<el-input v-model="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width"
|
||||
<el-input v-model.trim="formData.app_id" :placeholder="t('appidPlaceholder')" class="input-width"
|
||||
clearable />
|
||||
<div class="form-tip">{{ t('wechatAppidTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('wechatAppsecret')" prop="app_secret">
|
||||
<el-input v-model="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width"
|
||||
<el-input v-model.trim="formData.app_secret" :placeholder="t('appSecretPlaceholder')" class="input-width"
|
||||
clearable />
|
||||
<div class="form-tip">{{ t('wechatAppsecretTips') }}</div>
|
||||
</el-form-item>
|
||||
@ -61,13 +61,13 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Token" prop="token">
|
||||
<el-input v-model="formData.token" :placeholder="t('tokenPlaceholder')" class="input-width"
|
||||
<el-input v-model.trim="formData.token" :placeholder="t('tokenPlaceholder')" class="input-width"
|
||||
maxlength="32" show-word-limit clearable />
|
||||
<div class="form-tip">{{ t('tokenTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="EncodingAESKey" prop="encoding_aes_key">
|
||||
<el-input v-model="formData.encoding_aes_key" :placeholder="t('encodingAesKeyPlaceholder')"
|
||||
<el-input v-model.trim="formData.encoding_aes_key" :placeholder="t('encodingAesKeyPlaceholder')"
|
||||
class="input-width" maxlength="43" show-word-limit clearable />
|
||||
<div class="form-tip">{{ t('encodingAESKeyTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
383
admin/src/app/views/diy/components/edit-active-cube.vue
Normal file
383
admin/src/app/views/diy/components/edit-active-cube.vue
Normal file
@ -0,0 +1,383 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('selectStyle')" class="flex">
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showTitleStyle">{{ diyStore.editComponent.titleStyle.title }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('title')">
|
||||
<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>
|
||||
|
||||
<el-dialog v-model="showTitleDialog" :title="t('selectStyle')" width="500px">
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="(item,index) in titleStyleList" :key="index">
|
||||
<div :class="{ 'border-primary': selectTitleStyle.value == item.value }" @click="changeTitleStyle(item)" class="flex items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]">
|
||||
<img :src="img(item.url)" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showTitleDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmTitleStyle">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('activeCubeBlockContent') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
|
||||
<el-form-item :label="t('selectStyle')" class="flex">
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showBlockStyle">{{ diyStore.editComponent.blockStyle.title }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
</el-form-item>
|
||||
|
||||
<el-dialog v-model="showListDialog" :title="t('selectStyle')" width="600px">
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="(item,index) in blockStyleList" :key="index">
|
||||
<div :class="{ 'border-primary': selectBlockStyle.value == item.value }" @click="changeBlockStyle(item)" class="flex items-center justify-center overflow-hidden w-[250px] h-[150px] mr-[12px] mb-[12px] cursor-pointer border bg-[#eee]">
|
||||
<img :src="img(item.url)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showListDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmBlockStyle">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
|
||||
|
||||
<div ref="blockBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('activeCubeTitle')">
|
||||
<el-input v-model.trim="item.title.text" :placeholder="t('activeCubeTitlePlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('activeCubeSubTitleTextColor')" v-show="selectBlockStyle.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>
|
||||
|
||||
<div v-show="selectBlockStyle.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>
|
||||
<el-form-item :label="t('activeCubeSubTitleBgColor')">
|
||||
<el-color-picker v-model="item.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</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('activeCubeButton')">
|
||||
<el-input v-model.trim="item.moreTitle.text" :placeholder="t('activeCubeButtonPlaceholder')" clearable maxlength="3" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('activeCubeButtonColor')">
|
||||
<el-color-picker v-model="item.moreTitle.startColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="item.moreTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
|
||||
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addItem">{{ t('activeCubeAddItem') }}</el-button>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.titleColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('subTitleStyle') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.subTitle.textColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('subTextBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.subTitle.startColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.subTitle.endColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('activeCubeBlockStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('activeCubeBlockTextFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.blockStyle.fontWeight">
|
||||
<el-radio :label="'normal'">{{t('fontWeightNormal')}}</el-radio>
|
||||
<el-radio :label="'bold'">{{t('fontWeightBold')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</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, onMounted, nextTick } from 'vue'
|
||||
import Sortable from 'sortablejs'
|
||||
import { range } from 'lodash-es'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
|
||||
if(diyStore.value[index].text == ''){
|
||||
res.code = false
|
||||
res.message = t('activeCubeTitlePlaceholder')
|
||||
return res
|
||||
}
|
||||
|
||||
diyStore.value[index].list.forEach((item: any) => {
|
||||
if (item.imageUrl === '') {
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
if (item.title.text === '') {
|
||||
res.code = false
|
||||
res.message = t('activeCubeTitlePlaceholder')
|
||||
return res
|
||||
}
|
||||
if(['style-1','style-2','style-4'].indexOf(diyStore.value[index].blockStyle.value) != -1){
|
||||
if (item.subTitle.text === '') {
|
||||
res.code = false
|
||||
res.message = t('activeCubeSubTitlePlaceholder')
|
||||
return res
|
||||
}
|
||||
}
|
||||
if(['style-1','style-2'].indexOf(diyStore.value[index].blockStyle.value) != -1){
|
||||
if (item.moreTitle.text === '') {
|
||||
res.code = false
|
||||
res.message = t('activeCubeButtonPlaceholder')
|
||||
return res
|
||||
}
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
diyStore.editComponent.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
// 标题风格样式
|
||||
const showTitleDialog = ref(false)
|
||||
|
||||
const showTitleStyle = () => {
|
||||
showTitleDialog.value = true
|
||||
}
|
||||
|
||||
const titleStyleList = reactive([
|
||||
{
|
||||
url : 'static/resource/images/diy/active_cube/title_style1.png',
|
||||
title:'风格1',
|
||||
value:'style-1'
|
||||
},{
|
||||
url : 'static/resource/images/diy/active_cube/title_style2.png',
|
||||
title:'风格2',
|
||||
value:'style-2'
|
||||
},{
|
||||
url : 'static/resource/images/diy/active_cube/title_style3.png',
|
||||
title:'风格3',
|
||||
value:'style-3'
|
||||
},{
|
||||
url : 'static/resource/images/diy/active_cube/title_style5.png',
|
||||
title:'风格4',
|
||||
value:'style-4'
|
||||
}
|
||||
])
|
||||
|
||||
const selectTitleStyle = reactive({
|
||||
title: diyStore.editComponent.titleStyle.title,
|
||||
value: diyStore.editComponent.titleStyle.value
|
||||
})
|
||||
|
||||
const changeTitleStyle = (item:any) => {
|
||||
selectTitleStyle.title = item.title;
|
||||
selectTitleStyle.value = item.value;
|
||||
}
|
||||
|
||||
const confirmTitleStyle = () => {
|
||||
diyStore.editComponent.titleStyle.title = selectTitleStyle.title;
|
||||
diyStore.editComponent.titleStyle.value = selectTitleStyle.value;
|
||||
showTitleDialog.value = false
|
||||
}
|
||||
|
||||
// 板块风格样式
|
||||
const showListDialog = ref(false)
|
||||
|
||||
const showBlockStyle = () => {
|
||||
showListDialog.value = true
|
||||
}
|
||||
|
||||
const blockStyleList = reactive([
|
||||
{
|
||||
url : 'static/resource/images/diy/active_cube/block_style1.png',
|
||||
title:'风格1',
|
||||
value:'style-1'
|
||||
},
|
||||
{
|
||||
url : 'static/resource/images/diy/active_cube/block_style2.png',
|
||||
title:'风格2',
|
||||
value:'style-2'
|
||||
},
|
||||
{
|
||||
url : 'static/resource/images/diy/active_cube/block_style3.png',
|
||||
title:'风格3',
|
||||
value:'style-3'
|
||||
},
|
||||
{
|
||||
url : 'static/resource/images/diy/active_cube/block_style4.png',
|
||||
title:'风格4',
|
||||
value:'style-4'
|
||||
}
|
||||
])
|
||||
|
||||
const selectBlockStyle = reactive({
|
||||
title: diyStore.editComponent.blockStyle.title,
|
||||
value: diyStore.editComponent.blockStyle.value
|
||||
})
|
||||
|
||||
const changeBlockStyle = (item:any) => {
|
||||
selectBlockStyle.title = item.title;
|
||||
selectBlockStyle.value = item.value;
|
||||
}
|
||||
|
||||
const confirmBlockStyle = () => {
|
||||
diyStore.editComponent.blockStyle.title = selectBlockStyle.title;
|
||||
diyStore.editComponent.blockStyle.value = selectBlockStyle.value;
|
||||
showListDialog.value = false
|
||||
}
|
||||
|
||||
const addItem = () => {
|
||||
diyStore.editComponent.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
title:{
|
||||
title:'标题',
|
||||
textColor: "#000000"
|
||||
},
|
||||
subTitle:{
|
||||
text:'副标题',
|
||||
textColor: "#999999",
|
||||
startColor:'',
|
||||
endColor:''
|
||||
},
|
||||
listFrame: {
|
||||
startColor: "#4AC1FF",
|
||||
endColor: "#1D7CFF"
|
||||
},
|
||||
moreTitle:{
|
||||
text:'去看看',
|
||||
startColor:'#FEA715',
|
||||
endColor:'#FE1E00'
|
||||
},
|
||||
imageUrl: '',
|
||||
link: { name: '' }
|
||||
})
|
||||
}
|
||||
|
||||
const blockBoxRef = ref()
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const sortable = Sortable.create(blockBoxRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
onEnd: event => {
|
||||
const temp = diyStore.editComponent.list[event.oldIndex!]
|
||||
diyStore.editComponent.list.splice(event.oldIndex!, 1)
|
||||
diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
|
||||
sortable.sort(
|
||||
range(diyStore.editComponent.list.length).map(value => {
|
||||
return value.toString()
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
526
admin/src/app/views/diy/components/edit-carousel-search.vue
Normal file
526
admin/src/app/views/diy/components/edit-carousel-search.vue
Normal file
@ -0,0 +1,526 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchShowPosition') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchShowWay')">
|
||||
<el-radio-group v-model="diyStore.editComponent.positionWay">
|
||||
<el-radio label="static">{{ t('carouselSearchShowWayStatic') }}</el-radio>
|
||||
<el-radio label="fixed">{{ t('carouselSearchShowWayFixed') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchFixedBgColor')" v-show="diyStore.editComponent.positionWay == 'fixed'">
|
||||
<el-color-picker v-model="diyStore.editComponent.fixedBgColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchBgGradient')">
|
||||
<el-radio-group v-model="diyStore.editComponent.bgGradient">
|
||||
<el-radio :label="true">{{ t('carouselSearchOpen') }}</el-radio>
|
||||
<el-radio :label="false">{{ t('carouselSearchClose') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<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('logo')">
|
||||
<upload-image v-model="diyStore.editComponent.search.logo" :limit="1" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchText')">
|
||||
<el-input v-model.trim="diyStore.editComponent.search.text" :placeholder="t('carouselSearchPlaceholder')" clearable maxlength="20" show-word-limit />
|
||||
</el-form-item>
|
||||
<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">
|
||||
<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-form-item>
|
||||
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
|
||||
|
||||
<div ref="searchHotWordTabBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.search.hotWord.list" :key="item.id" class="item-wrap p-[10px] relative border border-dashed border-gray-300 mb-[16px]">
|
||||
|
||||
<el-form-item :label="t('carouselSearchHotWordText')" class="!mb-0">
|
||||
<el-input v-model.trim="item.text" :placeholder="t('carouselSearchHotWordTextPlaceholder')" clearable maxlength="4" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" @click="diyStore.editComponent.search.hotWord.list.splice(index,1)">
|
||||
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<el-button v-show="diyStore.editComponent.search.hotWord.list.length < 50" class="w-full" @click="addHotWordItem">{{ t('carouselSearchAddHotWordItem') }}</el-button>
|
||||
</div>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-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>
|
||||
|
||||
<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]">
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
||||
<!-- 选择微页面弹出框 -->
|
||||
<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="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-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 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>
|
||||
|
||||
<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-form>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchTabStyle') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('noColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.tab.noColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('selectColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.tab.selectColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fixedNoColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.tab.fixedNoColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('fixedSelectColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.tab.fixedSelectColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchSwiperStyle')" @change="changeSwiperStyle">
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.swiperStyle">
|
||||
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
|
||||
</el-radio-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-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-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('carouselSearchSwiperIndicatorSet') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('carouselSearchSwiperIndicatorStyle')">
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorStyle">
|
||||
<el-radio label="style-1">{{ t('carouselSearchSwiperIndicatorStyle1') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('carouselSearchSwiperIndicatorStyle2') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchSwiperIndicatorAlign')">
|
||||
<el-radio-group v-model="diyStore.editComponent.swiper.indicatorAlign">
|
||||
<el-radio label="left">{{ t('alignLeft') }}</el-radio>
|
||||
<el-radio label="center">{{ t('alignCenter') }}</el-radio>
|
||||
<el-radio label="right">{{ t('alignRight') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('noColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('selectColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.swiper.indicatorActiveColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<!-- <slot name="style"></slot> -->
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
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 { getDiyPageList } from '@/app/api/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['componentBgColor','componentBgUrl','marginTop','marginBottom','topRounded','bottomRounded','pageBgColor','marginBoth'] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
|
||||
diyStore.value[index].search.hotWord.list.forEach((item: any) => {
|
||||
if(item.text == ''){
|
||||
res.code = false
|
||||
res.message = t('carouselSearchHotWordTextPlaceholder')
|
||||
return res
|
||||
}
|
||||
});
|
||||
|
||||
diyStore.value[index].tab.list.forEach((item: any) => {
|
||||
if(item.text == ''){
|
||||
res.code = false
|
||||
res.message = t('carouselSearchTabCategoryTextPlaceholder')
|
||||
return res
|
||||
}
|
||||
// if(item.diy_id == ''){
|
||||
// res.code = false
|
||||
// res.message = t('selectDiyPagePlaceholder')
|
||||
// return res
|
||||
// }
|
||||
});
|
||||
|
||||
diyStore.value[index].swiper.list.forEach((item: any) => {
|
||||
if(item.imageUrl == ''){
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
});
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
diyStore.editComponent.search.hotWord.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
diyStore.editComponent.tab.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
diyStore.editComponent.swiper.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
const activeNames = ref(['tab', 'swiper'])
|
||||
const handleChange = (val: string[]) => {}
|
||||
|
||||
onMounted(() => {
|
||||
loadDiyPageList()
|
||||
})
|
||||
|
||||
const addHotWordItem = () => {
|
||||
diyStore.editComponent.search.hotWord.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
text : '关键词',
|
||||
})
|
||||
}
|
||||
|
||||
const tabClear = (index:any) => {
|
||||
diyStore.editComponent.tab.list[index].diy_id = 0;
|
||||
diyStore.editComponent.tab.list[index].diy_title = '';
|
||||
}
|
||||
|
||||
const addTabItem = () => {
|
||||
diyStore.editComponent.tab.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
text : '分类名称', // 最多4个字
|
||||
source : 'diy_page', // 数据源类型,微页面:diy_page
|
||||
diy_id : '',
|
||||
diy_title : ''
|
||||
})
|
||||
}
|
||||
|
||||
const searchHotWordTabBoxRef = ref()
|
||||
|
||||
const tabBoxRef = ref()
|
||||
|
||||
const imageBoxRef = ref()
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const hotWordSortable = Sortable.create(searchHotWordTabBoxRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
onEnd: event => {
|
||||
const temp = diyStore.editComponent.search.hotWord.list[event.oldIndex!]
|
||||
diyStore.editComponent.search.hotWord.list.splice(event.oldIndex!, 1)
|
||||
diyStore.editComponent.search.hotWord.list.splice(event.newIndex!, 0, temp)
|
||||
tabSortable.sort(
|
||||
range(diyStore.editComponent.search.hotWord.list.length).map(value => {
|
||||
return value.toString()
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const tabSortable = Sortable.create(tabBoxRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
onEnd: event => {
|
||||
const temp = diyStore.editComponent.tab.list[event.oldIndex!]
|
||||
diyStore.editComponent.tab.list.splice(event.oldIndex!, 1)
|
||||
diyStore.editComponent.tab.list.splice(event.newIndex!, 0, temp)
|
||||
tabSortable.sort(
|
||||
range(diyStore.editComponent.tab.list.length).map(value => {
|
||||
return value.toString()
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const imageSortable = Sortable.create(imageBoxRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
onEnd: event => {
|
||||
const temp = diyStore.editComponent.swiper.list[event.oldIndex!]
|
||||
diyStore.editComponent.swiper.list.splice(event.oldIndex!, 1)
|
||||
diyStore.editComponent.swiper.list.splice(event.newIndex!, 0, temp)
|
||||
imageSortable.sort(
|
||||
range(diyStore.editComponent.swiper.list.length).map(value => {
|
||||
return value.toString()
|
||||
})
|
||||
)
|
||||
handleHeight(true)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const diyPageShowDialog = ref(false)
|
||||
|
||||
const diyPageTable = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
type: 'DIY_PAGE' // todo 数据筛选,要考虑只能查询 微页面类型的数据
|
||||
}
|
||||
})
|
||||
const diyPageTableRef = ref<InstanceType<typeof ElTable>>()
|
||||
|
||||
/**
|
||||
* 获取自定义页面列表
|
||||
*/
|
||||
const loadDiyPageList = (page: number = 1) => {
|
||||
diyPageTable.loading = true
|
||||
diyPageTable.page = page
|
||||
|
||||
getDiyPageList({
|
||||
page: diyPageTable.page,
|
||||
limit: diyPageTable.limit,
|
||||
...diyPageTable.searchParam
|
||||
}).then(res => {
|
||||
diyPageTable.loading = false
|
||||
let data = res.data.data;
|
||||
let newData: any = [];
|
||||
let isExistCount = 0;
|
||||
|
||||
// 排除当前编辑的微页面以及存在 置顶组件的数据
|
||||
if (diyStore.id) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
if (data[i].id == diyStore.id || data[i].value.indexOf('top_fixed') != -1) {
|
||||
isExistCount++;
|
||||
} else {
|
||||
newData.push(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isExistCount) {
|
||||
res.data.total = res.data.total - isExistCount;
|
||||
}
|
||||
diyPageTable.data = newData
|
||||
diyPageTable.total = res.data.total
|
||||
}).catch(() => {
|
||||
diyPageTable.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
// 选择微页面
|
||||
let currDiyPage:any = {}
|
||||
let currTabIndexForDiyPage = 0;
|
||||
const handleCurrentDiyPageChange = (val: string | any[]) => {
|
||||
currDiyPage = val
|
||||
}
|
||||
|
||||
const saveDiyPageId = () => {
|
||||
diyStore.editComponent.tab.list[currTabIndexForDiyPage].diy_id = currDiyPage.id;
|
||||
diyStore.editComponent.tab.list[currTabIndexForDiyPage].diy_title = currDiyPage.title;
|
||||
diyPageShowDialog.value = false
|
||||
}
|
||||
|
||||
const diyPageShowDialogOpen = (index:any) => {
|
||||
diyPageShowDialog.value = true
|
||||
currTabIndexForDiyPage = index;
|
||||
if (currDiyPage) {
|
||||
setTimeout(() => {
|
||||
diyPageTableRef.value!.setCurrentRow(currDiyPage)
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => diyStore.editComponent.swiper.list,
|
||||
(newValue, oldValue) => {
|
||||
// 设置图片宽高
|
||||
handleHeight()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const addImageAd = () => {
|
||||
diyStore.editComponent.swiper.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
imageUrl: '',
|
||||
imgWidth: 0,
|
||||
imgHeight: 0,
|
||||
link: { name: '' }
|
||||
})
|
||||
}
|
||||
|
||||
const selectImg = (url:string) => {
|
||||
handleHeight(true)
|
||||
}
|
||||
|
||||
const changeSwiperStyle = (value:any) => {
|
||||
handleHeight(true)
|
||||
}
|
||||
|
||||
// 处理高度
|
||||
const handleHeight = (isCalcHeight:boolean = false)=> {
|
||||
diyStore.editComponent.swiper.list.forEach((item: any, index: number) => {
|
||||
const image = new Image()
|
||||
image.src = img(item.imageUrl)
|
||||
image.onload = async () => {
|
||||
item.imgWidth = image.width
|
||||
item.imgHeight = image.height
|
||||
// 计算第一张图片高度
|
||||
if (isCalcHeight && index == 0) {
|
||||
const ratio = item.imgHeight / item.imgWidth
|
||||
if(diyStore.editComponent.swiper.swiperStyle == 'style-1') {
|
||||
item.width = 375 * 0.92 // 0.92:前端缩放比例
|
||||
}else{
|
||||
item.width = 355
|
||||
}
|
||||
item.height = item.width * ratio
|
||||
diyStore.editComponent.swiper.imageHeight = parseInt(item.height)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
<style lang="scss">
|
||||
.select-diy-page-input .el-input__inner{
|
||||
cursor: pointer;
|
||||
}
|
||||
.collapse-wrap{
|
||||
.el-collapse-item__header{
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
157
admin/src/app/views/diy/components/edit-float-btn.vue
Normal file
157
admin/src/app/views/diy/components/edit-float-btn.vue
Normal file
@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap float-btn" v-show="diyStore.editTab == 'content'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('floatBtnBtton') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('floatBtnBtton')">
|
||||
<span>{{ selectTemplate.name }}</span>
|
||||
<ul class="ml-[10px] flex items-center">
|
||||
<li v-for="(item,i) in templateList" :key="i" :class="['w-[50px] h-[32px] flex items-center justify-center border-solid border-[1px] border-[#eee] cursor-pointer', {'border-r-transparent': templateList.length != (i+1)}, (item.className == diyStore.editComponent.bottomPosition) ? '!border-[var(--el-color-primary)]' : '' ]" @click="changeTemplateList(item)">
|
||||
<span :class="['iconfont', item.src]"></span>
|
||||
</li>
|
||||
</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-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('floatBtnImageSet') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('floatBtnImageSize')">
|
||||
<el-slider v-model="diyStore.editComponent.imageSize" show-input size="small" class="ml-[10px] horz-blank-slider" :min="40" :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-form-item>
|
||||
|
||||
<div class="text-[12px] text-[#999] mb-[15px] mt-[5px]">{{t('floatBtnImageSuggest')}}</div>
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
|
||||
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<el-button v-show="diyStore.editComponent.list.length < 3" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, onMounted, nextTick } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import Sortable from 'sortablejs'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { img } from '@/utils/common'
|
||||
import { range } from 'lodash-es'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
diyStore.value[index].list.forEach((item: any) => {
|
||||
if (item.imageUrl === '') {
|
||||
res.code = false
|
||||
res.message = t('imageUrlTip')
|
||||
return res
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
const templateList = ref([
|
||||
{
|
||||
name: '左上',
|
||||
src: 'iconzuoshangjiao',
|
||||
className: 'upperLeft'
|
||||
},
|
||||
{
|
||||
name: '右上',
|
||||
src: 'iconyoushangjiao',
|
||||
className: 'upperRight'
|
||||
},
|
||||
{
|
||||
name: '左下',
|
||||
src: 'iconzuoxiajiao',
|
||||
className: 'lowerLeft'
|
||||
},
|
||||
{
|
||||
name: '右下',
|
||||
src: 'iconyouxiajiao',
|
||||
className: 'lowerRight'
|
||||
}
|
||||
])
|
||||
|
||||
let selectTemplate = ref({})
|
||||
templateList.value.forEach((item) => {
|
||||
if (item.className == diyStore.editComponent.bottomPosition) {
|
||||
selectTemplate.value = item
|
||||
}
|
||||
})
|
||||
|
||||
const changeTemplateList = (data: any) => {
|
||||
selectTemplate.value = data;
|
||||
diyStore.editComponent.bottomPosition = data.className
|
||||
}
|
||||
|
||||
const addImageAd = () => {
|
||||
diyStore.editComponent.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
imageUrl: '',
|
||||
link: { name: '' }
|
||||
})
|
||||
}
|
||||
|
||||
const imageBoxRef = ref();
|
||||
diyStore.editComponent.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const imageSortable = Sortable.create(imageBoxRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
onEnd: event => {
|
||||
const temp = diyStore.editComponent.list[event.oldIndex!]
|
||||
diyStore.editComponent.list.splice(event.oldIndex!, 1)
|
||||
diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
|
||||
imageSortable.sort(
|
||||
range(diyStore.editComponent.list.length).map(value => {
|
||||
return value.toString()
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
defineExpose({})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
@ -12,18 +12,6 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('graphicNavTitle')">
|
||||
<el-input v-model="diyStore.editComponent.navTitle" :placeholder="t('graphicNavTitlePlaceholder')" clearable maxlength="20" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subGraphicNavTitle')">
|
||||
<el-input v-model="diyStore.editComponent.subNavTitle" :placeholder="t('subGraphicNavTitlePlaceholder')" clearable maxlength="20" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subGraphicNavTitleLink')">
|
||||
<diy-link v-model="diyStore.editComponent.subNavTitleLink"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('graphicNavSelectMode')">
|
||||
<el-radio-group v-model="diyStore.editComponent.mode">
|
||||
<el-radio :label="'graphic'">{{t('graphicNavModeGraphic')}}</el-radio>
|
||||
@ -34,8 +22,15 @@
|
||||
|
||||
<view v-show="diyStore.editComponent.layout == 'horizontal'">
|
||||
|
||||
<el-form-item :label="t('graphicNavPageCount')">
|
||||
<el-radio-group v-model="diyStore.editComponent.pageCount" @change="changePageCount">
|
||||
<el-radio :label="1">{{t('singleLine')}}</el-radio>
|
||||
<el-radio :label="2">{{t('multiline')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('graphicNavShowStyle')">
|
||||
<el-radio-group v-model="diyStore.editComponent.showStyle">
|
||||
<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="'pageSlide'">{{t('graphicNavStylePageSlide')}}</el-radio>
|
||||
@ -49,13 +44,6 @@
|
||||
<el-radio :label="5">5{{t('piece')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('graphicNavPageCount')">
|
||||
<el-radio-group v-model="diyStore.editComponent.pageCount">
|
||||
<el-radio :label="1">1{{t('line')}}</el-radio>
|
||||
<el-radio :label="2">2{{t('line')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</view>
|
||||
|
||||
</el-form>
|
||||
@ -73,7 +61,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('graphicNavTitle')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'text'">
|
||||
<el-input v-model="item.title" :placeholder="t('graphicNavTitlePlaceholder')" clearable maxlength="20" show-word-limit/>
|
||||
<el-input v-model.trim="item.title" :placeholder="t('graphicNavTitlePlaceholder')" clearable maxlength="20" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
|
||||
@ -120,9 +108,6 @@
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.font.color" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('subTextColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.subNavColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
@ -224,6 +209,14 @@ onMounted(() => {
|
||||
})
|
||||
})
|
||||
|
||||
const changePageCount = (value:any)=>{
|
||||
if(value == '1'){
|
||||
diyStore.editComponent.showStyle = 'singleSlide';
|
||||
}else if(value == '2'){
|
||||
diyStore.editComponent.showStyle = 'fixed';
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
@ -25,7 +25,7 @@ import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['pageBgColor', 'topRounded', 'bottomRounded', 'marginTop', 'marginBottom', 'marginBoth'] // 忽略公共属性
|
||||
diyStore.editComponent.ignore = ['pageBgColor', 'componentBgUrl'] // 忽略公共属性
|
||||
|
||||
defineExpose({})
|
||||
|
||||
|
||||
50
admin/src/app/views/diy/components/edit-horz-line.vue
Normal file
50
admin/src/app/views/diy/components/edit-horz-line.vue
Normal file
@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('horzLineStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('styleLabel')">
|
||||
<el-radio-group v-model="diyStore.editComponent.borderStyle">
|
||||
<el-radio label="solid">{{ t('horzLineStyleSolid') }}</el-radio>
|
||||
<el-radio label="dashed">{{ t('horzLineStyleDashed') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('horzLineBorderColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.borderColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('horzLineBorderWidth')">
|
||||
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small" class="ml-[10px] horz-blank-slider" :min="1" :max="10"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['pageBgColor','componentBgColor', 'componentBgUrl', 'topRounded', 'bottomRounded'] // 忽略公共属性
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.horz-blank-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -6,7 +6,7 @@
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
|
||||
<el-form-item :label="t('imageHeight')" class="display-block">
|
||||
<el-input v-model="diyStore.editComponent.imageHeight" :placeholder="t('imageHeightPlaceholder')" clearable maxlength="10" @blur="blurImageHeight">
|
||||
<el-input v-model.trim="diyStore.editComponent.imageHeight" :placeholder="t('imageHeightPlaceholder')" clearable maxlength="10" @blur="blurImageHeight">
|
||||
<template #append>px</template>
|
||||
</el-input>
|
||||
<div class="text-sm text-gray-400 mb-[10px]">{{ t('imageAdsTips') }}</div>
|
||||
@ -115,7 +115,7 @@ const handleHeight = (isCalcHeight:boolean = false)=> {
|
||||
// 计算第一张图片高度
|
||||
if (isCalcHeight && index == 0) {
|
||||
const ratio = item.imgHeight / item.imgWidth
|
||||
item.width = 375
|
||||
item.width = 375 - (diyStore.editComponent.margin.both*2)
|
||||
item.height = item.width * ratio
|
||||
diyStore.editComponent.imageHeight = parseInt(item.height)
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
|
||||
defineExpose({})
|
||||
|
||||
|
||||
@ -1,45 +1,83 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="content-wrap notice-content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">公告图标</h3>
|
||||
|
||||
<div class="px-[22px] pb-[20px]">
|
||||
<el-radio-group v-model="diyStore.editComponent.iconType" class="mb-[18px]">
|
||||
<el-radio label="system">系统图标</el-radio>
|
||||
<el-radio label="custom">自定义图标</el-radio>
|
||||
</el-radio-group>
|
||||
<div v-if="diyStore.editComponent.iconType == 'system'" class="flex items-center flex-wrap py-[8px] px-[10px] bg-[#f4f3f7] rounded">
|
||||
<img src="@/app/assets/images/diy/notice/style_01.png" :class="['h-[28px] px-[10px] py-[5px] mr-[10px] rounded cursor-pointer', {'border-[1px] border-solid border-[var(--el-color-primary)]': diyStore.editComponent.systemIcon == 'style_01'}]" @click="diyStore.editComponent.systemIcon = 'style_01'" alt="">
|
||||
</div>
|
||||
<div v-if="diyStore.editComponent.iconType == 'custom'">
|
||||
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">公告内容</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('title')">
|
||||
<el-input v-model="diyStore.editComponent.list.text" :placeholder="t('titlePlaceholder')" clearable show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item label="点击类型">
|
||||
<el-radio-group v-model="diyStore.editComponent.showType" class="mb-[18px]">
|
||||
<el-radio label="popup">弹出公告内容</el-radio>
|
||||
<el-radio label="link">跳出链接</el-radio>
|
||||
<h3 class="mb-[10px]">{{ t('noticeStyle') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item :label="t('noticeType')">
|
||||
<el-radio-group v-model="diyStore.editComponent.noticeType">
|
||||
<el-radio label="img">{{ t('noticeTypeImg') }}</el-radio>
|
||||
<el-radio label="text">{{ t('noticeTypeText') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')" class="!mb-0" v-if="diyStore.editComponent.showType == 'link'">
|
||||
<diy-link v-model="diyStore.editComponent.list.link"/>
|
||||
<div class="flex items-center flex-wrap py-[8px] px-[10px] bg-[#f4f3f7] rounded mb-[18px] mx-[18px]" v-show="diyStore.editComponent.noticeType == 'img'">
|
||||
<div :class="['mr-[10px] rounded cursor-pointer', {'border-[1px] border-solid border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_1' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<img src="@/app/assets/images/diy/notice/style_1.png" :class="['h-[28px] px-[10px] py-[5px]']" @click="changeStyle('style_1')"/>
|
||||
</div>
|
||||
|
||||
<div :class="['mr-[10px] rounded cursor-pointer w-[100px]', {'border-[1px] border-solid border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_2' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<img src="@/app/assets/images/diy/notice/style_2.png" class="px-[10px] py-[5px]" @click="changeStyle('style_2')"/>
|
||||
</div>
|
||||
<div @click="diyStore.editComponent.imgType = 'diy'" :class="['mr-[10px] rounded cursor-pointer diy-upload-img', {'border-[1px] border-solid border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
|
||||
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="t('noticeTitle')" v-show="diyStore.editComponent.noticeType == 'text'">
|
||||
<el-input v-model.trim="diyStore.editComponent.noticeTitle" :placeholder="t('titlePlaceholder')" clearable maxlength="20" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('noticeText') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
|
||||
<el-form-item :label="t('noticeScrollWay')">
|
||||
<el-radio-group v-model="diyStore.editComponent.scrollWay">
|
||||
<el-radio label="upDown">{{ t('noticeUpDown') }}</el-radio>
|
||||
<el-radio label="horizontal">{{ t('noticeHorizontal') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('noticeShowType')">
|
||||
<el-radio-group v-model="diyStore.editComponent.showType">
|
||||
<el-radio label="popup">{{ t('noticeShowPopUp') }}</el-radio>
|
||||
<el-radio label="link">{{ t('noticeShowLink') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('dragMouseAdjustOrder') }}</p>
|
||||
|
||||
<div ref="noticeBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
|
||||
<el-form-item :label="t('noticeText')">
|
||||
<el-input v-model.trim="item.text" :placeholder="t('noticePlaceholderText')" clearable maxlength="40" show-word-limit/>
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
|
||||
<icon name="element-CircleCloseFilled" color="#bbb" size="20px"/>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="t('link')" v-if="diyStore.editComponent.showType == 'link'">
|
||||
<diy-link v-model="item.link"/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button class="w-full" @click="addNotice">{{ t('addNotice') }}</el-button>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('titleStyle') }}</h3>
|
||||
<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"/>
|
||||
@ -64,47 +102,112 @@
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { ref } from 'vue'
|
||||
import { ref, watch, onMounted, nextTick } from 'vue'
|
||||
import { range } from 'lodash-es'
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
|
||||
const showDialog = ref(false)
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
|
||||
const showStyle = () => {
|
||||
showDialog.value = true
|
||||
if(diyStore.value[index].noticeType == 'text'){
|
||||
if(diyStore.value[index].noticeTitle == ''){
|
||||
res.code = false
|
||||
res.message = t('noticeTypeTextPlaceholder')
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
diyStore.value[index].list.forEach((item: any) => {
|
||||
if (item.text == '') {
|
||||
res.code = false
|
||||
res.message = t('noticePlaceholderText')
|
||||
return res
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
diyStore.editComponent.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
const selectStyle = ref(diyStore.editComponent.style)
|
||||
|
||||
const changeStyle = () => {
|
||||
switch (selectStyle.value) {
|
||||
case 'style-1':
|
||||
diyStore.editComponent.subTitle.control = false
|
||||
diyStore.editComponent.more.control = false
|
||||
diyStore.editComponent.styleName = '风格1'
|
||||
break
|
||||
case 'style-2':
|
||||
diyStore.editComponent.subTitle.control = true
|
||||
diyStore.editComponent.more.control = true
|
||||
diyStore.editComponent.styleName = '风格2'
|
||||
break
|
||||
}
|
||||
diyStore.editComponent.style = selectStyle.value
|
||||
showDialog.value = false
|
||||
const changeStyle = (value :any) => {
|
||||
diyStore.editComponent.systemUrl = value;
|
||||
diyStore.editComponent.imgType = 'system';
|
||||
}
|
||||
|
||||
watch(
|
||||
() => diyStore.editComponent.imageUrl,
|
||||
(newValue, oldValue) => {
|
||||
if(newValue){
|
||||
diyStore.editComponent.imgType = 'diy';
|
||||
}else{
|
||||
diyStore.editComponent.imgType = 'system';
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const addNotice = () => {
|
||||
diyStore.editComponent.list.push({
|
||||
id: diyStore.generateRandom(),
|
||||
text: '公告',
|
||||
link: { name: '' },
|
||||
})
|
||||
}
|
||||
|
||||
const noticeBoxRef = ref()
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const sortable = Sortable.create(noticeBoxRef.value, {
|
||||
group: 'item-wrap',
|
||||
animation: 200,
|
||||
onEnd: event => {
|
||||
const temp = diyStore.editComponent.list[event.oldIndex!]
|
||||
diyStore.editComponent.list.splice(event.oldIndex!, 1)
|
||||
diyStore.editComponent.list.splice(event.newIndex!, 0, temp)
|
||||
sortable.sort(
|
||||
range(diyStore.editComponent.list.length).map(value => {
|
||||
return value.toString()
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
defineExpose({})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.horz-blank-slider {
|
||||
.el-slider__input {
|
||||
width: 100px;
|
||||
.notice-content-wrap {
|
||||
.add-notice-width {
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.diy-upload-img {
|
||||
.image-wrap {
|
||||
width: 50px !important;
|
||||
height: 50px !important;
|
||||
margin-right: 0 !important;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
div {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.operation{
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.add-notice-width{
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('pageContent') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('pageName')">
|
||||
<el-input v-model="diyStore.global.title" :placeholder="t('pageNamePlaceholder')" clearable maxlength="12" show-word-limit/>
|
||||
<el-input v-model.trim="diyStore.global.title" :placeholder="t('pageNamePlaceholder')" clearable maxlength="12" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('tabbar')" class="display-block">
|
||||
<el-switch v-model="diyStore.global.bottomTabBarSwitch"/>
|
||||
@ -21,8 +21,20 @@
|
||||
<h3 class="mb-[10px]">{{ t('pageStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('pageBgColor')">
|
||||
<el-color-picker v-model="diyStore.global.pageBgColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bgGradientAngle')">
|
||||
<el-radio-group v-model="diyStore.editComponent.pageGradientAngle">
|
||||
<el-radio label="to bottom">{{ t('topToBottom') }}</el-radio>
|
||||
<el-radio label="to right">{{ t('leftToRight') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bgHeightScale')">
|
||||
<el-slider v-model="diyStore.global.bgHeightScale" show-input size="small" class="ml-[10px] horz-blank-slider"/>
|
||||
</el-form-item>
|
||||
<div class="text-sm text-gray-400 ml-[80px] mb-[10px]">{{ t('bgHeightScaleTip') }}</div>
|
||||
<el-form-item :label="t('bgUrl')">
|
||||
<upload-image v-model="diyStore.global.bgUrl" :limit="1"/>
|
||||
</el-form-item>
|
||||
|
||||
42
admin/src/app/views/diy/components/edit-rich-text.vue
Normal file
42
admin/src/app/views/diy/components/edit-rich-text.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('richTextContentSet') }}</h3>
|
||||
<editor v-model="diyStore.editComponent.html" height="600px" class="editor-width" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 样式 -->
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<!-- 组件样式 -->
|
||||
<slot name="style"></slot>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
|
||||
if(diyStore.value[index].html == '<p><br></p>'){
|
||||
res.code = false
|
||||
res.message = t('richTextPlaceholder')
|
||||
return res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -16,7 +16,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('titleContent') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('title')">
|
||||
<el-input v-model="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="15" show-word-limit />
|
||||
<el-input v-model.trim="diyStore.editComponent.text" :placeholder="t('titlePlaceholder')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.link" />
|
||||
@ -34,7 +34,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('subTitleContent') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('subTitle')">
|
||||
<el-input v-model="diyStore.editComponent.subTitle.text" :placeholder="t('subTitlePlaceholder')" clearable maxlength="30" show-word-limit />
|
||||
<el-input v-model.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" />
|
||||
@ -49,7 +49,7 @@
|
||||
<h3 class="mb-[10px]">{{ t('moreContent') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('more')">
|
||||
<el-input v-model="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
<el-input v-model.trim="diyStore.editComponent.more.text" :placeholder="t('morePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('link')">
|
||||
<diy-link v-model="diyStore.editComponent.more.link" />
|
||||
@ -63,13 +63,13 @@
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="40%">
|
||||
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="620px">
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
|
||||
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png" />
|
||||
</div>
|
||||
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
|
||||
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style2.png" />
|
||||
</div>
|
||||
</div>
|
||||
@ -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="20" />
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] article-slider" :min="12" :max="30" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textFontWeight')">
|
||||
<el-radio-group v-model="diyStore.editComponent.fontWeight">
|
||||
|
||||
@ -5,16 +5,17 @@
|
||||
<el-icon size="14">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<span class="pl-[5px]">{{ t('back') }}</span>
|
||||
<span class="pl-[5px] text-[14px]">{{ t('back') }}</span>
|
||||
</div>
|
||||
<div class="text-white ml-[10px] mr-[20px] flex items-center">
|
||||
<span class="mr-[5px]"> | {{ t('decorating') }}:{{ diyStore.typeName }}</span>
|
||||
<span class="mr-[5px] text-[rgba(255,255,255,.5)]">|</span>
|
||||
<span class="mr-[5px] text-[14px]">{{ t('decorating') }}:{{ diyStore.typeName }}</span>
|
||||
<!--<el-icon class="font-bold"><EditPen /></el-icon>-->
|
||||
</div>
|
||||
|
||||
<div v-if="diyStore.type && diyStore.type != 'DIY_PAGE'">
|
||||
<span class="text-white mr-[10px] text-base">{{ t('templatePagePlaceholder') }}</span>
|
||||
<el-select v-model="template" class="w-[180px]" :placeholder="t('templatePagePlaceholder')" @change="changeTemplatePage">
|
||||
<el-select size="small" v-model="template" class="w-[180px]" :placeholder="t('templatePagePlaceholder')" @change="changeTemplatePage">
|
||||
<el-option :label="t('templatePageEmpty')" value="" />
|
||||
<el-option v-for="(item, key) in templatePages" :label="item.title" :value="key" :key="key"/>
|
||||
</el-select>
|
||||
@ -33,9 +34,10 @@
|
||||
<el-collapse v-model="activeNames" @change="handleChange">
|
||||
<el-collapse-item v-for="(item, key) in component" :key="key" :title="item.title" :name="key">
|
||||
<ul class="flex flex-row flex-wrap">
|
||||
<li v-for="(compItem, compKey) in item.list" :key="compKey" class="w-2/6 text-center cursor-pointer h-[75px]" :title="compItem.title" @click="diyStore.addComponent(compKey, compItem)">
|
||||
<icon :name="compItem.icon" size="23px" />
|
||||
<span class="block text-base truncate">{{ compItem.title }}</span>
|
||||
<li v-for="(compItem, compKey) in item.list" :key="compKey" class="w-2/6 text-center cursor-pointer h-[65px]" :title="compItem.title" @click="diyStore.addComponent(compKey, compItem)">
|
||||
<icon v-if="compItem.icon" :name="compItem.icon" size="20px" class="inline-block mt-[3px]" />
|
||||
<icon v-else name="iconfont-iconkaifazujian" size="20px" class="inline-block mt-[3px]" />
|
||||
<span class="block text-[12px] truncate">{{ compItem.title }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-collapse-item>
|
||||
@ -111,14 +113,45 @@
|
||||
<template #style>
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('componentStyleTitle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('bottomBgColor')" class="display-block" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<div class="text-sm text-gray-400">{{ t('bottomBgTips') }}</div>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
|
||||
<template v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-form-item :label="t('bottomBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.pageEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
<div class="text-sm text-gray-400 ml-[80px] mb-[10px]">{{ t('bottomBgTips') }}</div>
|
||||
</template>
|
||||
|
||||
<el-form-item :label="t('bgGradientAngle')" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-radio-group v-model="diyStore.editComponent.pageGradientAngle">
|
||||
<el-radio label="to bottom">{{ t('topToBottom') }}</el-radio>
|
||||
<el-radio label="to right">{{ t('leftToRight') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('componentBgUrl')" v-if="diyStore.editComponent.ignore.indexOf('componentBgUrl') == -1">
|
||||
<upload-image v-model="diyStore.editComponent.componentBgUrl" :limit="1"/>
|
||||
</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-form-item>
|
||||
|
||||
<el-form-item :label="t('componentBgColor')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.componentBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<el-color-picker v-model="diyStore.editComponent.componentStartBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<icon name="iconfont-iconmap-connect" size="20px" class="block !text-gray-400 mx-[5px]"/>
|
||||
<el-color-picker v-model="diyStore.editComponent.componentEndBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('bgGradientAngle')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-radio-group v-model="diyStore.editComponent.componentGradientAngle">
|
||||
<el-radio label="to bottom">{{ t('topToBottom') }}</el-radio>
|
||||
<el-radio label="to right">{{ t('leftToRight') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('marginTop')" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="0" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
@ -138,33 +171,6 @@
|
||||
</div>
|
||||
</template>
|
||||
</component>
|
||||
<div class="edit-attr-item-wrap" v-else>
|
||||
<h3 class="mb-[10px]">{{ t('componentStyleTitle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('bottomBgColor')" class="display-block" v-if="diyStore.editComponent.ignore.indexOf('pageBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.pageBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<div class="text-sm text-gray-400">{{ t('bottomBgTips') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('componentBgColor')" v-if="diyStore.editComponent.ignore.indexOf('componentBgColor') == -1">
|
||||
<el-color-picker v-model="diyStore.editComponent.componentBgColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginTop')" v-if="diyStore.editComponent.ignore.indexOf('marginTop') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.top" show-input size="small" :min="0" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBottom')" v-if="diyStore.editComponent.ignore.indexOf('marginBottom') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.bottom" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('marginBoth')" v-if="diyStore.editComponent.ignore.indexOf('marginBoth') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.margin.both" show-input size="small" class="ml-[10px] horz-blank-slider" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('topRounded')" v-if="diyStore.editComponent.ignore.indexOf('topRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.topRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('bottomRounded')" v-if="diyStore.editComponent.ignore.indexOf('bottomRounded') == -1">
|
||||
<el-slider v-model="diyStore.editComponent.bottomRounded" show-input size="small" class="ml-[10px] horz-blank-slider" :max="50" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -299,6 +305,7 @@ const changeTemplatePage = (value:any)=> {
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
diyStore.changeCurrentIndex(-99)
|
||||
if (value) {
|
||||
let data = templatePages[value].data;
|
||||
diyStore.global = data.global;
|
||||
@ -427,28 +434,46 @@ initPage({
|
||||
wapDomain.value = data.domain_url.wap_domain
|
||||
wapUrl.value = data.domain_url.wap_url
|
||||
page.value = data.page
|
||||
setDomain()
|
||||
|
||||
// 生产模式禁止
|
||||
if (import.meta.env.MODE == 'production') return
|
||||
let repeat = true; // 防重复执行
|
||||
|
||||
// env文件配置过wap域名
|
||||
if (wapDomain.value) {
|
||||
wapUrl.value = wapDomain.value + '/wap'
|
||||
// 开发模式下执行
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
|
||||
// env文件配置过wap域名
|
||||
if (wapDomain.value) {
|
||||
wapUrl.value = wapDomain.value + '/wap'
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
|
||||
let wap_domain_storage = storage.get('wap_domain')
|
||||
if (wap_domain_storage) {
|
||||
wapUrl.value = wap_domain_storage
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
|
||||
if(repeat) {
|
||||
setDomain()
|
||||
}
|
||||
|
||||
let wap_domain_storage = storage.get('wap_domain')
|
||||
if (wap_domain_storage) {
|
||||
wapUrl.value = wap_domain_storage
|
||||
setDomain()
|
||||
}
|
||||
})
|
||||
|
||||
const uniAppLoadStatus = ref(false) // uni-app 加载状态,true:加载完成,false:未完成
|
||||
|
||||
// 监听组件数据 uni-app端
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
let data = {
|
||||
type: ''
|
||||
};
|
||||
if(typeof event.data == 'string') {
|
||||
data = JSON.parse(event.data)
|
||||
}else if(typeof event.data == 'object') {
|
||||
data = event.data
|
||||
}
|
||||
if (!data.type) return
|
||||
|
||||
switch (data.type) {
|
||||
@ -459,6 +484,7 @@ window.addEventListener('message', (event) => {
|
||||
loadingIframe.value = true
|
||||
let loadTime = new Date().getTime()
|
||||
difference.value = loadTime - timeIframe.value
|
||||
uniAppLoadStatus.value = true // 加载完成
|
||||
break
|
||||
case 'init':
|
||||
// 初始化,与uniapp建立连接传输数据
|
||||
@ -477,7 +503,7 @@ window.addEventListener('message', (event) => {
|
||||
break
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('后台接受数据错误', e)
|
||||
console.log('diy edit 后台接受数据错误', e)
|
||||
}
|
||||
}, false)
|
||||
|
||||
@ -499,11 +525,32 @@ const saveWapDomain = () => {
|
||||
const setDomain = () => {
|
||||
wapPreview.value = `${wapUrl.value}${page.value}?mode=decorate` // 模式:decorate 装修 访问预览页面
|
||||
|
||||
timeIframe.value = new Date().getTime()
|
||||
postMessage()
|
||||
const send = ()=>{
|
||||
timeIframe.value = new Date().getTime()
|
||||
postMessage()
|
||||
}
|
||||
|
||||
// 同步发送一次消息
|
||||
send()
|
||||
|
||||
// 如果同步发送消息的 uni-app没有接收到回应,则定时发送消息
|
||||
let sendCount = 0;
|
||||
let timeInterVal = setInterval(()=>{
|
||||
// 接收 uni-app 发送的消息 或者 发送50次后未响应,则停止发送
|
||||
if(uniAppLoadStatus.value || sendCount >= 50){
|
||||
clearInterval(timeInterVal)
|
||||
return
|
||||
}
|
||||
|
||||
send()
|
||||
sendCount++;
|
||||
},200)
|
||||
|
||||
// 如果10秒内加载不出来,则需要配置域名
|
||||
setTimeout(() => {
|
||||
if (difference.value == 0) initLoad()
|
||||
}, 1000 * 2)
|
||||
}, 1000 * 10)
|
||||
|
||||
}
|
||||
|
||||
// 将数据发送到uniapp
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap mt-[20px] min-w-[1000px]" v-if="page.use_template">
|
||||
<div class="flex flex-wrap mt-[20px] min-w-[1200px]" v-if="page.use_template">
|
||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
||||
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="w-[500px]">
|
||||
<div class="w-[700px]">
|
||||
<div class="flex flex-wrap">
|
||||
<diy-link v-model="link" :ignore="['DIY_LINK']" @success="changePage">
|
||||
<el-button type="primary">{{ t('changePage') }}</el-button>
|
||||
@ -41,7 +41,7 @@
|
||||
<div class="font-bold">{{ t('H5') }}</div>
|
||||
<el-form label-width="40px" class="mt-[5px]">
|
||||
<el-form-item :label="t('link')" class="mb-[5px]">
|
||||
<el-input readonly :value="page.shareUrl">
|
||||
<el-input readonly :value="page.shareUrl" class="!w-[390px]">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(page.shareUrl)" class="bg-primary copy">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
@ -118,39 +118,55 @@ const refreshData = () => {
|
||||
wapDomain.value = page.domain_url.wap_domain
|
||||
page.wapUrl = page.domain_url.wap_url
|
||||
|
||||
let repeat = true; // 防重复执行
|
||||
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
// 开发模式情况下,并且未配置wap域名,则获取缓存域名
|
||||
if (wapDomain.value) {
|
||||
page.wapUrl = wapDomain.value + '/wap'
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
if (storage.get('wap_domain')) {
|
||||
page.wapUrl = storage.get('wap_domain')
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
|
||||
setDomain()
|
||||
if(repeat) {
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
refreshData()
|
||||
|
||||
const uniAppLoadStatus = ref(false) // uni-app 加载状态,true:加载完成,false:未完成
|
||||
|
||||
// 监听 uni-app 端 是否加载完成
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
let data = {
|
||||
type :''
|
||||
};
|
||||
if(typeof event.data == 'string') {
|
||||
data = JSON.parse(event.data)
|
||||
}else if(typeof event.data == 'object') {
|
||||
data = event.data
|
||||
}
|
||||
if (data.type && ['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
page.loadingDev = false // 禁用开发环境配置
|
||||
page.loadingIframe = true // 加载iframe
|
||||
const loadTime = new Date().getTime()
|
||||
let loadTime = new Date().getTime()
|
||||
page.difference = loadTime - page.timeIframe
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
uniAppLoadStatus.value = true // 加载完成
|
||||
}
|
||||
} catch (e) {
|
||||
initLoad()
|
||||
console.log('后台接受数据错误', e)
|
||||
console.log('diy index 后台接受数据错误', e)
|
||||
}
|
||||
}, false)
|
||||
|
||||
@ -204,11 +220,32 @@ const setDomain = () => {
|
||||
QRCode.toDataURL(page.shareUrl, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
page.timeIframe = new Date().getTime()
|
||||
postMessage()
|
||||
|
||||
const send = ()=>{
|
||||
page.timeIframe = new Date().getTime()
|
||||
postMessage()
|
||||
}
|
||||
|
||||
// 同步发送一次消息
|
||||
send()
|
||||
|
||||
// 如果同步发送消息的 uni-app没有接收到回应,则定时发送消息
|
||||
let sendCount = 0;
|
||||
let timeInterVal = setInterval(()=>{
|
||||
// 接收 uni-app 发送的消息 或者 发送50次后未响应,则停止发送
|
||||
if(uniAppLoadStatus.value || sendCount >= 50){
|
||||
clearInterval(timeInterVal)
|
||||
return
|
||||
}
|
||||
|
||||
send()
|
||||
sendCount++;
|
||||
},200)
|
||||
|
||||
// 如果10秒内加载不出来,则需要配置域名
|
||||
setTimeout(() => {
|
||||
if (page.difference == 0) initLoad()
|
||||
}, 1000 * 2)
|
||||
}, 1000 * 10)
|
||||
}
|
||||
|
||||
// 跳转去装修
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap mt-[20px] min-w-[1000px]" v-if="page.use_template">
|
||||
<div class="flex flex-wrap mt-[20px] min-w-[1200px]" v-if="page.use_template">
|
||||
<div class="page-item relative bg-no-repeat ml-[20px] mr-[40px] bg-[#f7f7f7] w-[340px] pt-[90px] pb-[20px]">
|
||||
<p class="absolute top-[54px] left-[50%] translate-x-[-50%] text-[14px] truncate w-[130px] text-center">{{ page.use_template.title }}</p>
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="w-[500px]">
|
||||
<div class="w-[700px]">
|
||||
<div class="flex flex-wrap">
|
||||
<!-- 多应用切换启动页 -->
|
||||
<el-button type="primary" @click="showDialog = true" v-if="siteApps.length > 1">{{ t('changePage') }}</el-button>
|
||||
@ -40,7 +40,7 @@
|
||||
<div class="font-bold">{{ t('H5') }}</div>
|
||||
<el-form label-width="40px" class="mt-[5px]">
|
||||
<el-form-item :label="t('link')" class="mb-[5px]">
|
||||
<el-input readonly :value="page.shareUrl">
|
||||
<el-input readonly :value="page.shareUrl" class="!w-[400px]">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(page.shareUrl)" class="bg-primary copy">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
@ -152,39 +152,56 @@ const refreshData = () => {
|
||||
wapDomain.value = page.domain_url.wap_domain
|
||||
page.wapUrl = page.domain_url.wap_url
|
||||
|
||||
let repeat = true; // 防重复执行
|
||||
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
// 开发模式情况下,并且未配置wap域名,则获取缓存域名
|
||||
if (wapDomain.value) {
|
||||
page.wapUrl = wapDomain.value + '/wap'
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
if (storage.get('wap_domain')) {
|
||||
page.wapUrl = storage.get('wap_domain')
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
|
||||
setDomain()
|
||||
if(repeat) {
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
refreshData()
|
||||
|
||||
const uniAppLoadStatus = ref(false) // uni-app 加载状态,true:加粗完成,false:未完成
|
||||
|
||||
// 监听 uni-app 端 是否加载完成
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
let data = {
|
||||
type: ''
|
||||
};
|
||||
if(typeof event.data == 'string') {
|
||||
data = JSON.parse(event.data)
|
||||
}else if(typeof event.data == 'object') {
|
||||
data = event.data
|
||||
}
|
||||
|
||||
if (data.type && ['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
page.loadingDev = false // 禁用开发环境配置
|
||||
page.loadingIframe = true // 加载iframe
|
||||
const loadTime = new Date().getTime()
|
||||
let loadTime = new Date().getTime()
|
||||
page.difference = loadTime - page.timeIframe
|
||||
page.isDisabledPop = false // 是否禁止打开遮罩层
|
||||
uniAppLoadStatus.value = true // 加载完成
|
||||
}
|
||||
} catch (e) {
|
||||
initLoad()
|
||||
console.log('后台接受数据错误', e)
|
||||
console.log('diy member 后台接受数据错误', e)
|
||||
}
|
||||
}, false)
|
||||
|
||||
@ -238,11 +255,32 @@ const setDomain = () => {
|
||||
QRCode.toDataURL(page.shareUrl, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
page.timeIframe = new Date().getTime()
|
||||
postMessage()
|
||||
|
||||
const send = ()=>{
|
||||
page.timeIframe = new Date().getTime()
|
||||
postMessage()
|
||||
}
|
||||
|
||||
// 同步发送一次消息
|
||||
send()
|
||||
|
||||
// 如果同步发送消息的 uni-app没有接收到回应,则定时发送消息
|
||||
let sendCount = 0;
|
||||
let timeInterVal = setInterval(()=>{
|
||||
// 接收 uni-app 发送的消息 或者 发送50次后未响应,则停止发送
|
||||
if(uniAppLoadStatus.value || sendCount >= 50){
|
||||
clearInterval(timeInterVal)
|
||||
return
|
||||
}
|
||||
|
||||
send()
|
||||
sendCount++;
|
||||
},200)
|
||||
|
||||
// 如果10秒内加载不出来,则需要配置域名
|
||||
setTimeout(() => {
|
||||
if (page.difference == 0) initLoad()
|
||||
}, 1000 * 2)
|
||||
}, 1000 * 10)
|
||||
}
|
||||
|
||||
// 跳转去装修
|
||||
|
||||
@ -9,8 +9,7 @@
|
||||
<el-row class="flex">
|
||||
<el-col :span="8" class="min-w-[100px]">
|
||||
<div class="statistic-card">
|
||||
<el-statistic
|
||||
:value="accountStat.pay ? accountStat.pay.toFixed(2) : '0.00'"></el-statistic>
|
||||
<el-statistic :value="accountStat.pay ? accountStat.pay.toFixed(2) : '0.00'"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('totalPay') }}</span>
|
||||
@ -20,8 +19,7 @@
|
||||
</el-col>
|
||||
<el-col :span="8" class="min-w-[100px]">
|
||||
<div class="statistic-card">
|
||||
<el-statistic
|
||||
:value="accountStat.refund ? accountStat.refund.toFixed(2) : '0.00'"></el-statistic>
|
||||
<el-statistic :value="accountStat.refund ? accountStat.refund.toFixed(2) : '0.00'"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('totalRefund') }}</span>
|
||||
@ -31,8 +29,7 @@
|
||||
</el-col>
|
||||
<el-col :span="8" class="min-w-[100px]">
|
||||
<div class="statistic-card">
|
||||
<el-statistic
|
||||
:value="accountStat.transfer ? accountStat.transfer.toFixed(2) : '0.00'"></el-statistic>
|
||||
<el-statistic :value="accountStat.transfer ? accountStat.transfer.toFixed(2) : '0.00'"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('totalTransfer') }}</span>
|
||||
@ -45,15 +42,13 @@
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="siteAccountLogTable.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('type')" class="items-center" prop="type">
|
||||
<el-select v-model="siteAccountLogTable.searchParam.type" class="m-2"
|
||||
:placeholder="t('accountType')">
|
||||
<el-select v-model="siteAccountLogTable.searchParam.type" class="m-2" :placeholder="t('accountType')">
|
||||
<el-option :label="t('all')" value="" />
|
||||
<el-option v-for="(item, index) in accountType" :key="index" :label="item" :value="index" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('tradeNo')" prop="trade_no">
|
||||
<el-input v-model="siteAccountLogTable.searchParam.trade_no"
|
||||
:placeholder="t('tradeNoPlaceholder')" />
|
||||
<el-input v-model="siteAccountLogTable.searchParam.trade_no" :placeholder="t('tradeNoPlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('createTime')" prop="create_time">
|
||||
<el-date-picker v-model="siteAccountLogTable.searchParam.create_time" type="datetimerange"
|
||||
@ -100,9 +95,9 @@
|
||||
<el-dialog v-model="showDialog" :title="t('accountDetail')" width="550px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="110px" ref="formRef" class="page-form">
|
||||
|
||||
<el-form-item :label="t('tradeNo')">
|
||||
<div class="input-width"> {{ formData.trade_no }} </div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item :label="t('tradeNo')">-->
|
||||
<!-- <div class="input-width"> {{ formData.trade_no }} </div>-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item :label="t('type')">
|
||||
<div class="input-width"> {{ formData.type_name }} </div>
|
||||
</el-form-item>
|
||||
@ -173,7 +168,6 @@
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getAccountList, getAccountStat, getAccountType } from '@/app/api/site'
|
||||
// import { img } from '@/utils/common'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('cashOutStatus')" prop="order_from">
|
||||
<el-form-item :label="t('cashOutStatus')" prop="status">
|
||||
<el-select v-model="orderTableData.searchParam.status" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item" :value="key" v-for="(item, key) in cashOutStatusList" :key="key"/>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="detail-head">
|
||||
<div class="left" @click="router.push({ path: '/member/refund' })">
|
||||
<div class="left" @click="router.push({ path: '/finance/refund' })">
|
||||
<span class="iconfont iconxiangzuojiantou !text-xs"></span>
|
||||
<span class="ml-[1px]">{{ t('returnToPreviousPage') }}</span>
|
||||
</div>
|
||||
|
||||
@ -83,24 +83,33 @@ setLayout('decorate')
|
||||
|
||||
getUrl().then((res: any) => {
|
||||
wapUrl.value = res.data.wap_url
|
||||
setDomain()
|
||||
|
||||
// 生产模式禁止
|
||||
if (import.meta.env.MODE == 'production') return
|
||||
let repeat = true; // 防重复执行
|
||||
|
||||
wapDomain.value = res.data.wap_domain
|
||||
// 开发模式下执行
|
||||
if (import.meta.env.MODE == 'development') {
|
||||
|
||||
// env文件配置过wap域名
|
||||
if (wapDomain.value) {
|
||||
wapUrl.value = wapDomain.value + '/wap'
|
||||
wapDomain.value = res.data.wap_domain
|
||||
|
||||
// env文件配置过wap域名
|
||||
if (wapDomain.value) {
|
||||
wapUrl.value = wapDomain.value + '/wap'
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
|
||||
const wap_domain_storage = storage.get('wap_domain')
|
||||
if (wap_domain_storage) {
|
||||
wapUrl.value = wap_domain_storage
|
||||
repeat = false
|
||||
setDomain()
|
||||
}
|
||||
}
|
||||
|
||||
if(repeat) {
|
||||
setDomain()
|
||||
}
|
||||
|
||||
const wap_domain_storage = storage.get('wap_domain')
|
||||
if (wap_domain_storage) {
|
||||
wapUrl.value = wap_domain_storage
|
||||
setDomain()
|
||||
}
|
||||
})
|
||||
|
||||
const save = () => {
|
||||
@ -125,26 +134,58 @@ const setDomain = () => {
|
||||
QRCode.toDataURL(wapPreview.value, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
timeIframe.value = new Date().getTime()
|
||||
|
||||
const send = ()=>{
|
||||
timeIframe.value = new Date().getTime()
|
||||
postMessage()
|
||||
}
|
||||
|
||||
// 同步发送一次消息
|
||||
send()
|
||||
|
||||
// 如果同步发送消息的 uni-app没有接收到回应,则定时发送消息
|
||||
let sendCount = 0;
|
||||
let timeInterVal = setInterval(()=>{
|
||||
// 接收 uni-app 发送的消息 或者 发送50次后未响应,则停止发送
|
||||
if(uniAppLoadStatus.value || sendCount >= 50){
|
||||
clearInterval(timeInterVal)
|
||||
return
|
||||
}
|
||||
|
||||
send()
|
||||
sendCount++;
|
||||
},200)
|
||||
|
||||
// 如果10秒内加载不出来,则需要配置域名
|
||||
setTimeout(() => {
|
||||
if (difference.value == 0) initLoad()
|
||||
}, 1000 * 2)
|
||||
}, 1000 * 10)
|
||||
}
|
||||
}
|
||||
|
||||
const uniAppLoadStatus = ref(false) // uni-app 加载状态,true:加载完成,false:未完成
|
||||
|
||||
// 监听 uni-app 端 是否加载完成
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
if (['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
let data = {
|
||||
type :''
|
||||
};
|
||||
if(typeof event.data == 'string') {
|
||||
data = JSON.parse(event.data)
|
||||
}else if(typeof event.data == 'object') {
|
||||
data = event.data
|
||||
}
|
||||
if (data.type && ['appOnLaunch', 'appOnReady'].indexOf(data.type) != -1) {
|
||||
loadingDev.value = false
|
||||
loadingIframe.value = true
|
||||
const loadTime = new Date().getTime()
|
||||
let loadTime = new Date().getTime()
|
||||
uniAppLoadStatus.value = true // 加载完成
|
||||
difference.value = loadTime - timeIframe.value
|
||||
}
|
||||
} catch (e) {
|
||||
initLoad()
|
||||
console.log('后台接受数据错误', e)
|
||||
console.log('preview 后台接受数据错误', e)
|
||||
}
|
||||
}, false)
|
||||
|
||||
|
||||
@ -2,13 +2,13 @@
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-form-item :label="t('labelName')" prop="label_name">
|
||||
<el-input v-model="formData.label_name" clearable :placeholder="t('labelNamePlaceholder')" class="input-width" />
|
||||
<el-input v-model.trim="formData.label_name" clearable :placeholder="t('labelNamePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('memo')">
|
||||
<el-input v-model="formData.memo" type="textarea" rows="4" clearable :placeholder="t('memoPlaceholder')" class="input-width"/>
|
||||
<el-input v-model.trim="formData.memo" type="textarea" rows="4" clearable :placeholder="t('memoPlaceholder')" class="input-width" maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('sort')" prop="sort">
|
||||
<el-input v-model="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
|
||||
<el-input v-model.trim="formData.sort" clearable :placeholder="t('sortPlaceholder')" class="input-width" @keyup="filterNumber($event)" />
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="memberLabelTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('labelName')" prop="label_name">
|
||||
<el-input v-model="memberLabelTableData.searchParam.label_name" :placeholder="t('labelNamePlaceholder')" />
|
||||
<el-input v-model.trim="memberLabelTableData.searchParam.label_name" :placeholder="t('labelNamePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadMemberLabelList()">{{ t('search') }}</el-button>
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-form :model="formData" label-width="150px" ref="formRef" class="page-form" v-loading="loading">
|
||||
<el-card class="box-card !border-none relative" shadow="never" v-if="formData">
|
||||
<h3 class="panel-title">{{ t('orderInfo') }}</h3>
|
||||
|
||||
<el-form-item :label="t('orderNo')">
|
||||
<div class="input-width">{{ formData.order_no }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderMoney')">
|
||||
<div class="input-width">{{ formData.order_money }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderDiscountMoney')">
|
||||
<div class="input-width">{{ formData.order_discount_money }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('member')">
|
||||
<div class="input-width">
|
||||
<div class="flex flex flex-col cursor-pointer" @click="toMember(formData.member_id)">
|
||||
<span>{{ formData.member.nickname || '' }}</span>
|
||||
<span>{{ formData.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('ip')">
|
||||
<div class="input-width">{{ formData.ip }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderFromName')">
|
||||
<div class="input-width">{{ formData.order_from_name }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderStatus')">
|
||||
<div class="input-width">{{ formData.order_status_info.name }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('payTypeName')">
|
||||
<div class="input-width">{{ formData.pay_type_name }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('createTime')">
|
||||
<div class="input-width">{{ formData.create_time || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('payTime')">
|
||||
<div class="input-width">{{ formData.pay_time || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('remark')">
|
||||
<div class="input-width">{{ formData.remark || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('memberMessage')">
|
||||
<div class="input-width">{{ formData.member_message || '' }}</div>
|
||||
</el-form-item>
|
||||
|
||||
</el-card>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { getRechargeOrderInfo } from '@/app/api/order'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
// import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const tabbarStore = useTabbarStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const orderId: number = parseInt(route.query.order_id)
|
||||
const loading = ref(true)
|
||||
|
||||
const formData: Record<string, any> | null = ref(null)
|
||||
|
||||
const setFormData = async (orderId: number = 0) => {
|
||||
loading.value = true
|
||||
formData.value = null
|
||||
await getRechargeOrderInfo(orderId).then(({data}) => {
|
||||
formData.value = data
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
loading.value = false
|
||||
}
|
||||
if (orderId) setFormData(orderId)
|
||||
else loading.value = false
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const back = () => {
|
||||
tabbarStore.removeTab(route.path)
|
||||
router.push({ path: '/finance/recharge' })
|
||||
}
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (memberId: number) => {
|
||||
router.push(`/member/detail?id=${memberId}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,290 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center mb-[5px]">
|
||||
<span class="text-page-title">{{ pageName }}</span>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">
|
||||
<el-row class="flex">
|
||||
<el-col :span="12" class="min-w-[100px]">
|
||||
<el-statistic
|
||||
:value="rechargeStatistics.recharge_money ? Number.parseFloat(rechargeStatistics.recharge_money).toFixed(2) : '0.00'">
|
||||
<template #title>
|
||||
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeMoney') }}</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="12" class="min-w-[100px]">
|
||||
<el-statistic
|
||||
:value="rechargeStatistics.recharge_refund_money ? Number.parseFloat(rechargeStatistics.recharge_refund_money).toFixed(2) : '0.00'">
|
||||
<template #title>
|
||||
<div class="text-[14px] mb-[9px]">{{ t('totalRechargeRefundMoney') }}</div>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('rechargeNo')" prop="order_no">
|
||||
<el-input v-model="orderTableData.searchParam.order_no" :placeholder="t('rechargeNoPlaceholder')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderFromName')" prop="order_from">
|
||||
<el-select v-model="orderTableData.searchParam.order_from" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item" :value="key" v-for="(item, key) in channelList" :key="key"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('orderStatus')" prop="order_status">
|
||||
<el-select v-model="orderTableData.searchParam.order_status" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item['name']" :value="item['status']" v-for="(item,index) in statusList" :key="index"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('createTime')" prop="create_time">
|
||||
<el-date-picker v-model="orderTableData.searchParam.create_time" type="datetimerange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
|
||||
:end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('rechargeMoney')">
|
||||
<div class="region-input">
|
||||
<el-form-item prop="start_money">
|
||||
<input type="text" :placeholder="t('startMoney')" v-model="orderTableData.searchParam.start_money">
|
||||
</el-form-item>
|
||||
<span class="separator">-</span>
|
||||
<el-form-item prop="end_money">
|
||||
<input type="text" :placeholder="t('endMoney')" v-model="orderTableData.searchParam.end_money">
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('payTime')">
|
||||
<el-date-picker v-model="orderTableData.searchParam.pay_time" type="datetimerange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
|
||||
:end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadOrderList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div class="mt-[16px]">
|
||||
<el-table :data="orderTableData.data" size="large" v-loading="orderTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !orderTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" :label="t('member')" align="left" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
<span>{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('rechargeNo')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column prop="order_money" :label="t('rechargeMoney')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column prop="order_from_name" :label="t('orderFromName')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column :label="t('orderStatus')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.order_status_info.name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="pay_type_name" :label="t('payTypeName')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column :label="t('createTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('payTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.pay_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="[1, 10].includes(row.order_status_info.status) && row.is_enable_refund && row.refund_status == 0"
|
||||
type="primary" link @click="refundFn(row)">{{ t('refundBtn') }}</el-button>
|
||||
|
||||
<template v-for="(item, index) in row.order_status_info.action" :key="index">
|
||||
<el-button type="primary" link @click="orderEvent(row, item.class)">{{ item.name }}</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="orderTableData.page" v-model:page-size="orderTableData.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="orderTableData.total"
|
||||
@size-change="loadOrderList()" @current-change="loadOrderList" />
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 是否退款 -->
|
||||
<el-dialog v-model="refundShowDialog" :title="t('refundBtn')" width="500px" :destroy-on-close="true">
|
||||
<p>{{ t('refundContent') }}</p>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="refundShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirmRefund" :loading="refundLoading">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getRechargeOrderStatusList, getRechargeOrderList, rechargeRefund, getRechargeStat } from '@/app/api/order'
|
||||
import { getChannelType } from '@/app/api/sys'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { AnyObject } from '@/types/global'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { img } from '@/utils/common'
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title
|
||||
const memberId: number = parseInt(route.query.id || 0)
|
||||
|
||||
const channelList = ref([])
|
||||
const setChannelList = async () => {
|
||||
channelList.value = await (await getChannelType({})).data
|
||||
}
|
||||
setChannelList()
|
||||
|
||||
const orderTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
order_no: '',
|
||||
order_status: '',
|
||||
member_id: memberId,
|
||||
create_time: [],
|
||||
pay_time: [],
|
||||
order_from: '',
|
||||
start_money: '',
|
||||
end_money: ''
|
||||
}
|
||||
})
|
||||
|
||||
const rechargeStatistics = ref([])
|
||||
const checkRechargeInfo = () => {
|
||||
getRechargeStat({
|
||||
member_id: memberId
|
||||
}).then(res => {
|
||||
rechargeStatistics.value = res.data
|
||||
})
|
||||
}
|
||||
checkRechargeInfo()
|
||||
|
||||
const statusList = ref([])
|
||||
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
|
||||
const setCategoryList = async () => {
|
||||
statusList.value = await (await getRechargeOrderStatusList()).data
|
||||
}
|
||||
setCategoryList()
|
||||
|
||||
/**
|
||||
* 获取文章列表
|
||||
*/
|
||||
const loadOrderList = (page: number = 1) => {
|
||||
orderTableData.loading = true
|
||||
orderTableData.page = page
|
||||
|
||||
getRechargeOrderList({
|
||||
page: orderTableData.page,
|
||||
limit: orderTableData.limit,
|
||||
...orderTableData.searchParam
|
||||
}).then(res => {
|
||||
orderTableData.loading = false
|
||||
orderTableData.data = res.data.data
|
||||
orderTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
orderTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadOrderList()
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
* @param data
|
||||
*/
|
||||
const infoEvent = (data: any) => {
|
||||
router.push(`/order/recharge/detail?order_id=${data.order_id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单操作
|
||||
*/
|
||||
const orderEvent = (data: any, type: string) => {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款操作
|
||||
*/
|
||||
const refundShowDialog = ref(false)
|
||||
let refundData: AnyObject | null = null
|
||||
const refundLoading = ref(false)
|
||||
|
||||
const refundFn = (data: AnyObject) => {
|
||||
refundShowDialog.value = true
|
||||
refundData = data
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认退款
|
||||
*/
|
||||
const confirmRefund = () => {
|
||||
if (refundLoading.value) return
|
||||
refundLoading.value = true
|
||||
|
||||
rechargeRefund(refundData?.order_id).then(res => {
|
||||
refundShowDialog.value = false
|
||||
refundLoading.value = false
|
||||
}).catch(() => {
|
||||
refundLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (memberId: number) => {
|
||||
router.push(`/member/detail?id=${memberId}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -1,238 +0,0 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex justify-between items-center mb-[5px]">
|
||||
<span class="text-page-title">{{ pageName }}</span>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none table-search-wra base-bg !px-[35px]" shadow="never">
|
||||
<el-row class="flex">
|
||||
<el-col :span="12">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="refundStat.refund_all_money"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('accumulateRefundMoney') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="statistic-card">
|
||||
<el-statistic :value="refundStat.refund_have_money"></el-statistic>
|
||||
<div class="statistic-footer">
|
||||
<div class="footer-item text-[14px] text-[#666]">
|
||||
<span>{{ t('haveRefundMoney') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card !border-none mb-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="refundTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('memberInfo')" prop="keywords">
|
||||
<el-input v-model="refundTableData.searchParam.keywords" class="w-[240px]" :placeholder="t('memberInfoPlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundNumber')" prop="refund_no">
|
||||
<el-input v-model="refundTableData.searchParam.refund_no" class="w-[240px]" :placeholder="t('refundNumberPlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('orderNumber')" prop="order_no">
|
||||
<el-input v-model="refundTableData.searchParam.order_no" class="w-[240px]" :placeholder="t('orderNumberPlaceholder')" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('refundStatus')" prop="status">
|
||||
<el-select v-model="refundTableData.searchParam.status" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item.name" :value="key" v-for="(item, key) in refundList" :key="key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundTime')" prop="create_time">
|
||||
<el-date-picker v-model="refundTableData.searchParam.create_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadRefundList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div>
|
||||
<el-table :data="refundTableData.data" size="large" v-loading="refundTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !refundTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column :show-overflow-tooltip="true" :label="t('memberInfo')" align="left" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.member.headimg" :src="img(row.member.headimg)" alt="">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/default_headimg.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
<span>{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="refund_no" :label="t('refundNumber')" align="center" min-width="200" />
|
||||
<el-table-column prop="item.item_name" :label="t('refundSource')" align="center" min-width="140" />
|
||||
<el-table-column prop="money" :label="t('refundAmount')" align="center" min-width="140" />
|
||||
<el-table-column :label="t('refundTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('statusName')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.status_name || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="130">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="refundTableData.page" v-model:page-size="refundTableData.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="refundTableData.total"
|
||||
@size-change="loadRefundList()" @current-change="loadRefundList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="refundInfoShowDialog" :title="t('refundDetail')" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="refundInfo" label-width="120px" ref="formRef" :rules="formRules" class="page-form">
|
||||
<el-form-item :label="t('nickname')">
|
||||
<div class="input-width"> {{ refundInfo.member.nickname }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundSource')">
|
||||
<div class="input-width"> {{ refundInfo.item.item_name }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundAmount')">
|
||||
<div class="input-width"> {{ refundInfo.money }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('orderNumber')">
|
||||
<div class="input-width"> {{ refundInfo.item.order_no }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundNumber')">
|
||||
<div class="input-width"> {{ refundInfo.refund_no }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('refundTime')">
|
||||
<div class="input-width"> {{ refundInfo.create_time }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('statusName')">
|
||||
<div class="input-width"> {{ refundInfo.status_name }} </div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="refundInfoShowDialog = false">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { getRechargeRefund, getRechargeRefundStatus, getRechargeRefundStat } from '@/app/api/order'
|
||||
import { FormInstance } from 'element-plus'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
const refundTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
refund_no: '',
|
||||
// member_id,
|
||||
create_time: [],
|
||||
status: '',
|
||||
keywords: '',
|
||||
order_no: ''
|
||||
}
|
||||
})
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
formEl.resetFields()
|
||||
loadRefundList()
|
||||
}
|
||||
/**
|
||||
* 获取退款列表
|
||||
*/
|
||||
const loadRefundList = (page: number = 1) => {
|
||||
refundTableData.loading = true
|
||||
refundTableData.page = page
|
||||
|
||||
getRechargeRefund({
|
||||
page: refundTableData.page,
|
||||
limit: refundTableData.limit,
|
||||
...refundTableData.searchParam
|
||||
}).then(res => {
|
||||
refundTableData.loading = false
|
||||
refundTableData.data = res.data.data
|
||||
refundTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
refundTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadRefundList()
|
||||
|
||||
const refundList = ref([])
|
||||
const checkRefundList = () => {
|
||||
getRechargeRefundStatus().then(res => {
|
||||
refundList.value = res.data
|
||||
})
|
||||
}
|
||||
checkRefundList()
|
||||
|
||||
const refundStat = reactive({
|
||||
refund_all_money: 0.00,
|
||||
refund_have_money: 0.00,
|
||||
refund_Success_money: 0.00,
|
||||
refund_fail_moey: 0.00
|
||||
})
|
||||
const checkRefundStat = () => {
|
||||
getRechargeRefundStat().then(res => {
|
||||
refundStat.refund_all_money = res.data.all.money
|
||||
refundStat.refund_have_money = res.data.have.money
|
||||
refundStat.refund_Success_money = res.data['3'].money
|
||||
refundStat.refund_fail_moey = res.data['-1'].money
|
||||
})
|
||||
}
|
||||
checkRefundStat()
|
||||
|
||||
const refundInfoShowDialog = ref(false)
|
||||
const refundInfo = ref({})
|
||||
|
||||
const infoEvent = (info:any) => {
|
||||
refundInfo.value = info
|
||||
refundInfoShowDialog.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (memberId: number) => {
|
||||
router.push(`/member/detail?id=${memberId}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -11,10 +11,10 @@
|
||||
<el-card class="box-card !border-none" shadow="never" v-loading="loading">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form">
|
||||
<el-form-item :label="t('type')">
|
||||
<el-input v-model="formData.agreement_key_name" readonly class="input-width" />
|
||||
<el-input v-model.trim="formData.agreement_key_name" readonly class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" clearable :placeholder="t('titlePlaceholder')" class="input-width" maxlength="20" />
|
||||
<el-input v-model.trim="formData.title" clearable :placeholder="t('titlePlaceholder')" class="input-width" maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('content')">
|
||||
<editor v-model="formData.content" />
|
||||
|
||||
@ -6,22 +6,20 @@
|
||||
<div class="input-width"> {{ formData.name }} </div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('messageType')">
|
||||
<div v-if="formData.message_type == 'sms'">{{ t('sms') }}</div>
|
||||
<div v-if="formData.message_type == 'wechat'">{{ t('wechat') }}</div>
|
||||
<div v-if="formData.message_type == 'weapp'">{{ t('weapp') }}</div>
|
||||
<el-form-item :label="t('smsType')">
|
||||
<div class="input-width"> {{ formData.sms_type_name }} </div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('messageData')">
|
||||
<!-- <el-form-item :label="t('messageData')">
|
||||
<div class="input-width"> {{ formData.message_data }} </div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item :label="t('nickname')">
|
||||
<!-- <el-form-item :label="t('nickname')">
|
||||
<div class="input-width"> {{ formData.nickname }} </div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item :label="t('receiver')">
|
||||
<div class="input-width"> {{ formData.receiver }} </div>
|
||||
<div class="input-width"> {{ formData.mobile }} </div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('createTime')">
|
||||
@ -57,7 +55,8 @@ const initialFormData = {
|
||||
message_type: '',
|
||||
name: '',
|
||||
nickname: '',
|
||||
receiver: ''
|
||||
mobile: '',
|
||||
sms_type_name: ''
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<el-form :model="formData" label-width="110px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
|
||||
<el-form-item :label="t('appId')" prop="config.app_id">
|
||||
<el-input v-model="formData.config.app_id" :placeholder="t('appIdPlaceholder')" class="input-width" maxlength="32" show-word-limit clearable />
|
||||
<el-input v-model.trim="formData.config.app_id" :placeholder="t('appIdPlaceholder')" class="input-width" maxlength="32" show-word-limit clearable />
|
||||
<div class="form-tip">{{ t('appIdTips') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('appSecretCert')" prop="config.app_secret_cert">
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<el-form-item :label="t('appPublicCertPath')" prop="config.app_public_cert_path">
|
||||
<div class="input-width">
|
||||
<upload-file v-model="formData.config.app_public_cert_path" api="sys/document/aliyun" />
|
||||
<upload-file v-model.trim="formData.config.app_public_cert_path" api="sys/document/aliyun" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
@ -4,13 +4,13 @@
|
||||
v-loading="loading">
|
||||
|
||||
<el-form-item :label="t('mchId')" prop="config.mch_id">
|
||||
<el-input v-model="formData.config.mch_id" :placeholder="t('mchIdPlaceholder')" class="input-width"
|
||||
<el-input v-model.trim="formData.config.mch_id" :placeholder="t('mchIdPlaceholder')" class="input-width"
|
||||
maxlength="32" show-word-limit clearable />
|
||||
<div class="form-tip">{{ t('mchIdTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('mchSecretKey')" prop="config.mch_secret_key">
|
||||
<el-input v-model="formData.config.mch_secret_key" :placeholder="t('mchSecretKeyPlaceholder')"
|
||||
<el-input v-model.trim="formData.config.mch_secret_key" :placeholder="t('mchSecretKeyPlaceholder')"
|
||||
class="input-width" maxlength="32" show-word-limit clearable />
|
||||
<div class="form-tip">{{ t('mchSecretKeyTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
@ -52,7 +52,9 @@ const initialFormData = {
|
||||
sign: '',
|
||||
access_key: '',
|
||||
secret_key: '',
|
||||
is_use: ''
|
||||
is_use: '',
|
||||
app_id:'',
|
||||
secret_id:'',
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<h3 class="panel-title">{{ t('mapSetting') }}</h3>
|
||||
<el-form-item :label="t('mapKey')" prop="site_name">
|
||||
<el-input v-model="formData.key" class="input-width" clearable />
|
||||
<el-input v-model.trim="formData.key" class="input-width" clearable />
|
||||
<span class="ml-2 cursor-pointer tutorial-btn" @click="tutorialFn">{{ t('clickTutorial') }}</span>
|
||||
<span class="ml-2 cursor-pointer secret-btn" @click="secretlFn">{{ t('clickSecretKey') }}</span>
|
||||
</el-form-item>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('length')" prop="length">
|
||||
<el-input v-model="formData.length" :placeholder="t('lengthPlaceholder')" class="input-width" clearable @keyup="filterNumber($event)" @change="getMemberNo(ruleFormRef)"/>
|
||||
<el-input v-model.trim="formData.length" :placeholder="t('lengthPlaceholder')" class="input-width" clearable @keyup="filterNumber($event)" @change="getMemberNo(ruleFormRef)" @blur="formData.length = $event.target.value"/>
|
||||
<div class="form-tip">{{ t('lengthTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
@ -53,7 +53,7 @@ const formRules = reactive<FormRules>({
|
||||
{ validator: prefixVerify, trigger: 'blur' }
|
||||
],
|
||||
length: [
|
||||
{ required: true, message: t('lengthPlaceholder'), trigger: 'blur' },
|
||||
{ required: true, message: t('lengthPlaceholder'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (parseInt(value) > 30 || parseInt(value) - formData.prefix.length < 4) {
|
||||
|
||||
@ -38,16 +38,9 @@
|
||||
</template>
|
||||
|
||||
<el-table-column prop="name" :label="t('noticeKey')" min-width="120" />
|
||||
<el-table-column prop="notice_type" :label="t('noticeType')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.notice_type == 'sms'">{{ t('sms') }}</div>
|
||||
<div v-if="row.notice_type == 'wechat'">{{ t('wechat') }}</div>
|
||||
<div v-if="row.notice_type == 'weapp'">{{ t('weapp') }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="sms_type_name" :label="t('smsType')" min-width="120"/>
|
||||
|
||||
<el-table-column prop="nickname" :label="t('nickname')" min-width="120" />
|
||||
<el-table-column prop="receiver" :label="t('receiver')" min-width="120" />
|
||||
<el-table-column prop="mobile" :label="t('receiver')" min-width="120" />
|
||||
<el-table-column prop="create_time" :label="t('createTime')" min-width="140" />
|
||||
|
||||
<el-table-column :label="t('operation')" align="right" fixed="right" width="100">
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<h3 class="panel-title !text-sm">{{ t('websiteInfo') }}</h3>
|
||||
|
||||
<el-form-item :label="t('siteName')" prop="site_name">
|
||||
<el-input v-model="formData.site_name" :placeholder="t('siteNamePlaceholder')" class="input-width" clearable maxlength="20" />
|
||||
<el-input v-model.trim="formData.site_name" :placeholder="t('siteNamePlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('logo')">
|
||||
@ -23,17 +23,17 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('keywords')">
|
||||
<el-input v-model="formData.keywords" :placeholder="t('keywordsPlaceholder')" class="input-width" clearable maxlength="20" />
|
||||
<el-input v-model="formData.keywords" :placeholder="t('keywordsPlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('desc')">
|
||||
<el-input v-model="formData.desc" type="textarea" rows="4" clearable :placeholder="t('descPlaceholder')" class="input-width" maxlength="100" />
|
||||
<el-input v-model="formData.desc" type="textarea" rows="4" clearable :placeholder="t('descPlaceholder')" class="input-width" maxlength="100" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<h3 class="panel-title !text-sm">{{ t('frontEndInfo') }}</h3>
|
||||
<el-form-item :label="t('frontEndName')">
|
||||
<el-input v-model="formData.front_end_name" :placeholder="t('frontEndNamePlaceholder')" class="input-width" clearable maxlength="20" />
|
||||
<el-input v-model="formData.front_end_name" :placeholder="t('frontEndNamePlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('frontEndLogo')">
|
||||
@ -43,7 +43,7 @@
|
||||
<el-card class="box-card !border-none" shadow="never" v-if="app_type == 'admin'">
|
||||
<h3 class="panel-title !text-sm">{{ t('serviceInformation') }}</h3>
|
||||
<el-form-item :label="t('contactsTel')">
|
||||
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" />
|
||||
<el-input v-model="formData.tel" :placeholder="t('contactsTelPlaceholder')" class="input-width" clearable maxlength="20" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('wechatCode')">
|
||||
<upload-image v-model="formData.wechat_code" />
|
||||
|
||||
@ -30,9 +30,7 @@
|
||||
|
||||
<el-form-item :label="t('status')">
|
||||
<template #default="{ }">
|
||||
<el-tag class="ml-2" type="success" v-if="formData.status == 1">{{ t('statusNormal') }}</el-tag>
|
||||
<el-tag class="ml-2" type="error" v-if="formData.status == 0">{{t('statusDeactivate') }}</el-tag>
|
||||
<el-tag class="ml-2" type="error" v-if="formData.status == 2">{{t('statusExpire') }}</el-tag>
|
||||
<el-tag class="ml-2" :type="formData.status == 1?'success':'error'">{{ formData.status_name }}</el-tag>
|
||||
</template>
|
||||
</el-form-item>
|
||||
|
||||
@ -146,7 +144,8 @@ const initialFormData = {
|
||||
group_name: '',
|
||||
status: 0,
|
||||
create_time: 0,
|
||||
site_addons: []
|
||||
site_addons: [],
|
||||
status_name:''
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
|
||||
@ -66,12 +66,12 @@
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('status')" min-width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ row.status_name }}</el-tag>
|
||||
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ row.site_status_name }}</el-tag>
|
||||
<el-tag class="ml-2" type="error" v-else-if="row.status == 3">
|
||||
{{ row.status_name }}
|
||||
{{ row.site_status_name }}
|
||||
</el-tag>
|
||||
<el-tag class="ml-2" type="error" v-else>
|
||||
{{ row.status_name }}
|
||||
{{ row.site_status_name }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="border border-color">
|
||||
<toolbar class="border-b border-color" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
|
||||
<wang-editor :style="{ height, 'overflow-y': 'hidden', width: '100%' }" :defaultConfig="editorConfig" :mode="mode" v-model="content" @onCreated="handleCreated" />
|
||||
<wang-editor :style="{ height, 'overflow-y': 'hidden', width: '100%' }" :defaultConfig="editorConfig" :mode="mode" v-model="content" @onCreated="handleCreated" @onBlur="handleBlur" />
|
||||
<upload-attachment type="image" ref="imageRef" :limit="10" @confirm="imageSelect" />
|
||||
<upload-attachment type="video" ref="videoRef" @confirm="videoSelect" />
|
||||
</div>
|
||||
@ -31,7 +31,7 @@ const prop = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const emit = defineEmits(['update:modelValue','handleBlur'])
|
||||
|
||||
const imageRef: Record<string, any> | null = ref(null)
|
||||
const videoRef: Record<string, any> | null = ref(null)
|
||||
@ -86,7 +86,10 @@ const videoSelect = (data: Record<string, any>) => {
|
||||
const handleCreated = (editor: IDomEditor) => {
|
||||
editorRef.value = editor
|
||||
}
|
||||
|
||||
//编辑器 blur 时的回调函数。
|
||||
const handleBlur = (editor: IDomEditor)=>{
|
||||
emit('handleBlur',editor)
|
||||
}
|
||||
/**
|
||||
* 组件销毁时,也及时销毁编辑器
|
||||
*/
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<upload-attachment :limit="limit" @confirm="confirmSelect" v-else>
|
||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||
<div class="w-full h-full flex items-center justify-center flex-col content-wrap">
|
||||
<icon name="element-Plus" size="20px" color="var(--el-text-color-secondary)" />
|
||||
<div class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || t('upload.root') }}</div>
|
||||
</div>
|
||||
@ -33,7 +33,7 @@
|
||||
</div>
|
||||
<div class="rounded cursor-pointer overflow-hidden relative border border-dashed border-color" :style="style" v-if="images.data.length < limit">
|
||||
<upload-attachment :limit="limit" @confirm="confirmSelect">
|
||||
<div class="w-full h-full flex items-center justify-center flex-col">
|
||||
<div class="w-full h-full flex items-center justify-center flex-col content-wrap">
|
||||
<icon name="element-Plus" size="20px" color="var(--el-text-color-secondary)" />
|
||||
<div class="leading-none text-xs mt-[10px] text-secondary">{{ imageText || t('upload.root') }}</div>
|
||||
</div>
|
||||
|
||||
@ -113,6 +113,7 @@
|
||||
"preview": "预览",
|
||||
"emptyApp": "暂未安装任何应用",
|
||||
"newInfo": "最新消息",
|
||||
"visitWap": "访问店铺",
|
||||
"mapSetting": "地图设置",
|
||||
"mapKey": "腾讯地图KEY",
|
||||
"indexTemplate": "首页模版",
|
||||
|
||||
@ -66,7 +66,6 @@ const props = defineProps({
|
||||
type: String
|
||||
}
|
||||
})
|
||||
console.log("props",props.routePath)
|
||||
|
||||
const meta = computed(() => props.routes.meta)
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
<el-col :span="12">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<!-- 预览 只有站点时展示-->
|
||||
<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>
|
||||
<!-- 切换语言 -->
|
||||
<!-- <div class="navbar-item flex items-center h-full cursor-pointer">
|
||||
@ -65,7 +66,7 @@ import userInfo from './user-info.vue'
|
||||
import { useFullscreen } from '@vueuse/core'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useRoute,useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
@ -74,6 +75,7 @@ const { toggle: toggleFullscreen } = useFullscreen()
|
||||
const systemStore = useSystemStore()
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
const dark = computed(() => {
|
||||
@ -147,6 +149,17 @@ const breadcrumb = computed(() => {
|
||||
return matched
|
||||
})
|
||||
|
||||
// 跳转去预览
|
||||
const toPreview = () => {
|
||||
const url = router.resolve({
|
||||
path: '/preview/wap',
|
||||
query: {
|
||||
page:'/'
|
||||
}
|
||||
})
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
// const backFn = () => {
|
||||
// router.go(-1)
|
||||
|
||||
@ -37,7 +37,6 @@ const route = useRoute()
|
||||
const siteInfo = userStore.siteInfo
|
||||
|
||||
const menuActive = computed(() => String(route.name))
|
||||
console.log("userStore.routers",userStore.routers)
|
||||
userStore.routers.forEach((item, index) => {
|
||||
item.meta.class = 1
|
||||
if (item.children) {
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
<icon name="element-Refresh" />
|
||||
</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>
|
||||
<!-- 切换首页 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer" v-if="appType == 'site'" @click="checkIndexList">
|
||||
@ -159,6 +160,17 @@ const breadcrumb = computed(() => {
|
||||
return matched
|
||||
})
|
||||
|
||||
// 跳转去预览
|
||||
const toPreview = () => {
|
||||
const url = router.resolve({
|
||||
path: '/preview/wap',
|
||||
query: {
|
||||
page:'/'
|
||||
}
|
||||
})
|
||||
window.open(url.href)
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const backFn = () => {
|
||||
router.go(-1)
|
||||
|
||||
@ -138,7 +138,6 @@ router.beforeEach(async (to, from, next) => {
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
next({ path: loginPath, query: { redirect: to.fullPath } })
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,11 +39,15 @@ const useDiyStore = defineStore('diy', {
|
||||
'#c7158577'
|
||||
],
|
||||
components: [], // 组件集合
|
||||
position: ['fixed', 'top_fixed','right_fixed','bottom_fixed','left_fixed'],
|
||||
global: {
|
||||
title: "页面", // 页面标题
|
||||
|
||||
pageBgColor: "", // 页面背景颜色
|
||||
pageStartBgColor: "", // 页面背景颜色(开始)
|
||||
pageEndBgColor: "", // 页面背景颜色(结束)
|
||||
pageGradientAngle: 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
bgUrl: '', // 页面背景图片
|
||||
bgHeightScale: 0, // 页面背景高度比例,单位%,0为高度自适应
|
||||
imgWidth: '', // 页面背景图片宽度
|
||||
imgHeight: '', // 页面背景图片高度
|
||||
|
||||
@ -74,9 +78,15 @@ const useDiyStore = defineStore('diy', {
|
||||
// 公共模板属性,所有组件都继承,无需重复定义,组件内部根据业务自行调用
|
||||
template: {
|
||||
textColor: "#303133", // 文字颜色
|
||||
pageBgColor: '', // 底部背景颜色
|
||||
pageStartBgColor: "", // 组件底部背景颜色(开始)
|
||||
pageEndBgColor: "", // 组件底部背景颜色(结束)
|
||||
pageGradientAngle: 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
|
||||
componentBgColor: '', // 组件背景颜色
|
||||
componentBgUrl: '', // 组件背景图片
|
||||
componentBgAlpha: 2, // 组件背景图片的透明度,0~10
|
||||
componentStartBgColor: '', // 组件背景颜色(开始)
|
||||
componentEndBgColor: '', // 组件背景颜色(结束)
|
||||
componentGradientAngle: 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
topRounded: 0, // 组件上圆角
|
||||
bottomRounded: 0, // 组件下圆角
|
||||
|
||||
@ -111,8 +121,11 @@ const useDiyStore = defineStore('diy', {
|
||||
this.global = {
|
||||
title: "页面", // 页面标题
|
||||
|
||||
pageBgColor: "", // 页面背景颜色
|
||||
pageStartBgColor: "", // 页面背景颜色(开始)
|
||||
pageEndBgColor: "", // 页面背景颜色(结束)
|
||||
pageGradientAngle: 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
bgUrl: '', // 页面背景图片
|
||||
bgHeightScale: 100, // 页面背景高度比例,单位%
|
||||
imgWidth: '', // 页面背景图片宽度
|
||||
imgHeight: '', // 页面背景图片高度
|
||||
|
||||
@ -143,9 +156,15 @@ const useDiyStore = defineStore('diy', {
|
||||
// 公共模板属性,所有组件都继承,无需重复定义,组件内部根据业务自行调用
|
||||
template: {
|
||||
textColor: "#303133", // 文字颜色
|
||||
pageBgColor: '', // 底部背景颜色
|
||||
pageStartBgColor: "", // 组件底部背景颜色(开始)
|
||||
pageEndBgColor: "", // 组件底部背景颜色(结束)
|
||||
pageGradientAngle: 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
|
||||
componentBgColor: '', // 组件背景颜色
|
||||
componentBgUrl: '', // 组件背景图片
|
||||
componentBgAlpha: 2, // 组件背景图片的透明度
|
||||
componentStartBgColor: '', // 组件背景颜色(开始)
|
||||
componentEndBgColor: '', // 组件背景颜色(结束)
|
||||
componentGradientAngle: 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
topRounded: 0, // 组件上圆角
|
||||
bottomRounded: 0, // 组件下圆角
|
||||
|
||||
@ -182,25 +201,36 @@ const useDiyStore = defineStore('diy', {
|
||||
delete component.type;
|
||||
delete component.icon;
|
||||
|
||||
// 默认继承全局属性
|
||||
let template = cloneDeep(this.global.template);
|
||||
Object.assign(component, template);
|
||||
|
||||
if(component.template){
|
||||
// 按照组件初始的属性加载
|
||||
// 按照组件初始的属性加载覆盖
|
||||
Object.assign(component, component.template);
|
||||
delete component.template;
|
||||
}else{
|
||||
// 默认继承全局属性
|
||||
let template = cloneDeep(this.global.template);
|
||||
Object.assign(component, template);
|
||||
}
|
||||
|
||||
if (!this.checkComponentIsAdd(component)) return;
|
||||
|
||||
if (this.currentIndex === -99) {
|
||||
// 置顶组件,只能在第一个位置中添加
|
||||
if(component.position && this.position.indexOf(component.position) != -1){
|
||||
|
||||
this.currentIndex = 0;
|
||||
// 指定位置添加组件
|
||||
this.value.splice(0, 0, component);
|
||||
|
||||
}else if (this.currentIndex === -99) {
|
||||
|
||||
this.value.push(component);
|
||||
// 添加组件后(不是编辑调用的),选择最后一个
|
||||
this.currentIndex = this.value.length - 1;
|
||||
|
||||
} else {
|
||||
|
||||
// 指定位置添加组件
|
||||
this.value.splice(++this.currentIndex, 0, component);
|
||||
|
||||
}
|
||||
|
||||
this.currentComponent = component.path;
|
||||
@ -271,6 +301,14 @@ const useDiyStore = defineStore('diy', {
|
||||
var temp2 = cloneDeep(this.value[prevIndex]); // 上个组件
|
||||
temp2.id = this.generateRandom(); // 更新id,刷新组件数据
|
||||
|
||||
if(temp.position && this.position.indexOf(temp.position) != -1){
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('componentNotMoved')}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.value[this.currentIndex] = temp2;
|
||||
this.value[prevIndex] = temp;
|
||||
|
||||
@ -288,6 +326,14 @@ const useDiyStore = defineStore('diy', {
|
||||
var temp2 = cloneDeep(this.value[nextIndex]); // 下个组件
|
||||
temp2.id = this.generateRandom(); // 更新id,刷新组件数据
|
||||
|
||||
if(temp.position && this.position.indexOf(temp.position) != -1){
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('componentNotMoved')}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.value[this.currentIndex] = temp2;
|
||||
this.value[nextIndex] = temp;
|
||||
|
||||
@ -309,6 +355,14 @@ const useDiyStore = defineStore('diy', {
|
||||
return;
|
||||
}
|
||||
|
||||
if(component.position && this.position.indexOf(component.position) != -1){
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${t('notCopy')},${component.componentTitle}${t('componentCanOnlyAdd')}1${t('piece')}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var index = this.currentIndex + 1;
|
||||
this.value.splice(index, 0, component);
|
||||
|
||||
|
||||
@ -257,3 +257,7 @@ html.dark {
|
||||
// background-color: #636363 !important;
|
||||
// opacity: 1 !important;
|
||||
//}
|
||||
|
||||
:root input:-webkit-autofill, textarea:-webkit-autofill, select:-webkit-autofill {
|
||||
box-shadow: 0 0 50px 50px white inset;
|
||||
}
|
||||
@ -1 +1,2 @@
|
||||
/* addon icon */
|
||||
@import "addon/tourism/iconfont.css";
|
||||
@import "addon/o2o/iconfont.css";
|
||||
|
||||
38
admin/src/styles/icon/addon/o2o/iconfont.css
Normal file
38
admin/src/styles/icon/addon/o2o/iconfont.css
Normal file
@ -0,0 +1,38 @@
|
||||
@font-face {
|
||||
font-family: "o2o"; /* Project id 4412516 */
|
||||
src: url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff2?t=1705720131974') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.woff?t=1705720131974') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4412516_cacqsbew46.ttf?t=1705720131974') format('truetype');
|
||||
}
|
||||
|
||||
.o2o {
|
||||
font-family: "o2o" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.o2o-icon-danhanghuadong:before {
|
||||
content: "\e66f";
|
||||
}
|
||||
|
||||
.o2o-icon-yuanjiao:before {
|
||||
content: "\e6c0";
|
||||
}
|
||||
|
||||
.o2o-icon-gl-square:before {
|
||||
content: "\ea92";
|
||||
}
|
||||
|
||||
.o2o-icon-sousuo12:before {
|
||||
content: "\e699";
|
||||
}
|
||||
|
||||
.o2o-icon-sousuo11:before {
|
||||
content: "\e6d4";
|
||||
}
|
||||
|
||||
.o2o-icon-jishi:before {
|
||||
content: "\e600";
|
||||
}
|
||||
51
admin/src/styles/icon/addon/o2o/iconfont.json
Normal file
51
admin/src/styles/icon/addon/o2o/iconfont.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"id": "4412516",
|
||||
"name": "上门服务",
|
||||
"font_family": "o2o",
|
||||
"css_prefix_text": "o2o-icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "30621139",
|
||||
"name": "单行滑动",
|
||||
"font_class": "danhanghuadong",
|
||||
"unicode": "e66f",
|
||||
"unicode_decimal": 58991
|
||||
},
|
||||
{
|
||||
"icon_id": "7149037",
|
||||
"name": "圆角",
|
||||
"font_class": "yuanjiao",
|
||||
"unicode": "e6c0",
|
||||
"unicode_decimal": 59072
|
||||
},
|
||||
{
|
||||
"icon_id": "7594344",
|
||||
"name": "20gl-square",
|
||||
"font_class": "gl-square",
|
||||
"unicode": "ea92",
|
||||
"unicode_decimal": 60050
|
||||
},
|
||||
{
|
||||
"icon_id": "10133070",
|
||||
"name": "搜索",
|
||||
"font_class": "sousuo12",
|
||||
"unicode": "e699",
|
||||
"unicode_decimal": 59033
|
||||
},
|
||||
{
|
||||
"icon_id": "14652583",
|
||||
"name": "搜索",
|
||||
"font_class": "sousuo11",
|
||||
"unicode": "e6d4",
|
||||
"unicode_decimal": 59092
|
||||
},
|
||||
{
|
||||
"icon_id": "6818781",
|
||||
"name": "技师",
|
||||
"font_class": "jishi",
|
||||
"unicode": "e600",
|
||||
"unicode_decimal": 58880
|
||||
}
|
||||
]
|
||||
}
|
||||
58
admin/src/styles/icon/addon/tourism/iconfont.css
Normal file
58
admin/src/styles/icon/addon/tourism/iconfont.css
Normal file
@ -0,0 +1,58 @@
|
||||
@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";
|
||||
}
|
||||
86
admin/src/styles/icon/addon/tourism/iconfont.json
Normal file
86
admin/src/styles/icon/addon/tourism/iconfont.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"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_46xoryy5l7v.woff2?t=1701067532618') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_46xoryy5l7v.woff?t=1701067532618') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_46xoryy5l7v.ttf?t=1701067532618') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_au7p2pnufj8.woff2?t=1711684151959') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_au7p2pnufj8.woff?t=1711684151959') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_au7p2pnufj8.ttf?t=1711684151959') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,94 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconfenxiang:before {
|
||||
content: "\e655";
|
||||
}
|
||||
|
||||
.iconico:before {
|
||||
content: "\e63f";
|
||||
}
|
||||
|
||||
.iconhuojian1:before {
|
||||
content: "\e633";
|
||||
}
|
||||
|
||||
.iconkaifazujian:before {
|
||||
content: "\e640";
|
||||
}
|
||||
|
||||
.iconzuoshangjiao:before {
|
||||
content: "\e700";
|
||||
}
|
||||
|
||||
.iconyoushangjiao:before {
|
||||
content: "\e701";
|
||||
}
|
||||
|
||||
.iconyouxiajiao:before {
|
||||
content: "\e702";
|
||||
}
|
||||
|
||||
.iconzuoxiajiao:before {
|
||||
content: "\e703";
|
||||
}
|
||||
|
||||
.iconfudonganniu1:before {
|
||||
content: "\e630";
|
||||
}
|
||||
|
||||
.iconshangpinliebiaohengxianghuadong:before {
|
||||
content: "\e926";
|
||||
}
|
||||
|
||||
.iconhengxianghuadong:before {
|
||||
content: "\e63e";
|
||||
}
|
||||
|
||||
.iconduoshangpinzu:before {
|
||||
content: "\e650";
|
||||
}
|
||||
|
||||
.iconsousuokuang:before {
|
||||
content: "\e65b";
|
||||
}
|
||||
|
||||
.iconicon_congzuodaoyou:before {
|
||||
content: "\e7eb";
|
||||
}
|
||||
|
||||
.iconicon_congshangdaoxia:before {
|
||||
content: "\e7ec";
|
||||
}
|
||||
|
||||
.iconmap-connect:before {
|
||||
content: "\ea02";
|
||||
}
|
||||
|
||||
.iconmap-link:before {
|
||||
content: "\ea01";
|
||||
}
|
||||
|
||||
.iconfuwenben1:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.iconfuzhuxian1:before {
|
||||
content: "\e646";
|
||||
}
|
||||
|
||||
.iconyouhuiquan1:before {
|
||||
content: "\e665";
|
||||
}
|
||||
|
||||
.iconjishi:before {
|
||||
content: "\e749";
|
||||
}
|
||||
|
||||
.iconbanbenqiehuan:before {
|
||||
content: "\e792";
|
||||
}
|
||||
|
||||
.icontuichudenglu:before {
|
||||
content: "\e64a";
|
||||
}
|
||||
|
||||
@ -5,6 +5,188 @@
|
||||
"css_prefix_text": "icon",
|
||||
"description": "系统图标",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "2672195",
|
||||
"name": "分享",
|
||||
"font_class": "fenxiang",
|
||||
"unicode": "e655",
|
||||
"unicode_decimal": 58965
|
||||
},
|
||||
{
|
||||
"icon_id": "6360240",
|
||||
"name": "火箭",
|
||||
"font_class": "ico",
|
||||
"unicode": "e63f",
|
||||
"unicode_decimal": 58943
|
||||
},
|
||||
{
|
||||
"icon_id": "12084141",
|
||||
"name": "开发组件",
|
||||
"font_class": "kaifazujian",
|
||||
"unicode": "e640",
|
||||
"unicode_decimal": 58944
|
||||
},
|
||||
{
|
||||
"icon_id": "10879698",
|
||||
"name": "左上角",
|
||||
"font_class": "zuoshangjiao",
|
||||
"unicode": "e700",
|
||||
"unicode_decimal": 59136
|
||||
},
|
||||
{
|
||||
"icon_id": "10879728",
|
||||
"name": "右上角",
|
||||
"font_class": "youshangjiao",
|
||||
"unicode": "e701",
|
||||
"unicode_decimal": 59137
|
||||
},
|
||||
{
|
||||
"icon_id": "10879730",
|
||||
"name": "右下角",
|
||||
"font_class": "youxiajiao",
|
||||
"unicode": "e702",
|
||||
"unicode_decimal": 59138
|
||||
},
|
||||
{
|
||||
"icon_id": "10879766",
|
||||
"name": "左下角",
|
||||
"font_class": "zuoxiajiao",
|
||||
"unicode": "e703",
|
||||
"unicode_decimal": 59139
|
||||
},
|
||||
{
|
||||
"icon_id": "30454123",
|
||||
"name": "浮动按钮",
|
||||
"font_class": "fudonganniu1",
|
||||
"unicode": "e630",
|
||||
"unicode_decimal": 58928
|
||||
},
|
||||
{
|
||||
"icon_id": "26585483",
|
||||
"name": "商品列表横向滑动",
|
||||
"font_class": "shangpinliebiaohengxianghuadong",
|
||||
"unicode": "e926",
|
||||
"unicode_decimal": 59686
|
||||
},
|
||||
{
|
||||
"icon_id": "30244188",
|
||||
"name": "横向滑动",
|
||||
"font_class": "hengxianghuadong",
|
||||
"unicode": "e63e",
|
||||
"unicode_decimal": 58942
|
||||
},
|
||||
{
|
||||
"icon_id": "30454129",
|
||||
"name": "多商品组",
|
||||
"font_class": "duoshangpinzu",
|
||||
"unicode": "e650",
|
||||
"unicode_decimal": 58960
|
||||
},
|
||||
{
|
||||
"icon_id": "30454142",
|
||||
"name": "搜索框",
|
||||
"font_class": "sousuokuang",
|
||||
"unicode": "e65b",
|
||||
"unicode_decimal": 58971
|
||||
},
|
||||
{
|
||||
"icon_id": "8960779",
|
||||
"name": "icon_从左到右",
|
||||
"font_class": "icon_congzuodaoyou",
|
||||
"unicode": "e7eb",
|
||||
"unicode_decimal": 59371
|
||||
},
|
||||
{
|
||||
"icon_id": "8960781",
|
||||
"name": "icon_从上到下",
|
||||
"font_class": "icon_congshangdaoxia",
|
||||
"unicode": "e7ec",
|
||||
"unicode_decimal": 59372
|
||||
},
|
||||
{
|
||||
"icon_id": "18170999",
|
||||
"name": "地图连线,连线,连接",
|
||||
"font_class": "map-connect",
|
||||
"unicode": "ea02",
|
||||
"unicode_decimal": 59906
|
||||
},
|
||||
{
|
||||
"icon_id": "18170996",
|
||||
"name": "地图连线竖,连接,连线",
|
||||
"font_class": "map-link",
|
||||
"unicode": "ea01",
|
||||
"unicode_decimal": 59905
|
||||
},
|
||||
{
|
||||
"icon_id": "30454117",
|
||||
"name": "富文本",
|
||||
"font_class": "fuwenben1",
|
||||
"unicode": "e62f",
|
||||
"unicode_decimal": 58927
|
||||
},
|
||||
{
|
||||
"icon_id": "30454130",
|
||||
"name": "icon-kfckfc",
|
||||
"font_class": "fuzhuxian1",
|
||||
"unicode": "e646",
|
||||
"unicode_decimal": 58950
|
||||
},
|
||||
{
|
||||
"icon_id": "30454145",
|
||||
"name": "优惠券",
|
||||
"font_class": "youhuiquan1",
|
||||
"unicode": "e665",
|
||||
"unicode_decimal": 58981
|
||||
},
|
||||
{
|
||||
"icon_id": "5616072",
|
||||
"name": "技师",
|
||||
"font_class": "jishi",
|
||||
"unicode": "e749",
|
||||
"unicode_decimal": 59209
|
||||
},
|
||||
{
|
||||
"icon_id": "435890",
|
||||
"name": "版本切换",
|
||||
"font_class": "banbenqiehuan",
|
||||
"unicode": "e792",
|
||||
"unicode_decimal": 59282
|
||||
},
|
||||
{
|
||||
"icon_id": "1391488",
|
||||
"name": "退出登录",
|
||||
"font_class": "tuichudenglu",
|
||||
"unicode": "e64a",
|
||||
"unicode_decimal": 58954
|
||||
},
|
||||
{
|
||||
"icon_id": "37930768",
|
||||
"name": "火箭",
|
||||
"font_class": "huojian",
|
||||
"unicode": "e6ff",
|
||||
"unicode_decimal": 59135
|
||||
},
|
||||
{
|
||||
"icon_id": "37942158",
|
||||
"name": "icon_火箭",
|
||||
"font_class": "icon_huojian1",
|
||||
"unicode": "e6fe",
|
||||
"unicode_decimal": 59134
|
||||
},
|
||||
{
|
||||
"icon_id": "35348714",
|
||||
"name": "日历",
|
||||
"font_class": "rili1",
|
||||
"unicode": "e62e",
|
||||
"unicode_decimal": 58926
|
||||
},
|
||||
{
|
||||
"icon_id": "29941067",
|
||||
"name": "日历",
|
||||
"font_class": "rili",
|
||||
"unicode": "e664",
|
||||
"unicode_decimal": 58980
|
||||
},
|
||||
{
|
||||
"icon_id": "37970163",
|
||||
"name": "授权列表",
|
||||
|
||||
@ -283,4 +283,12 @@ export function filterDigit(event:any){
|
||||
*/
|
||||
export function filterNumber(event:any){
|
||||
event.target.value = event.target.value.replace(/[^\d]/g,'');
|
||||
}
|
||||
/**
|
||||
* 过滤特殊字符
|
||||
* @param event
|
||||
*/
|
||||
export function filterSpecial(event:any){
|
||||
event.target.value = event.target.value.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '')
|
||||
event.target.value = event.target.value.replace(/[`~!@#$%^&*()_\-+=<>?:"{}|,.\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g,'')
|
||||
}
|
||||
@ -60,7 +60,8 @@ module.exports = {
|
||||
'6xl': '30px',
|
||||
'7xl': '36px',
|
||||
'8xl': '48px',
|
||||
'9xl': '60px'
|
||||
'9xl': '60px',
|
||||
'page-title': '16px'
|
||||
},
|
||||
spacing: {
|
||||
px: '1px',
|
||||
|
||||
@ -1 +1 @@
|
||||
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
AUTH_KEY = {auth_key}
[DATABASE]
TYPE = mysql
HOSTNAME = {dbhost}
DATABASE = {dbname}
USERNAME = {dbuser}
PASSWORD = {dbpwd}
HOSTPORT = {dbport}
PREFIX = {dbprefix}
CHARSET = utf8
DEBUG = false
[REDIS]
REDIS_HOSTNAME = 127.0.0.1
PORT = 6379
REDIS_PASSWORD =
SELECT = 0
[LANG]
default_lang = zh-cn
[SYSTEM]
ADMIN_TOKEN_NAME = token
API_TOKEN_NAME = token
ADMIN_SITE_ID_NAME = site-id
API_SITE_ID_NAME = site-id
ADMIN_TOKEN_EXPIRE_TIME = 604800
API_TOKEN_EXPIRE_TIME = 86400
LANG_NAME = lang
CHANNEL_NAME = channel
ADMIN_DOMAIN =
WAP_DOMAIN =
WEB_DOMAIN =
[NIUCLOUD]
code =
secret =
|
||||
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
AUTH_KEY = {auth_key}
[DATABASE]
TYPE = mysql
HOSTNAME = {dbhost}
DATABASE = {dbname}
USERNAME = {dbuser}
PASSWORD = {dbpwd}
HOSTPORT = {dbport}
PREFIX = {dbprefix}
CHARSET = utf8mb4
DEBUG = false
[REDIS]
REDIS_HOSTNAME = 127.0.0.1
PORT = 6379
REDIS_PASSWORD =
SELECT = 0
[QUEUE]
state = false
[LANG]
default_lang = zh-cn
[SYSTEM]
ADMIN_TOKEN_NAME = token
API_TOKEN_NAME = token
ADMIN_SITE_ID_NAME = site-id
API_SITE_ID_NAME = site-id
ADMIN_TOKEN_EXPIRE_TIME = 604800
API_TOKEN_EXPIRE_TIME = 86400
LANG_NAME = lang
CHANNEL_NAME = channel
ADMIN_DOMAIN =
WAP_DOMAIN =
WEB_DOMAIN =
[NIUCLOUD]
code =
secret =
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
return [
|
||||
'HELLO_WORLD_LINK' => [
|
||||
'key' => 'hello_world',
|
||||
'addon_title' => get_lang('dict_diy.hello_world_title'),
|
||||
'title' => get_lang('dict_diy.hello_world_link'),
|
||||
'child_list' => [
|
||||
[
|
||||
|
||||
@ -12,15 +12,21 @@ return [
|
||||
"data" => [
|
||||
"global" => [
|
||||
"title" => "hello world首页页面",
|
||||
"pageBgColor" => "#F8F8F8",
|
||||
'pageStartBgColor' => '#F8F8F8',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'bgUrl' => '',
|
||||
'imgWidth' => '',
|
||||
'imgHeight' => '',
|
||||
"bottomTabBarSwitch" => true,
|
||||
"template" => [
|
||||
'textColor' => "#303133",
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentStartBgColor' => '',
|
||||
'componentEndBgColor' => '',
|
||||
'componentGradientAngle' => 'to bottom',
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
@ -70,8 +76,12 @@ return [
|
||||
]
|
||||
],
|
||||
"ignore" => [],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentStartBgColor' => '',
|
||||
'componentEndBgColor' => '',
|
||||
'componentGradientAngle' => 'to bottom',
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
return [
|
||||
'DIY_HELLO_WORLD_INDEX' => [
|
||||
'title' => get_lang('dict_diy.page_hello_world_index'),
|
||||
'page' => '/hello_world/pages/index',
|
||||
'page' => '/addon/hello_world/pages/index',
|
||||
'action' => ''
|
||||
],
|
||||
'DIY_HELLO_WORLD_INFO' => [
|
||||
'title' => get_lang('dict_diy.page_hello_world_info'),
|
||||
'page' => '/hello_world/pages/info',
|
||||
'page' => '/addon/hello_world/pages/info',
|
||||
'action' => ''
|
||||
],
|
||||
];
|
||||
@ -1,17 +1,3 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'menu_name' => '插件菜单',
|
||||
'menu_key' => 'niucloud_hello',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-iconyingyongshichang',
|
||||
'api_url' => '',
|
||||
'router_path' => 'hello_world',
|
||||
'view_path' => 'hello_world/index',
|
||||
'methods' => '',
|
||||
'sort' => 90,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
];
|
||||
return [
|
||||
];
|
||||
@ -1,36 +1,16 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'menu_name' => '插件站点菜单',
|
||||
'menu_key' => 'niucloud_site_hello',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-iconyingyongshichang',
|
||||
'api_url' => '',
|
||||
'router_path' => 'hello_world',
|
||||
'view_path' => 'hello_world/site',
|
||||
'methods' => '',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
],
|
||||
/* [
|
||||
'menu_name' => '会员列表',
|
||||
'menu_key' => 'member_list',
|
||||
'parent_key' => 'member',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-iconhuiyuanliebiao',
|
||||
'api_url' => 'member/member',
|
||||
'router_path' => 'hello_world_member_list',
|
||||
'view_path' => 'hello_world/member',
|
||||
'methods' => 'get',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
'children' => [
|
||||
|
||||
]
|
||||
],
|
||||
"delete" => "member" //针对修改系统菜单处理方式,可以删除系统菜单,设置对应key值,也可删除不需要的菜单处理
|
||||
*/
|
||||
];
|
||||
return [
|
||||
[
|
||||
'menu_name' => '插件站点菜单',
|
||||
'menu_key' => 'niucloud_site_hello',
|
||||
'menu_type' => 1,
|
||||
'icon' => 'iconfont-iconyingyongshichang',
|
||||
'api_url' => '',
|
||||
'router_path' => 'hello_world',
|
||||
'view_path' => 'hello_world/site',
|
||||
'methods' => '',
|
||||
'sort' => 100,
|
||||
'status' => 1,
|
||||
'is_show' => 1,
|
||||
]
|
||||
];
|
||||
|
||||
@ -2,15 +2,15 @@
|
||||
return [
|
||||
'pages' => <<<EOT
|
||||
// PAGE_BEGIN
|
||||
{
|
||||
"path": "addon/{{addon_name}}/pages/index",
|
||||
"style": {
|
||||
// #ifdef H5
|
||||
"navigationStyle": "custom",
|
||||
// #endif
|
||||
"navigationBarTitleText": "%{{addon_name}}.pages.index%"
|
||||
}
|
||||
}
|
||||
{
|
||||
"path": "hello_world/pages/index",
|
||||
"style": {
|
||||
// #ifdef H5
|
||||
"navigationStyle": "custom",
|
||||
// #endif
|
||||
"navigationBarTitleText": "%{{addon_name}}.pages.index%"
|
||||
}
|
||||
},
|
||||
// PAGE_END
|
||||
EOT
|
||||
];
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 128 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 673 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
@ -22,7 +22,8 @@
|
||||
|
||||
const warpCss = computed(() => {
|
||||
var style = '';
|
||||
style += 'background-color:' + diyComponent.value.componentBgColor + ';';
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
|
||||
style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
|
||||
style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
|
||||
style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
{
|
||||
"hello_world.pages.index": "hello_world首页"
|
||||
}
|
||||
"pages.index": "hello_world首页"
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class Request extends \think\Request
|
||||
if (!$param || !$filter || !is_string($param)) return $param;
|
||||
// 把数据过滤
|
||||
$filter_rule = [
|
||||
"/<(\\/?)(script|i?frame|style|html|body|title|link|meta|object|\\?|\\%)([^>]*?)>/isU",
|
||||
"/<(\\/?)(script|i?frame|style|html|body|title|link|metaf|alert|font|object|\\?|\\%)([^>]*?)>/isU",
|
||||
"/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
|
||||
"/select|join|where|drop|like|modify|rename|insert|update|table|database|alter|truncate|\'|\/\*|\.\.\/|\.\/|union|into|load_file|outfile/is"
|
||||
];
|
||||
|
||||
@ -82,7 +82,7 @@ class Diy extends BaseAdminController
|
||||
[ "type", "" ],
|
||||
[ 'template', '' ],
|
||||
[ 'mode', 'diy' ], // 页面展示模式,diy:自定义,fixed:固定
|
||||
[ "value", "" ],
|
||||
[ "value", "", false ],
|
||||
[ 'is_default', 0 ],
|
||||
[ 'is_change', '' ]
|
||||
]);
|
||||
@ -102,9 +102,10 @@ class Diy extends BaseAdminController
|
||||
$data = $this->request->params([
|
||||
[ "title", "" ],
|
||||
[ "name", "" ],
|
||||
[ "value", "" ],
|
||||
[ "value", "", false ],
|
||||
[ 'is_change', '' ]
|
||||
]);
|
||||
|
||||
$this->validate($data, 'app\validate\diy\Diy.edit');
|
||||
( new DiyService() )->edit($id, $data);
|
||||
return success('MODIFY_SUCCESS');
|
||||
@ -158,6 +159,7 @@ class Diy extends BaseAdminController
|
||||
$diy_service = new DiyService();
|
||||
return success($diy_service->getLink());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面模板
|
||||
* @return Response
|
||||
|
||||
@ -16,16 +16,16 @@ use app\service\admin\auth\ConfigService;
|
||||
use app\service\admin\auth\LoginService;
|
||||
use app\service\admin\upgrade\UpgradeService;
|
||||
use app\service\core\addon\CoreAddonDevelopBuildService;
|
||||
use app\service\core\addon\WapTrait;
|
||||
use app\service\core\menu\CoreMenuService;
|
||||
use app\service\core\upload\CoreFileService;
|
||||
use app\service\core\weapp\CoreWeappCloudService;
|
||||
use app\upgrade\v011\Upgrade;
|
||||
use core\base\BaseAdminController;
|
||||
use think\facade\Db;
|
||||
use think\Response;
|
||||
|
||||
class Login extends BaseAdminController
|
||||
{
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @return Response
|
||||
@ -69,6 +69,6 @@ class Login extends BaseAdminController
|
||||
}
|
||||
|
||||
public function test(){
|
||||
(new CoreWeappCloudService())->test();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,10 +27,9 @@ class MemberLabel extends BaseAdminController
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
|
||||
['label_name', ''],
|
||||
[ 'label_name', '' ],
|
||||
]);
|
||||
return success((new MemberLabelService())->getPage($data));
|
||||
return success(( new MemberLabelService() )->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,7 +39,7 @@ class MemberLabel extends BaseAdminController
|
||||
*/
|
||||
public function info(int $id)
|
||||
{
|
||||
return success((new MemberLabelService())->getInfo($id));
|
||||
return success(( new MemberLabelService() )->getInfo($id));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,27 +50,27 @@ class MemberLabel extends BaseAdminController
|
||||
{
|
||||
$data = $this->request->params([
|
||||
|
||||
['label_name', ''],
|
||||
['memo', ''],
|
||||
['sort', 0],
|
||||
[ 'label_name', '' ],
|
||||
[ 'memo', '' ],
|
||||
[ 'sort', 0 ],
|
||||
]);
|
||||
$this->validate($data, 'app\validate\member\MemberLabel.add');
|
||||
$id = (new MemberLabelService())->add($data);
|
||||
return success('ADD_SUCCESS', ['label_id' => $id]);
|
||||
$id = ( new MemberLabelService() )->add($data);
|
||||
return success('ADD_SUCCESS', [ 'label_id' => $id ]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单或接口更新
|
||||
* 编辑会员标签
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$data = $this->request->params([
|
||||
['label_name', ''],
|
||||
['memo', ''],
|
||||
['sort', 0],
|
||||
[ 'label_name', '' ],
|
||||
[ 'memo', '' ],
|
||||
[ 'sort', 0 ],
|
||||
]);
|
||||
$this->validate($data, 'app\validate\member\MemberLabel.edit');
|
||||
(new MemberLabelService())->edit($id, $data);
|
||||
( new MemberLabelService() )->edit($id, $data);
|
||||
return success('EDIT_SUCCESS');
|
||||
}
|
||||
|
||||
@ -82,8 +81,7 @@ class MemberLabel extends BaseAdminController
|
||||
*/
|
||||
public function del(int $id)
|
||||
{
|
||||
|
||||
(new MemberLabelService())->del($id);
|
||||
( new MemberLabelService() )->del($id);
|
||||
return success('DELETE_SUCCESS');
|
||||
}
|
||||
|
||||
@ -96,7 +94,7 @@ class MemberLabel extends BaseAdminController
|
||||
*/
|
||||
public function getAll()
|
||||
{
|
||||
return success((new MemberLabelService())->getAll());
|
||||
return success(( new MemberLabelService() )->getAll());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,119 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\adminapi\controller\order;
|
||||
|
||||
use app\service\admin\order\RechargeOrderRefundService;
|
||||
use app\service\admin\order\RechargeOrderService;
|
||||
use core\base\BaseAdminController;
|
||||
use think\Response;
|
||||
|
||||
class Recharge extends BaseAdminController
|
||||
{
|
||||
/**
|
||||
* 充值订单列表
|
||||
* @return Response
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
['order_no', ''],
|
||||
['order_status', ''],
|
||||
['order_from', ''],
|
||||
['create_time', []],
|
||||
['pay_time', []],
|
||||
['member_id', ''],
|
||||
['start_money', 0],
|
||||
['end_money', 0]
|
||||
]);
|
||||
return success((new RechargeOrderService())->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值订单详情
|
||||
* @param int $order_id
|
||||
* @return Response
|
||||
*/
|
||||
public function detail(int $order_id)
|
||||
{
|
||||
return success((new RechargeOrderService())->getDetail($order_id));
|
||||
}
|
||||
|
||||
public function status()
|
||||
{
|
||||
return success((new RechargeOrderService())->getStatus());
|
||||
}
|
||||
|
||||
public function refund($order_id)
|
||||
{
|
||||
$res = (new RechargeOrderRefundService())->create($order_id);
|
||||
if ($res === true) return success();
|
||||
return fail($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款列表
|
||||
* @return Response
|
||||
*/
|
||||
public function refundLists()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
['create_time', []],
|
||||
['member_id', ''],
|
||||
['refund_no', ''],
|
||||
['status', ''],
|
||||
['keywords', ''],
|
||||
['order_no', ''],
|
||||
]);
|
||||
return success((new RechargeOrderRefundService())->getPage($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款详情
|
||||
* @param int $refund_id
|
||||
* @return Response
|
||||
*/
|
||||
public function refundDetail(int $refund_id)
|
||||
{
|
||||
return success((new RechargeOrderRefundService())->getDetail($refund_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询退款状态
|
||||
* @return Response
|
||||
*/
|
||||
public function refundStatus()
|
||||
{
|
||||
return success((new RechargeOrderRefundService())->getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款统计
|
||||
*/
|
||||
public function refundStat()
|
||||
{
|
||||
return success((new RechargeOrderRefundService())->stat());
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值统计
|
||||
*/
|
||||
public function stat()
|
||||
{
|
||||
$data = $this->request->params([
|
||||
['member_id', ''],
|
||||
]);
|
||||
$res = (new RechargeOrderService())->stat($data);
|
||||
return success($res);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -31,7 +31,7 @@ class Template extends BaseAdminController
|
||||
['keys', []]
|
||||
]);
|
||||
$wechat_template_service = new WechatTemplateService();
|
||||
return success($wechat_template_service->syncAll($data['keys']));
|
||||
return success(data:$wechat_template_service->syncAll($data['keys']));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use app\adminapi\middleware\AdminCheckRole;
|
||||
use app\adminapi\middleware\AdminCheckToken;
|
||||
use app\adminapi\middleware\AdminLog;
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
/**
|
||||
* 订单相关路由
|
||||
*/
|
||||
Route::group('order', function () {
|
||||
/***************************************************** 充值订单 *************************************************/
|
||||
//订单列表
|
||||
Route::get('recharge', 'order.Recharge/lists');
|
||||
//订单详情
|
||||
Route::get('recharge/:order_id', 'order.Recharge/detail');
|
||||
//订单状态
|
||||
Route::get('recharge/status', 'order.Recharge/status');
|
||||
//订单统计
|
||||
Route::get('recharge/stat', 'order.Recharge/stat');
|
||||
// 订单发起退款
|
||||
Route::put('recharge/refund/:order_id', 'order.Recharge/refund');
|
||||
//退款订单列表
|
||||
Route::get('recharge/refund', 'order.Recharge/refundLists');
|
||||
//退款订单详情
|
||||
Route::get('recharge/refund/:refund_id', 'order.Recharge/refundDetail');
|
||||
//退款订单状态
|
||||
Route::get('recharge/refund/status', 'order.Recharge/refundStatus');
|
||||
//退款订单统计
|
||||
Route::get('recharge/refund/stat', 'order.Recharge/refundStat');
|
||||
})->middleware([
|
||||
AdminCheckToken::class,
|
||||
AdminCheckRole::class,
|
||||
AdminLog::class
|
||||
]);
|
||||
@ -1,52 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\api\controller\order;
|
||||
|
||||
use app\service\api\order\RechargeOrderService;
|
||||
use core\base\BaseApiController;
|
||||
use think\Response;
|
||||
|
||||
class Recharge extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* 充值订单创建
|
||||
* @return Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//['order_from' => 'h5', 'ip' => '127.0.0.1', 'member_message' => '','recharge_money' => 12.00]
|
||||
$data = $this->request->params([
|
||||
['member_message', ''],
|
||||
['recharge_money', 0]
|
||||
]);
|
||||
$res = (new RechargeOrderService())->recharge($data);
|
||||
return success($res);
|
||||
}
|
||||
|
||||
public function lists(){
|
||||
$data = $this->request->params([
|
||||
['order_status', '']
|
||||
]);
|
||||
$res = (new RechargeOrderService())->getPage($data);
|
||||
return success($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询充值订单详情
|
||||
* @param int $order_id
|
||||
* @return Response
|
||||
*/
|
||||
public function detail(int $order_id){
|
||||
$res = (new RechargeOrderService())->getDetail($order_id);
|
||||
return success($res);
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
use app\api\middleware\ApiChannel;
|
||||
use app\api\middleware\ApiCheckToken;
|
||||
use app\api\middleware\ApiLog;
|
||||
use think\facade\Route;
|
||||
|
||||
|
||||
/**
|
||||
* 会员个人信息管理
|
||||
*/
|
||||
Route::group('order', function () {
|
||||
|
||||
/***************************************************** 充值订单相关 *************************************************/
|
||||
//充值订单创建
|
||||
Route::post('recharge', 'order.Recharge/create');
|
||||
// 充值订单列表
|
||||
Route::get('recharge', 'order.Recharge/lists');
|
||||
// 充值订单详情
|
||||
Route::get('recharge/:order_id', 'order.Recharge/detail');
|
||||
})->middleware(ApiChannel::class)
|
||||
->middleware(ApiCheckToken::class, true)
|
||||
->middleware(ApiLog::class);
|
||||
42
niucloud/app/command/WorkerCommand.php
Normal file
42
niucloud/app/command/WorkerCommand.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use core\exception\CommonException;
|
||||
use core\job\Dispatch;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\queue\Job;
|
||||
|
||||
/**
|
||||
* worker 兼容think自定义指令
|
||||
*/
|
||||
trait WorkerCommand
|
||||
{
|
||||
|
||||
public function resetCli(Input $input, Output $output){
|
||||
// 指令输出
|
||||
$action = $input->getArgument('action');
|
||||
$mode = $input->getOption('mode');
|
||||
// 重新构造命令行参数,以便兼容workerman的命令
|
||||
global $argv;
|
||||
$argv = [];
|
||||
array_unshift($argv, 'think', $action);
|
||||
if ($mode == 'd') {
|
||||
$argv[] = '-d';
|
||||
} else if ($mode == 'g') {
|
||||
$argv[] = '-g';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
114
niucloud/app/command/queue/Queue.php
Normal file
114
niucloud/app/command/queue/Queue.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace app\command\queue;
|
||||
|
||||
use app\command\WorkerCommand;
|
||||
use app\model\sys\SysSchedule;
|
||||
use app\service\core\addon\CoreAddonService;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Log;
|
||||
use Workerman\RedisQueue\Client;
|
||||
use Workerman\Timer;
|
||||
use Workerman\Worker;
|
||||
|
||||
class Queue extends Command
|
||||
{
|
||||
use WorkerCommand;
|
||||
public function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('queue:listen')
|
||||
->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
|
||||
->addOption('mode', 'm', Option::VALUE_OPTIONAL, 'Run the workerman server in daemon mode.')
|
||||
->setDescription('基于Redis的消息队列,支持消息延迟处理。');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->resetCli($input, $output);
|
||||
Worker::$pidFile = runtime_path() .'workerman_queue.pid';
|
||||
Worker::$logFile = runtime_path().'workerman.log';
|
||||
$worker = new Worker();
|
||||
$worker->name = 'queue_work';
|
||||
// $worker->count = 3;
|
||||
$worker->onWorkerStart = function () use($output){
|
||||
// 定时,每10秒一次
|
||||
Timer::add(30, function()use($output)
|
||||
{
|
||||
(new SysSchedule())->select();
|
||||
});
|
||||
$redis_option = [
|
||||
'connect_timeout' => 10,
|
||||
'max_attempts' => 3,
|
||||
'retry_seconds' => 5,
|
||||
];
|
||||
if(!empty(env('redis.redis_password'))){
|
||||
$redis_option['auth'] = env('redis.redis_password');
|
||||
}
|
||||
$redis_option['db'] = env('redis.select');
|
||||
$client = new Client('redis://'.env('redis.redis_hostname').':'.env('redis.port'), $redis_option);
|
||||
$queue_list = $this->getAllQueue();
|
||||
|
||||
foreach ($queue_list as $queue_class_name){
|
||||
$queue_class_name = str_replace('.php', '', $queue_class_name);
|
||||
// 订阅
|
||||
$client->subscribe($queue_class_name, function($data) use($queue_class_name, $output){
|
||||
echo "\n".'['.date('Y-m-d H:i:s').']'." Processing:" . $queue_class_name;
|
||||
try{
|
||||
$class_name = '\\' .$queue_class_name;
|
||||
$class = new $class_name();
|
||||
$class->fire($data);
|
||||
} catch (\Throwable $e) {
|
||||
Log::write(date('Y-m-d H:i:s').',队列有错误:'.$queue_class_name.'_'.$e->getMessage().'_'.$e->getFile().'_'.$e->getLine());
|
||||
}
|
||||
echo "\n".'['.date('Y-m-d H:i:s').']'." Processed:" . $queue_class_name;
|
||||
});
|
||||
}
|
||||
// 消费失败触发的回调(可选)
|
||||
$client->onConsumeFailure(function (\Throwable $exception, $package) use($output){
|
||||
echo "\n"."队列 " . $package['queue'] . " 消费失败,".$exception->getMessage();
|
||||
});
|
||||
};
|
||||
Worker::runAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获所有队列任务
|
||||
* @return array
|
||||
*/
|
||||
public function getAllQueue(){
|
||||
$class_list = [];
|
||||
$system_dir = root_path() . 'app' . DIRECTORY_SEPARATOR . 'job';
|
||||
$addon_dir = root_path() . 'addon' . DIRECTORY_SEPARATOR;
|
||||
if(is_dir($system_dir)){
|
||||
search_dir($system_dir, $app_data, root_path());
|
||||
$class_list = array_merge($class_list, $app_data);
|
||||
}
|
||||
|
||||
$addons = (new CoreAddonService())->getInstallAddonList();
|
||||
foreach ($addons as $v) {
|
||||
|
||||
$addon_path = $addon_dir .$v['key']. DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR. 'job';
|
||||
if (is_dir($addon_path)) {
|
||||
search_dir($addon_path, $addon_data, root_path());
|
||||
$class_list = array_merge($class_list, $addon_data);
|
||||
}
|
||||
}
|
||||
|
||||
foreach($class_list as &$v){
|
||||
$v = str_replace('.php', '', $v);
|
||||
$v = str_replace('/', '\\', $v);
|
||||
}
|
||||
return $class_list;
|
||||
}
|
||||
}
|
||||
@ -2,51 +2,110 @@
|
||||
|
||||
namespace app\command\schedule;
|
||||
|
||||
use app\command\WorkerCommand;
|
||||
use app\dict\schedule\ScheduleDict;
|
||||
use app\service\core\addon\CoreAddonService;
|
||||
use app\service\core\schedule\CoreScheduleService;
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\helper\Str;
|
||||
use Workerman\Crontab\Crontab;
|
||||
use Workerman\RedisQueue\Client;
|
||||
use Workerman\Worker;
|
||||
use yunwuxin\cron\Task;
|
||||
|
||||
class Schedule extends Task
|
||||
class Schedule extends Command
|
||||
{
|
||||
|
||||
use WorkerCommand;
|
||||
public function configure()
|
||||
{
|
||||
$this->expression($this->getCrontab($this->vars['time']));
|
||||
// 指令配置
|
||||
$this->setName('cron:schedule')
|
||||
->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
|
||||
->addOption('mode', 'm', Option::VALUE_OPTIONAL, 'Run the workerman server in daemon mode.')
|
||||
->setDescription('定时任务,类似linux的crontab。支持秒级别定时。');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
* @return void
|
||||
*/
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$this->resetCli($input, $output);
|
||||
Worker::$pidFile = runtime_path() .'workerman_schedule.pid';
|
||||
$worker = new Worker();
|
||||
$worker->name = 'schedule_work';
|
||||
$worker->count = 1;
|
||||
$output->writeln('['.date('Y-m-d H:i:s').']'." Schedule Starting...");
|
||||
// 设置时区,避免运行结果与预期不一致
|
||||
date_default_timezone_set('PRC');
|
||||
$worker->onWorkerStart = function () use($output){
|
||||
// // 每分钟的第1秒执行.用于计划任务是否仍在执行
|
||||
new Crontab('*/10 * * * * *', function(){
|
||||
$file = root_path('runtime').'.schedule';
|
||||
file_put_contents($file, time());
|
||||
});
|
||||
$core_schedule_service = new CoreScheduleService();
|
||||
//查询所有的计划任务
|
||||
$task_list = $core_schedule_service->getList(['status' => ScheduleDict::ON]);
|
||||
$output->writeln('['.date('Y-m-d H:i:s').']'." Schedule Started.");
|
||||
foreach ($task_list as $item) {
|
||||
//获取定时任务时间字符串
|
||||
new Crontab($this->getCrontab($item['time']), function () use ($core_schedule_service, $item, $output) {
|
||||
$core_schedule_service->execute($item, $output);
|
||||
});
|
||||
}
|
||||
};
|
||||
Worker::runAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取计划任务所需的时间字符串
|
||||
* 0 1 2 3 4 5
|
||||
* | | | | | |
|
||||
* | | | | | +------ day of week (0 - 6) (Sunday=0)
|
||||
* | | | | +------ month (1 - 12)
|
||||
* | | | +-------- day of month (1 - 31)
|
||||
* | | +---------- hour (0 - 23)
|
||||
* | +------------ min (0 - 59)
|
||||
* +-------------- sec (0-59)[可省略,如果没有0位,则最小时间粒度是分钟]
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
protected function getCrontab($data): string
|
||||
{
|
||||
$sec = $data['sec'] ?? '*';
|
||||
$min = $data['min'] ?? '*';
|
||||
$hour = $data['hour'] ?? '*';
|
||||
$day = $data['day'] ?? '*';
|
||||
$week = $data['week'] ?? '*';
|
||||
$type = $data['type'] ?? '';
|
||||
switch ($type) {
|
||||
case 'sec':// 每隔几秒
|
||||
$crontab = '*/' . $sec . ' * * * * *';
|
||||
break;
|
||||
case 'min':// 每隔几分
|
||||
$crontab = '*/' . $min . ' * * * *';
|
||||
$crontab = '0 */' . $min . ' * * * *';
|
||||
break;
|
||||
case 'hour':// 每隔几时第几分钟执行
|
||||
$crontab = $min . ' */' . $hour . ' * * *';
|
||||
$crontab = '0 ' . $min . ' */' . $hour . ' * * *';
|
||||
break;
|
||||
case 'day':// 每隔几日几时几分几秒执行
|
||||
$crontab = $min . ' ' . $hour . ' */' . $day . ' * *';
|
||||
case 'day':// 每隔几日第几小时第几分钟执行
|
||||
$crontab = '0 ' . $min . ' ' . $hour . ' */' . $day . ' * *';
|
||||
break;
|
||||
case 'week':// 每周一次,周几具体时间执行
|
||||
$crontab = $min . ' ' . $hour . ' * * ' . $week;
|
||||
$crontab = '0 ' .$min . ' ' . $hour . ' * * ' . $week;
|
||||
break;
|
||||
case 'month':// 每月一次,某日具体时间执行
|
||||
$crontab = $min . ' ' . $hour . ' ' . $day . ' * *';
|
||||
$crontab = '0 ' .$min . ' ' . $hour . ' ' . $day . ' * *';
|
||||
break;
|
||||
}
|
||||
return $crontab ?? '* * * * *';
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行任务
|
||||
* @return void
|
||||
*/
|
||||
protected function execute()
|
||||
{
|
||||
//...具体的任务执行
|
||||
(new CoreScheduleService())->execute($this->vars);
|
||||
return $crontab ?? '* */1 * * * *';
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,14 +467,18 @@ function array_merge2(array $array1, array $array2)
|
||||
{
|
||||
foreach ($array2 as $array2_k => $array2_v) {
|
||||
if (array_key_exists($array2_k, $array1)) {
|
||||
foreach ($array2_v as $array2_kk => $array2_vv) {
|
||||
if (array_key_exists($array2_kk, $array1[$array2_k])) {
|
||||
if (is_array($array2_vv)) {
|
||||
$array1[$array2_k][$array2_kk] = array_merge($array1[$array2_k][$array2_kk], $array2_vv);
|
||||
if (is_array($array2_v)) {
|
||||
foreach ($array2_v as $array2_kk => $array2_vv) {
|
||||
if (array_key_exists($array2_kk, $array1[$array2_k])) {
|
||||
if (is_array($array2_vv)) {
|
||||
$array1[$array2_k][$array2_kk] = array_merge($array1[$array2_k][$array2_kk], $array2_vv);
|
||||
}
|
||||
} else {
|
||||
$array1[$array2_k][$array2_kk] = $array2_vv;
|
||||
}
|
||||
} else {
|
||||
$array1[$array2_k][$array2_kk] = $array2_vv;
|
||||
}
|
||||
} else {
|
||||
$array1[$array2_k] = $array2_v;
|
||||
}
|
||||
} else {
|
||||
$array1[$array2_k] = $array2_v;
|
||||
|
||||
@ -34,11 +34,18 @@ class ComponentDict
|
||||
'support_page' => [], // 支持页面
|
||||
'uses' => 0, // 最大添加数量
|
||||
'sort' => 10001,
|
||||
'position' => '', // 组件置顶标识,不能拖拽,可选值:fixed、top_fixed、right_fixed、bottom_fixed、left_fixed
|
||||
// 组件属性
|
||||
'template' => [
|
||||
"textColor" => "#303133", // 文字颜色
|
||||
"pageBgColor" => "", // 底部背景颜色
|
||||
"componentBgColor" => '', // 组件背景颜色
|
||||
'pageStartBgColor' => '', // 底部背景颜色(开始)
|
||||
'pageEndBgColor' => '', // 底部背景颜色(结束)
|
||||
'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
'componentBgUrl' => '', // 组件背景图片
|
||||
'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10
|
||||
"componentStartBgColor" => '', // 组件背景颜色(开始)
|
||||
"componentEndBgColor" => '', // 组件背景颜色(结束)
|
||||
"componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right)
|
||||
"topRounded" => 0, // 组件上圆角
|
||||
"bottomRounded" => 0, // 组件下圆角
|
||||
"elementBgColor" => '', // 元素背景颜色
|
||||
@ -109,12 +116,6 @@ class ComponentDict
|
||||
'sort' => 10003,
|
||||
'value' => [
|
||||
"layout" => "horizontal",
|
||||
"navTitle" => "",
|
||||
"subNavTitle" => "",
|
||||
"subNavTitleLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"subNavColor" => "#999999",
|
||||
"mode" => "graphic",
|
||||
"type" => "img",
|
||||
"showStyle" => "fixed",
|
||||
@ -221,24 +222,13 @@ class ComponentDict
|
||||
]
|
||||
],
|
||||
],
|
||||
'HorzBlank' => [
|
||||
'title' => '辅助空白',
|
||||
'icon' => 'iconfont-iconfuzhukongbai1',
|
||||
'path' => 'edit-horz-blank',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10005,
|
||||
'value' => [
|
||||
'height' => 20
|
||||
],
|
||||
],
|
||||
'HotArea' => [
|
||||
'title' => '热区',
|
||||
'icon' => 'iconfont-iconrequ',
|
||||
'path' => 'edit-hot-area',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10006,
|
||||
'sort' => 10007,
|
||||
'value' => [
|
||||
"imageUrl" => "",
|
||||
"imgWidth" => 0,
|
||||
@ -269,22 +259,328 @@ class ComponentDict
|
||||
'uses' => 0,
|
||||
'sort' => 10010,
|
||||
'value' => [
|
||||
"noticeType" => 'img',
|
||||
'imgType' => 'system',
|
||||
"systemUrl" => "style_1", // 系统定义的图片
|
||||
"imageUrl" => "", // 上传自定义图片
|
||||
"showType" => "popup", // 点击类型 弹出框,跳转
|
||||
"scrollWay" => "upDown", // 滚动方式 upDown:上下滚动,horizontal:横向滚动
|
||||
"fontSize" => 14,
|
||||
"fontWeight" => "normal",
|
||||
"noticeTitle" => "公告", // 公告标题文字
|
||||
"list" => [
|
||||
[
|
||||
"text" => "公告",
|
||||
"link" => [
|
||||
"name" => ""
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
'RichText' => [
|
||||
'title' => '富文本',
|
||||
'icon' => 'iconfont-iconfuwenben1',
|
||||
'path' => 'edit-rich-text',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10011,
|
||||
'value' => [
|
||||
"html" => ""
|
||||
],
|
||||
],
|
||||
'ActiveCube' => [
|
||||
'title' => '活动魔方',
|
||||
'icon' => 'iconfont-iconmofang1',
|
||||
'path' => 'edit-active-cube',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10012,
|
||||
'value' => [
|
||||
"titleStyle" => [
|
||||
'title' => '风格1',
|
||||
'value' => 'style-1'
|
||||
],
|
||||
'text' => '超值爆款',
|
||||
"textLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"titleColor" => "#F91700",
|
||||
"subTitle" => [
|
||||
"text" => "为您精选爆款",
|
||||
"textColor" => "#FFFFFF",
|
||||
"startColor" => "#FB792F",
|
||||
"endColor" => "#F91700",
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"text" => ""
|
||||
],
|
||||
"iconType" => "system",
|
||||
"systemIcon" => "style_01",
|
||||
"showType" => "popup",
|
||||
"imageUrl" => ""
|
||||
"blockStyle" => [
|
||||
'title' => '风格1',
|
||||
'value' => 'style-1',
|
||||
'fontWeight' => 'normal'
|
||||
],
|
||||
'list' => [
|
||||
[
|
||||
"title" => [
|
||||
"text" => "今日推荐",
|
||||
"textColor" => "#303133"
|
||||
],
|
||||
"subTitle" => [
|
||||
"text" => "诚意推荐",
|
||||
"textColor" => "#999999",
|
||||
"startColor" => "",
|
||||
"endColor" => "",
|
||||
],
|
||||
"moreTitle" => [
|
||||
"text" => "去看看",
|
||||
"startColor" => "#FEA715",
|
||||
"endColor" => "#FE1E00",
|
||||
],
|
||||
"listFrame" => [
|
||||
"startColor" => "#FEA715",
|
||||
"endColor" => "#FE1E00",
|
||||
],
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"imageUrl" => "static/resource/images/diy/active_cube/active_cube_goods1.png",
|
||||
],
|
||||
[
|
||||
"title" => [
|
||||
"text" => "优惠好物",
|
||||
"textColor" => "#303133"
|
||||
],
|
||||
"subTitle" => [
|
||||
"text" => "领券更优惠",
|
||||
"textColor" => "#999999",
|
||||
"startColor" => "",
|
||||
"endColor" => "",
|
||||
],
|
||||
"moreTitle" => [
|
||||
"text" => "去看看",
|
||||
"startColor" => "#FFBF50",
|
||||
"endColor" => "#FF9E03",
|
||||
],
|
||||
"listFrame" => [
|
||||
"startColor" => "#FFBF50",
|
||||
"endColor" => "#FF9E03",
|
||||
],
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"imageUrl" => "static/resource/images/diy/active_cube/active_cube_goods2.png",
|
||||
],
|
||||
[
|
||||
"title" => [
|
||||
"text" => "热销推荐",
|
||||
"textColor" => "#303133"
|
||||
],
|
||||
"subTitle" => [
|
||||
"text" => "本周热销商品",
|
||||
"textColor" => "#999999",
|
||||
"startColor" => "",
|
||||
"endColor" => "",
|
||||
],
|
||||
"moreTitle" => [
|
||||
"text" => "去看看",
|
||||
"startColor" => "#A2E792",
|
||||
"endColor" => "#49CD2D",
|
||||
],
|
||||
"listFrame" => [
|
||||
"startColor" => "#A2E792",
|
||||
"endColor" => "#49CD2D",
|
||||
],
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"imageUrl" => "static/resource/images/diy/active_cube/active_cube_goods3.png",
|
||||
],
|
||||
[
|
||||
"title" => [
|
||||
"text" => "书桌好物",
|
||||
"textColor" => "#303133"
|
||||
],
|
||||
"subTitle" => [
|
||||
"text" => "办公好物推荐",
|
||||
"textColor" => "#999999",
|
||||
"startColor" => "",
|
||||
"endColor" => "",
|
||||
],
|
||||
"moreTitle" => [
|
||||
"text" => "去看看",
|
||||
"startColor" => "#4AC1FF",
|
||||
"endColor" => "#1D7CFF",
|
||||
],
|
||||
"listFrame" => [
|
||||
"startColor" => "#4AC1FF",
|
||||
"endColor" => "#1D7CFF",
|
||||
],
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"imageUrl" => "static/resource/images/diy/active_cube/active_cube_goods4.png",
|
||||
],
|
||||
],
|
||||
// 组件属性
|
||||
'template' => [
|
||||
"textColor" => "#303133", // 文字颜色
|
||||
'pageStartBgColor' => '', // 底部背景颜色(开始)
|
||||
'pageEndBgColor' => '', // 底部背景颜色(结束)
|
||||
'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
'componentBgUrl' => '', // 组件背景图片
|
||||
'componentBgAlpha' => 2, // 组件背景图片的透明度,0~10
|
||||
"componentStartBgColor" => '', // 组件背景颜色(开始)
|
||||
"componentEndBgColor" => '', // 组件背景颜色(结束)
|
||||
"componentGradientAngle" => 'to bottom', // 渐变角度,上下(to bottom)、左右(to right)
|
||||
"topRounded" => 12, // 组件上圆角
|
||||
"bottomRounded" => 12, // 组件下圆角
|
||||
"elementBgColor" => '#FFFAF5', // 元素背景颜色
|
||||
"topElementRounded" => 0,// 元素上圆角
|
||||
"bottomElementRounded" => 0, // 元素下圆角
|
||||
"margin" => [
|
||||
"top" => 10, // 上边距
|
||||
"bottom" => 10, // 下边距
|
||||
"both" => 10 // 左右边距
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
],
|
||||
'CarouselSearch' => [
|
||||
'title' => '轮播搜索',
|
||||
'icon' => 'iconfont-iconsousuokuang',
|
||||
'path' => 'edit-carousel-search',
|
||||
'support_page' => [],
|
||||
'uses' => 1,
|
||||
'sort' => 10013,
|
||||
'position' => 'top_fixed', // 组件置顶标识,不能拖拽
|
||||
'value' => [
|
||||
'positionWay' => 'static',
|
||||
'fixedBgColor' => '',
|
||||
'bgGradient' => false,
|
||||
// 搜索设置
|
||||
'search' => [
|
||||
'logo' => '',
|
||||
'text' => '请输入搜索关键词',
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
'hotWord' => [
|
||||
"interval" => 3,
|
||||
'list' => []
|
||||
]
|
||||
],
|
||||
// 选项卡设置
|
||||
'tab' => [
|
||||
'control' => true, // 控制显示隐藏
|
||||
'noColor' => '', // 未选中颜色
|
||||
'selectColor' => '', // 选中颜色
|
||||
'fixedNoColor' => '', // 下滑未选中颜色
|
||||
'fixedSelectColor' => '', // 下滑选中颜色
|
||||
'list' => [
|
||||
[
|
||||
'text' => '分类名称', // 最多4个字
|
||||
'source' => 'diy_page',
|
||||
'diy_id' => '',
|
||||
'diy_title' => ''
|
||||
],
|
||||
[
|
||||
'text' => '分类名称',
|
||||
'source' => 'diy_page',
|
||||
'diy_id' => '',
|
||||
'diy_title' => ''
|
||||
],
|
||||
[
|
||||
'text' => '分类名称',
|
||||
'source' => 'diy_page',
|
||||
'diy_id' => '',
|
||||
'diy_title' => ''
|
||||
],
|
||||
[
|
||||
'text' => '分类名称',
|
||||
'source' => 'diy_page',
|
||||
'diy_id' => '',
|
||||
'diy_title' => ''
|
||||
]
|
||||
]
|
||||
],
|
||||
// 轮播图设置
|
||||
'swiper' => [
|
||||
'control' => true, // 控制显示隐藏
|
||||
"interval" => 5,
|
||||
'indicatorColor' => 'rgba(0, 0, 0, 0.3)', // 未选中颜色
|
||||
"indicatorActiveColor" => '#FF0E0E',
|
||||
'indicatorStyle' => 'style-1',
|
||||
'indicatorAlign' => 'center',
|
||||
'swiperStyle' => 'style-1',
|
||||
'imageHeight' => 168,
|
||||
'topRounded' => 0,
|
||||
'bottomRounded' => 0,
|
||||
'list' => [
|
||||
[
|
||||
"imageUrl" => "",
|
||||
"imgWidth" => 690,
|
||||
"imgHeight" => 330,
|
||||
"link" => [
|
||||
"name" => ""
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
],
|
||||
'FloatBtn' => [
|
||||
'title' => '浮动按钮',
|
||||
'icon' => 'iconfont-iconfudonganniu1',
|
||||
'path' => 'edit-float-btn',
|
||||
'support_page' => [],
|
||||
'uses' => 1,
|
||||
'sort' => 10014,
|
||||
'position' => 'fixed',
|
||||
'value' => [
|
||||
"imageSize" => 40,
|
||||
"aroundRadius" => 0,
|
||||
"bottomPosition" => "lowerRight", // 左上:upperLeft,右上:upperRight,左下:lowerLeft,右下:lowerRight
|
||||
"list" => [
|
||||
[
|
||||
"imageUrl" => "",
|
||||
"link" => [
|
||||
"name" => ""
|
||||
]
|
||||
]
|
||||
],
|
||||
"offset" => 0 // 偏移量
|
||||
],
|
||||
],
|
||||
'HorzBlank' => [
|
||||
'title' => '辅助空白',
|
||||
'icon' => 'iconfont-iconfuzhukongbai1',
|
||||
'path' => 'edit-horz-blank',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10015,
|
||||
'value' => [
|
||||
'height' => 20
|
||||
],
|
||||
],
|
||||
'HorzLine' => [
|
||||
'title' => '辅助线',
|
||||
'icon' => 'iconfont-iconfuzhuxian1',
|
||||
'path' => 'edit-horz-line',
|
||||
'support_page' => [],
|
||||
'uses' => 0,
|
||||
'sort' => 10016,
|
||||
'value' => [
|
||||
'borderWidth' => 1,
|
||||
'borderColor' => '#303133',
|
||||
'borderStyle' => 'solid'
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
],
|
||||
];
|
||||
return (new DictLoader("UniappComponent"))->load($system_components);
|
||||
return ( new DictLoader("UniappComponent") )->load($system_components);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,12 +31,6 @@ class PagesDict
|
||||
"componentTitle" => "图文导航",
|
||||
"uses" => 0,
|
||||
"layout" => "horizontal",
|
||||
"navTitle" => "",
|
||||
"subNavTitle" => "",
|
||||
"subNavTitleLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"subNavColor" => "#999999",
|
||||
"mode" => "graphic",
|
||||
"showStyle" => "fixed",
|
||||
"rowCount" => 4,
|
||||
@ -52,8 +46,14 @@ class PagesDict
|
||||
"weight" => "normal",
|
||||
"color" => "#303133"
|
||||
],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "rgba(255, 255, 255, 1)",
|
||||
'pageStartBgColor' => '', // 底部背景颜色(开始)
|
||||
'pageEndBgColor' => '', // 底部背景颜色(结束)
|
||||
'pageGradientAngle' => 'to bottom', // 渐变角度,从上到下(to bottom)、从左到右(to right)
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 9,
|
||||
"bottomRounded" => 9,
|
||||
"elementBgColor" => "",
|
||||
@ -120,15 +120,24 @@ class PagesDict
|
||||
"data" => [
|
||||
"global" => [
|
||||
"title" => "首页",
|
||||
"pageBgColor" => "#F8F8F8",
|
||||
'pageStartBgColor' => '#F8F8F8',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'bgUrl' => '',
|
||||
'bgHeightScale' => 0,
|
||||
'imgWidth' => '',
|
||||
'imgHeight' => '',
|
||||
"bottomTabBarSwitch" => true,
|
||||
"template" => [
|
||||
'textColor' => "#303133",
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
@ -176,15 +185,24 @@ class PagesDict
|
||||
"data" => [
|
||||
"global" => [
|
||||
"title" => "个人中心(风格一)",
|
||||
"pageBgColor" => "#F8F8F8",
|
||||
'pageStartBgColor' => '#F8F8F8',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'bgUrl' => '',
|
||||
'bgHeightScale' => 0,
|
||||
'imgWidth' => '',
|
||||
'imgHeight' => '',
|
||||
"bottomTabBarSwitch" => true,
|
||||
"template" => [
|
||||
'textColor' => "#303133",
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
@ -223,8 +241,14 @@ class PagesDict
|
||||
"componentTitle" => "会员信息",
|
||||
"uses" => 0,
|
||||
"ignore" => [],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 9,
|
||||
"bottomRounded" => 9,
|
||||
"elementBgColor" => "",
|
||||
@ -242,6 +266,90 @@ class PagesDict
|
||||
"bgColorStart" => "",
|
||||
"bgColorEnd" => ""
|
||||
],
|
||||
[
|
||||
"path" => "edit-horz-blank",
|
||||
"uses" => 0,
|
||||
"id" => "2da0xqyo8zms",
|
||||
"componentName" => "HorzBlank",
|
||||
"componentTitle" => "辅助空白",
|
||||
"ignore" => [
|
||||
"pageBgColor",
|
||||
"componentBgUrl"
|
||||
],
|
||||
"height" => 10,
|
||||
"textColor" => "#303133",
|
||||
"pageStartBgColor" => "",
|
||||
"pageEndBgColor" => "",
|
||||
"pageGradientAngle" => "to bottom",
|
||||
"componentBgUrl" => "",
|
||||
"componentBgAlpha" => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 9,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
"topElementRounded" => 0,
|
||||
"bottomElementRounded" => 0,
|
||||
"margin" => [
|
||||
"top" => 6,
|
||||
"bottom" => 0,
|
||||
"both" => 16
|
||||
]
|
||||
],
|
||||
[
|
||||
"path" => "edit-text",
|
||||
"uses" => 0,
|
||||
"position" => "",
|
||||
"id" => "1puhgfus8www",
|
||||
"componentName" => "Text",
|
||||
"componentTitle" => "标题",
|
||||
"ignore" => [],
|
||||
"style" => "style-2",
|
||||
"styleName" => "风格2",
|
||||
"text" => "我的服务",
|
||||
"link" => [
|
||||
"name" => "",
|
||||
],
|
||||
"textColor" => "#303133",
|
||||
"fontSize" => 16,
|
||||
"fontWeight" => "normal",
|
||||
"textAlign" => "center",
|
||||
"subTitle" => [
|
||||
"text" => "",
|
||||
"color" => "#999999",
|
||||
"fontSize" => 14,
|
||||
"control" => true,
|
||||
"fontWeight" => "normal"
|
||||
],
|
||||
"more" => [
|
||||
"text" => "全部",
|
||||
"control" => true,
|
||||
"isShow" => true,
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"color" => "#999999"
|
||||
],
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
"topElementRounded" => 0,
|
||||
"bottomElementRounded" => 0,
|
||||
"margin" => [
|
||||
"top" => 0,
|
||||
"bottom" => 0,
|
||||
"both" => 16
|
||||
]
|
||||
],
|
||||
[
|
||||
"path" => "edit-graphic-nav",
|
||||
"id" => "62b7d7hl4ok",
|
||||
@ -249,12 +357,6 @@ class PagesDict
|
||||
"componentTitle" => "图文导航",
|
||||
"uses" => 0,
|
||||
"layout" => "horizontal",
|
||||
"navTitle" => "我的服务",
|
||||
"subNavTitle" => "",
|
||||
"subNavTitleLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"subNavColor" => "#999999",
|
||||
"mode" => "graphic",
|
||||
"showStyle" => "fixed",
|
||||
"rowCount" => 4,
|
||||
@ -270,15 +372,21 @@ class PagesDict
|
||||
"weight" => "bold",
|
||||
"color" => "#303133"
|
||||
],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"topRounded" => 9,
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 9,
|
||||
"elementBgColor" => "",
|
||||
"topElementRounded" => 0,
|
||||
"bottomElementRounded" => 0,
|
||||
"margin" => [
|
||||
"top" => 6,
|
||||
"top" => 0,
|
||||
"bottom" => 6,
|
||||
"both" => 16
|
||||
],
|
||||
@ -371,12 +479,6 @@ class PagesDict
|
||||
"componentTitle" => "图文导航",
|
||||
"ignore" => [],
|
||||
"layout" => "vertical",
|
||||
"navTitle" => "",
|
||||
"subNavTitle" => "",
|
||||
"subNavTitleLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"subNavColor" => "#999999",
|
||||
"mode" => "graphic",
|
||||
"showStyle" => "fixed",
|
||||
"rowCount" => 4,
|
||||
@ -488,8 +590,14 @@ class PagesDict
|
||||
]
|
||||
]
|
||||
],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "rgba(255, 255, 255, 1)",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 9,
|
||||
"bottomRounded" => 9,
|
||||
"elementBgColor" => "",
|
||||
@ -514,15 +622,24 @@ class PagesDict
|
||||
"data" => [
|
||||
"global" => [
|
||||
"title" => "个人中心(风格二)",
|
||||
"pageBgColor" => "#F8F8F8",
|
||||
'pageStartBgColor' => '#F8F8F8',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
"bgUrl" => "static/resource/images/diy/member_style2_bg.png",
|
||||
'bgHeightScale' => 0,
|
||||
'imgWidth' => 750,
|
||||
'imgHeight' => 403,
|
||||
"bottomTabBarSwitch" => true,
|
||||
"template" => [
|
||||
'textColor' => "#303133",
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
@ -561,8 +678,14 @@ class PagesDict
|
||||
"componentTitle" => "会员信息",
|
||||
"uses" => 0,
|
||||
"ignore" => [],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
@ -580,6 +703,90 @@ class PagesDict
|
||||
"bgColorStart" => "",
|
||||
"bgColorEnd" => ""
|
||||
],
|
||||
[
|
||||
"path" => "edit-horz-blank",
|
||||
"uses" => 0,
|
||||
"id" => "5fo173bx5840",
|
||||
"componentName" => "HorzBlank",
|
||||
"componentTitle" => "辅助空白",
|
||||
"ignore" => [
|
||||
"pageBgColor",
|
||||
"componentBgUrl"
|
||||
],
|
||||
"height" => 10,
|
||||
"textColor" => "#303133",
|
||||
"pageStartBgColor" => "",
|
||||
"pageEndBgColor" => "",
|
||||
"pageGradientAngle" => "to bottom",
|
||||
"componentBgUrl" => "",
|
||||
"componentBgAlpha" => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 9,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
"topElementRounded" => 0,
|
||||
"bottomElementRounded" => 0,
|
||||
"margin" => [
|
||||
"top" => 0,
|
||||
"bottom" => 0,
|
||||
"both" => 16
|
||||
]
|
||||
],
|
||||
[
|
||||
"path" => "edit-text",
|
||||
"uses" => 0,
|
||||
"position" => "",
|
||||
"id" => "629cgb1ygcw0",
|
||||
"componentName" => "Text",
|
||||
"componentTitle" => "标题",
|
||||
"ignore" => [],
|
||||
"style" => "style-1",
|
||||
"styleName" => "风格1",
|
||||
"text" => "我的服务",
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"textColor" => "#303133",
|
||||
"fontSize" => 16,
|
||||
"fontWeight" => "normal",
|
||||
"textAlign" => "left",
|
||||
"subTitle" => [
|
||||
"text" => "",
|
||||
"color" => "#999999",
|
||||
"fontSize" => 14,
|
||||
"control" => false,
|
||||
"fontWeight" => "normal"
|
||||
],
|
||||
"more" => [
|
||||
"text" => "查看更多",
|
||||
"control" => false,
|
||||
"isShow" => false,
|
||||
"link" => [
|
||||
"name" => ""
|
||||
],
|
||||
"color" => "#999999"
|
||||
],
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 0,
|
||||
"elementBgColor" => "",
|
||||
"topElementRounded" => 0,
|
||||
"bottomElementRounded" => 0,
|
||||
"margin" => [
|
||||
"top" => 0,
|
||||
"bottom" => 0,
|
||||
"both" => 16
|
||||
]
|
||||
],
|
||||
[
|
||||
"path" => "edit-graphic-nav",
|
||||
"id" => "62b7d7hl4ok",
|
||||
@ -587,12 +794,6 @@ class PagesDict
|
||||
"componentTitle" => "图文导航",
|
||||
"uses" => 0,
|
||||
"layout" => "horizontal",
|
||||
"navTitle" => "我的服务",
|
||||
"subNavTitle" => "",
|
||||
"subNavTitleLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"subNavColor" => "#999999",
|
||||
"mode" => "graphic",
|
||||
"showStyle" => "fixed",
|
||||
"rowCount" => 4,
|
||||
@ -608,9 +809,15 @@ class PagesDict
|
||||
"weight" => "bold",
|
||||
"color" => "#303133"
|
||||
],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"topRounded" => 9,
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 0,
|
||||
"bottomRounded" => 9,
|
||||
"elementBgColor" => "",
|
||||
"topElementRounded" => 0,
|
||||
@ -709,12 +916,6 @@ class PagesDict
|
||||
"componentTitle" => "图文导航",
|
||||
"ignore" => [],
|
||||
"layout" => "vertical",
|
||||
"navTitle" => "",
|
||||
"subNavTitle" => "",
|
||||
"subNavTitleLink" => [
|
||||
"name" => ""
|
||||
],
|
||||
"subNavColor" => "#999999",
|
||||
"mode" => "graphic",
|
||||
"showStyle" => "fixed",
|
||||
"rowCount" => 4,
|
||||
@ -826,8 +1027,14 @@ class PagesDict
|
||||
]
|
||||
]
|
||||
],
|
||||
"pageBgColor" => "",
|
||||
"componentBgColor" => "rgba(255, 255, 255, 1)",
|
||||
'pageStartBgColor' => '',
|
||||
'pageEndBgColor' => '',
|
||||
'pageGradientAngle' => 'to bottom',
|
||||
'componentBgUrl' => '',
|
||||
'componentBgAlpha' => 2,
|
||||
"componentStartBgColor" => "rgba(255, 255, 255, 1)",
|
||||
"componentEndBgColor" => "",
|
||||
"componentGradientAngle" => "to bottom",
|
||||
"topRounded" => 9,
|
||||
"bottomRounded" => 9,
|
||||
"elementBgColor" => "",
|
||||
|
||||
@ -1,132 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\dict\order;
|
||||
|
||||
use app\dict\pay\PayDict;
|
||||
|
||||
/**
|
||||
*充值订单相关枚举类
|
||||
* Class RechargeOrderDict
|
||||
* @package app\dict\order
|
||||
*/
|
||||
class RechargeOrderDict
|
||||
{
|
||||
//订单状态
|
||||
//待支付
|
||||
const WAIT_PAY = 0;
|
||||
//已完成
|
||||
const FINISH = 10;
|
||||
//已关闭
|
||||
const CLOSE = -1;
|
||||
|
||||
// 退款相关状态
|
||||
// 未申请
|
||||
const NOT_APPLAY = 0;
|
||||
// 退款中
|
||||
const REFUNDING = 1;
|
||||
// 退款完成
|
||||
const REFUND_COMPLETED = 2;
|
||||
// 退款失败
|
||||
const REFUND_FAIL = -1;
|
||||
|
||||
/**
|
||||
* 当前订单支持的支付方式
|
||||
*/
|
||||
const ALLOW_PAY = [
|
||||
PayDict::WECHATPAY,
|
||||
PayDict::ALIPAY,
|
||||
PayDict::OFFLINEPAY,
|
||||
];
|
||||
|
||||
/**
|
||||
* 订单类型以及名称
|
||||
* @return array
|
||||
*/
|
||||
public static function getOrderType()
|
||||
{
|
||||
return [
|
||||
'type' => 'recharge',
|
||||
'name' => get_lang('dict_order.order_type_recharge')
|
||||
];
|
||||
}
|
||||
|
||||
public static function getStatus($status = '')
|
||||
{
|
||||
$data = [
|
||||
|
||||
self::WAIT_PAY => [
|
||||
'name' => '待支付',
|
||||
'status' => self::WAIT_PAY,
|
||||
'is_refund' => 0,
|
||||
'action' => [],
|
||||
'member_action' => [
|
||||
[
|
||||
'name' => '支付',
|
||||
'class' => '',
|
||||
'params' => ''
|
||||
],
|
||||
],
|
||||
],
|
||||
self::FINISH => [
|
||||
'name' => '已完成',
|
||||
'status' => self::FINISH,
|
||||
'is_refund' => 0,
|
||||
'action' => [],
|
||||
'member_action' => [
|
||||
],
|
||||
],
|
||||
self::CLOSE => [
|
||||
'name' => '已关闭',
|
||||
'status' => self::CLOSE,
|
||||
'is_refund' => 0,
|
||||
'action' => [],
|
||||
'member_action' => [
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
];
|
||||
if ($status == '') {
|
||||
return $data;
|
||||
}
|
||||
return $data[$status] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款状态
|
||||
* @param string $status
|
||||
* @return array|array[]|string
|
||||
*/
|
||||
public static function getRefundStatus(string $status = '')
|
||||
{
|
||||
$data = [
|
||||
self::REFUNDING => [
|
||||
'name' => get_lang('dict_order_refund.refunding'),
|
||||
'status' => self::REFUNDING
|
||||
],
|
||||
self::REFUND_COMPLETED => [
|
||||
'name' => get_lang('dict_order_refund.refund_complete'),
|
||||
'status' => self::REFUND_COMPLETED
|
||||
],
|
||||
self::REFUND_FAIL => [
|
||||
'name' => get_lang('dict_order_refund.refund_fail'),
|
||||
'status' => self::REFUND_FAIL
|
||||
]
|
||||
];
|
||||
|
||||
if ($status == '') {
|
||||
return $data;
|
||||
}
|
||||
return $data[$status] ?? '';
|
||||
}
|
||||
|
||||
}
|
||||
@ -55,6 +55,9 @@ class Index extends BaseInstall
|
||||
//fileinfo
|
||||
$fileinfo = extension_loaded('fileinfo');
|
||||
$system_variables[] = [ "name" => "fileinfo", "need" => "开启", "status" => $fileinfo ];
|
||||
//sodium
|
||||
$sodium = extension_loaded('sodium');
|
||||
$system_variables[] = [ "name" => "sodium", "need" => "开启", "status" => $sodium ];
|
||||
|
||||
$root_path = str_replace("\\", DIRECTORY_SEPARATOR, dirname(__FILE__, 4));
|
||||
$root_path = str_replace("../", DIRECTORY_SEPARATOR, $root_path);
|
||||
|
||||
@ -393,6 +393,7 @@ CREATE TABLE `pay_refund` (
|
||||
`refund_type` varchar(255) NOT NULL DEFAULT '' COMMENT '退款方式',
|
||||
`main_type` varchar(255) NOT NULL DEFAULT '' COMMENT '操作人类型',
|
||||
`main_id` int NOT NULL DEFAULT 0 COMMENT '操作人',
|
||||
`pay_refund_no` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '外部支付方式的退款单号',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '支付记录表' ROW_FORMAT = Dynamic;
|
||||
|
||||
|
||||
@ -44,18 +44,6 @@
|
||||
</div>
|
||||
<a href="javascript:void(0)" class="other-links-text" >站点后台</a>
|
||||
</li>
|
||||
<li class="other-links-item" onclick="window.open('{$root_url}/web/100000/')">
|
||||
<div class="other-links-pic">
|
||||
<img src="INSTALL_IMG/site_web.png" alt="">
|
||||
</div>
|
||||
<a href="javascript:void(0)" class="other-links-text" >站点电脑端</a>
|
||||
</li>
|
||||
<li class="other-links-item" onclick="window.open('{$root_url}/wap/100000/')">
|
||||
<div class="other-links-pic">
|
||||
<img src="INSTALL_IMG/site_h5.png" alt="">
|
||||
</div>
|
||||
<a href="javascript:void(0)" class="other-links-text" >站点手机端</a>
|
||||
</li>
|
||||
<li class="other-links-item" onclick="window.open('https://www.niucloud.com')">
|
||||
<div class="other-links-pic">
|
||||
<img src="INSTALL_IMG/admin.jpg" alt="">
|
||||
@ -91,4 +79,4 @@
|
||||
|
||||
|
||||
</script>
|
||||
{/block}
|
||||
{/block}
|
||||
|
||||
@ -26,11 +26,11 @@ class PayReturnTo extends BaseJob
|
||||
* @param $data
|
||||
* @return true
|
||||
*/
|
||||
protected function doJob($data)
|
||||
protected function doJob($site_id, $out_trade_no)
|
||||
{
|
||||
|
||||
Log::write('pay_log_' . json_encode($data));
|
||||
$res = (new CorePayService())->returnTo($data['site_id'], $data['out_trade_no']);
|
||||
Log::write('pay_log_' . $site_id.'_'.$out_trade_no);
|
||||
$res = (new CorePayService())->returnTo($site_id, $out_trade_no);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -43,8 +43,13 @@ class MemberLabel extends BaseModel
|
||||
*/
|
||||
public function getMemberNumAttr($value, $data)
|
||||
{
|
||||
if (isset($data['label_id'])) {
|
||||
return (new Member())->where([['member_label', 'like', '%"' . $data['label_id'] . '"%']])->count();
|
||||
if (isset($data[ 'label_id' ])) {
|
||||
$like_arr = [
|
||||
'[' . $data[ 'label_id' ] . ']',
|
||||
'[' . $data[ 'label_id' ] . ',%',
|
||||
'%,' . $data[ 'label_id' ] . ']'
|
||||
];
|
||||
return ( new Member() )->where([ [ 'member_label', "like", $like_arr, 'or' ] ])->count();
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,225 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\model\order;
|
||||
|
||||
use app\dict\common\ChannelDict;
|
||||
use app\model\member\Member;
|
||||
use app\model\pay\Pay;
|
||||
use core\base\BaseModel;
|
||||
use think\model\relation\HasMany;
|
||||
use think\model\relation\HasOne;
|
||||
|
||||
/**
|
||||
* 充值订单模型
|
||||
* Class RechargeOrder
|
||||
* @package app\model\order
|
||||
*/
|
||||
class RechargeOrder extends BaseModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 数据表主键
|
||||
* @var string
|
||||
*/
|
||||
protected $pk = 'order_id';
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'recharge_order';
|
||||
|
||||
//类型
|
||||
protected $type = [
|
||||
'pay_time' => 'timestamp',
|
||||
'close_time' => 'timestamp',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 登录渠道字段转化
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOrderFromNameAttr($value, $data)
|
||||
{
|
||||
if (isset($data['order_from'])) {
|
||||
return ChannelDict::getType()[$data['order_from']] ?? '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员id搜索
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchMemberIdAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('member_id', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单来源
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchOrderFromAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('order_from', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchOrderTypeAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('order_type', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付流水号
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchOutTradeNoAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('out_trade_no', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单号
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchOrderNoAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('order_no', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单金额
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function searchOrderMoneyAttr($query, $value, $data)
|
||||
{
|
||||
if (!empty($data['start_money']) && !empty($data['end_money'])) {
|
||||
$money = [$data['start_money'], $data['end_money']];
|
||||
sort($money);
|
||||
$query->where('order_money', 'between', $money);
|
||||
} else if (!empty($data['start_money'])) {
|
||||
$query->where('order_money', '>=', $data['start_money']);
|
||||
} else if (!empty($data['end_money'])) {
|
||||
$query->where('order_money', '<=', $data['end_money']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单状态
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchOrderStatusAttr($query, $value, $data)
|
||||
{
|
||||
if ($value != '') {
|
||||
$query->where('order_status', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建时间搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchCreateTimeAttr($query, $value, $data)
|
||||
{
|
||||
$start_time = empty($value[0]) ? 0 : strtotime($value[0]);
|
||||
$end_time = empty($value[1]) ? 0 : strtotime($value[1]);
|
||||
if ($start_time > 0 && $end_time > 0) {
|
||||
$query->whereBetweenTime('create_time', $start_time, $end_time);
|
||||
} else if ($start_time > 0 && $end_time == 0) {
|
||||
$query->where([['create_time', '>=', $start_time]]);
|
||||
} else if ($start_time == 0 && $end_time > 0) {
|
||||
$query->where([['create_time', '<=', $end_time]]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付时间筛选
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function searchPayTimeAttr($query, $value, $data)
|
||||
{
|
||||
$start_time = empty($value[0]) ? 0 : strtotime($value[0]);
|
||||
$end_time = empty($value[1]) ? 0 : strtotime($value[1]);
|
||||
if ($start_time > 0 && $end_time > 0) {
|
||||
$query->whereBetweenTime('pay_time', $start_time, $end_time);
|
||||
} else if ($start_time > 0 && $end_time == 0) {
|
||||
$query->where([['pay_time', '>=', $start_time]]);
|
||||
} else if ($start_time == 0 && $end_time > 0) {
|
||||
$query->where([['pay_time', '<=', $end_time]]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单项目
|
||||
* @return HasMany
|
||||
*/
|
||||
public function item()
|
||||
{
|
||||
return $this->hasMany(RechargeOrderItem::class, 'order_id', 'order_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单会员
|
||||
* @return HasOne
|
||||
*/
|
||||
public function member()
|
||||
{
|
||||
return $this->hasOne(Member::class, 'member_id', 'member_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付记录
|
||||
* @return HasOne
|
||||
*/
|
||||
public function pay()
|
||||
{
|
||||
return $this->hasOne(Pay::class, 'out_trade_no', 'out_trade_no')->bind(['pay_type_name' => 'type_name']);
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\model\order;
|
||||
|
||||
use core\base\BaseModel;
|
||||
use think\model\relation\HasOne;
|
||||
|
||||
/**
|
||||
* 订单项目模型
|
||||
* Class OrderItem
|
||||
* @package app\model\order
|
||||
*/
|
||||
class RechargeOrderItem extends BaseModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 数据表主键
|
||||
* @var string
|
||||
*/
|
||||
protected $pk = 'order_item_id';
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'recharge_order_item';
|
||||
|
||||
/**
|
||||
* @return HasOne
|
||||
*/
|
||||
public function orderNo()
|
||||
{
|
||||
return $this->hasOne(RechargeOrder::class, 'order_id', 'order_id')->joinType('left')->withField('order_id, order_no')->bind(['order_no' => 'order_no']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数量字段处理
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string|void
|
||||
*/
|
||||
public function getNumAttr($value, $data)
|
||||
{
|
||||
if (isset($data['num'])) {
|
||||
return number_format($data['num']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联订单主表
|
||||
* @return HasOne
|
||||
*/
|
||||
public function ordermain()
|
||||
{
|
||||
return $this->hasOne(RechargeOrder::class, 'order_id')->joinType('inner');
|
||||
}
|
||||
}
|
||||
@ -1,216 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\model\order;
|
||||
|
||||
use app\dict\order\RechargeOrderDict;
|
||||
use app\model\member\Member;
|
||||
use app\model\pay\Refund;
|
||||
use core\base\BaseModel;
|
||||
use think\model\relation\HasOne;
|
||||
|
||||
/**
|
||||
* 订单项目模型
|
||||
* Class OrderItem
|
||||
* @package app\model\order
|
||||
*/
|
||||
class RechargeOrderItemRefund extends BaseModel
|
||||
{
|
||||
//类型
|
||||
protected $type = [
|
||||
'create_time' => 'timestamp',
|
||||
'audit_time' => 'timestamp',
|
||||
'transfer_time' => 'timestamp',
|
||||
];
|
||||
|
||||
/**
|
||||
* 数据表主键
|
||||
* @var string
|
||||
*/
|
||||
protected $pk = 'refund_id';
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'recharge_order_item_refund';
|
||||
|
||||
/**
|
||||
* 退款状态字段处理
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function getStatusNameAttr($value, $data)
|
||||
{
|
||||
if (empty($data['status']))
|
||||
return '';
|
||||
$temp = RechargeOrderDict::getRefundStatus()[$data['status']] ?? [];
|
||||
return $temp['name'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return HasOne
|
||||
*/
|
||||
public function item()
|
||||
{
|
||||
return $this->hasOne(RechargeOrderItem::class, 'order_item_id', 'order_item_id')->joinType('inner');
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单会员
|
||||
* @return HasOne
|
||||
*/
|
||||
public function member()
|
||||
{
|
||||
return $this->hasOne(Member::class, 'member_id', 'member_id')->withField('member_id, username, mobile, nickname, headimg')->joinType('left');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联退款支付记录表
|
||||
* @return HasOne
|
||||
*/
|
||||
public function payrefund()
|
||||
{
|
||||
return $this->hasOne(Refund::class, 'refund_no', 'refund_no');
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员id搜索
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchRefundNoAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('refund_no', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单号搜索
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchOrderNoAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('order_no', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单号搜索(用于关联)
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchJoinOrderNoAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('recharge_order_item_refund.order_no', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员id搜索
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchMemberIdAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('member_id', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员id搜索
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchJoinMemberIdAttr($query, $value, $data)
|
||||
{
|
||||
if ($value) {
|
||||
$query->where('recharge_order_item_refund.member_id', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchStatusAttr($query, $value, $data)
|
||||
{
|
||||
if ($value != '') {
|
||||
$query->where('status', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款状态
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchJoinStatusAttr($query, $value, $data)
|
||||
{
|
||||
if ($value != '') {
|
||||
$query->where('recharge_order_item_refund.status', '=', $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建时间搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchCreateTimeAttr($query, $value, $data)
|
||||
{
|
||||
$start_time = empty($value[0]) ? 0 : strtotime($value[0]);
|
||||
$end_time = empty($value[1]) ? 0 : strtotime($value[1]);
|
||||
if ($start_time > 0 && $end_time > 0) {
|
||||
$query->whereBetweenTime('create_time', $start_time, $end_time);
|
||||
} else if ($start_time > 0 && $end_time == 0) {
|
||||
$query->where([['create_time', '>=', $start_time]]);
|
||||
} else if ($start_time == 0 && $end_time > 0) {
|
||||
$query->where([['create_time', '<=', $end_time]]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建时间搜索器
|
||||
* @param $query
|
||||
* @param $value
|
||||
* @param $data
|
||||
*/
|
||||
public function searchJoinCreateTimeAttr($query, $value, $data)
|
||||
{
|
||||
$start_time = empty($value[0]) ? 0 : strtotime($value[0]);
|
||||
$end_time = empty($value[1]) ? 0 : strtotime($value[1]);
|
||||
if ($start_time > 0 && $end_time > 0) {
|
||||
$query->whereBetweenTime('recharge_order_item_refund.create_time', $start_time, $end_time);
|
||||
} else if ($start_time > 0 && $end_time == 0) {
|
||||
$query->where([['recharge_order_item_refund.create_time', '>=', $start_time]]);
|
||||
} else if ($start_time == 0 && $end_time > 0) {
|
||||
$query->where([['recharge_order_item_refund.create_time', '<=', $end_time]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Niucloud-admin 企业快速开发的saas管理平台
|
||||
// +----------------------------------------------------------------------
|
||||
// | 官方网址:https://www.niucloud-admin.com
|
||||
// +----------------------------------------------------------------------
|
||||
// | niucloud团队 版权所有 开源版本可自由商用
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: Niucloud Team
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\model\order;
|
||||
|
||||
use core\base\BaseModel;
|
||||
|
||||
/**
|
||||
* 订单操作日志表
|
||||
* Class OrderLog
|
||||
* @package app\model\order
|
||||
*/
|
||||
class RechargeOrderLog extends BaseModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 数据表主键
|
||||
* @var string
|
||||
*/
|
||||
protected $pk = 'id';
|
||||
|
||||
/**
|
||||
* 模型名称
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'recharge_order_log';
|
||||
|
||||
|
||||
}
|
||||
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