🔥 删除无用文件

This commit is contained in:
lbw 2023-06-27 15:21:56 +08:00
parent bdac045aec
commit 2bb9142e22
156 changed files with 14 additions and 11559 deletions

View File

@ -4,6 +4,6 @@ COPY ./dist /data
RUN rm /etc/nginx/conf.d/default.conf RUN rm /etc/nginx/conf.d/default.conf
ADD pigx-ui.conf /etc/nginx/conf.d/default.conf ADD pig-ui.conf /etc/nginx/conf.d/default.conf
RUN /bin/bash -c 'echo init ok' RUN /bin/bash -c 'echo init ok'

View File

@ -4,16 +4,16 @@ services:
build: build:
context: . context: .
restart: always restart: always
container_name: pigx-ui container_name: pig-ui
image: pigx-ui image: pig-ui
networks: networks:
- pigx_default - pig_default
external_links: external_links:
- pigx-gateway - pig-gateway
ports: ports:
- 80:80 - 80:80
# 加入到后端网络, 默认为 pigx_default | docker network ls 查看 # 加入到后端网络, 默认为 pig_default | docker network ls 查看
networks: networks:
pigx_default: pig_default:
external: true external: true

View File

@ -1,9 +1,9 @@
{ {
"name": "pigx-ui", "name": "pig-ui",
"version": "5.1.0", "version": "3.7.0",
"description": "PIGCLOUD微服务开发平台", "description": "PIGCLOUD微服务开发平台",
"author": "pig4cloud", "author": "pig4cloud",
"license": "不对外分发 pig4cloud 版权所有,请购买商业版权", "license": "Apache-2.0",
"scripts": { "scripts": {
"dev": "vite --force", "dev": "vite --force",
"build": "vite build", "build": "vite build",

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/app/appArticle/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/app/appArticle',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: `/app/appArticle/details/${id}/1`,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/app/appArticle',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/app/appArticle',
method: 'put',
data: obj,
});
}

View File

@ -1,47 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/app/appArticleCategory/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/app/appArticleCategory',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/app/appArticleCategory/' + id,
method: 'get',
});
}
export function getObjList() {
return request({
url: '/app/appArticleCategory/list',
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/app/appArticleCategory',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/app/appArticleCategory',
method: 'put',
data: obj,
});
}

View File

@ -1,113 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query: any) {
return request({
url: '/app/approle/page',
method: 'get',
params: query,
});
}
export function list() {
return request({
url: '/app/approle/list',
method: 'get',
});
}
export function addObj(obj: any) {
return request({
url: '/app/approle',
method: 'post',
data: obj,
});
}
export function getObj(id: string) {
return request({
url: '/app/approle/' + id,
method: 'get',
});
}
export function delObj(ids?: object) {
return request({
url: '/app/approle',
method: 'delete',
data: ids,
});
}
export function putObj(obj: any) {
return request({
url: '/app/approle',
method: 'put',
data: obj,
});
}
export function fetchRoleTree(roleId: string) {
return request({
url: '/app/appmenu/tree/' + roleId,
method: 'get',
});
}
export function permissionUpd(roleId: string, menuIds: string) {
return request({
url: '/app/approle/menu',
method: 'put',
data: {
roleId: roleId,
menuIds: menuIds,
},
});
}
export function getDetails(obj: Object) {
return request({
url: '/app/approle/details/' + obj,
method: 'get',
});
}
export function getDetailsByCode(obj: Object) {
return request({
url: '/app/approle/detailsByCode/' + obj,
method: 'get',
});
}
export function validateApproleName(rule: any, value: any, callback: any, isEdit: boolean) {
const flag = new RegExp(/^([a-z\u4e00-\u9fa5\d]+?)$/).test(value);
if (!flag) {
callback(new Error('用户名支持小写英文、数字、中文'));
}
if (isEdit) {
return callback();
}
getDetails(value).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('用户名已经存在'));
} else {
callback();
}
});
}
export function validateAppRoleCode(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getDetailsByCode(value).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('角色标识已经存在'));
} else {
callback();
}
});
}

View File

@ -1,39 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query: any) {
return request({
url: '/app/approlemenu/page',
method: 'get',
params: query,
});
}
export function addObj(obj: any) {
return request({
url: '/app/approlemenu',
method: 'post',
data: obj,
});
}
export function getObj(id: string) {
return request({
url: '/app/approlemenu/' + id,
method: 'get',
});
}
export function delObj(id: string) {
return request({
url: '/app/approlemenu/' + id,
method: 'delete',
});
}
export function putObj(obj: string) {
return request({
url: '/app/approlemenu',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/app/appsocial/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/app/appsocial',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/app/appsocial/' + id,
method: 'get',
});
}
export function delObj(ids?: object) {
return request({
url: '/app/appsocial/',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/app/appsocial',
method: 'put',
data: obj,
});
}

View File

@ -1,86 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query: any) {
return request({
url: '/app/appuser/page',
method: 'get',
params: query,
});
}
export function addObj(obj: any) {
return request({
url: '/app/appuser',
method: 'post',
data: obj,
});
}
export function getObj(id: string) {
return request({
url: '/app/appuser/details/' + id,
method: 'get',
});
}
export function delObj(ids?: object) {
return request({
url: '/app/appuser/',
method: 'delete',
data: ids,
});
}
export function putObj(obj: any) {
return request({
url: '/app/appuser',
method: 'put',
data: obj,
});
}
export function getDetails(obj: Object) {
return request({
url: '/app/appuser/details/',
method: 'get',
params: obj,
});
}
export function validateUsername(rule: any, value: any, callback: any, isEdit: boolean) {
const flag = new RegExp(/^([a-z\d]+?)$/).test(value);
if (!flag) {
callback(new Error('用户名支持小写英文、数字'));
}
if (isEdit) {
return callback();
}
getDetails({
username: value,
}).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('用户名已经存在'));
} else {
callback();
}
});
}
export function validatePhone(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getDetails({
phone: value,
}).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('手机号已经存在'));
} else {
callback();
}
});
}

View File

@ -1,39 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query: any) {
return request({
url: '/app/appuserrole/page',
method: 'get',
params: query,
});
}
export function addObj(obj: any) {
return request({
url: '/app/appuserrole',
method: 'post',
data: obj,
});
}
export function getObj(id: string) {
return request({
url: '/app/appuserrole/' + id,
method: 'get',
});
}
export function delObj(id: string) {
return request({
url: '/app/appuserrole/' + id,
method: 'delete',
});
}
export function putObj(obj: any) {
return request({
url: '/app/appuserrole',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/app/page/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/app/appPage',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/app/appPage/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/app/page',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/app/appPage',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/app/appTabbar/list',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/app/appTabbar',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/app/appTabbar/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/app/appTabbar',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/app/appTabbar',
method: 'put',
data: obj,
});
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/mp/wx-account-fans/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/mp/wx-account-fans',
method: 'post',
data: obj,
});
}
export function sync(appId) {
return request({
url: '/mp/wx-account-fans/sync/' + appId,
method: 'post',
});
}
export function getObj(id) {
return request({
url: '/mp/wx-account-fans/' + id,
method: 'get',
});
}
export function delObjs(id) {
return request({
url: '/mp/wx-account-fans/' + id,
method: 'delete',
});
}
export function putObj(obj) {
return request({
url: '/mp/wx-account-fans',
method: 'put',
data: obj,
});
}
export function black(obj, appid) {
return request({
url: '/mp/wx-account-fans/black/' + appid,
method: 'post',
data: obj,
});
}
export function unblack(obj, appid) {
return request({
url: '/mp/wx-account-fans/unblack/' + appid,
method: 'post',
data: obj,
});
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
import request from '/@/utils/request';
export function getPage(query) {
return request({
url: '/mp/wx-account-tag/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/mp/wx-account-tag',
method: 'post',
data: obj,
});
}
export function delObjs(obj) {
return request({
url: '/mp/wx-account-tag',
method: 'delete',
data: obj,
});
}
export function putObj(obj) {
return request({
url: '/mp/wx-account-tag',
method: 'put',
data: obj,
});
}
export function sync(appId) {
return request({
url: '/mp/wx-account-tag/sync/' + appId,
method: 'post',
});
}
export function list(appId) {
return request({
url: '/mp/wx-account-tag/list/',
method: 'get',
params: { wxAccountAppid: appId },
});
}

View File

@ -1,86 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/mp/wx-account/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/mp/wx-account',
method: 'post',
data: obj,
});
}
export function getObj(id) {
return request({
url: '/mp/wx-account/' + id,
method: 'get',
});
}
export function generateQr(appid) {
return request({
url: '/mp/wx-account/qr/' + appid,
method: 'post',
});
}
export function clearQuota(appid) {
return request({
url: '/mp/wx-account/clear-quota/' + appid,
method: 'post',
});
}
export function delObjs(id) {
return request({
url: '/mp/wx-account/' + id,
method: 'delete',
});
}
export function putObj(obj) {
return request({
url: '/mp/wx-account',
method: 'put',
data: obj,
});
}
export function fetchAccountList(obj?: object) {
return request({
url: '/mp/wx-account/list',
method: 'get',
params: obj,
});
}
export function fetchStatistics(q) {
return request({
url: '/mp/wx-account/statistics',
method: 'get',
params: q,
});
}

View File

@ -1,39 +0,0 @@
import request from '/@/utils/request';
export function getPage(query) {
return request({
url: '/mp/wx-auto-reply/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/mp/wx-auto-reply',
method: 'post',
data: obj,
});
}
export function getObj(id) {
return request({
url: '/mp/wx-auto-reply/' + id,
method: 'get',
});
}
export function delObj(id) {
return request({
url: '/mp/wx-auto-reply/' + id,
method: 'delete',
});
}
export function putObj(obj) {
return request({
url: '/mp/wx-auto-reply',
method: 'put',
data: obj,
});
}

View File

@ -1,79 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/mp/wx-fans-msg/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/mp/wx-fans-msg',
method: 'post',
data: obj,
});
}
export function getObj(id) {
return request({
url: '/mp/wxfansmsg/' + id,
method: 'get',
});
}
export function delObjs(id) {
return request({
url: '/mp/wxfansmsg/' + id,
method: 'delete',
});
}
export function putObj(obj) {
return request({
url: '/mp/wxfansmsg',
method: 'put',
data: obj,
});
}
export function fetchResList(query) {
return request({
url: '/mp/wx-fans-msg/page',
method: 'get',
params: query,
});
}
export function addResObj(obj) {
return request({
url: '/mp/wx-fans-msg',
method: 'post',
data: obj,
});
}
export function delResObj(id) {
return request({
url: '/mp/wx-fans-msg/' + id,
method: 'delete',
});
}

View File

@ -1,74 +0,0 @@
import request from '/@/utils/request';
export function getPage(query) {
return request({
url: '/mp/wx-material/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/mp/wx-material/materialNews',
method: 'post',
data: obj,
});
}
export function materialNewsUpdate(obj) {
return request({
url: '/mp/wx-material/materialNews',
method: 'put',
data: obj,
});
}
export function getObj(id) {
return request({
url: '/mp/wx-material/' + id,
method: 'get',
});
}
export function delObj(query) {
return request({
url: '/mp/wx-material',
method: 'delete',
params: query,
});
}
export function putObj(obj) {
return request({
url: '/mp/wx-material',
method: 'put',
data: obj,
});
}
export function getMaterialOther(query) {
return request({
url: '/mp/wx-material/materialOther',
method: 'get',
params: query,
responseType: 'blob',
});
}
export function getMaterialVideo(query) {
return request({
url: '/mp/wx-material/materialVideo',
method: 'get',
params: query,
});
}
export function getTempMaterialOther(query) {
return request({
url: '/mp/wx-material/tempMaterialOther',
method: 'get',
params: query,
responseType: 'blob',
});
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
import request from '/@/utils/request';
export function getObj(id) {
return request({
url: '/mp/wx-menu/' + id,
method: 'get',
});
}
export function saveObj(appId, data) {
return request({
url: '/mp/wx-menu/' + appId,
method: 'post',
data: data,
});
}
export function publishObj(id) {
return request({
url: '/mp/wx-menu/' + id,
method: 'put',
});
}

View File

@ -1,47 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/act/leave-bill/page',
method: 'get',
params: query,
});
}
export function addObj(obj) {
return request({
url: '/act/leave-bill',
method: 'post',
data: obj,
});
}
export function getObj(id) {
return request({
url: '/act/leave-bill/' + id,
method: 'get',
});
}
export function submit(id) {
return request({
url: '/act/leave-bill/submit/' + id,
method: 'get',
});
}
export function delObj(ids?: Object) {
return request({
url: '/act/leave-bill',
method: 'delete',
data: ids,
});
}
export function putObj(obj) {
return request({
url: '/act/leave-bill/',
method: 'put',
data: obj,
});
}

