mirror of
https://gitee.com/log4j/pig-ui.git
synced 2024-12-22 12:58:55 +08:00
🔥 删除无用文件
This commit is contained in:
parent
bdac045aec
commit
2bb9142e22
@ -1,9 +1,9 @@
|
||||
FROM nginx
|
||||
FROM nginx
|
||||
|
||||
COPY ./dist /data
|
||||
COPY ./dist /data
|
||||
|
||||
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'
|
||||
|
@ -4,16 +4,16 @@ services:
|
||||
build:
|
||||
context: .
|
||||
restart: always
|
||||
container_name: pigx-ui
|
||||
image: pigx-ui
|
||||
container_name: pig-ui
|
||||
image: pig-ui
|
||||
networks:
|
||||
- pigx_default
|
||||
- pig_default
|
||||
external_links:
|
||||
- pigx-gateway
|
||||
- pig-gateway
|
||||
ports:
|
||||
- 80:80
|
||||
|
||||
# 加入到后端网络, 默认为 pigx_default | docker network ls 查看
|
||||
# 加入到后端网络, 默认为 pig_default | docker network ls 查看
|
||||
networks:
|
||||
pigx_default:
|
||||
external: true
|
||||
pig_default:
|
||||
external: true
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "pigx-ui",
|
||||
"version": "5.1.0",
|
||||
"name": "pig-ui",
|
||||
"version": "3.7.0",
|
||||
"description": "PIGCLOUD微服务开发平台",
|
||||
"author": "pig4cloud",
|
||||
"license": "不对外分发 pig4cloud 版权所有,请购买商业版权",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"dev": "vite --force",
|
||||
"build": "vite build",
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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 },
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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',
|
||||
});
|
||||
}
|
@ -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',
|
||||
});
|
||||
}
|
@ -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',
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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',
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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 },
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
@ -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>
|
@ -1,6 +0,0 @@
|
||||
export default {
|
||||
article: {
|
||||
edit: 'edit article',
|
||||
add: 'add article',
|
||||
},
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
export default {
|
||||
article: {
|
||||
edit: '编辑文章',
|
||||
add: '发布文章',
|
||||
},
|
||||
};
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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',
|
||||
},
|
||||
};
|
@ -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: '请输入角色描述',
|
||||
},
|
||||
};
|
@ -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>
|
@ -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>
|
@ -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',
|
||||
},
|
||||
};
|
@ -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: '请输入所属租户',
|
||||
},
|
||||
};
|
@ -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>
|
@ -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>
|
@ -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',
|
||||
},
|
||||
};
|
@ -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: '导入用户',
|
||||
},
|
||||
};
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
export default () => ({
|
||||
title: '首页轮播图',
|
||||
name: 'banner',
|
||||
content: {
|
||||
enabled: 1,
|
||||
data: [
|
||||
{
|
||||
image: '',
|
||||
name: '',
|
||||
link: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
@ -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像素;图片格式:jpg、png、jpeg</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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
export default () => ({
|
||||
title: '客服设置',
|
||||
name: 'customer-service',
|
||||
content: {
|
||||
title: '添加客服二维码',
|
||||
time: '',
|
||||
mobile: '',
|
||||
qrcode: '',
|
||||
},
|
||||
styles: {},
|
||||
});
|
@ -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;
|
@ -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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,16 +0,0 @@
|
||||
export default () => ({
|
||||
title: '我的服务',
|
||||
name: 'my-service',
|
||||
content: {
|
||||
style: 1,
|
||||
title: '我的服务',
|
||||
data: [
|
||||
{
|
||||
image: '',
|
||||
name: '导航名称',
|
||||
link: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
@ -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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
export default () => ({
|
||||
title: '导航菜单',
|
||||
name: 'nav',
|
||||
content: {
|
||||
enabled: 1,
|
||||
data: [
|
||||
{
|
||||
image: '',
|
||||
name: '导航名称',
|
||||
link: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
@ -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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
export default () => ({
|
||||
title: '资讯',
|
||||
name: 'news',
|
||||
disabled: 1,
|
||||
content: {},
|
||||
styles: {},
|
||||
});
|
@ -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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
export default () => ({
|
||||
title: '搜索',
|
||||
name: 'search',
|
||||
disabled: 1,
|
||||
content: {},
|
||||
styles: {},
|
||||
});
|
@ -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>
|
@ -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>
|
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
export default () => ({
|
||||
title: '个人中心广告图',
|
||||
name: 'user-banner',
|
||||
content: {
|
||||
enabled: 1,
|
||||
data: [
|
||||
{
|
||||
image: '',
|
||||
name: '',
|
||||
link: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
styles: {},
|
||||
});
|
@ -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>
|
@ -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 |
@ -1,8 +0,0 @@
|
||||
import attr from './attr.vue';
|
||||
import content from './content.vue';
|
||||
import options from './options';
|
||||
export default {
|
||||
attr,
|
||||
content,
|
||||
options,
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
export default () => ({
|
||||
title: '用户信息',
|
||||
name: 'user-info',
|
||||
disabled: 1,
|
||||
content: {},
|
||||
styles: {},
|
||||
});
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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',
|
||||
},
|
||||
};
|
@ -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: '请输入粉丝昵称',
|
||||
},
|
||||
};
|
@ -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>
|
||||
</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>
|
@ -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>
|
@ -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',
|
||||
},
|
||||
};
|
@ -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
Loading…
Reference in New Issue
Block a user