mirror of
https://gitee.com/niucloud-team/niucloud-admin.git
synced 2026-03-17 19:23:34 +00:00
up
This commit is contained in:
parent
e94d59134b
commit
e9e353effd
@ -219,6 +219,29 @@ export function getDiyTheme(params: Record<string, any>) {
|
||||
return request.get(`diy/theme`, {params})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加配色
|
||||
* @param params
|
||||
*/
|
||||
export function addTheme(params: Record<string, any>) {
|
||||
return request.post(`diy/theme/add`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑配色
|
||||
* @param params
|
||||
*/
|
||||
export function editTheme(params: Record<string, any>) {
|
||||
return request.put(`diy/theme/edit/${params.id}`, params, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除配色
|
||||
* @param params
|
||||
*/
|
||||
export function deleteTheme(id: number) {
|
||||
return request.delete(`diy/theme/delete/${id}`, {showSuccessMessage: true})
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置主题配色
|
||||
|
||||
@ -19,6 +19,14 @@ export function getDiyFormPageList(params: Record<string, any>) {
|
||||
export function getDiyFormList(params: Record<string, any>) {
|
||||
return request.get(`diy/form/list`, { params })
|
||||
}
|
||||
/**
|
||||
* 获取万能表单分页列表(用于弹框选择)
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getDiyFormSelectPageList(params: Record<string, any>) {
|
||||
return request.get(`diy/form/select`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取万能表单详情
|
||||
|
||||
@ -359,6 +359,14 @@ export function getCashOutDetail(id: number) {
|
||||
export function memberAudit(params: Record<string, any>) {
|
||||
return request.put(`member/cash_out/audit/${params.id}/${params.action}`, params, { showSuccessMessage: true })
|
||||
}
|
||||
/**
|
||||
* 会员取消提现
|
||||
* @param params
|
||||
*/
|
||||
export function memberCancel(params: Record<string, any>) {
|
||||
return request.put(`member/cash_out/cancel/${params.id}`, params, { showSuccessMessage: true,showErrorMessage: true })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 会员提现转账
|
||||
|
||||
@ -99,3 +99,25 @@ export function pay(params: Record<string, any>) {
|
||||
export function getFriendsPay(tradeType : string, tradeId : number, channel: string) {
|
||||
return request.get(`pay/friendspay/info/${tradeType}/${tradeId}/${channel}`, { showErrorMessage: false })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*转账场景
|
||||
*/
|
||||
export function getTransferScene() {
|
||||
return request.get(`pay/transfer_scene`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改场景id
|
||||
*/
|
||||
export function setSceneId(params: Record<string, any>) {
|
||||
return request.post(`pay/transfer_scene/set_scene_id/${params.scene}`, params, { showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置业务场景配置
|
||||
*/
|
||||
export function setTradeScene(params: Record<string, any>) {
|
||||
return request.post(`pay/transfer_scene/set_trade_scene/${params.type}`, params)
|
||||
}
|
||||
@ -585,6 +585,13 @@ export function clearSchemaCache(params: Record<string, any>) {
|
||||
return request.post(`sys/schema/clear`, {}, { showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理缓存
|
||||
*/
|
||||
export function clearCache(params: Record<string, any>) {
|
||||
return request.post(`sys/cache/clear`, {}, { showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 获取应用 ****************************************************/
|
||||
/**
|
||||
* 获取应用
|
||||
|
||||
@ -194,6 +194,7 @@ const open = async () => {
|
||||
} else {
|
||||
loading.value = false
|
||||
cloudBuildCheck.value = data
|
||||
showDialog.value = true
|
||||
}
|
||||
}).catch(() => {
|
||||
showDialog.value = false
|
||||
|
||||
@ -20,11 +20,6 @@
|
||||
"adminDisabled":"超级管理员不可编辑",
|
||||
"userUnlockTips":"确定要解锁该管理员吗?",
|
||||
"userLockTips":"确定要锁定该管理员吗?",
|
||||
"userType": "用户类型",
|
||||
"adminAdministrators": "平台管理员",
|
||||
"siteAdministrators": "站点管理员",
|
||||
"userTypePlaceholder": "请选择用户类型",
|
||||
"siteAdministratorsDisabled": "站点管理员不可编辑",
|
||||
"manager": "用户",
|
||||
"managerPlaceholder": "请选择用户",
|
||||
"managerTips": "选择或者新增用户作为管理员",
|
||||
|
||||
@ -257,8 +257,9 @@
|
||||
"horzLineStyleDashed": "虚线",
|
||||
"horzLineBorderColor": "线条颜色",
|
||||
"horzLineBorderWidth": "线条宽度",
|
||||
"floatBtnBtton": "按钮位置",
|
||||
"floatBtnButton": "按钮位置",
|
||||
"floatBtnOffset": "上下偏移",
|
||||
"lateralBtnOffset": "左右偏移",
|
||||
"floatBtnImageSet": "图片设置",
|
||||
"floatBtnImageSize": "图片大小",
|
||||
"floatBtnAroundRadius": "图片圆角",
|
||||
|
||||
@ -258,8 +258,9 @@
|
||||
"horzLineStyleDashed": "虚线",
|
||||
"horzLineBorderColor": "线条颜色",
|
||||
"horzLineBorderWidth": "线条宽度",
|
||||
"floatBtnBtton": "按钮位置",
|
||||
"floatBtnButton": "按钮位置",
|
||||
"floatBtnOffset": "上下偏移",
|
||||
"lateralBtnOffset": "左右偏移",
|
||||
"floatBtnImageSet": "图片设置",
|
||||
"floatBtnImageSize": "图片大小",
|
||||
"floatBtnAroundRadius": "图片圆角",
|
||||
@ -361,7 +362,7 @@
|
||||
"imageLimitErrorTips":"限制数量格式输入错误",
|
||||
"imageLimitErrorTipsTwo":"限制数量不能小于0",
|
||||
"imageLimitErrorTipsThree":"限制数量必须大于0",
|
||||
"imafeLimitErrorTipsFour":"限制数量最大不能超过20",
|
||||
"imafeLimitErrorTipsFour":"限制数量最大不能超过9",
|
||||
|
||||
"defaultValueTips":"设置后,默认值会自动填充到输入框,填表人可在此基础上进行修改。",
|
||||
"defaultErrorTips":"默认值格式输入错误",
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
"batchEmptySelectedFormsTips": "请选择要删除的表单",
|
||||
"batchFormsDeleteTips": "确定要删除选中的表单吗?",
|
||||
"promotion":"推广",
|
||||
"submirSuccess":"提交成功页",
|
||||
"submitSuccess":"提交成功页",
|
||||
"writeSet":"填写设置",
|
||||
"export":"导出",
|
||||
"detail":"详情",
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"cashOutMoney": "转账金额",
|
||||
"auditTime": "审核时间",
|
||||
"transferTime": "转账时间",
|
||||
"memberInfoPlaceholder": "请输入会员名称/会员昵称/手机号",
|
||||
"memberInfoPlaceholder": "请输入会员编号/昵称/手机号搜索",
|
||||
"cashOutNumber": "提现单号",
|
||||
"cashOutNumberPlaceholder": "请输入提现单号",
|
||||
"alipayAccount": "支付宝账号",
|
||||
@ -60,5 +60,7 @@
|
||||
"transferRemark":"转账补充说明",
|
||||
"transferRemarkPlaceholder":"请输入转账补充说明",
|
||||
"notes":"备注",
|
||||
"check":"检查打款进度"
|
||||
"check":"检查打款进度",
|
||||
"cancelWithdrawal":"取消",
|
||||
"cancelTips":"确定要取消提现吗?"
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
"todayData": "今日数据",
|
||||
"memberNumb": "新增会员数",
|
||||
"orderMoney": "订单金额",
|
||||
"numberOfSites": "站点数量",
|
||||
"numberOfVisitors": "今日访客数",
|
||||
"commonlyUsedFunction": "常用功能",
|
||||
"articleList": "文章列表",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"memberId":"会员编号",
|
||||
"memberInfoPlaceholder":"请输入会员信息",
|
||||
"memberInfoPlaceholder":"请输入会员编码/昵称/手机号搜索",
|
||||
"memberInfo":"会员信息",
|
||||
"mobile":"手机号码",
|
||||
"nickName":"会员昵称",
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"isMobile": "手机验证码登录",
|
||||
"isMobileTip": "开启之后可以使用手机+验证码进行注册和登录或者快捷登录/注册",
|
||||
"isBindMobile": "强制绑定手机",
|
||||
"isBindMobileTip": "开启之后,会员注册时会强制绑定手机号,并且在相关页面也会引导会员强制绑定手机账号,否则将影响功能正常使用,方便会员在不同端口统一账号,也方便商家进行管理",
|
||||
"isBindMobileTip": "开启之后,会员注册时会强制绑定手机号,并且在相关页面也会引导会员强制绑定手机账号,否则将影响功能正常使用,方便会员在不同端口统一账号,也方便商家进行管理,已注册会员不受影响",
|
||||
"agreement": "政策协议",
|
||||
"agreementTips": "注册时服务协议和隐私协议是否进行展示",
|
||||
"tripartiteSetting": "第三方设置",
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
"appPublicCertPathTips": "上传appCertPublicKey文件",
|
||||
"alipayPublicCertPathTips": "上传alipayCertPublicKey文件",
|
||||
"alipayRootCertPathTips": "上传alipayRootCert文件",
|
||||
"operationTip": "温馨提示:打款设置用于会员提现转账,发放红包等场景",
|
||||
"transferTips":"注意:应微信方规定,在2025年1月15日前开通商家转账到零钱服务的商户号可正常使用转账功能,之后开通的不支持使用转账到零钱服务"
|
||||
"operationTip": "温馨提示:打款设置用于会员提现转账,发放红包等场景"
|
||||
|
||||
}
|
||||
|
||||
10
admin/src/app/lang/zh-cn/setting.transfer_scene.json
Normal file
10
admin/src/app/lang/zh-cn/setting.transfer_scene.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"transferSceneId":"转账场景ID",
|
||||
"transferType":"业务类型",
|
||||
"recvPerception":"收款感知",
|
||||
"recvPerceptionTips":"请选择收款感知",
|
||||
"reportInfos":"报备背景",
|
||||
"operation":"操作",
|
||||
"deploy":"配置",
|
||||
"noData":"暂无数据"
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"refresh":"刷新",
|
||||
"refreshMenu":"刷新菜单",
|
||||
"refreshMenuDesc":"新增/修改插件菜单后,需要刷新插件菜单",
|
||||
"dataCache":"数据缓存",
|
||||
"dataCacheDesc":"新增/修改数据表后,需要清除数据表缓存"
|
||||
"dataCache":"清除缓存",
|
||||
"dataCacheDesc":"清除系统的所有缓存",
|
||||
"refresh": "立即清除",
|
||||
"clearCacheTips": "确定要清除缓存吗?"
|
||||
}
|
||||
@ -27,11 +27,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getAreaListByPid } from '@/app/api/sys'
|
||||
import { addMemberAddress } from '@/app/api/member'
|
||||
import { filterNumber } from '@/utils/common'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { FormRules } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
@ -39,7 +36,7 @@ import useDiyStore from '@/stores/modules/diy'
|
||||
const diyStore = useDiyStore()
|
||||
|
||||
const dialogThemeVisible = ref(false)
|
||||
let confirmRepeat = false
|
||||
const confirmRepeat = ref(false)
|
||||
const emit = defineEmits(['confirm'])
|
||||
/**
|
||||
* 表单数据
|
||||
@ -99,8 +96,10 @@ const formRules = reactive<FormRules>({
|
||||
})
|
||||
|
||||
const confirmFn = async (formEl: FormInstance | undefined) => {
|
||||
if (confirmRepeat || !formEl) return
|
||||
if (confirmRepeat.value || !formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (confirmRepeat.value) return
|
||||
confirmRepeat.value = true
|
||||
if (valid) {
|
||||
emit('confirm', cloneDeep(formData));
|
||||
dialogThemeVisible.value = false;
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
<el-radio label="static">{{ t('carouselSearchShowWayStatic') }}</el-radio>
|
||||
<el-radio label="fixed">{{ t('carouselSearchShowWayFixed') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<div v-if="diyStore.editComponent.positionWay == 'fixed'" class="text-sm text-gray-400 mb-[10px]">滑动页面查看效果</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('carouselSearchFixedBgColor')" v-show="diyStore.editComponent.positionWay == 'fixed'">
|
||||
<el-color-picker v-model="diyStore.editComponent.fixedBgColor" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
|
||||
@ -28,13 +28,15 @@
|
||||
</template>
|
||||
|
||||
</el-dialog> -->
|
||||
<h3 class="mb-[10px]">{{ t('floatBtnBtton') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('floatBtnButton') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('floatBtnBtton')">
|
||||
<el-form-item :label="t('floatBtnButton')">
|
||||
<span>{{ selectTemplate.name }}</span>
|
||||
<ul class="ml-[10px] flex items-center">
|
||||
<template v-for="(item,i) in templateList" :key="i">
|
||||
<li v-if="diyStore.editComponent.style==='style-1'||(diyStore.editComponent.style==='style-2'&&i>1)" :class="['w-[50px] h-[32px] flex items-center justify-center border-solid border-[1px] border-[#eee] cursor-pointer', {'border-r-transparent': templateList.length != (i+1)}, (item.className == diyStore.editComponent.bottomPosition) ? '!border-[var(--el-color-primary)]' : '' ]" @click="changeTemplateList(item)">
|
||||
<li v-if="diyStore.editComponent.style==='style-1'||(diyStore.editComponent.style==='style-2'&&i>1)"
|
||||
:class="['w-[50px] h-[32px] flex items-center justify-center border-solid border-[1px] border-[#eee] cursor-pointer', {'border-r-transparent': templateList.length != (i+1)}, (item.className == diyStore.editComponent.bottomPosition) ? '!border-[var(--el-color-primary)]' : '' ]"
|
||||
@click="changeTemplateList(item)">
|
||||
<span :class="['iconfont !text-[20px]', item.src]"></span>
|
||||
</li>
|
||||
</template>
|
||||
@ -43,6 +45,9 @@
|
||||
<el-form-item :label="t('floatBtnOffset')">
|
||||
<el-slider v-model="diyStore.editComponent.offset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="100" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('lateralBtnOffset')">
|
||||
<el-slider v-model="diyStore.editComponent.lateralOffset" show-input size="small" class="ml-[10px] diy-nav-slider" :max="15" :min="-10" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="edit-attr-item-wrap">
|
||||
@ -57,12 +62,15 @@
|
||||
|
||||
<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]">
|
||||
<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)">
|
||||
<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>
|
||||
|
||||
|
||||
@ -54,7 +54,8 @@
|
||||
<p class="text-sm text-gray-400 mb-[10px]">{{ t('graphicNavTips') }}</p>
|
||||
|
||||
<div ref="imageBoxRef">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-for="(item,index) in diyStore.editComponent.list" :key="item.id"
|
||||
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')" v-show="diyStore.editComponent.mode === 'graphic' || diyStore.editComponent.mode === 'img'">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
@ -63,7 +64,9 @@
|
||||
<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)">
|
||||
<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>
|
||||
|
||||
@ -73,7 +76,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button v-show="diyStore.editComponent.list.length < 50" class="w-full" @click="addGraphicNav">{{ t('addGraphicNav') }}</el-button>
|
||||
<el-button v-show="diyStore.editComponent.list.length < 50" class="w-full" @click="addGraphicNav">
|
||||
{{ t('addGraphicNav') }}
|
||||
</el-button>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
<el-color-picker v-model="diyStore.editComponent.borderColor" show-alpha :predefine="diyStore.predefineColors" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('horzLineBorderWidth')">
|
||||
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small" class="ml-[10px] diy-nav-slider" :min="1" :max="10"/>
|
||||
<el-slider v-model="diyStore.editComponent.borderWidth" show-input size="small"
|
||||
class="ml-[10px] diy-nav-slider" :min="1" :max="10" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -23,7 +23,9 @@
|
||||
<upload-image v-model="item.imageUrl" :limit="1" @change="selectImg" />
|
||||
</el-form-item>
|
||||
|
||||
<div class="del absolute cursor-pointer z-[2] top-[-8px] right-[-8px]" v-show="diyStore.editComponent.list.length > 1" @click="diyStore.editComponent.list.splice(index,1)">
|
||||
<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>
|
||||
|
||||
@ -33,7 +35,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addImageAd">{{ t('addImageAd') }}</el-button>
|
||||
<el-button v-show="diyStore.editComponent.list.length < 10" class="w-full" @click="addImageAd">
|
||||
{{ t('addImageAd') }}
|
||||
</el-button>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
<template>
|
||||
<!-- 内容 -->
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
@ -6,7 +5,8 @@
|
||||
<h3 class="mb-[10px]">{{ t('selectStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('selectStyle')" class="flex">
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName }}</span>
|
||||
<span class="text-primary flex-1 cursor-pointer"
|
||||
@click="showStyle">{{ diyStore.editComponent.styleName }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
@ -17,7 +17,10 @@
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<template v-for="(item,index) in styleList" :key="index">
|
||||
<div :class="{ 'border-primary': selectStyle.value == item.value, '!mr-[0]': [(index+1)%3] == 0 }" @click="changeStyle(item)" class="flex my-[5px] items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50">
|
||||
<div
|
||||
:class="{ 'border-primary': selectStyle.value == item.value, '!mr-[0]': [(index+1)%3] == 0 }"
|
||||
@click="changeStyle(item)"
|
||||
class="flex my-[5px] items-center justify-center overflow-hidden w-[200px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50">
|
||||
<img :src="img(item.url)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -18,7 +18,8 @@
|
||||
<div :class="['mr-[10px] rounded cursor-pointer w-[100px] border-[1px] border-solid', {'border-[var(--el-color-primary)]': diyStore.editComponent.systemUrl == 'style_2' && diyStore.editComponent.imgType == 'system'}]">
|
||||
<img src="@/app/assets/images/diy/notice/style_2.png" class="px-[10px] py-[5px]" @click="changeStyle('style_2')" />
|
||||
</div>
|
||||
<div @click.stop="diyStore.editComponent.imgType = 'diy'" :class="['mr-[10px] rounded cursor-pointer diy-upload-img border-[1px] border-solid', {'border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
|
||||
<div @click.stop="diyStore.editComponent.imgType = 'diy'"
|
||||
:class="['mr-[10px] rounded cursor-pointer diy-upload-img border-[1px] border-solid', {'border-[var(--el-color-primary)]': (diyStore.editComponent.imageUrl && diyStore.editComponent.imgType == 'diy') }]">
|
||||
<upload-image v-model="diyStore.editComponent.imageUrl" :limit="1" />
|
||||
</div>
|
||||
</div>
|
||||
@ -57,7 +58,9 @@
|
||||
<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)">
|
||||
<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>
|
||||
|
||||
@ -105,6 +108,7 @@ import useDiyStore from '@/stores/modules/diy'
|
||||
import { ref, watch, onMounted, nextTick } from 'vue'
|
||||
import { range } from 'lodash-es'
|
||||
import Sortable from 'sortablejs'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = [] // 忽略公共属性
|
||||
|
||||
@ -134,8 +138,6 @@ diyStore.editComponent.list.forEach((item: any) => {
|
||||
if (!item.id) item.id = diyStore.generateRandom()
|
||||
})
|
||||
|
||||
const selectStyle = ref(diyStore.editComponent.style)
|
||||
|
||||
const changeStyle = (value: any) => {
|
||||
diyStore.editComponent.systemUrl = value;
|
||||
diyStore.editComponent.imgType = 'system';
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
<h3 class="mb-[10px]">{{ t('pageContent') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('diyPageTitle')">
|
||||
<el-input v-model.trim="diyStore.pageTitle" :placeholder="t('diyPageTitlePlaceholder')" clearable maxlength="16" show-word-limit/>
|
||||
<el-input v-model.trim="diyStore.pageTitle" :placeholder="t('diyPageTitlePlaceholder')" clearable
|
||||
maxlength="16" show-word-limit />
|
||||
<div class="text-sm text-gray-400">{{ t('pageTitleTips') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -68,16 +69,20 @@
|
||||
<el-dialog v-model="showDialog" :title="t('selectStyle')" width="800px">
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50"
|
||||
:class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
|
||||
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style1.jpg" />
|
||||
</div>
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] mb-[15px] cursor-pointer border bg-gray-50"
|
||||
:class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
|
||||
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style2.jpg" />
|
||||
</div>
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mb-[15px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-3' }" @click="selectStyle = 'style-3'">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mb-[15px] cursor-pointer border bg-gray-50"
|
||||
:class="{ 'border-primary': selectStyle == 'style-3' }" @click="selectStyle = 'style-3'">
|
||||
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style3.jpg" />
|
||||
</div>
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-4' }" @click="selectStyle = 'style-4'">
|
||||
<div class="flex items-center justify-center overflow-hidden w-[32%] h-[100px] mr-[2%] cursor-pointer border bg-gray-50"
|
||||
:class="{ 'border-primary': selectStyle == 'style-4' }" @click="selectStyle = 'style-4'">
|
||||
<img class="max-w-[100%] max-h-[100%]" src="@/app/assets/images/diy/head/nav_style4.jpg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -10,7 +10,8 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subTitle')">
|
||||
<el-input v-model.trim="diyStore.editComponent.moduleOne.head.subText" :placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
<el-input v-model.trim="diyStore.editComponent.moduleOne.head.subText"
|
||||
:placeholder="t('subTitlePlaceholder')" clearable maxlength="8" show-word-limit />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('subTitleTextColor')">
|
||||
@ -23,7 +24,8 @@
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleOne.listFrame.endColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<div v-for="(item,index) in diyStore.editComponent.moduleOne.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-for="(item,index) in diyStore.editComponent.moduleOne.list" :key="item.id"
|
||||
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
@ -69,7 +71,8 @@
|
||||
<el-color-picker v-model="diyStore.editComponent.moduleTwo.listFrame.endColor" show-alpha />
|
||||
</el-form-item>
|
||||
|
||||
<div v-for="(item,index) in diyStore.editComponent.moduleTwo.list" :key="item.id" class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<div v-for="(item,index) in diyStore.editComponent.moduleTwo.list" :key="item.id"
|
||||
class="item-wrap p-[10px] pb-0 relative border border-dashed border-gray-300 mb-[16px]">
|
||||
<el-form-item :label="t('image')">
|
||||
<upload-image v-model="item.imageUrl" :limit="1" />
|
||||
</el-form-item>
|
||||
@ -121,7 +124,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { img } from '@/utils/common'
|
||||
import { ref, reactive } from 'vue'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
|
||||
@ -9,7 +9,9 @@
|
||||
<span>{{ selectTemplate.name }}</span>
|
||||
</el-form-item>
|
||||
<ul class="selected-template-list">
|
||||
<li v-for="(item,i) in templateList" :key="i" :class="[(item.className == diyStore.editComponent.mode) ? 'selected' : '' ]" @click="changeTemplateList(i)">
|
||||
<li v-for="(item,i) in templateList" :key="i"
|
||||
:class="[(item.className == diyStore.editComponent.mode) ? 'selected' : '' ]"
|
||||
@click="changeTemplateList(i)">
|
||||
<icon :name="'iconfont ' + item.src" size="16px" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
<h3 class="mb-[10px]">{{ t('styleSet') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('selectStyle')" class="flex">
|
||||
<span class="text-primary flex-1 cursor-pointer" @click="showStyle">{{ diyStore.editComponent.styleName }}</span>
|
||||
<span class="text-primary flex-1 cursor-pointer"
|
||||
@click="showStyle">{{ diyStore.editComponent.styleName }}</span>
|
||||
<el-icon>
|
||||
<ArrowRight />
|
||||
</el-icon>
|
||||
@ -66,10 +67,14 @@
|
||||
<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'">
|
||||
<div
|
||||
class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] mr-[12px] cursor-pointer border bg-gray-50"
|
||||
:class="{ 'border-primary': selectStyle == 'style-1' }" @click="selectStyle = 'style-1'">
|
||||
<img class="max-w-[280px] max-h-[220px]" src="@/app/assets/images/diy/text/style1.png" />
|
||||
</div>
|
||||
<div class="flex items-center justify-center overflow-hidden w-[280px] h-[100px] cursor-pointer border bg-gray-50" :class="{ 'border-primary': selectStyle == 'style-2' }" @click="selectStyle = 'style-2'">
|
||||
<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>
|
||||
|
||||
@ -2,17 +2,19 @@
|
||||
<el-dialog v-model="dialogThemeVisible" title="编辑色调" width="850px" align-center destroy-on-close="true">
|
||||
<el-form :model="openData" label-width="150px" :rules="formRules">
|
||||
<el-form-item label="色调名称" prop="title">
|
||||
<el-input v-model="openData.title" placeholder="请输入色调名称" maxlength="15" class="!w-[250px]" :disabled="openData.mark != 'diy'" />
|
||||
<el-input v-model="openData.title" placeholder="请输入色调名称" maxlength="15" class="!w-[250px]" :disabled="openData.id != ''" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-form :model="formData" label-width="150px" class="h-[640px] overflow-auto" ref="formRef" @submit.prevent>
|
||||
|
||||
<el-form-item :label="item.title" v-for="(item,index) in formData" :key="index" :prop="`${index}.value`" :rules="[{ required: true, message: `请选择${item.title}色调`, trigger: 'blur' }]">
|
||||
<el-color-picker v-model="item.value" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
<el-form-item :label="item.title" v-for="(item, index) in formData" :key="index" :prop="`${index}.value`"
|
||||
:rules="[{ required: true, message: `请选择${item.title}色调`, trigger: 'blur' }]">
|
||||
<el-color-picker v-model="item.value" show-alpha :predefine="diyStore.predefineColors" @change="colorPickerChange($event, item)" />
|
||||
<div class="form-tip">{{ item.tip }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="item.title" v-for="(item,index) in openData.diy_value" :key="index">
|
||||
<el-form-item :label="item.title" v-for="(item, index) in openData.new_theme" :key="index">
|
||||
<div class="flex items-center">
|
||||
<el-color-picker v-model="item.value" show-alpha :predefine="diyStore.predefineColors" />
|
||||
<span class="text-primary cursor-pointer text-[14px] ml-[20px]" @click="editThemeFn(item)">编辑</span>
|
||||
@ -29,7 +31,7 @@
|
||||
<div class="form-tip">新增颜色key值不能与当前的存在的key值重复</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<add-theme ref="addThemeRef" @confirm="addThemeConfirm" />
|
||||
<add-theme-component ref="addThemeRef" @confirm="addThemeConfirm" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogThemeVisible = false">取消</el-button>
|
||||
@ -43,22 +45,25 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { filterNumber } from '@/utils/common'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import addTheme from './add-theme.vue'
|
||||
import addThemeComponent from './add-theme.vue'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { addTheme, editTheme } from '@/app/api/diy'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
|
||||
const dialogThemeVisible = ref(false)
|
||||
const addThemeRef = ref(null)
|
||||
const addThemeRef = ref()
|
||||
const openData: Record<string, any> = reactive({ // 用于接收弹窗打开时的参数
|
||||
title: '',
|
||||
mark: '',
|
||||
diy_value: [],
|
||||
default: {},
|
||||
data: {}
|
||||
id: '',
|
||||
theme: {},
|
||||
default_theme: {},
|
||||
new_theme: [],
|
||||
key: '',
|
||||
theme_field: [] // 展示数据源
|
||||
})
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
@ -74,101 +79,45 @@ const formRules = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = [
|
||||
{
|
||||
title: '主色调',
|
||||
label: '--primary-color',
|
||||
value: '#333333',
|
||||
tip: '主色调在uiapp中使用:var(--primary-color)'
|
||||
},
|
||||
{
|
||||
title: '辅色调',
|
||||
label: '--primary-help-color',
|
||||
value: '#333333',
|
||||
tip: '辅色调在uiapp中使用:var(--primary-help-color)'
|
||||
},
|
||||
{
|
||||
title: '页面背景色',
|
||||
label: '--page-bg-color',
|
||||
value: '#ffffff',
|
||||
tip: '页面背景色在uiapp中使用:var(--page-bg-color)'
|
||||
},
|
||||
{
|
||||
title: '主色调浅色(淡)',
|
||||
label: '--primary-color-light',
|
||||
value: '',
|
||||
tip: '主色调浅色(淡)在uiapp中使用:var(--primary-color-light)'
|
||||
},
|
||||
{
|
||||
title: '主色调浅色(深)',
|
||||
label: '--primary-color-light2',
|
||||
value: '',
|
||||
tip: '主色调浅色(深)在uiapp中使用:var(--primary-color-light2)'
|
||||
},
|
||||
{
|
||||
title: '灰色调',
|
||||
label: '--primary-color-dark',
|
||||
value: '#cccccc',
|
||||
tip: '灰色调在uiapp中使用:var(--primary-color-dark)'
|
||||
},
|
||||
{
|
||||
title: '禁用色',
|
||||
label: '--primary-color-disabled',
|
||||
value: '#dddddd',
|
||||
tip: '禁用色在uiapp中使用:var(--primary-color-disabled)'
|
||||
},
|
||||
{
|
||||
title: '价格颜色',
|
||||
label: '--price-text-color',
|
||||
value: '#333333',
|
||||
tip: '价格颜色在uiapp中使用:var(--price-text-color)'
|
||||
}
|
||||
]
|
||||
const formData = ref([...cloneDeep(initialFormData)])
|
||||
const formData = ref()
|
||||
|
||||
const open = (res:any) => { // 参数: name=>色调名称,key=>区分系统还是应用的标识,default=>色调颜色的默认值,用于重置,data=>当前色调颜色值
|
||||
const open = (res: any) => { // 参数: title=>色调名称,key=>区分系统还是应用的标识,default_theme=>色调颜色的默认值,用于重置,theme=>当前色调颜色值
|
||||
Object.keys(openData).forEach((key: string) => {
|
||||
openData[key] = res[key] != undefined ? cloneDeep(res[key]) : ''
|
||||
})
|
||||
|
||||
// 恢复默认值
|
||||
formData.value.forEach((item, index) => {
|
||||
initialFormData.forEach((subItem, subIndex) => {
|
||||
if (item.label == subItem.label) {
|
||||
item.value = subItem.value
|
||||
}
|
||||
})
|
||||
})
|
||||
formData.value = [...cloneDeep(openData.theme_field)]
|
||||
|
||||
// 渲染值
|
||||
formData.value.forEach((item, index) => {
|
||||
item.value = res.data[item.label] ? res.data[item.label] : item.value
|
||||
item.value = res.theme[item.label] ? res.theme[item.label] : item.value
|
||||
})
|
||||
console.log(formData.value, openData)
|
||||
dialogThemeVisible.value = true
|
||||
}
|
||||
|
||||
// 新增颜色
|
||||
const addThemeFn = () => {
|
||||
const keyArr = []
|
||||
// 传入keyArr, 避免添加重复key
|
||||
const keyArr: string[] = []
|
||||
formData.value.forEach((item, index) => {
|
||||
keyArr.push(item.label)
|
||||
})
|
||||
const obj = {
|
||||
key: keyArr
|
||||
}
|
||||
|
||||
addThemeRef.value.open(obj)
|
||||
}
|
||||
|
||||
// 编辑颜色
|
||||
const editThemeFn = (res: any) => {
|
||||
const keyArr = []
|
||||
// 传入keyArr, 避免添加重复key
|
||||
const keyArr: string[] = []
|
||||
formData.value.forEach((item, index) => {
|
||||
keyArr.push(item.label)
|
||||
})
|
||||
|
||||
const obj = {
|
||||
key: keyArr,
|
||||
data: res
|
||||
@ -178,42 +127,42 @@ const editThemeFn = (res:any) => {
|
||||
// 删除颜色
|
||||
const deleteThemeFn = (res: any) => {
|
||||
let indent = -1
|
||||
for (let i = 0; i < openData.diy_value.length; i++) {
|
||||
if (openData.diy_value[i].label == res.label) {
|
||||
for (let i = 0; i < openData.new_theme.length; i++) {
|
||||
if (openData.new_theme[i].label == res.label) {
|
||||
indent = i
|
||||
}
|
||||
}
|
||||
if (indent > -1) {
|
||||
openData.diy_value.splice(indent, 1)
|
||||
openData.new_theme.splice(indent, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加颜色组件回调
|
||||
const addThemeConfirm = (res: any) => {
|
||||
for (let i = 0; i < openData.diy_value.length; i++) {
|
||||
if (openData.diy_value[i].label == res.label) {
|
||||
openData.diy_value[i] = res
|
||||
for (let i = 0; i < openData.new_theme.length; i++) {
|
||||
if (openData.new_theme[i].label == res.label) {
|
||||
openData.new_theme[i] = res
|
||||
return
|
||||
}
|
||||
}
|
||||
openData.diy_value.push(res)
|
||||
openData.new_theme.push(res)
|
||||
}
|
||||
|
||||
// 重置当前配色
|
||||
const resetConfirmFn = () => {
|
||||
if (openData.default && Object.keys(openData.default).length) {
|
||||
if (openData.default_theme && Object.keys(openData.default_theme).length) {
|
||||
formData.value.forEach((item, index) => {
|
||||
item.value = cloneDeep(openData.default[item.label])
|
||||
item.value = openData.default_theme[item.label]
|
||||
})
|
||||
} else {
|
||||
formData.value = cloneDeep(initialFormData)
|
||||
}
|
||||
|
||||
openData.diy_value = []
|
||||
|
||||
if (openData.mark == 'diy') {
|
||||
formData.value = cloneDeep(openData.theme_field)
|
||||
// 新增时,点击充值按钮,清空title
|
||||
if (!openData.id) {
|
||||
openData.title = ''
|
||||
}
|
||||
}
|
||||
|
||||
openData.new_theme = []
|
||||
|
||||
ElMessage({
|
||||
message: '重置成功',
|
||||
@ -221,38 +170,98 @@ const resetConfirmFn = () => {
|
||||
})
|
||||
}
|
||||
|
||||
let confirmRepeat = false
|
||||
const confirmFn = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
const params = {
|
||||
title: '',
|
||||
id: '',
|
||||
theme: {},
|
||||
diy_value: [],
|
||||
title: ''
|
||||
default_theme: {},
|
||||
new_theme: [],
|
||||
addon: ''
|
||||
}
|
||||
|
||||
params.title = openData.title
|
||||
|
||||
formData.value.forEach((item, index) => {
|
||||
params.theme[item.label] = item.value
|
||||
})
|
||||
openData.diy_value.forEach((item, index) => {
|
||||
openData.new_theme.forEach((item, index) => {
|
||||
params.theme[item.label] = item.value
|
||||
})
|
||||
|
||||
params.diy_value = openData.diy_value || []
|
||||
params.new_theme = openData.new_theme || []
|
||||
let api = null
|
||||
if (openData.id) {
|
||||
api = editTheme
|
||||
params.id = openData.id
|
||||
} else {
|
||||
api = addTheme
|
||||
}
|
||||
params.addon = openData.key
|
||||
|
||||
emit('confirm', params)
|
||||
// 新增时,默认主题为当前主题
|
||||
if (openData.id == '') {
|
||||
const defaultTheme = {}
|
||||
openData.theme_field.forEach((item, index) => {
|
||||
defaultTheme[item.label] = item.value
|
||||
})
|
||||
params.default_theme = cloneDeep(defaultTheme)
|
||||
} else {
|
||||
params.default_theme = cloneDeep(openData.default_theme)
|
||||
}
|
||||
if (confirmRepeat) return false
|
||||
confirmRepeat = true
|
||||
|
||||
api(params).then((res: any) => {
|
||||
confirmRepeat = false
|
||||
dialogThemeVisible.value = false
|
||||
emit('confirm', params)
|
||||
}).catch(() => {
|
||||
confirmRepeat = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const applyOpacity = (color, opacity) => {
|
||||
// 解析十六进制或 RGBA 格式
|
||||
const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/
|
||||
const rgbaRegex = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(,\s*\d*\.?\d+)?\)$/
|
||||
|
||||
if (hexRegex.test(color)) {
|
||||
// 处理十六进制颜色(如 #ffffff)
|
||||
const hex = color.replace('#', '')
|
||||
const r = parseInt(hex.substring(0, 2), 16)
|
||||
const g = parseInt(hex.substring(2, 4), 16)
|
||||
const b = parseInt(hex.substring(4, 6), 16)
|
||||
return `rgba(${r},${g},${b},${opacity})`
|
||||
} else if (rgbaRegex.test(color)) {
|
||||
// 处理 RGBA 颜色(如 rgba(255,255,255,0.5))
|
||||
return color.replace(/[\d\.]+\)$/, `${opacity})`)
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
const colorPickerChange = (e: any, data: any) => {
|
||||
if (data.label == '--primary-color') {
|
||||
formData.value.forEach((item, index) => {
|
||||
if (item.label == '--primary-color-light') {
|
||||
item.value = applyOpacity(data.value, 0.1)
|
||||
}
|
||||
if (item.label == '--primary-color-light2') {
|
||||
item.value = applyOpacity(data.value, 0.8)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
defineExpose({
|
||||
dialogThemeVisible,
|
||||
open
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -1,26 +1,42 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogThemeVisible" :title="data.addon_title" width="550px" align-center>
|
||||
<el-form class="page-form mt-[15px]" :model="formData" label-width="90px" v-loading="loading">
|
||||
<el-form-item label="选择配色">
|
||||
<div class="flex items-center flex-wrap">
|
||||
<template v-for="(tempItem,tempIndex) in theme_temp">
|
||||
<div :key="tempIndex" v-if="tempItem.name != 'diy'" class="flex items-center border-[1px] border-solid border-[#dcdee2] rounded-[5px] h-[40px] px-[15px] mr-[10px] cursor-pointer my-[5px]" :class="{'!border-[var(--el-color-primary)]': curr_theme_mark == tempItem.name}" @click="themeTempChange(tempItem)">
|
||||
<span v-if="data.theme" class="w-[20px] h-[20px] mr-[5px] rounded-[3px]" :style="{backgroundColor: data.theme['--primary-color']}"></span>
|
||||
<span class="text-[14px]" :class="{'!text-[var(--el-color-primary)]': curr_theme_mark == tempItem.name}">{{tempItem.title}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex items-center border-[1px] border-solid border-[#dcdee2] rounded-[5px] h-[40px] px-[15px] cursor-pointer" :class="{'!border-[var(--el-color-primary)]': curr_theme_mark == 'diy'}" @click="themeTempChange('diy')">
|
||||
<span class="nc-iconfont nc-icon-tianjiaV6xx mr-[5px]" :class="{'!text-[var(--el-color-primary)]': curr_theme_mark == 'diy'}"></span>
|
||||
<span class="text-[14px]" :class="{'!text-[var(--el-color-primary)]': curr_theme_mark == 'diy'}">自定义</span>
|
||||
<el-dialog v-model="dialogThemeVisible" :title="dialogTitle" width="535px" align-center class="custom-theme-dialog" @close="cancelFn">
|
||||
<div class="flex flex-col items-baseline">
|
||||
<div class="flex items-center flex-wrap max-h-[365px] overflow-auto [&>:nth-child(3n)]:mr-0">
|
||||
<div :key="tempIndex" v-for="(tempItem, tempIndex) in themeTemp"
|
||||
class="flex flex-col border-[1px] border-solid border-[#dcdee2] rounded-[4px] px-[10px] pt-[10px] pb-[15px] mr-[10px] cursor-pointer my-[5px]"
|
||||
:class="{ '!border-[var(--el-color-primary)]': currTheme.id == tempItem.id }"
|
||||
@click="themeTempChange(tempItem)">
|
||||
<div class="flex justify-between pb-[5px]">
|
||||
<div class="text-[14px] text-[#666] max-w-[85px] whitespace-nowrap overflow-hidden text-ellipsis" :class="{ '!text-[#333]': currTheme.id == tempItem.id }">{{ tempItem.title }}</div>
|
||||
<div>
|
||||
<span class="iconfont iconshanchu-fanggaiV6xx !text-[14px] text-[#999]" v-if="currTheme.id != tempItem.id && tempItem.theme_type != 'default' && currTableTheme != tempItem.id" @click.stop="deleteThemeFn(tempItem)"></span>
|
||||
<span class="nc-iconfont nc-icon-bianjiV6xx1 !text-[14px] text-[#999] ml-[5px]" @click.stop="editThemeFn('edit', tempItem)"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="w-[70px] h-[54px] pl-[7px] pt-[9px] flex flex-col mr-[4px] rounded-[4px] text-[10px] leading-[1] text-[#fff]"
|
||||
:style="{ backgroundColor: tempItem.theme['--primary-color'] }">
|
||||
<span>主色调</span>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="secod-color-item mb-[4px]" :style="{ backgroundColor: tempItem.theme['--primary-help-color2'] }">
|
||||
<span>辅色</span>
|
||||
</div>
|
||||
<div class="secod-color-item" :style="{ backgroundColor: tempItem.theme['--primary-color-dark'] }">
|
||||
<span>配色</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center border-[1px] border-solid border-[var(--el-color-primary)] rounded-[2px] h-[32px] px-[15px] cursor-pointer mt-[15px]" @click="editThemeFn()">
|
||||
<span class="text-[14px] text-[var(--el-color-primary)]">新增配色</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<edit-theme ref="editThemeRef" @confirm="editThemeConfirm" />
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogThemeVisible = false">取消</el-button>
|
||||
<el-button type="primary" plain @click="editThemeFn()">编辑</el-button>
|
||||
<el-button @click="cancelFn()">取消</el-button>
|
||||
<el-button type="primary" @click="confirmFn()">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
@ -28,139 +44,141 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { setDiyTheme, getDefaultTheme } from '@/app/api/diy'
|
||||
import { setDiyTheme, getDefaultTheme, deleteTheme } from '@/app/api/diy'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import editTheme from './edit-theme.vue'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { time } from 'echarts'
|
||||
const diyStore = useDiyStore()
|
||||
|
||||
const editThemeRef = ref(null)
|
||||
const editThemeRef = ref()
|
||||
const dialogThemeVisible = ref(false)
|
||||
let confirmRepeat = false
|
||||
const curr_theme_title = ref('') //当前配色title
|
||||
const curr_theme_mark = ref('') //当前配色标识
|
||||
const curr_theme_value = ref('') //当前配色theme
|
||||
const theme_temp = ref([]);
|
||||
const mode = ref('default'); // 当前模式
|
||||
const currTheme = reactive({
|
||||
title: '',
|
||||
id: '',
|
||||
theme: {},
|
||||
default_theme: {},
|
||||
new_theme: [],
|
||||
addon_title: '',
|
||||
key: ''
|
||||
})
|
||||
const themeTemp = ref([])
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
const data = ref({})
|
||||
const open = (res:any) => {
|
||||
|
||||
confirmRepeat = false;
|
||||
data.value = cloneDeep(res);
|
||||
curr_theme_value.value = res.value;
|
||||
curr_theme_mark.value = res.color_mark;
|
||||
curr_theme_title.value = res.color_name;
|
||||
|
||||
// 新增颜色
|
||||
theme_temp.value.forEach((item,index)=>{
|
||||
if(item.name == data.value.color_mark){
|
||||
item.diy_value = data.value.diy_value;
|
||||
item.title = res.color_name;
|
||||
const initData = (params: any, callback: any = '') => {
|
||||
getDefaultTheme({ addon: params.key }).then((res) => {
|
||||
themeTemp.value = res.data || []
|
||||
if (callback) {
|
||||
callback(res.data[res.data.length - 1])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mode.value = res.mode;
|
||||
const currTableTheme = ref('')
|
||||
const open = (res: any) => {
|
||||
currTableTheme.value = res.id
|
||||
initData(res)
|
||||
confirmRepeat = false
|
||||
currTheme.title = res.title
|
||||
currTheme.id = res.id
|
||||
currTheme.theme = res.theme
|
||||
currTheme.addon_title = res.addon_title
|
||||
currTheme.key = res.key
|
||||
dialogThemeVisible.value = true
|
||||
}
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
const initData = () => {
|
||||
getDefaultTheme().then((res) => {
|
||||
theme_temp.value = res.data || [];
|
||||
|
||||
// 将自定义添加到里面
|
||||
let diy_theme_temp = {
|
||||
name: 'diy',
|
||||
theme: '',
|
||||
title: ''
|
||||
}
|
||||
theme_temp.value.push(diy_theme_temp);
|
||||
const dialogTitle = computed(() => {
|
||||
const name = `选择${ currTheme.addon_title }配色`
|
||||
return name
|
||||
})
|
||||
}
|
||||
initData()
|
||||
|
||||
// 切换不同配色
|
||||
const themeTempChange = (item)=>{
|
||||
if(item.name == data.value.color_mark){ // 选择默认配色的情况
|
||||
curr_theme_title.value = data.value.color_name;
|
||||
curr_theme_mark.value = data.value.color_mark;
|
||||
curr_theme_value.value = data.value.value;
|
||||
}else if(typeof item == 'object'){ // 选择除默认配色的情况
|
||||
curr_theme_title.value = item.title;
|
||||
curr_theme_mark.value = item.name;
|
||||
curr_theme_value.value = item.theme;
|
||||
}else{ // 自定义情况
|
||||
curr_theme_title.value = '自定义';
|
||||
curr_theme_mark.value = item;
|
||||
curr_theme_value.value = '';
|
||||
}
|
||||
const themeTempChange = (item: any = {}) => {
|
||||
currTheme.title = item.title
|
||||
currTheme.id = item.id
|
||||
currTheme.theme = item.theme
|
||||
currTheme.default_theme = item.default_theme
|
||||
currTheme.new_theme = item.new_theme
|
||||
}
|
||||
|
||||
// 编辑色调
|
||||
const editThemeFn = ()=>{
|
||||
let theme = {
|
||||
default: {}, // 当前色调的默认值
|
||||
data: {}, // 当前色调
|
||||
const editThemeFn = (type = 'add', item = {}) => {
|
||||
const theme = {
|
||||
default_theme: {}, // 当前色调的默认值
|
||||
theme: {}, // 当前色调
|
||||
title: '',
|
||||
mark: '', // 标识,区分是自定义还是模版色调,
|
||||
diy_value: [] // 新增颜色值
|
||||
id: '', // 标识,区分是自定义还是模版色调,
|
||||
new_theme: [], // 新增颜色值
|
||||
key: '', // 表示是哪个插件
|
||||
theme_field: ''
|
||||
}
|
||||
theme.data = cloneDeep(curr_theme_value.value) || {};
|
||||
theme.mark = curr_theme_mark.value;
|
||||
theme_temp.value.forEach((item,index)=>{
|
||||
if(item.name == curr_theme_mark.value){
|
||||
theme.default = item.theme ? cloneDeep(item.theme) : '';
|
||||
theme.diy_value= item.diy_value || [];
|
||||
theme.title = item.title;
|
||||
if (type == 'edit') {
|
||||
theme.title = item.title
|
||||
theme.theme = cloneDeep(item.theme) || {}
|
||||
theme.id = item.id
|
||||
theme.default_theme = cloneDeep(item.default_theme) || ''
|
||||
theme.new_theme = cloneDeep(item.new_theme) || []
|
||||
theme.new_theme = cloneDeep(item.new_theme) || []
|
||||
}
|
||||
theme.key = currTheme.key
|
||||
// 颜色展示的默认数据
|
||||
themeTemp.value.forEach((item, index) => {
|
||||
if (item.id == currTheme.id) {
|
||||
theme.theme_field = item.theme_field
|
||||
}
|
||||
})
|
||||
editThemeRef.value.open(theme)
|
||||
}
|
||||
|
||||
// 编辑色调回调
|
||||
const editThemeConfirm = (res)=>{
|
||||
if(curr_theme_mark.value == data.value.color_mark){
|
||||
data.value.value = res.theme;
|
||||
}
|
||||
theme_temp.value.forEach((item,index)=>{
|
||||
if(item.name == curr_theme_mark.value){
|
||||
item.diy_value= res.diy_value || [];
|
||||
}
|
||||
const editThemeConfirm = (res: any) => {
|
||||
initData(currTheme, (params: any) => {
|
||||
currTheme.new_theme = res.new_theme
|
||||
currTheme.theme = res.theme
|
||||
currTheme.title = res.title
|
||||
currTheme.id = res.id || params.id // 若是新增的色调,id为空, 需要把之前的的id赋值
|
||||
})
|
||||
}
|
||||
|
||||
// 删除色调
|
||||
let deleteRepeat = false
|
||||
const deleteThemeFn = (res: any) => {
|
||||
if (deleteRepeat) return false
|
||||
deleteRepeat = true
|
||||
const id = res.id
|
||||
deleteTheme(id).then((res) => {
|
||||
initData(currTheme)
|
||||
deleteRepeat = false
|
||||
}).catch(() => {
|
||||
deleteRepeat = false
|
||||
})
|
||||
data.value.title = res.title;
|
||||
curr_theme_value.value = res.theme;
|
||||
}
|
||||
|
||||
// 点击保存
|
||||
const confirmFn = () => {
|
||||
if (confirmRepeat) return
|
||||
confirmRepeat = true
|
||||
let params = {}
|
||||
params.id = data.value.id;
|
||||
params.mode = mode.value;
|
||||
params.color_mark = curr_theme_mark.value;
|
||||
params.value = curr_theme_value.value;
|
||||
params.key = data.value.key;
|
||||
params.color_name = curr_theme_mark.value == 'diy' ? (data.value.title || '自定义') : curr_theme_title.value;
|
||||
theme_temp.value.forEach((item,index)=>{
|
||||
if(item.name == curr_theme_mark.value){
|
||||
params.diy_value = cloneDeep(item.diy_value);
|
||||
}
|
||||
})
|
||||
|
||||
const params = {}
|
||||
params.addon = currTheme.key
|
||||
params.id = currTheme.id
|
||||
params.title = currTheme.title
|
||||
params.theme = currTheme.theme
|
||||
params.new_theme = currTheme.new_theme
|
||||
|
||||
setDiyTheme(params).then((res) => {
|
||||
emit('confirm', data);
|
||||
confirmRepeat = false;
|
||||
dialogThemeVisible.value = false;
|
||||
confirmRepeat = false
|
||||
dialogThemeVisible.value = false
|
||||
emit('confirm')
|
||||
}).catch(() => {
|
||||
confirmRepeat = false;
|
||||
confirmRepeat = false
|
||||
})
|
||||
}
|
||||
|
||||
// 点击取消
|
||||
const cancelFn = () => {
|
||||
dialogThemeVisible.value = false
|
||||
emit('confirm')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@ -170,5 +188,7 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.secod-color-item {
|
||||
@apply w-[60px] h-[25px] flex flex-col rounded-[4px] text-[10px] text-[#fff] leading-[1] items-end pt-[8px] pr-[7px];
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -138,7 +138,7 @@
|
||||
|
||||
<div class="edit-component-wrap">
|
||||
|
||||
<component v-if="diyStore.currentComponent" :is="modules[diyStore.currentComponent]" :value="diyStore.value[diyStore.currentIndex]">
|
||||
<component v-if="diyStore.currentComponent" :is="modules[diyStore.currentComponent]" :key="diyStore.currentIndex" :value="diyStore.value[diyStore.currentIndex]">
|
||||
<template #style>
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('componentStyleTitle') }}</h3>
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<div class="w-[700px]">
|
||||
<div class="flex flex-wrap">
|
||||
<diy-link v-model="link" :ignore="['DIY_LINK','DIY_JUMP_OTHER_APPLET','DIY_MAKE_PHONE_CALL']" @success="changePage">
|
||||
<diy-link v-model="link" :ignore="['OTHER_LINK']" @success="changePage">
|
||||
<el-button type="primary">{{ t('changePage') }}</el-button>
|
||||
</diy-link>
|
||||
<el-button type="primary" @click="toDecorate()" v-show="page.use_template.action == 'decorate'" class="ml-[12px]">{{ t('decorate') }}</el-button>
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<el-table-column label="应用" min-width="120" >
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center">
|
||||
<el-image class="w-[40px] h-[40px] rounded-md overflow-hidden" :src="img(row.icon)" fit="contain">
|
||||
<el-image class="w-[40px] h-[40px] rounded-md overflow-hidden" :src="row.icon" fit="contain">
|
||||
<template #error>
|
||||
<div class="flex items-center w-full h-full">
|
||||
<img class="w-full h-full" src="@/app/assets/images/icon-addon.png" alt="">
|
||||
@ -27,16 +27,16 @@
|
||||
|
||||
<el-table-column label="配色名称" min-width="120" >
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.color_name }}</div>
|
||||
<div>{{ row.title }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="配色方案" min-width="120" >
|
||||
<template #default="{ row }">
|
||||
<div class="rounded-[3px] inline-flex items-center justify-center border-[1px] border-solid border-[#f2f2f2] overflow-hidden" v-if="row.value">
|
||||
<span class="w-[18px] h-[18px]" :style="{backgroundColor: row.value['--primary-color']}"></span>
|
||||
<span class="w-[18px] h-[18px]" :style="{backgroundColor: row.value['--primary-help-color']}"></span>
|
||||
<span class="w-[18px] h-[18px]" :style="{backgroundColor: '#fff'}"></span>
|
||||
<div class="rounded-[3px] inline-flex items-center justify-center border-[1px] border-solid border-[#f2f2f2] overflow-hidden" v-if="row.theme">
|
||||
<span class="w-[18px] h-[18px]" :style="{backgroundColor: row.theme['--primary-color']}"></span>
|
||||
<span class="w-[18px] h-[18px]" :style="{backgroundColor: row.theme['--primary-help-color2']}"></span>
|
||||
<span class="w-[18px] h-[18px]" :style="{backgroundColor: row.theme['--primary-color-dark']}"></span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -54,17 +54,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch, computed } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import { setDiyTheme, getDiyTheme, getDefaultTheme } from '@/app/api/diy'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage, FormInstance } from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import { getDiyTheme } from '@/app/api/diy'
|
||||
import { useRoute } from 'vue-router'
|
||||
import themeList from './components/theme-list.vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { tr } from 'element-plus/es/locale'
|
||||
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
@ -74,7 +69,7 @@ const data = ref([])
|
||||
|
||||
const initData = () => {
|
||||
loading.value = true;
|
||||
getDiyTheme().then((res) => {
|
||||
getDiyTheme({}).then((res) => {
|
||||
let obj = cloneDeep(res.data);
|
||||
for(let key in obj){
|
||||
obj[key].key = key;
|
||||
@ -85,11 +80,17 @@ const initData = () => {
|
||||
}
|
||||
initData()
|
||||
|
||||
|
||||
// 编辑
|
||||
const editEvent = (data)=> {
|
||||
themeListRef.value.open(data);
|
||||
themeListRef.value.open(data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<!-- 设置弹窗标题 -->
|
||||
<style scoped>
|
||||
/* 使用深度选择器 */
|
||||
::v-deep .custom-theme-dialog .el-dialog__title {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -31,7 +31,8 @@
|
||||
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.dateWay == 'diy'">
|
||||
<el-form-item
|
||||
v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.dateWay == 'diy'">
|
||||
<el-date-picker v-model="diyStore.editComponent.field.default.start.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('startDataPlaceholder')" @change="startDateChange" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -52,8 +53,12 @@
|
||||
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.dateWay == 'diy'">
|
||||
<el-date-picker :disabled-date="disabledEndDate" v-model="diyStore.editComponent.field.default.end.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('endDataPlaceholder')" @change="endDateChange" />
|
||||
<el-form-item
|
||||
v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.dateWay == 'diy'">
|
||||
<el-date-picker :disabled-date="disabledEndDate"
|
||||
v-model="diyStore.editComponent.field.default.end.date" format="YYYY/MM/DD"
|
||||
value-format="YYYY-MM-DD" type="date" :placeholder="t('endDataPlaceholder')"
|
||||
@change="endDateChange" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
@ -105,8 +110,6 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
let starTime = diyStore.value[index].field.default.start.date
|
||||
let endTime = diyStore.value[index].field.default.end.date
|
||||
|
||||
console.log(diyStore.value[index].field.default)
|
||||
|
||||
let today = new Date()
|
||||
const hours = String(today.getHours()).padStart(2, '0')
|
||||
const minutes = String(today.getMinutes()).padStart(2, '0')
|
||||
@ -117,6 +120,7 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
if (diyStore.editComponent.end.dateWay == 'current') {
|
||||
endTime = today.toISOString().split('T')[0]
|
||||
}
|
||||
|
||||
if (diyStore.editComponent.start.defaultControl && starTime == '' && diyStore.editComponent.end.dateWay == 'diy') {
|
||||
res.code = false
|
||||
res.message = t('startDataTips')
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import { ref,reactive,watch,onMounted } from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { timeTurnTimeStamp } from '@/utils/common'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
|
||||
@ -46,29 +46,29 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
if (diyStore.value[index].limit == '') {
|
||||
res.code = false;
|
||||
res.code = false
|
||||
res.message = t('imageLimitPlaceholder')
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
if (isNaN(diyStore.value[index].limit) || !regExp.number.test(diyStore.value[index].limit)) {
|
||||
res.code = false;
|
||||
res.message = t('imageLimitErrorTips');
|
||||
return res;
|
||||
res.code = false
|
||||
res.message = t('imageLimitErrorTips')
|
||||
return res
|
||||
}
|
||||
if (diyStore.value[index].limit < 0) {
|
||||
res.code = false;
|
||||
res.code = false
|
||||
res.message = t('imageLimitErrorTipsTwo')
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
if (diyStore.value[index].limit == 0) {
|
||||
res.code = false;
|
||||
res.code = false
|
||||
res.message = t('imageLimitErrorTipsThree')
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
if (diyStore.value[index].limit > 20) {
|
||||
res.code = false;
|
||||
if (diyStore.value[index].limit > 9) {
|
||||
res.code = false
|
||||
res.message = t('imafeLimitErrorTipsFour')
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ import { ref, onMounted, nextTick} from 'vue'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import Sortable from 'sortablejs'
|
||||
import { range } from 'lodash-es'
|
||||
import { FormInstance, ElMessage } from "element-plus";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
|
||||
@ -3,13 +3,17 @@
|
||||
<div class="content-wrap" v-show="diyStore.editTab == 'content'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('floatBtnBtton')" class="display-block">
|
||||
<el-form-item :label="t('floatBtnButton')" class="display-block">
|
||||
<el-radio-group v-model="diyStore.editComponent.btnPosition" @change="btnPositionChangeFn">
|
||||
<el-radio label="follow_content">{{ t('followContent') }}</el-radio>
|
||||
<el-radio label="hover_screen_bottom">{{ t('hoverScreenBottom') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="text-sm text-gray-400 mb-[5px] leading-[1.4]" v-show="diyStore.editComponent.btnPosition == 'follow_content'">{{ t('btnTips') }}</div>
|
||||
<div class="text-sm text-gray-400 mb-[5px]" v-show="diyStore.editComponent.btnPosition == 'hover_screen_bottom'">{{ t('btnTipsTwo') }}</div>
|
||||
<div class="text-sm text-gray-400 mb-[5px] leading-[1.4]"
|
||||
v-show="diyStore.editComponent.btnPosition == 'follow_content'">{{ t('btnTips') }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-400 mb-[5px]"
|
||||
v-show="diyStore.editComponent.btnPosition == 'hover_screen_bottom'">{{ t('btnTipsTwo') }}
|
||||
</div>
|
||||
<div class="text-sm text-gray-400 mb-[10px] leading-[1.4]">{{ t('btnTipsThree') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
@ -19,7 +19,8 @@
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model.trim="diyStore.editComponent.field.default" :placeholder="t('defaultValuePlaceholder')" clearable maxlength="18" show-word-limit />
|
||||
<el-input v-model.trim="diyStore.editComponent.field.default"
|
||||
:placeholder="t('defaultValuePlaceholder')" clearable maxlength="18" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('rowCount')">
|
||||
<el-input v-model.trim="diyStore.editComponent.rowCount" :placeholder="t('rowCountPlaceholder')" clearable maxlength="2" show-word-limit />
|
||||
|
||||
@ -20,7 +20,8 @@
|
||||
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.timeWay == 'diy'">
|
||||
<el-form-item
|
||||
v-if="diyStore.editComponent.start.defaultControl && diyStore.editComponent.start.timeWay == 'diy'">
|
||||
<el-time-picker v-model="diyStore.editComponent.field.default.start.date" :placeholder="t('startTimePlaceholder')" format="HH:mm" value-format="HH:mm" @change="startTimePickerChange" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -41,7 +42,8 @@
|
||||
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.timeWay == 'diy'">
|
||||
<el-form-item
|
||||
v-if="diyStore.editComponent.end.defaultControl && diyStore.editComponent.end.timeWay == 'diy'">
|
||||
<el-time-picker :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" v-model="diyStore.editComponent.field.default.end.date" :placeholder="t('endTimePlaceholder')" format="HH:mm" value-format="HH:mm" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -122,7 +124,6 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
const today = new Date();
|
||||
const hours = String(today.getHours()).padStart(2, '0');
|
||||
@ -143,7 +144,6 @@ onMounted(() => {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 开始时间选择器
|
||||
const startTimePickerChange = (e) => {
|
||||
diyStore.editComponent.field.default.start.timestamp = timeInvertSecond(e);
|
||||
|
||||
177
admin/src/app/views/diy_form/components/form-select-content.vue
Normal file
177
admin/src/app/views/diy_form/components/form-select-content.vue
Normal file
@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form :inline="true" :model="tableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('formSelectContentTitle')" prop="title" class="form-item-wrap">
|
||||
<el-input v-model.trim="tableData.searchParam.title" :placeholder="t('formSelectContentTitlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('formSelectContentTypeName')" prop="type" class="form-item-wrap">
|
||||
<el-select v-model="tableData.searchParam.type" :placeholder="t('formSelectContentTypeNamePlaceholder')">
|
||||
<el-option :label="t('formSelectContentTypeAll')" value="" />
|
||||
<el-option v-for="(item, key) in formType" :label="item.title" :value="key" :key="key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item class="form-item-wrap">
|
||||
<el-button type="primary" @click="loadList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="tableData.data" size="large" ref="tableRef" v-loading="tableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !tableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column min-width="7%">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.checked" @change="handleCheckChange($event,row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="page_title" :label="t('formSelectContentTitle')" min-width="65%" />
|
||||
<el-table-column prop="type_name" :label="t('formSelectContentTypeName')" min-width="25%" />
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="tableData.page" v-model:page-size="tableData.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="tableData.total"
|
||||
@size-change="loadList()" @current-change="loadList" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, nextTick } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getFormType, getDiyFormSelectPageList } from '@/app/api/diy_form'
|
||||
import { FormInstance, ElMessage } from "element-plus";
|
||||
|
||||
const prop = defineProps({
|
||||
formId: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const formType: any = reactive({}) // 表单类型
|
||||
|
||||
const searchFormRef = ref<FormInstance>()
|
||||
|
||||
const tableRef = ref();
|
||||
|
||||
const tableData: any = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
title: '',
|
||||
type: '',
|
||||
verify_form_ids: []
|
||||
}
|
||||
})
|
||||
|
||||
// 已选万能表单
|
||||
const selectData: any = reactive({
|
||||
form_id: prop.formId
|
||||
})
|
||||
|
||||
// 获取自定义表单列表
|
||||
const loadList = (page: number = 1) => {
|
||||
tableData.loading = true
|
||||
tableData.page = page
|
||||
|
||||
if (selectData.form_id) {
|
||||
tableData.searchParam.verify_form_ids = [selectData.form_id]
|
||||
}
|
||||
|
||||
getDiyFormSelectPageList({
|
||||
page: tableData.page,
|
||||
limit: tableData.limit,
|
||||
...tableData.searchParam
|
||||
}).then(res => {
|
||||
tableData.loading = false
|
||||
tableData.data = res.data.data
|
||||
|
||||
tableData.data.forEach((item: any) => {
|
||||
item.checked = item.form_id == selectData.form_id
|
||||
})
|
||||
tableData.total = res.data.total
|
||||
setGoodsSelected()
|
||||
}).catch(() => {
|
||||
tableData.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
// 获取万能表单类型
|
||||
const loadFormType = (addon = '') => {
|
||||
getFormType({}).then(res => {
|
||||
for (let key in formType) {
|
||||
delete formType[key];
|
||||
}
|
||||
|
||||
for (const key in res.data) {
|
||||
formType[key] = res.data[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
loadFormType();
|
||||
loadList()
|
||||
|
||||
const handleCheckChange = (isSelect: any, row: any) => {
|
||||
if (isSelect) {
|
||||
selectData.form_id = row.form_id
|
||||
} else {
|
||||
selectData.form_id = 0 // 未选中,移除当前
|
||||
}
|
||||
setGoodsSelected()
|
||||
}
|
||||
|
||||
// 表格设置选中状态
|
||||
const setGoodsSelected = () => {
|
||||
nextTick(() => {
|
||||
for (let i = 0; i < tableData.data.length; i++) {
|
||||
tableData.data[i].checked = false
|
||||
if (selectData.form_id == tableData.data[i].form_id) {
|
||||
tableData.data[i].checked = true
|
||||
Object.assign(selectData, tableData.data[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const resetForm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
formEl.resetFields()
|
||||
loadList()
|
||||
}
|
||||
|
||||
const getData = () => {
|
||||
if (selectData.form_id == 0) {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: `${ t('formSelectContentTips') }`
|
||||
})
|
||||
return;
|
||||
}
|
||||
return {
|
||||
name: 'DIY_FORM',
|
||||
title: selectData.page_title,
|
||||
url: `/app/pages/index/diy_form?form_id=${ selectData.form_id }`,
|
||||
action: '',
|
||||
formId: selectData.form_id
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.form-item-wrap {
|
||||
margin-right: 10px !important;
|
||||
margin-bottom: 10px !important;
|
||||
|
||||
&.last-child {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="showDialog" :title="t('submirSuccess')" width="850px" :close-on-press-escape="true" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-dialog v-model="showDialog" :title="t('submitSuccess')" width="850px" :close-on-press-escape="true" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
|
||||
<div class="flex flex-1 mt-[24px] mx-[24px] mb-0">
|
||||
<div class="preview-wrap">
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="row.type=='DIY_FORM'">
|
||||
<el-button type="primary" class="w-full" link @click="submitConfigEvent(row)">{{ t('submirSuccess') }}</el-button>
|
||||
<el-button type="primary" class="w-full" link @click="submitConfigEvent(row)">{{ t('submitSuccess') }}</el-button>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-button type="primary" class="w-full" link @click="writeConfigEvent(row)">{{ t('writeSet') }}</el-button>
|
||||
|
||||
@ -87,7 +87,7 @@
|
||||
<el-table-column :label="t('applicationForWithdrawalAmount')" align="center" min-width="120" />
|
||||
<el-table-column :label="t('actualTransferAmount')" align="center" min-width="120" />
|
||||
<el-table-column :label="t('cashOutCommission')" align="center" min-width="110" />
|
||||
<el-table-column :label="t('cashOutStatus')" align="center" min-width="100" />
|
||||
<el-table-column :label="t('cashOutStatus')" align="center" min-width="150" />
|
||||
<el-table-column :label="t('applyTime')" align="center" min-width="160" />
|
||||
<el-table-column :label="t('auditTime')" align="center" min-width="160" />
|
||||
<el-table-column :label="t('transferTime')" align="center" min-width="160" />
|
||||
@ -103,7 +103,7 @@
|
||||
<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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col items-baseline" style="width: calc(100% - 60px);">
|
||||
<div class="flex flex-col items-baseline" style="width: calc(100% - 60px);">
|
||||
<span class="w-[100%] truncate text-left">{{ row.member.nickname || row.member.username || '' }}</span>
|
||||
<span class="w-[100%] truncate">{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
@ -136,6 +136,14 @@
|
||||
<span>{{ t('bankAccount') }}:{{ row.transfer_account }}</span>
|
||||
<span>{{ t('bankName') }}:{{ row.transfer_bank }}</span>
|
||||
</div>
|
||||
<div class="flex items-center" v-else-if="row.transfer_type=='wechatpay'">
|
||||
<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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex-col items-baseline" style="width: calc(100% - 60px);">
|
||||
<span class="w-[100%] truncate text-left">{{ row.member.nickname || row.member.username || '' }}</span>
|
||||
<span class="w-[100%] truncate">{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="apply_money" min-width="120" align="center" />
|
||||
@ -144,7 +152,12 @@
|
||||
|
||||
<el-table-column prop="service_money" align="center" min-width="110" />
|
||||
|
||||
<el-table-column prop="status_name" align="center" min-width="100" />
|
||||
<el-table-column prop="status_name" align="center" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<div>{{ row.status_name }}</div>
|
||||
<div v-if="row.status == 2 && row.transfer_type == 'wechatpay'" class="text-[12px] text-[var(--el-color-success)]">(等待用户收款)</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column min-width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
@ -166,9 +179,11 @@
|
||||
|
||||
<el-table-column align="right" fixed="right" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-button v-for="(item, index) in operationBtn[row.status.toString()].value" :key="index + 'a'"
|
||||
@click="fnProcessing(operationBtn[row.status.toString()].clickArr[index], row)"
|
||||
type="primary" link>{{ item }}</el-button>
|
||||
<el-button type="primary" link @click="successfulAuditFn(row)" v-if="row.status == 1"> {{ t('successfulAudit') }}</el-button>
|
||||
<el-button type="primary" link @click="auditFailureFn(row)" v-if="row.status == 1"> {{ t('auditFailure') }}</el-button>
|
||||
<el-button type="primary" link @click="memberCancelFn(row)" v-if="row.status == 1 || row.status == 2 || row.status == 4"> {{ t('cancelWithdrawal') }}</el-button>
|
||||
<el-button type="primary" link @click="transferFn(row)" v-if="row.status == 2 && row.transfer_type !== 'wechatpay'"> {{ t('transfer') }}</el-button>
|
||||
<el-button type="primary" link @click="detailFn(row.id)"> {{ t('detail') }}</el-button>
|
||||
<el-button type="primary" link @click="handleRemark(row)"> {{ t('remark') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -284,6 +299,11 @@
|
||||
<div class="input-width"> {{ cashOutInfo.transfer.transfer_remark }} </div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="cashOutInfo.refuse_reason">
|
||||
<el-form-item :label="t('remark')">
|
||||
<div class="input-width"> {{ cashOutInfo.refuse_reason }} </div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
@ -482,11 +502,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getCashOutList, getTransfertype, memberTransfer, memberAudit, getCashOutDetail, getCashOutStatusList, getCashOutStat, memberRemark, memberCheck } from '@/app/api/member'
|
||||
import { getCashOutList, getTransfertype, memberTransfer, memberAudit, getCashOutDetail, getCashOutStatusList, getCashOutStat, memberRemark, memberCheck, memberCancel } from '@/app/api/member'
|
||||
import { img } from '@/utils/common'
|
||||
import { ElMessageBox, FormInstance, FormRules } from 'element-plus'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { AnyObject } from '@/types/global'
|
||||
|
||||
const cashOutStatusList = ref([])
|
||||
const checkStatusList = async () => {
|
||||
@ -496,32 +515,6 @@ checkStatusList()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const pageName = route.meta.title
|
||||
const operationBtn = ref<AnyObject>({
|
||||
1: {
|
||||
value: [t('successfulAudit'), t('auditFailure'), t('detail')],
|
||||
clickArr: ['successfulAuditFn', 'auditFailureFn', 'detailFn']
|
||||
},
|
||||
2: {
|
||||
value: [t('transfer'), t('detail')],
|
||||
clickArr: ['transferFn', 'detailFn']
|
||||
},
|
||||
3: {
|
||||
value: [t('detail')],
|
||||
clickArr: ['detailFn']
|
||||
},
|
||||
4: {
|
||||
value: [t('detail')],
|
||||
clickArr: ['detailFn']
|
||||
},
|
||||
'-1': {
|
||||
value: [t('detail')],
|
||||
clickArr: ['detailFn']
|
||||
},
|
||||
'-2': {
|
||||
value: [t('detail')],
|
||||
clickArr: ['detailFn']
|
||||
}
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = reactive<FormRules>({})
|
||||
@ -592,48 +585,14 @@ const loadOrderList = (page: number = 1) => {
|
||||
}
|
||||
loadOrderList()
|
||||
|
||||
// 函数总处理
|
||||
const auditFailure = ref({ refuse_reason: '', id: 0, action: 0 })
|
||||
const auditShowDialog = ref(false)
|
||||
const fnProcessing = (type: string, data: any) => {
|
||||
const obj = {}
|
||||
if (['successfulAuditFn', 'auditFailureFn'].includes(type)) {
|
||||
obj.id = data.id
|
||||
if (type == 'successfulAuditFn') {
|
||||
obj.action = 'agree'
|
||||
curData.value = data
|
||||
auditPassShowDialog.value = true
|
||||
} else {
|
||||
obj.action = 'refuse'
|
||||
auditFailure.value = Object.assign(auditFailure.value, obj)
|
||||
auditShowDialog.value = true
|
||||
}
|
||||
} else if (type == 'transferFn') {
|
||||
if (data.transfer_type == 'wechatpay') {
|
||||
obj.id = data.id
|
||||
ElMessageBox.confirm(`${t('isTransfer')}`, `${t('transfer')}`).then(() => {
|
||||
transferFn(obj)
|
||||
})
|
||||
} else {
|
||||
transferData.value = data
|
||||
formTransfer.id = data.id
|
||||
transferShowDialog.value = true
|
||||
}
|
||||
} else if (type == 'checkFn') {
|
||||
checkFn(data.id)
|
||||
} else {
|
||||
detailFn(data.id)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转账
|
||||
* @param data
|
||||
*/
|
||||
const transferData = ref({})
|
||||
const transferData = ref<any>({})
|
||||
const transferShowDialog = ref(false)
|
||||
const formTransferRef = ref<FormInstance>()
|
||||
const formTransfer = reactive({
|
||||
const formTransfer = reactive<any>({
|
||||
id: 0,
|
||||
transfer_voucher: '',
|
||||
transfer_remark: ''
|
||||
@ -646,16 +605,16 @@ const formTransferRules = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const transferFn = (data:any) => {
|
||||
transferData.value = data
|
||||
formTransfer.id = data.id
|
||||
transferShowDialog.value = true
|
||||
}
|
||||
const handleTransfer = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
transferFn(formTransfer)
|
||||
}
|
||||
})
|
||||
}
|
||||
const transferFn = (data:any) => {
|
||||
memberTransfer({ ...data }).then(res => {
|
||||
memberTransfer({ ...formTransfer }).then(res => {
|
||||
transferShowDialog.value = false
|
||||
loadOrderList()
|
||||
}).catch(() => {
|
||||
@ -663,6 +622,8 @@ const transferFn = (data:any) => {
|
||||
loadOrderList()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
@ -696,6 +657,12 @@ const detailFn = (id:any) => {
|
||||
|
||||
const auditPassShowDialog = ref(false)
|
||||
const curData = ref<any>({})
|
||||
|
||||
// 审核成功弹框
|
||||
const successfulAuditFn = (data: any) => {
|
||||
curData.value = data
|
||||
auditPassShowDialog.value = true
|
||||
}
|
||||
const handlePass = () => {
|
||||
const obj = {
|
||||
id: curData.value.id,
|
||||
@ -703,24 +670,55 @@ const handlePass = () => {
|
||||
}
|
||||
cashOutAuditFn(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝审核
|
||||
*/
|
||||
|
||||
const auditFailure = ref({ refuse_reason: '', id: 0, action: '' })
|
||||
const auditShowDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
const auditFailureFn = (data: any) => {
|
||||
auditFailure.value.id = data.id
|
||||
auditFailure.value.action = 'refuse'
|
||||
auditShowDialog.value = true
|
||||
}
|
||||
const confirm = () => {
|
||||
auditShowDialog.value = false
|
||||
cashOutAuditFn(auditFailure.value)
|
||||
}
|
||||
|
||||
const repeat = ref(false)
|
||||
const cashOutAuditFn = (data:any) => {
|
||||
if (repeat.value) return
|
||||
repeat.value = true
|
||||
memberAudit({
|
||||
...data
|
||||
}).then(res => {
|
||||
repeat.value = false
|
||||
auditPassShowDialog.value = false
|
||||
loadOrderList()
|
||||
}).catch(() => {
|
||||
repeat.value = false
|
||||
auditPassShowDialog.value = false
|
||||
loadOrderList()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝审核
|
||||
*/
|
||||
const confirm = () => {
|
||||
auditShowDialog.value = false
|
||||
cashOutAuditFn(auditFailure.value)
|
||||
// 取消提现
|
||||
const memberCancelFn = (data: any) => {
|
||||
ElMessageBox.confirm(t('cancelTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
memberCancel({ id: data.id }).then((res) => {
|
||||
loadOrderList()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -154,17 +154,17 @@ const formRules = reactive<FormRules>({
|
||||
}else if (value < 2 || value > 365) {
|
||||
callback(t('signPeriodMustZeroTips'))
|
||||
} else {
|
||||
callback();
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}],
|
||||
}]
|
||||
})
|
||||
|
||||
/**
|
||||
* 签到奖励文本请求参数
|
||||
*/
|
||||
const contentData = reactive<Record<string, any>>({
|
||||
gifts: [],
|
||||
gifts: []
|
||||
})
|
||||
|
||||
/**
|
||||
@ -211,17 +211,16 @@ const setFormData = async () => {
|
||||
|
||||
if (formData.continue_award) {
|
||||
formData.continue_award.forEach((item: any, index: number) => {
|
||||
|
||||
continueSignAwardTableData.data.push(cloneDeep(item))
|
||||
|
||||
contentData.gifts = [];
|
||||
contentData.gifts = []
|
||||
|
||||
const val = cloneDeep(item)
|
||||
|
||||
delete val['continue_sign'];
|
||||
delete val['continue_tag'];
|
||||
delete val['receive_limit'];
|
||||
delete val['receive_num'];
|
||||
delete val['continue_sign']
|
||||
delete val['continue_tag']
|
||||
delete val['receive_limit']
|
||||
delete val['receive_num']
|
||||
|
||||
contentData.gifts = val
|
||||
|
||||
@ -239,7 +238,7 @@ setFormData()
|
||||
const daySignAwardText = ref([])
|
||||
const setMemberBenefitsContent = async () => {
|
||||
const data = await (await getMemberGiftsContent(contentData)).data
|
||||
daySignAwardText.value = [];
|
||||
daySignAwardText.value = []
|
||||
Object.values(data).forEach((el: any) => {
|
||||
daySignAwardText.value.push(el)
|
||||
})
|
||||
@ -254,7 +253,7 @@ const setMemberBenefitsContent = async () => {
|
||||
*/
|
||||
const setMemberBenefitsContents = async (content: any, item: any, index: number = 0, tag = 0) => {
|
||||
const data = await (await getMemberGiftsContent(content)).data
|
||||
continueSignAwardText.value = [];
|
||||
continueSignAwardText.value = []
|
||||
Object.values(data).forEach((el: any) => {
|
||||
continueSignAwardText.value.push(el)
|
||||
})
|
||||
@ -276,7 +275,6 @@ const setMemberBenefitsContents = async (content: any, item: any, index: number
|
||||
|
||||
isEdit = false
|
||||
editIndex = 0
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,6 +311,9 @@ const setDaySignAward = async () => {
|
||||
if (!formData.day_award.hasOwnProperty('balance') && !formData.day_award.hasOwnProperty('point') && formData.day_award.shop_coupon.is_use == 0) {
|
||||
formData.day_award = ''
|
||||
}
|
||||
if (formData.day_award.hasOwnProperty('balance') && formData.day_award.balance.is_use == 1) {
|
||||
formData.day_award.balance.money = Number(formData.day_award.balance.money)
|
||||
}
|
||||
contentData.gifts = formData.day_award
|
||||
|
||||
setMemberBenefitsContent()
|
||||
@ -338,8 +339,8 @@ const continueSignAwardSet = () => {
|
||||
* 修改连签奖励设置页
|
||||
*/
|
||||
const continueSignAwardModify = (flag: boolean, index: any) => {
|
||||
isEdit = flag;
|
||||
editIndex = index;
|
||||
isEdit = flag
|
||||
editIndex = index
|
||||
|
||||
continue_award.value = formData.continue_award[index]
|
||||
continueSignDialog.value = true
|
||||
@ -356,18 +357,20 @@ const setContinueSignAward = async () => {
|
||||
if (!continue_award.value.hasOwnProperty('balance') && !continue_award.value.hasOwnProperty('point') && continue_award.value.shop_coupon.is_use == 0) {
|
||||
continue_award.value = ''
|
||||
}
|
||||
|
||||
if (continue_award.value.hasOwnProperty('balance') && continue_award.value.balance.is_use == 1) {
|
||||
continue_award.value.balance.money = Number(continue_award.value.balance.money)
|
||||
}
|
||||
if (Object.keys(continue_award.value).length > 0) {
|
||||
const val = cloneDeep(continue_award.value)
|
||||
|
||||
delete val['continue_sign'];
|
||||
delete val['continue_tag'];
|
||||
delete val['receive_limit'];
|
||||
delete val['receive_num'];
|
||||
delete val['continue_sign']
|
||||
delete val['continue_tag']
|
||||
delete val['receive_limit']
|
||||
delete val['receive_num']
|
||||
|
||||
contentData.gifts = val
|
||||
|
||||
let index = 0;
|
||||
let index = 0
|
||||
if (formData.continue_award.length > 0) {
|
||||
index = formData.continue_award.length - 1
|
||||
}
|
||||
@ -394,7 +397,7 @@ const deleteContinueSignAwardEvent = (index: number) => {
|
||||
* 使用默认说明
|
||||
*/
|
||||
const defaultExplainEvent = () => {
|
||||
formData.rule_explain = t('ruleExplainDefault');
|
||||
formData.rule_explain = t('ruleExplainDefault')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
<div class="flex items-center cursor-pointer" @click="toMember(row.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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<div class="flex items-center cursor-pointer " @click="toMember(row.member.member_id)" v-if="row.member">
|
||||
<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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
<span>{{ row.member.mobile || '' }}</span>
|
||||
</div>
|
||||
|
||||
@ -90,7 +90,7 @@
|
||||
<div class="flex items-center cursor-pointer" @click="toMember(row.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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
<div class="flex items-center cursor-pointer" @click="toMember(row.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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -245,33 +245,24 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, computed } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { addMember, getMemberList, getMemberNo, getMemberInfo } from '@/app/api/member'
|
||||
import { getMemberInfo } from '@/app/api/member'
|
||||
import { FormInstance, ElMessage } from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { img, filterNumber } from '@/utils/common'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { img } from '@/utils/common'
|
||||
import PointEdit from '@/app/views/member/components/member-point-edit.vue'
|
||||
import BalanceEdit from '@/app/views/member/components/member-balance-edit.vue'
|
||||
import EditMember from '@/app/views/member/components/edit-member.vue'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
const repeat = ref(false)
|
||||
let popTitle: string = '会员详情'
|
||||
let memberNo: string = ''
|
||||
let id = '';
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const emit = defineEmits(['load'])
|
||||
|
||||
const nickname_name_input = ref(true)
|
||||
const password_input = ref(true)
|
||||
const password_copy_input = ref(true)
|
||||
|
||||
const handleClose = (done: () => void) => {
|
||||
showDialog.value = false;
|
||||
}
|
||||
@ -290,8 +281,6 @@ const initialFormData = {
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const pointDialog: Record<string, any> | null = ref(null)
|
||||
const balanceDialog: Record<string, any> | null = ref(null)
|
||||
const editMemberDialog: Record<string, any> | null = ref(null)
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<el-checkbox v-model="formData.is_use" :true-label="1" :false-label="0" label="" size="large" />
|
||||
<span class="ml-[10px] el-form-item__label">送</span>
|
||||
<div class="w-[70px]">
|
||||
<el-input v-model.trim="formData.money" :maxlength="5" clearable />
|
||||
<el-input v-model.trim="formData.money" :maxlength="5" clearable :disabled="formData.is_use == 0" />
|
||||
</div>
|
||||
<span class="ml-[15px] el-form-item__label">元红包</span>
|
||||
</div>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<el-checkbox v-model="formData.is_use" :true-label="1" :false-label="0" label="" size="large" />
|
||||
<span class="ml-[10px] el-form-item__label">送</span>
|
||||
<div class="w-[70px]">
|
||||
<el-input v-model.trim="formData.num" clearable />
|
||||
<el-input v-model.trim="formData.num" clearable :disabled="formData.is_use == 0" />
|
||||
</div>
|
||||
<span class="ml-[15px] el-form-item__label">积分</span>
|
||||
</el-form-item>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('adjustBalance')" prop="adjust">
|
||||
<el-input-number v-model="formData.adjust" clearable :min="0" :max="999999" :placeholder="t('adjustPlaceholder')"/>
|
||||
<el-input-number v-model="formData.adjust" clearable :min="0" :max="999999" :placeholder="t('adjustBalancePlaceholder')" @focus="formData.adjust = ''" class="!w-[200px]"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('memo')" prop="memo">
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
<div class="flex items-center cursor-pointer" @click="toMember(row.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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -60,7 +60,7 @@
|
||||
<img class="max-w-[50px] max-h-[50px]" v-if="row.headimg" :src="img(row.headimg)" alt="">
|
||||
<img class="max-w-[50px] max-h-[50px]" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
</div>
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.nickname || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
<div class="flex items-center cursor-pointer" @click="toMember(row.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] rounded-full" v-else src="@/app/assets/images/member_head.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.member.nickname || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -229,7 +229,7 @@ import { t } from '@/lang'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import usePosterStore from '@/stores/modules/poster'
|
||||
import { initPoster, addPoster, editPoster, getPosterTemplate, getPreviewPoster } from '@/app/api/poster'
|
||||
|
||||
@ -249,8 +249,8 @@ if(route && route.query){
|
||||
}
|
||||
|
||||
const backPath:any = route.query.back
|
||||
const template = ref('');
|
||||
const oldTemplate = ref('');
|
||||
const template = ref('')
|
||||
const oldTemplate = ref('')
|
||||
|
||||
const component = ref([])
|
||||
const componentType: string[] = reactive([])
|
||||
@ -268,39 +268,39 @@ const previewIframeStyle = (data: any)=>{
|
||||
left: '',
|
||||
right: '',
|
||||
bottom: ''
|
||||
};
|
||||
style.transform = `rotate(${data.angle}deg)`;
|
||||
style.zIndex = `${data.zIndex}`;
|
||||
}
|
||||
style.transform = `rotate(${data.angle}deg)`
|
||||
style.zIndex = `${data.zIndex}`
|
||||
switch(data.y) {
|
||||
case 'top':
|
||||
style.top = 0;
|
||||
style.top = 0
|
||||
break;
|
||||
case 'center':
|
||||
style.top = '50%';
|
||||
style.transform = style.transform + ' translateY(-50%)';
|
||||
style.top = '50%'
|
||||
style.transform = style.transform + ' translateY(-50%)'
|
||||
break;
|
||||
case 'bottom':
|
||||
style.bottom = 0;
|
||||
style.bottom = 0
|
||||
break;
|
||||
default:
|
||||
style.top = data.y + 'px';
|
||||
style.top = data.y + 'px'
|
||||
}
|
||||
switch(data.x) {
|
||||
case 'left':
|
||||
style.left = 0;
|
||||
style.left = 0
|
||||
break;
|
||||
case 'center':
|
||||
style.left = '50%';
|
||||
style.transform = style.transform + ' translateX(-50%)';
|
||||
style.left = '50%'
|
||||
style.transform = style.transform + ' translateX(-50%)'
|
||||
break;
|
||||
case 'right':
|
||||
style.right = 0;
|
||||
style.right = 0
|
||||
break;
|
||||
default:
|
||||
style.left = data.x + 'px';
|
||||
style.left = data.x + 'px'
|
||||
}
|
||||
// console.log(data.x,data.y)
|
||||
return style;
|
||||
return style
|
||||
}
|
||||
|
||||
// 水平方向对齐
|
||||
@ -341,14 +341,14 @@ const yAlignList = ref([
|
||||
},
|
||||
])
|
||||
const alignChangeFn = (type: any,data: any)=>{
|
||||
posterStore.editComponent[type] = data.className;
|
||||
posterStore.editComponent[type] = data.className
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const isChange = ref(true) // 数据是否发生变化,true:没变化,false:变化了
|
||||
const goBack = () => {
|
||||
if (isChange.value) {
|
||||
location.href = `${location.origin}${backPath}`;
|
||||
location.href = `${location.origin}${backPath}`
|
||||
router.push(backPath)
|
||||
} else {
|
||||
// 数据发生变化,弹框提示:确定离开此页面
|
||||
@ -362,7 +362,7 @@ const goBack = () => {
|
||||
autofocus: false
|
||||
}
|
||||
).then(() => {
|
||||
location.href = `${location.origin}${backPath}`;
|
||||
location.href = `${location.origin}${backPath}`
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
@ -390,6 +390,9 @@ const loadPosterTemplate = ()=> {
|
||||
}).then(res => {
|
||||
if (res.data) {
|
||||
templatePoster.splice(0, templatePoster.length, ...res.data)
|
||||
if (posterStore.id) {
|
||||
template.value = templatePoster.findIndex((item:any) => item.type == posterStore.type)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -398,7 +401,7 @@ const loadPosterTemplate = ()=> {
|
||||
watch(
|
||||
() => template.value,
|
||||
(newValue, oldValue) => {
|
||||
oldTemplate.value = oldValue;
|
||||
oldTemplate.value = oldValue
|
||||
}
|
||||
)
|
||||
|
||||
@ -413,32 +416,32 @@ const changeTemplatePoster = (index:any)=> {
|
||||
}).then(() => {
|
||||
posterStore.changeCurrentIndex(-99)
|
||||
if (index !== '') {
|
||||
let data = templatePoster[index].data;
|
||||
posterStore.global = data.global;
|
||||
let data = templatePoster[index].data
|
||||
posterStore.global = data.global
|
||||
if (data.value.length) {
|
||||
posterStore.value = data.value
|
||||
}
|
||||
} else {
|
||||
// 清空
|
||||
posterStore.init();
|
||||
posterStore.init()
|
||||
}
|
||||
}).catch(() => {
|
||||
// 还原
|
||||
template.value = oldTemplate.value;
|
||||
});
|
||||
template.value = oldTemplate.value
|
||||
})
|
||||
}else{
|
||||
if (index !== '') {
|
||||
let data = templatePoster[index].data;
|
||||
posterStore.global = data.global;
|
||||
let data = templatePoster[index].data
|
||||
posterStore.global = data.global
|
||||
if (data.value.length) {
|
||||
posterStore.value = data.value
|
||||
}
|
||||
} else {
|
||||
// 清空
|
||||
posterStore.init();
|
||||
posterStore.init()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 根据当前页面路由查询页面初始化数据
|
||||
initPoster({
|
||||
@ -448,16 +451,16 @@ initPoster({
|
||||
}).then(async (res:any) => {
|
||||
const data = res.data
|
||||
|
||||
posterStore.init(); // 初始化清空数据
|
||||
posterStore.init() // 初始化清空数据
|
||||
|
||||
posterStore.id = data.id;
|
||||
posterStore.name = data.name;
|
||||
posterStore.channel = data.channel;
|
||||
posterStore.status = data.status;
|
||||
posterStore.isDefault = data.is_default;
|
||||
posterStore.addon = data.addon;
|
||||
posterStore.type = data.type;
|
||||
posterStore.typeName = data.poster_type.name;
|
||||
posterStore.id = data.id
|
||||
posterStore.name = data.name
|
||||
posterStore.channel = data.channel
|
||||
posterStore.status = data.status
|
||||
posterStore.isDefault = data.is_default
|
||||
posterStore.addon = data.addon
|
||||
posterStore.type = data.type
|
||||
posterStore.typeName = data.poster_type.name
|
||||
|
||||
if (data.value) {
|
||||
const sources = data.value
|
||||
@ -497,18 +500,18 @@ const save = (callback: any) => {
|
||||
posterStore.value.forEach((item:any,index:any, originalArr:any)=> {
|
||||
const box: any = document.getElementById(item.id)
|
||||
if (box) {
|
||||
item.width = box.offsetWidth;
|
||||
item.height = box.offsetHeight;
|
||||
item.width = box.offsetWidth
|
||||
item.height = box.offsetHeight
|
||||
if (item.type == 'draw') {
|
||||
// [x,y]:左上,右上,右下,左下
|
||||
let leftTop = [item.x * 1, item.y * 1]; // 左上
|
||||
let rightTop = [(item.x + item.width) * 1, item.y * 1]; // 右上
|
||||
let rightBottom = [(item.x + item.width) * 1, (item.y + item.height) * 1]; // 右下
|
||||
let leftBottom = [item.x * 1, (item.y + item.height) * 1]; // 左下
|
||||
item.points = [leftTop, rightTop, rightBottom, leftBottom];
|
||||
let leftTop = [item.x * 1, item.y * 1] // 左上
|
||||
let rightTop = [(item.x + item.width) * 1, item.y * 1] // 右上
|
||||
let rightBottom = [(item.x + item.width) * 1, (item.y + item.height) * 1] // 右下
|
||||
let leftBottom = [item.x * 1, (item.y + item.height) * 1] // 左下
|
||||
item.points = [leftTop, rightTop, rightBottom, leftBottom]
|
||||
}
|
||||
}
|
||||
delete item.verify;
|
||||
delete item.verify
|
||||
})
|
||||
|
||||
let data = {
|
||||
@ -532,7 +535,7 @@ const save = (callback: any) => {
|
||||
if (posterStore.id) {
|
||||
isRepeat.value = false // 不刷新
|
||||
} else {
|
||||
location.href = `${location.origin}${backPath}`;
|
||||
location.href = `${location.origin}${backPath}`
|
||||
}
|
||||
if (callback) callback(res.data.id)
|
||||
}
|
||||
@ -554,8 +557,8 @@ const preview = () => {
|
||||
type:posterStore.type
|
||||
}).then(((res:any)=>{
|
||||
if(res.data) {
|
||||
previewPosterUrl.value = res.data;
|
||||
previewDialogVisible.value = true;
|
||||
previewPosterUrl.value = res.data
|
||||
previewDialogVisible.value = true
|
||||
}
|
||||
isRepeat.value = false
|
||||
}))
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
</el-card>
|
||||
|
||||
<!--添加海报-->
|
||||
<el-dialog v-model="dialogVisible" :title="t('addPosterTitle')" width="350px">
|
||||
<el-dialog v-model="dialogVisible" :title="t('addPosterTitle')" width="350px" destroy-on-close="true">
|
||||
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||
<el-form-item :label="t('posterName')" prop="name">
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('transfer')" v-if="formData.is_open" class="items-baseline">
|
||||
<!-- <el-form-item :label="t('transfer')" v-if="formData.is_open" class="items-baseline">
|
||||
<div>
|
||||
<el-radio-group v-model="formData.is_auto_transfer">
|
||||
<el-radio label="0" size="large">{{t('manualTransfer')}}</el-radio>
|
||||
@ -41,7 +41,7 @@
|
||||
</el-radio-group>
|
||||
<div class="text-[12px] text-[#999] leading-[24px]">{{ t('transferTips') }}</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<el-form-item :label="t('transferMode')" v-if="formData.is_open" class="items-baseline">
|
||||
<div>
|
||||
<el-checkbox-group v-model="formData.transfer_type" size="large">
|
||||
|
||||
@ -10,22 +10,24 @@
|
||||
<div class="mt-[20px]">
|
||||
<div class="flex items-center bg">
|
||||
<span class="p-[15px] w-[25%] text-[14px]">规则名称</span>
|
||||
<span class="p-[15px] w-[50%] text-[14px]">规则详情</span>
|
||||
<span class="p-[15px] w-[15%] text-[14px]">所属应用</span>
|
||||
<span class="p-[15px] w-[35%] text-[14px]">规则详情</span>
|
||||
<span class="p-[15px] w-[15%] text-[14px]">是否启用</span>
|
||||
<span class="p-[15px] w-[10%] text-[14px]">操作</span>
|
||||
</div>
|
||||
<div v-for="(item, key) in rules" :key="key" class="flex items-center">
|
||||
<span class="p-[15px] w-[25%] text-[14px]">{{ item.name }}</span>
|
||||
<span class="p-[15px] w-[50%] text-[14px] text-[#666]">{{ formData[item.key] && formData[item.key].content ? formData[item.key].content : '--' }}</span>
|
||||
<span class="p-[15px] w-[15%] text-[14px]">{{ item.addon_name }}</span>
|
||||
<span class="p-[15px] w-[35%] text-[14px] text-[#666]">{{ rulesData[item.key] && rulesData[item.key].content ? rulesData[item.key].content : '--' }}</span>
|
||||
<span class="p-[15px] w-[15%] text-[14px] text-[#666]">
|
||||
<el-tag type="success" v-if="formData[item.key] && formData[item.key].is_use">已启用</el-tag>
|
||||
<el-tag type="success" v-if="rulesData[item.key] && rulesData[item.key].is_use">已启用</el-tag>
|
||||
<el-tag type="danger" v-else>未启用</el-tag>
|
||||
</span>
|
||||
<span class="p-[15px] w-[10%] text-[14px] text-[#666] text-[var(--el-color-primary)] cursor-pointer" @click="examineFn(key)">配置</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="ruleDialog" :title="'规则配置'" width="600px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-dialog v-model="ruleDialog" :title="'规则配置'" width="600px" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<div v-for="(item, key) in rules" :key="key" class="pl-[60px]">
|
||||
<component :is="item.component" v-model="formData[item.key]" ref="ruleRefs" v-if="item.component && currRule == key"/>
|
||||
</div>
|
||||
@ -48,11 +50,13 @@ import { useRoute } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import { getGrowthRuleConfig, setGrowthRuleConfig, getGrowthRuleDict } from '@/app/api/member'
|
||||
import Test from '@/utils/test'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const route = useRoute()
|
||||
const pageName = route.meta.title
|
||||
const rules = ref({})
|
||||
const formData = ref({})
|
||||
const rulesData = ref<any>({}) // 规则数据
|
||||
const formData = ref<any>({})
|
||||
const ruleRefs = ref(null)
|
||||
const loading = ref(true)
|
||||
|
||||
@ -66,7 +70,7 @@ getGrowthRuleDict().then(({ data }) => {
|
||||
|
||||
const ruleConfigFn = () => {
|
||||
getGrowthRuleConfig().then(({ data }) => {
|
||||
!Test.empty(data) && (formData.value = data)
|
||||
!Test.empty(data) && (rulesData.value = data)
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
@ -94,6 +98,7 @@ const ruleDialog = ref(false)
|
||||
// 查看操作
|
||||
const currRule = ref('')
|
||||
const examineFn = (key:string) => {
|
||||
formData.value = cloneDeep(rulesData.value)
|
||||
ruleDialog.value = true
|
||||
currRule.value = key
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="ruleDialog" :title="'规则配置'" width="600px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-dialog v-model="ruleDialog" :title="'规则配置'" width="600px" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<div v-for="(item, key) in rules.grant" :key="key" class="pl-[60px]">
|
||||
<component :is="item.component" v-model="formData.grant[item.key]" ref="ruleRefs" v-if="item.component && currRule == key"/>
|
||||
</div>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-[20px]">
|
||||
<el-alert :description="t('transferTips')" type="warning" show-icon>
|
||||
<el-alert type="warning" show-icon>
|
||||
<template #title>
|
||||
<span class="!text-[14px]">{{ t('operationTip') }}</span>
|
||||
</template>
|
||||
|
||||
149
admin/src/app/views/setting/transfer_scene.vue
Normal file
149
admin/src/app/views/setting/transfer_scene.vue
Normal file
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card mt-[15px] !border-none" shadow="never" v-for="(item, key) in screne" :key="key">
|
||||
<div class="flex items-center mb-[20px]">
|
||||
<h3 class="text-[14px] mr-[20px]">{{ item.name }}</h3>
|
||||
<div class="flex items-center">
|
||||
<span class="text-[14px] mr-[10px]">{{ t('transferSceneId') }}:</span>
|
||||
<div class="flex items-center">
|
||||
<el-input v-model.trim="item.scene_id" maxlength="5" class="!w-[60px]" :disabled="item.disabled" @blur="handleInput($event,key,item)" :ref="(el: any) =>{ if(el) inputRefs[key] = el }" v-show="!item.disabled"/>
|
||||
<div v-show="item.disabled">{{item.scene_id ? item.scene_id : '--'}}</div>
|
||||
<div @click="handleDisabled(item, key)" class="w-[40xp] flex items-center ml-[8px]"><el-icon size="20" color="var(--el-color-primary)"><Edit /></el-icon></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center justify-between p-[10px] table-item-border bg">
|
||||
<span class="text-base w-[230px]">{{ t('transferType') }}</span>
|
||||
<span class="text-base w-[230px]">{{ t('recvPerception') }}</span>
|
||||
<span class="text-base w-[230px]">{{ t('reportInfos') }}</span>
|
||||
<span class="text-base w-[80px] text-center">{{ t('operation') }}</span>
|
||||
</div>
|
||||
<div v-if="Object.values(item.trade_scene_data).length">
|
||||
<div class="flex items-center justify-between p-[10px] table-item-border" v-for="(subItem, subKey) in item.trade_scene_data" :key="subKey">
|
||||
<div class="flex w-[230px] flex-shrink-0 text-base">{{ subItem.name }}</div>
|
||||
<div class="flex w-[230px] flex-shrink-0 text-base">{{ subItem.perception }}</div>
|
||||
<div class="w-[230px] flex-shrink-0 text-base">
|
||||
<div v-for="(childItem,childKey) in subItem.infos" :key="childKey">{{ childKey }}:{{ childItem }}</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center w-[80px] select-none">
|
||||
<button class="text-base text-primary" @click="configFn(item,subItem,subKey)">{{ t('deploy') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="min-h-[80px] flex items-center justify-center text-base">
|
||||
{{ t('noData') }}
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-dialog v-model="showDialog" :title="curData.name" width="550px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="110px" ref="formRef" class="page-form">
|
||||
<el-form-item :label="t('recvPerception')" prop="perception" :rules="[{ required: true, message: t('recvPerceptionTips'), trigger: 'blur' }]">
|
||||
<el-select v-model="formData.perception" :placeholder="t('recvPerceptionTips')" clearable class="!w-[300px]">
|
||||
<el-option v-for="(item,index) in curData.user_recv_perception" :key="index" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<template v-for="(item, index) in curData.transfer_scene_report_infos" :key="index">
|
||||
<el-form-item :label="item" :prop="`infos[${item}]`" :rules="[{ required: true, message: `请输入${item}`, trigger: 'blur' }]">
|
||||
<el-input v-model.trim="formData.infos[item]" maxlength="40" class="!w-[300px]"/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="cancel">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getTransferScene, setSceneId, setTradeScene } from '@/app/api/pay'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { FormInstance } from 'element-plus'
|
||||
|
||||
const screne = ref<any>({})
|
||||
const loading = ref(false)
|
||||
const getTransferSceneFn = () => {
|
||||
getTransferScene().then(res => {
|
||||
screne.value = res.data
|
||||
for (const key in screne.value) {
|
||||
screne.value[key].disabled = true
|
||||
}
|
||||
})
|
||||
}
|
||||
getTransferSceneFn()
|
||||
|
||||
// 更改场景值
|
||||
const handleInput = (e: any, key: any, data: any) => {
|
||||
if (e.target.value) {
|
||||
setSceneId({
|
||||
scene: key,
|
||||
scene_id: e.target.value
|
||||
}).then(() => {
|
||||
data.disabled = true
|
||||
getTransferSceneFn()
|
||||
})
|
||||
} else {
|
||||
data.disabled = true
|
||||
}
|
||||
}
|
||||
const inputRefs = ref<any>({})
|
||||
const handleDisabled = (data: any, key: any) => {
|
||||
data.disabled = false
|
||||
nextTick(() => {
|
||||
inputRefs.value[key].focus()
|
||||
})
|
||||
}
|
||||
const showDialog = ref(false)
|
||||
const curData = ref<any>({})
|
||||
const formData = ref({
|
||||
type: '',
|
||||
scene: '',
|
||||
perception: '',
|
||||
infos: {}
|
||||
})
|
||||
const configFn = (data: any, subData: any, type: any) => {
|
||||
curData.value = cloneDeep(data)
|
||||
formData.value.type = type
|
||||
formData.value.scene = subData.scene
|
||||
formData.value.perception = subData.perception
|
||||
formData.value.infos = cloneDeep(subData.infos)
|
||||
showDialog.value = true
|
||||
}
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
/**
|
||||
* 确认
|
||||
* @param formEl
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
setTradeScene(formData.value).then(() => {
|
||||
loading.value = false
|
||||
showDialog.value = false
|
||||
getTransferSceneFn()
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
showDialog.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-item-border {
|
||||
@apply border-b border-[var(--el-border-color)];
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +1,6 @@
|
||||
<template>
|
||||
<div class="main-container h-[500px] w-full p-5 bg-white" v-loading="loading">
|
||||
<div class="flex flex-wrap px-2 plug-list pb-10">
|
||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
||||
<div class="flex flex-col ml-2">
|
||||
<span class="text-sm truncate w-[190px]">{{t('refreshMenu')}}</span>
|
||||
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('refreshMenuDesc')">{{t('refreshMenuDesc')}}</span>
|
||||
</div>
|
||||
<span class="plug-item-operate" @click="refreshMenu()">{{t('refresh')}}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center bg-[#F7F8FA] p-3 w-[295px] relative plug-item mr-4 mb-4 cursor-pointer">
|
||||
<div class="flex flex-col ml-2">
|
||||
<span class="text-sm truncate w-[190px]">{{t('dataCache')}}</span>
|
||||
@ -23,26 +15,26 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { clearSchemaCache, menuRefresh } from '@/app/api/sys'
|
||||
import { clearCache } from '@/app/api/sys'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
|
||||
const loading = ref<Boolean>(false)
|
||||
|
||||
// 数据缓存
|
||||
const schemaCache = () => {
|
||||
ElMessageBox.confirm(t('clearCacheTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
loading.value = true
|
||||
clearSchemaCache({}).then(res => {
|
||||
clearCache({}).then(res => {
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
// 更新菜单
|
||||
const refreshMenu = () => {
|
||||
loading.value = true
|
||||
menuRefresh({}).then(res => {
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -16,28 +16,43 @@
|
||||
</el-input>
|
||||
</slot>
|
||||
</div>
|
||||
<el-dialog v-model="showDialog" :title="t('selectLinkTips')" width="40%" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false" @close="cancel">
|
||||
|
||||
<el-dialog v-model="showDialog" :title="t('selectLinkTips')" width="850px" :destroy-on-close="true" :close-on-click-modal="false" @close="cancel">
|
||||
<div class="flex items-start">
|
||||
<el-scrollbar class="w-[140px] border-r h-[350px]">
|
||||
<div v-for="(item, index) in link" :key="index"
|
||||
class="h-[40px] leading-[40px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
|
||||
<el-scrollbar class="w-[140px] border-r !h-[550px] link-wrap">
|
||||
<template v-for="(item, index) in link" :key="index">
|
||||
<template v-if="item.type == 'folder'">
|
||||
<div class="flex h-[40px] leading-[40px] cursor-pointer px-[10px] items-center select-none mr-[10px]"
|
||||
@click="item.foldSwitch = !item.foldSwitch">
|
||||
<span class="flex-1">{{ item.title }}</span>
|
||||
<el-icon>
|
||||
<ArrowDown v-if="item.foldSwitch" />
|
||||
<ArrowUp v-else />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="child-list-wrap" v-show="item.foldSwitch">
|
||||
<div v-for="(childItem, childIndex) in item.child_list" :key="childIndex" class="h-[40px] leading-[40px] cursor-pointer hover:bg-primary-light-9 hover:text-primary select-none truncate pl-[25px] mr-[20px]" :class="[ childItem.name == parentLinkName ? 'bg-primary-light-9 text-primary' : '' ]" @click="changeParentLink(childItem)">{{ childItem.title }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else
|
||||
class="h-[40px] leading-[40px] cursor-pointer px-[10px] items-center select-none hover:bg-primary-light-9 hover:text-primary mr-[20px]"
|
||||
:class="[ item.name == parentLinkName ? 'bg-primary-light-9 text-primary' : '' ]"
|
||||
@click="changeParentLink(item)">
|
||||
{{ item.title }}
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
<el-scrollbar class="pl-4 h-[350px] flex-1">
|
||||
<el-scrollbar class="pl-4 !h-[550px] flex-1">
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<template v-if="parentLinkName == 'DIY_LINK'">
|
||||
<component v-if="dynamicComponentName" :is="dynamicComponentName" v-bind="selectLink" ref="dynamicComponentRefs" />
|
||||
<template v-else-if="parentLinkName == 'DIY_LINK'">
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyLinkName')">
|
||||
<el-input v-model="selectLink.title" :placeholder="t('diyLinkNamePlaceholder')" />
|
||||
<el-input v-model="selectLink.title" :placeholder="t('diyLinkNamePlaceholder')" class="!w-[300px]" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyLinkUrl')">
|
||||
<el-input v-model="selectLink.url" :placeholder="t('diyLinkUrlPlaceholder')" />
|
||||
<el-input v-model="selectLink.url" :placeholder="t('diyLinkUrlPlaceholder')" class="!w-[300px]" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label=" ">
|
||||
@ -47,15 +62,15 @@
|
||||
<div class="text-sm text-gray-400 select-text">跳转外部链接“http”或“https”开头,例:https://baidu.com</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="parentLinkName == 'DIY_JUMP_OTHER_APPLET'">
|
||||
<template v-else-if="parentLinkName == 'DIY_JUMP_OTHER_APPLET'">
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyAppletId')">
|
||||
<el-input v-model="selectLink.appid" :placeholder="t('diyAppletIdPlaceholder')" clearable maxlength="50" />
|
||||
<el-input v-model="selectLink.appid" :placeholder="t('diyAppletIdPlaceholder')" clearable maxlength="50" class="!w-[300px]" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyAppletPage')">
|
||||
<el-input v-model="selectLink.page" :placeholder="t('diyAppletPagePlaceholder')" clearable maxlength="100" />
|
||||
<el-input v-model="selectLink.page" :placeholder="t('diyAppletPagePlaceholder')" clearable maxlength="100" class="!w-[300px]" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label=" ">
|
||||
@ -65,10 +80,10 @@
|
||||
<div class="text-sm text-gray-400 select-text">小程序路径格式如:app/pages/index/index</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-if="parentLinkName == 'DIY_MAKE_PHONE_CALL'">
|
||||
<template v-else-if="parentLinkName == 'DIY_MAKE_PHONE_CALL'">
|
||||
<div class="mb-[16px]">
|
||||
<el-form-item :label="t('diyMakePhone')">
|
||||
<el-input v-model="selectLink.mobile" :placeholder="t('diyMakePhonePlaceholder')" clearable maxlength="50" />
|
||||
<el-input v-model="selectLink.mobile" :placeholder="t('diyMakePhonePlaceholder')" clearable maxlength="30" class="!w-[300px]" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<el-form-item label=" ">
|
||||
@ -98,7 +113,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { t } from '@/lang'
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, defineAsyncComponent } from 'vue'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { getLink } from '@/app/api/diy'
|
||||
import { ElMessage } from 'element-plus'
|
||||
@ -106,7 +121,8 @@ import { ElMessage } from 'element-plus'
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
ignore: {
|
||||
type: Array,
|
||||
@ -135,20 +151,40 @@ const parentLinkName = ref('')
|
||||
|
||||
const childList: any = ref([])
|
||||
|
||||
const dynamicComponentName: any = ref('') // 动态组件名称
|
||||
|
||||
const dynamicComponentRefs: any = ref(null) // 动态组件ref
|
||||
|
||||
const selectLink: any = ref([])
|
||||
|
||||
const modules: any = import.meta.glob('@/**/*.vue')
|
||||
|
||||
const show = () => {
|
||||
getLinkFn(() => {
|
||||
// 每次打开时赋值
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value)
|
||||
parentLinkName.value = selectLink.value.parent
|
||||
for (let key in link.value) {
|
||||
for (const key in link.value) {
|
||||
if (link.value[key].type == 'folder') {
|
||||
// 兼容以前数据结构
|
||||
if (link.value[key].name == parentLinkName.value) {
|
||||
changeParentLink(link.value[key].child_list[0])
|
||||
} else {
|
||||
for (let i = 0; i < link.value[key].child_list.length; i++) {
|
||||
if (link.value[key].child_list[i].name == parentLinkName.value) {
|
||||
changeParentLink(link.value[key].child_list[i])
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (link.value[key].name == parentLinkName.value) {
|
||||
changeParentLink(link.value[key])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
showDialog.value = true
|
||||
isDrag.value = true
|
||||
emit('confirm', isDrag.value)
|
||||
@ -169,12 +205,32 @@ const getLinkFn = (callback:any=null)=> {
|
||||
}
|
||||
}
|
||||
|
||||
childList.value = Object.values(link.value)[0].child_list
|
||||
// 默认全部展开
|
||||
for (const field in link.value) {
|
||||
if (link.value[field].type == 'folder') {
|
||||
link.value[field].foldSwitch = true
|
||||
}
|
||||
}
|
||||
|
||||
const firstLink: any = Object.values(link.value)[0]
|
||||
let parentName: any = ''
|
||||
if (firstLink.type == 'folder') {
|
||||
childList.value = firstLink.child_list[0].child_list
|
||||
parentName = firstLink.child_list[0].name
|
||||
if (!firstLink.child_list[0].component) {
|
||||
dynamicComponentName.value = ''
|
||||
}
|
||||
} else {
|
||||
childList.value = firstLink.child_list
|
||||
parentName = firstLink.parent_name
|
||||
dynamicComponentName.value = ''
|
||||
}
|
||||
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value)
|
||||
} else {
|
||||
selectLink.value = {
|
||||
parent: Object.values(link.value)[0].name
|
||||
parent: parentName
|
||||
}
|
||||
}
|
||||
parentLinkName.value = selectLink.value.parent
|
||||
@ -185,8 +241,14 @@ const getLinkFn = (callback:any=null)=> {
|
||||
|
||||
// 选择父级链接
|
||||
const changeParentLink = (item: any) => {
|
||||
childList.value = item.child_list
|
||||
parentLinkName.value = item.name
|
||||
childList.value = item.child_list
|
||||
if (item.component) {
|
||||
dynamicComponentName.value = item.component
|
||||
dynamicComponentName.value = defineAsyncComponent(modules[dynamicComponentName.value])
|
||||
} else {
|
||||
dynamicComponentName.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 选择子链接
|
||||
@ -205,14 +267,27 @@ const clear = () => {
|
||||
}
|
||||
|
||||
const save = () => {
|
||||
if (parentLinkName.value === 'DIY_LINK') {
|
||||
const fields = ['name', 'parent', 'title', 'url', 'appid', 'mobile', 'action', 'page']
|
||||
if (dynamicComponentName.value && dynamicComponentRefs.value) {
|
||||
// 扩展链接
|
||||
const data = dynamicComponentRefs.value.getData()
|
||||
if (!data) return
|
||||
|
||||
// 删除上次选择的关联字段
|
||||
for (const key in selectLink.value) {
|
||||
if (fields.indexOf(key) == -1) {
|
||||
delete selectLink.value[key]
|
||||
}
|
||||
}
|
||||
Object.assign(selectLink.value, data)
|
||||
} else if (parentLinkName.value === 'DIY_LINK') {
|
||||
// 自定义链接
|
||||
|
||||
if (!selectLink.value.title) {
|
||||
ElMessage({
|
||||
message: t('diyLinkNameNotEmpty'),
|
||||
type: 'warning'
|
||||
});
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@ -220,22 +295,20 @@ const save = () => {
|
||||
ElMessage({
|
||||
message: t('diyLinkUrlNotEmpty'),
|
||||
type: 'warning'
|
||||
});
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.name = parentLinkName.value
|
||||
selectLink.value.action = '';
|
||||
selectLink.value.action = ''
|
||||
|
||||
delete selectLink.value.appid;
|
||||
delete selectLink.value.mobile;
|
||||
delete selectLink.value.appid
|
||||
delete selectLink.value.mobile
|
||||
|
||||
} else if (parentLinkName.value == 'DIY_PAGE') {
|
||||
// 自定义页面
|
||||
|
||||
selectLink.value.name = parentLinkName.value
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.action = 'decorate';
|
||||
|
||||
delete selectLink.value.appid;
|
||||
@ -261,13 +334,11 @@ const save = () => {
|
||||
}
|
||||
|
||||
selectLink.value.name = parentLinkName.value
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.title = '微信小程序-' + selectLink.value.appid
|
||||
selectLink.value.action = '';
|
||||
|
||||
delete selectLink.value.url;
|
||||
delete selectLink.value.mobile;
|
||||
selectLink.value.action = ''
|
||||
|
||||
delete selectLink.value.url
|
||||
delete selectLink.value.mobile
|
||||
} else if (parentLinkName.value == 'DIY_MAKE_PHONE_CALL') {
|
||||
// 拨打电话
|
||||
|
||||
@ -275,17 +346,27 @@ const save = () => {
|
||||
ElMessage({
|
||||
message: t('diyMakePhoneNotEmpty'),
|
||||
type: 'warning'
|
||||
});
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
selectLink.value.name = parentLinkName.value
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
selectLink.value.title = '拨打电话:' + selectLink.value.mobile
|
||||
selectLink.value.action = '';
|
||||
selectLink.value.action = ''
|
||||
|
||||
delete selectLink.value.url;
|
||||
delete selectLink.value.appid;
|
||||
delete selectLink.value.url
|
||||
delete selectLink.value.appid
|
||||
}
|
||||
|
||||
selectLink.value.parent = parentLinkName.value
|
||||
|
||||
// 删除无用字段
|
||||
if (dynamicComponentName.value == '') {
|
||||
for (const key in selectLink.value) {
|
||||
if (fields.indexOf(key) == -1) {
|
||||
delete selectLink.value[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
value.value = cloneDeep(selectLink.value)
|
||||
@ -306,6 +387,9 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.link-wrap{
|
||||
|
||||
}
|
||||
.link-input .el-input__inner {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
<template>
|
||||
<upload-attachment type="image" ref="imageRef" limit="" @confirm="imageSelect" />
|
||||
<upload-attachment type="video" ref="videoRef" @confirm="videoSelect" />
|
||||
<vue-ueditor-wrap v-model="content" :config="editorConfig" :editorDependencies="['ueditor.config.js','ueditor.all.js']" ref="editorRef"></vue-ueditor-wrap>
|
||||
<vue-ueditor-wrap v-model="content" :config="editorConfig"
|
||||
:editorDependencies="['ueditor.config.js', 'ueditor.all.js']" ref="editorRef"
|
||||
@ready="handleEditorReady"></vue-ueditor-wrap>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
||||
import { getToken, img } from '@/utils/common'
|
||||
import { VueUeditorWrap } from 'vue-ueditor-wrap'
|
||||
import storage from '@/utils/storage'
|
||||
@ -50,6 +52,7 @@ const baseUrl = import.meta.env.VITE_APP_BASE_URL.substr(-1) == '/' ? import.met
|
||||
const editorConfig = ref({
|
||||
debug: false,
|
||||
UEDITOR_HOME_URL: import.meta.env.MODE == 'development' ? '/public/ueditor/' : '/admin/ueditor/',
|
||||
UEDITOR_CORS_URL: import.meta.env.MODE == 'development' ? location.origin + '/ueditor/' : location.origin + '/admin/ueditor/',
|
||||
serverUrl: `${baseUrl}sys/ueditor`,
|
||||
serverHeaders,
|
||||
// 编辑器不自动被内容撑高
|
||||
@ -58,6 +61,7 @@ const editorConfig = ref({
|
||||
initialFrameHeight: prop.height,
|
||||
// 初始容器宽度
|
||||
initialFrameWidth: '100%',
|
||||
wordCount: true,
|
||||
toolbarCallback: function (cmd, editor) {
|
||||
editorEl = editor
|
||||
switch (cmd) {
|
||||
@ -70,6 +74,27 @@ const editorConfig = ref({
|
||||
}
|
||||
}
|
||||
})
|
||||
// 监听编辑器准备就绪事件
|
||||
const handleEditorReady = (editor) => {
|
||||
// 方案一:通过内容变化事件手动统计(推荐)
|
||||
// editorInstance.addListener('contentChange', () => {
|
||||
// const rawContent = editorInstance.getContent()
|
||||
// // 过滤所有空白字符
|
||||
// charCount.value = rawContent.replace(/\s/g, '').length
|
||||
// // 同步到统计栏(需操作DOM)
|
||||
// updateStatsDisplay(charCount.value)
|
||||
// })
|
||||
console.log('扩展原型链', editor)
|
||||
|
||||
// 方案二:原型链扩展(如果编辑器版本支持)
|
||||
const originalCount = editor.getContentLength; // 原生统计方法
|
||||
|
||||
// 覆盖方法:去除空格后统计
|
||||
editor.getContentLength = function () {
|
||||
const rawContent = editor.getContent();
|
||||
return rawContent.replace(/[\s\u3000]+/g, '').length;
|
||||
};
|
||||
}
|
||||
|
||||
const imageSelect = (data: Record<string, any>) => {
|
||||
data.forEach((item: any) => {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<div v-else class="cursor-pointer">{{ t('addHotArea') }}</div>
|
||||
</slot>
|
||||
</div>
|
||||
<el-dialog v-model="showDialog" :title="t('hotAreaSet')" width="810px" :close-on-press-escape="false" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-dialog v-model="showDialog" :title="t('hotAreaSet')" width="810px" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
|
||||
<div class="flex">
|
||||
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
"cancel": "取消",
|
||||
"search": "搜索",
|
||||
"reset": "重置",
|
||||
"refresh": "刷新",
|
||||
"refreshSuccess": "刷新成功",
|
||||
"select": "选择",
|
||||
"export": "导出列表",
|
||||
"exportPlaceholder": "确定要导出数据吗?",
|
||||
"exportTip": "批量导出数据",
|
||||
@ -177,5 +180,12 @@
|
||||
"write": "可写",
|
||||
"cloudbuildSuccess": "编译完成",
|
||||
"showDialogCloseTips": "编译任务尚未完成,关闭将取消编译,是否要继续关闭?"
|
||||
}
|
||||
},
|
||||
"formSelectContentTitle": "表单名称",
|
||||
"formSelectContentTitlePlaceholder": "请输入表单名称",
|
||||
"formSelectContentTypeName": "表单类型",
|
||||
"formSelectContentTypeNamePlaceholder": "请选择表单类型",
|
||||
"formSelectContentTypeAll": "全部",
|
||||
"formSelectContentTips": "请选择表单"
|
||||
|
||||
}
|
||||
|
||||
@ -4,8 +4,6 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, markRaw, defineAsyncComponent, provide } from 'vue'
|
||||
import { getAppType } from '@/utils/common'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import Storage from '@/utils/storage'
|
||||
|
||||
const sysLayout = import.meta.glob('./*/index.vue')
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3883393 */
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_veozpkoyxa.woff2?t=1737014488882') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_veozpkoyxa.woff?t=1737014488882') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_veozpkoyxa.ttf?t=1737014488882') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_7g8irvl9kow.woff2?t=1740712666977') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_7g8irvl9kow.woff?t=1740712666977') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_7g8irvl9kow.ttf?t=1740712666977') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,18 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconshanchu-fanggaiV6xx:before {
|
||||
content: "\e88a";
|
||||
}
|
||||
|
||||
.iconshanchu-yuangaiV6xx:before {
|
||||
content: "\e88b";
|
||||
}
|
||||
|
||||
.iconbangzhuV6mm-1:before {
|
||||
content: "\e888";
|
||||
}
|
||||
|
||||
.iconshangchengshequ:before {
|
||||
content: "\e880";
|
||||
}
|
||||
@ -2716,4 +2728,3 @@
|
||||
.iconquanping:before {
|
||||
content: "\eb11";
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "nc-iconfont"; /* Project id 4567203 */
|
||||
src: url('//at.alicdn.com/t/c/font_4567203_1gdtkv2t1dd.woff2?t=1740126778258') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4567203_1gdtkv2t1dd.woff?t=1740126778258') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4567203_1gdtkv2t1dd.ttf?t=1740126778258') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_4567203_9qmfc2elgrt.woff2?t=1741345195504') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_4567203_9qmfc2elgrt.woff?t=1741345195504') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_4567203_9qmfc2elgrt.ttf?t=1741345195504') format('truetype');
|
||||
}
|
||||
|
||||
.nc-iconfont {
|
||||
@ -13,6 +13,14 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.nc-icon-qingliV6xx:before {
|
||||
content: "\e865";
|
||||
}
|
||||
|
||||
.nc-icon-liebiao-xiV6xx1:before {
|
||||
content: "\e863";
|
||||
}
|
||||
|
||||
.nc-icon-shequfenleiV6xx1:before {
|
||||
content: "\e862";
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user