View File

@ -1,47 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/act/model',
method: 'get',
params: query,
});
}
export function delObj(ids: Object) {
return request({
url: '/act/model',
method: 'delete',
data: ids,
});
}
export function deploy(id) {
return request({
url: '/act/model/deploy/' + id,
method: 'post',
});
}
export function addObj(obj?: Object) {
return request({
url: '/act/model/insert',
method: 'post',
data: obj,
});
}
export function getObj(id) {
return request({
url: '/act/log/' + id,
method: 'get',
});
}
export function putObj(obj) {
return request({
url: '/act/log/',
method: 'put',
data: obj,
});
}

View File

@ -1,24 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/act/process',
method: 'get',
params: query,
});
}
export function delObj(ids?: Object) {
return request({
url: '/act/process',
method: 'delete',
data: ids,
});
}
export function status(id, type) {
return request({
url: '/act/process/status/' + id + '/' + type,
method: 'put',
});
}

View File

@ -1,39 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query) {
return request({
url: '/act/task/todo',
method: 'get',
params: query,
});
}
export function fetchDetail(id) {
return request({
url: '/act/task/' + id,
method: 'get',
});
}
export function fetchComment(id) {
return request({
url: '/act/task/comment/' + id,
method: 'get',
});
}
export function doTask(obj) {
return request({
url: '/act/task',
method: 'post',
data: obj,
});
}
export function delObj(ids?: Object) {
return request({
url: '/act/task',
method: 'delete',
data: ids,
});
}

View File

@ -1,9 +0,0 @@
import request from '/@/utils/request';
export function useBuyApi(amount?: any) {
return request({
url: '/pay/goods/merge/buy',
method: 'get',
params: { amount: amount },
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/pay/channel/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/pay/channel',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/pay/channel/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/pay/channel',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/pay/channel',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/pay/goods/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/pay/goods',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/pay/goods/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/pay/goods',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/pay/goods',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/pay/notify/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/pay/notify',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/pay/notify/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/pay/notify',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/pay/notify',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/pay/refund/page',
method: 'get',
params: query,
});
}
export function useRefundApi(obj?: Object) {
return request({
url: '/pay/refund',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/pay/refund/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/pay/refund',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/pay/refund',
method: 'put',
data: obj,
});
}

View File

@ -1,40 +0,0 @@
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/pay/trade/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/pay/trade',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/pay/trade/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/pay/trade',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/pay/trade',
method: 'put',
data: obj,
});
}

View File

@ -1,190 +0,0 @@
<template>
<div class="layout-padding-auto layout-padding-view">
<el-card shadow="never">
<el-form ref="dataFormRef" class="form" :model="form" label-width="85px" :rules="dataRules">
<div class="flex">
<div>
<el-form-item label="文章标题" prop="title">
<div class="w-80">
<el-input
v-model="form.title"
placeholder="请输入文章标题"
type="textarea"
:autosize="{ minRows: 3, maxRows: 3 }"
maxlength="64"
show-word-limit
clearable
/>
</div>
</el-form-item>
<el-form-item label="文章简介" prop="intro">
<div class="w-80">
<el-input
v-model="form.intro"
placeholder="请输入文章简介"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
:maxlength="200"
show-word-limit
clearable
/>
</div>
</el-form-item>
<el-form-item label="摘要" prop="summary">
<div class="w-80">
<el-input type="textarea" :autosize="{ minRows: 6, maxRows: 6 }" v-model="form.summary" maxlength="200" show-word-limit clearable />
</div>
</el-form-item>
<el-form-item label="文章封面" prop="image">
<div>
<div>
<upload-img v-model:imageUrl="form.image" />
</div>
<div class="form-tips">建议尺寸240*180px</div>
</div>
</el-form-item>
</div>
<div class="xl:ml-20">
<el-row class="xl:mb-8">
<el-col :span="12">
<el-form-item label="文章栏目" prop="cid">
<el-select class="w-80" v-model="form.cid" placeholder="请选择文章栏目" clearable>
<el-option v-for="item in articleCateList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="作者" prop="author">
<div class="w-80">
<el-input class="w-40" v-model="form.author" placeholder="请输入作者名称" />
</div>
</el-form-item>
</el-col>
</el-row>
<el-row class="xl:mb-8">
<el-col :span="12">
<el-form-item label="初始浏览量" prop="visit">
<template #label> 浏览量<tip content="初始值" /> </template>
<el-input-number class="!w-80" v-model="form.visit" :min="0" :max="9999" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="sort">
<template #label> 排序<tip content="默认为0 数值越大越排前" /> </template>
<el-input-number class="!w-80" v-model="form.sort" :min="0" :max="9999" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="文章内容" required prop="content">
<editor v-model:get-html="form.content" :height="500" :width="600" />
</el-form-item>
<div style="text-align: center">
<el-button type="primary" @click="onSubmit">保存</el-button>
</div>
</div>
</div>
</el-form>
</el-card>
</div>
</template>
<script setup lang="ts" name="AppArticleDialog">
import { useMessage } from '/@/hooks/message';
import { getObj, addObj, putObj } from '/@/api/app/appArticle';
import { getObjList } from '/@/api/app/appArticleCategory';
const emit = defineEmits(['refresh']);
const route = useRoute();
//
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
//
const articleCateList = ref([]);
//
const form = reactive({
id: '',
cid: '',
title: '',
intro: '',
summary: '',
image: '',
content: '',
author: '',
visit: 0,
sort: 0,
});
//
const dataRules = ref({
cid: [{ required: true, message: '分类不能为空', trigger: 'blur' }],
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
intro: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
summary: [{ required: true, message: '摘要不能为空', trigger: 'blur' }],
image: [{ required: true, message: '封面不能为空', trigger: 'blur' }],
content: [{ required: true, message: '内容不能为空', trigger: 'blur' }],
author: [{ required: true, message: '作者不能为空', trigger: 'blur' }],
visit: [{ required: true, message: '浏览不能为空', trigger: 'blur' }],
});
//
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
try {
loading.value = true;
form.id ? await putObj(form) : await addObj(form);
useMessage().success(form.id ? '修改成功' : '添加成功');
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
//
const getAppArticleData = (id: string) => {
//
loading.value = true;
getObj(id)
.then((res: any) => {
Object.assign(form, res.data);
})
.finally(() => {
loading.value = false;
});
};
//
const getAppCateList = () => {
getObjList().then((res: any) => {
articleCateList.value = res.data;
});
};
onMounted(() => {
getAppCateList();
if (route.query?.id) {
getAppArticleData(route.query?.id);
}
});
</script>
<style scoped lang="scss">
.footer-btns {
height: 60px;
&__content {
bottom: 0;
height: 60px;
right: 0;
left: 0;
z-index: 99;
@apply flex justify-center items-center shadow;
}
}
</style>

View File

@ -1,6 +0,0 @@
export default {
article: {
edit: 'edit article',
add: 'add article',
},
};

View File

@ -1,6 +0,0 @@
export default {
article: {
edit: '编辑文章',
add: '发布文章',
},
};

View File

@ -1,133 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row v-show="showSearch">
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
<el-form-item label="标题" prop="title">
<el-input placeholder="请输入标题" v-model="state.queryForm.title" />
</el-form-item>
<el-form-item label="作者" prop="author">
<el-input placeholder="请输入作者" v-model="state.queryForm.author" />
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button v-auth="'app_appArticle_add'" icon="folder-add" type="primary" class="ml10" @click="addOrUpdate()"> </el-button>
<el-button plain :disabled="multiple" icon="Delete" type="primary" v-auth="'app_appArticle_del'" @click="handleDelete(selectObjs)">
删除
</el-button>
<right-toolbar
v-model:showSearch="showSearch"
:export="'app_appArticle_export'"
@exportExcel="exportExcel"
class="ml10 mr20"
style="float: right"
@queryTable="getDataList"
></right-toolbar>
</div>
</el-row>
<el-table
:data="state.dataList"
v-loading="state.loading"
@selection-change="handleSelectionChange"
@sort-change="sortChangeHandle"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="cname" label="分类" show-overflow-tooltip />
<el-table-column prop="title" label="标题" show-overflow-tooltip />
<el-table-column prop="author" label="作者" show-overflow-tooltip />
<el-table-column prop="visit" label="浏览" show-overflow-tooltip />
<el-table-column prop="sort" label="排序" show-overflow-tooltip />
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button icon="edit-pen" text type="primary" v-auth="'app_appArticle_edit'" @click="addOrUpdate(scope.row.id)">编辑</el-button>
<el-button icon="delete" text type="primary" v-auth="'app_appArticle_del'" @click="handleDelete([scope.row.id])">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</div>
</div>
</template>
<script setup lang="ts" name="systemAppArticle">
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObjs } from '/@/api/app/appArticle';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
//
//
const router = useRouter();
const { t } = useI18n();
//
const queryRef = ref();
const showSearch = ref(true);
//
const selectObjs = ref([]) as any;
const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
//
const resetQuery = () => {
//
queryRef.value?.resetFields();
//
selectObjs.value = [];
getDataList();
};
// excel
const exportExcel = () => {
downBlobFile('/app/appArticle/export', state.queryForm, 'appArticle.xlsx');
};
//
const handleSelectionChange = (objs: { id: string }[]) => {
selectObjs.value = objs.map(({ id }) => id);
multiple.value = !objs.length;
};
//
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm('此操作将永久删除');
} catch {
return;
}
try {
await delObjs(ids);
getDataList();
useMessage().success('删除成功');
} catch (err: any) {
useMessage().error(err.msg);
}
};
//
const addOrUpdate = (id?: string) => {
const tagsViewName = id ? `${t('article.edit')}:${id}` : t('article.add');
router.push({
path: '/app/appArticle/form',
query: { id: id, tagsViewName: tagsViewName },
});
};
</script>

View File

