mirror of
https://gitee.com/niucloud-team/niucloud.git
synced 2026-03-13 15:21:17 +00:00
admin
This commit is contained in:
parent
d0850818d2
commit
40ce047612
7
admin/components.d.ts
vendored
7
admin/components.d.ts
vendored
@ -10,6 +10,7 @@ declare module '@vue/runtime-core' {
|
||||
Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default']
|
||||
DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
|
||||
Editor: typeof import('./src/components/editor/index.vue')['default']
|
||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
||||
@ -17,12 +18,14 @@ declare module '@vue/runtime-core' {
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCard: typeof import('element-plus/es')['ElCard']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElCol: typeof import('element-plus/es')['ElCol']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
|
||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
@ -39,10 +42,12 @@ declare module '@vue/runtime-core' {
|
||||
ElImage: typeof import('element-plus/es')['ElImage']
|
||||
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElOptionGroup: typeof import('element-plus/es')['ElOptionGroup']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
@ -58,7 +63,9 @@ declare module '@vue/runtime-core' {
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
ElTree: typeof import('element-plus/es')['ElTree']
|
||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
Icon: typeof import('./src/components/icon/index.vue')['default']
|
||||
PopoverInput: typeof import('./src/components/popover-input/index.vue')['default']
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image" href="/niucloud.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>管理端</title>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@ -1,51 +1,53 @@
|
||||
{
|
||||
"name": "admin",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@vueuse/core": "^9.12.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.3.1",
|
||||
"css-color-function": "^1.3.3",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "^2.2.29",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.30",
|
||||
"qrcode": "^1.5.1",
|
||||
"sass": "^1.58.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-video-play": "^1.3.1-beta.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/line-clamp": "^0.4.2",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/sortablejs": "^1.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-standard-with-typescript": "^34.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-n": "^15.6.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"postcss": "^8.4.21",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"typescript": "^4.9.5",
|
||||
"unplugin-auto-import": "^0.13.0",
|
||||
"unplugin-vue-components": "^0.23.0",
|
||||
"vite": "^4.1.0",
|
||||
"vue-tsc": "^1.0.24"
|
||||
}
|
||||
"name": "admin",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@vueuse/core": "^9.12.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.4.0",
|
||||
"crypto-js": "^4.1.1",
|
||||
"css-color-function": "^1.3.3",
|
||||
"echarts": "^5.4.1",
|
||||
"element-plus": "^2.2.29",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.30",
|
||||
"qrcode": "^1.5.1",
|
||||
"sass": "^1.58.0",
|
||||
"sortablejs": "^1.15.0",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-web-terminal": "^3.1.7",
|
||||
"vue3-video-play": "^1.3.1-beta.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/line-clamp": "^0.4.2",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/sortablejs": "^1.15.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.53.0",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-config-standard-with-typescript": "^34.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-n": "^15.6.1",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"postcss": "^8.4.21",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"typescript": "^4.9.5",
|
||||
"unplugin-auto-import": "^0.13.0",
|
||||
"unplugin-vue-components": "^0.23.0",
|
||||
"vite": "^4.1.0",
|
||||
"vue-tsc": "^1.0.24"
|
||||
}
|
||||
}
|
||||
|
||||
35
admin/src/api/addon.ts
Normal file
35
admin/src/api/addon.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 本地下载的插件列表
|
||||
* @returns
|
||||
*/
|
||||
export function getAddonLocal(params: Record<string, any>) {
|
||||
return request.get('addon/local', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件详情
|
||||
* @returns
|
||||
*/
|
||||
export function getAddonDetial(id: number) {
|
||||
return request.get(`addon/${id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 安装插件
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function installAddon(params: Record<string, any>) {
|
||||
return request.post(`addon/install/${params.addon}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载插件
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function uninstallAddon(params: Record<string, any>) {
|
||||
return request.post(`addon/uninstall/${params.addon}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
@ -35,7 +35,7 @@ export function addArticle(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateArticle(params: Record<string, any>) {
|
||||
export function editArticle(params: Record<string, any>) {
|
||||
return request.put(`article/article/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ export function addArticleCategory(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateArticleCategory(params: Record<string, any>) {
|
||||
export function editArticleCategory(params: Record<string, any>) {
|
||||
return request.put(`article/category/${params.category_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ import request from '@/utils/request'
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function login(params: Record<string, any>) {
|
||||
return request.get('login', { params, showErrorMessage: true })
|
||||
export function login(params: Record<string, any>, app_type: string) {
|
||||
return request.get(`login/${app_type}`, { params, showErrorMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,4 +23,12 @@ export function getAuthMenus() {
|
||||
*/
|
||||
export function getSiteInfo() {
|
||||
return request.get('auth/site')
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录配置信息
|
||||
* @returns
|
||||
*/
|
||||
export function getLoginConfig() {
|
||||
return request.get('login/config')
|
||||
}
|
||||
@ -8,7 +8,7 @@ import request from '@/utils/request'
|
||||
* @returns
|
||||
*/
|
||||
export function getDiyPageList(params: Record<string, any>) {
|
||||
return request.get(`diy/diy`, {params})
|
||||
return request.get(`diy/diy`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,15 +26,15 @@ export function getDiyPageInfo(id: number) {
|
||||
* @returns
|
||||
*/
|
||||
export function addDiyPage(params: Record<string, any>) {
|
||||
return request.post('diy/diy', params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
return request.post('diy/diy', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑自定义页面
|
||||
* @param params
|
||||
*/
|
||||
export function updateDiyPage(params: Record<string, any>) {
|
||||
return request.put(`diy/diy/${params.id}`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
export function editDiyPage(params: Record<string, any>) {
|
||||
return request.put(`diy/diy/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -42,15 +42,15 @@ export function updateDiyPage(params: Record<string, any>) {
|
||||
* @param params
|
||||
*/
|
||||
export function setUseDiyPage(params: Record<string, any>) {
|
||||
return request.put(`diy/use`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
return request.put(`diy/use`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改自定义页面分享内容
|
||||
* @param params
|
||||
*/
|
||||
export function updateDiyPageShare(params: Record<string, any>) {
|
||||
return request.put(`diy/diy/share`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
export function editDiyPageShare(params: Record<string, any>) {
|
||||
return request.put(`diy/diy/share`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,28 +59,28 @@ export function updateDiyPageShare(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function deleteDiyPage(id: number) {
|
||||
return request.delete(`diy/diy/${id}`, {showErrorMessage: true, showSuccessMessage: true})
|
||||
return request.delete(`diy/diy/${id}`, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义页面初始化数据
|
||||
*/
|
||||
export function initPage(params: Record<string, any>) {
|
||||
return request.get(`diy/init`, {params})
|
||||
return request.get(`diy/init`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义链接列表
|
||||
*/
|
||||
export function getLink(params: Record<string, any>) {
|
||||
return request.get(`diy/link`, {params})
|
||||
return request.get(`diy/link`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取底部导航数据
|
||||
*/
|
||||
export function getDiyBottom(params: Record<string, any>) {
|
||||
return request.get(`diy/bottom`, {params})
|
||||
return request.get(`diy/bottom`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,14 +89,14 @@ export function getDiyBottom(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function setDiyBottom(params: Record<string, any>) {
|
||||
return request.post('diy/bottom', params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
return request.post('diy/bottom', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面类型
|
||||
*/
|
||||
export function getDiyPageType(params: Record<string, any>) {
|
||||
return request.get(`diy/type`, {params})
|
||||
return request.get(`diy/type`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,13 +105,21 @@ export function getDiyPageType(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getDiyRouteList(params: Record<string, any>) {
|
||||
return request.get(`diy/route`, {params})
|
||||
return request.get(`diy/route`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义路由信息
|
||||
* @param params
|
||||
*/
|
||||
export function getDiyRouteInfo(params: Record<string, any>) {
|
||||
return request.get(`diy/route/info`, { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改路由页面分享内容
|
||||
* @param params
|
||||
*/
|
||||
export function updateDiyRouteShare(params: Record<string, any>) {
|
||||
return request.put(`diy/route/share`, params, {showErrorMessage: true, showSuccessMessage: true})
|
||||
export function editDiyRouteShare(params: Record<string, any>) {
|
||||
return request.put(`diy/route/share`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
@ -9,7 +9,7 @@ import request from '@/utils/request'
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberList(params: Record<string, any>) {
|
||||
return request.get(`member/member`, {params})
|
||||
return request.get(`member/member`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -39,6 +39,15 @@ export function getRegisterType(params: Record<string, any>) {
|
||||
return request.get(`member/registertype`, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员注册渠道
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getRegisterChannelType(params: Record<string, any>) {
|
||||
return request.get(`member/register/channel`, params)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************** 会员标签 ****************************************************/
|
||||
@ -49,7 +58,7 @@ export function getRegisterType(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getMemberLabelList(params: Record<string, any>) {
|
||||
return request.get(`member/label`, {params})
|
||||
return request.get(`member/label`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,20 +113,13 @@ export function getMemberLabelAll() {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMemberDetail(params: Record<string, any>) {
|
||||
export function editMemberDetail(params: Record<string, any>) {
|
||||
return request.put(`member/member/modify/${params.member_id}/${params.field}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 会员零钱 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取会员零钱列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMoneyList(params: Record<string, any>) {
|
||||
return request.get(`member/account/money`, {params})
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************** 会员账户 ****************************************************/
|
||||
@ -146,7 +148,23 @@ export function getPointList(params: Record<string, any>) {
|
||||
*/
|
||||
export function getBalanceList(params: Record<string, any>) {
|
||||
return request.get(`member/account/balance`, { params })
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取会员可提现余额列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMoneyList(params: Record<string, any>) {
|
||||
return request.get(`member/account/money`, { params })
|
||||
}
|
||||
/**
|
||||
* 获取会员佣金列表
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getCommissionList(params: Record<string, any>) {
|
||||
return request.get(`member/account/commission`, { params })
|
||||
}
|
||||
/**
|
||||
* 会员积分调整
|
||||
* @param params
|
||||
@ -154,7 +172,7 @@ export function getBalanceList(params: Record<string, any>) {
|
||||
*/
|
||||
export function adjustPoint(params: Record<string, any>) {
|
||||
return request.post(`member/account/point`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 会员余额调整
|
||||
* @param params
|
||||
@ -162,9 +180,9 @@ export function adjustPoint(params: Record<string, any>) {
|
||||
*/
|
||||
export function adjustBalance(params: Record<string, any>) {
|
||||
return request.post(`member/account/balance`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************** 会员相关设置 ****************************************************/
|
||||
/***************************************************** 会员相关设置 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取登录设置
|
||||
@ -173,7 +191,7 @@ export function adjustBalance(params: Record<string, any>) {
|
||||
*/
|
||||
export function getLoginConfig(params: Record<string, any>) {
|
||||
return request.get(`member/config/login`, params)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 注册登录设置
|
||||
* @param params
|
||||
@ -183,21 +201,58 @@ export function setLoginConfig(params: Record<string, any>) {
|
||||
return request.post(`member/config/login`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员转账方式
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getTransfertype() {
|
||||
return request.get(`member/cash_out/transfertype`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额统计
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getBalanceSum(params: Record<string, any>) {
|
||||
return request.get(`member/account/sum_balance`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 余额类型
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getBalanceStatus() {
|
||||
return request.get(`member/account/type`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取余额变动类型
|
||||
*/
|
||||
export function getAccountType(params: Record<string, any>) {
|
||||
return request.get(`member/account/change_type/${params.account_type}`)
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 会员提现 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取提现设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getWithdrawConfig() {
|
||||
return request.get(`member/config/withdraw`)
|
||||
}
|
||||
return request.get(`member/config/cash_out`)
|
||||
}
|
||||
/**
|
||||
* 设置提现设置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setWithdrawConfig(params: Record<string, any>) {
|
||||
return request.post(`member/config/withdraw`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
return request.post(`member/config/cash_out`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,14 +261,53 @@ export function setWithdrawConfig(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function getWithdrawList(params: Record<string, any>) {
|
||||
return request.get(`member/withdraw`, {params})
|
||||
return request.get(`member/cash_out`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员转账方式
|
||||
* 会员提现详情
|
||||
* @param params
|
||||
* @returns id
|
||||
*/
|
||||
export function getWithdrawDetail(id: number) {
|
||||
return request.get(`member/cash_out/${id}`, {})
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员提现审核
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function memberAudit(params: Record<string, any>) {
|
||||
return request.put(`member/cash_out/audit/${params.id}/${params.action}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员提现转账
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function memberTransfer(params: Record<string, any>) {
|
||||
return request.put(`member/cash_out/transfer/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员状态变更
|
||||
* @param id
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getTransfertype() {
|
||||
return request.get(`member/withdraw/transfertype`)
|
||||
}
|
||||
export function editMemberStatus(params: Record<string, any>) {
|
||||
return request.put(`member/setstatus/${params.status}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员提现状态
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getWithdrawStatusList() {
|
||||
return request.get(`member/cash_out/status`)
|
||||
}
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 消息管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 消息列表
|
||||
* @returns
|
||||
*/
|
||||
export function getMessageList() {
|
||||
return request.get('message/message')
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息详情
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMessageInfo(key: string) {
|
||||
return request.get(`message/message/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发送记录
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getMessageLog(params: any) {
|
||||
return request.get(`message/log`, { params })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 消息启动与关闭
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMessageStatus(params: Record<string, any>) {
|
||||
return request.post(`message/message/updatestatus`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息修改
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMessage(params: Record<string, any>) {
|
||||
return request.post(`message/message/update`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置列表
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsList() {
|
||||
return request.get('message/message/sms')
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置详情
|
||||
* @param sms_type
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsInfo(sms_type: string) {
|
||||
return request.get(`message/message/sms/${sms_type}`,)
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置修改
|
||||
* @param sms_type
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateSms(params: Record<string, any>) {
|
||||
return request.put(`message/message/sms/${params.sms_type}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
85
admin/src/api/notice.ts
Normal file
85
admin/src/api/notice.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/***************************************************** 消息管理 ****************************************************/
|
||||
|
||||
/**
|
||||
* 消息列表
|
||||
* @returns
|
||||
*/
|
||||
export function getNoticeList() {
|
||||
return request.get('notice/notice')
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息详情
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getNoticeInfo(key: string) {
|
||||
return request.get(`notice/notice/${key}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发送记录
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getNoticeLog(params: any) {
|
||||
return request.get(`notice/log`, { params })
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 消息启动与关闭
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function editNoticeStatus(params: Record<string, any>) {
|
||||
return request.post(`notice/notice/editstatus`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息修改
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function editNotice(params: Record<string, any>) {
|
||||
return request.post(`notice/notice/edit`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置列表
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsList() {
|
||||
return request.get('notice/notice/sms')
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置详情
|
||||
* @param sms_type
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsInfo(sms_type: string) {
|
||||
return request.get(`notice/notice/sms/${sms_type}`,)
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信配置修改
|
||||
* @param sms_type
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function editSms(params: Record<string, any>) {
|
||||
return request.put(`notice/notice/sms/${params.sms_type}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信发送记录
|
||||
* @param sms_type
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getSmsLog(params: Record<string, any>) {
|
||||
return request.put(`notice/sms/log`, params)
|
||||
}
|
||||
@ -27,3 +27,27 @@ export function getRechargeOrderInfo(order_id: number) {
|
||||
export function getRechargeOrderStatusList() {
|
||||
return request.get(`order/recharge/status`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款记录
|
||||
* @returns
|
||||
*/
|
||||
export function getRefund(params: Record<string, any>) {
|
||||
return request.get(`refund/refund`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取退款状态
|
||||
* @returns
|
||||
*/
|
||||
export function getRefundStatus() {
|
||||
return request.get(`refund/status`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 充值订单发起退款
|
||||
* @returns
|
||||
*/
|
||||
export function rechargeRefund(id) {
|
||||
return request.get(`order/recharge/refund/${id}`);
|
||||
}
|
||||
@ -4,7 +4,7 @@ import request from '@/utils/request'
|
||||
* 获取支付设置
|
||||
* @returns
|
||||
*/
|
||||
export function getUserInfo(type:string) {
|
||||
export function getUserInfo(type: string) {
|
||||
return request.get(`auth/get`)
|
||||
}
|
||||
|
||||
@ -13,6 +13,6 @@ export function getUserInfo(type:string) {
|
||||
* @returns
|
||||
*/
|
||||
export function setUserInfo(params: Record<string, any>) {
|
||||
return request.put(`auth/update`, params, { showErrorMessage: true, showSuccessMessage: true });
|
||||
return request.put(`auth/edit`, params, { showErrorMessage: true, showSuccessMessage: true });
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import request from '@/utils/request'
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteList(params: Record<string, any>) {
|
||||
return request.get(`site/site`, {params})
|
||||
return request.get(`site/site`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,7 +37,7 @@ export function addSite(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateSite(params: Record<string, any>) {
|
||||
export function editSite(params: Record<string, any>) {
|
||||
return request.put(`site/site/${params.site_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ export function getStatusList() {
|
||||
* @returns
|
||||
*/
|
||||
export function getSiteGroupList(params: Record<string, any>) {
|
||||
return request.get(`site/group`, {params})
|
||||
return request.get(`site/group`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +86,7 @@ export function addSiteGroup(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateSiteGroup(params: Record<string, any>) {
|
||||
export function editSiteGroup(params: Record<string, any>) {
|
||||
return request.put(`site/group/${params.group_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ export function addUser(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateUser(params: Record<string, any>) {
|
||||
export function editUser(params: Record<string, any>) {
|
||||
return request.put(`site/user/${params.uid}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,14 @@ import request from '@/utils/request'
|
||||
export function getInfo() {
|
||||
return request.get('sys/role')
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统信息
|
||||
* @returns
|
||||
*/
|
||||
export function getUrl() {
|
||||
return request.get('sys/url')
|
||||
}
|
||||
/***************************************************** 用户组 ****************************************************/
|
||||
|
||||
/**
|
||||
@ -43,7 +51,7 @@ export function addRole(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateRole(params: Record<string, any>) {
|
||||
export function editRole(params: Record<string, any>) {
|
||||
return request.put(`sys/role/${params.role_id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -70,7 +78,7 @@ export function allRole() {
|
||||
* 获取全部菜单
|
||||
* @returns
|
||||
*/
|
||||
export function getMenus(type:string) {
|
||||
export function getMenus(type: string) {
|
||||
return request.get(`sys/menu/${type}`)
|
||||
}
|
||||
|
||||
@ -98,7 +106,7 @@ export function addMenu(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateMenu(params: Record<string, any>) {
|
||||
export function editMenu(params: Record<string, any>) {
|
||||
return request.put(`sys/menu/${params.menu_key}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -180,7 +188,7 @@ export function addAttachmentCategory(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateAttachmentCategory(params: Record<string, any>) {
|
||||
export function editAttachmentCategory(params: Record<string, any>) {
|
||||
return request.put(`sys/attachment/category/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -208,7 +216,7 @@ export function getAttachmentList(params: Record<string, any>) {
|
||||
* @returns
|
||||
*/
|
||||
export function deleteAttachment(params: Record<string, any>) {
|
||||
return request.delete(`sys/attachment/del`, { data: params, showErrorMessage: true, showSuccessMessage: true})
|
||||
return request.delete(`sys/attachment/del`, { data: params, showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,7 +274,7 @@ export function getStorageInfo(type: string) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateStorage(params: Record<string, any>) {
|
||||
export function editStorage(params: Record<string, any>) {
|
||||
return request.put(`sys/storage/${params.storage_type}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -276,7 +284,7 @@ export function updateStorage(params: Record<string, any>) {
|
||||
* 获取支付设置
|
||||
* @returns
|
||||
*/
|
||||
export function getPayConfig(type:string) {
|
||||
export function getPayConfig(type: string) {
|
||||
return request.get(`pay/config/${type}`)
|
||||
}
|
||||
|
||||
@ -296,13 +304,31 @@ export function getPayList() {
|
||||
return request.get(`pay/lists`)
|
||||
}
|
||||
|
||||
/***************************************************** 打款设置 ****************************************************/
|
||||
/**
|
||||
* 获取打款设置配置
|
||||
* @returns channel 渠道
|
||||
* @returns
|
||||
*/
|
||||
export function getTransferInfo(channel) {
|
||||
return request.get(`pay/channel/lists/${channel}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置打款配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setTransferInfo(params: Record<string, any>) {
|
||||
return request.post(`pay/channel/set/transfer`, params)
|
||||
}
|
||||
/***************************************************** 定时任务 ****************************************************/
|
||||
|
||||
/**
|
||||
* 获取任务列表
|
||||
* @returns
|
||||
*/
|
||||
export function getCronList(params:any) {
|
||||
export function getCronList(params: any) {
|
||||
return request.get(`sys/cron`, { params })
|
||||
}
|
||||
|
||||
@ -310,7 +336,7 @@ export function getCronList(params:any) {
|
||||
* 任务详情
|
||||
* @returns
|
||||
*/
|
||||
export function getCronInfo(id:string) {
|
||||
export function getCronInfo(id: string) {
|
||||
return request.get(`sys/cron/${id}`);
|
||||
}
|
||||
|
||||
@ -336,7 +362,7 @@ export function getAgreementList() {
|
||||
* 协议详情
|
||||
* @returns
|
||||
*/
|
||||
export function getAgreementInfo(key:string) {
|
||||
export function getAgreementInfo(key: string) {
|
||||
return request.get(`sys/agreement/${key}`);
|
||||
}
|
||||
|
||||
@ -344,7 +370,7 @@ export function getAgreementInfo(key:string) {
|
||||
* 更新协议
|
||||
* @returns
|
||||
*/
|
||||
export function updateAgreement(params: Record<string, any>) {
|
||||
export function editAgreement(params: Record<string, any>) {
|
||||
return request.put(`sys/agreement/${params.key}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -365,3 +391,54 @@ export function getSceneDomain() {
|
||||
return request.get(`sys/scene_domain`);
|
||||
}
|
||||
|
||||
/***************************************************** 登录注册配置 ****************************************************/
|
||||
|
||||
/**
|
||||
* 管理端登录注册配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function getConfigLogin() {
|
||||
return request.get(`sys/config/login`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置管理端登录注册配置
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function setConfigLogin(params: Record<string, any>) {
|
||||
return request.put(`sys/config/login`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付设置
|
||||
*/
|
||||
export function getPayConfigList() {
|
||||
return request.get(`pay/channel/lists`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置支付配置
|
||||
*/
|
||||
export function setPatConfig(params: Record<string, any>) {
|
||||
return request.post(`pay/channel/set/all`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
/***************************************************** 刷新菜单 ****************************************************/
|
||||
/**
|
||||
* 刷新菜单
|
||||
*/
|
||||
export function menuRefresh(params: Record<string, any>) {
|
||||
return request.post(`sys/menu/refresh`,{},{ showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
/***************************************************** 获取应用 ****************************************************/
|
||||
/**
|
||||
* 获取应用
|
||||
*/
|
||||
export function getAppMange() {
|
||||
return request.get(`sys/applist`)
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import request from '@/utils/request'
|
||||
* @returns
|
||||
*/
|
||||
export function getGenerateTableList(params: Record<string, any>) {
|
||||
return request.get(`generator/generator`, {params})
|
||||
return request.get(`generator/generator`, { params })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,7 +35,7 @@ export function addGenerateTable(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateGenerateTable(params: Record<string, any>) {
|
||||
export function editGenerateTable(params: Record<string, any>) {
|
||||
return request.put(`generator/generator/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -66,3 +66,11 @@ export function generateTable() {
|
||||
return request.get(`generator/table`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器环境配置
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
export function getSystem() {
|
||||
return request.get(`sys/system`)
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ export function addUser(params: Record<string, any>) {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateUser(params: Record<string, any>) {
|
||||
export function editUser(params: Record<string, any>) {
|
||||
return request.put(`user/user/${params.uid}`, params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ export function getWechatStatic() {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateWechatConfig(params: Record<string, any>) {
|
||||
export function editWechatConfig(params: Record<string, any>) {
|
||||
return request.put('wechat/config', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
@ -39,7 +39,7 @@ export function getWechatMenu() {
|
||||
* @param params
|
||||
* @returns
|
||||
*/
|
||||
export function updateWechatMenu(params: Record<string, any>) {
|
||||
export function editWechatMenu(params: Record<string, any>) {
|
||||
return request.put('wechat/menu', params, { showErrorMessage: true, showSuccessMessage: true })
|
||||
}
|
||||
|
||||
|
||||
BIN
admin/src/assets/images/back_login.jpg
Normal file
BIN
admin/src/assets/images/back_login.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
BIN
admin/src/assets/images/icon-addon.png
Normal file
BIN
admin/src/assets/images/icon-addon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 673 B |
BIN
admin/src/assets/images/login/login_index_bg.png
Normal file
BIN
admin/src/assets/images/login/login_index_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
admin/src/assets/images/login/login_index_left.png
Normal file
BIN
admin/src/assets/images/login/login_index_left.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
BIN
admin/src/assets/images/site_login.png
Normal file
BIN
admin/src/assets/images/site_login.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@ -76,6 +76,7 @@
|
||||
import {cloneDeep} from 'lodash-es'
|
||||
import {getLink} from '@/api/diy';
|
||||
import {ElMessage} from 'element-plus'
|
||||
import { CollectionTag } from '@element-plus/icons-vue';
|
||||
|
||||
const prop = defineProps({
|
||||
modelValue: {
|
||||
@ -115,18 +116,17 @@
|
||||
}
|
||||
|
||||
getLink({}).then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
link.value = res.data;
|
||||
childList.value = link.value[0].child_list;
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value);
|
||||
} else {
|
||||
selectLink.value = {
|
||||
parent: link.value[0].name
|
||||
};
|
||||
}
|
||||
parentLinkName.value = selectLink.value.parent;
|
||||
link.value = res.data;
|
||||
|
||||
childList.value = link.value[0].child_list;
|
||||
if (value.value.name != '') {
|
||||
selectLink.value = cloneDeep(value.value);
|
||||
} else {
|
||||
selectLink.value = {
|
||||
parent: link.value[0].name
|
||||
};
|
||||
}
|
||||
parentLinkName.value = selectLink.value.parent;
|
||||
});
|
||||
|
||||
// 选择父级链接
|
||||
|
||||
@ -37,8 +37,8 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
let type = ref('element')
|
||||
let visible = ref('false')
|
||||
const type = ref('element')
|
||||
const visible = ref('false')
|
||||
|
||||
// element 图标
|
||||
const element = computed(() => {
|
||||
@ -47,8 +47,8 @@ const element = computed(() => {
|
||||
|
||||
// iconfont 图标
|
||||
const iconfont = computed(() => {
|
||||
let iconfile = import.meta.globEager('@/styles/iconfont.css')['/src/styles/iconfont.css'].default
|
||||
let icons = Array.from(iconfile.matchAll(/(icon.*)\:before/g))
|
||||
const iconfile = import.meta.globEager('@/styles/icon/iconfont.css')['/src/styles/iconfont.css'].default
|
||||
const icons = Array.from(iconfile.matchAll(/(icon.*)\:before/g))
|
||||
|
||||
return icons.map(item => {
|
||||
return item[1]
|
||||
@ -72,4 +72,4 @@ const selectIcon = (name) => {
|
||||
.active {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -38,9 +38,15 @@
|
||||
<div class="attachment-list-wrap flex flex-col p-[15px] flex-1">
|
||||
<el-row :gutter="15" class="h-[32px]">
|
||||
<el-col :span="12">
|
||||
<el-upload v-bind="upload" ref="uploadRef">
|
||||
<el-button type="primary">{{ t('upload.upload' + type) }}</el-button>
|
||||
</el-upload>
|
||||
<div class="flex">
|
||||
<el-upload v-bind="upload" ref="uploadRef">
|
||||
<el-button type="primary">{{ t('upload.upload' + type) }}</el-button>
|
||||
</el-upload>
|
||||
<el-button v-if="operate === false" class="ml-[10px]" type="primary" @click="operate = true">{{
|
||||
t('edit') }}</el-button>
|
||||
<el-button v-else class="ml-[10px]" type="primary" @click="operate = false">{{ t('complete')
|
||||
}}</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12" class="text-right">
|
||||
<el-input v-model="attachmentParam.real_name" class="m-0 w-[200px]"
|
||||
@ -50,7 +56,7 @@
|
||||
</el-row>
|
||||
<div class="flex-1 my-[15px] h-0" v-loading="attachment.loading">
|
||||
<el-scrollbar>
|
||||
<div class="flex flex-wrap" v-if="attachment.data.length">
|
||||
<div class="flex flex-wrap" v-if="attachment.data.length && operate === true">
|
||||
<div class="attachment-item mr-[10px]" :class="scene == 'select' ? 'w-[100px]' : 'w-[120px]'"
|
||||
v-for="(item, index) in attachment.data" :key="index">
|
||||
<div class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center"
|
||||
@ -94,13 +100,32 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap" v-else-if="attachment.data.length && operate === false">
|
||||
<div class="attachment-item mr-[10px] w-[120px]" v-for="(item, index) in attachment.data"
|
||||
:key="index">
|
||||
<div
|
||||
class="attachment-wrap w-full rounded cursor-pointer overflow-hidden relative flex items-center justify-center h-[120px]">
|
||||
<el-image :src="img(item.url)" fit="contain" v-if="type == 'image'"
|
||||
:preview-src-list="item.image_list"></el-image>
|
||||
<video :src="img(item.url)" v-else></video>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<el-tooltip placement="top">
|
||||
<template #content>{{ item.real_name }}</template>
|
||||
<div class="truncate my-[10px] cursor-pointer text-base flex-1 ">
|
||||
{{ item.real_name }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-center" v-else>
|
||||
<el-empty :description="t('upload.attachmentEmpty')" :image-size="100" />
|
||||
<el-empty v-if="!attachment.loading" :description="t('upload.attachmentEmpty')" :image-size="100" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8" v-if="scene == 'attachment'">
|
||||
<el-col :span="8" v-if="scene == 'attachment' && operate === true">
|
||||
<div class="flex items-center">
|
||||
<el-checkbox v-model="selectAll" :label="t('selectAll')" size="large" />
|
||||
<el-button class="ml-[15px]" :disabled="batchOperateDisabled" @click="deleteAttachmentEvent()">{{
|
||||
@ -163,7 +188,7 @@ import {
|
||||
getAttachmentCategoryList as attachmentCategoryList,
|
||||
getAttachmentList as attachmentList,
|
||||
addAttachmentCategory as addCategory,
|
||||
updateAttachmentCategory as updateCategory,
|
||||
editAttachmentCategory as updateCategory,
|
||||
deleteAttachmentCategory as deleteCategory,
|
||||
deleteAttachment,
|
||||
moveAttachment
|
||||
@ -172,6 +197,7 @@ import { debounce, img, getToken } from '@/utils/common'
|
||||
import { ElMessage, UploadFile, UploadFiles, ElMessageBox } from 'element-plus'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const operate = ref(false)
|
||||
const prop = defineProps({
|
||||
// 选择数量限制
|
||||
limit: {
|
||||
@ -196,7 +222,7 @@ const attachmentCategory: Record<string, any> = reactive({
|
||||
data: []
|
||||
})
|
||||
const attachment: Record<string, any> = reactive({
|
||||
loading: false,
|
||||
loading: true,
|
||||
page: 1,
|
||||
total: 0,
|
||||
limit: prop.scene == 'select' ? 10 : 20,
|
||||
@ -241,6 +267,13 @@ const getAttachmentList = debounce((page: number = 1) => {
|
||||
attachment.total = res.data.total
|
||||
attachment.loading = false
|
||||
prop.scene == 'attachment' && clearSelected()
|
||||
|
||||
for (let i = 0; i < attachment.data.length; i++) {
|
||||
attachment.data[i]['image_list'] = []
|
||||
attachment.data[i]['image_list'].push(img(res.data.data[i]['url']))
|
||||
}
|
||||
|
||||
|
||||
}).catch(() => {
|
||||
attachment.loading = false
|
||||
})
|
||||
@ -508,5 +541,4 @@ defineExpose({
|
||||
background: #fff !important;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}</style>
|
||||
|
||||
@ -22,7 +22,7 @@ const prop = defineProps({
|
||||
},
|
||||
api: {
|
||||
type: String,
|
||||
default: 'sys/document'
|
||||
default: 'sys/document/document'
|
||||
}
|
||||
})
|
||||
|
||||
@ -41,7 +41,7 @@ const upload: Record<string, any> = {
|
||||
action: `${import.meta.env.VITE_APP_BASE_URL}/${prop.api}`,
|
||||
showFileList: false,
|
||||
headers: {},
|
||||
accept: '.doc,.docx,.xml,.txt,.pem,.zip,.rar,.7z',
|
||||
accept: '.doc,.docx,.xml,.txt,.pem,.zip,.rar,.7z,.crt',
|
||||
onSuccess: (response: any, uploadFile: UploadFile) => {
|
||||
value.value = response.data.url
|
||||
ElMessage({
|
||||
|
||||
434
admin/src/components/verifition/Verify.vue
Normal file
434
admin/src/components/verifition/Verify.vue
Normal file
File diff suppressed because one or more lines are too long
260
admin/src/components/verifition/Verify/VerifyPoints.vue
Normal file
260
admin/src/components/verifition/Verify/VerifyPoints.vue
Normal file
@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div style="position: relative"
|
||||
>
|
||||
<div class="verify-img-out">
|
||||
<div class="verify-img-panel" :style="{'width': setSize.imgWidth,
|
||||
'height': setSize.imgHeight,
|
||||
'background-size' : setSize.imgWidth + ' '+ setSize.imgHeight,
|
||||
'margin-bottom': vSpace + 'px'}"
|
||||
>
|
||||
<div class="verify-refresh" style="z-index:3" @click="refresh" v-show="showRefresh">
|
||||
<i class="iconfont icon-refresh"></i>
|
||||
</div>
|
||||
<img :src="'data:image/png;base64,'+pointBackImgBase"
|
||||
ref="canvas"
|
||||
alt="" style="width:100%;height:100%;display:block"
|
||||
@click="bindingClick?canvasClick($event):undefined">
|
||||
|
||||
<div v-for="(tempPoint, index) in tempPoints" :key="index" class="point-area"
|
||||
:style="{
|
||||
'background-color':'#1abd6c',
|
||||
color:'#fff',
|
||||
'z-index':9999,
|
||||
width:'20px',
|
||||
height:'20px',
|
||||
'text-align':'center',
|
||||
'line-height':'20px',
|
||||
'border-radius': '50%',
|
||||
position:'absolute',
|
||||
top:parseInt(tempPoint.y-10) + 'px',
|
||||
left:parseInt(tempPoint.x-10) + 'px'
|
||||
}">
|
||||
{{index + 1}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 'height': this.barSize.height, -->
|
||||
<div class="verify-bar-area"
|
||||
:style="{'width': setSize.imgWidth,
|
||||
'color': this.barAreaColor,
|
||||
'border-color': this.barAreaBorderColor,
|
||||
'line-height':this.barSize.height}">
|
||||
<span class="verify-msg">{{text}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/babel">
|
||||
/**
|
||||
* VerifyPoints
|
||||
* @description 点选
|
||||
* */
|
||||
import {resetSize, _code_chars, _code_color1, _code_color2} from './../utils/util'
|
||||
import {aesEncrypt} from "./../utils/ase"
|
||||
import {reqGet,reqCheck} from "./../api/index"
|
||||
import { computed, onMounted, reactive, ref,watch,nextTick,toRefs, watchEffect,getCurrentInstance} from 'vue';
|
||||
export default {
|
||||
name: 'VerifyPoints',
|
||||
props: {
|
||||
//弹出式pop,固定fixed
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'fixed'
|
||||
},
|
||||
captchaType:{
|
||||
type:String,
|
||||
},
|
||||
//间隔
|
||||
vSpace: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
imgSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '155px'
|
||||
}
|
||||
}
|
||||
},
|
||||
barSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '40px'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(props,context){
|
||||
const {mode,captchaType,vSpace,imgSize,barSize} = toRefs(props)
|
||||
const { proxy } = getCurrentInstance();
|
||||
let secretKey = ref(''), //后端返回的ase加密秘钥
|
||||
checkNum = ref(3), //默认需要点击的字数
|
||||
fontPos = reactive([]), //选中的坐标信息
|
||||
checkPosArr = reactive([]), //用户点击的坐标
|
||||
num = ref(1), //点击的记数
|
||||
pointBackImgBase = ref(''), //后端获取到的背景图片
|
||||
poinTextList = reactive([]), //后端返回的点击字体顺序
|
||||
backToken = ref(''), //后端返回的token值
|
||||
setSize = reactive({
|
||||
imgHeight: 0,
|
||||
imgWidth: 0,
|
||||
barHeight: 0,
|
||||
barWidth: 0
|
||||
}),
|
||||
tempPoints = reactive([]),
|
||||
text = ref(''),
|
||||
barAreaColor = ref(undefined),
|
||||
barAreaBorderColor = ref(undefined),
|
||||
showRefresh = ref(true),
|
||||
bindingClick = ref(true)
|
||||
|
||||
|
||||
|
||||
|
||||
const init = ()=>{
|
||||
//加载页面
|
||||
fontPos.splice(0, fontPos.length)
|
||||
checkPosArr.splice(0, checkPosArr.length)
|
||||
num.value = 1
|
||||
getPictrue();
|
||||
nextTick(() => {
|
||||
let {imgHeight,imgWidth,barHeight,barWidth} = resetSize(proxy)
|
||||
setSize.imgHeight = imgHeight
|
||||
setSize.imgWidth = imgWidth
|
||||
setSize.barHeight = barHeight
|
||||
setSize.barWidth = barWidth
|
||||
proxy.$parent.$emit('ready', proxy)
|
||||
})
|
||||
}
|
||||
onMounted(()=>{
|
||||
// 禁止拖拽
|
||||
init()
|
||||
proxy.$el.onselectstart = function () {
|
||||
return false
|
||||
}
|
||||
})
|
||||
const canvas = ref(null)
|
||||
const canvasClick = (e)=>{
|
||||
checkPosArr.push(getMousePos(canvas, e));
|
||||
if (num.value == checkNum.value) {
|
||||
num.value = createPoint(getMousePos(canvas, e));
|
||||
//按比例转换坐标值
|
||||
let arr = pointTransfrom(checkPosArr,setSize)
|
||||
checkPosArr.length = 0
|
||||
checkPosArr.push(...arr);
|
||||
//等创建坐标执行完
|
||||
setTimeout(() => {
|
||||
// var flag = this.comparePos(this.fontPos, this.checkPosArr);
|
||||
//发送后端请求
|
||||
var captchaVerification = secretKey.value? aesEncrypt(backToken.value+'---'+JSON.stringify(checkPosArr),secretKey.value):backToken.value+'---'+JSON.stringify(checkPosArr)
|
||||
let data = {
|
||||
captchaType:captchaType.value,
|
||||
"captcha_code":secretKey.value? aesEncrypt(JSON.stringify(checkPosArr),secretKey.value):JSON.stringify(checkPosArr),
|
||||
"captcha_key":backToken.value
|
||||
}
|
||||
reqCheck(data).then(res=>{
|
||||
if (res.code == "200") {
|
||||
barAreaColor.value = '#4cae4c'
|
||||
barAreaBorderColor.value = '#5cb85c'
|
||||
text.value = '验证成功'
|
||||
bindingClick.value = false
|
||||
if (mode.value=='pop') {
|
||||
setTimeout(()=>{
|
||||
proxy.$parent.clickShow = false;
|
||||
refresh();
|
||||
},1500)
|
||||
}
|
||||
proxy.$parent.$emit('success', {captchaVerification})
|
||||
}else{
|
||||
proxy.$parent.$emit('error', proxy)
|
||||
barAreaColor.value = '#d9534f'
|
||||
barAreaBorderColor.value = '#d9534f'
|
||||
text.value = '验证失败'
|
||||
setTimeout(() => {
|
||||
refresh();
|
||||
}, 700);
|
||||
}
|
||||
})
|
||||
}, 400);
|
||||
}
|
||||
if (num.value < checkNum.value) {
|
||||
num.value = createPoint(getMousePos(canvas, e));
|
||||
}
|
||||
}
|
||||
//获取坐标
|
||||
const getMousePos = function (obj, e) {
|
||||
var x = e.offsetX
|
||||
var y = e.offsetY
|
||||
return {x, y}
|
||||
}
|
||||
//创建坐标点
|
||||
const createPoint = function (pos) {
|
||||
tempPoints.push(Object.assign({}, pos))
|
||||
return num.value+1;
|
||||
}
|
||||
const refresh = function () {
|
||||
tempPoints.splice(0, tempPoints.length)
|
||||
barAreaColor.value = '#000'
|
||||
barAreaBorderColor.value = '#ddd'
|
||||
bindingClick.value = true
|
||||
fontPos.splice(0, fontPos.length)
|
||||
checkPosArr.splice(0, checkPosArr.length)
|
||||
num.value = 1
|
||||
getPictrue();
|
||||
text.value = '验证失败'
|
||||
showRefresh.value = true
|
||||
}
|
||||
|
||||
// 请求背景图片和验证图片
|
||||
function getPictrue() {
|
||||
let data = {
|
||||
captchaType:captchaType.value
|
||||
}
|
||||
reqGet(data).then(res=>{
|
||||
if (res.code == "200") {
|
||||
pointBackImgBase.value = res.data.originalImageBase64
|
||||
backToken.value = res.data.token
|
||||
secretKey.value = res.data.secretKey
|
||||
poinTextList.value = res.data.wordList
|
||||
text.value = '请依次点击【' + poinTextList.value.join(",") + '】'
|
||||
}else{
|
||||
text.value = res.msg;
|
||||
}
|
||||
})
|
||||
}
|
||||
//坐标转换函数
|
||||
const pointTransfrom = function(pointArr,imgSize){
|
||||
var newPointArr = pointArr.map(p=>{
|
||||
let x = Math.round(310 * p.x/parseInt(imgSize.imgWidth))
|
||||
let y =Math.round(155 * p.y/parseInt(imgSize.imgHeight))
|
||||
return {x,y}
|
||||
})
|
||||
return newPointArr
|
||||
}
|
||||
return {
|
||||
secretKey,
|
||||
checkNum,
|
||||
fontPos,
|
||||
checkPosArr,
|
||||
num,
|
||||
pointBackImgBase,
|
||||
poinTextList,
|
||||
backToken,
|
||||
setSize,
|
||||
tempPoints,
|
||||
text,
|
||||
barAreaColor,
|
||||
barAreaBorderColor,
|
||||
showRefresh,
|
||||
bindingClick,
|
||||
init,
|
||||
canvas,
|
||||
canvasClick,
|
||||
getMousePos,createPoint,refresh,getPictrue,pointTransfrom
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
366
admin/src/components/verifition/Verify/VerifySlide.vue
Normal file
366
admin/src/components/verifition/Verify/VerifySlide.vue
Normal file
@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<div style="position: relative;">
|
||||
<div v-if="type === '2'" class="verify-img-out"
|
||||
:style="{height: (parseInt(setSize.imgHeight) + vSpace) + 'px'}"
|
||||
>
|
||||
<div class="verify-img-panel" :style="{width: setSize.imgWidth,
|
||||
height: setSize.imgHeight,}">
|
||||
<img :src="'data:image/png;base64,'+backImgBase" alt="" style="width:100%;height:100%;display:block">
|
||||
<div class="verify-refresh" @click="refresh" v-show="showRefresh"><i class="iconfont icon-refresh"></i>
|
||||
</div>
|
||||
<transition name="tips">
|
||||
<span class="verify-tips" v-if="tipWords" :class="passFlag ?'suc-bg':'err-bg'">{{tipWords}}</span>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 公共部分 -->
|
||||
<div class="verify-bar-area" :style="{width: setSize.imgWidth,
|
||||
height: barSize.height,
|
||||
'line-height':barSize.height}">
|
||||
<span class="verify-msg" v-text="text"></span>
|
||||
<div class="verify-left-bar"
|
||||
:style="{width: (leftBarWidth!==undefined)?leftBarWidth: barSize.height, height: barSize.height, 'border-color': leftBarBorderColor, transaction: transitionWidth}">
|
||||
<span class="verify-msg" v-text="finishText"></span>
|
||||
<div class="verify-move-block"
|
||||
@touchstart="start"
|
||||
@mousedown="start"
|
||||
:style="{width: barSize.height, height: barSize.height, 'background-color': moveBlockBackgroundColor, left: moveBlockLeft, transition: transitionLeft}">
|
||||
<i :class="['verify-icon iconfont', iconClass]"
|
||||
:style="{color: iconColor}"></i>
|
||||
<div v-if="type === '2'" class="verify-sub-block"
|
||||
:style="{'width':Math.floor(parseInt(setSize.imgWidth)*47/310)+ 'px',
|
||||
'height': setSize.imgHeight,
|
||||
'top':'-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
|
||||
'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
|
||||
}">
|
||||
<img :src="'data:image/png;base64,'+blockBackImgBase" alt="" style="width:100%;height:100%;display:block;-webkit-user-drag:none;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/babel">
|
||||
/**
|
||||
* VerifySlide
|
||||
* @description 滑块
|
||||
* */
|
||||
import {aesEncrypt} from "./../utils/ase"
|
||||
import {resetSize} from './../utils/util'
|
||||
import {reqGet,reqCheck} from "./../api/index"
|
||||
import { computed, onMounted, reactive, ref,watch,nextTick,toRefs, watchEffect,getCurrentInstance} from 'vue';
|
||||
// "captchaType":"blockPuzzle",
|
||||
export default {
|
||||
name: 'VerifySlide',
|
||||
props: {
|
||||
captchaType:{
|
||||
type:String,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: '1'
|
||||
},
|
||||
//弹出式pop,固定fixed
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'fixed'
|
||||
},
|
||||
vSpace: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
explain: {
|
||||
type: String,
|
||||
default: '向右滑动完成验证'
|
||||
},
|
||||
imgSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '155px'
|
||||
}
|
||||
}
|
||||
},
|
||||
blockSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '50px',
|
||||
height: '50px'
|
||||
}
|
||||
}
|
||||
},
|
||||
barSize: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
width: '310px',
|
||||
height: '40px'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(props,context){
|
||||
const {mode,captchaType,vSpace,imgSize,barSize,type,blockSize,explain} = toRefs(props)
|
||||
const { proxy } = getCurrentInstance();
|
||||
let secretKey = ref(''), //后端返回的ase加密秘钥
|
||||
passFlag = ref(''), //是否通过的标识
|
||||
backImgBase = ref(''), //验证码背景图片
|
||||
blockBackImgBase = ref(''), //验证滑块的背景图片
|
||||
backToken = ref(''), //后端返回的唯一token值
|
||||
startMoveTime = ref(''), //移动开始的时间
|
||||
endMovetime = ref(''), //移动结束的时间
|
||||
tipsBackColor = ref(''), //提示词的背景颜色
|
||||
tipWords = ref(''),
|
||||
text = ref(''),
|
||||
finishText = ref(''),
|
||||
setSize = reactive({
|
||||
imgHeight: 0,
|
||||
imgWidth: 0,
|
||||
barHeight: 0,
|
||||
barWidth: 0
|
||||
}),
|
||||
top = ref(0),
|
||||
left = ref(0),
|
||||
moveBlockLeft = ref(undefined),
|
||||
leftBarWidth = ref(undefined),
|
||||
// 移动中样式
|
||||
moveBlockBackgroundColor = ref(undefined),
|
||||
leftBarBorderColor = ref('#ddd'),
|
||||
iconColor = ref(undefined),
|
||||
iconClass = ref('icon-right'),
|
||||
status = ref(false), //鼠标状态
|
||||
isEnd = ref(false) , //是够验证完成
|
||||
showRefresh = ref(true),
|
||||
transitionLeft = ref(''),
|
||||
transitionWidth = ref(''),
|
||||
startLeft = ref(0)
|
||||
|
||||
const barArea = computed(()=>{
|
||||
return proxy.$el.querySelector('.verify-bar-area')
|
||||
})
|
||||
function init() {
|
||||
text.value = explain.value
|
||||
getPictrue();
|
||||
nextTick(() => {
|
||||
let {imgHeight,imgWidth,barHeight,barWidth} = resetSize(proxy)
|
||||
setSize.imgHeight = imgHeight
|
||||
setSize.imgWidth = imgWidth
|
||||
setSize.barHeight = barHeight
|
||||
setSize.barWidth = barWidth
|
||||
proxy.$parent.$emit('ready', proxy)
|
||||
})
|
||||
|
||||
window.removeEventListener("touchmove", function (e) {
|
||||
move(e);
|
||||
});
|
||||
window.removeEventListener("mousemove", function (e) {
|
||||
move(e);
|
||||
});
|
||||
|
||||
//鼠标松开
|
||||
window.removeEventListener("touchend", function () {
|
||||
end();
|
||||
});
|
||||
window.removeEventListener("mouseup", function () {
|
||||
end();
|
||||
});
|
||||
|
||||
window.addEventListener("touchmove", function (e) {
|
||||
move(e);
|
||||
});
|
||||
window.addEventListener("mousemove", function (e) {
|
||||
move(e);
|
||||
});
|
||||
|
||||
//鼠标松开
|
||||
window.addEventListener("touchend", function () {
|
||||
end();
|
||||
});
|
||||
window.addEventListener("mouseup", function () {
|
||||
end();
|
||||
});
|
||||
}
|
||||
watch(type,()=>{
|
||||
init()
|
||||
})
|
||||
onMounted(()=>{
|
||||
// 禁止拖拽
|
||||
init()
|
||||
proxy.$el.onselectstart = function () {
|
||||
return false
|
||||
}
|
||||
})
|
||||
//鼠标按下
|
||||
function start(e) {
|
||||
e = e || window.event
|
||||
if (!e.touches) { //兼容PC端
|
||||
var x = e.clientX;
|
||||
} else { //兼容移动端
|
||||
var x = e.touches[0].pageX;
|
||||
}
|
||||
console.log(barArea);
|
||||
startLeft.value =Math.floor(x - barArea.value.getBoundingClientRect().left);
|
||||
startMoveTime.value = +new Date(); //开始滑动的时间
|
||||
if (isEnd.value == false) {
|
||||
text.value = ''
|
||||
moveBlockBackgroundColor.value = '#337ab7'
|
||||
leftBarBorderColor.value = '#337AB7'
|
||||
iconColor.value = '#fff'
|
||||
e.stopPropagation();
|
||||
status.value = true;
|
||||
}
|
||||
}
|
||||
//鼠标移动
|
||||
function move(e) {
|
||||
e = e || window.event
|
||||
if (status.value && isEnd.value == false) {
|
||||
if (!e.touches) { //兼容PC端
|
||||
var x = e.clientX;
|
||||
} else { //兼容移动端
|
||||
var x = e.touches[0].pageX;
|
||||
}
|
||||
var bar_area_left = barArea.value.getBoundingClientRect().left;
|
||||
var move_block_left = x - bar_area_left //小方块相对于父元素的left值
|
||||
if (move_block_left >= barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width) / 2) - 2) {
|
||||
move_block_left = barArea.value.offsetWidth - parseInt(parseInt(blockSize.value.width) / 2) - 2;
|
||||
}
|
||||
if (move_block_left <= 0) {
|
||||
move_block_left = parseInt(parseInt(blockSize.value.width) / 2);
|
||||
}
|
||||
//拖动后小方块的left值
|
||||
moveBlockLeft.value = (move_block_left - startLeft.value) + "px"
|
||||
leftBarWidth.value = (move_block_left - startLeft.value) + "px"
|
||||
}
|
||||
}
|
||||
|
||||
//鼠标松开
|
||||
function end() {
|
||||
endMovetime.value = +new Date();
|
||||
//判断是否重合
|
||||
if (status.value && isEnd.value == false) {
|
||||
var moveLeftDistance = parseInt((moveBlockLeft.value || '').replace('px', ''));
|
||||
moveLeftDistance = moveLeftDistance * 310/ parseInt(setSize.imgWidth)
|
||||
let data = {
|
||||
captchaType:captchaType.value,
|
||||
"captcha_code":secretKey.value ? aesEncrypt(JSON.stringify({x:moveLeftDistance,y:5.0}),secretKey.value):JSON.stringify({x:moveLeftDistance,y:5.0}),
|
||||
"captcha_key":backToken.value
|
||||
}
|
||||
reqCheck(data).then(res=>{
|
||||
if (res.code == "200") {
|
||||
moveBlockBackgroundColor.value = '#5cb85c'
|
||||
leftBarBorderColor.value = '#5cb85c'
|
||||
iconColor.value = '#fff'
|
||||
iconClass.value = 'icon-check'
|
||||
showRefresh.value = false
|
||||
isEnd.value = true;
|
||||
if (mode.value=='pop') {
|
||||
setTimeout(()=>{
|
||||
proxy.$parent.clickShow = false;
|
||||
refresh();
|
||||
},1500)
|
||||
}
|
||||
passFlag.value = true
|
||||
tipWords.value = `${((endMovetime.value-startMoveTime.value)/1000).toFixed(2)}s验证成功`
|
||||
var captchaVerification = secretKey.value ? aesEncrypt(backToken.value+'---'+JSON.stringify({x:moveLeftDistance,y:5.0}),secretKey.value):backToken.value+'---'+JSON.stringify({x:moveLeftDistance,y:5.0})
|
||||
setTimeout(()=>{
|
||||
tipWords.value = ""
|
||||
proxy.$parent.closeBox();
|
||||
proxy.$parent.$emit('success', {captchaVerification})
|
||||
},1000)
|
||||
}else{
|
||||
moveBlockBackgroundColor.value = '#d9534f'
|
||||
leftBarBorderColor.value = '#d9534f'
|
||||
iconColor.value = '#fff'
|
||||
iconClass.value = 'icon-close'
|
||||
passFlag.value = false
|
||||
setTimeout(function () {
|
||||
refresh();
|
||||
}, 1000);
|
||||
proxy.$parent.$emit('error',proxy)
|
||||
tipWords.value = "验证失败"
|
||||
setTimeout(()=>{
|
||||
tipWords.value = ""
|
||||
},1000)
|
||||
}
|
||||
})
|
||||
status.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const refresh = ()=>{
|
||||
showRefresh.value = true
|
||||
finishText.value = ''
|
||||
|
||||
transitionLeft.value = 'left .3s'
|
||||
moveBlockLeft.value = 0
|
||||
|
||||
leftBarWidth.value = undefined
|
||||
transitionWidth.value = 'width .3s'
|
||||
|
||||
leftBarBorderColor.value = '#ddd'
|
||||
moveBlockBackgroundColor.value = '#fff'
|
||||
iconColor.value = '#000'
|
||||
iconClass.value = 'icon-right'
|
||||
isEnd.value = false
|
||||
|
||||
getPictrue()
|
||||
setTimeout(() => {
|
||||
transitionWidth.value = ''
|
||||
transitionLeft.value = ''
|
||||
text.value = explain.value
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 请求背景图片和验证图片
|
||||
function getPictrue(){
|
||||
let data = {
|
||||
captchaType:captchaType.value
|
||||
}
|
||||
reqGet(data).then(res=>{
|
||||
if (res.code == "200") {
|
||||
backImgBase.value = res.data.originalImageBase64
|
||||
blockBackImgBase.value = res.data.jigsawImageBase64
|
||||
backToken.value = res.data.token
|
||||
secretKey.value = res.data.secretKey
|
||||
}else{
|
||||
tipWords.value = res.msg;
|
||||
}
|
||||
})
|
||||
}
|
||||
return {
|
||||
secretKey, //后端返回的ase加密秘钥
|
||||
passFlag, //是否通过的标识
|
||||
backImgBase, //验证码背景图片
|
||||
blockBackImgBase, //验证滑块的背景图片
|
||||
backToken, //后端返回的唯一token值
|
||||
startMoveTime, //移动开始的时间
|
||||
endMovetime, //移动结束的时间
|
||||
tipsBackColor, //提示词的背景颜色
|
||||
tipWords,
|
||||
text,
|
||||
finishText,
|
||||
setSize,
|
||||
top,
|
||||
left,
|
||||
moveBlockLeft,
|
||||
leftBarWidth,
|
||||
// 移动中样式
|
||||
moveBlockBackgroundColor,
|
||||
leftBarBorderColor,
|
||||
iconColor,
|
||||
iconClass,
|
||||
status, //鼠标状态
|
||||
isEnd, //是够验证完成
|
||||
showRefresh,
|
||||
transitionLeft,
|
||||
transitionWidth,
|
||||
barArea,
|
||||
refresh,
|
||||
start
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
31
admin/src/components/verifition/api/index.js
Normal file
31
admin/src/components/verifition/api/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 此处可直接引用自己项目封装好的 axios 配合后端联调
|
||||
*/
|
||||
|
||||
|
||||
import request from "./../utils/axios" //组件内部封装的axios
|
||||
// import request from "@/api/axios.js" //调用项目封装的axios
|
||||
|
||||
//获取验证图片 以及token
|
||||
export function reqGet(data) {
|
||||
return request.get('/captcha/create',{params:{...data}});
|
||||
|
||||
// return request({
|
||||
// url: '/captcha/create',
|
||||
// method: 'get',
|
||||
// data
|
||||
// })
|
||||
}
|
||||
|
||||
//滑动或者点选验证
|
||||
export function reqCheck(data) {
|
||||
return request.get('/captcha/check',{params:{...data}});
|
||||
|
||||
// return request({
|
||||
// url: '/captcha/check',
|
||||
// method: 'post',
|
||||
// data
|
||||
// })
|
||||
}
|
||||
|
||||
|
||||
11
admin/src/components/verifition/utils/ase.js
Normal file
11
admin/src/components/verifition/utils/ase.js
Normal file
@ -0,0 +1,11 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
/**
|
||||
* @word 要加密的内容
|
||||
* @keyWord String 服务器随机返回的关键字
|
||||
* */
|
||||
export function aesEncrypt(word,keyWord="XwKsGlMcdPMEhR1B"){
|
||||
var key = CryptoJS.enc.Utf8.parse(keyWord);
|
||||
var srcs = CryptoJS.enc.Utf8.parse(word);
|
||||
var encrypted = CryptoJS.AES.encrypt(srcs, key, {mode:CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});
|
||||
return encrypted.toString();
|
||||
}
|
||||
30
admin/src/components/verifition/utils/axios.js
Normal file
30
admin/src/components/verifition/utils/axios.js
Normal file
@ -0,0 +1,30 @@
|
||||
import axios from 'axios';
|
||||
|
||||
axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_URL;
|
||||
|
||||
const service = axios.create({
|
||||
timeout: 40000,
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Content-Type': 'application/json; charset=UTF-8'
|
||||
},
|
||||
})
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response.data;
|
||||
return res
|
||||
},
|
||||
error => {
|
||||
}
|
||||
)
|
||||
export default service
|
||||
35
admin/src/components/verifition/utils/util.js
Normal file
35
admin/src/components/verifition/utils/util.js
Normal file
@ -0,0 +1,35 @@
|
||||
export function resetSize(vm) {
|
||||
var img_width, img_height, bar_width, bar_height; //图片的宽度、高度,移动条的宽度、高度
|
||||
|
||||
var parentWidth = vm.$el.parentNode.offsetWidth || window.offsetWidth
|
||||
var parentHeight = vm.$el.parentNode.offsetHeight || window.offsetHeight
|
||||
if (vm.imgSize.width.indexOf('%') != -1) {
|
||||
img_width = parseInt(vm.imgSize.width) / 100 * parentWidth + 'px'
|
||||
} else {
|
||||
img_width = vm.imgSize.width;
|
||||
}
|
||||
|
||||
if (vm.imgSize.height.indexOf('%') != -1) {
|
||||
img_height = parseInt(vm.imgSize.height) / 100 * parentHeight + 'px'
|
||||
} else {
|
||||
img_height = vm.imgSize.height
|
||||
}
|
||||
|
||||
if (vm.barSize.width.indexOf('%') != -1) {
|
||||
bar_width = parseInt(vm.barSize.width) / 100 * parentWidth + 'px'
|
||||
} else {
|
||||
bar_width = vm.barSize.width
|
||||
}
|
||||
|
||||
if (vm.barSize.height.indexOf('%') != -1) {
|
||||
bar_height = parseInt(vm.barSize.height) / 100 * parentHeight + 'px'
|
||||
} else {
|
||||
bar_height = vm.barSize.height
|
||||
}
|
||||
|
||||
return {imgWidth: img_width, imgHeight: img_height, barWidth: bar_width, barHeight: bar_height}
|
||||
}
|
||||
|
||||
export const _code_chars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
|
||||
export const _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0']
|
||||
export const _code_color2 = ['#FF0033', '#006699', '#993366', '#FF9900', '#66CC66', '#FF33CC']
|
||||
@ -9,6 +9,7 @@ let i18n = createI18n({
|
||||
datetimeFormats: {},
|
||||
numberFormats: {},
|
||||
globalInjection: true, //是否全局注入
|
||||
silentTranslationWarn: true,
|
||||
messages: {
|
||||
"zh-cn": zhCn,
|
||||
en
|
||||
|
||||
@ -3,7 +3,7 @@ import useAppStore from '@/stores/modules/app'
|
||||
|
||||
const t = (message: string) => {
|
||||
const path = useAppStore().route
|
||||
const file = path == '/' ? 'index' : path.replace('/', '').replaceAll('/', '.')
|
||||
const file = path == '/' ? 'index' : path.replace(/^(\/admin\/|\/site\/|\/)/, '').replaceAll('/', '.')
|
||||
const key = `${file}.${message}`
|
||||
return i18n.global.t(key) != key ? i18n.global.t(key) : i18n.global.t(message)
|
||||
}
|
||||
|
||||
@ -30,12 +30,7 @@ class Language {
|
||||
*/
|
||||
public async loadLocaleMessages(path: string, locale: string) {
|
||||
try {
|
||||
const file = path == '/' ? 'index' : path.replace('/', '').replaceAll('/', '.')
|
||||
|
||||
if (this.loadLocale.includes(`${locale}/${file}`)) {
|
||||
return nextTick()
|
||||
}
|
||||
this.loadLocale.push(`${locale}/${file}`)
|
||||
const file = path == '/' ? 'index' : path.replace(/^(\/admin\/|\/site\/|\/)/, '').replaceAll('/', '.')
|
||||
|
||||
// 引入语言包文件
|
||||
const messages = await import(`./${locale}/${file}.json`)
|
||||
@ -48,7 +43,8 @@ class Language {
|
||||
this.i18n.global.mergeLocaleMessage(locale, data)
|
||||
this.setI18nLanguage(locale)
|
||||
return nextTick()
|
||||
} catch {
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
this.setI18nLanguage(locale)
|
||||
return nextTick()
|
||||
}
|
||||
|
||||
@ -31,5 +31,6 @@
|
||||
"isShowNumber":"是否显示必须是数字",
|
||||
"isShowBetween":"是否显示只能是0或者1",
|
||||
"sortNumber":"排序号必须是数字",
|
||||
"sortBetween":"排序号需要在0-10000之间"
|
||||
"sortBetween":"排序号需要在0-10000之间",
|
||||
"articleNull":"未读取到文章信息!"
|
||||
}
|
||||
25
admin/src/lang/zh-cn/auth.menu.json
Normal file
25
admin/src/lang/zh-cn/auth.menu.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"menuName": "菜单名称",
|
||||
"menuType": "类型",
|
||||
"authId": "权限标识",
|
||||
"menuTypeDir": "目录",
|
||||
"menuTypeMenu": "菜单",
|
||||
"menuTypeButton": "按钮",
|
||||
"menuDeleteTips": "确定要删除该菜单吗?",
|
||||
"addMenu": "添加菜单",
|
||||
"updateMenu": "编辑菜单",
|
||||
"routePath": "路由路径",
|
||||
"viewPath": "组件路径",
|
||||
"parentMenu": "父级菜单",
|
||||
"menuIcon": "菜单图标",
|
||||
"sort":"权重",
|
||||
"menuKey":"菜单标识",
|
||||
"menuNamePlaceholder": "请输入菜单名称",
|
||||
"menuKeyPlaceholder": "请输入菜单标识",
|
||||
"menuKeyValidata":"菜单标识只能使用字母数字下划线并且开头不能为数字",
|
||||
"routePathPlaceholder": "请输入路由路径",
|
||||
"viewPathPlaceholder": "请输入组件路径",
|
||||
"authIdPlaceholder": "请输入权限标识",
|
||||
"selectIconPlaceholder": "请选择菜单图标",
|
||||
"topLevel": "顶级"
|
||||
}
|
||||
@ -15,6 +15,8 @@
|
||||
"lock":"锁定",
|
||||
"unlock":"解锁",
|
||||
"status":"用户状态",
|
||||
"statusUnlock":"正常",
|
||||
"statusLock":"锁定",
|
||||
"userUnlockTips":"确定要解锁该管理员吗?",
|
||||
"userLockTips":"确定要锁定该管理员吗?"
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"isOpen": "是否开启",
|
||||
"h5DomainName": "h5域名",
|
||||
"clickVisit": "点击访问",
|
||||
"H5Info": "h5配置信息"
|
||||
|
||||
}
|
||||
@ -1,4 +1,7 @@
|
||||
{
|
||||
"pcInfo": "电脑端信息",
|
||||
"preview": "预览图"
|
||||
"preview": "预览图",
|
||||
"copy": "复制",
|
||||
"clickVisit": "点击访问",
|
||||
"PCDomainName": "pc域名"
|
||||
}
|
||||
@ -34,6 +34,7 @@
|
||||
"yes": "是",
|
||||
"no": "否",
|
||||
"copy": "复制",
|
||||
"complete": "完成",
|
||||
"copySuccess": "复制成功",
|
||||
"notSupportCopy": "浏览器不支持一键复制,请手动进行复制",
|
||||
"selectPlaceholder": "全部",
|
||||
@ -69,7 +70,10 @@
|
||||
"layoutSetting": "主题设置",
|
||||
"darkMode": "黑暗模式",
|
||||
"sidebarMode": "主题风格",
|
||||
"themeColor": "主题颜色"
|
||||
"themeColor": "主题颜色",
|
||||
"detectionLoginOperation": "确定",
|
||||
"detectionLoginContent": "已检测到有其他账号登录,需要刷新后才能继续操作。",
|
||||
"detectionLoginTip": "提示"
|
||||
},
|
||||
"axios": {
|
||||
"unknownError": "未知错误",
|
||||
|
||||
39
admin/src/lang/zh-cn/finance.cash_out.json
Normal file
39
admin/src/lang/zh-cn/finance.cash_out.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择",
|
||||
"applyTime":"申请时间",
|
||||
"cashOutStatus":"提现状态",
|
||||
"actualTransferAmount":"实际转账金额",
|
||||
"cashOutCommission":"提现手续费",
|
||||
"applicationForWithdrawalAmount":"申请提现金额",
|
||||
"cashOutMethod":"提现方式",
|
||||
"cashOutAccountType":"会员账户",
|
||||
"memberInfo":"会员信息",
|
||||
"toBeReviewed":"待审核",
|
||||
"toBeTransferred":"待转账",
|
||||
"transferred":"已转账",
|
||||
"turnDown":"拒绝",
|
||||
"transfer": "转账",
|
||||
"detail": "详情",
|
||||
"auditFailure": "审核失败",
|
||||
"successfulAudit": "审核成功",
|
||||
"rejectionAudit": "拒绝审核",
|
||||
"reasonsRefusal": "拒绝理由",
|
||||
"reasonsRefusalPlaceholder": "请输入拒绝理由",
|
||||
"isTransfer": "是否确认转账",
|
||||
"nickname":"会员名称",
|
||||
"headimg":"会员头像",
|
||||
"cashOutDetail":"提现详情",
|
||||
"cashOutMoney": "转账金额"
|
||||
|
||||
}
|
||||
@ -10,5 +10,9 @@
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择"
|
||||
"namePlaceholder":"请选择",
|
||||
"refundBtn":"退款",
|
||||
"refundContent":"是否确认退款"
|
||||
|
||||
|
||||
}
|
||||
14
admin/src/lang/zh-cn/finance.refund.json
Normal file
14
admin/src/lang/zh-cn/finance.refund.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"refundNumber":"退款单号",
|
||||
"userInfo":"用户信息",
|
||||
"sourceNumber":"来源单号",
|
||||
"refundAmount":"退款金额",
|
||||
"refundTime":"退款时间",
|
||||
"detail": "详情",
|
||||
"statusName": "状态",
|
||||
"memberInfo": "会员",
|
||||
"refundSource": "退款来源",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"refundStatus": "退款状态"
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
{
|
||||
"orderNo":"订单编号",
|
||||
"orderStatus":"订单状态",
|
||||
"orderNoPlaceholder":"请输入订单编号",
|
||||
"createTime":"创建时间",
|
||||
"rechargeMoney":"充值金额",
|
||||
"orderMoney":"订单金额",
|
||||
"member":"买家",
|
||||
"orderFromName":"订单来源",
|
||||
"payTypeName":"支付方式",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"namePlaceholder":"请选择",
|
||||
"applyTime":"申请时间",
|
||||
"withdrawalStatus":"提现状态",
|
||||
"actualTransferAmount":"实际转账金额",
|
||||
"withdrawalCommission":"提现手续费",
|
||||
"applicationForWithdrawalAmount":"申请提现金额",
|
||||
"withdrawalMethod":"提现方式",
|
||||
"memberInfo":"会员信息",
|
||||
"toBeTransferred":"待转账",
|
||||
"transferred":"已转账",
|
||||
"turnDown":"拒绝"
|
||||
}
|
||||
@ -1,9 +1,10 @@
|
||||
{
|
||||
"dataSummarize": "数据概括",
|
||||
"todayData": "今日数据",
|
||||
"memberNumb": "会员数量",
|
||||
"memberNumb": "新增会员数",
|
||||
"orderMoney": "订单金额",
|
||||
"numberOfSites": "站点数量",
|
||||
"numberOfVisitors": "访客数量",
|
||||
"numberOfVisitors": "今日访客数",
|
||||
"commonlyUsedFunction": "常用功能",
|
||||
"articleList": "文章列表",
|
||||
"memberManagement": "会员管理",
|
||||
@ -20,7 +21,7 @@
|
||||
"versions": "当前版本",
|
||||
"frame": "基于框架",
|
||||
"channel": "获取渠道",
|
||||
"serviceSupport": "服务支持",
|
||||
"serviceSupport": "官方客服",
|
||||
"officialWbsite": "官网",
|
||||
"pageView": "访问量",
|
||||
"siteInfo":"站点信息",
|
||||
@ -28,5 +29,17 @@
|
||||
"groupName":"站点套餐",
|
||||
"expireTime":"过期时间",
|
||||
"permanent":"永久",
|
||||
"statusName":"站点状态"
|
||||
"statusName":"站点状态",
|
||||
"newSiteSum": "新增站点数",
|
||||
"total": "总计",
|
||||
"newMemberSum": "新增用户数",
|
||||
"siteList": "站点列表",
|
||||
"sitePackage": "站点套餐",
|
||||
"newSite": "新增站点",
|
||||
"appMarketplace": "应用市场",
|
||||
"siteDistribution": "站点分布",
|
||||
"siteSum": "站点数",
|
||||
"memberSum": "用户数",
|
||||
"appSum": "应用数",
|
||||
"installAppSun": "安装应用数"
|
||||
}
|
||||
@ -1,9 +1,12 @@
|
||||
{
|
||||
"siteTitle": "Niucloud Admin",
|
||||
"siteTitle": "NIUCLOUD-ADMIN",
|
||||
"siteDesc": "基于thinkphp6+elementplus+typescript等技术的多端saas通用管理框架,采用restful的api接口设计,前后端完全分离,同时支持多语言开发。",
|
||||
"logging": "登录中",
|
||||
"platform": "管理端",
|
||||
"login" : "登录",
|
||||
"siteLogin": "站点登录",
|
||||
"adminLogin": "平台登录",
|
||||
"userPlaceholder": "请输入您的账号",
|
||||
"passwordPlaceholder": "请输入您的密码"
|
||||
"passwordPlaceholder": "请输入您的密码",
|
||||
"manageAdminFramework": "管理系统后台框架"
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"accountData":"金额",
|
||||
"fromType":"变动类型",
|
||||
"fromType":"来源/用途",
|
||||
"balanceInfo":"余额变动详情",
|
||||
"memo":"备注",
|
||||
"mobile":"手机号码",
|
||||
@ -20,5 +20,8 @@
|
||||
"memoPlaceholder":"请输入备注信息",
|
||||
"addMemberAccountLog":"添加会员账单表",
|
||||
"updateMemberAccountLog":"编辑会员账单表",
|
||||
"member_account_logDeleteTips":"确定要删除该会员账单表吗?"
|
||||
"memberAccountLogDeleteTips":"确定要删除该会员账单表吗?",
|
||||
"balance": "不可提现余额",
|
||||
"money":"可提现余额",
|
||||
"balanceType":"账户类型"
|
||||
}
|
||||
24
admin/src/lang/zh-cn/member.commission.json
Normal file
24
admin/src/lang/zh-cn/member.commission.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"accountData":"金额",
|
||||
"fromType":"来源/用途",
|
||||
"moneyInfo":"佣金变动详情",
|
||||
"memo":"备注",
|
||||
"mobile":"手机号码",
|
||||
"nickName":"会员信息",
|
||||
"headimg":"会员头像",
|
||||
"createTime":"产生时间",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"searchMember":"昵称/手机号",
|
||||
"searchMemberPlaceholder":"请输入会员昵称/手机号码",
|
||||
"memberIdPlaceholder":"请输入会员id",
|
||||
"accountTypePlaceholder":"请输入账户类型",
|
||||
"accountDataPlaceholder":"请输入账户数据",
|
||||
"fromTypePlaceholder":"请输入来源类型",
|
||||
"relatedIdPlaceholder":"请输入关联Id",
|
||||
"createTimePlaceholder":"请输入创建时间",
|
||||
"memoPlaceholder":"请输入备注信息",
|
||||
"addMemberAccountLog":"添加会员账单表",
|
||||
"updateMemberAccountLog":"编辑会员账单表",
|
||||
"member_account_logDeleteTips":"确定要删除该会员账单表吗?"
|
||||
}
|
||||
@ -24,6 +24,7 @@
|
||||
"wxOpenid": "微信小程openid",
|
||||
"memberLabel": "会员标签",
|
||||
"memberLabelPlaceholder": "请选择会员标签",
|
||||
"nickNamePlaceholder": "请输入会员名称",
|
||||
"updateMember": "编辑会员信息",
|
||||
"notAvailable":"暂无",
|
||||
"girlSex":"女",
|
||||
@ -42,6 +43,8 @@
|
||||
"mobile":"手机号",
|
||||
"detail":"详情",
|
||||
"accumulative":"累计",
|
||||
"looseChange":"零钱",
|
||||
"adjustPoint":"调整积分"
|
||||
"money":"可提现余额",
|
||||
"adjustPoint":"调整积分",
|
||||
"commission":"佣金",
|
||||
"memberNull":"未读取到会员详情信息"
|
||||
}
|
||||
@ -12,6 +12,6 @@
|
||||
"updateMemberLabel":"编辑会员标签",
|
||||
"sortVerifyOne":"排序要大于零",
|
||||
"sortVerifyTwo":"排序不能是小数",
|
||||
"member_labelDeleteTips":"确定要删除该会员标签吗?"
|
||||
"memberLabelDeleteTips":"确定要删除该会员标签吗?"
|
||||
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
{
|
||||
"registerType":"注册方式",
|
||||
"registerChannel":"注册来源",
|
||||
"nickname":"会员名称",
|
||||
"mobile":"手机号",
|
||||
"createTime":"注册时间",
|
||||
"lastVisitTime":"最后登录时间",
|
||||
"lastVisitTime":"最后访问时间",
|
||||
"addMember":"添加会员",
|
||||
"updateMember":"编辑会员",
|
||||
"nickNamePlaceholder":"请输入会员名称",
|
||||
@ -39,9 +39,11 @@
|
||||
"doubleCipherHint": "输入的两次密码不一致",
|
||||
"mobileHint": "请输入正确的手机号!",
|
||||
"lable": "标签",
|
||||
"setLable": "设置标签",
|
||||
"setLable": "标签",
|
||||
"notAvailable": "暂无",
|
||||
"memberLabelPlaceholder": "请选择会员标签",
|
||||
"memberInfo":"会员信息",
|
||||
"memberInfoPlaceholder":"请输入会员名称/会员昵称/手机号"
|
||||
"memberInfoPlaceholder":"请输入会员名称/会员昵称/手机号",
|
||||
"lock": "锁定",
|
||||
"scrubLock": "取消锁定"
|
||||
}
|
||||
7
admin/src/lang/zh-cn/setting.adminlogin.json
Normal file
7
admin/src/lang/zh-cn/setting.adminlogin.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"isCaptcha": "是否启用验证码",
|
||||
"bgImg": "背景图片",
|
||||
"admin": "平台端",
|
||||
"isBgImgTip": "建议上传尺寸为450*400px",
|
||||
"site": "站点端"
|
||||
}
|
||||
@ -1,13 +1,13 @@
|
||||
{
|
||||
"siteId":"站点id",
|
||||
"messageKey":"消息模板",
|
||||
"messageType":"消息类型",
|
||||
"messageInfo":"消息详情",
|
||||
"noticeKey":"消息模板",
|
||||
"noticeType":"消息类型",
|
||||
"noticeInfo":"消息详情",
|
||||
"uid":"通知的用户id",
|
||||
"memberId":"消息的会员id",
|
||||
"nickname":"接收会员",
|
||||
"receiver":"手机/OPENID",
|
||||
"messageData":"消息内容",
|
||||
"noticeData":"消息内容",
|
||||
"isClick":"点击次数",
|
||||
"searchReceiver":"接收人",
|
||||
"isVisit":"访问次数",
|
||||
@ -17,16 +17,16 @@
|
||||
"sms":"短信",
|
||||
"weapp":"微信小程序",
|
||||
"wechat":"微信公众号",
|
||||
"messageTypePlaceholder":"请选择消息类型",
|
||||
"noticeTypePlaceholder":"请选择消息类型",
|
||||
"uidPlaceholder":"请输入通知的用户id",
|
||||
"memberIdPlaceholder":"请输入消息的会员id",
|
||||
"nicknamePlaceholder":"请输入接收人用户昵称或姓名",
|
||||
"receiverPlaceholder":"请输入接收人手机号/openid",
|
||||
"messageDataPlaceholder":"请输入消息数据",
|
||||
"noticeDataPlaceholder":"请输入消息数据",
|
||||
"isClickPlaceholder":"请输入点击次数",
|
||||
"isVisitPlaceholder":"请输入访问次数",
|
||||
"visitTimePlaceholder":"请输入访问时间",
|
||||
"createTimePlaceholder":"请输入消息时间",
|
||||
"buyerMessage": "会员消息",
|
||||
"sellerMessage":"平台消息"
|
||||
"buyerNotice": "会员消息",
|
||||
"sellerNotice":"平台消息"
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
{
|
||||
"buyerMessage": "会员消息",
|
||||
"sellerMessage":"平台消息",
|
||||
"buyerNotice": "会员消息",
|
||||
"sellerNotice":"平台消息",
|
||||
"sms":"短信",
|
||||
"weapp":"微信小程序",
|
||||
"wechat":"微信公众号",
|
||||
"messageSetting":"消息设置",
|
||||
"noticeSetting":"消息设置",
|
||||
"name": "模板名称",
|
||||
"title": "场景",
|
||||
"smsContent": "短信内容",
|
||||
@ -34,5 +34,20 @@
|
||||
"appIdTips": "支付宝分配给开发者的应用ID",
|
||||
"appPublicCertPathTips": "上传appCertPublicKey文件",
|
||||
"alipayPublicCertPathTips": "上传alipayCertPublicKey文件",
|
||||
"alipayRootCertPathTips": "上传alipayRootCert文件"
|
||||
"alipayRootCertPathTips": "上传alipayRootCert文件",
|
||||
"payType": "支付方式",
|
||||
"templateName": "配置信息",
|
||||
"settingDefaultPay": "设置默认支付",
|
||||
"settingDefault": "设置默认",
|
||||
"defaultTamplate": "请选择模板",
|
||||
"isEnable": "是否启用",
|
||||
"onState": "开启状态",
|
||||
"configurePaymentMethod": "请先配置值该支付方式",
|
||||
"enablePaymentMode": "请先开启该支付方式",
|
||||
"clickConfigure": "点击配置",
|
||||
"setConfig": "设置支付配置",
|
||||
"open": "开启",
|
||||
"notOpen": "未开启",
|
||||
"cancel": "取消"
|
||||
|
||||
}
|
||||
31
admin/src/lang/zh-cn/setting.pay.transfer.json
Normal file
31
admin/src/lang/zh-cn/setting.pay.transfer.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"wechatpay": "微信打款设置",
|
||||
"alipay": "支付宝打款设置",
|
||||
"mchId": "商户号",
|
||||
"mchIdPlaceholder": "请输入商户号",
|
||||
"mchIdTips": "微信支付商户号(MCHID)",
|
||||
"mchSecretKey": "API密钥",
|
||||
"mchSecretKeyPlaceholder": "请输入API密钥",
|
||||
"mchSecretKeyTips": "微信支付商户API密钥(paySignKey)",
|
||||
"mchSecretCert": "商户私钥",
|
||||
"mchSecretCertPlaceholder": "请上传商户私钥",
|
||||
"mchSecretCertTips": "微信支付API证书(apiclient_key.pem)",
|
||||
"mchPublicCertPath": "商户公钥",
|
||||
"mchPublicCertPathPlaceholder": "请上传商户公钥",
|
||||
"mchPublicCertPathTips": "微信支付API证书(apiclient_cert.pem)",
|
||||
"appId": "app_id",
|
||||
"appIdPlaceholder": "请输入app_id",
|
||||
"appSecretCert": "应用私钥",
|
||||
"appSecretCertPlaceholder": "请输入应用私钥",
|
||||
"appPublicCertPath": "应用公钥",
|
||||
"appPublicCertPathPlaceholder": "请上传应用公钥",
|
||||
"alipayPublicCertPath": "支付宝公钥",
|
||||
"alipayPublicCertPathPlaceholder": "请上传支付宝公钥",
|
||||
"alipayRootCertPath": "支付宝根证书",
|
||||
"alipayRootCertPathPlaceholder": "请上传支付宝根证书",
|
||||
"appIdTips": "支付宝分配给开发者的应用ID",
|
||||
"appPublicCertPathTips": "上传appCertPublicKey文件",
|
||||
"alipayPublicCertPathTips": "上传alipayCertPublicKey文件",
|
||||
"alipayRootCertPathTips": "上传alipayRootCert文件",
|
||||
"operationTip": "温馨提示:打款设置用于会员提现转账,发放红包等场景"
|
||||
}
|
||||
32
admin/src/lang/zh-cn/setting.sms.records.json
Normal file
32
admin/src/lang/zh-cn/setting.sms.records.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"siteId":"站点id",
|
||||
"noticeKey":"消息模板",
|
||||
"noticeType":"消息类型",
|
||||
"noticeInfo":"消息详情",
|
||||
"uid":"通知的用户id",
|
||||
"memberId":"消息的会员id",
|
||||
"nickname":"接收会员",
|
||||
"receiver":"手机号",
|
||||
"noticeData":"消息内容",
|
||||
"isClick":"点击次数",
|
||||
"searchReceiver":"接收人",
|
||||
"isVisit":"访问次数",
|
||||
"createTime":"发送时间",
|
||||
"startDate":"开始时间",
|
||||
"endDate":"结束时间",
|
||||
"sms":"短信",
|
||||
"weapp":"微信小程序",
|
||||
"wechat":"微信公众号",
|
||||
"noticeTypePlaceholder":"请选择消息类型",
|
||||
"uidPlaceholder":"请输入通知的用户id",
|
||||
"memberIdPlaceholder":"请输入消息的会员id",
|
||||
"nicknamePlaceholder":"请输入接收人用户昵称或姓名",
|
||||
"receiverPlaceholder":"请输入接收人手机号",
|
||||
"noticeDataPlaceholder":"请输入消息数据",
|
||||
"isClickPlaceholder":"请输入点击次数",
|
||||
"isVisitPlaceholder":"请输入访问次数",
|
||||
"visitTimePlaceholder":"请输入访问时间",
|
||||
"createTimePlaceholder":"请输入消息时间",
|
||||
"buyerNotice": "会员消息",
|
||||
"sellerNotice":"平台消息"
|
||||
}
|
||||
@ -3,18 +3,18 @@
|
||||
"updateTime": "修改时间",
|
||||
"createTime": "创建时间",
|
||||
"groupName": "套餐名称",
|
||||
"groupDesc": "套餐介绍",
|
||||
"groupDesc": "套餐说明",
|
||||
"groupRoles": "套餐权限",
|
||||
"groupDeleteTips": "确定要删除该套餐吗?",
|
||||
"groupNamePlaceholder": "请输入套餐名称",
|
||||
"groupDescPlaceholder": "请输入套餐介绍",
|
||||
"groupDescPlaceholder": "请输入套餐说明",
|
||||
"groupRolesPlaceholder": "请选择套餐权限",
|
||||
"groupPlaceholder": "请选择权限",
|
||||
"permission": "权限",
|
||||
"updateGroup":"编辑套餐",
|
||||
"addGroup":"添加套餐",
|
||||
"checkStrictly": "父子级不关联",
|
||||
"remark": "备注",
|
||||
"remark": "套餐说明",
|
||||
"reset": "重置",
|
||||
"search": "搜索"
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
"status":"状态",
|
||||
"businessHours":"营业时间",
|
||||
"createTime":"创建时间",
|
||||
"expireTime":"过期时间",
|
||||
"expireTime":"到期时间",
|
||||
"siteNamePlaceholder":"请输入站点名称",
|
||||
"createTimePlaceholder":"请输入创建时间",
|
||||
"addSite":"添加站点",
|
||||
@ -24,5 +24,7 @@
|
||||
"confirmPasswordPlaceholder": "请再次确认密码",
|
||||
"userRealNamePlaceholder": "请输入名称",
|
||||
"expireTimePlaceholder":"请选择到期时间",
|
||||
"confirmPasswordError": "两次输入的密码不一致"
|
||||
"confirmPasswordError": "两次输入的密码不一致",
|
||||
"operationTip": "温馨提示:站点登录页面"
|
||||
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
{
|
||||
"todayData": "今日数据",
|
||||
"memberNumb": "会员数量",
|
||||
"memberNumb": "新增会员数",
|
||||
"orderMoney": "订单金额",
|
||||
"numberOfSites": "站点数量",
|
||||
"numberOfVisitors": "访客数量",
|
||||
"numberOfVisitors": "今日访客数",
|
||||
"commonlyUsedFunction": "常用功能",
|
||||
"articleList": "文章列表",
|
||||
"memberManagement": "会员管理",
|
||||
|
||||
@ -1,3 +1,12 @@
|
||||
{
|
||||
"content":"功能正在开发,请敬请期待..."
|
||||
"noPlug":"暂无插件",
|
||||
"install":"安装",
|
||||
"unload":"卸载",
|
||||
"installLabel":"已安装",
|
||||
"uninstalledLabel":"未安装",
|
||||
"version":"版本",
|
||||
"title":"名称",
|
||||
"desc":"描述",
|
||||
"plugDetail": "插件信息",
|
||||
"author": "作者"
|
||||
}
|
||||
15
admin/src/lang/zh-cn/tools.detection.json
Normal file
15
admin/src/lang/zh-cn/tools.detection.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"title": "名称",
|
||||
"serverInformation": "服务器信息",
|
||||
"systemDemand": "系统环境要求",
|
||||
"authorityStatus": "权限状态",
|
||||
"name": "选项",
|
||||
"demand": "要求",
|
||||
"status": "状态",
|
||||
"environment": "环境",
|
||||
"version": "版本",
|
||||
"phpType": "PHP版本",
|
||||
"phpTypeValue": "大于等于8.0.0",
|
||||
"mysqlType": "mysql版本",
|
||||
"mysqlTypeValue": "大于等于5.7"
|
||||
}
|
||||
7
admin/src/lang/zh-cn/tools.update.json
Normal file
7
admin/src/lang/zh-cn/tools.update.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"refresh":"刷新",
|
||||
"refreshMenu":"刷新菜单",
|
||||
"refreshMenuDesc":"新增/修改插件菜单后,需要刷新插件菜单",
|
||||
"dataCache":"数据缓存",
|
||||
"dataCacheDesc":"新增/修改数据表后,需要清除数据表缓存"
|
||||
}
|
||||
@ -14,8 +14,10 @@
|
||||
</div>
|
||||
<!-- 返回上一页 -->
|
||||
<div class="flex items-center cursor-pointer" v-if="appStore.pageReturn" @click="backFn">
|
||||
<el-icon class="mr-1"><Back /></el-icon>
|
||||
<span class="text-base mr-3">{{t('returnToPreviousPage')}}</span>
|
||||
<el-icon class="mr-1">
|
||||
<Back />
|
||||
</el-icon>
|
||||
<span class="text-base mr-3">{{ t('returnToPreviousPage') }}</span>
|
||||
<span class=" text-gray-300">|</span>
|
||||
</div>
|
||||
<!-- 面包屑导航 -->
|
||||
@ -30,8 +32,9 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="right-panel h-full flex items-center justify-end">
|
||||
<!-- 预览 -->
|
||||
<img class="w-[16px] h-[16px] mr-1" src="@/assets/images/icon_preview.png" :alt="t('preview')" :title="t('preview')">
|
||||
<!-- 预览 只有站点时展示-->
|
||||
<img class="w-[16px] h-[16px] mr-1" v-if="appType == 'site'" src="@/assets/images/icon_preview.png"
|
||||
:alt="t('preview')" :title="t('preview')">
|
||||
<!-- 切换语言 -->
|
||||
<div class="navbar-item flex items-center h-full cursor-pointer">
|
||||
<switch-lang />
|
||||
@ -52,6 +55,18 @@
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<input type="hidden" v-model="comparisonToken">
|
||||
<input type="hidden" v-model="comparisonSiteId">
|
||||
|
||||
<el-dialog v-model="detectionLoginDialog" :title="t('layout.detectionLoginTip')" width="30%"
|
||||
:close-on-click-modal="false" :close-on-press-escape="false" :show-close="false">
|
||||
<span>{{ t('layout.detectionLoginContent') }}</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="detectionLoginFn">{{ t('layout.detectionLoginOperation') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
@ -65,17 +80,43 @@ import useSystemStore from '@/stores/modules/system'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { t } from '@/lang'
|
||||
import storage from '@/utils/storage'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
const router = useRouter()
|
||||
|
||||
const appType = storage.get('app_type')
|
||||
const { toggle: toggleFullscreen, isFullscreen } = useFullscreen()
|
||||
const systemStore = useSystemStore()
|
||||
const appStore = useAppStore()
|
||||
const route = useRoute()
|
||||
const screenWidth = ref(window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth)
|
||||
|
||||
// 检测登录 start
|
||||
const detectionLoginDialog = ref(false)
|
||||
const comparisonToken = ref('')
|
||||
const comparisonSiteId = ref('')
|
||||
if (storage.get('comparisonTokenStorage')) {
|
||||
comparisonToken.value = storage.get('comparisonTokenStorage')
|
||||
// storage.remove(['comparisonTokenStorage']);
|
||||
}
|
||||
if (storage.get('comparisonSiteIdStorage')) {
|
||||
comparisonSiteId.value = storage.get('comparisonSiteIdStorage')
|
||||
// storage.remove(['comparisonSiteIdStorage']);
|
||||
}
|
||||
// 监听标签页面切换
|
||||
document.addEventListener('visibilitychange', e => {
|
||||
if (document.visibilityState === 'visible' && (comparisonSiteId.value != storage.get('siteId') || comparisonToken.value != storage.get('token'))) {
|
||||
detectionLoginDialog.value = true
|
||||
}
|
||||
})
|
||||
|
||||
const detectionLoginFn = () => {
|
||||
detectionLoginDialog.value = false
|
||||
location.reload();
|
||||
}
|
||||
// 检测登录 end
|
||||
|
||||
// 监听窗体宽度变化
|
||||
onMounted(() => {
|
||||
// 监听窗体宽度变化
|
||||
window.onresize = () => {
|
||||
return (() => {
|
||||
screenWidth.value = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
|
||||
@ -111,15 +152,15 @@ const refreshRouter = () => {
|
||||
|
||||
// 面包屑导航
|
||||
const breadcrumb = computed(() => {
|
||||
const matched = route.matched
|
||||
const matched = route.matched.filter(item => { return item.meta.title })
|
||||
if (matched[0] && matched[0].path == '/') matched.splice(0, 1)
|
||||
return matched
|
||||
})
|
||||
|
||||
// 返回上一页
|
||||
const backFn = ()=>{
|
||||
router.go(-1);
|
||||
};
|
||||
const backFn = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -129,5 +170,4 @@ const backFn = ()=>{
|
||||
&:hover {
|
||||
background-color: var(--el-bg-color-page);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
}</style>
|
||||
|
||||
@ -1,18 +1,29 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory, RouteLocationRaw } from 'vue-router'
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
import { STATIC_ROUTES, NO_LOGIN_ROUTES, INDEX_ROUTE, findFirstValidRoute, DECORATE_ROUTER } from './routers'
|
||||
import { STATIC_ROUTES, NO_LOGIN_ROUTES, ROOT_ROUTER, ADMIN_ROUTE, SITE_ROUTE, DECORATE_ROUTER, findFirstValidRoute } from './routers'
|
||||
import { language } from '@/lang'
|
||||
import useSystemStore from '@/stores/modules/system'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import { setWindowTitle } from '@/utils/common'
|
||||
import { setWindowTitle, getAppType, urlToRouteRaw } from '@/utils/common'
|
||||
import storage from '@/utils/storage'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: STATIC_ROUTES,
|
||||
routes: [...STATIC_ROUTES, ADMIN_ROUTE, SITE_ROUTE]
|
||||
})
|
||||
|
||||
/**
|
||||
* 重写push方法
|
||||
*/
|
||||
const originPush = router.push
|
||||
router.push = (to: RouteLocationRaw) => {
|
||||
const route = typeof to == 'string' ? urlToRouteRaw(to) : to
|
||||
const paths = route.path.split('/').filter((item: string) => { return item })
|
||||
route.path = ['admin', 'site', 'decorate'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
|
||||
return originPush(route)
|
||||
}
|
||||
|
||||
// 全局前置守卫
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.configure({ showSpinner: false })
|
||||
@ -23,19 +34,22 @@ router.beforeEach(async (to, from, next) => {
|
||||
const userStore = useUserStore()
|
||||
const siteInfo = storage.get('siteInfo') || false
|
||||
let title = (to.meta?.title || '') + (siteInfo.site_name ? ('-' + siteInfo.site_name) : '')
|
||||
|
||||
// 设置网站标题
|
||||
setWindowTitle(title)
|
||||
// 加载语言包
|
||||
await language.loadLocaleMessages(to.path, useSystemStore().lang);
|
||||
|
||||
const loginPath = to.path == '/' ? '/admin/login' : `${to.matched[0].path}/login`
|
||||
|
||||
// 判断是否需登录
|
||||
if (NO_LOGIN_ROUTES.includes(to.path)) {
|
||||
next()
|
||||
} else if (userStore.token) {
|
||||
// 如果已加载路由
|
||||
if (userStore.routers.length) {
|
||||
if (to.path === '/login') {
|
||||
next('/')
|
||||
if (to.path === loginPath) {
|
||||
next(`/${getAppType()}`)
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
@ -45,8 +59,17 @@ router.beforeEach(async (to, from, next) => {
|
||||
|
||||
// 设置首页路由
|
||||
const firstRoute = findFirstValidRoute(userStore.routers)
|
||||
INDEX_ROUTE.redirect = { name: firstRoute }
|
||||
router.addRoute(INDEX_ROUTE)
|
||||
ROOT_ROUTER.redirect = { name: firstRoute }
|
||||
router.addRoute(ROOT_ROUTER)
|
||||
|
||||
// 设置应用首页路由
|
||||
if (getAppType() == 'admin') {
|
||||
ADMIN_ROUTE.children[0].redirect = { name: firstRoute }
|
||||
router.addRoute(ADMIN_ROUTE)
|
||||
} else {
|
||||
SITE_ROUTE.children[0].redirect = { name: firstRoute }
|
||||
router.addRoute(SITE_ROUTE)
|
||||
}
|
||||
|
||||
// 添加动态路由
|
||||
userStore.routers.forEach(route => {
|
||||
@ -56,25 +79,35 @@ router.beforeEach(async (to, from, next) => {
|
||||
router.addRoute(DECORATE_ROUTER)
|
||||
return
|
||||
}
|
||||
|
||||
if (!route.children) {
|
||||
router.addRoute('root', route)
|
||||
if (route.meta.app == 'admin') {
|
||||
router.addRoute(ADMIN_ROUTE.children[0].name, route)
|
||||
} else {
|
||||
router.addRoute(SITE_ROUTE.children[0].name, route)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 动态添加可访问路由表
|
||||
router.addRoute(route)
|
||||
if (route.meta.app == 'admin') {
|
||||
router.addRoute(ADMIN_ROUTE.name, route)
|
||||
} else {
|
||||
router.addRoute(SITE_ROUTE.name, route)
|
||||
}
|
||||
})
|
||||
|
||||
next({ path: to.path, query: to.query, replace: true })
|
||||
} catch (err) {
|
||||
userStore.logout()
|
||||
next({ path: '/login', query: { redirect: to.fullPath } })
|
||||
next({ path: loginPath, query: { redirect: to.fullPath } })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (to.path === '/login') {
|
||||
if (to.path === loginPath) {
|
||||
next()
|
||||
} else {
|
||||
next({ path: '/login', query: { redirect: to.fullPath } })
|
||||
next({ path: loginPath, query: { redirect: to.fullPath } })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -4,52 +4,86 @@ import Decorate from '@/layout/decorate/index.vue'
|
||||
|
||||
// 静态路由
|
||||
export const STATIC_ROUTES: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: `${import.meta.env.BASE_URL}`,
|
||||
component: Default,
|
||||
name: 'root'
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: () => import('@/views/error/404.vue')
|
||||
},
|
||||
{
|
||||
path: '/403',
|
||||
component: () => import('@/views/error/403.vue')
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
component: () => import('@/views/login/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/user',
|
||||
component: Default,
|
||||
children: [
|
||||
{
|
||||
path: 'center',
|
||||
meta: {
|
||||
type: 1,
|
||||
title: '个人中心'
|
||||
},
|
||||
component: () => import('@/views/index/personal.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 免登录路由
|
||||
export const NO_LOGIN_ROUTES: string[] = [
|
||||
'/403',
|
||||
'/404'
|
||||
]
|
||||
|
||||
// 首页路由
|
||||
export const INDEX_ROUTE: RouteRecordRaw = {
|
||||
// 根路由
|
||||
export const ROOT_ROUTER: RouteRecordRaw = {
|
||||
path: '/',
|
||||
component: Default,
|
||||
name: Symbol()
|
||||
}
|
||||
|
||||
// 平台端根路由
|
||||
export const ADMIN_ROUTE: RouteRecordRaw = {
|
||||
path: '/admin',
|
||||
name: Symbol('admin'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: Symbol('adminRoot'),
|
||||
component: Default
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
component: () => import('@/views/login/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
component: Default,
|
||||
children: [
|
||||
{
|
||||
path: 'center',
|
||||
meta: {
|
||||
type: 1,
|
||||
title: '个人中心'
|
||||
},
|
||||
component: () => import('@/views/index/personal.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 站点端路由
|
||||
export const SITE_ROUTE: RouteRecordRaw = {
|
||||
path: '/site',
|
||||
name: Symbol('site'),
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: Symbol('siteRoot'),
|
||||
component: Default
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
component: () => import('@/views/login/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
component: Default,
|
||||
children: [
|
||||
{
|
||||
path: 'center',
|
||||
meta: {
|
||||
type: 1,
|
||||
title: '个人中心'
|
||||
},
|
||||
component: () => import('@/views/index/personal.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 装修路由
|
||||
export const DECORATE_ROUTER: RouteRecordRaw = {
|
||||
path: '/decorate',
|
||||
@ -70,7 +104,8 @@ interface Route {
|
||||
type: string
|
||||
},
|
||||
children?: [],
|
||||
is_show: boolean
|
||||
is_show: boolean,
|
||||
app_type: string
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,13 +115,14 @@ interface Route {
|
||||
*/
|
||||
const createRoute = function (route: Route, parentRoute: RouteRecordRaw | null = null): RouteRecordRaw {
|
||||
const record: RouteRecordRaw = {
|
||||
path: parentRoute ? route.router_path : '/' + route.router_path,
|
||||
path: parentRoute ? route.router_path : route.router_path != 'decorate' ? `/${route.app_type}/${route.router_path}` : `/${route.router_path}`,
|
||||
name: parentRoute ? Symbol(`${parentRoute.path}/${route.router_path}`) : Symbol(`/${route.router_path}`),
|
||||
meta: {
|
||||
title: route.menu_name,
|
||||
icon: route.icon,
|
||||
type: route.menu_type,
|
||||
show: route.is_show
|
||||
show: route.is_show,
|
||||
app: route.app_type
|
||||
}
|
||||
}
|
||||
if (route.menu_type == 0) {
|
||||
|
||||
@ -50,20 +50,19 @@ const useDiyStore = defineStore('diy', {
|
||||
},
|
||||
actions: {
|
||||
// 添加组件
|
||||
addComponent(data: any) {
|
||||
addComponent(key: string, data: any) {
|
||||
// 加载完才能添加组件
|
||||
if(!this.load) return;
|
||||
if (!this.load) return;
|
||||
|
||||
// 删除不用的字段
|
||||
let component = cloneDeep(data);
|
||||
|
||||
component.id = this.generateRandom();
|
||||
component.componentName = component.name;
|
||||
component.componentName = key;
|
||||
component.componentTitle = component.title;
|
||||
component.maxCount = component.max_count;
|
||||
|
||||
Object.assign(component, component.value);
|
||||
delete component.name;
|
||||
delete component.title;
|
||||
delete component.value;
|
||||
delete component.type;
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { getToken, setToken, removeToken } from '@/utils/common'
|
||||
import { getToken, setToken, removeToken, getAppType } from '@/utils/common'
|
||||
import { login, getAuthMenus } from '@/api/auth'
|
||||
import storage from '@/utils/storage'
|
||||
import router from '@/router'
|
||||
import { formatRouters, INDEX_ROUTE } from '@/router/routers'
|
||||
import { formatRouters } from '@/router/routers'
|
||||
import useTabbarStore from './tabbar'
|
||||
|
||||
interface User {
|
||||
@ -25,9 +25,9 @@ const useSystemStore = defineStore('user', {
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
login(form: object) {
|
||||
login(form: object, app_type: any) {
|
||||
return new Promise((resolve, reject) => {
|
||||
login(form)
|
||||
login(form, app_type)
|
||||
.then((res) => {
|
||||
this.token = res.data.token
|
||||
this.userInfo = res.data.userinfo
|
||||
@ -35,6 +35,8 @@ const useSystemStore = defineStore('user', {
|
||||
storage.set({ key: 'userinfo', data: res.data.userinfo })
|
||||
storage.set({ key: 'siteId', data: res.data.site_id })
|
||||
storage.set({ key: 'siteInfo', data: res.data.site_info })
|
||||
storage.set({ key: 'comparisonSiteIdStorage', data: res.data.site_id })
|
||||
storage.set({ key: 'comparisonTokenStorage', data: res.data.token })
|
||||
resolve(res)
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -48,15 +50,10 @@ const useSystemStore = defineStore('user', {
|
||||
this.siteInfo = {}
|
||||
removeToken()
|
||||
storage.remove(['userinfo', 'siteId', 'siteInfo'])
|
||||
// 清除路由
|
||||
this.routers.forEach(item => {
|
||||
router.removeRoute(item.name)
|
||||
})
|
||||
router.removeRoute(INDEX_ROUTE.name)
|
||||
this.routers = []
|
||||
// 清除tabbar
|
||||
useTabbarStore().clearTab()
|
||||
router.push('/login')
|
||||
router.push(`/${getAppType()}/login`)
|
||||
},
|
||||
getAuthMenus() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 3883393 */
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_c2tb4v0fz24.woff2?t=1681374762000') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_c2tb4v0fz24.woff?t=1681374762000') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_c2tb4v0fz24.ttf?t=1681374762000') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_3883393_4jlgm3tby7.woff2?t=1683947082967') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_4jlgm3tby7.woff?t=1683947082967') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3883393_4jlgm3tby7.ttf?t=1683947082967') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,46 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icontuikuanjilu:before {
|
||||
content: "\e8cf";
|
||||
}
|
||||
|
||||
.icongengxinhuancun:before {
|
||||
content: "\e686";
|
||||
}
|
||||
|
||||
.iconsixingjiance:before {
|
||||
content: "\e645";
|
||||
}
|
||||
|
||||
.iconzhuceshezhi:before {
|
||||
content: "\e6ad";
|
||||
}
|
||||
|
||||
.iconmanage-apply:before {
|
||||
content: "\e619";
|
||||
}
|
||||
|
||||
.iconyingyongguanli:before {
|
||||
content: "\e61f";
|
||||
}
|
||||
|
||||
.iconkaifazheguanli:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.iconlianmengguanli:before {
|
||||
content: "\e65f";
|
||||
}
|
||||
|
||||
.icondianzan:before {
|
||||
content: "\ec7f";
|
||||
}
|
||||
|
||||
.iconh5e:before {
|
||||
content: "\e654";
|
||||
}
|
||||
|
||||
.iconyingyongshichang:before {
|
||||
content: "\e618";
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import type {App} from 'vue'
|
||||
import type { App } from 'vue'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import {useCssVar, useTitle} from '@vueuse/core'
|
||||
import { useCssVar, useTitle } from '@vueuse/core'
|
||||
import colorFunction from 'css-color-function'
|
||||
import storage from './storage'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
/**
|
||||
* 全局注册element-icon
|
||||
@ -45,6 +46,20 @@ export function setThemeColor(color: string, mode: string = 'light'): void {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前访问应用类型
|
||||
*/
|
||||
export function getAppType() {
|
||||
const path = location.pathname.split('/').filter((val) => { return val })
|
||||
|
||||
if (!path.length) {
|
||||
return 'admin'
|
||||
} else {
|
||||
const app = path[0]
|
||||
return app == 'decorate' ? 'site' : app
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置网站 title
|
||||
* @param value
|
||||
@ -68,7 +83,7 @@ export function getToken(): null | string {
|
||||
* @returns
|
||||
*/
|
||||
export function setToken(token: string): void {
|
||||
storage.set({key: 'token', data: token})
|
||||
storage.set({ key: 'token', data: token })
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,4 +157,20 @@ export function getWapDomain(): string {
|
||||
} else {
|
||||
return (import.meta.env.VITE_WAP_DOMAIN || location.origin + '/wap') + (storage.get('siteId') == 1 ? '' : '/s' + storage.get('siteId'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* url 转 route
|
||||
* @param url
|
||||
*/
|
||||
export function urlToRouteRaw(url: string) {
|
||||
const query = {}
|
||||
const [path, param] = url.split('?')
|
||||
|
||||
param && param.split('&').forEach((str : string) => {
|
||||
let [name, value] = str.split('=')
|
||||
query[name] = value
|
||||
})
|
||||
|
||||
return { path, query }
|
||||
}
|
||||
@ -52,7 +52,7 @@ class Request {
|
||||
this.instance.interceptors.response.use(
|
||||
(response: requestResponse) => {
|
||||
const res = response.data
|
||||
if (res.code != 200) {
|
||||
if (res.code != 1) {
|
||||
this.handleAuthError(res.code)
|
||||
if (response.config.showErrorMessage) ElMessage({ message: res.msg, type: 'error' })
|
||||
return Promise.reject(new Error(res.msg || 'Error'))
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { getAppType } from './common'
|
||||
|
||||
interface setParam {
|
||||
key: string,
|
||||
data: any,
|
||||
@ -6,6 +8,11 @@ interface setParam {
|
||||
}
|
||||
|
||||
class Storage {
|
||||
private prefix = ''
|
||||
|
||||
public constructor() {
|
||||
this.prefix = getAppType()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
@ -13,7 +20,7 @@ class Storage {
|
||||
*/
|
||||
public set(param: setParam) {
|
||||
try {
|
||||
window.localStorage.setItem(param.key, JSON.stringify(param.data))
|
||||
window.localStorage.setItem(`${this.prefix}.${param.key}`, JSON.stringify(param.data))
|
||||
typeof param.success == 'function' && param.success()
|
||||
} catch (error) {
|
||||
typeof param.fail == 'function' && param.fail(error)
|
||||
@ -27,7 +34,7 @@ class Storage {
|
||||
*/
|
||||
public get(key: string) {
|
||||
try {
|
||||
const json: any = window.localStorage.getItem(key)
|
||||
const json: any = window.localStorage.getItem(`${this.prefix}.${key}`)
|
||||
return JSON.parse(json)
|
||||
} catch (error) {
|
||||
return null
|
||||
@ -39,8 +46,8 @@ class Storage {
|
||||
* @param key
|
||||
*/
|
||||
public remove(key: string | string[]) {
|
||||
if (typeof key == 'string') window.localStorage.removeItem(key)
|
||||
else key.forEach(item => { window.localStorage.removeItem(item) })
|
||||
if (typeof key == 'string') window.localStorage.removeItem(`${this.prefix}.${key}`)
|
||||
else key.forEach(item => { window.localStorage.removeItem(`${this.prefix}.${item}`) })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
63
admin/src/views/app/index.vue
Normal file
63
admin/src/views/app/index.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="main-container bg-[#fff] min-w-[1000px] min-h-[650px]">
|
||||
<div class="pt-[1px]" v-for="(listItems, listIndex) in appManageList" :key="listIndex">
|
||||
<p class="ml-4 mt-[20px] border-l-[2px] border-[#273de3] pl-4 leading-[1]">{{ listItems.name }}</p>
|
||||
<div class="flex flex-wrap" v-if="isTrue == 0">
|
||||
<div @click="toLink(appItems.url)" class="flex cursor-pointer ml-4 mt-[20px] w-[240px] p-[10px] border-[1px] border-[#eee] border-[solid]" v-for="(appItems, appIndex) in listItems.app_list" :key="appIndex">
|
||||
<div class="flex justify-center items-center mr-[10px] min-w-[50px]">
|
||||
<img v-if="appItems.icon" class="w-[50px] h-[50px]" :src="img(appItems.icon)"/>
|
||||
</div>
|
||||
<div class="w-[150px]">
|
||||
<p class="app-text text-[14px] text-[#666]">{{ appItems.title }}</p>
|
||||
<p class="app-text text-[12px] text-[#999]">{{ appItems.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap" v-if="isTrue == 1">
|
||||
<div @click="toLink(appItems.url)" class="cursor-pointer ml-4 mt-[20px] w-[140px] p-[10px] border-[1px] border-[#eee] border-[solid]" v-for="(appItems, appIndex) in listItems.app_list" :key="appIndex">
|
||||
<div class="flex justify-center items-center">
|
||||
<img v-if="appItems.cover" class="w-[110px] h-[110px]" :src="img(appItems.cover)"/>
|
||||
</div>
|
||||
<div class="text-center mt-2">
|
||||
<p class="app-text text-[14px] text-[#666]">{{ appItems.title }}</p>
|
||||
<p class="app-text text-[12px] text-[#999]">{{ appItems.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getAppMange } from '@/api/sys'
|
||||
import { img } from '@/utils/common'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const appManageList = ref([])
|
||||
const isTrue = ref(1)
|
||||
const checkAppMange = () => {
|
||||
getAppMange().then(res=>{
|
||||
appManageList.value = res.data;
|
||||
})
|
||||
}
|
||||
checkAppMange()
|
||||
|
||||
const router = useRouter()
|
||||
/**
|
||||
* 链接跳转
|
||||
*/
|
||||
const toLink = (link) => {
|
||||
router.push(link)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-text {
|
||||
overflow:hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow:ellipsis;
|
||||
}
|
||||
</style>
|
||||
@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px"
|
||||
:destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form"
|
||||
v-loading="loading">
|
||||
<el-form-item :label="t('name')" prop="name">
|
||||
<el-input v-model="formData.name" clearable :placeholder="t('namePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('sort')" prop="sort">
|
||||
<el-input-number v-model="formData.sort" :min="0" />
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item :label="t('isShow')">
|
||||
<el-radio-group v-model="formData.is_show" :placeholder="t('isShowPlaceholder')">
|
||||
<el-radio :label="1">{{ t('show') }}</el-radio>
|
||||
@ -32,9 +32,9 @@
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { addArticleCategory, updateArticleCategory, getArticleCategoryInfo } from '@/api/article'
|
||||
import { addArticleCategory, editArticleCategory, getArticleCategoryInfo } from '@/api/article'
|
||||
|
||||
let popTitle:string = '';
|
||||
let popTitle: string = '';
|
||||
|
||||
let showDialog = ref(false)
|
||||
const loading = ref(true)
|
||||
@ -42,7 +42,7 @@ const loading = ref(true)
|
||||
/**
|
||||
* 表单数据
|
||||
*/
|
||||
const initialFormData = {
|
||||
const initialFormData = {
|
||||
category_id: '',
|
||||
name: '',
|
||||
sort: '',
|
||||
@ -55,34 +55,34 @@ const formRef = ref<FormInstance>()
|
||||
// 表单验证规则
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
name: [
|
||||
{ required: true, message: t('namePlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value.length > 20) {
|
||||
callback(new Error(t('nameMax')))
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
sort: [
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if(value === "" || isNaN(value)){
|
||||
callback(new Error(t('sortNumber')))
|
||||
}
|
||||
if (parseInt(value) > 10000) {
|
||||
callback(new Error(t('sortBetween')))
|
||||
}
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
|
||||
name: [
|
||||
{ required: true, message: t('namePlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value.length > 20) {
|
||||
callback(new Error(t('nameMax')))
|
||||
}
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
sort: [
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if (value === "" || isNaN(value)) {
|
||||
callback(new Error(t('sortNumber')))
|
||||
}
|
||||
if (parseInt(value) > 10000) {
|
||||
callback(new Error(t('sortBetween')))
|
||||
}
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
@ -94,7 +94,7 @@ const emit = defineEmits(['complete'])
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
let save = formData.category_id ? updateArticleCategory : addArticleCategory
|
||||
let save = formData.category_id ? editArticleCategory : addArticleCategory
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form"
|
||||
v-loading="loading">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" clearable :placeholder="t('titlePlaceholder')" class="input-width"
|
||||
maxlength="20" />
|
||||
@ -62,10 +63,11 @@
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance, ElNotification } from 'element-plus'
|
||||
import { getArticleInfo, getArticleCategoryAll, addArticle, updateArticle } from '@/api/article'
|
||||
import { getArticleInfo, getArticleCategoryAll, addArticle, editArticle } from '@/api/article'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import useTabbarStore from '@/stores/modules/tabbar'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@ -77,7 +79,7 @@ const appStore = useAppStore()
|
||||
|
||||
// 页面返回按钮
|
||||
appStore.pageReturn = true;
|
||||
watch(route, (newX,oldX) => {
|
||||
watch(route, (newX, oldX) => {
|
||||
appStore.pageReturn = false;
|
||||
});
|
||||
|
||||
@ -104,16 +106,23 @@ const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
const setFormData = async (id: number = 0) => {
|
||||
loading.value = true;
|
||||
Object.assign(formData, initialFormData)
|
||||
if(id){
|
||||
if (id) {
|
||||
const data = await (await getArticleInfo(id)).data
|
||||
if (!data || Object.keys(data).length == 0) {
|
||||
ElMessage.error(t('articleNull'))
|
||||
setTimeout(() => {
|
||||
router.go(-1);
|
||||
}, 2000)
|
||||
return false;
|
||||
}
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
loading.value = false;
|
||||
}else{
|
||||
} else {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (id) setFormData(id)
|
||||
|
||||
@ -139,9 +148,9 @@ const formRules = computed(() => {
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
let content = value.replace(/<[^<>]+>/g, "").replace(/ /gi, "")
|
||||
if(!content && value.indexOf('img') === -1){
|
||||
if (!content && value.indexOf('img') === -1) {
|
||||
callback(new Error(t('contentPlaceholder')))
|
||||
}else callback()
|
||||
} else callback()
|
||||
},
|
||||
trigger: ['blur', 'change']
|
||||
}
|
||||
@ -155,7 +164,7 @@ const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
const data = formData
|
||||
const save = id ? updateArticle : addArticle
|
||||
const save = id ? editArticle : addArticle
|
||||
save(data).then(res => {
|
||||
loading.value = false
|
||||
back();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
|
||||
|
||||
<div class="flex justify-between">
|
||||
<el-button type="primary" @click="addEvent">
|
||||
{{ t('addArticle') }}
|
||||
@ -14,8 +14,8 @@
|
||||
<el-input v-model="articleTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('categoryName')" prop="category_id">
|
||||
<el-select v-model="articleTableData.searchParam.category_id" clearable :placeholder="t('categoryIdPlaceholder')"
|
||||
class="input-width">
|
||||
<el-select v-model="articleTableData.searchParam.category_id" clearable
|
||||
:placeholder="t('categoryIdPlaceholder')" class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item['name']" :value="item['category_id']" v-for="item in categoryList" />
|
||||
</el-select>
|
||||
@ -34,18 +34,18 @@
|
||||
</template>
|
||||
|
||||
<el-table-column prop="title" :show-overflow-tooltip="true" :label="t('title')" width="140" />
|
||||
|
||||
|
||||
<el-table-column :label="t('image')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-image class="w-12 h-12" v-if="row.image" :src="img(row.image)" fit="contain" />
|
||||
|
||||
<el-image class="w-12 h-12" v-if="row.image" :src="img(row.image)" fit="contain" />
|
||||
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="category_name" :label="t('categoryName')" align="center" min-width="140" />
|
||||
<el-table-column prop="category_name" :label="t('categoryName')" align="center" min-width="140" />
|
||||
|
||||
<el-table-column prop="summary" :label="t('summary')" width="180" :show-overflow-tooltip="true" />
|
||||
|
||||
<el-table-column prop="summary" :label="t('summary')" width="180" :show-overflow-tooltip="true"/>
|
||||
|
||||
<el-table-column :label="t('isShow')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.is_show == 1">{{ t('show') }}</span>
|
||||
@ -83,8 +83,8 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getArticleList, deleteArticle,getArticleCategoryAll } from '@/api/article'
|
||||
import { img } from '@/utils/common'
|
||||
import { getArticleList, deleteArticle, getArticleCategoryAll } from '@/api/article'
|
||||
import { img, getAppType } from '@/utils/common'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
@ -96,7 +96,7 @@ const articleTableData = reactive({
|
||||
data: [],
|
||||
searchParam: {
|
||||
title: '',
|
||||
category_id:''
|
||||
category_id: ''
|
||||
}
|
||||
})
|
||||
const categoryList = ref([])
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px"
|
||||
:destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" class="page-form" ref="formRef" :rules="formRules" v-loading="loading">
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" class="page-form" ref="formRef" :rules="formRules"
|
||||
v-loading="loading">
|
||||
<el-form-item :label="t('menuName')" prop="menu_name">
|
||||
<el-input v-model="formData.menu_name" :placeholder="t('menuNamePlaceholder')" class="input-width" />
|
||||
</el-form-item>
|
||||
@ -98,12 +98,12 @@ import { ref, reactive, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import selectMenuItem from './select-menu-item.vue'
|
||||
import { addMenu, updateMenu, getMenuInfo } from '@/api/sys'
|
||||
import { addMenu, editMenu, getMenuInfo } from '@/api/sys'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const method = ref('post')
|
||||
const loading = ref(false)
|
||||
let popTitle:string = '';
|
||||
let popTitle: string = '';
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
@ -121,8 +121,8 @@ const initialFormData = {
|
||||
sort: '',
|
||||
status: 1,
|
||||
is_show: 1,
|
||||
menu_key:'',
|
||||
app_type:''
|
||||
menu_key: '',
|
||||
app_type: ''
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
@ -147,12 +147,12 @@ const formRules = computed(() => {
|
||||
],
|
||||
menu_key: [
|
||||
{ required: true, message: t('menuKeyPlaceholder'), trigger: 'blur' },
|
||||
{
|
||||
{
|
||||
validator: (rule: any, value: string, callback: any) => {
|
||||
if(!validataMenuKey(value)){
|
||||
if (!validataMenuKey(value)) {
|
||||
callback(new Error(t('menuKeyValidata')))
|
||||
}
|
||||
|
||||
|
||||
callback()
|
||||
},
|
||||
trigger: 'blur'
|
||||
@ -188,7 +188,7 @@ const emit = defineEmits(['complete'])
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
const save = formData.id ? updateMenu : addMenu
|
||||
const save = formData.id ? editMenu : addMenu
|
||||
|
||||
await formEl.validate(async (valid, fields) => {
|
||||
if (valid) {
|
||||
@ -219,7 +219,7 @@ const setFormData = async (row: any = null) => {
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (data[key] != undefined) formData[key] = data[key]
|
||||
})
|
||||
}else{
|
||||
} else {
|
||||
Object.keys(formData).forEach((key: string) => {
|
||||
if (row[key] != undefined) formData[key] = row[key]
|
||||
})
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px"
|
||||
:destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form"
|
||||
v-loading="loading">
|
||||
<el-form-item :label="t('roleName')" prop="role_name">
|
||||
<el-input v-model="formData.role_name" :placeholder="t('roleNamePlaceholder')" clearable
|
||||
:disabled="formData.uid" class="input-width" maxlength="10" :show-word-limit="true" />
|
||||
@ -42,12 +42,12 @@
|
||||
import { ref, reactive, computed, watch, toRaw } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { addRole, updateRole, getRoleInfo, getSiteMenus } from '@/api/sys'
|
||||
import { addRole, editRole, getRoleInfo, getSiteMenus } from '@/api/sys'
|
||||
import { debounce } from '@/utils/common'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
let popTitle:string = '';
|
||||
let popTitle: string = '';
|
||||
|
||||
// 获取权限数据
|
||||
const menus = ref<Record<string, any>[]>([])
|
||||
@ -110,7 +110,7 @@ const emit = defineEmits(['complete'])
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
const save = formData.role_id ? updateRole : addRole
|
||||
const save = formData.role_id ? editRole : addRole
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
@ -134,7 +134,7 @@ const setFormData = async (row: any = null) => {
|
||||
loading.value = true
|
||||
selectAll.value = false
|
||||
Object.assign(formData, initialFormData)
|
||||
popTitle = t('addRole')
|
||||
popTitle = t('addRole')
|
||||
if (row) {
|
||||
popTitle = t('updateRole')
|
||||
const data = await (await getRoleInfo(row.role_id)).data
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px"
|
||||
:destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-dialog v-model="showDialog" :title="popTitle" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules" class="page-form"
|
||||
v-loading="loading">
|
||||
<el-form-item :label="t('accountNumber')" prop="username">
|
||||
<el-input v-model="formData.username" :placeholder="t('accountNumberPlaceholder')" clearable
|
||||
:disabled="formData.uid" class="input-width" maxlength="10" show-word-limit />
|
||||
@ -35,8 +35,8 @@
|
||||
|
||||
<el-form-item :label="t('status')">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="1">{{ t('statusNormal') }}</el-radio>
|
||||
<el-radio :label="0">{{ t('statusDeactivate') }}</el-radio>
|
||||
<el-radio :label="1">{{ t('statusUnlock') }}</el-radio>
|
||||
<el-radio :label="0">{{ t('lock') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@ -56,12 +56,12 @@
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
import { addUser, updateUser, getUserInfo } from '@/api/site'
|
||||
import { addUser, editUser, getUserInfo } from '@/api/site'
|
||||
import { allRole } from '@/api/sys'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const loading = ref(false)
|
||||
let popTitle:string = '';
|
||||
let popTitle: string = '';
|
||||
|
||||
/**
|
||||
* 表单数据
|
||||
@ -75,7 +75,7 @@ const initialFormData = {
|
||||
confirm_password: '',
|
||||
status: 1,
|
||||
role_ids: [],
|
||||
userrole:{}
|
||||
userrole: {}
|
||||
}
|
||||
const formData: Record<string, any> = reactive({ ...initialFormData })
|
||||
|
||||
@ -115,6 +115,9 @@ const emit = defineEmits(['complete'])
|
||||
const roles = ref<Record<string, any>>([])
|
||||
allRole().then(res => {
|
||||
roles.value = res.data
|
||||
roles.value.forEach(element => {
|
||||
element.role_id = element.role_id.toString()
|
||||
});
|
||||
})
|
||||
|
||||
/**
|
||||
@ -123,7 +126,7 @@ allRole().then(res => {
|
||||
*/
|
||||
const confirm = async (formEl: FormInstance | undefined) => {
|
||||
if (loading.value || !formEl) return
|
||||
const save = formData.uid ? updateUser : addUser
|
||||
const save = formData.uid ? editUser : addUser
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
@ -147,7 +150,7 @@ const setFormData = async (row: any = null) => {
|
||||
loading.value = true
|
||||
Object.assign(formData, initialFormData)
|
||||
popTitle = t('addUser')
|
||||
|
||||
|
||||
if (row) {
|
||||
popTitle = t('updateUser')
|
||||
const data = await (await getUserInfo(row.uid)).data
|
||||
|
||||
@ -31,9 +31,9 @@
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('status')" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusNormal') }}</el-tag>
|
||||
<el-tag class="ml-2" type="success" v-if="row.status == 1">{{ t('statusUnlock') }}</el-tag>
|
||||
<el-tag class="ml-2" type="error" v-if="row.status == 0">{{
|
||||
t('statusDeactivate')
|
||||
t('statusLock')
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
@ -36,21 +36,21 @@
|
||||
|
||||
<el-form-item :label="t('publicKey')">
|
||||
<div class="input-width">
|
||||
<upload-file v-model="formData.public_key_crt" api="upload/cert/aliapp" />
|
||||
<upload-file v-model="formData.public_key_crt" api="sys/document/aliyun" />
|
||||
</div>
|
||||
<div class="form-tip">{{ t('publicKeyTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('alipayPublicKey')">
|
||||
<div class="input-width">
|
||||
<upload-file v-model="formData.alipay_public_key_crt" api="upload/cert/aliapp" />
|
||||
<upload-file v-model="formData.alipay_public_key_crt" api="sys/document/aliyun" />
|
||||
</div>
|
||||
<div class="form-tip">{{ t('alipayPublicKeyTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('alipayWithCrt')">
|
||||
<div class="input-width">
|
||||
<upload-file v-model="formData.alipay_with_crt" api="upload/cert/aliapp" />
|
||||
<upload-file v-model="formData.alipay_with_crt" api="sys/document/aliyun" />
|
||||
</div>
|
||||
<div class="form-tip">{{ t('alipayWithCrtTips') }}</div>
|
||||
</el-form-item>
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<span class="ml-2 cursor-pointer visit-btn" @click="visitFn">{{t('clickVisit')}}</span>
|
||||
</el-form-item>
|
||||
|
||||
</el-card>
|
||||
@ -35,7 +36,7 @@
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { setH5Config, getH5Config } from '@/api/h5'
|
||||
import { getSceneDomain } from '@/api/sys'
|
||||
import { getUrl } from '@/api/sys'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage, FormInstance } from 'element-plus'
|
||||
|
||||
@ -60,8 +61,8 @@ getH5Config().then(res => {
|
||||
/**
|
||||
* 获取h5域名
|
||||
*/
|
||||
getSceneDomain().then(res => {
|
||||
formData.request_url = res.data.wap_domain
|
||||
getUrl().then(res => {
|
||||
formData.request_url = res.data.wap_url
|
||||
})
|
||||
|
||||
|
||||
@ -89,6 +90,11 @@ watch(copied, () => {
|
||||
}
|
||||
})
|
||||
|
||||
// 点击访问
|
||||
const visitFn = ()=>{
|
||||
window.open(formData.request_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存
|
||||
*/
|
||||
@ -111,4 +117,8 @@ const save = async (formEl: FormInstance | undefined) => {
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.visit-btn{
|
||||
color:var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-form label-width="120px" ref="formRef" class="page-form">
|
||||
<div class="main-container" v-loading="loading">
|
||||
<el-form :model="formData" label-width="120px" ref="formRef" class="page-form">
|
||||
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<h3 class="panel-title">{{ t('pcInfo') }}</h3>
|
||||
|
||||
<el-form-item :label="t('preview')" prop="weapp_name">
|
||||
<img class="w-[1010px]" src="@/assets/images/channel/preview.png" alt="">
|
||||
<img class="w-[500px]" src="@/assets/images/channel/preview.png" alt="">
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="t('PCDomainName')">
|
||||
<el-input :model-value="formData.request_url" class="input-width" :readonly="true">
|
||||
<template #append>
|
||||
<div class="cursor-pointer" @click="copyEvent(formData.request_url)">{{ t('copy') }}</div>
|
||||
</template>
|
||||
</el-input>
|
||||
<span class="ml-2 cursor-pointer visit-btn" @click="visitFn">{{t('clickVisit')}}</span>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
|
||||
@ -15,9 +24,65 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getUrl } from '@/api/sys'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const loading = ref(true)
|
||||
|
||||
const formData = reactive<Record<string, string | boolean>>({
|
||||
is_open: false,
|
||||
request_url: ''
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const router = useRouter()
|
||||
|
||||
|
||||
/**
|
||||
* 获取pc域名
|
||||
*/
|
||||
getUrl().then(res => {
|
||||
formData.request_url = res.data.web_url;
|
||||
loading.value = false;
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
const { copy, isSupported, copied } = useClipboard()
|
||||
const copyEvent = (text: string) => {
|
||||
if (!isSupported.value) {
|
||||
ElMessage({
|
||||
message: t('notSupportCopy'),
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
copy(text)
|
||||
}
|
||||
|
||||
watch(copied, () => {
|
||||
if (copied.value) {
|
||||
ElMessage({
|
||||
message: t('copySuccess'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 点击访问
|
||||
const visitFn = ()=>{
|
||||
window.open(formData.request_url);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.visit-btn{
|
||||
color:var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-alert class="warm-prompt" type="info">
|
||||
<template #default>
|
||||
<p class="text-base">{{t('operationTip')}} 1、{{ t('operationTipOne') }}</p>
|
||||
<p class="text-base">{{ t('operationTip') }} 1、{{ t('operationTipOne') }}</p>
|
||||
<p class="text-base">2、{{ t('operationTipTwo') }}</p>
|
||||
</template>
|
||||
</el-alert>
|
||||
@ -51,7 +51,7 @@
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getTemplateList, getBatchAcquisition } from '@/api/weapp'
|
||||
import { updateMessageStatus } from '@/api/message'
|
||||
import { editMessageStatus } from '@/api/notice'
|
||||
import { ElLoading } from 'element-plus'
|
||||
|
||||
const cronTableData = reactive({
|
||||
@ -105,7 +105,7 @@ const infoSwitch = (res) => {
|
||||
data.value.key = res.key
|
||||
data.value.type = 'weapp'
|
||||
cronTableData.loading = true
|
||||
updateMessageStatus(data.value).then(res => {
|
||||
editMessageStatus(data.value).then(res => {
|
||||
loadCronList()
|
||||
}).catch(() => {
|
||||
cronTableData.loading = false
|
||||
@ -115,13 +115,15 @@ const infoSwitch = (res) => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .warm-prompt{
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
::v-deep .warm-prompt .el-icon{
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
::v-deep .warm-prompt p{
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
::v-deep .warm-prompt {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
|
||||
::v-deep .warm-prompt .el-icon {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep .warm-prompt p {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -129,7 +129,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getWechatConfig, getWechatStatic, updateWechatConfig } from '@/api/wechat'
|
||||
import { getWechatConfig, getWechatStatic, editWechatConfig } from '@/api/wechat'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
@ -223,7 +223,7 @@ const save = async (formEl: FormInstance | undefined) => {
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
loading.value = true
|
||||
updateWechatConfig(formData).then(() => {
|
||||
editWechatConfig(formData).then(() => {
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
import { ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
import { getWechatMenu, updateWechatMenu } from '@/api/wechat'
|
||||
import { getWechatMenu, editWechatMenu } from '@/api/wechat'
|
||||
import menuForm from './components/menu-form.vue'
|
||||
|
||||
const loading = ref(true)
|
||||
@ -199,7 +199,7 @@ const save = async () => {
|
||||
}
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
updateWechatMenu({ button: button.value }).then(() => {
|
||||
editWechatMenu({ button: button.value }).then(() => {
|
||||
loading.value = false
|
||||
}).catch(() => {
|
||||
loading.value = false
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<el-alert class="warm-prompt" type="info">
|
||||
<template #default>
|
||||
<p class="text-base">{{t('operationTip')}} 1、{{ t('operationTipOne') }}</p>
|
||||
<p class="text-base">{{ t('operationTip') }} 1、{{ t('operationTipOne') }}</p>
|
||||
<p class="text-base">2、{{ t('operationTipTwo') }}</p>
|
||||
<p class="text-base">3、{{ t('operationTipThree') }}</p>
|
||||
<p class="text-base">4、{{ t('operationTipFour') }}</p>
|
||||
@ -58,7 +58,7 @@
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getTemplateList, getBatchAcquisition } from '@/api/wechat'
|
||||
import { updateMessageStatus } from '@/api/message'
|
||||
import { editMessageStatus } from '@/api/notice'
|
||||
import { AnyObject } from '@/types/global'
|
||||
import { ElLoading } from 'element-plus'
|
||||
|
||||
@ -114,7 +114,7 @@ const infoSwitch = (res: AnyObject) => {
|
||||
data.value.key = res.key
|
||||
data.value.type = 'wechat'
|
||||
cronTableData.loading = true
|
||||
updateMessageStatus(data.value).then(res => {
|
||||
editMessageStatus(data.value).then(res => {
|
||||
loadCronList()
|
||||
}).catch(() => {
|
||||
cronTableData.loading = false
|
||||
@ -123,13 +123,15 @@ const infoSwitch = (res: AnyObject) => {
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
::v-deep .warm-prompt{
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
::v-deep .warm-prompt .el-icon{
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
::v-deep .warm-prompt p{
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
::v-deep .warm-prompt {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
}
|
||||
|
||||
::v-deep .warm-prompt .el-icon {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
::v-deep .warm-prompt p {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,365 +1,374 @@
|
||||
<template>
|
||||
<div class="main-container flex-1">
|
||||
<el-header class="flex items-center h-[60px] bg-primary px-[20px]">
|
||||
<div class="text-white cursor-pointer flex items-center" @click="goBack">
|
||||
<el-icon size="14">
|
||||
<ArrowLeft />
|
||||
</el-icon>
|
||||
<span class="pl-[5px]">{{ t('back') }}</span>
|
||||
</div>
|
||||
<div class="text-white ml-[10px] flex items-center">
|
||||
<span class="mr-[5px]"> | {{ t('decorating') }}:{{ diyStore.typeName }}</span>
|
||||
<!-- <el-icon class="font-bold"><EditPen /></el-icon>-->
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
<el-button @click="save()">{{ t('save') }}</el-button>
|
||||
</el-header>
|
||||
|
||||
<div class="main-container flex-1">
|
||||
<el-header class="flex items-center h-[60px] bg-primary px-[20px]">
|
||||
<div class="text-white cursor-pointer flex items-center" @click="goBack">
|
||||
<el-icon size="14"><ArrowLeft /></el-icon>
|
||||
<span class="pl-[5px]">{{ t('back') }}</span>
|
||||
</div>
|
||||
<div class="text-white ml-[10px] flex items-center">
|
||||
<span class="mr-[5px]"> | {{ t('decorating') }}:{{ diyStore.typeName }}</span>
|
||||
<!-- <el-icon class="font-bold"><EditPen /></el-icon>-->
|
||||
</div>
|
||||
<div class="flex-1"></div>
|
||||
<el-button @click="save()">{{ t('save') }}</el-button>
|
||||
</el-header>
|
||||
<div class="full-container flex flex-row flex-1 bg-page">
|
||||
|
||||
<div class="full-container flex flex-row flex-1 bg-page">
|
||||
<div class="component-list w-[290px]">
|
||||
|
||||
<div class="component-list w-[290px]">
|
||||
<!-- 组件列表区域 -->
|
||||
<el-scrollbar class="px-[10px]">
|
||||
<el-collapse v-model="activeNames" @change="handleChange">
|
||||
<el-collapse-item v-for="(item, key) in component" :key="key" :title="item.title" :name="key">
|
||||
<ul class="flex flex-row flex-wrap">
|
||||
<li v-for="(compItem, compKey) in item.list" :key="compKey"
|
||||
class="w-2/6 text-center cursor-pointer h-[75px]" :title="compItem.title"
|
||||
@click="diyStore.addComponent(compKey, compItem)">
|
||||
<icon :name="compItem.icon" size="23px" />
|
||||
<span class="block text-base truncate">{{ compItem.title }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-scrollbar>
|
||||
|
||||
<!-- 组件列表区域 -->
|
||||
<el-scrollbar class="px-[10px]">
|
||||
<el-collapse v-model="activeNames" @change="handleChange">
|
||||
<el-collapse-item v-for="(item,index) in component" :key="index" :title="item.type_name" :name="item.type">
|
||||
<ul class="flex flex-row flex-wrap">
|
||||
<li v-for="(compItem,compIndex) in item.list" :key="compIndex" class="w-2/6 text-center cursor-pointer h-[75px]" :title="compItem.title" @click="diyStore.addComponent(compItem)">
|
||||
<icon :name="compItem.icon" size="23px"/>
|
||||
<span class="block text-base truncate">{{compItem.title}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="preview-wrap flex-1 relative mt-[20px]">
|
||||
|
||||
<div class="preview-wrap flex-1 relative mt-[20px]">
|
||||
<el-scrollbar>
|
||||
<el-button class="page-btn absolute right-[20px]" @click="diyStore.changeCurrentIndex(-99)">{{
|
||||
t('pageSet') }}</el-button>
|
||||
<div class="diy-view-wrap w-[375px] shadow-lg mx-auto">
|
||||
<div class="preview-head bg-no-repeat bg-center bg-cover" @click="diyStore.changeCurrentIndex(-99)">
|
||||
<span class="text-base block text-center truncate cursor-pointer h-[64px] leading-[84px]">{{
|
||||
diyStore.global.title }}</span>
|
||||
</div>
|
||||
<div class="preview-block relative">
|
||||
|
||||
<el-scrollbar>
|
||||
<el-button class="page-btn absolute right-[20px]" @click="diyStore.changeCurrentIndex(-99)">{{ t('pageSet')}}</el-button>
|
||||
<div class="diy-view-wrap w-[375px] shadow-lg mx-auto">
|
||||
<div class="preview-head bg-no-repeat bg-center bg-cover" @click="diyStore.changeCurrentIndex(-99)">
|
||||
<span class="text-base block text-center truncate cursor-pointer h-[64px] leading-[84px]">{{ diyStore.global.title }}</span>
|
||||
</div>
|
||||
<div class="preview-block relative">
|
||||
<ul
|
||||
class="quick-action absolute text-center -right-[70px] top-[20px] w-[42px] rounded shadow-md">
|
||||
<el-tooltip effect="light" :content="t('moveUpComponent')" placement="right">
|
||||
<icon name="iconfont-iconjiantoushang" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('moveDownComponent')" placement="right">
|
||||
<icon name="iconfont-iconjiantouxia" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('copyComponent')" placement="right">
|
||||
<icon name="iconfont-iconcopy-line" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('delComponent')" placement="right">
|
||||
<icon name="iconfont-icondelete-line" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('resetComponent')" placement="right">
|
||||
<icon name="iconfont-iconloader-line" size="20px"
|
||||
class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
|
||||
</el-tooltip>
|
||||
</ul>
|
||||
|
||||
<ul class="quick-action absolute text-center -right-[70px] top-[20px] w-[42px] rounded shadow-md">
|
||||
<el-tooltip effect="light" :content="t('moveUpComponent')" placement="right">
|
||||
<icon name="iconfont-iconjiantoushang" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveUpComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('moveDownComponent')" placement="right">
|
||||
<icon name="iconfont-iconjiantouxia" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.moveDownComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('copyComponent')" placement="right">
|
||||
<icon name="iconfont-iconcopy-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.copyComponent" />
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('delComponent')" placement="right">
|
||||
<icon name="iconfont-icondelete-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.delComponent"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="light" :content="t('resetComponent')" placement="right">
|
||||
<icon name="iconfont-iconloader-line" size="20px" class="block cursor-pointer leading-[40px]" @click="diyStore.resetComponent" />
|
||||
</el-tooltip>
|
||||
</ul>
|
||||
<!-- 组件预览渲染区域 -->
|
||||
<iframe id="previewIframe" v-show="wapDomain" :src="wapDomain" frameborder="0"
|
||||
class="preview-iframe w-[375px]"></iframe>
|
||||
|
||||
<!-- 组件预览渲染区域 -->
|
||||
<iframe id="previewIframe" v-show="wapDomain" :src="wapDomain" frameborder="0" class="preview-iframe w-[375px]"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="edit-attribute-wrap w-[400px]">
|
||||
|
||||
<div class="edit-attribute-wrap w-[400px]">
|
||||
<!-- 编辑组件属性区域 -->
|
||||
<el-scrollbar>
|
||||
<el-card class="box-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<span class="title flex-1">{{ diyStore.currentIndex == -99 ? t('pageSet') :
|
||||
diyStore.editComponent.componentTitle }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<component :is="modules[diyStore.currentComponent]"
|
||||
:value="diyStore.value[diyStore.currentIndex]" />
|
||||
</el-card>
|
||||
</el-scrollbar>
|
||||
|
||||
<!-- 编辑组件属性区域 -->
|
||||
<el-scrollbar>
|
||||
<el-card class="box-card" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<span class="title flex-1">{{ diyStore.currentIndex == -99 ? t('pageSet') : diyStore.editComponent.componentTitle }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<component :is="modules[diyStore.currentComponent]" :value="diyStore.value[diyStore.currentIndex]" />
|
||||
</el-card>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref, reactive, toRaw, onMounted, watch} from 'vue'
|
||||
import {t} from '@/lang'
|
||||
import { addDiyPage, updateDiyPage,initPage} from '@/api/diy';
|
||||
import {useRoute,useRouter} from 'vue-router'
|
||||
import { cloneDeep, range, isEmpty } from 'lodash-es'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
import { getWapDomain } from '@/utils/common'
|
||||
import { ref, reactive, toRaw, onMounted, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { addDiyPage, editDiyPage, initPage } from '@/api/diy';
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { cloneDeep, range, isEmpty } from 'lodash-es'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import useDiyStore from '@/stores/modules/diy'
|
||||
|
||||
const diyStore = useDiyStore()
|
||||
const route = useRoute();
|
||||
const router = useRouter()
|
||||
const diyStore = useDiyStore()
|
||||
const route = useRoute();
|
||||
const router = useRouter()
|
||||
|
||||
const wapDomain = ref('')
|
||||
const wapDomain = ref('')
|
||||
|
||||
const component = ref([])
|
||||
const componentType:string[] = reactive([])
|
||||
const component = ref([])
|
||||
const componentType: string[] = reactive([])
|
||||
|
||||
const activeNames = ref(componentType)
|
||||
const handleChange = (val: string[]) => {}
|
||||
const activeNames = ref(componentType)
|
||||
const handleChange = (val: string[]) => { }
|
||||
|
||||
route.query.id = route.query.id || 0;
|
||||
route.query.name = route.query.name || '';
|
||||
route.query.type = route.query.type || ''; // 页面类型,新页面传入
|
||||
route.query.title = route.query.title || '';
|
||||
route.query.id = route.query.id || 0;
|
||||
route.query.name = route.query.name || '';
|
||||
route.query.type = route.query.type || ''; // 页面类型,新页面传入
|
||||
route.query.title = route.query.title || '';
|
||||
|
||||
// 初始化原数据
|
||||
const originData = reactive({
|
||||
id: diyStore.id,
|
||||
name: diyStore.name,
|
||||
title: diyStore.global.title,
|
||||
value: JSON.stringify({
|
||||
global: toRaw(diyStore.global),
|
||||
value: toRaw(diyStore.value)
|
||||
})
|
||||
})
|
||||
|
||||
// 返回上一页
|
||||
const isChange = ref(true) // 数据是否发生变化,true:没变化,false:变化了
|
||||
const goBack = () => {
|
||||
if (isChange.value) {
|
||||
router.push('/diy/list');
|
||||
} else {
|
||||
// 数据发生变化,弹框提示:确定离开此页面
|
||||
ElMessageBox.confirm(
|
||||
t('leavePageTitleTips'),
|
||||
t('leavePageContentTips'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning',
|
||||
autofocus: false
|
||||
}
|
||||
).then(() => {
|
||||
router.push('/diy/list');
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 动态加载后台自定义组件编辑
|
||||
const modulesFiles = import.meta.glob('./components/*.vue', { eager: true })
|
||||
const modules = {}
|
||||
for (const [key, value] of Object.entries(modulesFiles)) {
|
||||
const moduleName = key.replace(/^\.\/(.*)\.\w+$/, '$1')
|
||||
const name = moduleName.split('/')[1]
|
||||
modules[name] = value.default
|
||||
}
|
||||
|
||||
// 全局监听自定义数据变化
|
||||
watch(
|
||||
() => diyStore,
|
||||
(newValue, oldValue) => {
|
||||
let data = {
|
||||
id: newValue.id,
|
||||
name: newValue.name,
|
||||
title: newValue.global.title,
|
||||
value: JSON.stringify({
|
||||
global: toRaw(newValue.global),
|
||||
value: toRaw(newValue.value)
|
||||
})
|
||||
};
|
||||
|
||||
diyStore.postMessage();
|
||||
isChange.value = JSON.stringify(data) == JSON.stringify(originData);
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 根据当前页面路由查询页面初始化数据
|
||||
initPage({
|
||||
id: route.query.id,
|
||||
name: route.query.name,
|
||||
type: route.query.type,
|
||||
title: route.query.title
|
||||
}).then(res => {
|
||||
let data = res.data;
|
||||
diyStore.id = data.id || 0;
|
||||
diyStore.name = data.name;
|
||||
diyStore.type = data.type;
|
||||
diyStore.typeName = data.type_name;
|
||||
if (data.value) {
|
||||
let sources = JSON.parse(data.value);
|
||||
diyStore.global = sources.global;
|
||||
if (sources.value.length) {
|
||||
diyStore.value = sources.value;
|
||||
// diyStore.changeCurrentIndex(0,diyStore.value[0]);
|
||||
}
|
||||
} else {
|
||||
diyStore.global.title = data.title;
|
||||
}
|
||||
|
||||
// 初始化原数据
|
||||
const originData = reactive({
|
||||
originData.id = diyStore.id;
|
||||
originData.name = diyStore.name;
|
||||
originData.title = diyStore.global.title;
|
||||
originData.value = JSON.stringify({
|
||||
global: toRaw(diyStore.global),
|
||||
value: toRaw(diyStore.value)
|
||||
});
|
||||
|
||||
component.value = data.component
|
||||
for (let type in component.value) {
|
||||
componentType.push(type)
|
||||
for (let key in component.value[type].list) {
|
||||
let com = cloneDeep(component.value[type].list[key]);
|
||||
com.id = diyStore.generateRandom();
|
||||
com.componentName = key;
|
||||
com.componentTitle = com.title;
|
||||
com.maxCount = com.max_count;
|
||||
Object.assign(com, com.value);
|
||||
delete com.name;
|
||||
delete com.title;
|
||||
delete com.value;
|
||||
delete com.type;
|
||||
delete com.icon;
|
||||
delete com.max_count;
|
||||
diyStore.components.push(com)
|
||||
}
|
||||
}
|
||||
|
||||
wapDomain.value = `${data.domain_url.wap_url}/${data.page}?mode=decorate`; // 模式:decorate 装修 访问预览页面
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 预览前端 uniapp iframe
|
||||
window.previewIframe = document.getElementById('previewIframe')
|
||||
})
|
||||
|
||||
// 监听组件数据 uni-app端
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
let data = JSON.parse(event.data);
|
||||
if (!data.type) return;
|
||||
|
||||
switch (data.type) {
|
||||
case 'init':
|
||||
// 初始化,与uniapp建立连接传输数据
|
||||
diyStore.load = true;
|
||||
diyStore.postMessage();
|
||||
break;
|
||||
case 'change':
|
||||
// 切换
|
||||
diyStore.changeCurrentIndex(data.index, data.component);
|
||||
break;
|
||||
case 'data':
|
||||
// 传数据
|
||||
diyStore.changeCurrentIndex(data.index, data.component);
|
||||
diyStore.global = data.global;
|
||||
diyStore.value = data.value;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('后台接受数据错误', e)
|
||||
}
|
||||
}, false);
|
||||
|
||||
const loading = ref(false)
|
||||
const save = () => {
|
||||
if (!diyStore.verify()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
let data = {
|
||||
id: diyStore.id,
|
||||
name: diyStore.name,
|
||||
title: diyStore.global.title,
|
||||
type: diyStore.type,
|
||||
value: JSON.stringify({
|
||||
global: toRaw(diyStore.global),
|
||||
value: toRaw(diyStore.value)
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// 返回上一页
|
||||
const isChange = ref(true) // 数据是否发生变化,true:没变化,false:变化了
|
||||
const goBack = () => {
|
||||
if(isChange.value){
|
||||
router.push('/diy/list');
|
||||
}else{
|
||||
// 数据发生变化,弹框提示:确定离开此页面
|
||||
ElMessageBox.confirm(
|
||||
t('leavePageTitleTips'),
|
||||
t('leavePageContentTips'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning',
|
||||
autofocus: false
|
||||
}
|
||||
).then(() => {
|
||||
router.push('/diy/list');
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 动态加载后台自定义组件编辑
|
||||
const modulesFiles = import.meta.glob('./components/*.vue', {eager: true})
|
||||
const modules = {}
|
||||
for (const [key, value] of Object.entries(modulesFiles)) {
|
||||
const moduleName = key.replace(/^\.\/(.*)\.\w+$/, '$1')
|
||||
const name = moduleName.split('/')[1]
|
||||
modules[name] = value.default
|
||||
}
|
||||
|
||||
// 全局监听自定义数据变化
|
||||
watch(
|
||||
() => diyStore,
|
||||
(newValue, oldValue) => {
|
||||
let data = {
|
||||
id: newValue.id,
|
||||
name: newValue.name,
|
||||
title: newValue.global.title,
|
||||
value: JSON.stringify({
|
||||
global: toRaw(newValue.global),
|
||||
value: toRaw(newValue.value)
|
||||
})
|
||||
};
|
||||
|
||||
diyStore.postMessage();
|
||||
isChange.value = JSON.stringify(data) == JSON.stringify(originData);
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
// 根据当前页面路由查询页面初始化数据
|
||||
initPage({
|
||||
id:route.query.id,
|
||||
name:route.query.name,
|
||||
type:route.query.type,
|
||||
title:route.query.title
|
||||
}).then(res=> {
|
||||
const save = diyStore.id ? editDiyPage : addDiyPage
|
||||
save(data).then((res: any) => {
|
||||
loading.value = false
|
||||
if (res.code == 200) {
|
||||
let data = res.data;
|
||||
diyStore.id = data.id || 0;
|
||||
diyStore.name = data.name;
|
||||
diyStore.type = data.type;
|
||||
diyStore.typeName = data.type_name;
|
||||
if (data.value) {
|
||||
let sources = JSON.parse(data.value);
|
||||
diyStore.global = sources.global;
|
||||
if(sources.value.length) {
|
||||
diyStore.value = sources.value;
|
||||
// diyStore.changeCurrentIndex(0,diyStore.value[0]);
|
||||
}
|
||||
if (diyStore.id) {
|
||||
loading.value = false // 不刷新
|
||||
} else {
|
||||
diyStore.global.title = data.title;
|
||||
router.push('/diy/list');
|
||||
}
|
||||
|
||||
// 初始化原数据
|
||||
originData.id = diyStore.id;
|
||||
originData.name = diyStore.name;
|
||||
originData.title = diyStore.global.title;
|
||||
originData.value = JSON.stringify({
|
||||
global: toRaw(diyStore.global),
|
||||
value: toRaw(diyStore.value)
|
||||
});
|
||||
|
||||
component.value = data.component
|
||||
component.value.forEach((item: any) => {
|
||||
componentType.push(item.type)
|
||||
item.list.forEach((comp: any) => {
|
||||
let com = cloneDeep(comp);
|
||||
com.id = diyStore.generateRandom();
|
||||
com.componentName = com.name;
|
||||
com.componentTitle = com.title;
|
||||
com.maxCount = com.max_count;
|
||||
Object.assign(com, com.value);
|
||||
delete com.name;
|
||||
delete com.title;
|
||||
delete com.value;
|
||||
delete com.type;
|
||||
delete com.icon;
|
||||
delete com.max_count;
|
||||
diyStore.components.push(com)
|
||||
})
|
||||
})
|
||||
|
||||
wapDomain.value = `${getWapDomain()}/${data.page}?mode=decorate`; // 模式:decorate 装修 访问预览页面
|
||||
}
|
||||
}).catch(err => {
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 预览前端 uniapp iframe
|
||||
window.previewIframe = document.getElementById('previewIframe')
|
||||
})
|
||||
|
||||
// 监听组件数据 uni-app端
|
||||
window.addEventListener('message', (event) => {
|
||||
try {
|
||||
let data = JSON.parse(event.data);
|
||||
if (!data.type) return;
|
||||
|
||||
switch (data.type) {
|
||||
case 'init':
|
||||
// 初始化,与uniapp建立连接传输数据
|
||||
diyStore.load = true;
|
||||
diyStore.postMessage();
|
||||
break;
|
||||
case 'change':
|
||||
// 切换
|
||||
diyStore.changeCurrentIndex(data.index, data.component);
|
||||
break;
|
||||
case 'data':
|
||||
// 传数据
|
||||
diyStore.changeCurrentIndex(data.index, data.component);
|
||||
diyStore.global = data.global;
|
||||
diyStore.value = data.value;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('后台接受数据错误',e)
|
||||
}
|
||||
}, false);
|
||||
|
||||
const loading = ref(false)
|
||||
const save = ()=> {
|
||||
if (!diyStore.verify()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (loading.value) return
|
||||
loading.value = true
|
||||
|
||||
let data = {
|
||||
id: diyStore.id,
|
||||
name: diyStore.name,
|
||||
title: diyStore.global.title,
|
||||
type: diyStore.type,
|
||||
value: JSON.stringify({
|
||||
global: toRaw(diyStore.global),
|
||||
value: toRaw(diyStore.value)
|
||||
})
|
||||
};
|
||||
|
||||
const save = diyStore.id ? updateDiyPage : addDiyPage
|
||||
save(data).then((res: any) => {
|
||||
loading.value = false
|
||||
if (res.code == 200) {
|
||||
if (diyStore.id) {
|
||||
loading.value = false // 不刷新
|
||||
} else {
|
||||
router.push('/diy/list');
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
loading.value = false
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.el-collapse-item__wrap {
|
||||
border-bottom: none;
|
||||
}
|
||||
.el-collapse-item__wrap {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.el-collapse-item__content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.el-collapse-item__content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.el-collapse-item__header {
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
.el-collapse-item__header {
|
||||
font-size: var(--el-font-size-base);
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.full-container {
|
||||
height: calc(100vh - 60px);
|
||||
}
|
||||
.full-container {
|
||||
height: calc(100vh - 60px);
|
||||
}
|
||||
|
||||
.preview-iframe{
|
||||
height: calc(100vh - 160px);
|
||||
}
|
||||
.preview-iframe {
|
||||
height: calc(100vh - 160px);
|
||||
}
|
||||
|
||||
.component-list {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.component-list {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.component-list ul li {
|
||||
&:not(.disabled):hover {
|
||||
color: var(--el-color-primary);
|
||||
background: var(--el-color-primary-light-9);
|
||||
}
|
||||
}
|
||||
.component-list ul li {
|
||||
&:not(.disabled):hover {
|
||||
color: var(--el-color-primary);
|
||||
background: var(--el-color-primary-light-9);
|
||||
}
|
||||
}
|
||||
|
||||
.diy-view-wrap {
|
||||
background: var(--el-bg-color-page);
|
||||
}
|
||||
.diy-view-wrap {
|
||||
background: var(--el-bg-color-page);
|
||||
}
|
||||
|
||||
.diy-view-wrap .preview-head {
|
||||
background-image: url(assets/images/diy_preview_head.png);
|
||||
background-color: var(--el-bg-color);
|
||||
}
|
||||
.diy-view-wrap .preview-head {
|
||||
background-image: url(assets/images/diy_preview_head.png);
|
||||
background-color: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.quick-action {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.quick-action {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.edit-attribute-wrap {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
.edit-attribute-wrap {
|
||||
background: var(--el-bg-color);
|
||||
}
|
||||
|
||||
.edit-attribute-wrap .box-card {
|
||||
border: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
.edit-attribute-wrap .box-card {
|
||||
border: none;
|
||||
}</style>
|
||||
@ -49,18 +49,21 @@
|
||||
import {t} from '@/lang'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import {getWeappConfig} from '@/api/weapp'
|
||||
import {getUrl} from '@/api/sys'
|
||||
import {useClipboard} from '@vueuse/core'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {img} from '@/utils/common'
|
||||
import {getWapDomain} from '@/utils/common'
|
||||
import QRCode from "qrcode";
|
||||
|
||||
const wapDomain = ref(getWapDomain() + '/pages/index/index')
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
|
||||
QRCode.toDataURL(wapDomain.value, {errorCorrectionLevel: 'L', margin: 0, width: 100}).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
getUrl().then((res:any)=>{
|
||||
wapDomain.value = res.data.wap_url + '/pages/index/index'
|
||||
QRCode.toDataURL(wapDomain.value, {errorCorrectionLevel: 'L', margin: 0, width: 100}).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
});
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@ -84,6 +87,7 @@
|
||||
path: '/decorate/edit',
|
||||
query: {name: 'DIY_INDEX'}
|
||||
});
|
||||
|
||||
const toDecorate = () => {
|
||||
router.push('/decorate/edit?name=DIY_INDEX')
|
||||
// window.open(url.href);
|
||||
|
||||
@ -1,465 +1,507 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex">
|
||||
<el-button type="primary" @click="dialogVisible=true">
|
||||
{{ t('addDiyPage') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
<div class="flex">
|
||||
<el-button type="primary" @click="dialogVisible = true">
|
||||
{{ t('addDiyPage') }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-card class="box-card !border-none my-[16px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="diyRouteTableData.searchParam" ref="searchFormDiyRouteRef" v-if="tabValue == 'route'">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyRouteTableData.searchParam.title" :placeholder="t('titlePlaceholder')"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadDiyRouteList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormDiyRouteRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true" :model="diyPageTableData.searchParam" ref="searchFormDiyPageRef" v-if="tabValue == 'diy'">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="diyPageTableData.searchParam.type" :placeholder="t('pageTypePlaceholder')">
|
||||
<el-option :label="t('all')" value="" />
|
||||
<el-option v-for="item in pageType" :label="item.type_name" :value="item.type" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadDiyPageList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormDiyPageRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-card class="box-card !border-none my-[16px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="diyPageTableData.searchParam" ref="searchFormDiyPageRef"
|
||||
v-if="tabValue == 'diy'">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyPageTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="diyPageTableData.searchParam.type" :placeholder="t('pageTypePlaceholder')">
|
||||
<el-option :label="t('all')" value="" />
|
||||
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadDiyPageList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormDiyPageRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true" :model="diyRouteTableData.searchParam" ref="searchFormDiyRouteRef"
|
||||
v-if="tabValue == 'route'">
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="diyRouteTableData.searchParam.title" :placeholder="t('titlePlaceholder')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadDiyRouteList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormDiyRouteRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div class="mt-[16px]">
|
||||
<div class="mt-[16px]">
|
||||
|
||||
<el-tabs v-model="tabValue" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane :label="t('diyPage')" name="diy">
|
||||
<el-tabs v-model="tabValue" class="demo-tabs" @tab-click="handleClick">
|
||||
<el-tab-pane :label="t('diyPage')" name="diy">
|
||||
|
||||
<el-table :data="diyPageTableData.data" size="large" v-loading="diyPageTableData.loading">
|
||||
<el-table :data="diyPageTableData.data" size="large" v-loading="diyPageTableData.loading">
|
||||
|
||||
<template #empty>
|
||||
<span>{{ !diyPageTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<template #empty>
|
||||
<span>{{ !diyPageTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column prop="title" :label="t('title')" min-width="120"/>
|
||||
<el-table-column prop="type_name" :label="t('typeName')" min-width="80"/>
|
||||
<el-table-column :label="t('status')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.type == 'DIY_PAGE'">-</span>
|
||||
<template v-else>
|
||||
<span v-if="row.is_default == 1" class="text-primary">{{ t('isUse') }}</span>
|
||||
<span v-else>{{ t('unused') }}</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="update_time" :label="t('updateTime')" min-width="120"/>
|
||||
<el-table-column prop="title" :label="t('title')" min-width="120" />
|
||||
<el-table-column prop="type_name" :label="t('typeName')" min-width="80" />
|
||||
<el-table-column :label="t('status')" min-width="80">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.type == 'DIY_PAGE'">-</span>
|
||||
<template v-else>
|
||||
<span v-if="row.is_default == 1" class="text-primary">{{ t('isUse') }}</span>
|
||||
<span v-else>{{ t('unused') }}</span>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="update_time" :label="t('updateTime')" min-width="120" />
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="promoteEvent(row)">{{ t('promote') }}</el-button>
|
||||
<el-button v-if="row.type != 'DIY_PAGE' && row.is_default == 0" type="primary" link @click="setUse(row)">{{ t('use') }}</el-button>
|
||||
<el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{ t('shareSet') }}</el-button>
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<el-button v-if="row.type == 'DIY_PAGE' || row.is_default == 0" type="danger" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('operation')" fixed="right" align="right" min-width="160">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="promoteEvent(row)">{{ t('promote') }}</el-button>
|
||||
<el-button v-if="row.type != 'DIY_PAGE' && row.is_default == 0" type="primary" link
|
||||
@click="setUse(row)">{{ t('use') }}</el-button>
|
||||
<el-button v-if="row.type == 'DIY_PAGE'" type="primary" link @click="openShare(row)">{{
|
||||
t('shareSet') }}</el-button>
|
||||
<el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
|
||||
<el-button v-if="row.type == 'DIY_PAGE' || row.is_default == 0" type="danger" link
|
||||
@click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="diyPageTableData.page" v-model:page-size="diyPageTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="diyPageTableData.total" @size-change="loadDiyPageList()" @current-change="loadDiyPageList"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!-- 基础页面路径 -->
|
||||
<el-tab-pane :label="t('basicRoute')" name="route">
|
||||
<el-table :data="diyRouteTableData.data" size="large" v-loading="diyRouteTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !diyRouteTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column prop="title" :label="t('title')" min-width="120"/>
|
||||
<el-table-column prop="page" :label="t('wapUrl')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="mr-[10px]">{{ getWapDomain() + row.page }}</span>
|
||||
<el-button type="primary" link @click="copyEvent(getWapDomain() + row.page)">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="page" :label="t('weappUrl')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="mr-[10px]">{{ row.page }}</span>
|
||||
<el-button type="primary" link @click="copyEvent(row.page)">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('share')" fixed="right" min-width="80">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.is_share == 1" type="primary" link @click="openShare(row)">{{ t('shareSet') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="diyRouteTableData.page" v-model:page-size="diyRouteTableData.limit" layout="total, sizes, prev, pager, next, jumper" :total="diyRouteTableData.total" @size-change="loadDiyPageList()" @current-change="loadDiyPageList"/>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="diyPageTableData.page"
|
||||
v-model:page-size="diyPageTableData.limit" layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="diyPageTableData.total" @size-change="loadDiyPageList()"
|
||||
@current-change="loadDiyPageList" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<!-- 基础页面路径 -->
|
||||
<el-tab-pane :label="t('basicRoute')" name="route">
|
||||
<el-table :data="diyRouteTableData.data" size="large" v-loading="diyRouteTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !diyRouteTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
<el-table-column prop="title" :label="t('title')" min-width="120" />
|
||||
<el-table-column prop="page" :label="t('wapUrl')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="mr-[10px]">{{ wapDomain + row.page }}</span>
|
||||
<el-button type="primary" link @click="copyEvent(wapDomain + row.page)">{{ t('copy')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="page" :label="t('weappUrl')" min-width="120">
|
||||
<template #default="{ row }">
|
||||
<span class="mr-[10px]">{{ row.page }}</span>
|
||||
<el-button type="primary" link @click="copyEvent(row.page)">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('share')" fixed="right" min-width="80">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.is_share == 1" type="primary" link @click="openShare(row)">{{
|
||||
t('shareSet') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
</el-tabs>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</el-card>
|
||||
|
||||
<!--添加页面-->
|
||||
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="20%">
|
||||
<!--添加页面-->
|
||||
<el-dialog v-model="dialogVisible" :title="t('addPageTips')" width="20%">
|
||||
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')">
|
||||
<el-option v-for="item in pageType" :label="item.type_name" :value="item.type" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12" show-word-limit/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :model="formData" label-width="90px" ref="formRef" :rules="formRules">
|
||||
<el-form-item :label="t('typeName')" prop="type">
|
||||
<el-select v-model="formData.type" :placeholder="t('pageTypePlaceholder')">
|
||||
<el-option v-for="(item, key) in pageType" :label="item.title" :value="key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('title')" prop="title">
|
||||
<el-input v-model="formData.title" :placeholder="t('titlePlaceholder')" clearable maxlength="12"
|
||||
show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">{{ t('cancel')}}</el-button>
|
||||
<el-button type="primary" @click="addEvent(formRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="addEvent(formRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 分享设置-->
|
||||
<el-dialog v-model="shareDialogVisible" :title="t('shareSet')" width="30%">
|
||||
<!-- 分享设置-->
|
||||
<el-dialog v-model="shareDialogVisible" :title="t('shareSet')" width="30%">
|
||||
|
||||
<el-tabs v-model="tabShareType">
|
||||
<el-tab-pane :label="t('wechat')" name="wechat"></el-tab-pane>
|
||||
<el-tab-pane :label="t('weapp')" name="weapp"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form :model="shareFormData[tabShareType]" label-width="90px" ref="shareFormRef" :rules="shareFormRules">
|
||||
<el-form-item :label="t('sharePage')">
|
||||
<span>{{ sharePage }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareTitle')" prop="title">
|
||||
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')" clearable maxlength="30" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'">
|
||||
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')" type="textarea" rows="4" clearable maxlength="100" show-word-limit/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareImageUrl')" prop="url">
|
||||
<upload-image v-model="shareFormData[tabShareType].url" :limit="1"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-tabs v-model="tabShareType">
|
||||
<el-tab-pane :label="t('wechat')" name="wechat"></el-tab-pane>
|
||||
<el-tab-pane :label="t('weapp')" name="weapp"></el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form :model="shareFormData[tabShareType]" label-width="90px" ref="shareFormRef" :rules="shareFormRules">
|
||||
<el-form-item :label="t('sharePage')">
|
||||
<span>{{ sharePage }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareTitle')" prop="title">
|
||||
<el-input v-model="shareFormData[tabShareType].title" :placeholder="t('shareTitlePlaceholder')"
|
||||
clearable maxlength="30" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareDesc')" prop="desc" v-if="tabShareType == 'wechat'">
|
||||
<el-input v-model="shareFormData[tabShareType].desc" :placeholder="t('shareDescPlaceholder')"
|
||||
type="textarea" rows="4" clearable maxlength="100" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('shareImageUrl')" prop="url">
|
||||
<upload-image v-model="shareFormData[tabShareType].url" :limit="1" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="shareDialogVisible = false">{{ t('cancel')}}</el-button>
|
||||
<el-button type="primary" @click="shareEvent(shareFormRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="shareDialogVisible = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="shareEvent(shareFormRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 推广-->
|
||||
<el-dialog v-model="promoteDialogVisible" :title="t('promote')" width="30%">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item :label="t('shareLink')">
|
||||
<el-input readonly :value="wapDomain">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(wapDomain)" class="bg-primary copy">{{ t('copy') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
<el-image :src="wapImage"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 推广-->
|
||||
<el-dialog v-model="promoteDialogVisible" :title="t('promote')" width="30%">
|
||||
<el-form label-width="90px">
|
||||
<el-form-item :label="t('shareLink')">
|
||||
<el-input readonly :value="promoteWapDomain">
|
||||
<template #append>
|
||||
<el-button @click="copyEvent(promoteWapDomain)" class="bg-primary copy">{{ t('copy')
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label=" ">
|
||||
<el-image :src="wapImage" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- <el-tabs v-model="tabPromote">-->
|
||||
<!-- <el-tab-pane :label="t('wechat')" name="wechat"></el-tab-pane>-->
|
||||
<!-- <el-tab-pane :label="t('weapp')" name="weapp"></el-tab-pane>-->
|
||||
<!-- </el-tabs>-->
|
||||
<!-- <el-tabs v-model="tabPromote">-->
|
||||
<!-- <el-tab-pane :label="t('wechat')" name="wechat"></el-tab-pane>-->
|
||||
<!-- <el-tab-pane :label="t('weapp')" name="weapp"></el-tab-pane>-->
|
||||
<!-- </el-tabs>-->
|
||||
|
||||
</el-dialog>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {reactive, ref,watch,computed} from 'vue'
|
||||
import {t} from '@/lang'
|
||||
import {getDiyPageList, deleteDiyPage, setUseDiyPage,getDiyPageType,getDiyRouteList,updateDiyPageShare,updateDiyRouteShare} from '@/api/diy'
|
||||
import {TabsPaneContext, ElMessage,ElMessageBox,FormInstance} from 'element-plus'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {useClipboard} from '@vueuse/core'
|
||||
import { getWapDomain } from '@/utils/common'
|
||||
import QRCode from "qrcode";
|
||||
import { reactive, ref, watch, computed } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getDiyPageList, deleteDiyPage, setUseDiyPage, getDiyPageType, getDiyRouteList, getDiyRouteInfo, editDiyPageShare, editDiyRouteShare } from '@/api/diy'
|
||||
import { TabsPaneContext, ElMessage, ElMessageBox, FormInstance } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import QRCode from "qrcode";
|
||||
import { getUrl } from '@/api/sys'
|
||||
|
||||
const pageType:any = reactive([])
|
||||
const pageType: any = reactive({})
|
||||
|
||||
const router = useRouter()
|
||||
const router = useRouter()
|
||||
|
||||
// 添加自定义页面
|
||||
const formData = reactive({
|
||||
type: '',
|
||||
title: ''
|
||||
})
|
||||
// 表单验证规则
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
type: [
|
||||
{ required: true, message: t('pageTypePlaceholder'), trigger: 'blur' },
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: t('titlePlaceholder'), trigger: 'blur' },
|
||||
]
|
||||
// 添加自定义页面
|
||||
const formData = reactive({
|
||||
type: '',
|
||||
title: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = computed(() => {
|
||||
return {
|
||||
type: [
|
||||
{ required: true, message: t('pageTypePlaceholder'), trigger: 'blur' },
|
||||
],
|
||||
title: [
|
||||
{ required: true, message: t('titlePlaceholder'), trigger: 'blur' },
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
const dialogVisible = ref(false)
|
||||
const addEvent = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
dialogVisible.value = false;
|
||||
router.push('/decorate/edit?type=' + formData.type + '&title=' + formData.title);
|
||||
}
|
||||
})
|
||||
const formRef = ref<FormInstance>()
|
||||
const dialogVisible = ref(false)
|
||||
const addEvent = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
}
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
dialogVisible.value = false;
|
||||
router.push('/decorate/edit?type=' + formData.type + '&title=' + formData.title);
|
||||
}
|
||||
})
|
||||
let diyRouteTableData = reactive({
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
"title": "",
|
||||
}
|
||||
})
|
||||
|
||||
const wapDomain = ref('')
|
||||
const getDomain = async () => {
|
||||
wapDomain.value = (await getUrl()).data.wap_url;
|
||||
};
|
||||
getDomain();
|
||||
|
||||
/**
|
||||
* 获取自定义路由列表
|
||||
*/
|
||||
const loadDiyRouteList = () => {
|
||||
diyRouteTableData.loading = true
|
||||
|
||||
getDiyRouteList({
|
||||
...diyRouteTableData.searchParam
|
||||
}).then(res => {
|
||||
diyRouteTableData.loading = false
|
||||
diyRouteTableData.data = res.data
|
||||
}).catch(() => {
|
||||
diyRouteTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadDiyRouteList()
|
||||
|
||||
// 获取自定义页面类型
|
||||
getDiyPageType({}).then(res => {
|
||||
for (let key in res.data) {
|
||||
pageType[key] = res.data[key]
|
||||
}
|
||||
})
|
||||
|
||||
let diyPageTableData: any = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
"title": "",
|
||||
"type": '',
|
||||
}
|
||||
})
|
||||
|
||||
const tabValue = ref('diy')
|
||||
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||
tabValue.value = tab.props.name;
|
||||
if (tabValue.value == 'diy') {
|
||||
loadDiyPageList()
|
||||
} else {
|
||||
loadDiyRouteList()
|
||||
}
|
||||
|
||||
let diyRouteTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam:{
|
||||
"title":"",
|
||||
}
|
||||
|
||||
const searchFormDiyRouteRef = ref<FormInstance>()
|
||||
const searchFormDiyPageRef = ref<FormInstance>()
|
||||
|
||||
// 获取自定义页面列表
|
||||
const loadDiyPageList = (page: number = 1) => {
|
||||
diyPageTableData.loading = true
|
||||
diyPageTableData.page = page
|
||||
|
||||
getDiyPageList({
|
||||
page: diyPageTableData.page,
|
||||
limit: diyPageTableData.limit,
|
||||
...diyPageTableData.searchParam
|
||||
}).then(res => {
|
||||
diyPageTableData.loading = false
|
||||
diyPageTableData.data = res.data.data
|
||||
diyPageTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
diyPageTableData.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
loadDiyPageList()
|
||||
|
||||
// 编辑自定义页面
|
||||
const editEvent = (data: any) => {
|
||||
let url = router.resolve({
|
||||
path: '/decorate/edit',
|
||||
query: { id: data.id }
|
||||
});
|
||||
window.open(url.href);
|
||||
}
|
||||
|
||||
// 删除自定义页面
|
||||
const deleteEvent = (id: number) => {
|
||||
ElMessageBox.confirm(t('diyPageDeleteTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning',
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取自定义路由列表
|
||||
*/
|
||||
const loadDiyRouteList = (page: number = 1) => {
|
||||
diyRouteTableData.loading = true
|
||||
diyRouteTableData.page = page
|
||||
|
||||
getDiyRouteList({
|
||||
page: diyRouteTableData.page,
|
||||
limit: diyRouteTableData.limit,
|
||||
...diyRouteTableData.searchParam
|
||||
}).then(res => {
|
||||
diyRouteTableData.loading = false
|
||||
diyRouteTableData.data = res.data.data
|
||||
diyRouteTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
diyRouteTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadDiyRouteList()
|
||||
|
||||
// 获取自定义页面类型
|
||||
getDiyPageType({}).then(res=>{
|
||||
for (let item in res.data){
|
||||
pageType.push(res.data[item])
|
||||
}
|
||||
})
|
||||
|
||||
let diyPageTableData:any = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
"title": "",
|
||||
"type": '',
|
||||
}
|
||||
})
|
||||
|
||||
const tabValue = ref('diy')
|
||||
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||
tabValue.value = tab.props.name;
|
||||
if(tabValue.value == 'diy'){
|
||||
).then(() => {
|
||||
deleteDiyPage(id).then(() => {
|
||||
loadDiyPageList()
|
||||
}else{
|
||||
loadDiyRouteList()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const searchFormDiyRouteRef = ref<FormInstance>()
|
||||
|
||||
const searchFormDiyPageRef = ref<FormInstance>()
|
||||
|
||||
// 获取自定义页面列表
|
||||
const loadDiyPageList = (page: number = 1) => {
|
||||
diyPageTableData.loading = true
|
||||
diyPageTableData.page = page
|
||||
|
||||
getDiyPageList({
|
||||
page: diyPageTableData.page,
|
||||
limit: diyPageTableData.limit,
|
||||
...diyPageTableData.searchParam
|
||||
}).then(res => {
|
||||
diyPageTableData.loading = false
|
||||
diyPageTableData.data = res.data.data
|
||||
diyPageTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
diyPageTableData.loading = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 设为使用
|
||||
const setUse = (data: any) => {
|
||||
setUseDiyPage({ id: data.id }).then(() => {
|
||||
loadDiyPageList()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
const { copy, isSupported, copied } = useClipboard()
|
||||
const copyEvent = (text: string) => {
|
||||
if (!isSupported.value) {
|
||||
ElMessage({
|
||||
message: t('notSupportCopy'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
copy(text)
|
||||
}
|
||||
|
||||
loadDiyPageList()
|
||||
watch(copied, () => {
|
||||
if (copied.value) {
|
||||
ElMessage({
|
||||
message: t('copySuccess'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 编辑自定义页面
|
||||
const editEvent = (data: any) => {
|
||||
let url = router.resolve({
|
||||
path: '/decorate/edit',
|
||||
query: {id: data.id}
|
||||
});
|
||||
window.open(url.href);
|
||||
const tabShareType = ref('wechat')
|
||||
const sharePage = ref('')
|
||||
const shareFormId = ref(0)
|
||||
const diyRouteData = reactive({
|
||||
title: '',
|
||||
name: '',
|
||||
page: '',
|
||||
is_share: 0,
|
||||
sort: 0
|
||||
})
|
||||
const shareFormData = reactive({
|
||||
wechat: {
|
||||
title: '',
|
||||
desc: '',
|
||||
url: ''
|
||||
},
|
||||
weapp: {
|
||||
title: '',
|
||||
url: ''
|
||||
}
|
||||
})
|
||||
const shareDialogVisible = ref(false)
|
||||
const shareFormRules = computed(() => {
|
||||
return {
|
||||
// title: [
|
||||
// { required: true, message: t('shareTitlePlaceholder'), trigger: 'blur' },
|
||||
// // {
|
||||
// // validator: (rule: any, value: string, callback: any) => {
|
||||
// // console.log('validator',value,tabShareType)
|
||||
// // // let content = value.replace(/<[^<>]+>/g, "").replace(/ /gi, "")
|
||||
// // // if(!content && value.indexOf('img') === -1){
|
||||
// // // callback(new Error(t('shareTitlePlaceholder')))
|
||||
// // // }else callback()
|
||||
// // },
|
||||
// // trigger: ['blur', 'change']
|
||||
// // }
|
||||
// ],
|
||||
}
|
||||
})
|
||||
|
||||
const shareFormRef = ref<FormInstance>()
|
||||
const openShare = async (row: any) => {
|
||||
if (tabValue.value == 'route') {
|
||||
// 基础页面
|
||||
let info = (await getDiyRouteInfo({
|
||||
name: row.name
|
||||
})).data;
|
||||
|
||||
if (info.title) {
|
||||
row.id = info.id;
|
||||
row.title = info.title
|
||||
row.name = info.name
|
||||
row.page = info.page
|
||||
row.is_share = info.is_share
|
||||
row.sort = info.sort
|
||||
row.share = info.share
|
||||
}
|
||||
|
||||
diyRouteData.title = row.title
|
||||
diyRouteData.name = row.name
|
||||
diyRouteData.page = row.page
|
||||
diyRouteData.is_share = row.is_share
|
||||
diyRouteData.sort = row.sort
|
||||
|
||||
}
|
||||
shareFormId.value = row.id;
|
||||
sharePage.value = row.title;
|
||||
let share = row.share ? JSON.parse(row.share) : {
|
||||
wechat: { title: '', desc: '', url: '' },
|
||||
weapp: { title: '', url: '' }
|
||||
};
|
||||
if (share) {
|
||||
shareFormData.wechat = share.wechat;
|
||||
shareFormData.weapp = share.weapp;
|
||||
}
|
||||
|
||||
// 删除自定义页面
|
||||
const deleteEvent = (id: number) => {
|
||||
ElMessageBox.confirm(t('diyPageDeleteTips'), t('warning'),
|
||||
{
|
||||
confirmButtonText: t('confirm'),
|
||||
cancelButtonText: t('cancel'),
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
deleteDiyPage(id).then(() => {
|
||||
loadDiyPageList()
|
||||
shareDialogVisible.value = true;
|
||||
}
|
||||
|
||||
const shareEvent = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
let save = tabValue.value == 'diy' ? editDiyPageShare : editDiyRouteShare
|
||||
save({
|
||||
id: shareFormId.value,
|
||||
share: JSON.stringify(shareFormData),
|
||||
...diyRouteData
|
||||
}).then(() => {
|
||||
if (tabValue.value == 'diy') {
|
||||
loadDiyPageList()
|
||||
} else {
|
||||
loadDiyRouteList()
|
||||
}
|
||||
shareDialogVisible.value = false;
|
||||
}).catch(() => {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 设为使用
|
||||
const setUse = (data: any) => {
|
||||
setUseDiyPage({id: data.id}).then(() => {
|
||||
loadDiyPageList()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
const {copy, isSupported, copied} = useClipboard()
|
||||
const copyEvent = (text: string) => {
|
||||
if (!isSupported.value) {
|
||||
ElMessage({
|
||||
message: t('notSupportCopy'),
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
copy(text)
|
||||
}
|
||||
|
||||
watch(copied, () => {
|
||||
if (copied.value) {
|
||||
ElMessage({
|
||||
message: t('copySuccess'),
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const tabShareType = ref('wechat')
|
||||
const sharePage = ref('')
|
||||
const shareFormId = ref(0)
|
||||
const shareFormData = reactive({
|
||||
wechat:{
|
||||
title: '',
|
||||
desc: '',
|
||||
url: ''
|
||||
},
|
||||
weapp:{
|
||||
title: '',
|
||||
url: ''
|
||||
}
|
||||
})
|
||||
const shareDialogVisible = ref(false)
|
||||
const shareFormRules = computed(() => {
|
||||
return {
|
||||
// title: [
|
||||
// { required: true, message: t('shareTitlePlaceholder'), trigger: 'blur' },
|
||||
// // {
|
||||
// // validator: (rule: any, value: string, callback: any) => {
|
||||
// // console.log('validator',value,tabShareType)
|
||||
// // // let content = value.replace(/<[^<>]+>/g, "").replace(/ /gi, "")
|
||||
// // // if(!content && value.indexOf('img') === -1){
|
||||
// // // callback(new Error(t('shareTitlePlaceholder')))
|
||||
// // // }else callback()
|
||||
// // },
|
||||
// // trigger: ['blur', 'change']
|
||||
// // }
|
||||
// ],
|
||||
}
|
||||
const promoteDialogVisible = ref(false)
|
||||
const tabPromote = ref('wechat')
|
||||
const promoteWapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const promoteEvent = (data: any) => {
|
||||
promoteWapDomain.value = wapDomain.value + '/pages/index/diy?id=' + data.id;
|
||||
QRCode.toDataURL(promoteWapDomain.value, { errorCorrectionLevel: 'L', margin: 0, width: 100 }).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
|
||||
const shareFormRef = ref<FormInstance>()
|
||||
const openShare = (row:any)=> {
|
||||
shareFormId.value = row.id;
|
||||
sharePage.value = row.title;
|
||||
let share = row.share ? JSON.parse(row.share) : {
|
||||
wechat: {title: '', desc: '', url: ''},
|
||||
weapp: {title: '', url: ''}
|
||||
};
|
||||
if (share) {
|
||||
shareFormData.wechat = share.wechat;
|
||||
shareFormData.weapp = share.weapp;
|
||||
}
|
||||
|
||||
shareDialogVisible.value = true;
|
||||
}
|
||||
|
||||
const shareEvent = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
|
||||
await formEl.validate(async (valid) => {
|
||||
if (valid) {
|
||||
let save = tabValue.value == 'diy' ? updateDiyPageShare : updateDiyRouteShare
|
||||
save({
|
||||
id:shareFormId.value,
|
||||
share:JSON.stringify(shareFormData)
|
||||
}).then(() => {
|
||||
if(tabValue.value == 'diy'){
|
||||
loadDiyPageList()
|
||||
}else{
|
||||
loadDiyRouteList()
|
||||
}
|
||||
shareDialogVisible.value = false;
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const promoteDialogVisible = ref(false)
|
||||
const tabPromote = ref('wechat')
|
||||
const wapDomain = ref('')
|
||||
const wapImage = ref('')
|
||||
const promoteEvent = (data:any)=>{
|
||||
wapDomain.value = getWapDomain() + '/pages/index/diy?id=' + data.id;
|
||||
QRCode.toDataURL(wapDomain.value, {errorCorrectionLevel: 'L', margin: 0, width: 100}).then(url => {
|
||||
wapImage.value = url
|
||||
})
|
||||
|
||||
promoteDialogVisible.value = true;
|
||||
console.log('promoteEvent',data)
|
||||
}
|
||||
promoteDialogVisible.value = true;
|
||||
console.log('promoteEvent', data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.copy {
|
||||
background: var(--el-color-primary) !important;
|
||||
color: var(--el-color-white) !important;
|
||||
}
|
||||
.copy {
|
||||
background: var(--el-color-primary) !important;
|
||||
color: var(--el-color-white) !important;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
@ -5,9 +5,6 @@
|
||||
<script lang="ts" setup>
|
||||
import {ref} from 'vue'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {getWapDomain} from '@/utils/common'
|
||||
|
||||
const wapDomain = ref(getWapDomain() + '/pages/member/index')
|
||||
|
||||
const router = useRouter()
|
||||
const url = router.resolve({
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<div class="error404">
|
||||
<error code="403" :title="t('tips')" :show-btn="false">
|
||||
<template #content>
|
||||
<div class="flex justify-center">
|
||||
<img class="w-[150px] h-[150px]" src="@/assets/images/no_perms.png" alt="" />
|
||||
</div>
|
||||
</template>
|
||||
</error>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import error from './components/error.vue'
|
||||
import { t } from '@/lang'
|
||||
</script>
|
||||
@ -1,9 +1,56 @@
|
||||
<template>
|
||||
<div class="error404">
|
||||
<error code="404" title="哎呀,出错了!您访问的页面不存在…"></error>
|
||||
<div class="error">
|
||||
<div>
|
||||
<slot name="content">
|
||||
<div class="error-code">404</div>
|
||||
</slot>
|
||||
<div class="text-lg text-tx-secondary mt-7 mb-7">页面不存在</div>
|
||||
<div>
|
||||
<el-button type="primary" @click="router.go(-1)">
|
||||
{{ second }} 秒后返回上一页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Error from './components/error.vue'
|
||||
import { onUnmounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
let timer: any = null
|
||||
const second = ref(5)
|
||||
const router = useRouter()
|
||||
|
||||
timer = setInterval(() => {
|
||||
if (second.value === 0) {
|
||||
clearInterval(timer)
|
||||
router.go(-1)
|
||||
} else {
|
||||
second.value--
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
onUnmounted(() => {
|
||||
timer && clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error {
|
||||
text-align: center;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.error-code {
|
||||
@apply text-primary;
|
||||
font-size: 150px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
width: 176px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
<template>
|
||||
<div class="error">
|
||||
<div>
|
||||
<slot name="content">
|
||||
<div class="error-code">{{ code }}</div>
|
||||
</slot>
|
||||
<div class="text-lg text-tx-secondary mt-7 mb-7">{{ title }}</div>
|
||||
<el-button v-if="showBtn" type="primary" @click="router.go(-1)">
|
||||
{{ second }} 秒后返回上一页
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onUnmounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
const props = defineProps({
|
||||
code: String,
|
||||
title: String,
|
||||
showBtn: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
let timer: any = null
|
||||
const second = ref(5)
|
||||
const router = useRouter()
|
||||
props.showBtn &&
|
||||
(timer = setInterval(() => {
|
||||
if (second.value === 0) {
|
||||
clearInterval(timer)
|
||||
router.go(-1)
|
||||
} else {
|
||||
second.value--
|
||||
}
|
||||
}, 1000))
|
||||
onUnmounted(() => {
|
||||
timer && clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error {
|
||||
text-align: center;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.error-code {
|
||||
@apply text-primary;
|
||||
font-size: 150px;
|
||||
}
|
||||
.el-button {
|
||||
width: 176px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
332
admin/src/views/finance/cash_out.vue
Normal file
332
admin/src/views/finance/cash_out.vue
Normal file
@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
|
||||
<el-card class="box-card !border-none my-[16px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
|
||||
<el-form-item :label="t('cashOutStatus')" prop="order_from">
|
||||
<el-select v-model="orderTableData.searchParam.status" clearable class="input-width">
|
||||
<el-option :label="t('selectPlaceholder')" value="" />
|
||||
<el-option :label="item" :value="key" v-for="(item, key) in cashOutStatusList" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('createTime')" prop="create_time">
|
||||
<el-date-picker v-model="orderTableData.searchParam.create_time" type="datetimerange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" :start-placeholder="t('startDate')"
|
||||
:end-placeholder="t('endDate')" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadOrderList()">{{ t('search') }}</el-button>
|
||||
<el-button @click="searchFormRef?.resetFields()">{{ t('reset') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<div class="mt-[16px]">
|
||||
<el-table :data="orderTableData.data" size="large" v-loading="orderTableData.loading">
|
||||
<template #empty>
|
||||
<span>{{ !orderTableData.loading ? t('emptyData') : '' }}</span>
|
||||
</template>
|
||||
|
||||
<el-table-column prop="order_no" :show-overflow-tooltip="true" :label="t('memberInfo')" align="center" min-width="140">
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center cursor-pointer " @click="toMember(row.member_id)">
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-if="row.headimg" :src="img(row.headimg)" alt="" >
|
||||
<img class="w-[50px] h-[50px] mr-[10px]" v-else src="@/assets/images/default_headimg.png" alt="" >
|
||||
<div class="flex flex flex-col">
|
||||
<span class="text-blue-700">{{ row.nickname || '' }}</span>
|
||||
<span class="text-blue-700">{{ row.mobile || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="account_type_name" :label="t('cashOutAccountType')" align="center" min-width="140" />
|
||||
<el-table-column :label="t('cashOutMethod')" align="center" min-width="140" >
|
||||
<template #default="{ row }">
|
||||
{{ Transfertype[row.transfer_type].name }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="apply_money" :label="t('applicationForWithdrawalAmount')" min-width="140" align="center" />
|
||||
<!--
|
||||
<el-table-column prop="service_money" :label="t('cashOutCommission')" align="center" min-width="140" />
|
||||
-->
|
||||
<el-table-column prop="money" :label="t('cashOutMoney')" min-width="200" align="center">
|
||||
<template #default="{ row }">
|
||||
<div>{{ t('actualTransferAmount') }} :{{ row.money }}</div>
|
||||
<div>{{ t('cashOutCommission') }} :{{ row.service_money }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="status_name" :label="t('cashOutStatus')" align="center" min-width="100" />
|
||||
|
||||
<el-table-column :label="t('applyTime')" min-width="180" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.create_time || '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column :label="t('operation')" fixed="right" width="230">
|
||||
<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>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
<div class="mt-[16px] flex justify-end">
|
||||
<el-pagination v-model:current-page="orderTableData.page" v-model:page-size="orderTableData.limit"
|
||||
layout="total, sizes, prev, pager, next, jumper" :total="orderTableData.total"
|
||||
@size-change="loadOrderList()" @current-change="loadOrderList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
<!-- 详情 -->
|
||||
<el-dialog v-model="cashOutShowDialog" :title="t('cashOutDetail')" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="cashOutInfo" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="cashOutLoading">
|
||||
<el-form-item :label="t('nickname')">
|
||||
<div class="input-width"> {{ cashOutInfo.nickname }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('cashOutAccountType')">
|
||||
<div class="input-width"> {{ cashOutInfo.account_type_name }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('cashOutMethod')">
|
||||
<div class="input-width"> {{ Transfertype[cashOutInfo.transfer_type].name }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('applicationForWithdrawalAmount')">
|
||||
<div class="input-width"> {{ cashOutInfo.apply_money }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('cashOutCommission')">
|
||||
<div class="input-width"> {{ cashOutInfo.service_money }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('actualTransferAmount')">
|
||||
<div class="input-width"> {{ cashOutInfo.money }} </div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('cashOutStatus')">
|
||||
<div class="input-width"> {{ cashOutInfo.status_name }} </div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button type="primary" @click="cashOutShowDialog = false">{{t('confirm')}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 是否审核 -->
|
||||
<el-dialog v-model="auditShowDialog" :title="t('rejectionAudit')" width="500px" :destroy-on-close="true">
|
||||
<el-form :model="auditFailure" label-width="90px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
|
||||
<el-form-item :label="t('reasonsRefusal')" prop="label_name">
|
||||
<el-input v-model="auditFailure.refuse_reason" clearable :placeholder="t('reasonsRefusalPlaceholder')" class="input-width" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="auditShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
|
||||
t('confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 是否转账 -->
|
||||
<el-dialog v-model="transferShowDialog" :title="t('rejectionAudit')" width="500px" :destroy-on-close="true">
|
||||
<p>{{t('isTransfer')}}</p>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="transferShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm(formRef)">{{
|
||||
t('confirm')
|
||||
}}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getWithdrawList, getTransfertype, memberTransfer, memberAudit, getWithdrawDetail, getWithdrawStatusList } from '@/api/member'
|
||||
import { img } from '@/utils/common'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { data } from 'dom7'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
const cashOutStatusList = ref([])
|
||||
const checkStatusList = async () => {
|
||||
cashOutStatusList.value = await (await getWithdrawStatusList({})).data
|
||||
}
|
||||
checkStatusList()
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const member_id: number = parseInt(route.query.id || 0)
|
||||
const operationBtn = ref({
|
||||
"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']
|
||||
},
|
||||
"-1": {
|
||||
value: [t('detail')],
|
||||
clickArr: ['detailFn']
|
||||
},
|
||||
"-2": {
|
||||
value: [t('detail')],
|
||||
clickArr: ['detailFn']
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const orderTableData = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
loading: true,
|
||||
data: [],
|
||||
searchParam: {
|
||||
order_no: '',
|
||||
member_id,
|
||||
create_time: [],
|
||||
status: ''
|
||||
}
|
||||
})
|
||||
|
||||
// 获取会员转账方式
|
||||
const Transfertype = ref<Array<Object>>([])
|
||||
const getTransfertypeFn = async()=>{
|
||||
Transfertype.value = await (await getTransfertype()).data
|
||||
}
|
||||
getTransfertypeFn()
|
||||
|
||||
/**
|
||||
* 获取提现列表
|
||||
*/
|
||||
const loadOrderList = (page: number = 1) => {
|
||||
orderTableData.loading = true
|
||||
orderTableData.page = page
|
||||
|
||||
getWithdrawList({
|
||||
page: orderTableData.page,
|
||||
limit: orderTableData.limit,
|
||||
...orderTableData.searchParam
|
||||
}).then(res => {
|
||||
orderTableData.loading = false
|
||||
orderTableData.data = res.data.data
|
||||
orderTableData.total = res.data.total
|
||||
}).catch(() => {
|
||||
orderTableData.loading = false
|
||||
})
|
||||
}
|
||||
loadOrderList()
|
||||
|
||||
// 函数总处理
|
||||
let auditFailure = ref({refuse_reason:'',id:0,action: 0})
|
||||
let auditShowDialog = ref(false);
|
||||
const fnProcessing = (type:string, data: any)=>{
|
||||
let obj = {}
|
||||
if(['successfulAuditFn','auditFailureFn'].includes(type)){
|
||||
obj.id = data.id;
|
||||
if(type == 'successfulAuditFn'){
|
||||
obj.action = 'agree';
|
||||
cashOutAuditFn(obj)
|
||||
}else{
|
||||
obj.action = 'refuse';
|
||||
auditFailure.value = Object.assign(auditFailure.value,obj);
|
||||
auditShowDialog.value = true;
|
||||
}
|
||||
}else if(type == 'transferFn'){
|
||||
obj.id = data.id;
|
||||
ElMessageBox.confirm(`${t('isTransfer')}`,`${t('transfer')}`)
|
||||
.then(() => {
|
||||
transferFn(obj);
|
||||
})
|
||||
}else{
|
||||
detailFn(data.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转账
|
||||
* @param data
|
||||
*/
|
||||
const transferFn = (data)=>{
|
||||
memberTransfer({...data}).then(res => {
|
||||
loadOrderList()
|
||||
}).catch(() => {
|
||||
loadOrderList()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情
|
||||
* @param data
|
||||
*/
|
||||
|
||||
let cashOutShowDialog = ref(false);
|
||||
let cashOutInfo = ref({});
|
||||
let cashOutLoading = ref(true);
|
||||
const detailFn = (id)=>{
|
||||
getWithdrawDetail(id).then(res => {
|
||||
cashOutInfo.value = res.data;
|
||||
cashOutShowDialog.value = true;
|
||||
cashOutLoading.value = false;
|
||||
}).catch(() => {
|
||||
loadOrderList()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 提现审核
|
||||
* @param data
|
||||
*/
|
||||
const cashOutAuditFn = (data)=>{
|
||||
memberAudit({
|
||||
...data
|
||||
}).then(res => {
|
||||
loadOrderList()
|
||||
}).catch(() => {
|
||||
loadOrderList()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝审核
|
||||
* @param data
|
||||
*/
|
||||
const confirm = ()=>{
|
||||
auditShowDialog.value = false;
|
||||
cashOutAuditFn(auditFailure.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单详情
|
||||
* @param data
|
||||
*/
|
||||
const infoEvent = (data: any) => {
|
||||
router.push(`/finance/recharge/detail?order_id=${data.order_id}`)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 会员详情
|
||||
*/
|
||||
const toMember = (member_id: number) => {
|
||||
router.push(`/member/detail?id=${member_id}`)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="main-container">
|
||||
<el-card class="box-card !border-none" shadow="never">
|
||||
|
||||
<el-card class="box-card !border-none my-[16px] table-search-wrap" shadow="never">
|
||||
<el-card class="box-card !border-none mb-[16px] table-search-wrap" shadow="never">
|
||||
<el-form :inline="true" :model="orderTableData.searchParam" ref="searchFormRef">
|
||||
<!-- <el-form-item :label="t('orderNo')" prop="order_no">
|
||||
<el-input v-model="orderTableData.searchParam.order_no" :placeholder="t('orderNoPlaceholder')" />
|
||||
@ -73,9 +73,10 @@
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="infoEvent(row)">{{ t('info') }}</el-button>
|
||||
|
||||
<el-button v-if="[1, 10].includes(row.order_status_info.status)" type="primary" link @click="refundBtnFn(row)">{{ t('refundBtn') }}</el-button>
|
||||
|
||||
<template v-for="(item, index) in row.order_status_info.action">
|
||||
<el-button type="danger" link @click="orderEvent(row, item.class)">{{ item.name
|
||||
}}</el-button>
|
||||
<el-button type="danger" link @click="orderEvent(row, item.class)">{{ item.name }}</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@ -87,20 +88,28 @@
|
||||
@size-change="loadOrderList()" @current-change="loadOrderList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
|
||||
<!-- 是否退款 -->
|
||||
<el-dialog v-model="refundShowDialog" :title="t('refundBtn')" width="500px" :destroy-on-close="true">
|
||||
<p>{{t('refundContent')}}</p>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="refundShowDialog = false">{{ t('cancel') }}</el-button>
|
||||
<el-button type="primary" @click="confirm(formRef)">{{ t('confirm') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { t } from '@/lang'
|
||||
import { getRechargeOrderStatusList, getRechargeOrderList } from '@/api/order'
|
||||
import { getRechargeOrderStatusList, getRechargeOrderList, rechargeRefund } from '@/api/order'
|
||||
import { getChannelType } from '@/api/sys'
|
||||
import { img } from '@/utils/common'
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import { data } from 'dom7'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const member_id: number = parseInt(route.query.id || 0)
|
||||
@ -169,6 +178,32 @@ const infoEvent = (data: any) => {
|
||||
const orderEvent = (data: any, type: string) => {
|
||||
|
||||
}
|
||||
/**
|
||||
* 退款操作
|
||||
*/
|
||||
let refundShowDialog = ref(false);
|
||||
const refundFn = (data) => {
|
||||
console.log("退款操作",data);
|
||||
refundShowDialog.value = true;
|
||||
rechargeRefund(data.order_id).then(res => {
|
||||
refundShowDialog.value = false;
|
||||
}).catch(() => {
|
||||
|
||||
})
|
||||
|
||||
|
||||
// getRechargeOrderList({
|
||||
// page: orderTableData.page,
|
||||
// limit: orderTableData.limit,
|
||||
// ...orderTableData.searchParam
|
||||
// }).then(res => {
|
||||
// orderTableData.loading = false
|
||||
// orderTableData.data = res.data.data
|
||||
// orderTableData.total = res.data.total
|
||||
// }).catch(() => {
|
||||
// orderTableData.loading = false
|
||||
// })
|
||||
}
|
||||
|
||||
/**
|
||||
* 会员详情
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user