mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-03-13 07:15:52 +00:00
up
This commit is contained in:
parent
6648951a28
commit
b021bc6660
@ -90,3 +90,4 @@ export function cancelInstall(addon: string) {
|
||||
export function getInstalledAddonList() {
|
||||
return request.get('addon/list/install')
|
||||
}
|
||||
|
||||
|
||||
@ -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 })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取万能表单详情
|
||||
@ -225,4 +233,4 @@ export function getFormRecordsMember(params: Record<string, any>) {
|
||||
*/
|
||||
export function copyForm(params: Record<string, any>) {
|
||||
return request.post(`diy/form/copy`, params, { showSuccessMessage: true })
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
@ -604,6 +604,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 })
|
||||
}
|
||||
|
||||
/***************************************************** 获取应用 ****************************************************/
|
||||
/**
|
||||
* 获取应用
|
||||
|
||||
@ -61,8 +61,8 @@ export function getWeappVersionList(params: Record<string, any>) {
|
||||
|
||||
/**
|
||||
* 获取微信小程序上传日志
|
||||
* @param key
|
||||
* @returns
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
export function getWeappUploadLog(key: string) {
|
||||
return request.get(`weapp/upload/${key}`)
|
||||
@ -130,4 +130,28 @@ export function deleteVersion(id: string) {
|
||||
*/
|
||||
export function getIsTradeManaged() {
|
||||
return request.get('weapp/delivery/getIsTradeManaged')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置服务器域名
|
||||
* @param params
|
||||
*/
|
||||
export function setWeappDomain(params: Record<string, any>) {
|
||||
return request.put('weapp/domain', params, { showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置小程序隐私协议
|
||||
* @param params
|
||||
*/
|
||||
export function setWeappPrivacySetting(params: Record<string, any>) {
|
||||
return request.put('weapp/privacysetting', params, { showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取小程序隐私协议
|
||||
* @param params
|
||||
*/
|
||||
export function getWeappPrivacySetting() {
|
||||
return request.get('weapp/privacysetting')
|
||||
}
|
||||
|
||||
@ -194,6 +194,7 @@ const open = async () => {
|
||||
} else {
|
||||
loading.value = false
|
||||
cloudBuildCheck.value = data
|
||||
showDialog.value = true
|
||||
}
|
||||
}).catch(() => {
|
||||
showDialog.value = false
|
||||
|
||||
@ -134,6 +134,7 @@ const emits = defineEmits(['complete', 'cloudbuild'])
|
||||
const upgradeTipsShowDialog = ref<boolean>(false)
|
||||
|
||||
let upgradeLog: any = []
|
||||
let errorLog: any = []
|
||||
/**
|
||||
* 查询升级任务
|
||||
*/
|
||||
@ -158,12 +159,18 @@ const getUpgradeTaskFn = () => {
|
||||
})
|
||||
// 安装失败
|
||||
if (data.error) {
|
||||
upgradeTask.value = data
|
||||
ElMessage({ message: '升级失败', type: 'error' })
|
||||
terminalRef.value.pushMessage({ content: data.error, class: 'error' })
|
||||
data.error.forEach(item => {
|
||||
if (!errorLog.includes(item)) {
|
||||
terminalRef.value.pushMessage({ content: item, class: 'error' })
|
||||
errorLog.push(item)
|
||||
}
|
||||
})
|
||||
}
|
||||
// 恢复完毕
|
||||
if (data.step == 'restoreComplete') {
|
||||
return
|
||||
}
|
||||
// 安装完成
|
||||
// 升级完成
|
||||
if (data.step == 'upgradeComplete') {
|
||||
active.value = 'complete'
|
||||
notificationEl && notificationEl.close()
|
||||
@ -316,6 +323,7 @@ const clearUpgradeTaskFn = () => {
|
||||
uploading.value = false
|
||||
upgradeTask.value = null
|
||||
upgradeLog = []
|
||||
errorLog = []
|
||||
flashInterval && clearInterval(flashInterval)
|
||||
clearUpgradeTask().then(() => {}).catch()
|
||||
}
|
||||
|
||||
@ -42,5 +42,6 @@
|
||||
"uploadSuccessTips": "小程序上传成功后还需到<a href='https://mp.weixin.qq.com/' target='_blank' class='text-primary'>微信公众平台</a>提交审核,审核通过后发布才算正式上线。",
|
||||
"knownToKnow": "我已知晓,不需要再次提示",
|
||||
"siteAuthTips": "上传代码需先绑定授权码,请联系平台管理员进行绑定",
|
||||
"againUpload": "重新上传"
|
||||
"againUpload": "重新上传",
|
||||
"uploadWeapp": "上传小程序"
|
||||
}
|
||||
|
||||
@ -34,5 +34,26 @@
|
||||
"weappUpload": "小程序代码上传",
|
||||
"uploadKey": "上传密钥",
|
||||
"uploadKeyTips": "配置之后可实现在线上传小程序版本",
|
||||
"uploadIpTips": "如果小程序代码上传开启了ip白名单设置,在ip白名单中添加ip:"
|
||||
}
|
||||
"uploadIpTips": "如果小程序代码上传开启了ip白名单设置,在ip白名单中添加ip:",
|
||||
"update": "修改",
|
||||
"udpUrl": "udp合法域名",
|
||||
"tcpUrl": "tcp合法域名",
|
||||
"requestdomainPlaceholder": "以 https:// 开头。域名间请用 ; 分割",
|
||||
"wsrequestdomainPlaceholder": "以 wss:// 开头。域名间请用 ; 分割",
|
||||
"uploaddomainPlaceholder": "以 https:// 开头。域名间请用 ; 分割",
|
||||
"downloaddomainPlaceholder": "以 https:// 开头。域名间请用 ; 分割",
|
||||
"udpdomainPlaceholder": "以 udp:// 开头。域名间请用 ; 分割",
|
||||
"tcpdomainPlaceholder": "以 tcp:// 开头。域名间请用 ; 分割",
|
||||
"domainError": "该域名协议头非法",
|
||||
"serviceContentStatement": "服务内容声明",
|
||||
"privacyAgreement": "用户隐私保护指引",
|
||||
"privacyAgreementTips": "基于微信提供的 标准化用户隐私保护指引,根据小程序实际情况更新并展示给用户。",
|
||||
"setting": "设置",
|
||||
"privacyAgreementTitle": "用户隐私保护指引设置",
|
||||
"settingPlaceholder": "请填写用途",
|
||||
"addSettingType": "增加信息类型",
|
||||
"settingTypeTitle": "使用用户信息类型",
|
||||
"addContact": "增加联系方式",
|
||||
"addSdkInfo": "增加第三方SDK信息",
|
||||
"addSdkSettingList": "增加SDK提供方的隐私信息"
|
||||
}
|
||||
|
||||
@ -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": "图片圆角",
|
||||
@ -291,5 +292,104 @@
|
||||
"formPlaceholder": "提示语",
|
||||
"formPlaceholderTips": "请输入提示语",
|
||||
"isRequired": "是否必填",
|
||||
"optionPlaceholder": "请输入选项内容"
|
||||
"optionPlaceholder": "请输入选项内容",
|
||||
"formLayout": "表单布局",
|
||||
"layoutStyle": "排版风格",
|
||||
"singleTiling": "单列平铺",
|
||||
"singleTilingTipsOne": "将所有需要填写的表单内容项直接罗列在页面上。",
|
||||
"singleTilingTipsTwo": "适用于表单内容项较少且项目之间无逻辑关系的情况。",
|
||||
"singleTilingTipsThree": "其优势在于相对简洁、便于操作",
|
||||
"singleTilingTipsFour": "但当表单项数量较大时,一次性展示全部信息会增加用户的操作负担,填写效率较低",
|
||||
"arrangeSideBySide": "左右排列",
|
||||
"arrangeSideBySideTipsOne": "将表单分为左右两部分,左侧为标题和描述,右侧为输入区域。",
|
||||
"arrangeSideBySideTipsTwo": "这种布局适用于标题和描述内容较少的情况,能够提高表单的紧凑性和用户体验。",
|
||||
"layoutStyleTips": "切换后将同步所有表单组件的展示形式",
|
||||
"borderControl": "边框开关",
|
||||
"fieleContent": "字段内容",
|
||||
"fieldName": "字段名称",
|
||||
"filedRemark": "字段说明",
|
||||
"otherSetting": "其他设置",
|
||||
"hideControl": "隐藏该组件",
|
||||
"hideControlTipsOne": "勾选后填表人填表时看不到该字段。",
|
||||
"hideControlTipsTwo": "适用于你不再收集该字段又不希望删除已收集的数据。",
|
||||
"textStyle": "文字样式",
|
||||
"filedRemarkStyle": "字段说明样式",
|
||||
|
||||
"style": "样式",
|
||||
"listStyle": "列表",
|
||||
"dropDownStyle": "下拉",
|
||||
"option": "选项",
|
||||
"addSingleOption": "添加单个选项",
|
||||
"addMultipleOption": "批量添加选项",
|
||||
"addOptionTips": "每个选项之间用英文“,” 隔开,自动过滤重复内容",
|
||||
"errorTipsOne": "存在重复选项,请检查内容",
|
||||
"errorTipsTwo": "选项已存在,请重新输入",
|
||||
|
||||
"dataFormat": "日期格式",
|
||||
"startDate": "开始日期",
|
||||
"startTime": "开始时间",
|
||||
"startDataTips": "开始日期不能为空",
|
||||
"startTimeTips": "开始时间不能为空",
|
||||
"startDataPlaceholder": "请选择开始日期",
|
||||
"dataPlaceholder": "请选择日期",
|
||||
"timePlaceholder": "请选择时间",
|
||||
"startTimePlaceholder": "请选择开始时间",
|
||||
"endDate": "结束日期",
|
||||
"endTime": "结束时间",
|
||||
"endDataPlaceholder": "请选择结束日期",
|
||||
"endTimePlaceholder": "请选择结束时间",
|
||||
"endDataTips": "结束日期不能为空",
|
||||
"endTimeTips": "结束时间不能为空",
|
||||
"startEndDataTips": "开始日期不能大于结束日期",
|
||||
"startEndTimeTips": "开始时间不能大于结束时间",
|
||||
"currentDate": "当天日期",
|
||||
"diyDate": "指定日期",
|
||||
"currentTime": "当天时间",
|
||||
"diyTime": "指定时间",
|
||||
|
||||
"preventDuplication":"内容防重复",
|
||||
"preventDuplicationTipsOne":"该组件填写的内容不能与已提交的数据重复。",
|
||||
"preventDuplicationTipsTwo":"极端情况下可能存在延时导致限制失效。",
|
||||
"privacyProtection":"隐私保护",
|
||||
"privacyProtectionTipsOne":"会自动将提交的个人信息做加密展示。",
|
||||
"privacyProtectionTipsTwo":"适用于公开展示收集的数据且不暴露用户隐私。",
|
||||
"privacyProtectionTipsThree":"提交后自动隐藏中间11位数字,仅管理员可查看",
|
||||
"privacyProtectionTipsFour":"提交后自动隐藏文本,仅管理员可查看",
|
||||
"privacyProtectionTipsFive":"提交后自动隐藏中间5位数字,仅管理员可查看",
|
||||
|
||||
"imageLimit":"限制数量",
|
||||
"imageLimitPlaceholder":"请输入限制数量",
|
||||
"imageLimitErrorTips":"限制数量格式输入错误",
|
||||
"imageLimitErrorTipsTwo":"限制数量不能小于0",
|
||||
"imageLimitErrorTipsThree":"限制数量必须大于0",
|
||||
"imafeLimitErrorTipsFour":"限制数量最大不能超过9",
|
||||
|
||||
"defaultValueTips":"设置后,默认值会自动填充到输入框,填表人可在此基础上进行修改。",
|
||||
"defaultErrorTips":"默认值格式输入错误",
|
||||
"defaultMustZeroTips":"默认值不能小于0",
|
||||
|
||||
"access":"获取方式",
|
||||
"authorizeWeChatLocation":"授权微信定位",
|
||||
"manuallySelectPositioning":"手动选择定位",
|
||||
|
||||
"unit":"单位",
|
||||
"unitPlaceholder":"请输入单位",
|
||||
|
||||
"followContent":"跟随内容",
|
||||
"hoverScreenBottom":"悬浮屏幕底部",
|
||||
"btnTips":"当表单内容多时,只有滚动页面至最底部才会显示提交按钮",
|
||||
"btnTipsTwo":"当表单内容多时,滚动页面至最底部时,提交按钮会自动按钮悬浮在屏幕底部,方便填表人快速提交显示在屏幕底部",
|
||||
"btnTipsThree":"若前端以嵌入形式调用表单,提交按钮组件将不显示,相关业务由该页面负责处理",
|
||||
"submitBtn":"提交按钮",
|
||||
"submitBtnName":"按钮名称",
|
||||
"btnNamePlaceholder":"请输入按钮名称",
|
||||
"submitBtnNamePlaceholder":"请输入提交按钮名称",
|
||||
"resetBtn":"重置按钮",
|
||||
"btnStyle":"按钮样式",
|
||||
"resetBtnNamePlaceholder":"请输入重置按钮名称",
|
||||
|
||||
"rowCount":"显示行数",
|
||||
"rowCountPlaceholder":"请输入显示行数"
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -45,5 +45,82 @@
|
||||
|
||||
"batchDeletion": "批量删除",
|
||||
"batchEmptySelectedFormsTips": "请选择要删除的表单",
|
||||
"batchFormsDeleteTips": "确定要删除选中的表单吗?"
|
||||
"batchFormsDeleteTips": "确定要删除选中的表单吗?",
|
||||
"promotion":"推广",
|
||||
"submitSuccess":"提交成功页",
|
||||
"writeSet":"填写设置",
|
||||
"export":"导出",
|
||||
"detail":"详情",
|
||||
"more":"更多",
|
||||
|
||||
"formPromotion":"表单推广",
|
||||
"promoteUrl":"推广链接",
|
||||
"downLoadQRCode":"下载二维码",
|
||||
"configureFailed":"配置失败",
|
||||
|
||||
"writeSuccess":"填写成功",
|
||||
"viewFillingDetails":"查看填写详情",
|
||||
"finish":"完成",
|
||||
"finishTips":"点击后进入首页",
|
||||
"back":"返回",
|
||||
"backTips":"点击后返回表单",
|
||||
"afterSubmission":"填表人提交后",
|
||||
"displayTextMessages":"显示文字消息",
|
||||
"displayTextMessagesTips":"提交后页面显示文字信息。",
|
||||
"promptText":"提示文字",
|
||||
"defaultPrompt":"默认提示",
|
||||
"defaultPromptTips":"将显示: 填写成功",
|
||||
"diyPrompt":"自定义提示",
|
||||
"tipsTextPlaceholder":"感谢你的填写",
|
||||
"subsequentPperationButtons":"后续操作按钮",
|
||||
|
||||
"validityPeriodOfVoucher":"凭证有效期",
|
||||
"noLimit":"不限制",
|
||||
"specifyTime":"设置固定有效期",
|
||||
"specifyTimeTips":"每条记录的凭证有效期都是一样的,例如:会议凭证可设置有效期为会议举行时间。",
|
||||
"submissionTime":"按提交时间设置有效期",
|
||||
"submissionTimeTips":"每条记录的凭证有效期按照提交时间来计算,例如:优惠凭证的有效期可以设置为领取后3天内有效。",
|
||||
"afterSubmissionRecords":"提交记录后",
|
||||
"effective":"有效",
|
||||
|
||||
"voucherStyle":"凭证样式",
|
||||
"titleAboveTheCode":"码上方标题",
|
||||
"titleAboveTheCodePlaceholder":"请妥善保存你的核销凭证",
|
||||
"contentAboveTheCode":"码上方内容",
|
||||
"contentAboveTheCodePlaceholder":"请输入码上方内容",
|
||||
"addLinefeeds":"添加换行符",
|
||||
"addFields":"添加字段",
|
||||
"contentBelowTheCode":"码下方内容",
|
||||
"submissionRecordTime":"展示提交记录时间",
|
||||
"currentTime":"展示当前时间",
|
||||
"currentTimeTips":"会以秒进行跳动,可起到防作假的功能",
|
||||
"voucherDeadline":"展示凭证截止时间",
|
||||
"saveVoucher":"支持填表人保存凭证",
|
||||
"dispalyPromptText":"展示提示文字",
|
||||
|
||||
"diy":"自定义",
|
||||
"apieceFillQuantity":"每人可填写次数",
|
||||
"fillQuantityTotal":"表单可填写总数",
|
||||
"writeTips":"填写限制的校验在极端情况下可能存在延时,从而导致限制失效,不建议商品限时抢购等场景使用该功能",
|
||||
"fillInTheTimePeriod":"可填写时间段",
|
||||
"setSpecifyTime":"设置开始/停止时间",
|
||||
"openDayTime":"设置每日开启时间",
|
||||
"timeLimitRuleOne":"开始/停止时间不能为空",
|
||||
"timeLimitRuleTwo":"开启时间不能为空",
|
||||
"timeLimitRuleThree":"开始时间不能等于结束时间",
|
||||
"numCannotNull":"次数不能为空",
|
||||
|
||||
"dataAndStatistics":"数据与统计",
|
||||
"detailData":"明细数据",
|
||||
"fillInFormPerson":"填表人",
|
||||
"fillInFormPersonplaceholder":"请输入填表人",
|
||||
"fillInFormDate":"填表时间",
|
||||
"fillInFormPersonInfo":"填表人信息",
|
||||
"fillInFormPersonStatics":"填表人统计",
|
||||
"fillInFormTotal":"总计(表单填写数)",
|
||||
"fieldStatistics":"字段统计",
|
||||
"viewInformation":"查看信息",
|
||||
|
||||
"deleteTips":"确定删除该条数据吗"
|
||||
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
"cashOutMoney": "转账金额",
|
||||
"auditTime": "审核时间",
|
||||
"transferTime": "转账时间",
|
||||
"memberInfoPlaceholder": "请输入会员名称/会员昵称/手机号",
|
||||
"memberInfoPlaceholder": "请输入会员编号/昵称/手机号搜索",
|
||||
"cashOutNumber": "提现单号",
|
||||
"cashOutNumberPlaceholder": "请输入提现单号",
|
||||
"alipayAccount": "支付宝账号",
|
||||
@ -60,5 +60,7 @@
|
||||
"transferRemark":"转账补充说明",
|
||||
"transferRemarkPlaceholder":"请输入转账补充说明",
|
||||
"notes":"备注",
|
||||
"check":"检查打款进度"
|
||||
"check":"检查打款进度",
|
||||
"cancelWithdrawal":"取消",
|
||||
"cancelTips":"确定要取消提现吗?"
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"memberId":"会员编号",
|
||||
"memberInfoPlaceholder":"请输入会员信息",
|
||||
"memberInfoPlaceholder":"请输入会员编码/昵称/手机号搜索",
|
||||
"memberInfo":"会员信息",
|
||||
"mobile":"手机号码",
|
||||
"nickName":"会员昵称",
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"isMobile": "手机验证码登录",
|
||||
"isMobileTip": "开启之后可以使用手机+验证码进行注册和登录或者快捷登录/注册",
|
||||
"isBindMobile": "强制绑定手机",
|
||||
"isBindMobileTip": "开启之后,会员注册时会强制绑定手机号,并且在相关页面也会引导会员强制绑定手机账号,否则将影响功能正常使用,方便会员在不同端口统一账号,也方便商家进行管理",
|
||||
"isBindMobileTip": "开启之后,会员注册时会强制绑定手机号,并且在相关页面也会引导会员强制绑定手机账号,否则将影响功能正常使用,方便会员在不同端口统一账号,也方便商家进行管理,已注册会员不受影响",
|
||||
"agreement": "政策协议",
|
||||
"agreementTips": "注册时服务协议和隐私协议是否进行展示",
|
||||
"tripartiteSetting": "第三方设置",
|
||||
@ -20,4 +20,4 @@
|
||||
"bgUrlPlaceholder": "建议图片尺寸:750*669像素;图片格式:jpg、png、jpeg",
|
||||
"desc": "描述",
|
||||
"descPlaceholder": "请输入描述"
|
||||
}
|
||||
}
|
||||
|
||||
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": "确定要清除缓存吗?"
|
||||
}
|
||||
|
||||
@ -62,10 +62,8 @@ const getAppList = async () => {
|
||||
// loading.value = false
|
||||
|
||||
const res = await getShowApp();
|
||||
console.log('app',res)
|
||||
appList.value = res.data
|
||||
loading.value = false
|
||||
console.log('appList.value',appList.value,appList.value.length)
|
||||
}
|
||||
getAppList()
|
||||
|
||||
|
||||
@ -17,6 +17,9 @@
|
||||
<el-button type="primary" @click="insert" :loading="uploading" :disabled="loading">{{ t('cloudRelease') }}</el-button>
|
||||
<el-button @click="localInsert" :disabled="loading">{{ t('localRelease') }}</el-button>
|
||||
</div>
|
||||
<div class="mt-[20px]" v-else>
|
||||
<el-button type="primary" @click="againUpload" :loading="uploading" :disabled="loading">{{ t('uploadWeapp') }}</el-button>
|
||||
</div>
|
||||
|
||||
<el-table class="mt-[15px]" :data="weappTableData.data" v-loading="weappTableData.loading" size="default">
|
||||
<template #empty>
|
||||
|
||||
164
admin/src/app/views/channel/weapp/components/modify-domain.vue
Normal file
164
admin/src/app/views/channel/weapp/components/modify-domain.vue
Normal file
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="t('functionSetting')" width="700px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="180px" ref="formRef" :rules="formRules" class="page-form pr-[100px]" v-loading="loading">
|
||||
<el-form-item :label="t('requestUrl')" prop="requestdomain">
|
||||
<el-input v-model="formData.requestdomain" :placeholder="t('requestdomainPlaceholder')" type="textarea">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('socketUrl')" prop="wsrequestdomain">
|
||||
<el-input v-model="formData.wsrequestdomain" :placeholder="t('wsrequestdomainPlaceholder')" type="textarea">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('uploadUrl')" prop="uploaddomain">
|
||||
<el-input v-model="formData.uploaddomain" :placeholder="t('uploaddomainPlaceholder')" type="textarea">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('downloadUrl')" prop="downloaddomain">
|
||||
<el-input v-model="formData.downloaddomain" :placeholder="t('downloaddomainPlaceholder')" type="textarea">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('udpUrl')" prop="udpdomain">
|
||||
<el-input v-model="formData.udpdomain" :placeholder="t('udpdomainPlaceholder')" type="textarea">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('tcpUrl')" prop="tcpdomain">
|
||||
<el-input v-model="formData.tcpdomain" :placeholder="t('tcpdomainPlaceholder')" type="textarea">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{t('confirm')}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed, reactive, ref} from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { setWeappDomain } from '@/app/api/weapp'
|
||||
import Test from '@/utils/test'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
requestdomain: '',
|
||||
wsrequestdomain: '',
|
||||
uploaddomain: '',
|
||||
downloaddomain: '',
|
||||
tcpdomain: '',
|
||||
udpdomain: ''
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const emit = defineEmits(['complete'])
|
||||
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
requestdomain: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => validatorProtocol(rule, value, callback, 'https://'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
uploaddomain: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => validatorProtocol(rule, value, callback, 'https://'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
downloaddomain: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => validatorProtocol(rule, value, callback, 'https://'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
wsrequestdomain: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => validatorProtocol(rule, value, callback, 'wss://'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
tcpdomain: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => validatorProtocol(rule, value, callback, 'tcp://'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
udpdomain: [
|
||||
{
|
||||
validator: (rule: any, value: any, callback: any) => validatorProtocol(rule, value, callback, 'udp://'),
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const validatorProtocol = (rule: any, value: any, callback: any, protocol: string) => {
|
||||
if (!Test.empty(value)) {
|
||||
let flag = true
|
||||
value.split(';').forEach((item: string) => {
|
||||
if (!item.startsWith(protocol)) {
|
||||
flag = false
|
||||
callback(new Error(t('domainError')))
|
||||
}
|
||||
})
|
||||
if (flag) callback()
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认
|
||||
* @param formEl
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
const data = formData
|
||||
|
||||
setWeappDomain(data).then(res => {
|
||||
loading.value = false
|
||||
showDialog.value = false
|
||||
emit('complete', data)
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const setFormData = async (data: any = null) => {
|
||||
loading.value = false
|
||||
Object.assign(formData, initialFormData)
|
||||
if (data) {
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog,
|
||||
setFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -0,0 +1,223 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="t('privacyAgreementTitle')" width="900px" :destroy-on-close="true">
|
||||
<div class="h-[60vh]">
|
||||
<el-scrollbar>
|
||||
<el-form :model="formData" label-width="auto" label-position="left" ref="formRef" :rules="formRules"
|
||||
class="page-form w-[700px] mx-auto" v-loading="loading">
|
||||
<h3 class="text-center text-xl font-bold my-[20px]">{{ config.weapp_name }} 小程序隐私保护指引</h3>
|
||||
<h4 class="text-lg my-[10px]">1. 开发者处理的信息</h4>
|
||||
<div class="mb-[8px]">根据法律规定,开发者仅处理实现小程序功能所必要的信息。</div>
|
||||
<div class="setting-list">
|
||||
<setting-list v-model="formData.setting_list" ref="settingListRef"/>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" link @click="settingListRef.addSettingList()">{{ t('addSettingType') }}</el-button>
|
||||
</div>
|
||||
<h4 class="text-lg my-[10px]">2. 第三方插件信息/SDK信息</h4>
|
||||
<div class="mb-[8px]">
|
||||
为实现特定功能,开发者可能会接入由第三方提供的插件/SDK。第三方插件/SDK的个人信息处理规则,请以其公示的官方说明为准。{{ config.weapp_name }}小程序接入的第三方插件信息/SDK信息如下:
|
||||
</div>
|
||||
<div>
|
||||
<div v-for="(item, index) in formData.sdk_privacy_info_list" class="mb-[15px]">
|
||||
<el-form-item label="SDK名称" class="!mb-[8px]">
|
||||
<el-input v-model="formData.sdk_privacy_info_list[index].sdk_name" class="input-width" placeholder="请输入SDK名称" />
|
||||
<el-button type="primary" class="ml-[10px]" link @click="delSdk(index)">{{ t('delete') }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="SDK提供方名称" class="!mb-[8px]">
|
||||
<el-input v-model="formData.sdk_privacy_info_list[index].sdk_biz_name" class="input-width" placeholder="请输入SDK提供方名称" />
|
||||
</el-form-item>
|
||||
<setting-list v-model="formData.sdk_privacy_info_list[index].sdk_list" ref="sdkSettingListRef"/>
|
||||
<el-form-item label="" class="!mb-[8px]">
|
||||
<el-button type="primary" link @click="sdkSettingListRef[index].addSettingList()">{{ t('addSdkSettingList') }}</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" link @click="addSdk">{{ t('addSdkInfo') }}</el-button>
|
||||
</div>
|
||||
<h4 class="text-lg my-[10px]">3. 你的权益</h4>
|
||||
<div class="mb-[8px]">3.1
|
||||
关于收集你的位置信息,你可以通过以下路径:小程序主页右上角“…”—“设置”—点击特定信息—点击“不允许”,撤回对开发者的授权。</div>
|
||||
<div class="mb-[8px]">3.2 关于收集你的微信昵称、头像、收集你的手机号,你可以通过以下路径:小程序主页右上角“...” — “设置” —
|
||||
“小程序已获取的信息” — 点击特定信息 —
|
||||
点击“通知开发者删除”,开发者承诺收到通知后将删除信息。法律法规另有规定的,开发者承诺将停止除存储和采取必要的安全保护措施之外的处理。</div>
|
||||
<div class="mb-[8px]">3.3 关于你的个人信息,你可以通过以下方式与开发者联系,行使查阅、复制、更正、删除等法定权利。</div>
|
||||
<div class="mb-[8px]">3.4
|
||||
若你在小程序中注册了账号,你可以通过以下方式与开发者联系,申请注销你在小程序中使用的账号。在受理你的申请后,开发者承诺在十五个工作日内完成核查和处理,并按照法律法规要求处理你的相关信息。</div>
|
||||
<div>
|
||||
<el-form-item label="电话" class="!mb-[8px]">
|
||||
<el-input v-model="formData.owner_setting.contact_phone" class="input-width" placeholder="请输入开发者的手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" class="!mb-[8px]">
|
||||
<el-input v-model="formData.owner_setting.contact_email" class="input-width" placeholder="请输入开发者的邮箱" />
|
||||
</el-form-item>
|
||||
<el-form-item label="微信号" class="!mb-[8px]">
|
||||
<el-input v-model="formData.owner_setting.contact_weixin" class="input-width" placeholder="请输入开发者的微信号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="qq号" class="!mb-[8px]">
|
||||
<el-input v-model="formData.owner_setting.contact_qq" class="input-width" placeholder="请输入开发者的qq号" />
|
||||
</el-form-item>
|
||||
<div class="form-tip">信息收集方(开发者)的联系方式,4种联系方式至少要填一种</div>
|
||||
</div>
|
||||
<h4 class="text-lg my-[10px]">4. 开发者对信息的存储</h4>
|
||||
<div>
|
||||
<el-radio-group v-model="formData.store_expire_type">
|
||||
<div>
|
||||
<el-radio :label="1">
|
||||
固定存储期限
|
||||
<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="formData.store_expire_timestamp"/></div>
|
||||
</el-radio>
|
||||
</div>
|
||||
<div>
|
||||
<el-radio :label="0">开发者承诺,除法律法规另有规定外,开发者对你的信息的保存期限应当为实现处理目的所必要的最短时间。</el-radio>
|
||||
</div>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<h4 class="text-lg my-[10px]">5. 信息的使用规则</h4>
|
||||
<div class="mb-[8px]">5.1 开发者将会在本指引所明示的用途内使用收集的信息</div>
|
||||
<div class="mb-[8px]">
|
||||
5.2 如开发者使用你的信息超出本指引目的或合理范围,开发者必须在变更使用目的或范围前,再次以
|
||||
<div class="!w-[180px] inline-block">
|
||||
<el-input v-model="formData.owner_setting.notice_method"/>
|
||||
</div>
|
||||
方式告知并征得你的明示同意。</div>
|
||||
<h4 class="text-lg my-[10px]">6. 信息对外提供</h4>
|
||||
<div class="mb-[8px]">6.1
|
||||
开发者承诺,不会主动共享或转让你的信息至任何第三方,如存在确需共享或转让时,开发者应当直接征得或确认第三方征得你的单独同意。</div>
|
||||
<div class="mb-[8px]">6.2
|
||||
开发者承诺,不会对外公开披露你的信息,如必须公开披露时,开发者应当向你告知公开披露的目的、披露信息的类型及可能涉及的信息,并征得你的单独同意。</div>
|
||||
<h4 class="text-lg my-[10px]">7.
|
||||
你认为开发者未遵守上述约定,或有其他的投诉建议、或未成年人个人信息保护相关问题,可通过以下方式与开发者联系;或者向微信进行投诉。</h4>
|
||||
<!-- <h4 class="text-lg my-[10px]">8. 补充文档</h4>-->
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import Test from '@/utils/test'
|
||||
import SettingList from './setting-list.vue'
|
||||
import { getWeappPrivacySetting, setWeappPrivacySetting } from '@/app/api/weapp'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
const settingListRef = ref(null)
|
||||
const sdkSettingListRef = ref(null)
|
||||
|
||||
const props = defineProps({
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
setting_list: [
|
||||
{
|
||||
privacy_key: 'UserInfo',
|
||||
privacy_text: ''
|
||||
},
|
||||
{
|
||||
privacy_key: 'Location',
|
||||
privacy_text: ''
|
||||
},
|
||||
{
|
||||
privacy_key: 'PhoneNumber',
|
||||
privacy_text: ''
|
||||
}
|
||||
],
|
||||
owner_setting: {
|
||||
notice_method: ''
|
||||
},
|
||||
sdk_privacy_info_list: [],
|
||||
store_expire_type: 0,
|
||||
store_expire_timestamp: ''
|
||||
}
|
||||
|
||||
const formData: Record<string, any> = reactive({...initialFormData})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const emit = defineEmits(['complete'])
|
||||
|
||||
const formRules = computed(() => {
|
||||
return {}
|
||||
})
|
||||
|
||||
const addSdk = () => {
|
||||
formData.sdk_privacy_info_list.push({
|
||||
sdk_name: '',
|
||||
sdk_biz_name: '',
|
||||
sdk_list: []
|
||||
})
|
||||
}
|
||||
|
||||
const delSdk = (index: number) => {
|
||||
formData.sdk_privacy_info_list.splice(index, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认
|
||||
* @param formEl
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
const data = formData
|
||||
|
||||
if (!data.store_expire_type) data.owner_setting.store_expire_timestamp = data.store_expire_timestamp
|
||||
|
||||
setWeappPrivacySetting(data).then(res => {
|
||||
loading.value = false
|
||||
showDialog.value = false
|
||||
emit('complete', data)
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const setFormData = async () => {
|
||||
getWeappPrivacySetting().then(({ data }) => {
|
||||
loading.value = false
|
||||
Object.assign(formData, initialFormData)
|
||||
if (data) {
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
if (data.owner_setting.store_expire_timestamp) {
|
||||
formData.store_expire_type = 1
|
||||
formData.store_expire_timestamp = data.owner_setting.store_expire_timestamp
|
||||
}
|
||||
}
|
||||
showDialog.value = true
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog,
|
||||
setFormData
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
221
admin/src/app/views/channel/weapp/components/setting-list.vue
Normal file
221
admin/src/app/views/channel/weapp/components/setting-list.vue
Normal file
@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<div v-for="(item, index) in value">
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'UserInfo'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,收集你的微信昵称、头像。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Location'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,收集你的位置信息。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'PhoneNumber'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,收集你的手机号。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Address'">
|
||||
开发者收集你的地址,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Record'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,访问你的麦克风。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Contact'">
|
||||
开发者使用你的通讯录(仅写入)权限,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'EXOrderInfo'">
|
||||
开发者收集你的订单信息,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'EXUserOpLog'">
|
||||
开发者收集你的操作日志,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'BlueTooth'">
|
||||
开发者访问你的蓝牙,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'MessageFile'">
|
||||
开发者收集你选中的文件,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Compass'">
|
||||
开发者调用你的磁场传感器,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Clipboard'">
|
||||
开发者读取你的剪切板,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'DeviceMotion'">
|
||||
开发者调用你的方向传感器,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'ChooseLocation'">
|
||||
开发者获取你选择的位置信息,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'CalendarWriteOnly'">
|
||||
开发者使用你的日历(仅写入)权限,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'AlbumWriteOnly'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div> ,开发者将在获取你的明示同意后,使用你的相册(仅写入)权限。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'EXUserPublishContent'">
|
||||
开发者收集你的发布内容,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'DeviceInfo'">
|
||||
开发者收集你的设备信息,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Album'">
|
||||
开发者收集你选中的照片或视频信息,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Invoice'">
|
||||
开发者收集你的发票信息,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'RunData'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,收集你的微信运动步数。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Camera'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,访问你的摄像头。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'EXUserFollowAcct'">
|
||||
开发者收集你的所关注账号,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'EXIDNumber'">
|
||||
开发者收集你的身份证号码,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'LicensePlate'">
|
||||
为了<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>,开发者将在获取你的明示同意后,收集你的车牌号。
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Email'">
|
||||
开发者收集你的邮箱,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Accelerometer'">
|
||||
开发者调用你的加速传感器,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
<div class="flex items-center mb-[8px]" v-if="item.privacy_key == 'Gyroscope'">
|
||||
开发者调用你的陀螺仪传感器,用于<div class="!w-[200px] inline-block mx-[5px]"><el-input v-model="value[index].privacy_text" :placeholder="t('settingPlaceholder')"/></div>
|
||||
<icon name="element Remove" @click="removeSettingList(index)" color="red" class="cursor-pointer"></icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="settingTypeDialog" :title="t('settingTypeTitle')" width="500px" :destroy-on-close="true">
|
||||
<el-checkbox-group v-model="checkList">
|
||||
<template v-for="(item, index) in privacyList">
|
||||
<el-checkbox :label="item.privacy_key" v-if="!checkIsSelected(item.privacy_key)">{{ item.privacy_text }}</el-checkbox>
|
||||
</template>
|
||||
</el-checkbox-group>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="settingTypeDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="selectSettingType()">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const settingTypeDialog = ref(false)
|
||||
|
||||
const privacyList = ref([
|
||||
{ privacy_key: 'UserInfo', privacy_text: '用户信息(微信昵称、头像)' },
|
||||
{ privacy_key: 'Location', privacy_text: '位置信息' },
|
||||
{ privacy_key: 'Address', privacy_text: '地址' },
|
||||
{ privacy_key: 'Invoice', privacy_text: '发票信息' },
|
||||
{ privacy_key: 'RunData', privacy_text: '微信运动数据' },
|
||||
{ privacy_key: 'Record', privacy_text: '麦克风' },
|
||||
{ privacy_key: 'Album', privacy_text: '选中的照片或视频信息' },
|
||||
{ privacy_key: 'Camera', privacy_text: '摄像头' },
|
||||
{ privacy_key: 'PhoneNumber', privacy_text: '手机号码' },
|
||||
{ privacy_key: 'Contact', privacy_text: '通讯录(仅写入)权限' },
|
||||
{ privacy_key: 'DeviceInfo', privacy_text: '设备信息' },
|
||||
{ privacy_key: 'EXIDNumber', privacy_text: '身份证号码' },
|
||||
{ privacy_key: 'EXOrderInfo', privacy_text: '订单信息' },
|
||||
{ privacy_key: 'EXUserPublishContent', privacy_text: '发布内容' },
|
||||
{ privacy_key: 'EXUserFollowAcct', privacy_text: '所关注账号' },
|
||||
{ privacy_key: 'EXUserOpLog', privacy_text: '操作日志' },
|
||||
{ privacy_key: 'AlbumWriteOnly', privacy_text: '相册(仅写入)权限' },
|
||||
{ privacy_key: 'LicensePlate', privacy_text: '车牌号' },
|
||||
{ privacy_key: 'BlueTooth', privacy_text: '蓝牙' },
|
||||
{ privacy_key: 'CalendarWriteOnly', privacy_text: '日历(仅写入)权限' },
|
||||
{ privacy_key: 'Email', privacy_text: '邮箱' },
|
||||
{ privacy_key: 'MessageFile', privacy_text: '选中的文件' },
|
||||
{ privacy_key: 'ChooseLocation', privacy_text: '选择的位置信息' },
|
||||
{ privacy_key: 'Accelerometer', privacy_text: '加速传感器' },
|
||||
{ privacy_key: 'Compass', privacy_text: '磁场传感器' },
|
||||
{ privacy_key: 'DeviceMotion', privacy_text: '方向传感器' },
|
||||
{ privacy_key: 'Gyroscope', privacy_text: '陀螺仪传感器' },
|
||||
{ privacy_key: 'Clipboard', privacy_text: '剪切板' }
|
||||
])
|
||||
|
||||
const emits = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const value = computed({
|
||||
get () {
|
||||
return props.modelValue
|
||||
},
|
||||
set (value) {
|
||||
emits('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
|
||||
const removeSettingList = (index: number) => {
|
||||
value.value.splice(index, 1)
|
||||
}
|
||||
|
||||
const checkList = ref([])
|
||||
const selectSettingType = () => {
|
||||
checkList.value.forEach((item: string) => {
|
||||
value.value.push({
|
||||
privacy_key: item,
|
||||
privacy_text: ''
|
||||
})
|
||||
})
|
||||
settingTypeDialog.value = false
|
||||
checkList.value = []
|
||||
}
|
||||
|
||||
const addSettingList = () => {
|
||||
settingTypeDialog.value = true
|
||||
}
|
||||
|
||||
const selectedSettingType = computed(() => {
|
||||
return value.value.map((item: any) => item.privacy_key)
|
||||
})
|
||||
const checkIsSelected = (key: string) => {
|
||||
return selectedSettingType.value.includes(key)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
addSettingList
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -84,37 +84,78 @@
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card !border-none mt-[15px]" shadow="never">
|
||||
<div class="flex">
|
||||
<div class="flex items-start justify-between">
|
||||
<h3 class="panel-title !text-sm">{{ t('functionSetting') }}</h3>
|
||||
<el-button type="primary" link @click="modifyDomainFn" v-if="formData.is_authorization">{{ t('update') }}</el-button>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="t('requestUrl')">
|
||||
<el-input :model-value="formData.request_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('socketUrl')">
|
||||
<el-input :model-value="formData.socket_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.socket_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('uploadUrl')">
|
||||
<el-input :model-value="formData.upload_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.upload_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('downloadUrl')">
|
||||
<el-input :model-value="formData.download_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.download_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<div v-if="!formData.is_authorization">
|
||||
<el-form-item :label="t('requestUrl')">
|
||||
<el-input :model-value="formData.request_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('socketUrl')">
|
||||
<el-input :model-value="formData.socket_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.socket_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('uploadUrl')">
|
||||
<el-input :model-value="formData.upload_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.upload_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('downloadUrl')">
|
||||
<el-input :model-value="formData.download_url" placeholder="Please input" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.download_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-form-item :label="t('requestUrl')">
|
||||
<div v-if="formData.domain.requestdomain">{{ formData.domain.requestdomain }}</div>
|
||||
<div v-else>-</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('socketUrl')">
|
||||
<div v-if="formData.domain.wsrequestdomain">{{ formData.domain.wsrequestdomain }}</div>
|
||||
<div v-else>-</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('uploadUrl')">
|
||||
<div v-if="formData.domain.uploaddomain">{{ formData.domain.uploaddomain }}</div>
|
||||
<div v-else>-</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('downloadUrl')">
|
||||
<div v-if="formData.domain.downloaddomain">{{ formData.domain.downloaddomain }}</div>
|
||||
<div v-else>-</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('udpUrl')">
|
||||
<div v-if="formData.domain.udpdomain">{{ formData.domain.udpdomain }}</div>
|
||||
<div v-else>-</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('tcpUrl')">
|
||||
<div v-if="formData.domain.tcpdomain">{{ formData.domain.tcpdomain }}</div>
|
||||
<div v-else>-</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card !border-none mt-[15px]" shadow="never" v-if="formData.is_authorization">
|
||||
<div class="flex items-start justify-between">
|
||||
<h3 class="panel-title !text-sm">{{ t('serviceContentStatement') }}</h3>
|
||||
</div>
|
||||
<el-form-item :label="t('privacyAgreement')">
|
||||
<div class="flex items-center">
|
||||
<div class="form-tip !mt-0">{{ t('privacyAgreementTips') }}</div>
|
||||
<el-button type="primary" link @click="modifyPrivacyAgreementFn">{{ t('setting') }}</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form>
|
||||
@ -125,6 +166,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<modify-domain ref="modifyDomainRef" @complete="modifyDomainComplete"/>
|
||||
<modify-privacy-agreement :config="formData" ref="modifyPrivacyAgreementRef"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -135,6 +179,8 @@ import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage, FormInstance } from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import ModifyDomain from '@/app/views/channel/weapp/components/modify-domain.vue'
|
||||
import ModifyPrivacyAgreement from '@/app/views/channel/weapp/components/modify-privacy-agreement.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -159,7 +205,15 @@ const formData = reactive<Record<string, any>>({
|
||||
upload_url: '',
|
||||
download_url: '',
|
||||
upload_private_key: '',
|
||||
is_authorization: 0
|
||||
is_authorization: 0,
|
||||
domain: {
|
||||
requestdomain: '',
|
||||
wsrequestdomain: '',
|
||||
uploaddomain: '',
|
||||
downloaddomain: '',
|
||||
tcpdomain: '',
|
||||
udpdomain: ''
|
||||
}
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
@ -242,6 +296,20 @@ const save = async (formEl: FormInstance | undefined) => {
|
||||
})
|
||||
}
|
||||
|
||||
const modifyDomainRef = ref(null)
|
||||
const modifyDomainFn = () => {
|
||||
modifyDomainRef.value.setFormData(formData.domain)
|
||||
modifyDomainRef.value.showDialog = true
|
||||
}
|
||||
|
||||
const modifyDomainComplete = (data) => {
|
||||
formData.domain = data
|
||||
}
|
||||
|
||||
const modifyPrivacyAgreementRef = ref(null)
|
||||
const modifyPrivacyAgreementFn = () => {
|
||||
modifyPrivacyAgreementRef.value.setFormData()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
||||
@ -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,9 +28,9 @@
|
||||
</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">
|
||||
@ -43,6 +43,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">
|
||||
@ -91,7 +94,7 @@ import { t } from '@/lang'
|
||||
import Sortable from 'sortablejs'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { img } from '@/utils/common'
|
||||
import { range } from 'lodash-es'
|
||||
import { min, range } from 'lodash-es'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
diyStore.editComponent.ignore = ['pageBgColor','marginTop','marginBottom','marginBoth','componentBgUrl'] // 忽略公共属性
|
||||
|
||||
@ -1,23 +1,28 @@
|
||||
<template>
|
||||
<el-dialog v-model="dialogThemeVisible" title="编辑色调" width="850px" align-center>
|
||||
<el-form :model="openData" label-width="150px" :rules="formRules" class="h-[640px] overflow-auto" ref="formRef" @submit.prevent>
|
||||
<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.id != ''" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-form-item label="色调名称" prop="title" >
|
||||
<el-input v-model="openData.title" placeholder="请输入色调名称" maxlength="15" class="!w-[250px]" :disabled="openData.mark != 'diy'" />
|
||||
<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" @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 formData" :key="index">
|
||||
<el-color-picker v-model="item.value" show-alpha :predefine="diyStore.predefineColors"/>
|
||||
<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>
|
||||
<span class="text-primary cursor-pointer text-[14px] ml-[8px]" @click="deleteThemeFn(item)">删除</span>
|
||||
<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>
|
||||
<span class="text-primary cursor-pointer text-[14px] ml-[8px]"
|
||||
@click="deleteThemeFn(item)">删除</span>
|
||||
</div>
|
||||
<div class="form-tip">{{item.tip}}</div>
|
||||
<div class="form-tip">{{ item.tip }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
@ -28,7 +33,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>
|
||||
@ -42,23 +47,26 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { filterNumber } from '@/utils/common'
|
||||
import { deepClone, 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 { deleteTheme, 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'])
|
||||
|
||||
@ -68,191 +76,194 @@ const formRef = ref<FormInstance>()
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
title: [
|
||||
{ required: true, message: "请输入色调名称", trigger: 'blur' }
|
||||
{ required: true, message: '请输入色调名称', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
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: '#eeeeee',
|
||||
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]) : '';
|
||||
});
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
formData.value.forEach((item, index) => {
|
||||
item.value = res.theme[item.label] ? res.theme[item.label] : item.value
|
||||
})
|
||||
dialogThemeVisible.value = true
|
||||
}
|
||||
|
||||
// 新增颜色
|
||||
const addThemeFn = ()=>{
|
||||
let keyArr = []
|
||||
formData.value.forEach((item,index) => {
|
||||
keyArr.push(item.label);
|
||||
});
|
||||
let obj = {
|
||||
const addThemeFn = () => {
|
||||
// 传入keyArr, 避免添加重复key
|
||||
const keyArr: string[] = []
|
||||
formData.value.forEach((item, index) => {
|
||||
keyArr.push(item.label)
|
||||
})
|
||||
const obj = {
|
||||
key: keyArr
|
||||
}
|
||||
addThemeRef.value.open(obj);
|
||||
|
||||
addThemeRef.value.open(obj)
|
||||
}
|
||||
|
||||
// 编辑颜色
|
||||
const editThemeFn = (res:any)=>{
|
||||
let keyArr = []
|
||||
formData.value.forEach((item,index) => {
|
||||
keyArr.push(item.label);
|
||||
});
|
||||
let obj = {
|
||||
const editThemeFn = (res: any) => {
|
||||
// 传入keyArr, 避免添加重复key
|
||||
const keyArr: string[] = []
|
||||
formData.value.forEach((item, index) => {
|
||||
keyArr.push(item.label)
|
||||
})
|
||||
|
||||
const obj = {
|
||||
key: keyArr,
|
||||
data: res
|
||||
}
|
||||
addThemeRef.value.open(obj);
|
||||
addThemeRef.value.open(obj)
|
||||
}
|
||||
// 删除颜色
|
||||
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){
|
||||
indent = i;
|
||||
// 删除颜色
|
||||
const deleteThemeFn = (res: any) => {
|
||||
let indent = -1
|
||||
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);
|
||||
if (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;
|
||||
return;
|
||||
const addThemeConfirm = (res: any) => {
|
||||
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){
|
||||
formData.value.forEach((item,index)=>{
|
||||
item.value = cloneDeep(openData.default[item.label]);
|
||||
const resetConfirmFn = () => {
|
||||
if (openData.default_theme && Object.keys(openData.default_theme).length) {
|
||||
formData.value.forEach((item, index) => {
|
||||
item.value = openData.default_theme[item.label]
|
||||
})
|
||||
}else{
|
||||
formData.value = cloneDeep(initialFormData);
|
||||
} else {
|
||||
formData.value = cloneDeep(openData.theme_field)
|
||||
// 新增时,点击充值按钮,清空title
|
||||
if (!openData.id) {
|
||||
openData.title = ''
|
||||
}
|
||||
}
|
||||
|
||||
openData.diy_value = [];
|
||||
|
||||
if(openData.mark == 'diy'){
|
||||
openData.title = '';
|
||||
}
|
||||
openData.new_theme = []
|
||||
|
||||
ElMessage({
|
||||
message: '重置成功',
|
||||
type: 'success',
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
let confirmRepeat = false
|
||||
const confirmFn = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
let params = {
|
||||
const params = {
|
||||
title: '',
|
||||
id: '',
|
||||
theme: {},
|
||||
diy_value: [],
|
||||
title: ''
|
||||
default_theme: {},
|
||||
new_theme: [],
|
||||
addon: ''
|
||||
}
|
||||
params.title = openData.title;
|
||||
|
||||
formData.value.forEach((item,index) => {
|
||||
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 || [];
|
||||
|
||||
emit('confirm', params);
|
||||
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
|
||||
|
||||
dialogThemeVisible.value = false;
|
||||
// 新增时,默认主题为当前主题
|
||||
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,41 @@
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<edit-theme ref="editThemeRef" @confirm="editThemeConfirm"/>
|
||||
</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>
|
||||
<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>
|
||||
@ -30,137 +45,142 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } 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);
|
||||
})
|
||||
}
|
||||
initData()
|
||||
const dialogTitle = computed(() => {
|
||||
const name = `选择${currTheme.addon_title}配色`
|
||||
return name
|
||||
})
|
||||
|
||||
// 切换不同配色
|
||||
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: {}, // 当前色调
|
||||
title:'',
|
||||
mark: '', // 标识,区分是自定义还是模版色调,
|
||||
diy_value: [] // 新增颜色值
|
||||
const editThemeFn = (type = 'add', item = {}) => {
|
||||
const theme = {
|
||||
default_theme: {}, // 当前色调的默认值
|
||||
theme: {}, // 当前色调
|
||||
title: '',
|
||||
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;
|
||||
}).catch(()=>{
|
||||
confirmRepeat = false;
|
||||
confirmRepeat = false
|
||||
dialogThemeVisible.value = false
|
||||
emit('confirm')
|
||||
}).catch(() => {
|
||||
confirmRepeat = false
|
||||
})
|
||||
}
|
||||
|
||||
// 点击取消
|
||||
const cancelFn = () => {
|
||||
dialogThemeVisible.value = false
|
||||
emit('confirm')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
@ -170,5 +190,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>
|
||||
|
||||
@ -237,8 +237,6 @@ route.query.type = route.query.type || '' // 页面模板,新页面传入
|
||||
route.query.title = route.query.title || ''
|
||||
route.query.back = route.query.back || '/site/diy/list'
|
||||
|
||||
console.log('route',route.path)
|
||||
|
||||
const backPath = route.query.back
|
||||
const template = ref('');
|
||||
const oldTemplate = ref('');
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
@ -85,11 +85,17 @@ const initData = () => {
|
||||
}
|
||||
initData()
|
||||
|
||||
|
||||
// 编辑
|
||||
const editEvent = (data)=>{
|
||||
themeListRef.value.open(data);
|
||||
const editEvent = (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>
|
||||
|
||||
@ -5,31 +5,31 @@
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<slot name="field"></slot>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('样式')">
|
||||
<el-form-item :label="t('style')">
|
||||
<el-radio-group v-model="diyStore.editComponent.style">
|
||||
<el-radio label="style-1">{{ t('默认') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('列表') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('下拉') }}</el-radio>
|
||||
<el-radio label="style-1">{{ t('defaultSources') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('listStyle') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('dropDownStyle') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('选项')">
|
||||
<el-form-item :label="t('option')">
|
||||
<div ref="formCheckboxRef">
|
||||
<div v-for="(option, index) in diyStore.editComponent.options" :key="option.id" class="option-item flex items-center mb-[15px]">
|
||||
<el-input v-model="diyStore.editComponent.options[index].text" class="!w-[215px]" :placeholder="t('optionPlaceholder')" maxlength="30" clearable />
|
||||
<span v-if="diyStore.editComponent.options.length > 1" @click="removeOption(index)" class="cursor-pointer ml-[5px] nc-iconfont nc-icon-shanchu-yuangaizhiV6xx"></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">添加单个选项</span>
|
||||
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">{{ t('addSingleOption') }}</span>
|
||||
<el-popover :visible="visible" placement="bottom" :width="300">
|
||||
<p class="mb-[5px]">批量添加选项</p>
|
||||
<p class="text-[#888] text-[12px] mb-[5px]">每个选项之间用英文 "," 隔开,自动过滤重复内容</p>
|
||||
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
|
||||
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
|
||||
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200" show-word-limit />
|
||||
<div class="mt-[10px] text-right">
|
||||
<el-button size="small" text @click="visible = false">取消</el-button>
|
||||
<el-button size="small" type="primary" @click="batchAddOptions">确定</el-button>
|
||||
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
|
||||
<el-button size="small" type="primary" @click="batchAddOptions">{{ t('confirm') }}</el-button>
|
||||
</div>
|
||||
<template #reference>
|
||||
<span class="text-primary cursor-pointer" @click="visible = true">批量添加选项</span>
|
||||
<span class="text-primary cursor-pointer" @click="visible = true">{{ t('addMultipleOption') }}</span>
|
||||
</template>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
@ -102,7 +102,7 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
let uniqueOptions = uniqueByKey(diyStore.value[index].options, 'text')
|
||||
if (uniqueOptions.length != diyStore.value[index].options.length) {
|
||||
res.code = false;
|
||||
res.message = t('存在重复选项,请检查内容')
|
||||
res.message = t('errorTipsOne')
|
||||
}
|
||||
return res
|
||||
}
|
||||
@ -147,7 +147,7 @@ const batchAddOptions = () => {
|
||||
diyStore.editComponent.options.push(...filteredNewOptions);
|
||||
} else {
|
||||
ElMessage({
|
||||
message: "选项已存在,请重新输入",
|
||||
message: t('errorTipsTwo'),
|
||||
type: "error",
|
||||
});
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<slot name="field"></slot>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('时间格式')">
|
||||
<el-form-item :label="t('dataFormat')">
|
||||
<el-radio-group v-model="diyStore.editComponent.dateFormat">
|
||||
<div class="flex flex-col">
|
||||
<el-radio label="YYYY年M月D日">{{ dateFormat.format1 }}</el-radio>
|
||||
@ -17,43 +17,43 @@
|
||||
</el-form>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('开始日期') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('startDate') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('提示语')">
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.start.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('默认值')">
|
||||
<el-form-item :label="t('defaultValue')">
|
||||
<el-switch v-model="diyStore.editComponent.start.defaultControl" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.start.defaultControl">
|
||||
<el-radio-group v-model="diyStore.editComponent.start.dateWay">
|
||||
<el-radio label="current">{{ t('当天日期') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('指定日期') }}</el-radio>
|
||||
<el-radio label="current">{{ t('currentDate') }}</el-radio>
|
||||
<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-date-picker v-model="diyStore.editComponent.field.default.start.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" placeholder="请选择日期" @change="startDateChange" />
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('结束日期') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('endDate') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('提示语')">
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.end.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('默认值')">
|
||||
<el-form-item :label="t('defaultValue')">
|
||||
<el-switch v-model="diyStore.editComponent.end.defaultControl" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.end.defaultControl">
|
||||
<el-radio-group v-model="diyStore.editComponent.end.dateWay">
|
||||
<el-radio label="current">{{ t('当天日期') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('指定日期') }}</el-radio>
|
||||
<el-radio label="current">{{ t('currentDate') }}</el-radio>
|
||||
<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="请选择结束日期" @change="endDateChange" />
|
||||
<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>
|
||||
@ -67,7 +67,7 @@
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('文字样式') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
|
||||
@ -102,101 +102,101 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
let starTime = diyStore.value[index].field.default.start.date;
|
||||
let endTime = diyStore.value[index].field.default.end.date;
|
||||
let starTime = diyStore.value[index].field.default.start.date
|
||||
let endTime = diyStore.value[index].field.default.end.date
|
||||
|
||||
let today = new Date();
|
||||
const hours = String(today.getHours()).padStart(2, '0');
|
||||
const minutes = String(today.getMinutes()).padStart(2, '0');
|
||||
let today = new Date()
|
||||
const hours = String(today.getHours()).padStart(2, '0')
|
||||
const minutes = String(today.getMinutes()).padStart(2, '0')
|
||||
|
||||
if(diyStore.editComponent.start.dateWay == 'current'){
|
||||
starTime = today.toISOString().split('T')[0];
|
||||
if (diyStore.editComponent.start.dateWay == 'current') {
|
||||
starTime = today.toISOString().split('T')[0]
|
||||
}
|
||||
if(diyStore.editComponent.end.dateWay == 'current'){
|
||||
endTime = today.toISOString().split('T')[0];
|
||||
if (diyStore.editComponent.end.dateWay == 'current') {
|
||||
endTime = today.toISOString().split('T')[0]
|
||||
}
|
||||
|
||||
if(diyStore.editComponent.start.defaultControl && starTime == ''){
|
||||
if (diyStore.editComponent.start.defaultControl && starTime == '' && diyStore.editComponent.end.dateWay == 'diy') {
|
||||
res.code = false
|
||||
res.message = "开始日期不能为空"
|
||||
res.message = t('startDataTips')
|
||||
return res
|
||||
}
|
||||
if(diyStore.editComponent.end.defaultControl && endTime == ''){
|
||||
if (diyStore.editComponent.end.defaultControl && endTime == '' && diyStore.editComponent.end.dateWay == 'diy') {
|
||||
res.code = false
|
||||
res.message = "结束日期不能为空"
|
||||
res.message = t('endDataTips')
|
||||
return res
|
||||
}
|
||||
|
||||
if(diyStore.editComponent.start.defaultControl && diyStore.editComponent.end.defaultControl && timeTurnTimeStamp(starTime) > timeTurnTimeStamp(endTime)){
|
||||
if (diyStore.editComponent.start.defaultControl && diyStore.editComponent.end.defaultControl && timeTurnTimeStamp(starTime) > timeTurnTimeStamp(endTime)) {
|
||||
res.code = false
|
||||
res.message = "开始日期不能大于结束日期"
|
||||
res.message = t('startEndDataTips')
|
||||
return res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
const dateFormat: any = reactive({
|
||||
format1: '',
|
||||
format2: '',
|
||||
format3: ''
|
||||
});
|
||||
format1: '',
|
||||
format2: '',
|
||||
format3: ''
|
||||
})
|
||||
|
||||
// 结束日期-禁止的日期
|
||||
const disabledEndDate = (time:Date)=>{
|
||||
let cutoffDate = null
|
||||
let bool = false;
|
||||
if(diyStore.editComponent.start && diyStore.editComponent.start.defaultControl){
|
||||
if(diyStore.editComponent.start.dateWay == 'diy'){
|
||||
cutoffDate = new Date(diyStore.editComponent.field.default.start.date);
|
||||
}else{
|
||||
cutoffDate = new Date();
|
||||
}
|
||||
bool = time.getTime() < cutoffDate.getTime();
|
||||
}
|
||||
return bool;
|
||||
let cutoffDate = null
|
||||
let bool = false
|
||||
if (diyStore.editComponent.start && diyStore.editComponent.start.defaultControl) {
|
||||
if (diyStore.editComponent.start.dateWay == 'diy') {
|
||||
cutoffDate = new Date(diyStore.editComponent.field.default.start.date)
|
||||
} else {
|
||||
cutoffDate = new Date()
|
||||
}
|
||||
bool = time.getTime() < cutoffDate.getTime()
|
||||
}
|
||||
return bool
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let today = new Date();
|
||||
let endDate = new Date();
|
||||
endDate.setDate(endDate.getDate() + 7); // 设置日期为7天后的日期
|
||||
let today = new Date()
|
||||
let endDate = new Date()
|
||||
endDate.setDate(endDate.getDate() + 7) // 设置日期为7天后的日期
|
||||
|
||||
if(diyStore.editComponent.field.default.start.timestamp){
|
||||
diyStore.editComponent.field.default.start.date = today.toISOString().split('T')[0];
|
||||
diyStore.editComponent.field.default.start.timestamp = parseInt(today.getTime() / 1000);
|
||||
if (diyStore.editComponent.field.default.start.timestamp) {
|
||||
diyStore.editComponent.field.default.start.date = today.toISOString().split('T')[0]
|
||||
diyStore.editComponent.field.default.start.timestamp = parseInt(today.getTime() / 1000)
|
||||
}
|
||||
|
||||
if(diyStore.editComponent.field.default.end.timestamp){
|
||||
diyStore.editComponent.field.default.end.date = endDate.toISOString().split('T')[0];
|
||||
diyStore.editComponent.field.default.end.timestamp = parseInt(endDate.getTime() / 1000);
|
||||
if (diyStore.editComponent.field.default.end.timestamp) {
|
||||
diyStore.editComponent.field.default.end.date = endDate.toISOString().split('T')[0]
|
||||
diyStore.editComponent.field.default.end.timestamp = parseInt(endDate.getTime() / 1000)
|
||||
}
|
||||
|
||||
let year = today.getFullYear();
|
||||
let month = String(today.getMonth() + 1).padStart(2, '0');
|
||||
let day = String(today.getDate()).padStart(2, '0');
|
||||
let year = today.getFullYear()
|
||||
let month = String(today.getMonth() + 1).padStart(2, '0')
|
||||
let day = String(today.getDate()).padStart(2, '0')
|
||||
|
||||
const hours = String(today.getHours()).padStart(2, '0');
|
||||
const minutes = String(today.getMinutes()).padStart(2, '0');
|
||||
dateFormat.format1 = `${year}年${month}月${day}日`;
|
||||
dateFormat.format2 = `${year}-${month}-${day}`;
|
||||
dateFormat.format3 = `${year}/${month}/${day}`;
|
||||
dateFormat.format4 = `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
});
|
||||
const hours = String(today.getHours()).padStart(2, '0')
|
||||
const minutes = String(today.getMinutes()).padStart(2, '0')
|
||||
dateFormat.format1 = `${year}年${month}月${day}日`
|
||||
dateFormat.format2 = `${year}-${month}-${day}`
|
||||
dateFormat.format3 = `${year}/${month}/${day}`
|
||||
dateFormat.format4 = `${year}-${month}-${day} ${hours}:${minutes}`
|
||||
})
|
||||
|
||||
// 开始日期选择器
|
||||
const startDateChange = (date)=>{
|
||||
diyStore.editComponent.field.default.start.date = date;
|
||||
diyStore.editComponent.field.default.start.timestamp = timeTurnTimeStamp(date);
|
||||
const startDateChange = (date) => {
|
||||
diyStore.editComponent.field.default.start.date = date
|
||||
diyStore.editComponent.field.default.start.timestamp = timeTurnTimeStamp(date)
|
||||
|
||||
let endDate = new Date(date)
|
||||
endDate.setDate(endDate.getDate() + 7);
|
||||
diyStore.editComponent.field.default.end.date = endDate.toISOString().split('T')[0];
|
||||
diyStore.editComponent.field.default.end.timestamp = parseInt(endDate.getTime() / 1000);
|
||||
endDate.setDate(endDate.getDate() + 7)
|
||||
diyStore.editComponent.field.default.end.date = endDate.toISOString().split('T')[0]
|
||||
diyStore.editComponent.field.default.end.timestamp = parseInt(endDate.getTime() / 1000)
|
||||
}
|
||||
// 结束日期选择器
|
||||
const endDateChange = (date)=>{
|
||||
diyStore.editComponent.field.default.end.date = date;
|
||||
diyStore.editComponent.field.default.end.timestamp = timeTurnTimeStamp(date);
|
||||
const endDateChange = (date) => {
|
||||
diyStore.editComponent.field.default.end.date = date
|
||||
diyStore.editComponent.field.default.end.timestamp = timeTurnTimeStamp(date)
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<slot name="field"></slot>
|
||||
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('日期格式')">
|
||||
<el-form-item :label="t('dataFormat')">
|
||||
<el-radio-group v-model="diyStore.editComponent.dateFormat" class="!block">
|
||||
<el-radio class="!block" label="YYYY年M月D日">{{ dateFormat.format1 }}</el-radio>
|
||||
<el-radio class="!block" label="YYYY-MM-DD">{{ dateFormat.format2 }}</el-radio>
|
||||
@ -16,18 +16,18 @@
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('默认值')">
|
||||
<el-form-item :label="t('defaultValue')">
|
||||
<el-switch v-model="diyStore.editComponent.defaultControl"/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.defaultControl">
|
||||
<el-radio-group v-model="diyStore.editComponent.dateWay">
|
||||
<el-radio label="current">{{ t('当天日期') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('指定日期') }}</el-radio>
|
||||
<el-radio label="current">{{ t('currentDate') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('diyDate') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.defaultControl && diyStore.editComponent.dateWay == 'diy'">
|
||||
<el-date-picker v-if="diyStore.editComponent.dateFormat != 'YYYY-MM-DD HH:mm'" v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" placeholder="请选择日期" @change="dateChange"/>
|
||||
<el-date-picker v-else v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD HH:mm" value-format="YYYY-MM-DD HH:mm" type="datetime" placeholder="请选择日期" @change="dateChange"/>
|
||||
<el-date-picker v-if="diyStore.editComponent.dateFormat != 'YYYY-MM-DD HH:mm'" v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" :placeholder="t('dataPlaceholder')" @change="dateChange"/>
|
||||
<el-date-picker v-else v-model="diyStore.editComponent.field.default.date" format="YYYY/MM/DD HH:mm" value-format="YYYY-MM-DD HH:mm" type="datetime" :placeholder="t('dataPlaceholder')" @change="dateChange"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('内容防重复') }}</span>
|
||||
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>该组件填写的内容不能与已提交的数据重复。</p>
|
||||
<p>极端情况下可能存在延时导致限制失效。</p>
|
||||
<p>{{ t('preventDuplicationTipsOne') }}</p>
|
||||
<p>{{ t('preventDuplicationTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -33,11 +33,11 @@
|
||||
<el-form-item class="display-block">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
|
||||
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>会自动将提交的个人信息做加密展示。</p>
|
||||
<p>适用于公开展示收集的数据且不暴露用户隐私。</p>
|
||||
<p>{{ t('privacyProtectionTipsOne') }}</p>
|
||||
<p>{{ t('privacyProtectionTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
|
||||
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏中间11位数字,仅管理员可查看') }}</div>
|
||||
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsThree') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
@ -5,16 +5,16 @@
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<slot name="field"></slot>
|
||||
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('限制数量')">
|
||||
<el-input v-model.trim="diyStore.editComponent.limit" :placeholder="t('请输入限制数量')" clearable maxlength="2" />
|
||||
<el-form-item :label="t('imageLimit')">
|
||||
<el-input v-model.trim="diyStore.editComponent.limit" :placeholder="t('imageLimitPlaceholder')" clearable maxlength="2" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- <el-form-item :label="t('上传方式')">
|
||||
<el-form-item :label="t('上传方式')">
|
||||
<el-checkbox-group v-model="diyStore.editComponent.uploadMode" :min="1">
|
||||
<el-checkbox label="拍照上传" value="take_pictures" />
|
||||
<el-checkbox label="从相册选择" value="select_from_album" />
|
||||
</el-checkbox-group>
|
||||
</el-form-item> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 表单组件 其他设置 -->
|
||||
@ -44,41 +44,41 @@ diyStore.editComponent.ignore = ['componentBgUrl'] // 忽略公共属性
|
||||
|
||||
// 组件验证
|
||||
diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
if (diyStore.value[index].limit == '') {
|
||||
res.code = false;
|
||||
res.message = t('请输入限制数量')
|
||||
return res;
|
||||
}
|
||||
if (isNaN(diyStore.value[index].limit) || !regExp.number.test(diyStore.value[index].limit)) {
|
||||
res.code = false;
|
||||
res.message = t('限制数量格式输入错误');
|
||||
return res;
|
||||
}
|
||||
if (diyStore.value[index].limit < 0) {
|
||||
res.code = false;
|
||||
res.message = t('限制数量不能小于0')
|
||||
return res;
|
||||
}
|
||||
if (diyStore.value[index].limit == 0) {
|
||||
res.code = false;
|
||||
res.message = t('限制数量必须大于0')
|
||||
return res;
|
||||
}
|
||||
if (diyStore.value[index].limit > 20) {
|
||||
res.code = false;
|
||||
res.message = t('限制数量最大不能超过20')
|
||||
return res;
|
||||
}
|
||||
return res
|
||||
const res = { code: true, message: '' }
|
||||
if (diyStore.value[index].limit == '') {
|
||||
res.code = false
|
||||
res.message = t('imageLimitPlaceholder')
|
||||
return res
|
||||
}
|
||||
if (isNaN(diyStore.value[index].limit) || !regExp.number.test(diyStore.value[index].limit)) {
|
||||
res.code = false
|
||||
res.message = t('imageLimitErrorTips')
|
||||
return res
|
||||
}
|
||||
if (diyStore.value[index].limit < 0) {
|
||||
res.code = false
|
||||
res.message = t('imageLimitErrorTipsTwo')
|
||||
return res
|
||||
}
|
||||
if (diyStore.value[index].limit == 0) {
|
||||
res.code = false
|
||||
res.message = t('imageLimitErrorTipsThree')
|
||||
return res
|
||||
}
|
||||
if (diyStore.value[index].limit > 9) {
|
||||
res.code = false
|
||||
res.message = t('imafeLimitErrorTipsFour')
|
||||
return res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// 正则表达式
|
||||
const regExp: any = {
|
||||
required: /[\S]+/,
|
||||
number: /^\d{0,10}$/,
|
||||
digit: /^\d{0,10}(.?\d{0,2})$/,
|
||||
special: /^\d{0,10}(.?\d{0,3})$/
|
||||
required: /[\S]+/,
|
||||
number: /^\d{0,10}$/,
|
||||
digit: /^\d{0,10}(.?\d{0,2})$/,
|
||||
special: /^\d{0,10}(.?\d{0,3})$/
|
||||
}
|
||||
|
||||
defineExpose({})
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
|
||||
<el-tooltip effect="light" :content="t('设置后,默认值会自动填充到输入框,填表人可在此基础上进行修改。')" placement="top">
|
||||
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
</el-icon>
|
||||
@ -29,11 +29,11 @@
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('内容防重复') }}</span>
|
||||
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>该组件填写的内容不能与已提交的数据重复。</p>
|
||||
<p>极端情况下可能存在延时导致限制失效。</p>
|
||||
<p>{{ t('preventDuplicationTipsOne') }}</p>
|
||||
<p>{{ t('preventDuplicationTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<slot name="field"></slot>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('获取方式')">
|
||||
<el-form-item :label="t('access')">
|
||||
<el-radio-group v-model="diyStore.editComponent.mode">
|
||||
<el-radio class="!mr-[20px]" label="authorized_wechat_location">{{ t('授权微信定位') }}</el-radio>
|
||||
<el-radio label="open_choose_location">{{ t('手动选择定位') }}</el-radio>
|
||||
<el-radio class="!mr-[20px]" label="authorized_wechat_location">{{ t('authorizeWeChatLocation') }}</el-radio>
|
||||
<el-radio label="open_choose_location">{{ t('manuallySelectPositioning') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -19,11 +19,11 @@
|
||||
<el-form-item class="display-block">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
|
||||
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>会自动将提交的个人信息做加密展示。</p>
|
||||
<p>适用于公开展示收集的数据且不暴露用户隐私。</p>
|
||||
<p>{{ t('privacyProtectionTipsOne') }}</p>
|
||||
<p>{{ t('privacyProtectionTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -32,7 +32,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
|
||||
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏文本,仅管理员可查看') }}</div>
|
||||
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsFour') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('内容防重复') }}</span>
|
||||
<span class="mr-[3px]">{{ t('preventDuplication') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>该组件填写的内容不能与已提交的数据重复。</p>
|
||||
<p>极端情况下可能存在延时导致限制失效。</p>
|
||||
<p>{{ t('preventDuplicationTipsOne') }}</p>
|
||||
<p>{{ t('preventDuplicationTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -33,11 +33,11 @@
|
||||
<el-form-item class="display-block">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('隐私保护') }}</span>
|
||||
<span class="mr-[3px]">{{ t('privacyProtection') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>会自动将提交的个人信息做加密展示。</p>
|
||||
<p>适用于公开展示收集的数据且不暴露用户隐私。</p>
|
||||
<p>{{ t('privacyProtectionTipsOne') }}</p>
|
||||
<p>{{ t('privacyProtectionTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-switch v-model="diyStore.editComponent.field.privacyProtection" />
|
||||
<div class="text-sm text-gray-400">{{ t('提交后自动隐藏中间5位数字,仅管理员可查看') }}</div>
|
||||
<div class="text-sm text-gray-400">{{ t('privacyProtectionTipsFive') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
@ -8,14 +8,14 @@
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('单位')">
|
||||
<el-input v-model.trim="diyStore.editComponent.unit" :placeholder="t('请输入单位')" clearable maxlength="5" show-word-limit />
|
||||
<el-form-item :label="t('unit')">
|
||||
<el-input v-model.trim="diyStore.editComponent.unit" :placeholder="t('unitPlaceholder')" clearable maxlength="5" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
|
||||
<el-tooltip effect="light" :content="t('设置后,默认值会自动填充到输入框,填表人可在此基础上进行修改。')" placement="top">
|
||||
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
</el-icon>
|
||||
@ -95,10 +95,10 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
if(diyStore.value[index].field.default){
|
||||
if (isNaN(diyStore.value[index].field.default) || !regExp.digit.test(diyStore.value[index].field.default)) {
|
||||
res.code = false;
|
||||
res.message = t('默认值格式输入错误');
|
||||
res.message = t('defaultErrorTips');
|
||||
} else if (diyStore.value[index].field.default < 0) {
|
||||
res.code = false;
|
||||
res.message = t('默认值不能小于0')
|
||||
res.message = t('defaultMustZeroTips')
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
||||
@ -5,31 +5,31 @@
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<slot name="field"></slot>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('样式')">
|
||||
<el-form-item :label="t('style')">
|
||||
<el-radio-group v-model="diyStore.editComponent.style">
|
||||
<el-radio label="style-1">{{ t('默认') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('列表') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('下拉') }}</el-radio>
|
||||
<el-radio label="style-1">{{ t('defaultSources') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('listStyle') }}</el-radio>
|
||||
<el-radio label="style-3">{{ t('dropDownStyle') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('选项')">
|
||||
<el-form-item :label="t('option')">
|
||||
<div ref="formRadioRef">
|
||||
<div v-for="(option, index) in diyStore.editComponent.options" :key="option.id" class="option-item flex items-center mb-[15px]">
|
||||
<el-input v-model="diyStore.editComponent.options[index].text" class="!w-[215px]" :placeholder="t('optionPlaceholder')" clearable maxlength="30" />
|
||||
<span v-if="diyStore.editComponent.options.length > 1" @click="removeOption(index)" class="cursor-pointer ml-[5px] nc-iconfont nc-icon-shanchu-yuangaizhiV6xx"></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">添加单个选项</span>
|
||||
<span class="text-primary cursor-pointer mr-[10px]" @click="addOption">{{ t('addSingleOption') }}</span>
|
||||
<el-popover :visible="visible" placement="bottom" :width="300">
|
||||
<p class="mb-[5px]">批量添加选项</p>
|
||||
<p class="text-[#888] text-[12px] mb-[5px]">可添加多个选项,每个选项之间用英文","隔开</p>
|
||||
<p class="mb-[5px]">{{ t('addMultipleOption') }}</p>
|
||||
<p class="text-[#888] text-[12px] mb-[5px]">{{ t('addOptionTips') }}</p>
|
||||
<el-input v-model.trim="optionsValue" type="textarea" clearable maxlength="200" show-word-limit />
|
||||
<div class="mt-[10px] text-right">
|
||||
<el-button size="small" text @click="visible = false">取消</el-button>
|
||||
<el-button size="small" type="primary" @click="batchAddOptions">确定</el-button>
|
||||
<el-button size="small" text @click="visible = false">{{ t('cancel') }}</el-button>
|
||||
<el-button size="small" type="primary" @click="batchAddOptions">{{ t('confirm') }}</el-button>
|
||||
</div>
|
||||
<template #reference>
|
||||
<span class="text-primary cursor-pointer" @click="visible = true">批量添加选项</span>
|
||||
<span class="text-primary cursor-pointer" @click="visible = true">{{ t('addMultipleOption') }}</span>
|
||||
</template>
|
||||
</el-popover>
|
||||
</el-form-item>
|
||||
@ -123,7 +123,7 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
|
||||
if (uniqueOptions.length != diyStore.value[index].options.length) {
|
||||
res.code = false;
|
||||
res.message = t('存在重复选项,请检查内容')
|
||||
res.message = t('errorTipsOne')
|
||||
}
|
||||
return res
|
||||
}
|
||||
@ -167,7 +167,7 @@ const batchAddOptions = () => {
|
||||
diyStore.editComponent.options.push(...filteredNewOptions);
|
||||
} else {
|
||||
ElMessage({
|
||||
message: "选项已存在,请重新输入",
|
||||
message: t('errorTipsTwo'),
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
|
||||
@ -3,47 +3,47 @@
|
||||
<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('按钮位置')" 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('跟随内容') }}</el-radio>
|
||||
<el-radio label="hover_screen_bottom">{{ t('悬浮屏幕底部') }}</el-radio>
|
||||
<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('当表单内容多时,只有滚动页面至最底部才会显示提交按钮') }}</div>
|
||||
<div class="text-sm text-gray-400 mb-[5px]" v-show="diyStore.editComponent.btnPosition == 'hover_screen_bottom'">{{ t('按钮悬浮在屏幕底部,方便填表人快速提交') }}</div>
|
||||
<div class="text-sm text-gray-400 mb-[10px] leading-[1.4]">{{ t('若前端以嵌入形式调用表单,提交按钮组件将不显示,相关业务由该页面负责处理') }}</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>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('提交按钮') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('submitBtn') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('按钮名称')">
|
||||
<el-input v-model.trim="diyStore.editComponent.submitBtn.text" :placeholder="t('请输入按钮名称')" clearable maxlength="10" show-word-limit />
|
||||
<el-form-item :label="t('submitBtnName')">
|
||||
<el-input v-model.trim="diyStore.editComponent.submitBtn.text" :placeholder="t('btnNamePlaceholder')" clearable maxlength="10" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.submitBtn.color" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('背景色')">
|
||||
<el-form-item :label="t('subTextBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.submitBtn.bgColor" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('重置按钮') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('resetBtn') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('carouselSearchTabControl')">
|
||||
<el-switch v-model="diyStore.editComponent.resetBtn.control" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('按钮名称')">
|
||||
<el-input v-model.trim="diyStore.editComponent.resetBtn.text" :placeholder="t('请输入按钮名称')" clearable maxlength="10" show-word-limit />
|
||||
<el-form-item :label="t('submitBtnName')">
|
||||
<el-input v-model.trim="diyStore.editComponent.resetBtn.text" :placeholder="t('btnNamePlaceholder')" clearable maxlength="10" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.resetBtn.color" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('背景色')">
|
||||
<el-form-item :label="t('subTextBgColor')">
|
||||
<el-color-picker v-model="diyStore.editComponent.resetBtn.bgColor" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -55,7 +55,7 @@
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('按钮样式') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('btnStyle') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('topRounded')">
|
||||
<el-slider v-model="diyStore.editComponent.topElementRounded" show-input size="small" class="ml-[10px] diy-nav-slider" :max="50" />
|
||||
@ -94,12 +94,12 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
const res = { code: true, message: '' }
|
||||
if (diyStore.value[index].submitBtn.text == '') {
|
||||
res.code = false;
|
||||
res.message = t('请输入提交按钮名称');
|
||||
res.message = t('submitBtnNamePlaceholder');
|
||||
return res;
|
||||
}
|
||||
if (diyStore.value[index].resetBtn.text == '') {
|
||||
res.code = false;
|
||||
res.message = t('请输入重置按钮名称');
|
||||
res.message = t('resetBtnNamePlaceholder');
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('defaultValue') }}</span>
|
||||
<el-tooltip effect="light" :content="t('设置后,默认值会自动填充到输入框,填表人可在此基础上进行修改。')" placement="top">
|
||||
<el-tooltip effect="light" :content="t('defaultValueTips')" placement="top">
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
</el-icon>
|
||||
@ -21,8 +21,8 @@
|
||||
</template>
|
||||
<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('显示行数')">
|
||||
<el-input v-model.trim="diyStore.editComponent.rowCount" :placeholder="t('请输入显示行数')" clearable maxlength="2" show-word-limit />
|
||||
<el-form-item :label="t('rowCount')">
|
||||
<el-input v-model.trim="diyStore.editComponent.rowCount" :placeholder="t('rowCountPlaceholder')" clearable maxlength="2" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
@ -6,43 +6,43 @@
|
||||
<slot name="field"></slot>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('开始时间') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('startTime') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('提示语')">
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.start.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('默认值')">
|
||||
<el-form-item :label="t('defaultValue')">
|
||||
<el-switch v-model="diyStore.editComponent.start.defaultControl"/>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.start.defaultControl">
|
||||
<el-radio-group v-model="diyStore.editComponent.start.timeWay">
|
||||
<el-radio label="current">{{ t('当天时间') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('指定时间') }}</el-radio>
|
||||
<el-radio label="current">{{ t('currentTime') }}</el-radio>
|
||||
<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-time-picker v-model="diyStore.editComponent.field.default.start.date" placeholder="请选择开始时间" format="HH:mm" value-format="HH:mm" @change="startTimePickerChange" />
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('结束时间') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('endTime') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]" @submit.prevent>
|
||||
<el-form-item :label="t('提示语')">
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.end.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('默认值')">
|
||||
<el-form-item :label="t('defaultValue')">
|
||||
<el-switch v-model="diyStore.editComponent.end.defaultControl" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.end.defaultControl">
|
||||
<el-radio-group v-model="diyStore.editComponent.end.timeWay">
|
||||
<el-radio label="current">{{ t('当天时间') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('指定时间') }}</el-radio>
|
||||
<el-radio label="current">{{ t('currentTime') }}</el-radio>
|
||||
<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-time-picker :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" v-model="diyStore.editComponent.field.default.end.date" placeholder="请选择结束时间" format="HH:mm" value-format="HH:mm" />
|
||||
<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>
|
||||
</div>
|
||||
@ -55,7 +55,7 @@
|
||||
<div class="style-wrap" v-show="diyStore.editTab == 'style'">
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('文字样式') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
|
||||
@ -105,18 +105,18 @@ diyStore.editComponent.verify = (index: number) => {
|
||||
|
||||
if(diyStore.editComponent.start.defaultControl && starTime == ''){
|
||||
res.code = false
|
||||
res.message = "开始时间不能为空"
|
||||
res.message = t('startTimeTips')
|
||||
return res
|
||||
}
|
||||
if(diyStore.editComponent.end.defaultControl && endTime == ''){
|
||||
res.code = false
|
||||
res.message = "结束时间不能为空"
|
||||
res.message = t('endTimeTips')
|
||||
return res
|
||||
}
|
||||
|
||||
if(diyStore.editComponent.start.defaultControl && diyStore.editComponent.end.defaultControl && timeInvertSecond(starTime) > timeInvertSecond(endTime)){
|
||||
res.code = false
|
||||
res.message = "开始时间不能大于结束时间"
|
||||
res.message = t('startEndTimeTips')
|
||||
return res
|
||||
}
|
||||
return res
|
||||
|
||||
@ -8,17 +8,17 @@
|
||||
<el-form-item :label="t('formPlaceholder')">
|
||||
<el-input v-model.trim="diyStore.editComponent.placeholder" :placeholder="t('formPlaceholderTips')" clearable maxlength="15" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('默认值')">
|
||||
<el-form-item :label="t('defaultValue')">
|
||||
<el-switch v-model="diyStore.editComponent.defaultControl" @change="changeDateDefaultControl" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.defaultControl">
|
||||
<el-radio-group v-model="diyStore.editComponent.timeWay">
|
||||
<el-radio label="current">{{ t('当天时间') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('指定时间') }}</el-radio>
|
||||
<el-radio label="current">{{ t('currentTime') }}</el-radio>
|
||||
<el-radio label="diy">{{ t('diyTime') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="diyStore.editComponent.defaultControl && diyStore.editComponent.timeWay == 'diy'">
|
||||
<el-time-picker v-model="diyStore.editComponent.field.default" placeholder="请选择时间" format="HH:mm" value-format="HH:mm" />
|
||||
<el-time-picker v-model="diyStore.editComponent.field.default" :placeholder="t('timePlaceholder')" format="HH:mm" value-format="HH:mm" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
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('表单推广')" width="500px" :destroy-on-close="true">
|
||||
<el-dialog v-model="showDialog" :title="t('formPromotion')" width="500px" :destroy-on-close="true">
|
||||
|
||||
<el-tabs v-model="channel" class="mb-[10px]">
|
||||
<el-tab-pane label="H5" name="h5"></el-tab-pane>
|
||||
@ -13,13 +13,13 @@
|
||||
</div>
|
||||
|
||||
<div class="px-[20px] flex-1">
|
||||
<div class="mb-[10px]">{{ t('推广链接') }}</div>
|
||||
<div class="mb-[10px]">{{ t('promoteUrl') }}</div>
|
||||
<el-input class="mb-[10px]" readonly :value="wapPreview">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(wapPreview)">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<a class="text-primary" :href="wapImage" download>{{ t('下载二维码') }}</a>
|
||||
<a class="text-primary" :href="wapImage" download>{{ t('downLoadQRCode') }}</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -28,14 +28,14 @@
|
||||
<div class="promote-img flex justify-center items-center bg-[#f8f8f8] w-[150px] h-[150px]">
|
||||
<el-image :src="img(weappData.path)" v-if="weappData.path" class="w-[150px] h-[150px]">
|
||||
<template #error>
|
||||
<div class="w-[150px] h-[150px] text-[14px] text-center leading-[150px]">配置失败</div>
|
||||
<div class="w-[150px] h-[150px] text-[14px] text-center leading-[150px]">{{ t('configureFailed') }}</div>
|
||||
</template>
|
||||
</el-image>
|
||||
<div v-else class="w-[150px] h-[150px] text-[14px] text-center leading-[150px]">配置失败</div>
|
||||
<div v-else class="w-[150px] h-[150px] text-[14px] text-center leading-[150px]">{{ t('configureFailed') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="px-[20px] flex-1">
|
||||
<a class="text-primary" :href="img(weappData.path)" target="_blank" download>{{ t('下载二维码') }}</a>
|
||||
<a class="text-primary" :href="img(weappData.path)" target="_blank" download>{{ t('downLoadQRCode') }}</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="showDialog" :title="t('提交成功页')" 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">
|
||||
@ -17,19 +17,19 @@
|
||||
<el-icon><SuccessFilled color="#20bf64" /></el-icon>
|
||||
</div>
|
||||
<div class="record-name">
|
||||
<span class="text-[#1E1E1E] font-bold text-[24px]" v-if="formData.tips_type == 'default'">填写成功</span>
|
||||
<span class="text-[#1E1E1E] font-bold text-[24px]" v-if="formData.tips_type == 'default'">{{ t('writeSuccess') }}</span>
|
||||
<span class="text-[#1E1E1E] font-bold text-[16px]" v-else-if="formData.tips_type == 'diy'">{{ formData.tips_text ? formData.tips_text : '填写成功' }}</span>
|
||||
</div>
|
||||
<div class="to-detail">
|
||||
<div class="text-[14px] mt-[16px] py-[4px] px[8px] text-[#576b95]">查看填写详情</div>
|
||||
<div class="text-[14px] mt-[16px] py-[4px] px[8px] text-[#576b95]">{{ t('viewFillingDetails') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative pt-[8px] pb-[48px] h-[112px]">
|
||||
<div v-if="formData.success_after_action.finish" class="!mt-[16px] rounded-[3px] mx-auto text-[15px] w-[100px] min-w-[160px] h-[32px] leading-[32px] text-center max-w-[274px] truncate bg-[#20bf64] text-[#ffffff]">
|
||||
<div class="text-[15px]">完成</div>
|
||||
<div class="text-[15px]">{{ t('finish') }}</div>
|
||||
</div>
|
||||
<div v-if="formData.success_after_action.goback" class="!mt-[16px] rounded-[3px] mx-auto text-[15px] w-[100px] min-w-[160px] h-[32px] leading-[32px] text-center max-w-[274px] truncate bg-[#f2f2f2] text-[#353535]">
|
||||
<div class="text-[14px]">返回</div>
|
||||
<div class="text-[14px]">{{ t('back') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -60,13 +60,13 @@
|
||||
|
||||
<div class="flex-1">
|
||||
<div class="item-wrap">
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">填表人提交后</div>
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">{{ t('afterSubmission') }}</div>
|
||||
<el-radio-group v-model="formData.submit_after_action" class="!block">
|
||||
<el-radio label="text" class="!flex">
|
||||
<span class="mr-[3px]">{{ t('显示文字信息') }}</span>
|
||||
<span class="mr-[3px]">{{ t('displayTextMessages') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>{{ t('提交后页面显示文字信息。') }}</p>
|
||||
<p>{{ t('displayTextMessagesTips') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -89,16 +89,16 @@
|
||||
</div>
|
||||
|
||||
<div class="item-wrap" v-if="formData.submit_after_action == 'text'">
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">{{ t('提示文字') }}</div>
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">{{ t('promptText') }}</div>
|
||||
<div>
|
||||
<el-radio-group v-model="formData.tips_type" class="!block">
|
||||
<el-radio label="default" class="!block">
|
||||
<span class="mr-[3px]">{{ t('默认提示') }}</span>
|
||||
<span class="!text-[#999] text-[12px] ml-[8px]">{{ t('将显示: 填写成功') }}</span>
|
||||
<span class="mr-[3px]">{{ t('defaultPrompt') }}</span>
|
||||
<span class="!text-[#999] text-[12px] ml-[8px]">{{ t('defaultPromptTips') }}</span>
|
||||
</el-radio>
|
||||
<el-radio label="diy" class="!block">{{ t('自定义提示') }}</el-radio>
|
||||
<el-radio label="diy" class="!block">{{ t('diyPrompt') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-input v-if="formData.tips_type == 'diy'" v-model.trim="formData.tips_text" :placeholder="t('感谢你的填写')" class="w-[350px]" maxlength="30" clearable show-word-limit />
|
||||
<el-input v-if="formData.tips_type == 'diy'" v-model.trim="formData.tips_text" :placeholder="t('tipsTextPlaceholder')" class="w-[350px]" maxlength="30" clearable show-word-limit />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -106,15 +106,15 @@
|
||||
<template v-else-if="formData.submit_after_action == 'voucher'">
|
||||
|
||||
<div class="item-wrap">
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">{{ t('凭证有效期') }}</div>
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">{{ t('validityPeriodOfVoucher') }}</div>
|
||||
<div>
|
||||
<el-radio-group v-model="formData.time_limit_type" class="!block">
|
||||
<el-radio label="no_limit" class="!block">{{ t('不限制') }}</el-radio>
|
||||
<el-radio label="no_limit" class="!block">{{ t('noLimit') }}</el-radio>
|
||||
<el-radio label="specify_time" class="!block">
|
||||
<span class="mr-[3px]">{{ t('设置固定有效期') }}</span>
|
||||
<span class="mr-[3px]">{{ t('specifyTime') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>{{ t('每条记录的凭证有效期都是一样的,例如:会议凭证可设置有效期为会议举行时间。') }}</p>
|
||||
<p>{{ t('specifyTimeTips') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -122,10 +122,10 @@
|
||||
</el-tooltip>
|
||||
</el-radio>
|
||||
<el-radio label="submission_time" class="!block">
|
||||
<span class="mr-[3px]">按提交时间设置有效期</span>
|
||||
<span class="mr-[3px]">{{ t('submissionTime') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p class="w-[250px]">每条记录的凭证有效期按照提交时间来计算,例如:优惠凭证的有效期可以设置为领取后3天内有效。</p>
|
||||
<p class="w-[250px]">{{ t('submissionTimeTips') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -135,44 +135,44 @@
|
||||
</el-radio-group>
|
||||
<el-date-picker v-if="formData.time_limit_type == 'specify_time'" v-model="formData.validity_time" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" />
|
||||
<div class="flex items-center mt-[5px]" v-if="formData.time_limit_type == 'submission_time'">
|
||||
<span>提交记录后</span>
|
||||
<span>{{ t('afterSubmissionRecords') }}</span>
|
||||
<!-- <div class="flex items-center px-[5px]">-->
|
||||
<!-- v-model.trim="formData.length"-->
|
||||
<el-input v-model.trim="formData.submission_time_value" @keyup="filterNumber($event)" size="small" clearable class="!w-[100px] px-[5px]" maxlength="3" />
|
||||
<el-select v-model="formData.timeUnit" clearable class="!w-[100px] pr-[5px]" size="small">
|
||||
<el-option v-for="(item, index) in validityOptions" :key="item.value" :label="item.text" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
<span>有效</span>
|
||||
<span>{{ t('effective') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-wrap">
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">凭证样式</div>
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">{{ t('voucherStyle') }}</div>
|
||||
<div>
|
||||
<el-form-item :label="t('码上方标题')">
|
||||
<el-form-item :label="t('titleAboveTheCode')">
|
||||
<!-- v-model.trim="formData.active_name"-->
|
||||
<el-input clearable :placeholder="t('请妥善保存你的核销凭证')" class="input-width" :maxlength="20" />
|
||||
<el-input clearable :placeholder="t('titleAboveTheCodePlaceholder')" class="input-width" :maxlength="20" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('码上方内容')">
|
||||
<el-input clearable :placeholder="t('请输入码上方内容')" class="input-width" :maxlength="20" />
|
||||
<el-form-item :label="t('contentAboveTheCode')">
|
||||
<el-input clearable :placeholder="t('contentAboveTheCodePlaceholder')" class="input-width" :maxlength="20" />
|
||||
<div>
|
||||
<span class="text-primary cursor-pointer mr-[10px]">添加换行符</span>
|
||||
<span class="text-primary cursor-pointer">添加字段</span>
|
||||
<span class="text-primary cursor-pointer mr-[10px]">{{ t('addLinefeeds') }}</span>
|
||||
<span class="text-primary cursor-pointer">{{ t('addFields') }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('码下方内容')">
|
||||
<el-form-item :label="t('contentBelowTheCode')">
|
||||
<div class="block">
|
||||
<el-checkbox class="!block" label="展示提交记录时间" value="" />
|
||||
<el-checkbox class="!block" :label="t('submissionRecordTime')" value="" />
|
||||
|
||||
<el-checkbox class="!block !h-[20px]" label="展示当前时间" value="" />
|
||||
<div class="text-[#999] ml-[22px]">会以秒进行跳动,可起到防作假的功能</div>
|
||||
<el-checkbox class="!block !h-[20px]" :label="t('currentTime')" value="" />
|
||||
<div class="text-[#999] ml-[22px]">{{ t('currentTimeTips') }}</div>
|
||||
|
||||
<el-checkbox class="!block" label="展示提示文字" value="" />
|
||||
<el-input class="ml-[22px]" :rows="4" type="textarea" placeholder="感谢你的填写" maxlength="100" />
|
||||
<el-checkbox class="!block" :label="t('dispalyPromptText')" value="" />
|
||||
<el-input class="ml-[22px]" :rows="4" type="textarea" :placeholder="t('tipsTextPlaceholder')" maxlength="100" />
|
||||
|
||||
<el-checkbox class="!block" label="展示凭证截止时间" value="" />
|
||||
<el-checkbox class="!block" label="支持填表人保存凭证" value="" />
|
||||
<el-checkbox class="!block" :label="t('voucherDeadline')" value="" />
|
||||
<el-checkbox class="!block" :label="t('saveVoucher')" value="" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
@ -182,7 +182,7 @@
|
||||
<!-- todo 后续完善 -->
|
||||
<div class="item-wrap">
|
||||
<div class="text-[16px] h-[24px] font-bold text-[#262626] mb-[16px] w-[140px] mr-[32px] flex-shrink-0">
|
||||
<span>后续操作按钮</span>
|
||||
<span>{{ t('subsequentPperationButtons') }}</span>
|
||||
<!-- <p class="text-[12px] text-[#999] mt-[4px] font-normal">最多选择2个</p>-->
|
||||
</div>
|
||||
<div class="content-list-wrap">
|
||||
@ -192,15 +192,15 @@
|
||||
<!-- </el-checkbox>-->
|
||||
<!-- <p class="text-[#999] text-[12px] pl-[24px] mt-[4px]">提交表单后,可转发给微信好友查看。支持按钮文案自定义,提醒填表人转发给特定人员查看</p>-->
|
||||
|
||||
<el-checkbox v-model="formData.success_after_action.finish" label="完成" value="finish">
|
||||
<div class="text-[#333]">完成</div>
|
||||
<el-checkbox v-model="formData.success_after_action.finish" :label="t('finish')" value="finish">
|
||||
<div class="text-[#333]">{{ t('finish') }}</div>
|
||||
</el-checkbox>
|
||||
<p class="text-[#999] text-[12px] pl-[24px] mt-[4px]">点击后进入首页</p>
|
||||
<p class="text-[#999] text-[12px] pl-[24px] mt-[4px]">{{ t('finishTips') }}</p>
|
||||
|
||||
<el-checkbox v-model="formData.success_after_action.goback" label="返回" value="goback">
|
||||
<div class="text-[#333]">返回</div>
|
||||
<el-checkbox v-model="formData.success_after_action.goback" :label="t('back')" value="goback">
|
||||
<div class="text-[#333]">{{ t('back') }}</div>
|
||||
</el-checkbox>
|
||||
<p class="text-[#999] text-[12px] pl-[24px] mt-[4px]">点击后返回表单</p>
|
||||
<p class="text-[#999] text-[12px] pl-[24px] mt-[4px]">{{ t('backTips') }}</p>
|
||||
<!-- </el-checkbox-group>-->
|
||||
</div>
|
||||
</div>
|
||||
@ -210,7 +210,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ t('保存') }}</el-button>
|
||||
<el-button type="primary" @click="confirm">{{ t('save') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="t('填写设置')" width="600px" class="diy-dialog-wrap" :close-on-press-escape="true" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
<el-dialog v-model="showDialog" :title="t('writeSet')" width="600px" class="diy-dialog-wrap" :close-on-press-escape="true" :destroy-on-close="true" :close-on-click-modal="false">
|
||||
|
||||
<el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
|
||||
@ -33,10 +33,10 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('每人可填写次数')" :class="{ '!mb-[5px]' : formData.member_write_type == 'diy' }">
|
||||
<el-form-item :label="t('apieceFillQuantity')" :class="{ '!mb-[5px]' : formData.member_write_type == 'diy' }">
|
||||
<el-radio-group v-model="formData.member_write_type">
|
||||
<el-radio label="no_limit">{{t('不限制')}}</el-radio>
|
||||
<el-radio label="diy">{{t('自定义')}}</el-radio>
|
||||
<el-radio label="no_limit">{{t('noLimit')}}</el-radio>
|
||||
<el-radio label="diy">{{t('diy')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
@ -53,10 +53,10 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('表单可填写总数')" :class="{ '!mb-[5px]' : formData.form_write_type == 'diy' }">
|
||||
<el-form-item :label="t('fillQuantityTotal')" :class="{ '!mb-[5px]' : formData.form_write_type == 'diy' }">
|
||||
<el-radio-group v-model="formData.form_write_type">
|
||||
<el-radio label="no_limit">{{t('不限制')}}</el-radio>
|
||||
<el-radio label="diy">{{t('自定义')}}</el-radio>
|
||||
<el-radio label="no_limit">{{t('noLimit')}}</el-radio>
|
||||
<el-radio label="diy">{{t('diy')}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
<span class="mr-[5px]">次</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p class="w-[250px]">{{ t('填写限制的校验在极端情况下可能存在延时,从而导致限制失效,不建议商品限时抢购等场景使用该功能') }}</p>
|
||||
<p class="w-[250px]">{{ t('writeTips') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -81,11 +81,11 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('可填写时间段')" prop="time_limit_rule">
|
||||
<el-form-item :label="t('fillInTheTimePeriod')" prop="time_limit_rule">
|
||||
<el-radio-group v-model="formData.time_limit_type">
|
||||
<el-radio label="no_limit">{{t('不限制')}}</el-radio>
|
||||
<el-radio label="specify_time">{{t('设置开始/停止时间')}}</el-radio>
|
||||
<el-radio label="open_day_time">{{t('设置每日开启时间')}}</el-radio>
|
||||
<el-radio label="no_limit">{{t('noLimit')}}</el-radio>
|
||||
<el-radio label="specify_time">{{t('setSpecifyTime')}}</el-radio>
|
||||
<el-radio label="open_day_time">{{t('openDayTime')}}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-date-picker v-if="formData.time_limit_type == 'specify_time'" v-model="formData.time_limit_rule.specify_time" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" />
|
||||
<div class="flex items-center mt-[5px]" v-if="formData.time_limit_type == 'open_day_time'">
|
||||
@ -186,7 +186,7 @@ const formRules = computed(() => {
|
||||
if(!value.time_value){
|
||||
callback(new Error(`${unit}数不能为空`))
|
||||
}else if(!value.num){
|
||||
callback(new Error(`次数不能为空`))
|
||||
callback(new Error(t('numCannotNull')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
@ -210,7 +210,7 @@ const formRules = computed(() => {
|
||||
if(!value.time_value){
|
||||
callback(new Error(`${unit}数不能为空`))
|
||||
}else if(!value.num){
|
||||
callback(new Error(`次数不能为空`))
|
||||
callback(new Error(t('numCannotNull')))
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
@ -225,12 +225,12 @@ const formRules = computed(() => {
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (formData.time_limit_type == 'specify_time' && (!value.specify_time || !value.specify_time.length)) {
|
||||
callback(new Error('开始/停止时间不能为空'))
|
||||
callback(new Error(t('timeLimitRuleOne')))
|
||||
} else if (formData.time_limit_type == 'open_day_time' && (!value.open_day_time || !value.open_day_time.length)) {
|
||||
callback(new Error('开启时间不能为空'))
|
||||
callback(new Error(t('timeLimitRuleTwo')))
|
||||
} else if (formData.time_limit_type == 'open_day_time' && value.open_day_time && value.open_day_time.length) {
|
||||
if (value.open_day_time[0] == value.open_day_time[1]) {
|
||||
callback(new Error('开始时间不能等于结束时间'))
|
||||
callback(new Error(t('timeLimitRuleThree')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
|
||||
@ -142,23 +142,23 @@
|
||||
<template #content>
|
||||
<!-- 表单布局 页面设置 -->
|
||||
<div class="edit-attr-item-wrap" v-if="diyStore.currentComponent == 'edit-page'">
|
||||
<h3 class="mb-[10px]">{{ t('表单布局') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('formLayout') }}</h3>
|
||||
<el-form label-width="90px" class="px-[10px]">
|
||||
<el-form-item class="display-block">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('排版风格') }}</span>
|
||||
<span class="mr-[3px]">{{ t('layoutStyle') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<h6 class="font-bold text-[13px] mb-[5px]">单列平铺</h6>
|
||||
<p class="ml-[10px]">将所有需要填写的表单内容项直接罗列在页面上。</p>
|
||||
<p class="ml-[10px]">适用于表单内容项较少且项目之间无逻辑关系的情况。</p>
|
||||
<p class="ml-[10px]">其优势在于相对简洁、便于操作</p>
|
||||
<p class="ml-[10px]">但当表单项数量较大时,一次性展示全部信息会增加用户的操作负担,填写效率较低</p>
|
||||
<h6 class="font-bold text-[13px] mb-[5px]">{{ t('singleTiling') }}</h6>
|
||||
<p class="ml-[10px]">{{ t('singleTilingTipsOne') }}</p>
|
||||
<p class="ml-[10px]">{{ t('singleTilingTipsTwo') }}</p>
|
||||
<p class="ml-[10px]">{{ t('singleTilingTipsThree') }}</p>
|
||||
<p class="ml-[10px]">{{ t('singleTilingTipsFour') }}</p>
|
||||
|
||||
<h6 class="font-bold text-[13px] mb-[5px] mt-[10px]">左右排列</h6>
|
||||
<p class="ml-[10px]">将表单分为左右两部分,左侧为标题和描述,右侧为输入区域。</p>
|
||||
<p class="ml-[10px]">这种布局适用于标题和描述内容较少的情况,能够提高表单的紧凑性和用户体验。</p>
|
||||
<h6 class="font-bold text-[13px] mb-[5px] mt-[10px]">{{ t('arrangeSideBySide') }}</h6>
|
||||
<p class="ml-[10px]">{{ t('arrangeSideBySideTipsOne') }}</p>
|
||||
<p class="ml-[10px]">{{ t('arrangeSideBySideTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -167,10 +167,10 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-radio-group v-model="diyStore.global.completeLayout" @change="completeLayoutChange">
|
||||
<el-radio label="style-1">{{ t('单列平铺') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('左右排列') }}</el-radio>
|
||||
<el-radio label="style-1">{{ t('singleTiling') }}</el-radio>
|
||||
<el-radio label="style-2">{{ t('arrangeSideBySide') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<div class="text-sm text-gray-400">{{ t('切换后将同步所有表单组件的展示形式') }}</div>
|
||||
<div class="text-sm text-gray-400">{{ t('layoutStyleTips') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('textAlign')" v-show="diyStore.global.completeLayout == 'style-2'">
|
||||
<el-radio-group v-model="diyStore.global.completeAlign">
|
||||
@ -178,7 +178,7 @@
|
||||
<el-radio :label="'right'">{{ t('textAlignRight') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('边框开关')" v-show="diyStore.global.completeLayout == 'style-2'">
|
||||
<el-form-item :label="t('borderControl')" v-show="diyStore.global.completeLayout == 'style-2'">
|
||||
<el-switch v-model="diyStore.global.borderControl" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -187,12 +187,12 @@
|
||||
<template #field>
|
||||
<!-- 表单组件 字段内容设置 -->
|
||||
<div class="edit-attr-item-wrap" v-if="diyStore.editComponent.componentType == 'diy_form'">
|
||||
<h3 class="mb-[10px]">{{ t('字段内容') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('fieleContent') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('字段名称')">
|
||||
<el-form-item :label="t('fieldName')">
|
||||
<el-input v-model.trim="diyStore.editComponent.field.name" :placeholder="t('fieldNamePlaceholder')" clearable :maxlength="inputMaxLength" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('字段说明')">
|
||||
<el-form-item :label="t('filedRemark')">
|
||||
<el-input v-model.trim="diyStore.editComponent.field.remark.text" :placeholder="t('fieldRemarkPlaceholder')" clearable maxlength="60" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -201,7 +201,7 @@
|
||||
<template #other>
|
||||
<!-- 表单组件 其他设置 -->
|
||||
<div class="edit-attr-item-wrap" v-if="diyStore.editComponent.componentType == 'diy_form'">
|
||||
<h3 class="mb-[10px]">{{ t('其他设置') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('otherSetting') }}</h3>
|
||||
<el-form label-width="100px" class="px-[10px]">
|
||||
<el-form-item :label="t('isRequired')">
|
||||
<el-switch v-model="diyStore.editComponent.field.required" />
|
||||
@ -243,11 +243,11 @@
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-[3px]">{{ t('隐藏该组件') }}</span>
|
||||
<span class="mr-[3px]">{{ t('hideControl') }}</span>
|
||||
<el-tooltip effect="light" placement="top">
|
||||
<template #content>
|
||||
<p>勾选后填表人填表时看不到该字段。</p>
|
||||
<p>适用于你不再收集该字段又不希望删除已收集的数据。</p>
|
||||
<p>{{ t('hideControlTipsOne') }}</p>
|
||||
<p>{{ t('hideControlTipsTwo') }}</p>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled color="#999999" />
|
||||
@ -264,7 +264,7 @@
|
||||
<!-- 表单组件 字段样式设置 -->
|
||||
<template v-if="diyStore.editComponent.componentType == 'diy_form'">
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('文字样式') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('textStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
|
||||
@ -282,7 +282,7 @@
|
||||
</div>
|
||||
|
||||
<div class="edit-attr-item-wrap">
|
||||
<h3 class="mb-[10px]">{{ t('字段说明样式') }}</h3>
|
||||
<h3 class="mb-[10px]">{{ t('filedRemarkStyle') }}</h3>
|
||||
<el-form label-width="80px" class="px-[10px]">
|
||||
<el-form-item :label="t('textFontSize')">
|
||||
<el-slider v-model="diyStore.editComponent.field.remark.fontSize" show-input size="small" class="ml-[10px] diy-nav-slider" :min="12" :max="18" />
|
||||
@ -750,7 +750,7 @@ const verifyFormComponent = () => {
|
||||
if (diyStore.value[i].componentType == 'diy_form' && diyStore.value[i].componentName != 'FormSubmit' && diyStore.value[i].field.name == '') {
|
||||
diyStore.changeCurrentIndex(i, diyStore.value[i])
|
||||
ElMessage({
|
||||
message: t('请输入字段名称'),
|
||||
message: t('fieldNamePlaceholder'),
|
||||
type: 'warning'
|
||||
})
|
||||
return false;
|
||||
|
||||
@ -53,29 +53,29 @@
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center justify-end">
|
||||
<el-button type="primary" v-if="row.status == 1" link @click="spreadEvent(row)">{{ t('推广') }}</el-button>
|
||||
<el-button type="primary" v-if="row.status == 1 && row.type=='DIY_FORM'" link @click="spreadEvent(row)">{{ t('promotion') }}</el-button>
|
||||
<!-- <el-button type="primary" link @click="toPreview(row)">{{ t('preview') }}</el-button>-->
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<el-button v-if="row.status == 0" type="primary" link @click="deleteEvent(row.form_id)">{{ t('delete') }}</el-button>
|
||||
<el-button type="primary" link @click="detailEvent(row)">{{ t('详情') }}</el-button>
|
||||
<el-button type="primary" link @click="detailEvent(row)">{{ t('detail') }}</el-button>
|
||||
<el-dropdown placement="bottom" trigger="click" class="ml-[12px]">
|
||||
<el-button type="primary" link>更多</el-button>
|
||||
<el-button type="primary" link>{{ t('more') }}</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>
|
||||
<el-button type="primary" class="w-full" link @click="submitConfigEvent(row)">{{ t('提交成功页') }}</el-button>
|
||||
<el-dropdown-item v-if="row.type=='DIY_FORM'">
|
||||
<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('填写设置') }}</el-button>
|
||||
<el-button type="primary" class="w-full" link @click="writeConfigEvent(row)">{{ t('writeSet') }}</el-button>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-dropdown-item v-if="row.type=='DIY_FORM'">
|
||||
<el-button type="primary" class="w-full" link @click="openShare(row)">{{ t('shareSet') }}</el-button>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-button type="primary" class="w-full" link @click="exportEvent(row)">{{ t('导出') }}</el-button>
|
||||
<el-button type="primary" class="w-full" link @click="exportEvent(row)">{{ t('export') }}</el-button>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<el-button type="primary" class="w-full" link @click="copyEvent(row.form_id)">{{ t('复制') }}</el-button>
|
||||
<el-button type="primary" class="w-full" link @click="copyEvent(row.form_id)">{{ t('copy') }}</el-button>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
@ -239,12 +239,14 @@ const addEvent = async (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
|
||||
const showClick = (row: any) => {
|
||||
row.status = row.status === 1 ? 0 : 1
|
||||
const data = row.status === 1 ? 0 : 1
|
||||
const obj = {
|
||||
form_id: row.form_id,
|
||||
status: row.status,
|
||||
status: data
|
||||
}
|
||||
editFormStatus(obj)
|
||||
editFormStatus(obj).then((res) => {
|
||||
row.status = data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取万能表单类型
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<el-drawer v-model="showDialog" :title="t('数据与统计')" direction="rtl" size="70%" :before-close="handleClose" class="member-detail-drawer">
|
||||
<el-drawer v-model="showDialog" :title="t('dataAndStatistics')" direction="rtl" size="70%" :before-close="handleClose" class="member-detail-drawer">
|
||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane :label="t('明细数据')" name="detail_data">
|
||||
<el-tab-pane :label="t('detailData')" name="detail_data">
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="formData.searchParam" ref="searchFormDiyFormRef">
|
||||
<el-form-item :label="t('填表人')" prop="keyword">
|
||||
<el-input v-model.trim="formData.searchParam.keyword" placeholder="请输入填表人" />
|
||||
<el-form-item :label="t('fillInFormPerson')" prop="keyword">
|
||||
<el-input v-model.trim="formData.searchParam.keyword" :placeholder="t('fillInFormPersonplaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('填表时间')" prop="create_time">
|
||||
<el-form-item :label="t('fillInFormDate')" prop="create_time">
|
||||
<el-date-picker v-model="formData.searchParam.create_time" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
@ -22,7 +22,7 @@
|
||||
<template #empty>
|
||||
<span>{{ !formData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column fixed :label="t('填表人信息')" min-width="160">
|
||||
<el-table-column fixed :label="t('fillInFormPersonInfo')" min-width="160">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer" @click="detailEvent(row.member.member_id)">
|
||||
<div class="min-w-[50px] h-[50px] flex items-center justify-center">
|
||||
@ -42,7 +42,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed prop="create_time" :label="t('填表时间')" min-width="120" />
|
||||
<el-table-column fixed prop="create_time" :label="t('fillInFormDate')" min-width="120" />
|
||||
|
||||
<el-table-column v-for="item in formFieldsList" :key="item.field_key" :label="item.field_name" min-width="200">
|
||||
<template #default="{ row }">
|
||||
@ -67,11 +67,11 @@
|
||||
@size-change="loadFormRecordsListFn()" @current-change="loadFormRecordsListFn" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="t('填表人统计')" name="member_stat">
|
||||
<el-tab-pane :label="t('fillInFormPersonStatics')" name="member_stat">
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="formMemberList.searchParam" ref="searchFormDiyMemberRef">
|
||||
<el-form-item :label="t('填表人')" prop="keyword">
|
||||
<el-input v-model.trim="formMemberList.searchParam.keyword" placeholder="请输入填表人" />
|
||||
<el-form-item :label="t('fillInFormPerson')" prop="keyword">
|
||||
<el-input v-model.trim="formMemberList.searchParam.keyword" :placeholder="t('fillInFormPersonplaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getFormRecordsMemberFn()">{{ t('search') }}</el-button>
|
||||
@ -84,7 +84,7 @@
|
||||
<template #empty>
|
||||
<span>{{ !formMemberList.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column fixed :label="t('填表人信息')" min-width="200">
|
||||
<el-table-column fixed :label="t('fillInFormPersonInfo')" min-width="200">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer" @click="detailEvent(row.member.member_id)">
|
||||
<div class="min-w-[50px] h-[50px] flex items-center justify-center">
|
||||
@ -105,7 +105,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column fixed prop="create_time" :label="t('填表时间')" min-width="120" /> -->
|
||||
<el-table-column fixed prop="create_time" :label="t('总计(表单填写数)')" min-width="500">
|
||||
<el-table-column fixed prop="create_time" :label="t('fillInFormTotal')" min-width="500">
|
||||
<template #default="{ row }" @click="">
|
||||
{{ row.write_count }}
|
||||
</template>
|
||||
@ -119,7 +119,14 @@
|
||||
</div>
|
||||
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="t('字段统计')" name="field_stat">
|
||||
<el-tab-pane :label="t('fieldStatistics')" name="field_stat">
|
||||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="formData.searchParam" ref="searchFormDiyFieldsRef">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="exportFieldsEvent">{{ t('export') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-collapse v-model="activeNames" class="diy-collapse mt-[15px]">
|
||||
<el-collapse-item :title="item.field_name" :name="item.field_id" v-for="(item, index) in formFieldsStat" :key="index">
|
||||
<template #title>
|
||||
@ -143,7 +150,7 @@
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<el-dialog v-model="dialogVisible" :title="t('查看信息')" width="400px">
|
||||
<el-dialog v-model="dialogVisible" :title="t('viewInformation')" width="400px">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex mb-[10px]" v-for="(item, index) in formDetail" :key="index">
|
||||
<div class="flex justify-end w-[100px]">{{ item.label }}:</div>
|
||||
@ -166,6 +173,7 @@
|
||||
</el-drawer>
|
||||
<export-sure ref="exportSureDialog" :show="flag" type="diy_form_records" :searchParam="formData.searchParam" @close="handleExportClose" />
|
||||
<export-sure ref="exportSureDialog" :show="flagMember" type="diy_form_records_member" :searchParam="formMemberList.searchParam" @close="handleMemberExportClose" />
|
||||
<export-sure ref="exportSureDialog" :show="flagFields" type="diy_form_records_fields" :searchParam="formData.searchParam" @close="handleFieldsExportClose" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@ -184,6 +192,7 @@ const formId = ref(0)
|
||||
const dialogVisible = ref(false)
|
||||
const searchFormDiyFormRef = ref<FormInstance>()
|
||||
const searchFormDiyMemberRef = ref<FormInstance>()
|
||||
const searchFormDiyFieldsRef = ref<FormInstance>()
|
||||
const handleClose = (done: () => void) => {
|
||||
showDialog.value = false;
|
||||
}
|
||||
@ -236,7 +245,7 @@ const formDetailEvent = (row: any) => {
|
||||
|
||||
// 删除
|
||||
const deleteEvent = (row: any) => {
|
||||
ElMessageBox.confirm(t('确定删除该条数据吗'), t('warning'),
|
||||
ElMessageBox.confirm(t('deleteTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
@ -355,6 +364,14 @@ const exportMemberEvent = () => {
|
||||
flagMember.value = true
|
||||
}
|
||||
|
||||
const flagFields = ref(false)
|
||||
const handleFieldsExportClose = (val) => {
|
||||
flagFields.value = val
|
||||
}
|
||||
const exportFieldsEvent = () => {
|
||||
flagFields.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDialog,
|
||||
setFormData
|
||||
|
||||
@ -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,23 +605,25 @@ 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)
|
||||
memberTransfer({ ...formTransfer }).then(res => {
|
||||
transferShowDialog.value = false
|
||||
loadOrderList()
|
||||
}).catch(() => {
|
||||
transferShowDialog.value = false
|
||||
loadOrderList()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
const transferFn = (data:any) => {
|
||||
memberTransfer({ ...data }).then(res => {
|
||||
transferShowDialog.value = false
|
||||
loadOrderList()
|
||||
}).catch(() => {
|
||||
transferShowDialog.value = false
|
||||
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()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -127,13 +127,11 @@
|
||||
<span class="mr-3" v-if="copyright.company_name">{{ copyright.company_name }}</span>
|
||||
</a>
|
||||
<a href="https://beian.miit.gov.cn/" v-if="copyright.icp" target="_blank">
|
||||
<span class="mr-3">备案号: {{ copyright.icp }}</span>
|
||||
<span class="mr-3">{{ copyright.icp }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<span class="mx-1" @click="getInfoFn">版权信息</span>
|
||||
<!-- | <span class="mx-1">隐私政策</span> | <span class="mx-1">联系我们</span> -->
|
||||
<!-- 版权信息 | 开发者联盟与隐私的声明 | 隐私政策 | 联系我们 | Cookies -->
|
||||
<div class="flex items-center cursor-pointer">
|
||||
<span class="mx-1" @click="getInfoFn">版权信息</span> | <span class="mx-1">开发者联盟与隐私的声明</span> | <span class="mx-1">隐私政策</span> | <span class="mx-1">联系我们</span> | <span class="mx-1">Cookies</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -35,6 +35,15 @@
|
||||
</div>
|
||||
<img src="@/app/assets/images/tools/sys_dict_list.png" class="w-[256px] h-[128px]" />
|
||||
</div>
|
||||
<div class="w-[256px] tools-item-shadow mb-[24px] mx-[14px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/update_cache')">
|
||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col">
|
||||
<span class="text-[16px] text-[#222] font-bold">更新缓存</span>
|
||||
<div class="text-[13px] text-[#6D7278] leading-[18px] mt-[8px] truncate">
|
||||
更新缓存
|
||||
</div>
|
||||
</div>
|
||||
<img src="@/app/assets/images/tools/tools_Update_cache.png" class="w-[256px] h-[128px]" />
|
||||
</div>
|
||||
<div class="w-[256px] tools-item-shadow m-[20px] !mr-[0px] !mt-[0px] rounded-[8px] flex flex-col cursor-pointer leading-[1]" @click="toLink('/admin/tools/detection')">
|
||||
<div class="flex-1 pt-[18px] pb-[14px] px-[24px] flex flex-col bg-[var(--el-bg-color)]">
|
||||
<span class="text-[16px] font-bold">环境监测</span>
|
||||
|
||||
@ -144,27 +144,27 @@ const formRules = reactive<FormRules>({
|
||||
{ required: true, message: t('daySignAwardPlaceholder'), trigger: 'change' }
|
||||
],
|
||||
sign_period:[{
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (value === null || value === '') {
|
||||
callback(t('signPeriodTip'))
|
||||
}else if (isNaN(value) || !regExp.number.test(value)) {
|
||||
callback(t('signPeriodLimitTips'))
|
||||
}else if (value < 2 || value > 365) {
|
||||
callback(t('signPeriodMustZeroTips'))
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
required: true,
|
||||
trigger: 'blur',
|
||||
validator: (rule: any, value: any, callback: any) => {
|
||||
if (value === null || value === '') {
|
||||
callback(t('signPeriodTip'))
|
||||
}else if (isNaN(value) || !regExp.number.test(value)) {
|
||||
callback(t('signPeriodLimitTips'))
|
||||
}else if (value < 2 || value > 365) {
|
||||
callback(t('signPeriodMustZeroTips'))
|
||||
} else {
|
||||
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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('memberLevel')" prop="member_label">
|
||||
<el-form-item :label="t('memberLevel')" prop="member_level">
|
||||
<el-select v-model="memberTableData.searchParam.member_level" collapse-tags clearable :placeholder="t('memberLevelPlaceholder')" class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item['level_name']" :value="item['level_id']" v-for="(item, index) in levelSelectData" :key="index" />
|
||||
@ -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,9 +229,9 @@ 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'
|
||||
import { initPoster, addPoster, editPoster, getPosterTemplate, getPreviewPoster } from '@/app/api/poster'
|
||||
|
||||
const setLayout = inject('setLayout')
|
||||
setLayout('decorate')
|
||||
@ -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,51 +416,51 @@ 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({
|
||||
id: route.query.id,
|
||||
type: route.query.type,
|
||||
name: route.query.name
|
||||
}).then( async (res:any)=>{
|
||||
}).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
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
<h3 class="panel-title !text-sm">{{ t('themeColor') }}</h3>
|
||||
<div class="">
|
||||
<el-color-picker v-model="themeColor[currAddon]" size="large" />
|
||||
<div class="form-tip text-[#999] mt-2">设置的色调会在前端站点列表体现</div>
|
||||
<div class="form-tip text-[#999] mt-2">设置的色调会在前端站点列表体现[home/index],用于区分不同的应用</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
@ -120,9 +120,11 @@ getInstalledAddonList().then(({ data }) => {
|
||||
const getLayoutConfig = () => {
|
||||
getLayout().then(({ data }) => {
|
||||
layoutConfig.value = data
|
||||
console.log('getLayoutConfig - layoutConfig', layoutConfig.value)
|
||||
})
|
||||
getThemecolor().then(({ data }) => {
|
||||
themeColor.value = data
|
||||
console.log('getLayoutConfig - themeColor', themeColor.value)
|
||||
})
|
||||
}
|
||||
getLayoutConfig()
|
||||
|
||||
@ -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>
|
||||
|
||||
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>
|
||||
@ -42,11 +42,11 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('password')" prop="password">
|
||||
<el-input v-model.trim="formData.password" clearable :placeholder="t('passwordPlaceholder')" class="input-width" :show-password="true" type="password" :readonly="password_input" @click="inputClick('password_input')" @blur="password_input = true" />
|
||||
<el-input v-model.trim="formData.password" autocomplete="off" clearable :placeholder="t('passwordPlaceholder')" class="input-width" :show-password="true" type="password" :readonly="password_input" @click="inputClick('password_input')" @blur="password_input = true" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('confirmPassword')" prop="confirm_password">
|
||||
<el-input v-model.trim="formData.confirm_password" :placeholder="t('confirmPasswordPlaceholder')" type="password" :show-password="true" clearable class="input-width" :readonly="confirm_password_input" @click="inputClick('confirm_password_input')" @blur="confirm_password_input = true" />
|
||||
<el-input v-model.trim="formData.confirm_password" autocomplete="off" :placeholder="t('confirmPasswordPlaceholder')" type="password" :show-password="true" clearable class="input-width" :readonly="confirm_password_input" @click="inputClick('confirm_password_input')" @blur="confirm_password_input = true" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -73,8 +73,11 @@ import { t } from '@/lang'
|
||||
import { FormInstance } from 'element-plus'
|
||||
import { getSiteGroupAll } from '@/app/api/site'
|
||||
import { addUser, getUserInfo, editUser } from '@/app/api/user'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import Test from '@/utils/test'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(true)
|
||||
const formData = ref({
|
||||
@ -95,13 +98,13 @@ const formRules = computed(() => {
|
||||
{ required: true, message: t('usernamePlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: formData.value.uid == 0, message: t('passwordPlaceholder'), trigger: 'blur' }
|
||||
{ required: userStore.userInfo && userStore.userInfo.is_super_admin == true, message: t('passwordPlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
real_name: [
|
||||
{ required: true, message: t('userRealNamePlaceholder'), trigger: 'blur' }
|
||||
],
|
||||
confirm_password: [
|
||||
{ required: formData.value.uid == 0, message: t('confirmPasswordPlaceholder'), trigger: 'blur' },
|
||||
{ required: userStore.userInfo && userStore.userInfo.is_super_admin == true, message: t('confirmPasswordPlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value != formData.value.password) callback(new Error(t('confirmPasswordError')))
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<el-checkbox-group v-model="formData.app" class="flex flex-wrap w-full" v-else>
|
||||
<template #default>
|
||||
<div class="flex w-[300px]" v-for="(item, index) in appList" :key="index">
|
||||
<el-checkbox :label="item.key" name="" class="w-full !h-auto border border-[var(--el-color-info-light-7)] border-solid p-[10px] !mr-[10px] !mb-[10px] rounded-md">
|
||||
<el-checkbox :label="item.key" class="w-full !h-auto border border-[var(--el-color-info-light-7)] border-solid p-[10px] !mr-[10px] !mb-[10px] rounded-md">
|
||||
<template #default>
|
||||
<div class="w-full">
|
||||
<div class="flex">
|
||||
@ -28,7 +28,9 @@
|
||||
<el-image v-else class="w-full h-full">
|
||||
<template #error>
|
||||
<div class="image-error">
|
||||
<el-icon><icon-picture /></el-icon>
|
||||
<el-icon>
|
||||
<icon-picture />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
@ -51,7 +53,7 @@
|
||||
<el-checkbox-group v-model="formData.addon" class="flex flex-wrap w-full" v-else>
|
||||
<template #default>
|
||||
<div class="flex w-[300px]" v-for="(item, index) in addonList" :key="index">
|
||||
<el-checkbox :label="item.key" name="" class="w-full !h-auto border border-[var(--el-color-info-light-7)] border-solid p-[10px] !mr-[10px] !mb-[10px] rounded-md">
|
||||
<el-checkbox :label="item.key" :disabled="item.disabled" @click="prompt(item)" class="w-full !h-auto border border-[var(--el-color-info-light-7)] border-solid p-[10px] !mr-[10px] !mb-[10px] rounded-md">
|
||||
<template #default>
|
||||
<div class="w-full">
|
||||
<div class="flex">
|
||||
@ -60,7 +62,9 @@
|
||||
<el-image v-else class="w-full h-full">
|
||||
<template #error>
|
||||
<div class="image-error">
|
||||
<el-icon><icon-picture /></el-icon>
|
||||
<el-icon>
|
||||
<icon-picture />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</el-image>
|
||||
@ -90,14 +94,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup async>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { ElMessage, FormInstance } from 'element-plus'
|
||||
import { ArrowLeft } from '@element-plus/icons-vue'
|
||||
import { menuRefresh } from '@/app/api/sys'
|
||||
import { addSiteGroup, editSiteGroup, getSiteGroupInfo } from '@/app/api/site'
|
||||
import { getInstalledAddonList } from '@/app/api/addon'
|
||||
import { img, deepClone } from '@/utils/common'
|
||||
import { deepClone } from '@/utils/common'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
const loading = ref(true)
|
||||
@ -119,8 +123,16 @@ const formData: Record<string, any> = ref({
|
||||
addon: []
|
||||
})
|
||||
|
||||
let installAddon = []
|
||||
const getInstalledAddonListFn = async () => {
|
||||
watch(() => formData.value.app, (val) => {
|
||||
checkAddon()
|
||||
}, { deep: true })
|
||||
|
||||
watch(() => formData.value.addon, (val) => {
|
||||
checkAddon()
|
||||
}, { deep: true })
|
||||
|
||||
const installAddon = []
|
||||
const getInstalledAddonListFn = async() => {
|
||||
await getInstalledAddonList().then(({ data }) => {
|
||||
const apps: any[] = []
|
||||
const addons: any[] = []
|
||||
@ -128,18 +140,20 @@ const getInstalledAddonListFn = async () => {
|
||||
Object.keys(data).forEach(key => {
|
||||
installAddon.push(key)
|
||||
const item = data[key]
|
||||
item.disabled = false
|
||||
item.type == 'addon' ? addons.push(item) : apps.push(item)
|
||||
})
|
||||
|
||||
appList.value = apps
|
||||
addonList.value = addons
|
||||
checkAddon()
|
||||
}).catch()
|
||||
}
|
||||
getInstalledAddonListFn()
|
||||
|
||||
if (route.query.id) {
|
||||
getSiteGroupInfo(route.query.id).then((res) => {
|
||||
let data = deepClone(res.data)
|
||||
const data = deepClone(res.data)
|
||||
formData.value = data
|
||||
loading.value = false
|
||||
}).catch()
|
||||
@ -169,11 +183,11 @@ const formRules = computed(() => {
|
||||
* 确认
|
||||
* @param formEl
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
const confirm = async(formEl: FormInstance | undefined) => {
|
||||
if (saveLoading.value || !formEl) return
|
||||
const save = formData.value.group_id ? editSiteGroup : addSiteGroup
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
await formEl.validate(async(valid) => {
|
||||
if (valid) {
|
||||
saveLoading.value = true
|
||||
save(formData.value).then(res => {
|
||||
@ -189,18 +203,49 @@ const confirm = async (formEl: FormInstance | undefined) => {
|
||||
}
|
||||
const menuRefreshFn = () => {
|
||||
menuRefresh({}).then(res => {
|
||||
}).catch(() => {})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
|
||||
// 检测插件是否禁用
|
||||
const checkAddon = () => {
|
||||
addonList.value.forEach((addon: any) => {
|
||||
// 找到插件
|
||||
if (addon.support_app == '' || formData.value.app.indexOf(addon.support_app) != -1) {
|
||||
addon.disabled = false
|
||||
} else {
|
||||
// 如果未选中应用,则移除已选中的关联插件
|
||||
addon.disabled = true
|
||||
if (formData.value.addon.indexOf(addon.key) != -1) {
|
||||
formData.value.addon.splice(formData.value.addon.indexOf(addon.key), 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const prompt = (item: any) => {
|
||||
if (item.disabled && item.support_app) {
|
||||
const currApp: any = appList.value.filter((app: any) => {
|
||||
return app.key == item.support_app
|
||||
})
|
||||
if (currApp.length) {
|
||||
ElMessage({
|
||||
message: `请先选择 ${ currApp[0].title } 应用`,
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.image-error {
|
||||
background: var(--el-border-color-extra-light);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.image-error {
|
||||
background: var(--el-border-color-extra-light);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.el-checkbox__label) {
|
||||
width: 100%;
|
||||
}
|
||||
:deep(.el-checkbox__label) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
<div class="flex items-center">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.logo" :src="img(row.logo)" alt="">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/app/assets/images/site_logo.png" alt="">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.site_name || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -87,7 +87,7 @@
|
||||
<el-table-column :label="t('manager')" width="150" align="left">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center">
|
||||
<div class="flex flex flex-col">
|
||||
<div class="flex flex-col">
|
||||
<span>{{ row.admin.username || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
56
admin/src/app/views/tools/updatecache.vue
Normal file
56
admin/src/app/views/tools/updatecache.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<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('dataCache')}}</span>
|
||||
<span class="text-xs text-gray-400 mt-1 truncate w-[190px]" :title="t('dataCacheDesc')">{{t('dataCacheDesc')}}</span>
|
||||
</div>
|
||||
<span class="plug-item-operate" @click="schemaCache()">{{t('refresh')}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
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
|
||||
clearCache({}).then(res => {
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.demo-tabs > .el-tabs__content {
|
||||
padding: 32px;
|
||||
color: #6b778c;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.plug-item{
|
||||
.plug-item-operate{
|
||||
@apply text-xs absolute right-3 cursor-pointer;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -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"
|
||||
:class="[item.name == parentLinkName ? 'bg-primary-light-9 text-primary' : '']"
|
||||
@click="changeParentLink(item)">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<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)">
|
||||
<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=" ">
|
||||
@ -77,9 +92,9 @@
|
||||
</template>
|
||||
<div v-else class="flex flex-wrap">
|
||||
<div v-for="(item, index) in childList" :key="index"
|
||||
class="border border-br rounded-[3px] mr-[10px] mb-[10px] px-4 h-[32px] leading-[32px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
|
||||
class="border border-br rounded-[3px] mr-[10px] mb-[10px] px-4 h-[32px] leading-[32px] cursor-pointer hover:bg-primary-light-9 px-[10px] hover:text-primary"
|
||||
:class="{ 'border-primary text-primary': (parentLinkName != 'DIY_PAGE' && item.name == selectLink.name) || (parentLinkName == 'DIY_PAGE' && item.url == selectLink.url) }"
|
||||
@click="changeChildLink(item)">{{ item.title }}
|
||||
@click="changeChildLink(item)">{{ item.title }}
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
@ -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,21 +121,22 @@ import { ElMessage } from 'element-plus'
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => { }
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
ignore:{
|
||||
type:Array,
|
||||
default:[]
|
||||
ignore: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'confirm','success'])
|
||||
const emit = defineEmits(['update:modelValue', 'confirm', 'success'])
|
||||
|
||||
const value: any = computed({
|
||||
get () {
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set (value) {
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
@ -135,17 +151,37 @@ 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) {
|
||||
if (link.value[key].name == parentLinkName.value) {
|
||||
changeParentLink(link.value[key])
|
||||
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])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,7 +191,7 @@ const show = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const getLinkFn = (callback:any=null)=> {
|
||||
const getLinkFn = (callback: any = null) => {
|
||||
getLink({}).then((res: any) => {
|
||||
link.value = res.data
|
||||
if (prop.ignore && prop.ignore.length) {
|
||||
@ -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,7 +387,10 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.link-input .el-input__inner{
|
||||
cursor: pointer;
|
||||
}
|
||||
.link-wrap{
|
||||
|
||||
}
|
||||
.link-input .el-input__inner {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -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'
|
||||
@ -33,10 +35,10 @@ const imageRef: Record<string, any> | null = ref(null)
|
||||
const videoRef: Record<string, any> | null = ref(null)
|
||||
|
||||
const content = computed({
|
||||
get () {
|
||||
get() {
|
||||
return prop.modelValue
|
||||
},
|
||||
set (value) {
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
@ -60,7 +62,8 @@ const editorConfig = ref({
|
||||
initialFrameHeight: prop.height,
|
||||
// 初始容器宽度
|
||||
initialFrameWidth: '100%',
|
||||
toolbarCallback: function(cmd, editor) {
|
||||
wordCount: true,
|
||||
toolbarCallback: function (cmd, editor) {
|
||||
editorEl = editor
|
||||
switch (cmd) {
|
||||
case 'insertimage':
|
||||
@ -72,6 +75,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">
|
||||
|
||||
|
||||
@ -202,6 +202,9 @@ import storage from '@/utils/storage'
|
||||
|
||||
const attachmentCategoryName = ref('')
|
||||
const operate = ref(false)
|
||||
|
||||
const repeat = ref(false)
|
||||
|
||||
const prop = defineProps({
|
||||
// 选择数量限制
|
||||
limit: {
|
||||
@ -261,7 +264,6 @@ const attachmentParam = reactive({
|
||||
* 查询分组
|
||||
*/
|
||||
const getAttachmentCategoryList = debounce(() => {
|
||||
|
||||
const getFn = prop.type == 'icon' ? getIconCategoryList : attachmentCategoryList
|
||||
getFn({
|
||||
type: prop.type,
|
||||
@ -304,6 +306,7 @@ const getAttachmentList = debounce((page: number = 1) => {
|
||||
attachment.loading = false
|
||||
})
|
||||
})
|
||||
|
||||
getAttachmentList()
|
||||
|
||||
watch(() => attachmentParam.cate_id, () => {
|
||||
@ -314,14 +317,18 @@ watch(() => attachmentParam.cate_id, () => {
|
||||
* 添加分组
|
||||
*/
|
||||
const addAttachmentCategory = (name: string) => {
|
||||
if (repeat.value) return
|
||||
repeat.value = true
|
||||
|
||||
addCategory({
|
||||
type: prop.type,
|
||||
name
|
||||
}).then(res => {
|
||||
repeat.value = false
|
||||
attachmentCategoryName.value = ''
|
||||
getAttachmentCategoryList(1)
|
||||
}).catch(() => {
|
||||
|
||||
repeat.value = false
|
||||
})
|
||||
}
|
||||
|
||||
@ -331,13 +338,16 @@ const addAttachmentCategory = (name: string) => {
|
||||
* @param index
|
||||
*/
|
||||
const updateAttachmentCategory = (name: string, index: number) => {
|
||||
if (repeat.value) return
|
||||
repeat.value = true
|
||||
updateCategory({
|
||||
id: attachmentCategory.data[index].id,
|
||||
name
|
||||
}).then(res => {
|
||||
repeat.value = false
|
||||
attachmentCategory.data[index].name = name
|
||||
}).catch(() => {
|
||||
|
||||
repeat.value = false
|
||||
})
|
||||
}
|
||||
|
||||
@ -345,6 +355,8 @@ const updateAttachmentCategory = (name: string, index: number) => {
|
||||
* 删除分组
|
||||
*/
|
||||
const deleteAttachmentCategory = (index: number) => {
|
||||
if (repeat.value) return
|
||||
repeat.value = true
|
||||
ElMessageBox.confirm(t('upload.deleteCategoryTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
@ -354,7 +366,9 @@ const deleteAttachmentCategory = (index: number) => {
|
||||
).then(() => {
|
||||
deleteCategory(attachmentCategory.data[index].id).then(() => {
|
||||
attachmentCategory.data.splice(index, 1)
|
||||
repeat.value = false
|
||||
}).catch(() => {
|
||||
repeat.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -387,7 +401,7 @@ const upload = computed(() => {
|
||||
clearTimeout(time.value)
|
||||
time.value=null
|
||||
},500)
|
||||
|
||||
|
||||
}else{
|
||||
clearTimeout(time.value)
|
||||
time.value=null
|
||||
|
||||
@ -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": "请选择表单"
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="['layout-aside ease-in duration-200 flex ', { 'bright': !dark }]">
|
||||
<div :class="['layout-aside ease-in duration-200 flex border-t-[1px] border-solid border-[var(--el-color-info-light-8)] box-border', { 'bright': !dark }]">
|
||||
<div class="flex flex-col border-0 border-r-[1px] border-solid border-[var(--el-color-info-light-8)] box-border">
|
||||
<!-- <div class="w-full h-[64px] flex justify-center items-center w-[65px]flex-shrink-0">
|
||||
<div class="w-[40px] h-[40px] rounded-[50%] overflow-hidden">
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
<el-container class="h-[64px] w-full layout-admin flex items-center justify-between px-[15px]" >
|
||||
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
||||
<div class="flex items-center">
|
||||
<div class="w-[120px] flex justify-center items-center flex-shrink-0">
|
||||
<div class="w-[120px] h-[40px] overflow-hidden">
|
||||
<div class="max-w-[120px] flex justify-center items-center flex-shrink-0">
|
||||
<div class="max-w-[120px] h-[40px] overflow-hidden">
|
||||
<el-image style="width: 100%; height: 100%" :src="img(logoUrl)" fit="contain">
|
||||
<template #error>
|
||||
<div class="flex justify-center items-center w-full h-full"><img class="max-w-[120px]" src="@/app/assets/images/logo.default.png" alt="" object-fit="contain"></div>
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
<el-container class="h-[64px] layout-admin flex items-center justify-between px-[15px]" >
|
||||
<!-- :class="['h-full px-[10px]',{'layout-header border-b border-color': !dark}]" -->
|
||||
<div class="flex items-center">
|
||||
<div class="w-[120px] flex justify-center items-center flex-shrink-0">
|
||||
<div class="w-[120px] h-[40px] overflow-hidden">
|
||||
<div class="max-w-[120px] flex justify-center items-center flex-shrink-0">
|
||||
<div class="max-w-[120px] h-[40px] overflow-hidden">
|
||||
<el-image class="w-full h-full" :src="img(website.icon)" fit="contain">
|
||||
<template #error>
|
||||
<div class="flex justify-center items-center w-full h-full"><img class="max-w-[120px]" src="@/app/assets/images/logo.default.png" alt="" object-fit="contain"></div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user