@ -1,114 +0,0 @@
<template>
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="排序" prop="sort">
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序"></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="是否显示" prop="isShow">
<el-radio-group v-model="form.isShow">
<el-radio :label="item.value" v-for="(item, index) in yes_no_type" border :key="index">{{ item.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="AppArticleCategoryDialog">
import { useDict } from '/@/hooks/dict';
import { useMessage } from '/@/hooks/message';
import { getObj, addObj, putObj } from '/@/api/app/appArticleCategory';
const emit = defineEmits(['refresh']);
//
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
//
const { yes_no_type } = useDict('yes_no_type');
//
const form = reactive({
id: '',
name: '',
sort: 0,
isShow: '',
});
//
const dataRules = ref({
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
isShow: [{ required: true, message: '是否显示: 0=否, 1=是不能为空', trigger: 'blur' }],
});
//
const openDialog = (id: string) => {
visible.value = true;
form.id = '';
//
nextTick(() => {
dataFormRef.value?.resetFields();
});
// appArticleCategory
if (id) {
form.id = id;
getappArticleCategoryData(id);
}
};
//
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
try {
loading.value = true;
form.id ? await putObj(form) : await addObj(form);
useMessage().success(form.id ? '修改成功' : '添加成功');
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
//
const getappArticleCategoryData = (id: string) => {
//
loading.value = true;
getObj(id)
.then((res: any) => {
Object.assign(form, res.data);
})
.finally(() => {
loading.value = false;
});
};
//
defineExpose({
openDialog,
});
</script>

View File

@ -1,124 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row v-show="showSearch">
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
<el-form-item label="名称" prop="name">
<el-input placeholder="请输入名称" v-model="state.queryForm.name" />
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'app_appArticleCategory_add'">
</el-button>
<el-button plain :disabled="multiple" icon="Delete" type="primary" v-auth="'app_appArticleCategory_del'" @click="handleDelete(selectObjs)">
删除
</el-button>
<right-toolbar
v-model:showSearch="showSearch"
:export="'app_appArticleCategory_export'"
@exportExcel="exportExcel"
class="ml10 mr20"
style="float: right"
@queryTable="getDataList"
></right-toolbar>
</div>
</el-row>
<el-table
:data="state.dataList"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="name" label="名称" show-overflow-tooltip />
<el-table-column prop="sort" label="排序" show-overflow-tooltip />
<el-table-column prop="isShow" label="是否显示" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="yes_no_type" :value="scope.row.isShow"></dict-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="scope">
<el-button icon="edit-pen" text type="primary" v-auth="'app_appArticleCategory_edit'" @click="formDialogRef.openDialog(scope.row.id)"
>编辑</el-button
>
<el-button icon="delete" text type="primary" v-auth="'app_appArticleCategory_del'" @click="handleDelete([scope.row.id])">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</div>
<!-- 编辑新增 -->
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
</div>
</template>
<script setup lang="ts" name="systemAppArticleCategory">
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObjs } from '/@/api/app/appArticleCategory';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useDict } from '/@/hooks/dict';
//
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
//
const { yes_no_type } = useDict('yes_no_type');
//
const formDialogRef = ref();
//
const queryRef = ref();
const showSearch = ref(true);
//
const selectObjs = ref([]) as any;
const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
//
const resetQuery = () => {
//
queryRef.value?.resetFields();
//
selectObjs.value = [];
getDataList();
};
// excel
const exportExcel = () => {
downBlobFile('/app/appArticleCategory/export', state.queryForm, 'appArticleCategory.xlsx');
};
//
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm('此操作将永久删除');
} catch {
return;
}
try {
await delObjs(ids);
getDataList();
useMessage().success('删除成功');
} catch (err: any) {
useMessage().error(err.msg);
}
};
</script>

View File

@ -1,148 +0,0 @@
<template>
<el-dialog :close-on-click-modal="false" :title="form.roleId ? $t('common.editBtn') : $t('common.addBtn')" draggable v-model="visible">
<el-form :model="form" :rules="dataRules" label-width="90px" ref="dataFormRef" v-loading="loading">
<el-row :gutter="35">
<el-col :span="12" class="mb20">
<el-form-item :label="$t('approle.roleName')" prop="roleName">
<el-input :placeholder="$t('approle.please_enter_a_role_name')" clearable v-model="form.roleName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('approle.roleCode')" prop="roleCode">
<el-input :placeholder="$t('approle.please_enter_the_role_Code')" clearable v-model="form.roleCode"></el-input>
</el-form-item>
</el-col>
<el-col :lg="24" :md="24" :sm="24" :xl="24" :xs="24" class="mb20">
<el-form-item :label="$t('approle.roleDesc')" prop="roleDesc">
<el-input
:placeholder="$t('approle.please_enter_the_role_description')"
maxlength="150"
type="textarea"
v-model="form.roleDesc"
></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" name="systemRoleDialog" setup>
import { rule } from '/@/utils/validate';
import { useMessage } from '/@/hooks/message';
import { addObj, getObj, putObj, validateAppRoleCode, validateApproleName } from '/@/api/app/approle';
import { useI18n } from 'vue-i18n';
// /
const emit = defineEmits(['refresh']);
const { t } = useI18n();
//
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
//
const form = reactive({
roleId: '',
roleName: '',
roleCode: '',
roleDesc: '',
});
//
const dataForm = reactive({
deptData: [],
checkedDsScope: [],
deptProps: {
children: 'children',
label: 'name',
value: 'id',
},
});
//
const dataRules = ref({
roleName: [
{ required: true, message: '角色名称不能为空', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
validateApproleName(rule, value, callback, form.roleId !== '');
},
trigger: 'blur',
},
],
roleCode: [
{ required: true, message: '角色标识不能为空', trigger: 'blur' },
{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' },
{ validator: rule.validatorCapital, trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
validateAppRoleCode(rule, value, callback, form.roleId !== '');
},
trigger: 'blur',
},
],
roleDesc: [{ max: 128, message: '长度在 128 个字符内', trigger: 'blur' }],
});
//
const openDialog = (id: string) => {
visible.value = true;
form.roleId = '';
//
nextTick(() => {
dataFormRef.value?.resetFields();
});
//
if (id) {
form.roleId = id;
getRoleData(id);
}
};
//
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
try {
loading.value = true;
form.roleId ? await putObj(form) : await addObj(form);
useMessage().success(t(form.roleId ? 'common.editSuccessText' : 'common.addSuccessText'));
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
//
const getRoleData = (id: string) => {
//
getObj(id).then((res: any) => {
Object.assign(form, res.data);
if (res.data.dsScope) {
dataForm.checkedDsScope = res.data.dsScope.split(',');
} else {
dataForm.checkedDsScope = [];
}
});
};
//
defineExpose({
openDialog,
});
</script>

View File

@ -1,15 +0,0 @@
export default {
approle: {
index: '#',
roleName: 'roleName',
inputRoleNameTip: 'input roleName',
permissionTip: 'grant',
roleCode: 'roleCode',
roleDesc: 'role description',
createTime: 'createTime',
please_enter_a_role_name: 'please enter a role name',
please_enter_the_role_Code: 'please enter the role Code',
please_enter_the_role_description: 'please enter the role description',
},
};

View File

@ -1,15 +0,0 @@
export default {
approle: {
index: '#',
roleName: '角色名',
inputRoleNameTip: '请输入角色名称',
permissionTip: '授权',
roleCode: '用户标识',
roleDesc: '用户描述',
createTime: '创建时间',
please_enter_a_role_name: '请输入角色名称',
please_enter_the_role_Code: '请输入角色标识',
please_enter_the_role_description: '请输入角色描述',
},
};

View File

@ -1,153 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row class="ml10" v-show="showSearch">
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
<el-form-item :label="$t('approle.roleName')" prop="roleName">
<el-input :placeholder="$t('approle.inputRoleNameTip')" style="max-width: 180px" v-model="state.queryForm.roleName" />
</el-form-item>
<el-form-item>
<el-button @click="getDataList" icon="search" type="primary">
{{ $t('common.queryBtn') }}
</el-button>
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button @click="roleDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary" v-auth="'app_approle_add'">
{{ $t('common.addBtn') }}
</el-button>
<el-button plain @click="excelUploadRef.show()" class="ml10" icon="upload-filled" type="primary" v-auth="'app_approle_export'">
{{ $t('common.importBtn') }}
</el-button>
<el-button
plain
:disabled="multiple"
@click="handleDelete(selectObjs)"
class="ml10"
icon="Delete"
type="primary"
v-auth="'app_approle_del'"
>
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar
:export="'app_approle_export'"
@exportExcel="exportExcel"
@queryTable="getDataList"
class="ml10"
style="float: right; margin-right: 20px"
v-model:showSearch="showSearch"
></right-toolbar>
</div>
</el-row>
<el-table
:data="state.dataList"
@selection-change="handleSelectionChange"
style="width: 100%"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column align="center" type="selection" width="40" />
<el-table-column :label="$t('approle.index')" type="index" width="60" />
<el-table-column :label="$t('approle.roleName')" prop="roleName" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('approle.roleCode')" prop="roleCode" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('approle.roleDesc')" prop="roleDesc" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('approle.createTime')" prop="createTime" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('common.action')" width="250">
<template #default="scope">
<el-button icon="edit-pen" @click="roleDialogRef.openDialog(scope.row.roleId)" text type="primary" v-auth="'app_approle_edit'"
>{{ $t('common.editBtn') }}
</el-button>
<el-button icon="delete" @click="handleDelete([scope.row.roleId])" text type="primary" v-auth="'app_approle_del'"
>{{ $t('common.delBtn') }}
</el-button>
</template>
</el-table-column>
</el-table>
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
</div>
<!-- 角色编辑新增 -->
<role-dialog @refresh="getDataList()" ref="roleDialogRef" />
<!-- 导入角色 -->
<upload-excel
:title="$t('sysuser.importUserTip')"
@refreshDataList="getDataList"
ref="excelUploadRef"
temp-url="/admin/sys-file/local/file/approle.xlsx"
url="/admin/approle/import"
/>
</div>
</template>
<script lang="ts" name="systemRole" setup>
import { BasicTableProps, useTable } from '/@/hooks/table';
import { delObj, fetchList } from '/@/api/app/approle';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
//
const RoleDialog = defineAsyncComponent(() => import('./form.vue'));
const { t } = useI18n();
//
const roleDialogRef = ref();
const excelUploadRef = ref();
const queryRef = ref();
const showSearch = ref(true);
// rows
const selectObjs = ref([]) as any;
//
const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {
roleName: '',
},
pageList: fetchList, // H
descs: ['create_time'],
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
//
const resetQuery = () => {
queryRef.value.resetFields();
getDataList();
};
// excel
const exportExcel = () => {
downBlobFile('/app/approle/export', state.queryForm, 'approle.xlsx');
};
//
const handleSelectionChange = (objs: { roleId: string }[]) => {
selectObjs.value = objs.map(({ roleId }) => roleId);
multiple.value = !objs.length;
};
//
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm(t('common.delConfirmText'));
} catch {
return;
}
try {
await delObj(ids);
getDataList();
useMessage().success(t('common.delSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
}
};
</script>

View File

@ -1,151 +0,0 @@
<template>
<el-dialog :close-on-click-modal="false" :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" draggable v-model="visible">
<el-form :model="form" :rules="dataRules" formDialogRef label-width="90px" ref="dataFormRef" v-loading="loading">
<el-row :gutter="20">
<el-col :span="12" class="mb20">
<el-form-item :label="t('appsocial.type')" prop="type">
<el-select :placeholder="t('appsocial.inputTypeTip')" v-model="form.type">
<el-option :key="index" :label="item.label" :value="item.value" v-for="(item, index) in app_social_type"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('appsocial.remark')" prop="remark">
<el-input :placeholder="t('appsocial.inputRemarkTip')" v-model="form.remark" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('appsocial.appId')" prop="appId">
<el-input :placeholder="t('appsocial.inputAppIdTip')" v-model="form.appId" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('appsocial.appSecret')" prop="appSecret">
<el-input :placeholder="t('appsocial.inputAppSecretTip')" v-model="form.appSecret" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item :label="t('appsocial.redirectUrl')" prop="redirectUrl">
<el-input :placeholder="t('appsocial.inputRedirectUrlTip')" type="textarea" v-model="form.redirectUrl" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item :label="t('appsocial.ext')" prop="ext">
<el-input :placeholder="t('appsocial.inputExtTip')" type="textarea" v-model="form.ext" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button @click="onSubmit" type="primary" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" name="AppSocialDetailsDialog" setup>
// /
import { useDict } from '/@/hooks/dict';
import { useMessage } from '/@/hooks/message';
import { addObj, getObj, putObj } from '/@/api/app/appsocial';
import { useI18n } from 'vue-i18n';
import { rule } from '/@/utils/validate';
const emit = defineEmits(['refresh']);
const { t } = useI18n();
//
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
//
const { app_social_type } = useDict('app_social_type');
//
const form = reactive({
id: '',
type: '',
remark: '',
appId: '' as string | undefined,
appSecret: '' as string | undefined,
redirectUrl: '',
ext: '',
});
//
const dataRules = ref({
type: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
appId: [{ required: true, message: 'appId不能为空', trigger: 'blur' }],
appSecret: [{ required: true, message: 'app秘钥不能为空', trigger: 'blur' }],
redirectUrl: [
{ required: true, message: '回调地址不能为空', trigger: 'blur' },
{ validator: rule.url, trigger: 'blur' },
],
});
//
const openDialog = (id: string) => {
visible.value = true;
form.id = '';
//
nextTick(() => {
dataFormRef.value?.resetFields();
});
// appSocialDetails
if (id) {
form.id = id;
getappSocialDetailsData(id);
}
};
//
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
//
form.appSecret = form.appSecret?.includes('******') ? undefined : form.appSecret;
form.appId = form.appId?.includes('******') ? undefined : form.appId;
try {
loading.value = true;
if (form.id) {
await putObj(form);
useMessage().success(t('common.editSuccessText'));
} else {
await addObj(form);
useMessage().success(t('common.addSuccessText'));
}
visible.value = false; //
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
//
const getappSocialDetailsData = (id: string) => {
//
getObj(id).then((res: any) => {
Object.assign(form, res.data);
});
};
//
defineExpose({
openDialog,
});
</script>

View File

@ -1,32 +0,0 @@
export default {
appsocial: {
index: '#',
importappSocialDetailsTip: 'import AppSocialDetails',
id: 'id',
type: 'type',
remark: 'remark',
appId: 'appId',
appSecret: 'appSecret',
redirectUrl: 'redirectUrl',
ext: 'ext',
createBy: 'createBy',
updateBy: 'updateBy',
createTime: 'createTime',
updateTime: 'updateTime',
delFlag: 'delFlag',
tenantId: 'tenantId',
inputIdTip: 'input id',
inputTypeTip: 'input type',
inputRemarkTip: 'input remark',
inputAppIdTip: 'input appId',
inputAppSecretTip: 'input appSecret',
inputRedirectUrlTip: 'input redirectUrl',
inputExtTip: 'input ext',
inputCreateByTip: 'input createBy',
inputUpdateByTip: 'input updateBy',
inputCreateTimeTip: 'input createTime',
inputUpdateTimeTip: 'input updateTime',
inputDelFlagTip: 'input delFlag',
inputTenantIdTip: 'input tenantId',
},
};

View File

@ -1,32 +0,0 @@
export default {
appsocial: {
index: '#',
importappSocialDetailsTip: '导入系统社交登录账号表',
id: '主鍵',
type: '类型',
remark: '描述',
appId: 'appId',
appSecret: 'app秘钥',
redirectUrl: '回调地址',
ext: '拓展字段',
createBy: '创建人',
updateBy: '修改人',
createTime: '创建时间',
updateTime: '更新时间',
delFlag: '${field.fieldComment}',
tenantId: '所属租户',
inputIdTip: '请输入主鍵',
inputTypeTip: '请输入类型',
inputRemarkTip: '请输入描述',
inputAppIdTip: '请输入appId',
inputAppSecretTip: '请输入appSecret',
inputRedirectUrlTip: '请输入回调地址',
inputExtTip: '请输入拓展字段',
inputCreateByTip: '请输入创建人',
inputUpdateByTip: '请输入修改人',
inputCreateTimeTip: '请输入创建时间',
inputUpdateTimeTip: '请输入更新时间',
inputDelFlagTip: '请输入${field.fieldComment}',
inputTenantIdTip: '请输入所属租户',
},
};

View File

@ -1,162 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row class="ml10" v-show="showSearch">
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
<el-form-item :label="t('appsocial.type')" class="ml2" prop="type">
<el-select :placeholder="t('appsocial.inputTypeTip')" v-model="state.queryForm.type">
<el-option :key="index" :label="item.label" :value="item.value" v-for="(item, index) in app_social_type"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="getDataList" formDialogRef icon="search" type="primary">
{{ $t('common.queryBtn') }}
</el-button>
<el-button @click="resetQuery" formDialogRef icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button
@click="formDialogRef.openDialog()"
class="ml10"
formDialogRef
icon="folder-add"
type="primary"
v-auth="'app_social_details_add'"
>
{{ $t('common.addBtn') }}
</el-button>
<el-button
plain
:disabled="multiple"
@click="handleDelete(selectObjs)"
class="ml10"
formDialogRef
icon="Delete"
type="primary"
v-auth="'app_social_details_del'"
>
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar
:export="'app_social_details_del'"
@exportExcel="exportExcel"
@queryTable="getDataList"
class="ml10"
style="float: right; margin-right: 20px"
v-model:showSearch="showSearch"
></right-toolbar>
</div>
</el-row>
<el-table
:data="state.dataList"
@selection-change="handleSelectionChange"
@sort-change="sortChangeHandle"
style="width: 100%"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column align="center" type="selection" width="40" />
<el-table-column :label="t('appsocial.index')" type="index" width="60" />
<el-table-column :label="t('appsocial.type')" prop="type" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="app_social_type" :value="scope.row.type"></dict-tag>
</template>
</el-table-column>
<el-table-column :label="t('appsocial.remark')" prop="remark" show-overflow-tooltip />
<el-table-column :label="t('appsocial.appId')" prop="appId" show-overflow-tooltip />
<el-table-column :label="t('appsocial.appSecret')" prop="appSecret" show-overflow-tooltip />
<el-table-column :label="t('appsocial.createTime')" prop="createTime" show-overflow-tooltip />
<el-table-column :label="$t('common.action')" width="150">
<template #default="scope">
<el-button icon="edit-pen" @click="formDialogRef.openDialog(scope.row.id)" text type="primary" v-auth="'app_social_details_edit'"
>{{ $t('common.editBtn') }}
</el-button>
<el-button icon="delete" @click="handleDelete([scope.row.id])" text type="primary" v-auth="'app_social_details_del'"
>{{ $t('common.delBtn') }}
</el-button>
</template>
</el-table-column>
</el-table>
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
</div>
<!-- 编辑新增 -->
<form-dialog @refresh="getDataList()" ref="formDialogRef" />
</div>
</template>
<script lang="ts" name="systemAppSocialDetails" setup>
import { BasicTableProps, useTable } from '/@/hooks/table';
import { delObj, fetchList } from '/@/api/app/appsocial';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useDict } from '/@/hooks/dict';
import { useI18n } from 'vue-i18n';
//
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
const { t } = useI18n();
//
const { app_social_type } = useDict('app_social_type');
//
const formDialogRef = ref();
//
const queryRef = ref();
const showSearch = ref(true);
//
const selectObjs = ref([]) as any;
const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {
type: '',
},
pageList: fetchList,
descs: ['create_time'],
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
//
const resetQuery = () => {
//
queryRef.value.resetFields();
//
selectObjs.value = [];
getDataList();
};
// excel
const exportExcel = () => {
downBlobFile('/app/appsocial/export', state.queryForm, 'appsocial.xlsx');
};
//
const handleSelectionChange = (objs: { id: string }[]) => {
selectObjs.value = objs.map(({ id }) => id);
multiple.value = !objs.length;
};
//
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm(t('common.delConfirmText'));
} catch {
return;
}
try {
await delObj(ids);
getDataList();
useMessage().success(t('common.delSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
}
};
</script>

View File

@ -1,218 +0,0 @@
<template>
<div class="system-user-dialog-container">
<el-dialog v-model="visible" :close-on-click-modal="false" :title="dataForm.userId ? $t('common.editBtn') : $t('common.addBtn')" draggable>
<el-form ref="dataFormRef" v-loading="loading" :model="dataForm" :rules="dataRules" label-width="90px">
<el-row :gutter="20">
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.username')" prop="username">
<el-input v-model="dataForm.username" :disabled="dataForm.userId !== ''" :placeholder="$t('appuser.inputUserNameTip')"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.password')" prop="password">
<el-input v-model="dataForm.password" :placeholder="$t('appuser.inputPasswordTip')" clearable type="password"></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.name')" prop="name">
<el-input v-model="dataForm.name" :placeholder="$t('appuser.inputNameTip')" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.phone')" prop="phone">
<el-input v-model="dataForm.phone" :placeholder="$t('appuser.inputPhoneTip')" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.role')" prop="role">
<el-select v-model="dataForm.role" :placeholder="$t('appuser.inputRoleTip')" class="w100" clearable multiple>
<el-option v-for="item in roleData" :key="item.roleId" :label="item.roleName" :value="item.roleId" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.email')" prop="email">
<el-input v-model="dataForm.email" :placeholder="$t('appuser.inputEmailTip')" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.nickname')" prop="nickname">
<el-input v-model="dataForm.nickname" :placeholder="$t('appuser.inputNickNameTip')" clearable></el-input>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="$t('appuser.lockFlag')" prop="lockFlag">
<el-radio-group v-model="dataForm.lockFlag">
<el-radio v-for="(item, index) in lock_flag" :key="index" :label="item.value" border>{{ item.label }} </el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" name="systemUserDialog" setup>
import { addObj, getObj, putObj, validatePhone, validateUsername } from '/@/api/app/appuser';
import { list as roleList } from '/@/api/app/approle';
import { useDict } from '/@/hooks/dict';
import { useI18n } from 'vue-i18n';
import { useMessage } from '/@/hooks/message';
import { rule } from '/@/utils/validate';
const { t } = useI18n();
// emit
const emit = defineEmits(['refresh']);
// @ts-ignore
const { lock_flag } = useDict('lock_flag');
//
const dataFormRef = ref();
const visible = ref(false);
const roleData = ref<any[]>([]);
const loading = ref(false);
const dataForm = reactive({
userId: '',
username: '',
password: '' as String | undefined,
salt: '',
wxOpenid: '',
qqOpenid: '',
lockFlag: '0',
phone: '' as String | undefined,
deptId: '',
roleList: [],
postList: [],
nickname: '',
name: '',
email: '',
post: [] as string[],
role: [] as string[],
});
const dataRules = ref({
username: [
{ required: true, message: '用户名不能为空', trigger: 'blur' },
{ min: 3, max: 20, message: '用户名称长度必须介于 3 和 20 之间', trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
validateUsername(rule, value, callback, dataForm.userId !== '');
},
trigger: 'blur',
},
],
password: [
{ required: true, message: '密码不能为空', trigger: 'blur' },
{
min: 6,
max: 20,
message: '用户密码长度必须介于 6 和 20 之间',
trigger: 'blur',
},
],
name: [
{ required: true, message: '姓名不能为空', trigger: 'blur' },
{ validator: rule.chinese, trigger: 'blur' },
],
role: [{ required: true, message: '角色不能为空', trigger: 'blur' }],
phone: [
{ required: true, message: '手机号不能为空', trigger: 'blur' },
{ validator: rule.validatePhone, trigger: 'blur' },
{
validator: (rule: any, value: any, callback: any) => {
validatePhone(rule, value, callback, dataForm.userId !== '');
},
trigger: 'blur',
},
],
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
nickname: [{ required: true, message: '姓名不能为空', nickname: 'blur' }],
});
//
const openDialog = (id: string) => {
visible.value = true;
dataForm.userId = '';
//
nextTick(() => {
dataFormRef.value.resetFields();
});
//
if (id) {
dataForm.userId = id;
getUserData(id);
}
getRoleData();
};
//
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
try {
const { userId, phone, password } = dataForm;
if (userId) {
//
if (phone?.includes('*')) dataForm.phone = undefined;
if (password?.includes('******')) dataForm.password = undefined;
loading.value = true;
await putObj(dataForm);
useMessage().success(t('common.editSuccessText'));
visible.value = false; //
emit('refresh');
} else {
loading.value = true;
await addObj(dataForm);
useMessage().success(t('common.addSuccessText'));
visible.value = false; //
emit('refresh');
}
} catch (error: any) {
useMessage().error(error.msg);
} finally {
loading.value = false;
}
};
//
const getUserData = async (id: string) => {
loading.value = true;
try {
const { data } = await getObj(id);
Object.assign(dataForm, data);
dataForm.password = '******';
if (data.roleList) {
dataForm.role = data.roleList.map((item: any) => item.roleId);
}
} finally {
loading.value = false;
}
};
//
const getRoleData = () => {
roleList().then((res) => {
roleData.value = res.data;
});
};
//
defineExpose({
openDialog,
});
</script>

View File

@ -1,25 +0,0 @@
export default {
appuser: {
index: '#',
username: 'username',
name: 'name',
phone: 'phone',
post: 'post',
role: 'role',
lockFlag: 'lockFlag',
createTime: 'createTime',
password: 'password',
dept: 'dept',
email: 'email',
avatar: 'avatar',
nickname: 'nickname',
inputNameTip: 'input name',
inputRoleTip: 'input role',
inputUserNameTip: 'input username',
inputPasswordTip: 'input Password',
inputPhoneTip: 'input phone',
inputEmailTip: 'input Email',
inputNickNameTip: 'input NickName',
importUserTip: 'import user',
},
};

View File

@ -1,25 +0,0 @@
export default {
appuser: {
index: '#',
username: '用户名',
name: '姓名',
phone: '手机号',
post: '岗位',
role: '角色',
lockFlag: '状态',
createTime: '创建时间',
password: '密码',
dept: '部门',
email: '邮箱',
nickname: '昵称',
avatar: '头像',
inputNameTip: '请输入姓名',
inputRoleTip: '请选择角色',
inputUserNameTip: '请输入用户名',
inputPasswordTip: '请输入密码',
inputEmailTip: '请输入邮箱',
inputPhoneTip: '请输入手机号码',
inputNickNameTip: '请输入昵称',
importUserTip: '导入用户',
},
};

View File

@ -1,167 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row class="ml10" v-show="showSearch">
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
<el-form-item :label="$t('appuser.username')" prop="username">
<el-input :placeholder="$t('appuser.inputUserNameTip')" @keyup.enter="getDataList" clearable v-model="state.queryForm.username" />
</el-form-item>
<el-form-item :label="$t('appuser.phone')" prop="phone">
<el-input :placeholder="$t('appuser.inputPhoneTip')" @keyup.enter="getDataList" clearable v-model="state.queryForm.phone" />
</el-form-item>
<el-form-item>
<el-button @click="getDataList" icon="Search" type="primary">{{ $t('common.queryBtn') }} </el-button>
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button @click="userDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary" v-auth="'app_appuser_add'">
{{ $t('common.addBtn') }}
</el-button>
<el-button plain @click="excelUploadRef.show()" class="ml10" icon="upload-filled" type="primary" v-auth="'app_appuser_export'">
{{ $t('common.importBtn') }}
</el-button>
<el-button :disabled="multiple" @click="handleDelete(selectObjs)" class="ml10" icon="Delete" type="primary" v-auth="'app_appuser_del'">
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar
:export="'app_appuser_export'"
@exportExcel="exportExcel"
@queryTable="getDataList"
class="ml10"
style="float: right; margin-right: 20px"
v-model:showSearch="showSearch"
></right-toolbar>
</div>
</el-row>
<el-table
:data="state.dataList"
@selection-change="handleSelectionChange"
style="width: 100%"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column align="center" type="selection" width="40" />
<el-table-column :label="$t('appuser.index')" type="index" width="60" />
<el-table-column :label="$t('appuser.username')" prop="username" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('appuser.nickname')" prop="nickname" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('appuser.avatar')" prop="avatar" show-overflow-tooltip>
<template #default="scope">
<div style="display: flex; justify-content: center">
<ImageUpload v-model:imageUrl="scope.row.avatar" height="50px" width="50px" disabled />
</div>
</template>
</el-table-column>
<el-table-column :label="$t('appuser.role')" show-overflow-tooltip>
<template #default="scope">
<el-tag :key="index" v-for="(item, index) in scope.row.roleList">{{ item.roleName }} </el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('appuser.lockFlag')" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="lock_flag" :value="scope.row.lockFlag"></dict-tag>
</template>
</el-table-column>
<el-table-column :label="$t('appuser.createTime')" prop="createTime" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('common.action')" width="150">
<template #default="scope">
<el-button icon="edit-pen" @click="userDialogRef.openDialog(scope.row.userId)" text type="primary" v-auth="'app_appuser_edit'">
{{ $t('common.editBtn') }}
</el-button>
<el-button icon="delete" @click="handleDelete([scope.row.userId])" text type="primary" v-auth="'app_appuser_del'">
{{ $t('common.delBtn') }}
</el-button>
</template>
</el-table-column>
</el-table>
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination"> </pagination>
</div>
<user-form @refresh="getDataList()" ref="userDialogRef" />
<upload-excel
:title="$t('appuser.importUserTip')"
@refreshDataList="getDataList"
ref="excelUploadRef"
temp-url="/admin/sys-file/local/file/appuser.xlsx"
url="/admin/appuser/import"
/>
</div>
</template>
<script lang="ts" name="systemUser" setup>
import { delObj, fetchList } from '/@/api/app/appuser';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { useDict } from '/@/hooks/dict';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
//
const UserForm = defineAsyncComponent(() => import('./form.vue'));
const ImageUpload = defineAsyncComponent(() => import('/@/components/Upload/Image.vue'));
const { lock_flag } = useDict('lock_flag');
const { t } = useI18n();
//
const userDialogRef = ref();
const excelUploadRef = ref();
const queryRef = ref();
const showSearch = ref(true);
// rows
const selectObjs = ref([]) as any;
//
const multiple = ref(true);
// API
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {
username: '',
phone: '',
},
pageList: fetchList,
descs: ['create_time'],
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, downBlobFile, tableStyle } = useTable(state);
//
const resetQuery = () => {
queryRef.value.resetFields();
getDataList();
};
// excel
const exportExcel = () => {
downBlobFile('/app/appuser/export', state.queryForm, 'users.xlsx');
};
//
const handleSelectionChange = (objs: { userId: string }[]) => {
selectObjs.value = objs.map(({ userId }) => userId);
multiple.value = !objs.length;
};
//
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm(t('common.delConfirmText'));
} catch {
return;
}
try {
await delObj(ids);
getDataList();
useMessage().success(t('common.delSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
}
};
</script>

View File

@ -1,80 +0,0 @@
<template>
<div>
<div>
<draggable class="draggable" v-model="navLists" item-key="index" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap class="max-w-[400px]" :key="index" @close="handleDelete(index)">
<div class="flex items-center w-full p-4 mb-4 cursor-move bg-fill-light">
<upload-img v-model:imageUrl="item.image" height="50px" width="50px" iconSize="12" />
<div class="flex-1 ml-3">
<div class="flex">
<span class="flex-none mr-3 text-tx-regular">名称</span>
<el-input v-model="item.name" placeholder="请输入名称" />
</div>
<div class="flex mt-[18px]">
<span class="flex-none mr-3 text-tx-regular">链接</span>
<link-picker v-model="item.link" />
</div>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
<div>
<el-button type="primary" @click="handleAdd">添加</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import Draggable from 'vuedraggable';
import { useMessage } from '/@/hooks/message';
const LinkPicker = defineAsyncComponent(() => import('/@/components/Link/picker.vue'));
const props = defineProps({
modelValue: {
type: Array as PropType<any[]>,
default: () => [],
},
max: {
type: Number,
default: 10,
},
min: {
type: Number,
default: 1,
},
});
const emit = defineEmits(['update:modelValue']);
const navLists = computed({
get() {
return props.modelValue;
},
set(value) {
emit('update:modelValue', value);
},
});
const handleAdd = () => {
if (props.modelValue?.length < props.max) {
navLists.value.push({
image: '',
name: '导航名称',
link: {},
});
} else {
useMessage().error(`最多添加${props.max}`);
}
};
const handleDelete = (index: number) => {
if (props.modelValue?.length <= props.min) {
return useMessage().error(`最少保留${props.min}`);
}
navLists.value.splice(index, 1);
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,57 +0,0 @@
<template>
<el-image :style="styles" v-bind="props" :src="src.includes('http') ? src : baseURL + src">
<template #placeholder>
<div class="image-slot"></div>
</template>
<template #error>
<div class="image-slot">
<el-icon><Picture /></el-icon>
</div>
</template>
</el-image>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import type { CSSProperties } from 'vue';
import { imageProps } from 'element-plus';
import other from '/@/utils/other';
const props = defineProps({
width: {
type: [String, Number],
default: 'auto',
},
height: {
type: [String, Number],
default: 'auto',
},
radius: {
type: [String, Number],
default: 0,
},
...imageProps,
});
const styles = computed<CSSProperties>(() => {
return {
width: other.addUnit(props.width),
height: other.addUnit(props.height),
borderRadius: other.addUnit(props.radius),
};
});
</script>
<style lang="scss" scoped>
.el-image {
display: block;
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #fafafa;
color: #909399;
}
}
</style>

View File

@ -1,25 +0,0 @@
<template>
<div class="pages-setting">
<div class="title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2">
{{ widget?.title }}
</div>
<keep-alive>
<component class="pt-5 pr-4" :is="widgets[widget?.name]?.attr" :content="widget?.content" :styles="widget?.styles" :type="type" />
</keep-alive>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import widgets from '../widgets';
defineProps({
widget: {
type: Object as PropType<Record<string, any>>,
default: () => ({}),
},
type: {
type: String as PropType<'mobile' | 'pc'>,
default: 'mobile',
},
});
</script>

View File

@ -1,40 +0,0 @@
<template>
<el-menu :default-active="modelValue" class="w-[160px] min-h-[668px] pages-menu" @select="handleSelect">
<el-menu-item v-for="(item, key) in menus" :index="key" :key="item.id">
<span>{{ item.name }}</span>
</el-menu-item>
</el-menu>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
defineProps({
menus: {
type: Object as PropType<Record<string, any>>,
default: () => ({}),
},
modelValue: {
type: String,
default: '1',
},
});
const emit = defineEmits<{
(event: 'update:modelValue', value: string): void;
}>();
const handleSelect = (index: string) => {
emit('update:modelValue', index);
};
</script>
<style lang="scss" scoped>
.pages-menu {
:deep(.el-menu-item) {
border-color: transparent;
&.is-active {
border-right-width: 2px;
border-color: var(--el-color-primary);
background-color: var(--el-color-primary-light-9);
}
}
}
</style>

View File

@ -1,61 +0,0 @@
<template>
<div class="shadow mx-[30px] pages-preview">
<div
v-for="(widget, index) in pageData"
:key="widget.id"
class="relative"
:class="{
'cursor-pointer': !widget?.disabled,
}"
@click="handleClick(widget, index)"
>
<div
class="absolute w-full h-full z-[100] border-dashed"
:class="{
select: index == modelValue,
'border-[#dcdfe6] border-2': !widget?.disabled,
}"
></div>
<slot>
<component :is="widgets[widget?.name]?.content" :content="widget.content" :styles="widget.styles" :key="widget.id" />
</slot>
</div>
<slot name="footer" />
</div>
</template>
<script lang="ts" setup>
import widgets from '../widgets';
import type { PropType } from 'vue';
defineProps({
pageData: {
type: Array as PropType<any[]>,
default: () => [],
},
modelValue: {
type: Number,
default: 0,
},
});
const emit = defineEmits<{
(event: 'update:modelValue', value: number): void;
}>();
const handleClick = (widget: any, index: number) => {
if (widget.disabled) return;
emit('update:modelValue', index);
};
</script>
<style lang="scss" scoped>
.pages-preview {
background-color: #f8f8f8;
width: 360px;
height: 585px;
color: #333;
.select {
@apply border-primary border-solid;
}
}
</style>

View File

@ -1,84 +0,0 @@
<template>
<div>
<el-scrollbar style="height: 550px">
<el-form label-width="70px">
<el-form-item label="是否启用" v-if="type == 'mobile'">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*340px</div>
<draggable class="draggable" v-model="content.data" item-key="index" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap :key="index" @close="handleDelete(index)" class="max-w-[400px]">
<div class="flex items-center w-full p-1 mt-4 cursor-move bg-fill-light">
<upload-img v-model:imageUrl="item.image" />
<div class="flex-1 ml-3">
<el-form-item label="图片名称">
<el-input v-model="item.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-if="type == 'mobile'" v-model="item.link" />
<el-input v-if="type == 'pc'" placeholder="请输入链接" v-model="item.link.path" />
</el-form-item>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
</el-form-item>
<el-form-item v-if="content.data?.length < limit">
<el-button type="primary" @click="handleAdd">添加图片</el-button>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import { useMessage } from '/@/hooks/message';
import Draggable from 'vuedraggable';
const LinkPicker = defineAsyncComponent(() => import('/@/components/Link/picker.vue'));
const limit = 5;
type OptionsType = ReturnType<typeof options>;
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
type: {
type: String as PropType<'mobile' | 'pc'>,
default: 'mobile',
},
});
const handleAdd = () => {
if (props.content.data?.length < limit) {
props.content.data.push({
image: '',
name: '',
link: {},
});
} else {
useMessage().error(`最多添加${limit}张图片`);
}
};
const handleDelete = (index: number) => {
if (props.content.data?.length <= 1) {
return useMessage().error('最少保留一张图片');
}
props.content.data.splice(index, 1);
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,37 +0,0 @@
<template>
<div class="banner" :style="styles">
<div class="banner-image w-full h-full">
<decoration-img width="100%" :height="styles.height || height" :src="getImage" fit="contain" />
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import DecorationImg from '../../decoration-img.vue';
type OptionsType = ReturnType<typeof options>;
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
height: {
type: String,
default: '170px',
},
});
const getImage = computed(() => {
const { data } = props.content;
if (Array.isArray(data)) {
return data[0] ? data[0].image : '';
}
return '';
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,15 +0,0 @@
export default () => ({
title: '首页轮播图',
name: 'banner',
content: {
enabled: 1,
data: [
{
image: '',
name: '',
link: {},
},
],
},
styles: {},
});

View File

@ -1,38 +0,0 @@
<template>
<div>
<el-form label-width="90px">
<el-form-item label="客服标题">
<el-input class="w-[400px]" v-model="content.title" />
</el-form-item>
<el-form-item label="服务时间">
<el-input class="w-[400px]" v-model="content.time" />
</el-form-item>
<el-form-item label="联系电话">
<el-input class="w-[400px]" v-model="content.mobile" />
</el-form-item>
<el-form-item label="客服二维码">
<div>
<upload-img v-model:imageUrl="content.qrcode" />
<div class="form-tips">建议图片尺寸200*200像素图片格式jpgpngjpeg</div>
</div>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,35 +0,0 @@
<template>
<div class="customer-service">
<decoration-img width="140px" height="140px" :src="content.qrcode" alt="" />
<div class="text-[15px] mt-[7px] font-medium">{{ content.title }}</div>
<div class="text-[#666] mt-[20px]">服务时间{{ content.time }}</div>
<div class="text-[#666] mt-[7px]">客服电话{{ content.mobile }}</div>
<div class="text-white text-[16px] rounded-[42px] bg-[#4173FF] w-full h-[42px] flex justify-center items-center mt-[50px]">保存二维码图片</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import DecorationImg from '../../decoration-img.vue';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped>
.customer-service {
margin: 10px 18px;
border-radius: 10px;
padding: 50px 55px 80px;
background: #fff;
@apply flex flex-col justify-center items-center;
}
</style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,11 +0,0 @@
export default () => ({
title: '客服设置',
name: 'customer-service',
content: {
title: '添加客服二维码',
time: '',
mobile: '',
qrcode: '',
},
styles: {},
});

View File

@ -1,13 +0,0 @@
const widgets: Record<string, any> = import.meta.glob('./**/index.ts', { eager: true });
interface Widget {
attr: any;
content: any;
options: any;
}
const exportWidgets: Record<string, Widget> = {};
Object.keys(widgets).forEach((key) => {
const widgetName = key.replace(/^\.\/([\w-]+).*/gi, '$1');
exportWidgets[widgetName] = widgets[key]?.default;
});
export default exportWidgets;

View File

@ -1,40 +0,0 @@
<template>
<div>
<el-scrollbar style="height: 700px">
<el-form label-width="70px">
<el-form-item label="排版样式">
<el-radio-group v-model="content.style">
<el-radio :label="1">横排</el-radio>
<el-radio :label="2">竖排</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="标题名称">
<el-input class="!w-[400px]" v-model="content.title" />
</el-form-item>
<el-form-item label="菜单设置">
<div class="flex-1">
<AddNav v-model="content.data" />
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import AddNav from '../../add-nav.vue';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,51 +0,0 @@
<template>
<div class="my-service">
<div v-if="content.title" class="title px-[15px] py-[10px]">
<div>{{ content.title }}</div>
</div>
<div v-if="content.style == 1" class="flex flex-wrap pt-[20px] pb-[10px]">
<div v-for="(item, index) in content.data" :key="index" class="flex flex-col items-center w-1/4 mb-[15px]">
<decoration-img width="26px" height="26px" :src="item.image" alt="" />
<div class="mt-[7px]">{{ item.name }}</div>
</div>
</div>
<div v-if="content.style == 2">
<div v-for="(item, index) in content.data" :key="index" class="flex items-center border-b border-[#e5e5e5] h-[50px] px-[12px]">
<decoration-img width="24px" height="24px" :src="item.image" alt="" />
<div class="ml-[10px] flex-1">{{ item.name }}</div>
<div>
<el-icon><ArrowRight /></el-icon>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import DecorationImg from '../../decoration-img.vue';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped>
.my-service {
margin: 10px 10px 0;
background-color: #fff;
border-radius: 7px;
.title {
border-bottom: 1px solid #e5e5e5;
font-size: 16px;
font-weight: 500;
}
}
</style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,16 +0,0 @@
export default () => ({
title: '我的服务',
name: 'my-service',
content: {
style: 1,
title: '我的服务',
data: [
{
image: '',
name: '导航名称',
link: {},
},
],
},
styles: {},
});

View File

@ -1,40 +0,0 @@
<template>
<div>
<el-scrollbar style="height: 700px">
<el-form label-width="70px">
<el-form-item label="是否启用">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单设置">
<div class="flex-1">
<div class="mb-4 form-tips">最多可添加10个建议图片尺寸100px*100px</div>
<el-scrollbar style="height: 500px">
<AddNav v-model="content.data" />
</el-scrollbar>
</div>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import AddNav from '../../add-nav.vue';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,28 +0,0 @@
<template>
<div class="nav bg-white pt-[15px] pb-[8px]">
<div class="flex flex-wrap">
<div v-for="(item, index) in content.data" :key="index" class="flex flex-col items-center w-1/5 mb-[15px]">
<decoration-img width="41px" height="41px" :src="item.image" alt="" />
<div class="mt-[7px]">{{ item.name }}</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import DecorationImg from '../../decoration-img.vue';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,15 +0,0 @@
export default () => ({
title: '导航菜单',
name: 'nav',
content: {
enabled: 1,
data: [
{
image: '',
name: '导航名称',
link: {},
},
],
},
styles: {},
});

View File

@ -1,20 +0,0 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,62 +0,0 @@
<template>
<div class="news">
<div class="flex items-center news-title mx-[10px] my-[15px] text-[17px] font-medium">最新资讯</div>
<div v-for="item in newsList" :key="item.id" class="news-card flex bg-white px-[10px] py-[16px] text-[#333] border-[#f2f2f2] border-b">
<div class="mr-[10px]" v-if="item.image">
<img :src="item.image.includes('http') ? item.image : baseURL + item.image" class="w-[120px] h-[90px]" />
</div>
<div class="flex flex-col justify-between flex-1">
<div class="text-[15px] font-medium line-clamp-2">{{ item.title }}</div>
<div class="line-clamp-1 text-sm mt-[8px]">
{{ item.intro }}
</div>
<div class="text-[#999] text-xs w-full flex justify-between mt-[8px]">
<div>{{ item.createTime }}</div>
<div class="flex items-center">
<el-icon><View /></el-icon>
<div class="ml-[5px]">{{ item.visit }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import { fetchList } from '/@/api/app/appArticle';
import type options from './options';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
const newsList = ref<any[]>([]);
const getData = async () => {
const { data } = await fetchList();
newsList.value = data.records;
};
getData();
</script>
<style lang="scss" scoped>
.news {
.news-title {
&::before {
content: '';
width: 4px;
height: 17px;
display: block;
margin-right: 5px;
background: #4173ff;
}
}
}
</style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,7 +0,0 @@
export default () => ({
title: '资讯',
name: 'news',
disabled: 1,
content: {},
styles: {},
});

View File

@ -1,20 +0,0 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,23 +0,0 @@
<template>
<div class="search">
<div class="search-con flex items-center px-[15px]">
<el-icon><Search /></el-icon>
<span class="ml-[5px]">请输入关键词搜索</span>
</div>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.search {
background-color: #fff;
padding: 7px 12px;
.search-con {
height: 100%;
height: 36px;
border-radius: 36px;
background: #f4f4f4;
color: #999999;
}
}
</style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,7 +0,0 @@
export default () => ({
title: '搜索',
name: 'search',
disabled: 1,
content: {},
styles: {},
});

View File

@ -1,79 +0,0 @@
<template>
<div>
<el-scrollbar style="height: 550px">
<el-form label-width="70px">
<el-form-item label="是否启用">
<el-radio-group v-model="content.enabled">
<el-radio :label="1">开启</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图片设置">
<div class="flex-1">
<div class="form-tips">最多添加5张建议图片尺寸750px*200px</div>
<draggable class="draggable" v-model="content.data" item-key="index" animation="300">
<template v-slot:item="{ element: item, index }">
<del-wrap :key="index" @close="handleDelete(index)" class="max-w-[400px]">
<div class="flex items-center w-full p-4 mt-4 cursor-move bg-fill-light">
<upload-img v-model:imageUrl="item.image" />
<div class="flex-1 ml-3">
<el-form-item label="图片名称">
<el-input v-model="item.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item class="mt-[18px]" label="图片链接">
<link-picker v-model="item.link" />
</el-form-item>
</div>
</div>
</del-wrap>
</template>
</draggable>
</div>
</el-form-item>
<el-form-item v-if="content.data?.length < limit">
<el-button type="primary" @click="handleAdd">添加图片</el-button>
</el-form-item>
</el-form>
</el-scrollbar>
</div>
</template>
<script lang="ts" setup>
import { useMessage } from '/@/hooks/message';
import type { PropType } from 'vue';
import type options from './options';
import Draggable from 'vuedraggable';
const LinkPicker = defineAsyncComponent(() => import('/@/components/Link/picker.vue'));
const limit = 5;
type OptionsType = ReturnType<typeof options>;
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
const handleAdd = () => {
if (props.content.data?.length < limit) {
props.content.data.push({
image: '',
name: '',
link: {},
});
} else {
useMessage().error(`最多添加${limit}张图片`);
}
};
const handleDelete = (index: number) => {
if (props.content.data?.length <= 1) {
return useMessage().error('最少保留一张图片');
}
props.content.data.splice(index, 1);
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,32 +0,0 @@
<template>
<div class="banner mx-[10px] mt-[10px]">
<div class="banner-image">
<decoration-img width="100%" height="100px" :src="getImage" fit="contain" />
</div>
</div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
import DecorationImg from '../../decoration-img.vue';
type OptionsType = ReturnType<typeof options>;
const props = defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
const getImage = computed(() => {
const { data } = props.content;
if (Array.isArray(data)) {
return data[0] ? data[0].image : '';
}
return '';
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,15 +0,0 @@
export default () => ({
title: '个人中心广告图',
name: 'user-banner',
content: {
enabled: 1,
data: [
{
image: '',
name: '',
link: {},
},
],
},
styles: {},
});

View File

@ -1,20 +0,0 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
import type { PropType } from 'vue';
import type options from './options';
type OptionsType = ReturnType<typeof options>;
defineProps({
content: {
type: Object as PropType<OptionsType['content']>,
default: () => ({}),
},
styles: {
type: Object as PropType<OptionsType['styles']>,
default: () => ({}),
},
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,16 +0,0 @@
<template>
<div class="user-info flex items-center px-[25px]">
<img src="./images/default_avatar.png" class="w-[60px] h-[60px]" alt="" />
<div class="text-white text-[18px] ml-[10px]">未登录</div>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss" scoped>
.user-info {
background: url(./images/my_topbg.png);
height: 115px;
background-position: bottom;
background-size: 100% auto;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

View File

@ -1,8 +0,0 @@
import attr from './attr.vue';
import content from './content.vue';
import options from './options';
export default {
attr,
content,
options,
};

View File

@ -1,7 +0,0 @@
export default () => ({
title: '用户信息',
name: 'user-info',
disabled: 1,
content: {},
styles: {},
});

View File

@ -1,112 +0,0 @@
<template>
<div class="layout-padding decoration-pages min-w-[1100px]">
<el-card shadow="never" class="!border-none flex-1 flex" :body-style="{ flex: 1 }">
<div class="flex items-start h-full">
<Menu v-model="activeMenu" :menus="menus" />
<preview v-model="selectWidgetIndex" :pageData="getPageData">
<template #footer>
<div class="flex justify-center mt-4">
<el-button type="primary" @click="setData">保存</el-button>
</div>
</template>
</preview>
<attr-setting class="flex-1" :widget="getSelectWidget" />
</div>
</el-card>
</div>
</template>
<script lang="ts" setup name="decorationPages">
import Menu from './component/pages/menu.vue';
import Preview from './component/pages/preview.vue';
import AttrSetting from './component/pages/attr-setting.vue';
import widgets from './component/widgets';
import { getObj, putObj } from '/@/api/app/page';
import { useMessage } from '/@/hooks/message';
import other from '/@/utils/other';
enum pagesTypeEnum {
HOME = '1',
USER = '2',
SERVICE = '3',
}
const generatePageData = (widgetNames: string[]) => {
return widgetNames.map((widgetName) => {
const options = {
id: other.getNonDuplicateID(),
...(widgets[widgetName]?.options() || {}),
};
return options;
});
};
const menus: Record<
string,
{
id: number;
name: string;
pageData: any[];
}
> = reactive({
[pagesTypeEnum.HOME]: {
id: 1,
pageType: 1,
name: '首页装修',
pageData: generatePageData(['search', 'banner', 'nav', 'news']),
},
[pagesTypeEnum.USER]: {
id: 2,
pageType: 2,
name: '个人中心',
pageData: generatePageData(['user-info', 'my-service', 'user-banner']),
},
[pagesTypeEnum.SERVICE]: {
id: 3,
pageType: 3,
name: '客服设置',
pageData: generatePageData(['customer-service']),
},
});
const activeMenu = ref('1');
const selectWidgetIndex = ref(-1);
const getPageData = computed(() => {
return menus[activeMenu.value]?.pageData ?? [];
});
const getSelectWidget = computed(() => {
return menus[activeMenu.value]?.pageData[selectWidgetIndex.value] ?? '';
});
const getData = async () => {
const { data } = await getObj(activeMenu.value);
menus[String(data.id)].pageData = JSON.parse(data.pageData);
};
const setData = async () => {
await putObj({
...menus[activeMenu.value],
pageData: JSON.stringify(menus[activeMenu.value].pageData),
});
getData();
useMessage().success('保存成功');
};
watch(
activeMenu,
() => {
selectWidgetIndex.value = getPageData.value.findIndex((item) => !item.disabled);
getData();
},
{
immediate: true,
}
);
</script>
<style lang="scss" scoped>
.decoration-pages {
min-height: calc(100vh - var(--navbar-height) - 80px);
@apply flex flex-col;
}
.el-menu {
width: 15% !important;
}
</style>

View File

@ -1,143 +0,0 @@
<template>
<div class="layout-padding decoration-tabbar min-w-[800px]">
<el-card shadow="never" class="!border-none flex-1" :body-style="{ height: '100%' }">
<div class="flex items-start h-full">
<div class="pages-preview mx-[30px]">
<div class="flex tabbar">
<div class="flex flex-col items-center justify-center flex-1 tabbar-item" v-for="(item, index) in tabbar.list" :key="index">
<img class="w-[22px] h-[22px]" :src="item.unselected" alt="" />
<div class="leading-3 text-[12px] mt-[4px]">{{ item.name }}</div>
</div>
</div>
</div>
<div class="flex-1">
<div class="title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2">
底部导航设置
<span class="form-tips ml-[10px] !mt-0"> 至少添加2个导航最多添加5个导航 </span>
</div>
<el-form label-width="70px">
<div class="mb-[18px]">
<el-scrollbar style="height: 520px">
<draggable class="draggable" v-model="tabbar.list" animation="300" draggable=".draggable" itemKey="index" :move="onMove">
<template v-slot:item="{ element, index }">
<del-wrap @close="handleDelete(index)" class="max-w-[400px]" :class="{ draggable: index != 0 }">
<div class="w-full p-4 mt-4 bg-fill-light">
<el-form-item label="导航图标">
<upload-img v-model:imageUrl="element.unselected" height="60px" width="60px" />
<upload-img v-model:imageUrl="element.selected" height="60px" width="60px" class="ml-2" />
</el-form-item>
<el-form-item label="导航名称">
<el-input v-model="element.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="链接地址">
<link-picker v-model="element.link" :disabled="index == 0" />
</el-form-item>
</div>
</del-wrap>
</template>
</draggable>
</el-scrollbar>
</div>
<el-form-item v-if="tabbar.list?.length < max" label-width="0">
<el-button type="primary" @click="setData">保存导航</el-button>
<el-button type="primary" @click="handleAdd"> 添加导航 </el-button>
</el-form-item>
</el-form>
</div>
</div>
</el-card>
</div>
</template>
<script lang="ts" setup name="decorationTabbar">
import { fetchList, putObj } from '/@/api/app/tabbar';
import Draggable from 'vuedraggable';
import { useMessage } from '/@/hooks/message';
const LinkPicker = defineAsyncComponent(() => import('/@/components/Link/picker.vue'));
const max = 5;
const min = 2;
const tabbar = reactive({
list: [
{
name: '',
selected: '',
unselected: '',
link: {},
},
{
name: '',
selected: '',
unselected: '',
link: {},
},
],
});
const handleAdd = () => {
if (tabbar.list?.length < max) {
tabbar.list.push({
name: '',
selected: '',
unselected: '',
link: {},
});
} else {
useMessage().error(`最多添加${max}`);
}
};
const handleDelete = (index: number) => {
if (tabbar.list?.length <= min) {
return useMessage().error(`最少保留${min}`);
}
tabbar.list.splice(index, 1);
};
const onMove = (e: any) => {
if (e.relatedContext.index == 0) {
return false;
}
return true;
};
const getData = async () => {
const { data } = await fetchList();
tabbar.list = data;
};
const setData = async () => {
const data = toRaw(tabbar.list).map((item) => {
return {
id: item.id,
name: item.name,
selected: item.selected,
unselected: item.unselected,
link: JSON.stringify(item.link), // link
};
});
await putObj(data);
getData();
useMessage().success('保存成功');
};
getData();
</script>
<style lang="scss" scoped>
.decoration-tabbar {
min-height: calc(100vh - var(--navbar-height) - 80px);
@apply flex flex-col;
.pages-preview {
background-color: #f7f7f7;
width: 360px;
height: 600px;
color: #333;
position: relative;
.tabbar {
position: absolute;
height: 50px;
background-color: #fff;
bottom: 0;
width: 100%;
border: 2px solid var(--el-color-primary);
}
}
}
</style>

View File

@ -1,40 +0,0 @@
<template>
<div class="layout-padding">
<el-scrollbar class="main">
<iframe :src="src" class="iframe" v-if="isMicro === 'true'" />
<span v-else>单体架构暂不支持报表设计器</span>
</el-scrollbar>
</div>
</template>
<script lang="ts" name="modelView" setup>
import { Session } from '/@/utils/storage';
const { proxy } = getCurrentInstance();
const route = useRoute();
const src = ref('');
const isMicro = import.meta.env.VITE_IS_MICRO;
watch([route], () => {
init();
});
onMounted(() => {
init();
});
const init = () => {
const token = Session.getToken();
const tenantId = Session.getTenant();
src.value = proxy.baseURL + `/jimu/jmreport/list?token=${tenantId}_${token}`;
};
</script>
<style lang="scss" scoped>
.iframe {
width: 100%;
height: 80vh;
border: 0;
overflow: hidden;
box-sizing: border-box;
}
</style>

View File

@ -1,38 +0,0 @@
<template>
<div class="layout-padding">
<iframe :src="src" class="iframe" v-if="isMicro === 'true'" />
<span v-else>单体架构暂不支持大屏设计器</span>
</div>
</template>
<script lang="ts" name="modelView" setup>
import { Session } from '/@/utils/storage';
const { proxy } = getCurrentInstance();
const route = useRoute();
const src = ref('');
const isMicro = import.meta.env.VITE_IS_MICRO;
watch([route], () => {
init();
});
onMounted(() => {
init();
});
const init = () => {
const token = Session.getToken();
const tenantId = Session.getTenant();
src.value = proxy.baseURL + `/gv?token=${token}&TENANT-ID=${tenantId}`;
};
</script>
<style lang="scss" scoped>
.iframe {
width: 100%;
height: 80vh;
border: 0;
overflow: hidden;
box-sizing: border-box;
}
</style>

View File

@ -1,75 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-alert title="路由配置是非常专业的事情,不建议非工程师操作" type="warning" />
<el-scrollbar class="mt10">
<vue-jsoneditor mode="table" :queryLanguagesIds="queryLanguages" v-model:json="jsonData" v-if="show" v-loading="loading" />
<div align="center" class="copy_btn">
<el-button type="primary" @click="edit()" :disabled="loading">更新</el-button>
</div>
<div align="center">
<el-button type="primary" @click="edit()" :disabled="loading">更新</el-button>
</div>
</el-scrollbar>
</div>
</div>
</template>
<script lang="ts" name="routeConfig" setup>
import VueJsoneditor from 'vue3-ts-jsoneditor';
import { fetchList, putObj, refreshObj } from '/@/api/admin/route';
import type { QueryLanguageId } from 'vue3-ts-jsoneditor';
import { useMessage } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const jsonData = ref({});
const loading = ref(false);
const show = ref(false);
const queryLanguages = ref<QueryLanguageId[]>(['javascript', 'lodash', 'jmespath']);
const edit = async () => {
loading.value = true;
try {
await putObj(jsonData.value);
await refreshObj();
useMessage().success(t('common.optSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
onMounted(() => {
fetchList().then((response) => {
const result = response.data;
for (var i = 0; i < result.length; i++) {
const route = result[i];
if (route.predicates) {
const predicates = route.predicates;
route.predicates = JSON.parse(predicates);
}
if (route.filters) {
const filters = route.filters;
route.filters = JSON.parse(filters);
}
}
jsonData.value = result;
// jsoneditor #I7890E
show.value = true;
});
});
</script>
<style lang="scss" scoped>
.copy_btn {
position: absolute;
top: 60px;
right: 20px;
z-index: 9;
color: rgb(255, 255, 255);
}
</style>

View File

@ -1,149 +0,0 @@
<template>
<el-dialog v-model="visible" :close-on-click-modal="false" :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" draggable>
<el-form ref="dataFormRef" v-loading="loading" :model="form" :rules="dataRules" label-width="90px">
<el-row :gutter="24">
<el-col :span="12" class="mb20">
<el-form-item :label="t('fans.wxAccountName')" prop="wxAccountName">
<el-input v-model="form.wxAccountName" disabled />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fans.wxAccountAppid')" prop="wxAccountAppid">
<el-input v-model="form.wxAccountAppid" disabled />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fans.openid')" prop="openid">
<el-input v-model="form.openid" disabled />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fans.nickname')" prop="nickname">
<el-input v-model="form.nickname" disabled />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fans.remark')" prop="remark">
<el-input v-model="form.remark" :placeholder="t('fans.inputremarkTip')" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('fans.tagIds')" prop="tagIds">
<el-select v-model="form.tagIds" :placeholder="t('fans.inputTagTip')" class="w100" clearable multiple>
<el-option v-for="item in tagOption" :key="item.tagId" :label="item.tag" :value="item.tagId" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" name="wx-fans" setup>
import { addObj, getObj, putObj } from '/@/api/mp/wx-account-fans';
import { list } from '/@/api/mp/wx-account-tag';
import { useMessage } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const emit = defineEmits(['refresh']);
//
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
const wxAccountAppid = ref();
//
const form = reactive({
id: '',
});
const dataRules = ref([]);
//
const openDialog = (row: any, accountId: string) => {
visible.value = true;
form.id = row.id;
wxAccountAppid.value = accountId;
//
if (dataFormRef.value) {
dataFormRef.value.resetFields();
}
if (form.id) {
getFansData();
}
getTagList();
};
const getFansData = () => {
loading.value = true;
getObj(form.id)
.then((res) => {
Object.assign(form, res.data);
})
.finally(() => {
loading.value = false;
});
};
//
const onSubmit = () => {
dataFormRef.value.validate((valid: boolean) => {
if (!valid) {
return false;
}
loading.value = true;
if (form.id) {
putObj(form)
.then(() => {
useMessage().success(t('common.editSuccessText'));
visible.value = false; //
emit('refresh');
})
.catch((err: any) => {
useMessage().error(err.msg);
})
.finally(() => {
loading.value = false;
});
} else {
addObj(form)
.then(() => {
useMessage().success(t('common.addSuccessText'));
visible.value = false; //
emit('refresh');
})
.catch((err: any) => {
useMessage().error(err.msg);
})
.finally(() => {
loading.value = false;
});
}
});
};
const tagOption = ref([]);
const getTagList = () => {
list(wxAccountAppid.value).then((res) => {
tagOption.value = res.data;
});
};
//
defineExpose({
openDialog,
});
</script>
<style scoped></style>

View File

@ -1,24 +0,0 @@
export default {
fans: {
index: '#',
importwxAccountFansTip: 'import WxAccountFans',
id: 'id',
openid: 'openid',
subscribeStatus: 'subscribeStatus',
subscribeTime: 'subscribeTime',
nickname: 'nickname',
gender: 'gender',
language: 'language',
country: 'country',
province: 'province',
isBlack: 'black',
city: 'city',
tagIds: 'tagIds',
headimgUrl: 'headimgUrl',
remark: 'remark',
wxAccountId: 'wxAccountId',
wxAccountName: 'wxAccountName',
wxAccountAppid: 'wxAccountAppid',
inputNicknameTip: 'input nickname',
},
};

View File

@ -1,26 +0,0 @@
export default {
fans: {
index: '#',
importwxAccountFansTip: '导入微信公众号粉丝表',
id: '主键',
openid: '用户标识',
subscribeStatus: '订阅状态',
subscribeTime: '订阅时间',
nickname: '昵称',
gender: '性别',
language: '语言',
country: '国家',
province: '省份',
isBlack: '黑名单',
city: '城市',
tagIds: '分组',
headimgUrl: ' headimgUrl',
remark: '备注',
wxAccountId: '微信公众号ID',
wxAccountName: '微信公众号',
wxAccountAppid: '公众号appid',
inputremarkTip: '请输入备注',
inputTagTip: '请选择分组',
inputNicknameTip: '请输入粉丝昵称',
},
};

View File

@ -1,222 +0,0 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row v-show="showSearch">
<el-form ref="queryRef" :inline="true" :model="state.queryForm" @keyup.enter="getDataList">
<el-form-item :label="$t('fans.nickname')" prop="nickname">
<el-input v-model="state.queryForm.nickname" style="max-width: 180px" :placeholder="$t('fans.inputNicknameTip')" />
</el-form-item>
<el-form-item :label="$t('fans.wxAccountName')" prop="wxAccountAppid">
<el-select v-model="state.queryForm.wxAccountAppid" :placeholder="$t('fans.wxAccountName')" clearable class="w100">
<el-option v-for="item in accountList" :key="item.appid" :label="item.name" :value="item.appid" />
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="search" type="primary" @click="getDataList">
{{ $t('common.queryBtn') }}
</el-button>
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button type="primary" class="ml10" icon="Sort" @click="asyncFans" v-auth="'mp_wxaccountfans_sync'">同步</el-button>
<right-toolbar
:export="'mp_wxaccountfans_sync'"
@exportExcel="exportExcel"
v-model:showSearch="showSearch"
class="ml10"
style="float: right; margin-right: 20px"
@queryTable="getDataList"
></right-toolbar>
</div>
</el-row>
<el-table
v-loading="state.loading"
:data="state.dataList"
style="width: 100%"
@sort-change="sortChangeHandle"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column :label="t('fans.index')" type="index" width="60" />
<el-table-column :label="t('fans.openid')" prop="openid" show-overflow-tooltip />
<el-table-column :label="t('fans.subscribeStatus')" prop="subscribeStatus" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="subscribe" :value="scope.row.subscribeStatus"></dict-tag>
</template>
</el-table-column>
<el-table-column :label="t('fans.subscribeTime')" prop="subscribeTime" show-overflow-tooltip />
<el-table-column :label="t('fans.nickname')" prop="nickname" show-overflow-tooltip />
<el-table-column :label="t('fans.language')" prop="language" show-overflow-tooltip />
<el-table-column :label="t('fans.isBlack')" prop="isBlack" show-overflow-tooltip>
<template #default="scope">
<dict-tag :options="blackList" :value="scope.row.isBlack"></dict-tag>
</template>
</el-table-column>
<el-table-column :label="t('fans.tagIds')" prop="tagIds" show-overflow-tooltip>
<template #default="scope">
<span v-for="(tag, index) in scope.row.tagList" :key="index">
<el-tag>{{ tag.tag }} </el-tag>&nbsp;&nbsp;
</span>
</template>
</el-table-column>
<el-table-column :label="t('fans.remark')" prop="remark" show-overflow-tooltip />
<el-table-column :label="t('fans.wxAccountName')" prop="wxAccountName" show-overflow-tooltip />
<el-table-column :label="$t('common.action')" width="250" fixed="right">
<template #default="scope">
<el-button icon="edit-pen" text type="primary" @click="formDialogRef.openDialog(scope.row, state.queryForm.wxAccountAppid)"
>{{ $t('common.editBtn') }}
</el-button>
<el-button icon="delete" text type="primary" @click="handleDelete([scope.row.id])">{{ $t('common.delBtn') }} </el-button>
<el-button icon="CircleCheck" text type="primary" @click="handelUnBlack([scope.row.id])" v-if="scope.row.isBlack"> 取消拉黑 </el-button>
<el-button icon="warning" text type="primary" @click="handelBlack([scope.row.id])" v-else> 拉黑 </el-button>
</template>
</el-table-column>
</el-table>
<pagination v-bind="state.pagination" @size-change="sizeChangeHandle" @current-change="currentChangeHandle" />
<form-dialog ref="formDialogRef" @refresh="getDataList"></form-dialog>
</div>
</div>
</template>
<script lang="ts" name="systemWxAccountFans" setup>
import { BasicTableProps, useTable } from '/@/hooks/table';
import { black, delObjs, fetchList, sync, unblack } from '/@/api/mp/wx-account-fans';
import { fetchAccountList } from '/@/api/mp/wx-account';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
import { useDict } from '/@/hooks/dict';
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
const { subscribe } = useDict('subscribe');
//
const { t } = useI18n();
//
const blackList = ref([
{
label: '是',
value: '1',
},
{
label: '否',
value: '0',
},
]);
//
const formDialogRef = ref();
//
const queryRef = ref();
const showSearch = ref(true);
//
const selectObjs = ref([]) as any;
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
createdIsNeed: false,
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
const accountList = ref([]);
const getAccountList = () => {
fetchAccountList().then((res) => {
accountList.value = res.data;
if (accountList.value.length > 0) {
state.queryForm.wxAccountAppid = accountList.value[0].appid;
getDataList();
}
});
};
watch(
() => state.queryForm.wxAccountAppid,
() => {
getDataList();
}
);
const asyncFans = () => {
if (state.queryForm.wxAccountAppid) {
sync(state.queryForm.wxAccountAppid).then(() => {
useMessage().success('已开始从微信同步粉丝信息,建议等待后查询');
getDataList();
});
} else {
useMessage().error('请选择公众号');
}
};
onMounted(() => {
getAccountList();
});
//
const resetQuery = () => {
//
queryRef.value.resetFields();
//
selectObjs.value = [];
getDataList();
};
// excel
const exportExcel = () => {
downBlobFile('/mp/fans/export', state.queryForm, 'fans.xlsx');
};
//
const handleDelete = (ids: string[]) => {
useMessageBox()
.confirm(t('common.delConfirmText'))
.then(() => {
delObjs(ids)
.then(() => {
getDataList();
useMessage().success(t('common.delSuccessText'));
})
.catch((err: any) => {
useMessage().error(err.msg);
});
});
};
const handelBlack = (ids: string[]) => {
useMessageBox()
.confirm('是否要拉黑用户')
.then(() => {
black(ids, state.queryForm.wxAccountAppid)
.then(() => {
getDataList();
useMessage().success('拉黑用户成功');
})
.catch((err: any) => {
useMessage().error(err.msg);
});
});
};
const handelUnBlack = (ids: string[]) => {
useMessageBox()
.confirm('是否要取消拉黑用户')
.then(() => {
unblack(ids, state.queryForm.wxAccountAppid)
.then(() => {
getDataList();
useMessage().success('设置成功');
})
.catch((err: any) => {
useMessage().error(err.msg);
});
});
};
</script>

View File

@ -1,91 +0,0 @@
<template>
<el-dialog v-model="visible" :close-on-click-modal="false" :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" draggable>
<el-form ref="dataFormRef" v-loading="loading" :model="form" :rules="dataRules" label-width="90px">
<el-row :gutter="24">
<el-col :span="24" class="mb20">
<el-form-item :label="t('wxAccountTag.tag')" prop="tag">
<el-input v-model="form.tag" :placeholder="t('wxAccountTag.inputTagTip')" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" name="WxAccountTagDialog" setup>
import { useMessage } from '/@/hooks/message';
import { addObj, putObj } from '/@/api/mp/wx-account-tag';
import { useI18n } from 'vue-i18n';
// /
const emit = defineEmits(['refresh']);
const { t } = useI18n();
//
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
//
//
const form = reactive({
wxAccountAppid: '',
tag: '',
id: '',
});
//
const dataRules = ref({});
//
const openDialog = (row: any, appid: string) => {
visible.value = true;
form.wxAccountAppid = '';
form.tag = '';
form.id = '';
//
if (dataFormRef.value) {
dataFormRef.value.resetFields();
}
if (row) {
Object.assign(form, row);
}
form.wxAccountAppid = appid;
};
//
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) return false;
loading.value = true;
try {
if (form.id) {
await putObj(form);
useMessage().success(t('common.editSuccessText'));
} else {
await addObj(form);
useMessage().success(t('common.addSuccessText'));
}
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
//
defineExpose({
openDialog,
});
</script>

View File

@ -1,18 +0,0 @@
export default {
wxAccountTag: {
index: '#',
importwxAccountTagTip: 'import WxAccountTag',
id: 'id',
tag: 'tag',
wxAccountId: 'wxAccountId',
wxAccountName: 'wxAccountName',
wxAccountAppid: 'wxAccountAppid',
tagId: 'tagId',
inputIdTip: 'input id',
inputTagTip: 'input tag',
inputWxAccountIdTip: 'input wxAccountId',
inputWxAccountNameTip: 'input wxAccountName',
inputWxAccountAppidTip: 'input wxAccountAppid',
inputTagIdTip: 'input tagId',
},
};

View File

@ -1,18 +0,0 @@
export default {
wxAccountTag: {
index: '#',
importwxAccountTagTip: '导入标签管理',
id: '主键',
tag: '标签',
wxAccountId: '微信账号ID',
wxAccountName: '微信账号名称',
wxAccountAppid: 'appID',
tagId: '标签ID',
inputIdTip: '请输入主键',
inputTagTip: '请输入标签',
inputWxAccountIdTip: '请输入微信账号ID',
inputWxAccountNameTip: '请输入微信账号名称',
inputWxAccountAppidTip: '请输入appID',
inputTagIdTip: '请输入标签ID',
},
};

Some files were not shown because too many files have changed in this diff Show More