【合并v3.8.2最新版代码】
Squashed commit of the following: commitf30a8c658aAuthor: JEECG <445654970@qq.com> Date: Thu Jul 31 11:35:16 2025 +0800 数据库缺少openapi微服务网关配置 commite84d7726d2Author: JEECG <445654970@qq.com> Date: Thu Jul 31 10:20:09 2025 +0800 后台接口地址修改 commit0f39802698Author: JEECG <445654970@qq.com> Date: Thu Jul 31 09:56:24 2025 +0800 docker自动化部署命令 commita014a3ed0eAuthor: JEECG <445654970@qq.com> Date: Wed Jul 30 21:55:16 2025 +0800 v3.8.2 优化一键docker启动前后端 commit5720d1a01eAuthor: JEECG <445654970@qq.com> Date: Wed Jul 30 19:26:38 2025 +0800 升级版本号到3.8.2 commit5eed6ac6d2Author: JEECG <445654970@qq.com> Date: Wed Jul 30 18:49:29 2025 +0800 升级版本号到3.8.2 commit0cfa1e223aAuthor: JEECG <445654970@qq.com> Date: Wed Jul 30 18:28:10 2025 +0800 v3.8.2 系统通知改造支持分类 commit219869f4c0Author: JEECG <445654970@qq.com> Date: Wed Jul 30 18:25:58 2025 +0800 v3.8.2 版本前端代码 commite6edde963aAuthor: JEECG <445654970@qq.com> Date: Wed Jul 30 18:25:46 2025 +0800 v3.8.2 版本后端代码 commitc44b66128eAuthor: JEECG <445654970@qq.com> Date: Wed Jul 30 18:23:09 2025 +0800 XXL-JOB(2.4.0 及以上)已被移除,分片参数获取方式变更。 commit9356b04741Author: JEECG <445654970@qq.com> Date: Wed Jul 30 10:57:52 2025 +0800 升级online到3.8.2-beta commitd0a094f9a3Author: JEECG <445654970@qq.com> Date: Wed Jul 30 10:57:31 2025 +0800 升级mybatis-plus到3.5.12、升级jsqlparser到4.9 commit73eb625737Author: JEECG <445654970@qq.com> Date: Wed Jul 30 09:51:34 2025 +0800 升级jimureport到v2.1.1 commit74880705b8Author: JEECG <445654970@qq.com> Date: Wed Jul 30 09:18:46 2025 +0800 升级online到3.8.2-beta # Conflicts: # jeecg-boot/jeecg-boot-base-core/pom.xml # jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/Swagger3Config.java # jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/java/org/jeecg/JeecgSystemApplication.java # jeecg-boot/jeecg-server-cloud/jeecg-visual/jeecg-cloud-sentinel/pom.xml # jeecg-boot/pom.xml
34
jeecgboot-vue3/.env.docker
Normal file
@ -0,0 +1,34 @@
|
||||
# 是否启用mock
|
||||
VITE_USE_MOCK = false
|
||||
|
||||
# 发布路径
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# 是否启用gzip或brotli压缩
|
||||
# 选项值: gzip | brotli | none
|
||||
# 如果需要多个可以使用“,”分隔
|
||||
VITE_BUILD_COMPRESS = 'gzip'
|
||||
|
||||
# 使用压缩时是否删除原始文件,默认为false
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
|
||||
#后台接口父地址(必填)
|
||||
VITE_GLOB_API_URL=/jeecgboot
|
||||
|
||||
#后台接口全路径地址(必填)
|
||||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot
|
||||
|
||||
# 接口父路径前缀
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
|
||||
# 填写后将作为乾坤子应用启动,主应用注册时AppName需保持一致(放开 VITE_GLOB_QIANKUN_MICRO_APP_NAME 参数表示jeecg-vue3将以乾坤子应用模式启动)
|
||||
#VITE_GLOB_QIANKUN_MICRO_APP_NAME=jeecg-vue3
|
||||
# 作为乾坤子应用启动时必填,需与qiankun主应用注册子应用时填写的 entry 保持一致
|
||||
#VITE_GLOB_QIANKUN_MICRO_APP_ENTRY=//qiankun.boot3.jeecg.com/jeecg-vue3
|
||||
|
||||
# 全局隐藏哪些布局。可选属性:sider,header,multi-tabs;多个用逗号隔开
|
||||
#VITE_GLOB_HIDE_LAYOUT_TYPES=sider,header,multi-tabs
|
||||
|
||||
# 在线文档编辑版本。可选属性:wps, offlineWps(离线版), onlyoffice
|
||||
VITE_GLOB_ONLINE_DOCUMENT_VERSION=wps
|
||||
34
jeecgboot-vue3/.env.dockercloud
Normal file
@ -0,0 +1,34 @@
|
||||
# 是否启用mock
|
||||
VITE_USE_MOCK = false
|
||||
|
||||
# 发布路径
|
||||
VITE_PUBLIC_PATH = /
|
||||
|
||||
# 是否启用gzip或brotli压缩
|
||||
# 选项值: gzip | brotli | none
|
||||
# 如果需要多个可以使用“,”分隔
|
||||
VITE_BUILD_COMPRESS = 'gzip'
|
||||
|
||||
# 使用压缩时是否删除原始文件,默认为false
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
|
||||
#后台接口父地址(必填)
|
||||
VITE_GLOB_API_URL=/jeecgboot
|
||||
|
||||
#后台接口全路径地址(必填)
|
||||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-gateway:9999
|
||||
|
||||
# 接口父路径前缀
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
|
||||
# 填写后将作为乾坤子应用启动,主应用注册时AppName需保持一致(放开 VITE_GLOB_QIANKUN_MICRO_APP_NAME 参数表示jeecg-vue3将以乾坤子应用模式启动)
|
||||
#VITE_GLOB_QIANKUN_MICRO_APP_NAME=jeecg-vue3
|
||||
# 作为乾坤子应用启动时必填,需与qiankun主应用注册子应用时填写的 entry 保持一致
|
||||
#VITE_GLOB_QIANKUN_MICRO_APP_ENTRY=//qiankun.boot3.jeecg.com/jeecg-vue3
|
||||
|
||||
# 全局隐藏哪些布局。可选属性:sider,header,multi-tabs;多个用逗号隔开
|
||||
#VITE_GLOB_HIDE_LAYOUT_TYPES=sider,header,multi-tabs
|
||||
|
||||
# 在线文档编辑版本。可选属性:wps, offlineWps(离线版), onlyoffice
|
||||
VITE_GLOB_ONLINE_DOCUMENT_VERSION=wps
|
||||
@ -16,7 +16,7 @@ VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
|
||||
VITE_GLOB_API_URL=/jeecgboot
|
||||
|
||||
#后台接口全路径地址(必填)
|
||||
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot
|
||||
VITE_GLOB_DOMAIN_URL=http://127.0.0.1:8080/jeecg-boot
|
||||
|
||||
# 接口父路径前缀
|
||||
VITE_GLOB_API_URL_PREFIX=
|
||||
|
||||
30
jeecgboot-vue3/Dockerfile.cloud
Normal file
@ -0,0 +1,30 @@
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/dockerhub_mirror/nginx
|
||||
MAINTAINER jeecgos@163.com
|
||||
VOLUME /tmp
|
||||
ENV LANG en_US.UTF-8
|
||||
RUN echo "server { \
|
||||
listen 80; \
|
||||
location /jeecgboot/ { \
|
||||
proxy_pass http://jeecg-boot-gateway:9999/; \
|
||||
proxy_redirect off; \
|
||||
proxy_set_header Host jeecg-boot-system; \
|
||||
proxy_set_header X-Real-IP \$remote_addr; \
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; \
|
||||
} \
|
||||
#解决Router(mode: 'history')模式下,刷新路由地址不能找到页面的问题 \
|
||||
location / { \
|
||||
root /var/www/html/; \
|
||||
index index.html index.htm; \
|
||||
if (!-e \$request_filename) { \
|
||||
rewrite ^(.*)\$ /index.html?s=\$1 last; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
access_log /var/log/nginx/access.log ; \
|
||||
} " > /etc/nginx/conf.d/default.conf \
|
||||
&& mkdir -p /var/www \
|
||||
&& mkdir -p /var/www/html
|
||||
|
||||
ADD dist/ /var/www/html/
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
@ -22,7 +22,7 @@ SOFTWARE.
|
||||
|
||||
In any case, you must not make any such use of this software as to develop software which may be considered competitive with this software.
|
||||
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
JeecgBoot 是由 北京国炬信息技术有限公司 发行的软件。 总部位于北京,地址:中国·北京·朝阳区科荟前街1号院奥林佳泰大厦。邮箱:jeecgos@163.com
|
||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||
|
||||
开源协议中文释意如下:
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
JeecgBoot 企业级低代码开发平台
|
||||
===============
|
||||
当前最新版本: 3.8.1(预计发布时间:2025-04-21)
|
||||
当前最新版本: 3.8.2(预计发布时间:2025-08-04)
|
||||
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||
[](http://jeecg.com/aboutusIndex)
|
||||
[](https://github.com
|
||||
[](https://github.com
|
||||
/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"electron:build-all": "npm run electron:build-web && npm run electron:build-app",
|
||||
"electron:build-web": "cross-env VITE_GLOB_RUN_PLATFORM=electron NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 vite build --mode prod_electron && cross-env VITE_GLOB_RUN_PLATFORM=electron esno ./build/script/postBuild.ts && esno ./build/script/copyChat.ts",
|
||||
"electron:build-app": "esno ./electron/script/buildBefore.ts && electron-builder && esno ./electron/script/buildAfter.ts",
|
||||
"electron:install": "cross-env ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ node node_modules/electron/install.js",
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "35.1.4",
|
||||
@ -23,9 +24,9 @@
|
||||
"vite-plugin-electron": "^0.29.0",
|
||||
},
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
> 提示:在执行`pnpm install`后如果Electron安装失败,可以尝试运行`npm run electron:install`进行安装
|
||||
|
||||
# Electron桌面通知示例和代码位置
|
||||
|
||||
|
||||
BIN
jeecgboot-vue3/electron/icons/mac/dock.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
jeecgboot-vue3/electron/icons/mac/tray-icon.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
jeecgboot-vue3/electron/icons/mac/tray-icon@2x.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
@ -1,4 +1,43 @@
|
||||
import {ipcMain} from 'electron'
|
||||
import {openInBrowser} from "../utils";
|
||||
import { Tray, ipcMain, BrowserWindow, app, Notification } from 'electron';
|
||||
import type { NotificationConstructorOptions, IpcMainInvokeEvent } from 'electron';
|
||||
import { openInBrowser } from '../utils';
|
||||
import { omit } from 'lodash-es';
|
||||
|
||||
ipcMain.on('open-in-browser', (event, url) => openInBrowser(url));
|
||||
ipcMain.on('open-in-browser', (event: IpcMainInvokeEvent, url: string) => openInBrowser(url));
|
||||
// 处理任务栏闪烁
|
||||
ipcMain.on('notify-flash', (event: IpcMainInvokeEvent, count: number = 0) => {
|
||||
const win = BrowserWindow.getAllWindows()[0];
|
||||
if (!win) return;
|
||||
if (win.isFocused()) return;
|
||||
if (process.platform === 'win32') {
|
||||
// windows
|
||||
win.flashFrame(true);
|
||||
} else if (process.platform === 'darwin') {
|
||||
// Mac
|
||||
if (app.dock) {
|
||||
app.dock.bounce('informational');
|
||||
// 设置角标(未读消息)
|
||||
if (count > 0) {
|
||||
app.dock.setBadge(count.toString());
|
||||
} else {
|
||||
app.dock.setBadge('');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// 通知 (点击通知打开指定页面)
|
||||
ipcMain.on('notify-with-path', (event: IpcMainInvokeEvent, options: NotificationConstructorOptions & { path: string }) => {
|
||||
const win = BrowserWindow.getAllWindows()[0];
|
||||
if (!win) return;
|
||||
if (win.isFocused()) return;
|
||||
const notification = new Notification({
|
||||
...omit(options, 'path'),
|
||||
});
|
||||
notification.on('click', () => {
|
||||
if (win.isMinimized()) win.restore();
|
||||
win.show();
|
||||
win.focus();
|
||||
// win.webContents.send('navigate-to', options.path);
|
||||
});
|
||||
notification.show();
|
||||
});
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import './ipc';
|
||||
|
||||
import { app, BrowserWindow, Menu } from 'electron';
|
||||
import { app, BrowserWindow, Menu, ipcMain } from 'electron';
|
||||
import { isDev } from './env';
|
||||
import { createMainWindow, createIndexWindow } from './utils/window';
|
||||
import { getAppInfo} from "./utils";
|
||||
import { getAppInfo } from './utils';
|
||||
import { ElectronEnum } from '../src/enums/jeecgEnum';
|
||||
import './ipc';
|
||||
|
||||
// 隐藏所有菜单
|
||||
Menu.setApplicationMenu(null);
|
||||
@ -12,6 +12,14 @@ let mainWindow: BrowserWindow | null = null;
|
||||
|
||||
function main() {
|
||||
mainWindow = createMainWindow();
|
||||
// update-begin--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
mainWindow.on('focus', () => {
|
||||
// 清除任务栏闪烁
|
||||
if (process.platform === 'win32') {
|
||||
mainWindow!.flashFrame(false);
|
||||
}
|
||||
});
|
||||
// update-end--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,20 @@
|
||||
import {contextBridge, ipcRenderer} from 'electron'
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
import { ElectronEnum } from '../../src/enums/jeecgEnum';
|
||||
|
||||
contextBridge.exposeInMainWorld('_ELECTRON_PRELOAD_UTILS_', {
|
||||
contextBridge.exposeInMainWorld(ElectronEnum.ELECTRON_API, {
|
||||
openInBrowser: (url: string) => ipcRenderer.send('open-in-browser', url),
|
||||
// 发送消息通知
|
||||
sendNotification: (title: string, body: string, path: string) => {
|
||||
ipcRenderer.send('notify-with-path', { title, body, path });
|
||||
},
|
||||
// 绑定路由跳转
|
||||
onNavigate: (cb: (path: string) => void) => {
|
||||
ipcRenderer.on('navigate-to', (_, path) => cb(path));
|
||||
},
|
||||
// 任务栏闪
|
||||
sendNotifyFlash: () => ipcRenderer.send('notify-flash'),
|
||||
// 托盘闪动
|
||||
trayFlash: () => ipcRenderer.send('tray-flash'),
|
||||
// 托盘停止闪动
|
||||
trayFlashStop: () => ipcRenderer.send('tray-flash-stop'),
|
||||
});
|
||||
|
||||
@ -1,11 +1,18 @@
|
||||
// tray = 系统托盘
|
||||
import path from 'path';
|
||||
import {Tray, Menu, app, dialog, nativeImage, BrowserWindow, Notification} from 'electron';
|
||||
import { Tray, Menu, app, dialog, nativeImage, BrowserWindow, Notification, ipcMain } from 'electron';
|
||||
import type { IpcMainInvokeEvent } from 'electron';
|
||||
import {_PATHS} from '../paths';
|
||||
import {$env, isDev} from '../env';
|
||||
|
||||
const TrayIcons = {
|
||||
normal: nativeImage.createFromPath(path.join(_PATHS.publicRoot, 'logo.png')),
|
||||
// update-begin--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
normal: nativeImage.createFromPath(
|
||||
process.platform === 'win32'
|
||||
? path.join(_PATHS.publicRoot, 'logo.png')
|
||||
: path.join(_PATHS.electronRoot, './icons/mac/tray-icon.png').replace(/[\\/]dist[\\/]/, '/')
|
||||
),
|
||||
// update-end--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
empty: nativeImage.createEmpty(),
|
||||
};
|
||||
|
||||
@ -60,7 +67,21 @@ export function useTray(tray: Tray, win: BrowserWindow) {
|
||||
}
|
||||
tray.setImage(TrayIcons.normal);
|
||||
}
|
||||
|
||||
ipcMain.on('tray-flash', (event: IpcMainInvokeEvent) => {
|
||||
// 仅在 Windows 系统中闪烁
|
||||
if (process.platform === 'win32') {
|
||||
startBlink();
|
||||
}
|
||||
});
|
||||
ipcMain.on('tray-flash-stop', (event: IpcMainInvokeEvent) => {
|
||||
// 仅在 Windows 系统中停止闪烁
|
||||
if (process.platform === 'win32') {
|
||||
stopBlink();
|
||||
}
|
||||
});
|
||||
win.on('focus', () => {
|
||||
stopBlink();
|
||||
});
|
||||
// 发送桌面通知
|
||||
function sendDesktopNotice() {
|
||||
// 判断是否支持桌面通知
|
||||
@ -75,9 +96,8 @@ export function useTray(tray: Tray, win: BrowserWindow) {
|
||||
}
|
||||
const ins = new Notification({
|
||||
title: '通知标题',
|
||||
subtitle: '通知副标题',
|
||||
body: '通知内容第一行\n通知内容第二行',
|
||||
icon: TrayIcons.normal.resize({width: 32, height: 32}),
|
||||
// icon: TrayIcons.normal.resize({width: 32, height: 32}),
|
||||
});
|
||||
|
||||
ins.on('click', () => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type {BrowserWindowConstructorOptions} from 'electron';
|
||||
import {BrowserWindow, dialog} from 'electron';
|
||||
import {app, BrowserWindow, dialog} from 'electron';
|
||||
import path from 'path';
|
||||
import {_PATHS} from '../paths';
|
||||
import {$env, isDev} from '../env';
|
||||
@ -19,7 +19,13 @@ export function createBrowserWindow(options?: BrowserWindowConstructorOptions) {
|
||||
icon: isDev ? _PATHS.appIcon : void 0,
|
||||
...options,
|
||||
});
|
||||
|
||||
// update-begin--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
if (process.platform === 'darwin') { // 仅 macOS 生效
|
||||
if (app.dock) {
|
||||
app.dock.setIcon(path.join(_PATHS.electronRoot, './icons/mac/dock.png').replace(/[\\/]dist[\\/]/, '/'));
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
// 设置窗口打开处理器
|
||||
win.webContents.setWindowOpenHandler(({url}) => {
|
||||
const win = createBrowserWindow();
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import { resultSuccess, resultError, getRequestToken, requestParams,baseUrl} from '../_util';
|
||||
import { MockMethod } from 'vite-plugin-mock';
|
||||
import { createFakeUserList } from './user';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
|
||||
// single
|
||||
const dashboardRoute = {
|
||||
path: '/dashboard',
|
||||
name: 'Dashboard',
|
||||
component: 'LAYOUT',
|
||||
redirect: '/dashboard/analysis',
|
||||
redirect: PageEnum.BASE_HOME,
|
||||
meta: {
|
||||
title: 'routes.dashboard.dashboard',
|
||||
hideChildrenInMenu: true,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { MockMethod } from 'vite-plugin-mock';
|
||||
import { resultError, resultSuccess, getRequestToken, requestParams, baseUrl } from '../_util';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
export function createFakeUserList() {
|
||||
return [
|
||||
{
|
||||
@ -10,7 +11,7 @@ export function createFakeUserList() {
|
||||
desc: 'manager',
|
||||
password: '123456',
|
||||
token: 'fakeToken1',
|
||||
homePath: '/dashboard/analysis',
|
||||
homePath: PageEnum.BASE_HOME,
|
||||
roles: [
|
||||
{
|
||||
roleName: 'Super Admin',
|
||||
@ -26,7 +27,7 @@ export function createFakeUserList() {
|
||||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
|
||||
desc: 'tester',
|
||||
token: 'fakeToken2',
|
||||
homePath: '/dashboard/workbench',
|
||||
homePath: PageEnum.BASE_HOME,
|
||||
roles: [
|
||||
{
|
||||
roleName: 'Tester',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jeecgboot-vue3",
|
||||
"version": "3.8.1",
|
||||
"version": "3.8.2",
|
||||
"author": {
|
||||
"name": "北京国炬信息技术有限公司",
|
||||
"email": "jeecgos@163.com",
|
||||
@ -10,7 +10,9 @@
|
||||
"pinstall": "pnpm install",
|
||||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
|
||||
"dev": "vite",
|
||||
"build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 vite build && esno ./build/script/postBuild.ts",
|
||||
"build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 vite build && esno ./build/script/postBuild.ts && esno ./build/script/copyChat.ts",
|
||||
"build:docker": "cross-env NODE_ENV=docker NODE_OPTIONS=--max-old-space-size=8192 vite build --mode docker && esno ./build/script/postBuild.ts && esno ./build/script/copyChat.ts",
|
||||
"build:dockercloud": "cross-env NODE_ENV=dockercloud NODE_OPTIONS=--max-old-space-size=8192 vite build --mode dockercloud && esno ./build/script/postBuild.ts && esno ./build/script/copyChat.ts",
|
||||
"build:report": "pnpm clean:cache && cross-env REPORT=true npm run build",
|
||||
"preview": "npm run build && vite preview",
|
||||
"reinstall": "rimraf pnpm-lock.yaml && rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run install",
|
||||
@ -21,7 +23,7 @@
|
||||
"husky:install": "husky install"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jeecg/online": "3.7.4",
|
||||
"@jeecg/online": "3.8.2-beta",
|
||||
"@jeecg/aiflow": "1.1.1",
|
||||
"@logicflow/core": "^2.0.10",
|
||||
"@logicflow/extension": "^2.0.14",
|
||||
@ -79,8 +81,8 @@
|
||||
"vue-types": "^5.1.3",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vxe-table": "4.13.31",
|
||||
"vxe-table-plugin-antd": "4.0.8",
|
||||
"vxe-pc-ui": "4.6.12",
|
||||
"vxe-table-plugin-antd": "4.0.8",
|
||||
"xe-utils": "3.5.26",
|
||||
"xss": "^1.0.15"
|
||||
},
|
||||
|
||||
2873
jeecgboot-vue3/pnpm-lock.yaml
generated
@ -15,6 +15,7 @@ enum Api {
|
||||
getTableList = '/sys/user/queryUserComponentData',
|
||||
getCategoryData = '/sys/category/loadAllData',
|
||||
refreshDragCache = '/drag/page/refreshCache',
|
||||
refreshDefaultIndexCache = '/sys/sysRoleIndex/cleanDefaultIndexCache',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,3 +155,8 @@ export const uploadMyFile = (url, data) => {
|
||||
* @param params
|
||||
*/
|
||||
export const refreshDragCache = () => defHttp.get({ url: Api.refreshDragCache }, { isTransformResponse: false });
|
||||
/**
|
||||
* 刷新默认首页缓存
|
||||
* @param params
|
||||
*/
|
||||
export const refreshHomeCache = () => defHttp.get({ url: Api.refreshDefaultIndexCache }, { isTransformResponse: false });
|
||||
|
||||
BIN
jeecgboot-vue3/src/assets/icons/calendarNotice.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
jeecgboot-vue3/src/assets/icons/flowNotice.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
jeecgboot-vue3/src/assets/icons/folderNotice.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
jeecgboot-vue3/src/assets/icons/systemNotice.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
@ -7,6 +7,7 @@
|
||||
<a-menu :class="[`${prefixCls}-menu`]" :selectedKeys="selectedKeys">
|
||||
<template v-for="item in dropMenuList" :key="`${item.event}`">
|
||||
<a-menu-item
|
||||
v-if="!item.hide"
|
||||
v-bind="getAttr(item.event)"
|
||||
@click="handleClickMenu(item)"
|
||||
:disabled="item.disabled"
|
||||
|
||||
@ -5,5 +5,7 @@ export interface DropMenu {
|
||||
event: string | number;
|
||||
text: string;
|
||||
disabled?: boolean;
|
||||
// 是否隐藏
|
||||
hide?: boolean;
|
||||
divider?: boolean;
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
:allDefaultValues="defaultValueRef"
|
||||
:formModel="formModel"
|
||||
:formName="getBindValue.name"
|
||||
:source="getBindValue.source"
|
||||
:setFormModel="setFormModel"
|
||||
:validateFields="validateFields"
|
||||
:clearValidate="clearValidate"
|
||||
@ -126,7 +127,15 @@
|
||||
};
|
||||
});
|
||||
|
||||
const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable));
|
||||
const getBindValue = computed(() => {
|
||||
const bindValue = { ...attrs, ...props, ...unref(getProps) } as Recordable;
|
||||
// update-begin--author:liaozhiyang---date:20250630---for:【issues/8484】分类字典中的新增弹窗的label点击会触发查询区域的input
|
||||
if (bindValue.name === undefined && bindValue.source === 'table-query') {
|
||||
bindValue.name = 'top-query-form';
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250630---for:【issues/8484】分类字典中的新增弹窗的label点击会触发查询区域的input
|
||||
return bindValue;
|
||||
});
|
||||
|
||||
const getSchema = computed((): FormSchema[] => {
|
||||
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
||||
@ -302,6 +311,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 componentProps,处理可能是函数的情况
|
||||
* @param schema
|
||||
*/
|
||||
function getSchemaComponentProps(schema: FormSchema) {
|
||||
if (typeof schema.componentProps === 'function') {
|
||||
return schema.componentProps({
|
||||
schema,
|
||||
tableAction: props.tableAction,
|
||||
formActionType,
|
||||
formModel,
|
||||
})
|
||||
}
|
||||
return schema.componentProps
|
||||
}
|
||||
|
||||
const formActionType: Partial<FormActionType> = {
|
||||
getFieldsValue,
|
||||
setFieldsValue,
|
||||
@ -318,6 +343,7 @@
|
||||
validate,
|
||||
submit: handleSubmit,
|
||||
scrollToField: scrollToField,
|
||||
getSchemaComponentProps,
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@ -66,6 +66,7 @@ import JEllipsis from './jeecg/components/JEllipsis.vue';
|
||||
import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue';
|
||||
import JSelectUserByDepartment from './jeecg/components/JSelectUserByDepartment.vue';
|
||||
import JLinkTableCard from './jeecg/components/JLinkTableCard/JLinkTableCard.vue';
|
||||
|
||||
import JUpload from './jeecg/components/JUpload/JUpload.vue';
|
||||
import JSearchSelect from './jeecg/components/JSearchSelect.vue';
|
||||
import JAddInput from './jeecg/components/JAddInput.vue';
|
||||
|
||||
@ -190,7 +190,7 @@
|
||||
} finally {
|
||||
loading.value = false;
|
||||
//--@updateBy-begin----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||
unref(attrs).mode == 'multiple' && !Array.isArray(unref(state)) && setState([]);
|
||||
['multiple', 'tags'].includes(unref(attrs).mode) && !Array.isArray(unref(state)) && setState([]);
|
||||
//--@updateBy-end----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||
|
||||
//update-begin---author:wangshuai ---date:20230505 for:初始化value值,如果是多选字符串的情况下显示不出来------------
|
||||
@ -202,7 +202,7 @@
|
||||
function initValue() {
|
||||
let value = props.value;
|
||||
// update-begin--author:liaozhiyang---date:20250407---for:【issues/8037】初始化值单选的值被错误地写入数组值
|
||||
if (unref(attrs).mode == 'multiple') {
|
||||
if (['multiple', 'tags'].includes(unref(attrs).mode)) {
|
||||
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
|
||||
state.value = value.split(',');
|
||||
} else if (isNumber(value)) {
|
||||
|
||||
@ -66,6 +66,10 @@
|
||||
default: '',
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
||||
source: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const { t } = useI18n();
|
||||
@ -506,7 +510,7 @@
|
||||
<div style="display:flex">
|
||||
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */}
|
||||
{/* update-begin--author:liaozhiyang---date:20240510---for:【TV360X-719】表单校验不通过项滚动到可视区内 */}
|
||||
<Middleware formName={props.formName} fieldName={field}>{getContent()}</Middleware>
|
||||
<Middleware formName={props.formName} fieldName={field} source={props.source}>{getContent()}</Middleware>
|
||||
{/* update-end--author:liaozhiyang---date:20240510---for:【TV360X-719】表单校验不通过项滚动到可视区内 */}
|
||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||
</div>
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
import { ref } from 'vue';
|
||||
// update-begin--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
||||
const formItemId = ref(null);
|
||||
const props = defineProps(['formName', 'fieldName']);
|
||||
if (props.formName && props.fieldName) {
|
||||
const props = defineProps(['formName', 'fieldName', 'source']);
|
||||
if (props.formName && props.fieldName && props.source !== 'table-query') {
|
||||
formItemId.value = `${props.formName}_${props.fieldName}`;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
||||
|
||||
@ -137,7 +137,7 @@ export function useForm(props?: Props): UseFormReturnType {
|
||||
let values = form.validate(nameList).then((values) => {
|
||||
for (let key in values) {
|
||||
if (values[key] instanceof Array) {
|
||||
let valueType = getValueTypeBySchema(form.getSchemaByField(key)!);
|
||||
let valueType = getValueTypeBySchema(form.getSchemaByField(key)!, form);
|
||||
if (valueType === 'string') {
|
||||
values[key] = values[key].join(',');
|
||||
}
|
||||
|
||||
@ -595,6 +595,9 @@
|
||||
flex: 1;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
.search-box {
|
||||
:deep(.ant-input-affix-wrapper) {
|
||||
border-color: #d9d9d9 !important;
|
||||
}
|
||||
margin: 0 16px 16px 16px;
|
||||
}
|
||||
:deep(.ant-breadcrumb) {
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
v-bind="getBindValue"
|
||||
:useSearchForm="true"
|
||||
:formConfig="formConfig"
|
||||
:api="getUserList"
|
||||
:api="hasCustomApi ? customListApi : getUserList"
|
||||
:searchInfo="searchInfo"
|
||||
:rowSelection="rowSelection"
|
||||
:indexColumnProps="indexColumnProps"
|
||||
@ -54,7 +54,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, unref, ref, watch } from 'vue';
|
||||
import { defineComponent, unref, ref, watch, computed } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { getUserList } from '/@/api/common/api';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
@ -85,6 +85,11 @@
|
||||
default: [],
|
||||
},
|
||||
//update-end---author:wangshuai ---date:20230703 for:【QQYUN-5685】5、离职人员可以选自己------------
|
||||
|
||||
// 查询table数据使用的自定义接口
|
||||
customListApi: {type: Function},
|
||||
// 自定义接口的查询条件是否使用 JInput
|
||||
customApiJInput: {type: Boolean, default: true},
|
||||
},
|
||||
emits: ['register', 'getSelectResult', 'close'],
|
||||
setup(props, { emit, refs }) {
|
||||
@ -93,6 +98,8 @@
|
||||
const tableRef = ref();
|
||||
const maxHeight = ref(600);
|
||||
|
||||
const hasCustomApi = computed(() => typeof props.customListApi === 'function');
|
||||
|
||||
//注册弹框
|
||||
const [register, { closeModal }] = useModalInner(() => {
|
||||
if (window.innerWidth < 900) {
|
||||
@ -156,12 +163,12 @@
|
||||
{
|
||||
label: '账号',
|
||||
field: 'username',
|
||||
component: 'JInput',
|
||||
component: (hasCustomApi.value && !props.customApiJInput) ? 'Input' : 'JInput',
|
||||
},
|
||||
{
|
||||
label: '姓名',
|
||||
field: 'realname',
|
||||
component: 'JInput',
|
||||
component: (hasCustomApi.value && !props.customApiJInput) ? 'Input' : 'JInput',
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -300,6 +307,7 @@
|
||||
handleCancel,
|
||||
maxHeight,
|
||||
beforeFetch,
|
||||
hasCustomApi,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -41,6 +41,7 @@ export interface FormActionType {
|
||||
validateFields: (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>;
|
||||
validate: (nameList?: NamePath[]) => Promise<any>;
|
||||
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
|
||||
getSchemaComponentProps: (schema: FormSchema) => Recordable
|
||||
}
|
||||
|
||||
export type RegisterFn = (formInstance: FormActionType) => void;
|
||||
|
||||
@ -143,6 +143,11 @@
|
||||
function scaleFunc(num: number) {
|
||||
if (imgState.imgScale <= 0.2 && num < 0) return;
|
||||
imgState.imgScale += num;
|
||||
// update-begin--author:liaozhiyang---date:20250722---for:【QQYUN-13162】图片预览点击缩小一下就没了
|
||||
if (imgState.imgScale < 0.2) {
|
||||
imgState.imgScale = 0.2;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250722---for:【QQYUN-13162】图片预览点击缩小一下就没了
|
||||
}
|
||||
|
||||
// 旋转图片
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
:class="{ 'table-search-area-hidden': !getBindValues.formConfig?.schemas?.length }"
|
||||
submitOnReset
|
||||
v-bind="getFormProps"
|
||||
source="table-query"
|
||||
v-if="getBindValues.useSearchForm"
|
||||
:tableAction="tableAction"
|
||||
@register="registerForm"
|
||||
@ -214,7 +215,7 @@
|
||||
onChange && isFunction(onChange) && onChange.call(undefined, ...args);
|
||||
}
|
||||
|
||||
const { getViewColumns, getColumns, setCacheColumnsByField, setColumns, getColumnsRef, getCacheColumns } = useColumns(
|
||||
const { getViewColumns, getColumns, getRefColumns, setCacheColumnsByField, setColumns, getColumnsRef, getCacheColumns } = useColumns(
|
||||
getProps,
|
||||
getPaginationInfo,
|
||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
@ -367,6 +368,9 @@
|
||||
getRowSelection,
|
||||
getPaginationRef: getPagination,
|
||||
getColumns,
|
||||
// update-begin--author:liaozhiyang---date:20250722---for:【issues/8529】setColumns后列配置没联动更新
|
||||
getColumnsRef: () => getColumnsRef,
|
||||
// update-end--author:liaozhiyang---date:20250722---for:【issues/8529】setColumns后列配置没联动更新
|
||||
getCacheColumns,
|
||||
emit,
|
||||
updateTableData,
|
||||
|
||||
@ -49,6 +49,7 @@
|
||||
},
|
||||
setup(props) {
|
||||
const table = useTableContext();
|
||||
const getColumnsRef = table.getColumnsRef();
|
||||
const tableFooter = ref<any>(null);
|
||||
const getDataSource = computed((): Recordable[] => {
|
||||
const { summaryFunc, summaryData } = props;
|
||||
@ -71,7 +72,10 @@
|
||||
|
||||
const getColumns = computed(() => {
|
||||
const dataSource = unref(getDataSource);
|
||||
let columns: BasicColumn[] = cloneDeep(table.getColumns());
|
||||
// update-begin--author:liaozhiyang---date:20250729---for:【issues/8502】权限列不显示后,表尾行合计栏还显示导致对不齐
|
||||
const allColumns = unref(getColumnsRef);
|
||||
let columns: BasicColumn[] = cloneDeep(table.getColumns({ ignoreAuth: true, ignoreIfShow: true }));
|
||||
// update-end--author:liaozhiyang---date:20250729---for:【issues/8502】权限列不显示后,表尾行合计栏还显示导致对不齐
|
||||
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
||||
columns = columns.filter((item) => !item.defaultHidden);
|
||||
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
||||
|
||||
@ -148,7 +148,27 @@
|
||||
|
||||
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
|
||||
const option = options.find((item) => `${item.value}` === `${value}`);
|
||||
|
||||
// update-begin---author:liaozhiyang---date:2025-07-28---for:【QQYUN-13251】表格可编辑单元格apiSelect多选不翻译 ---
|
||||
if (['tags', 'multiple'].includes(editComponentProps?.mode)) {
|
||||
const result = options
|
||||
.filter((item) => {
|
||||
let v = value;
|
||||
if (isString(value)) {
|
||||
v = value.split(',');
|
||||
} else if (isNumber(value)) {
|
||||
v = [value];
|
||||
}
|
||||
if (v.includes(item.value)) {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.map((item) => item.label);
|
||||
if (result.length) {
|
||||
return result.join(',');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
// update-end---author:liaozhiyang---date:2025-07-28---for:【QQYUN-13251】表格可编辑单元格apiSelect多选不翻译 ---
|
||||
return option?.label ?? value;
|
||||
});
|
||||
|
||||
|
||||
@ -151,6 +151,9 @@
|
||||
// nextTick(() => popoverVisible.value = false);
|
||||
// update-end--author:sunjianlei---date:20221101---for: 修复第一次进入时列表配置不能拖拽
|
||||
const defaultRowSelection = omit(table.getRowSelection(), 'selectedRowKeys');
|
||||
// update-begin--author:liaozhiyang---date:20250722---for:【issues/8529】setColumns后列配置没联动更新
|
||||
const getColumnsRef = table.getColumnsRef();
|
||||
// update-end--author:liaozhiyang---date:20250722---for:【issues/8529】setColumns后列配置没联动更新
|
||||
let inited = false;
|
||||
|
||||
const cachePlainOptions = ref<Options[]>([]);
|
||||
@ -219,7 +222,7 @@
|
||||
checkSelect.value = !!values.rowSelection;
|
||||
});
|
||||
// update-begin--author:liaozhiyang---date:20240724---for:【issues/6908】多语言无刷新切换时,BasicColumn和FormSchema里面的值不能正常切换
|
||||
watch(localeStore, () => {
|
||||
watch([localeStore, getColumnsRef], () => {
|
||||
const columns = getColumns();
|
||||
plainOptions.value = columns;
|
||||
plainSortOptions.value = columns;
|
||||
@ -230,7 +233,7 @@
|
||||
function getColumns() {
|
||||
const ret: Options[] = [];
|
||||
// update-begin--author:liaozhiyang---date:20250403---for:【issues/7996】表格列组件取消所有或者只勾选中间,显示非预期
|
||||
let t = table.getColumns({ ignoreIndex: true, ignoreAction: true });
|
||||
let t = table.getColumns({ ignoreIndex: true, ignoreAction: true, ignoreAuth: true, ignoreIfShow: true });
|
||||
if (!t.length) {
|
||||
t = table.getCacheColumns();
|
||||
}
|
||||
@ -249,7 +252,7 @@
|
||||
const columns = getColumns();
|
||||
|
||||
const checkList = table
|
||||
.getColumns({ ignoreAction: true, ignoreIndex: true })
|
||||
.getColumns({ ignoreAction: true, ignoreIndex: true, ignoreAuth: true, ignoreIfShow: true })
|
||||
.map((item) => {
|
||||
if (item.defaultHidden) {
|
||||
return '';
|
||||
@ -341,7 +344,7 @@
|
||||
// state.checkedList = [...state.defaultCheckList];
|
||||
// update-begin--author:liaozhiyang---date:20231103---for:【issues/825】tabel的列设置隐藏列保存后切换路由问题[重置没勾选]
|
||||
state.checkedList = table
|
||||
.getColumns({ ignoreAction: true })
|
||||
.getColumns({ ignoreAction: true, ignoreAuth: true, ignoreIfShow: true })
|
||||
.map((item) => {
|
||||
return item.dataIndex || item.title;
|
||||
})
|
||||
|
||||
@ -285,7 +285,7 @@ export function useColumns(
|
||||
// update-end--author:sunjianlei---date:20220523---for: 【VUEN-1089】合并vben最新版代码,解决表格字段排序问题
|
||||
|
||||
function getColumns(opt?: GetColumnsParams) {
|
||||
const { ignoreIndex, ignoreAction, sort } = opt || {};
|
||||
const { ignoreIndex, ignoreAction, ignoreAuth, ignoreIfShow, sort } = opt || {};
|
||||
let columns = toRaw(unref(getColumnsRef));
|
||||
if (ignoreIndex) {
|
||||
columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG);
|
||||
@ -297,7 +297,27 @@ export function useColumns(
|
||||
// 过滤自定义选择列
|
||||
columns = columns.filter((item) => item.key !== CUS_SEL_COLUMN_KEY);
|
||||
// update-enb--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||
|
||||
// update-begin--author:liaozhiyang---date:20250729---for:【issues/8502】解决权限列在列表中不显示,列配置中还显示
|
||||
if (ignoreAuth) {
|
||||
columns = columns.filter((item) => {
|
||||
if (item.auth) {
|
||||
return hasPermission(item.auth);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (ignoreIfShow) {
|
||||
columns = columns.filter((item) => {
|
||||
if (isBoolean(item.ifShow)) {
|
||||
return item.ifShow;
|
||||
}
|
||||
if (isFunction(item.ifShow)) {
|
||||
return item.ifShow(item);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250729---for:【issues/8502】解决权限列在列表中不显示,列配置中还显示
|
||||
if (sort) {
|
||||
columns = sortFixedColumn(columns);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { VNodeChild } from 'vue';
|
||||
import type { VNodeChild, ComputedRef } from 'vue';
|
||||
import type { PaginationProps } from './pagination';
|
||||
import type { FormProps } from '/@/components/Form';
|
||||
import type { TableRowSelection as ITableRowSelection } from 'ant-design-vue/lib/table/interface';
|
||||
@ -80,6 +80,10 @@ export interface FetchParams {
|
||||
export interface GetColumnsParams {
|
||||
ignoreIndex?: boolean;
|
||||
ignoreAction?: boolean;
|
||||
// update-begin--author:liaozhiyang---date:20250729---for:【issues/8502】解决权限列在列表中不显示,列配置中还显示
|
||||
ignoreAuth?: boolean;
|
||||
ignoreIfShow?: boolean | ((column: BasicColumn) => boolean);
|
||||
// update-end--author:liaozhiyang---date:20250729---for:【issues/8502】解决权限列在列表中不显示,列配置中还显示
|
||||
sort?: boolean;
|
||||
}
|
||||
|
||||
@ -116,6 +120,7 @@ export interface TableActionType {
|
||||
setShowPagination: (show: boolean) => Promise<void>;
|
||||
getShowPagination: () => boolean;
|
||||
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void;
|
||||
getColumnsRef: () => ComputedRef<BasicColumn[]>;
|
||||
}
|
||||
|
||||
export interface FetchSetting {
|
||||
|
||||
@ -151,6 +151,28 @@
|
||||
toolbar,
|
||||
menubar: false,
|
||||
plugins,
|
||||
// 添加以下粘贴相关配置
|
||||
paste_data_images: true, // 允许粘贴图片
|
||||
paste_as_text: false, // 不以纯文本粘贴
|
||||
paste_retain_style_properties: 'all', // 保留所有样式属性
|
||||
paste_webkit_styles: 'all', // 保留webkit样式
|
||||
paste_merge_formats: true, // 合并格式
|
||||
paste_block_drop: true, // 允许拖放粘贴
|
||||
paste_preprocess: (plugin, args) => {
|
||||
// 可以在这里对粘贴的内容进行预处理
|
||||
//console.log('粘贴的内容:', args.content);
|
||||
},
|
||||
paste_postprocess: (plugin, args) => {
|
||||
// 可以在这里对粘贴的内容进行后处理
|
||||
//console.log('处理后的内容:', args.node);
|
||||
},
|
||||
// 放宽内容过滤规则
|
||||
valid_elements: '*[*]',
|
||||
extended_valid_elements: '*[*]',
|
||||
valid_children: '+body[style]',
|
||||
allow_conditional_comments: true,
|
||||
allow_html_in_named_anchor: true,
|
||||
|
||||
language_url: publicPath + 'resource/tinymce/langs/' + langName.value + '.js',
|
||||
language: langName.value,
|
||||
branding: false,
|
||||
|
||||
@ -10,10 +10,10 @@ export const plugins = [
|
||||
export const toolbar =
|
||||
'fullscreen code preview | undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent lineheight|subscript superscript blockquote| numlist bullist checklist | forecolor backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | insertfile image media pageembed link anchor codesample insertdatetime hr| a11ycheck ltr rtl';
|
||||
|
||||
export const simplePlugins = 'lists image link fullscreen';
|
||||
export const simplePlugins = 'lists image link fullscreen paste';
|
||||
|
||||
export const simpleToolbar = [
|
||||
'undo redo styles bold italic alignleft aligncenter alignright alignjustify bullist numlist outdent indent lists image link fullscreen',
|
||||
'undo redo styles forecolor fontsize bold italic alignleft aligncenter alignright alignjustify bullist numlist outdent indent lists image link fullscreen',
|
||||
];
|
||||
|
||||
export const menubar = 'file edit insert view format table';
|
||||
|
||||
@ -316,4 +316,10 @@ html[data-theme='dark'] {
|
||||
text-overflow: ellipsis;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
.table-action-item {
|
||||
&.color-red {
|
||||
color: red !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import type {App} from "vue";
|
||||
import {router} from "@/router";
|
||||
import {useGlobSetting} from "@/hooks/setting";
|
||||
|
||||
import { ElectronEnum } from '/@/enums/jeecgEnum'
|
||||
const glob = useGlobSetting();
|
||||
|
||||
const _PRELOAD_UTILS = '_ELECTRON_PRELOAD_UTILS_';
|
||||
const _PRELOAD_UTILS = ElectronEnum.ELECTRON_API;
|
||||
|
||||
export const $electron = {
|
||||
// 当前是否为Electron平台
|
||||
@ -38,8 +38,16 @@ export function setupElectron(_: App) {
|
||||
return;
|
||||
}
|
||||
hookWindowOpen();
|
||||
// update-begin--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
hookNavigate();
|
||||
// update-end--author:liaozhiyang---date:20250725---for:【JHHB-13】桌面应用消息通知
|
||||
}
|
||||
function hookNavigate() {
|
||||
// @ts-ignore
|
||||
window[ElectronEnum.ELECTRON_API].onNavigate((path) => {
|
||||
router.push({ path });
|
||||
});
|
||||
}
|
||||
|
||||
function hookWindowOpen() {
|
||||
// 保存原生方法引用
|
||||
const originFunc = window.open;
|
||||
@ -62,4 +70,4 @@ function hookWindowOpen() {
|
||||
// 自定义逻辑
|
||||
return originFunc(url, windowName, windowFeatures)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,3 +21,7 @@ export enum JDragConfigEnum {
|
||||
//拖拽缓存前缀
|
||||
DRAG_CACHE_PREFIX = 'drag-cache:',
|
||||
}
|
||||
// electron 枚举
|
||||
export enum ElectronEnum {
|
||||
ELECTRON_API = '_ELECTRON_PRELOAD_UTILS_',
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
// components
|
||||
import { Dropdown, Menu } from 'ant-design-vue';
|
||||
|
||||
import { defineComponent, computed, ref } from 'vue';
|
||||
import { defineComponent, computed, ref, nextTick } from 'vue';
|
||||
|
||||
import { SITE_URL } from '/@/settings/siteSetting';
|
||||
|
||||
@ -57,9 +57,9 @@
|
||||
import { removeAuthCache, setAuthCache } from '/src/utils/auth';
|
||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||
import { getRefPromise } from '/@/utils/index';
|
||||
import { refreshDragCache } from "@/api/common/api";
|
||||
import { refreshDragCache, refreshHomeCache } from "@/api/common/api";
|
||||
|
||||
type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart';
|
||||
type MenuEvent = 'logout' | 'doc' | 'lock' | 'cache' | 'depart' | 'defaultHomePage' | 'password' | 'account';
|
||||
const { createMessage } = useMessage();
|
||||
export default defineComponent({
|
||||
name: 'UserDropdown',
|
||||
@ -82,6 +82,7 @@
|
||||
const userStore = useUserStore();
|
||||
const go = useGo();
|
||||
const passwordVisible = ref(false);
|
||||
const homeSelectVisible = ref(false);
|
||||
const lockActionVisible = ref(false);
|
||||
const lockActionRef = ref(null);
|
||||
|
||||
@ -123,9 +124,8 @@
|
||||
// 清除缓存
|
||||
async function clearCache() {
|
||||
const result = await refreshCache();
|
||||
//TODO 当前版本还不支持刷新缓存,需要等jimibi升级
|
||||
// const dragRes = await refreshDragCache();
|
||||
// console.log('dragRes', dragRes);
|
||||
const dragRes = await refreshDragCache();
|
||||
console.log('dragRes', dragRes);
|
||||
if (result.success) {
|
||||
const res = await queryAllDictItems();
|
||||
removeAuthCache(DB_DICT_DATA_KEY);
|
||||
@ -255,4 +255,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
// update-begin--author:liaozhiyang---date:20250702---for:【QQYUN-13013】切换到英文模式下拉菜单宽度有点窄
|
||||
html[lang="en"] {
|
||||
.@{prefix-cls} {
|
||||
&-dropdown-overlay {
|
||||
width: 175px;
|
||||
}
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250702---for:【QQYUN-13013】切换到英文模式下拉菜单宽度有点窄
|
||||
</style>
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
import { useTabDropdown } from '../useTabDropdown';
|
||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||
import { useLocaleStore } from '/@/store/modules/locale';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TabContent',
|
||||
@ -61,7 +62,7 @@
|
||||
const prefixIconType = computed(() => {
|
||||
if (props.tabItem.meta.icon) {
|
||||
return props.tabItem.meta.icon;
|
||||
} else if (props.tabItem.path === '/dashboard/analysis') {
|
||||
} else if (props.tabItem.path === PageEnum.BASE_HOME) {
|
||||
// 当是首页时返回 home 图标 TODO 此处可能需要动态判断首页路径
|
||||
return 'ant-design:home-outlined';
|
||||
} else {
|
||||
|
||||
65
jeecgboot-vue3/src/layouts/default/tabs/useHideHomeDesign.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { ref } from 'vue';
|
||||
import { getMenus } from '/@/router/menus';
|
||||
|
||||
export const useHideHomeDesign = (currentRoute) => {
|
||||
let menus: any = [];
|
||||
// 是否隐藏门户设计
|
||||
const isHideHomeDesign = ref(true);
|
||||
const getHideHomeDesign = (isCurItem, path) => {
|
||||
if (/^\/portal-view\/[^/]+$/.test(path) && isCurItem) {
|
||||
if (['/portal-view/system', '/portal-view/template'].includes(path)) {
|
||||
// 主门户、模板门户 (需要检查是否存在设计列表,存在则显示门户设计,不存在则隐藏门户设计)
|
||||
getIsHasPortalDesignList();
|
||||
} else if (['/portal-view/default'].includes(path)) {
|
||||
// 设计器打开的预览需隐藏设计模式
|
||||
isHideHomeDesign.value = true;
|
||||
} else {
|
||||
// 个人工作台或者普通门户都可显示门户设计
|
||||
isHideHomeDesign.value = false;
|
||||
}
|
||||
} else {
|
||||
// 非门户页面隐藏门户设计
|
||||
isHideHomeDesign.value = true;
|
||||
}
|
||||
};
|
||||
const getMenusContainPath = async (ptah) => {
|
||||
if (!menus.length) {
|
||||
menus = await getMenus();
|
||||
}
|
||||
const result = getMatchingRouterName(menus, ptah);
|
||||
return !!result;
|
||||
};
|
||||
const getIsHasPortalDesignList = async () => {
|
||||
if (['/portal-view/system', '/portal-view/template'].includes(currentRoute.value.path)) {
|
||||
// 主门户、模板门户时才需要查询菜单中是否有portalDesignList
|
||||
getMenusContainPath('/super/eoa/portalapp/portalDesignList').then((result) => {
|
||||
isHideHomeDesign.value = !result;
|
||||
});
|
||||
}
|
||||
};
|
||||
getIsHasPortalDesignList();
|
||||
return {
|
||||
getHideHomeDesign,
|
||||
isHideHomeDesign,
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* 20250701
|
||||
* liaozhiyang
|
||||
* 通过path匹配菜单中的项
|
||||
* */
|
||||
function getMatchingRouterName(menus, path) {
|
||||
for (let i = 0, len = menus.length; i < len; i++) {
|
||||
const item = menus[i];
|
||||
if (item.path === path && !item.redirect && !item.paramPath) {
|
||||
return item;
|
||||
} else if (item.children?.length) {
|
||||
const result = getMatchingRouterName(item.children, path);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -8,6 +8,7 @@ import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
||||
import { RouteLocationNormalized, useRouter } from 'vue-router';
|
||||
import { useTabs } from '/@/hooks/web/useTabs';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { useHideHomeDesign } from './useHideHomeDesign';
|
||||
|
||||
export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
|
||||
const state = reactive({
|
||||
@ -23,6 +24,10 @@ export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: Comp
|
||||
const getTargetTab = computed((): RouteLocationNormalized => {
|
||||
return unref(getIsTabs) ? tabContentProps.tabItem : unref(currentRoute);
|
||||
});
|
||||
// update-begin--author:liaozhiyang---date:20250701---for:【QQYUN-12994】门户
|
||||
// 隐藏下拉菜单中的门户设计项
|
||||
const { getHideHomeDesign, isHideHomeDesign } = useHideHomeDesign(currentRoute);
|
||||
// update-end--author:liaozhiyang---date:20250701---for:【QQYUN-12994】门户
|
||||
|
||||
/**
|
||||
* @description: drop-down list
|
||||
@ -65,6 +70,10 @@ export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: Comp
|
||||
// Close right
|
||||
const closeRightDisabled = index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0;
|
||||
// update-end--author:liaozhiyang---date:20240605---for:【TV360X-732】非当前页右键关闭左侧、关闭右侧、关闭其它功能正常使用
|
||||
// update-begin--author:liaozhiyang---date:20250701---for:【QQYUN-12994】门户
|
||||
// 隐藏下拉菜单中的门户设计项
|
||||
getHideHomeDesign(isCurItem, path);
|
||||
// update-end--author:liaozhiyang---date:20250701---for:【QQYUN-12994】门户
|
||||
const dropMenuList: DropMenu[] = [
|
||||
{
|
||||
icon: 'jam:refresh-reverse',
|
||||
@ -76,7 +85,8 @@ export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: Comp
|
||||
icon: 'ant-design:setting-outlined',
|
||||
event: MenuEventEnum.HOME_DESIGN,
|
||||
text: t('layout.multipleTab.homeDesign'),
|
||||
disabled: path !== '/PortalView',
|
||||
disabled: !/^\/portal-view\/[^/]+$/.test(path),
|
||||
hide: isHideHomeDesign.value,
|
||||
divider: true,
|
||||
},
|
||||
// {
|
||||
|
||||
@ -8,6 +8,7 @@ export default {
|
||||
dropdownItemSwitchDepart: 'Switch Department',
|
||||
dropdownItemRefreshCache: 'Clean cache',
|
||||
dropdownItemSwitchAccount: 'Account Setting',
|
||||
dropdownItemSwitchDefaultHomePage: 'Switch Home Page',
|
||||
|
||||
tooltipErrorLog: 'Error log',
|
||||
tooltipLock: 'Lock screen',
|
||||
|
||||
@ -8,6 +8,7 @@ export default {
|
||||
dropdownItemSwitchDepart: '切换部门',
|
||||
dropdownItemRefreshCache: '刷新缓存',
|
||||
dropdownItemSwitchAccount: '账户设置',
|
||||
dropdownItemSwitchDefaultHomePage: '切换首页',
|
||||
|
||||
// tooltip
|
||||
tooltipErrorLog: '错误日志',
|
||||
@ -34,7 +35,7 @@ export default {
|
||||
closeRight: '关闭右侧',
|
||||
closeOther: '关闭其它',
|
||||
closeAll: '关闭全部',
|
||||
homeDesign: '设计模式',
|
||||
homeDesign: '门户设计',
|
||||
},
|
||||
setting: {
|
||||
// content mode
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { AppRouteModule } from '/@/router/types';
|
||||
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
import { LAYOUT } from '/@/router/constant';
|
||||
import { t } from '/@/hooks/web/useI18n';
|
||||
|
||||
@ -7,7 +7,7 @@ const dashboard: AppRouteModule = {
|
||||
path: '/dashboard',
|
||||
name: 'Dashboard',
|
||||
component: LAYOUT,
|
||||
redirect: '/dashboard/analysis',
|
||||
redirect: PageEnum.BASE_HOME,
|
||||
meta: {
|
||||
orderNo: 10,
|
||||
icon: 'ion:grid-outline',
|
||||
|
||||
@ -67,7 +67,9 @@ export const defIndexApi = {
|
||||
async update(url: string, component: string, isRoute: boolean) {
|
||||
let apiUrl = '/sys/sysRoleIndex/updateDefIndex'
|
||||
apiUrl += '?url=' + url
|
||||
apiUrl += '&component=' + component
|
||||
//update-begin-author:liusq---date:2025-07-04--for: 设置默认首页接口传参修改,增加encodeURIComponent,防止{{ window._CONFIG['domianURL'] }}/**保存不上
|
||||
apiUrl += '&component=' + encodeURIComponent(component)
|
||||
//update-end-author:liusq---date:2025-07-04--for: 设置默认首页接口传参修改,增加encodeURIComponent,防止{{ window._CONFIG['domianURL'] }}/**保存不上
|
||||
apiUrl += '&isRoute=' + isRoute
|
||||
return await defHttp.put({url: apiUrl});
|
||||
},
|
||||
|
||||
@ -232,6 +232,15 @@ export const useMultipleTabStore = defineStore({
|
||||
curTab.fullPath = fullPath || curTab.fullPath;
|
||||
this.tabList.splice(updateIndex, 1, curTab);
|
||||
} else {
|
||||
// update-begin--author:liaozhiyang---date:20250709---for:【QQYUN-13058】菜单检测同样的地址(忽略query查询参数)只打开一个
|
||||
// 只比较path,忽略query
|
||||
const findIndex = this.tabList.findIndex((tab) => tab.path === path);
|
||||
const isTabExist = findIndex !== -1;
|
||||
if (isTabExist) {
|
||||
this.tabList.splice(findIndex, 1, route);
|
||||
return;
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250709---for:【QQYUN-13058】菜单检测同样的地址(忽略query查询参数)只打开一个
|
||||
// Add tab
|
||||
// 获取动态路由打开数,超过 0 即代表需要控制打开数
|
||||
const dynamicLevel = meta?.dynamicLevel ?? -1;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
|
||||
import type { App, Plugin } from 'vue';
|
||||
import type { FormSchema } from "@/components/Form";
|
||||
import type { FormSchema, FormActionType } from "@/components/Form";
|
||||
|
||||
import { unref } from 'vue';
|
||||
import { isObject, isFunction, isString } from '/@/utils/is';
|
||||
@ -110,11 +110,12 @@ export function getValueType(props, field) {
|
||||
/**
|
||||
* 获取表单字段值数据类型
|
||||
* @param schema
|
||||
* @param formAction
|
||||
*/
|
||||
export function getValueTypeBySchema(schema: FormSchema) {
|
||||
export function getValueTypeBySchema(schema: FormSchema, formAction: FormActionType) {
|
||||
let valueType = 'string';
|
||||
if (schema) {
|
||||
const componentProps = schema.componentProps as Recordable;
|
||||
const componentProps = formAction.getSchemaComponentProps(schema);
|
||||
valueType = componentProps?.valueType ? componentProps?.valueType : valueType;
|
||||
}
|
||||
return valueType;
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
<a @click="handleDetail(record)">详情</a>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<Popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
|
||||
<Popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)" placement="left">
|
||||
<a>删除</a>
|
||||
</Popconfirm>
|
||||
</a-menu-item>
|
||||
|
||||
@ -1,230 +1,234 @@
|
||||
<template>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.name">
|
||||
<a-input v-model:value="formState.name" placeholder="请输入文本"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.miMa">
|
||||
<a-input-password v-model:value="formState.miMa" placeholder="请输入密码" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典下拉" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xiala">
|
||||
<JDictSelectTag type="select" v-model:value="formState.xiala" dictCode="sex" placeholder="请选择字典下拉" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典单选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.danxuan">
|
||||
<JDictSelectTag type="radio" v-model:value="formState.danxuan" dictCode="sex" placeholder="请选择字典单选" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.duoxuan">
|
||||
<JCheckbox v-model:value="formState.duoxuan" dictCode="urgent_level" placeholder="请选择字典多选" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="开关" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.kaiguan">
|
||||
<JSwitch v-model:value="formState.kaiguan" :options="['1', '0']"></JSwitch>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="日期" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.riqi">
|
||||
<a-date-picker placeholder="请选择日期" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD" v-model:value="formState.riqi" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="年月日时分秒" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.nyrsfm">
|
||||
<a-date-picker show-time v-model:value="formState.nyrsfm" style="width: 100%" valueFormat="YYYY-MM-DD HH:mm:ss" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="时间" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shijian">
|
||||
<TimePicker placeholder="请选择时间" v-model:value="formState.shijian" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="文件" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.wenjian">
|
||||
<JUpload v-model:value="formState.wenjian"></JUpload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.tupian">
|
||||
<JImageUpload :fileMax="2" v-model:value="formState.tupian"></JImageUpload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="多行文本框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.dhwb">
|
||||
<a-textarea v-model:value="formState.dhwb" rows="4" placeholder="请输入多行文本框" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典表下拉搜索框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xlss">
|
||||
<JSearchSelect v-model:value="formState.xlss" dict="sys_user,realname,username" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="popup弹窗" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popup">
|
||||
<JPopup
|
||||
v-model:value="formState.popup"
|
||||
:fieldConfig="[
|
||||
{ source: 'name', target: 'popup' },
|
||||
{ source: 'id', target: 'popback' },
|
||||
]"
|
||||
code="report_user"
|
||||
:multi="true"
|
||||
:setFieldsValue="setFieldsValue"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="popback" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popback">
|
||||
<a-input v-model:value="formState.popback" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="分类字典树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.flzds">
|
||||
<JCategorySelect
|
||||
@change="(value) => handleFormChange('flzds', value)"
|
||||
v-model:value="formState.flzds"
|
||||
pcode="B02"
|
||||
placeholder="请选择分类字典树"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="部门选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.bmxz">
|
||||
<JSelectDept v-model:value="formState.bmxz" :multi="true" type="array" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="用户选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yhxz">
|
||||
<JSelectUserByDept v-model:value="formState.yhxz" :multi="true" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="富文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.fwb">
|
||||
<JEditor v-model:value="formState.fwb" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="markdown" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.markdownString">
|
||||
<JMarkdownEditor v-model:value="formState.markdownString"></JMarkdownEditor>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="省市区JAreaSelect" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shq">
|
||||
<JAreaSelect v-model:value="formState.shq" placeholder="请输入省市区" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="省市区JAreaLinkage" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jssq">
|
||||
<JAreaLinkage v-model:value="formState.jssq" placeholder="请输入省市区" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JInputPop" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzje">
|
||||
<JInputPop
|
||||
v-model:value="formState.ldzje"
|
||||
placeholder="请输入JInputPop"
|
||||
@change="(value) => handleFormChange('ldzje', value)"
|
||||
></JInputPop>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JSelectInput" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzjs">
|
||||
<JSelectInput
|
||||
v-model:value="formState.ldzjs"
|
||||
placeholder="请选择JSelectInput"
|
||||
:options="ldzjsOptions"
|
||||
@change="(value) => handleFormChange('ldzjs', value)"
|
||||
></JSelectInput>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="下拉多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zddtjxl">
|
||||
<JSelectMultiple v-model:value="formState.zddtjxl" placeholder="请选择下拉多选" dictCode="sex"></JSelectMultiple>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yongHu">
|
||||
<JSelectUser v-model:value="formState.yongHu" placeholder="请选择用户"></JSelectUser>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="职务" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zhiWu">
|
||||
<JSelectPosition
|
||||
v-model:value="formState.zhiWu"
|
||||
placeholder="请选择职务"
|
||||
@change="(value) => handleFormChange('zhiWu', value)"
|
||||
></JSelectPosition>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="角色" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jueSe">
|
||||
<JSelectRole v-model:value="formState.jueSe" placeholder="请选择角色" @change="(value) => handleFormChange('jueSe', value)"></JSelectRole>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="自定义树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdys">
|
||||
<JTreeSelect
|
||||
ref="treeSelect"
|
||||
placeholder="请选择自定义树"
|
||||
v-model:value="formState.zdys"
|
||||
dict="sys_category,name,id"
|
||||
pidValue="0"
|
||||
loadTriggleChange
|
||||
>
|
||||
</JTreeSelect>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="数值" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yuanjia">
|
||||
<a-input-number v-model:value="formState.yuanjia" placeholder="请输入double类型" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="输入2到10位的字母" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ywzz">
|
||||
<a-input v-model:value="formState.ywzz" placeholder="请输入2到10位的字母"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JTreeDict" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdbxl">
|
||||
<JTreeDict
|
||||
v-model:value="formState.zdbxl"
|
||||
placeholder="请选择JTreeDict"
|
||||
@change="(value) => handleFormChange('zdbxl', value)"
|
||||
></JTreeDict>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JCodeEditor" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdmrz">
|
||||
<JCodeEditor
|
||||
v-model:value="formState.zdmrz"
|
||||
placeholder="请输入JCodeEditor"
|
||||
@change="(value) => handleFormChange('zdmrz', value)"
|
||||
></JCodeEditor>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="参数" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jsonParam">
|
||||
<JAddInput v-model:value="formState.jsonParam" placeholder="参数"></JAddInput>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<JFormContainer :disabled="disabled">
|
||||
<template #detail>
|
||||
<a-form class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.name">
|
||||
<a-input v-model:value="formState.name" placeholder="请输入文本"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.miMa">
|
||||
<a-input-password v-model:value="formState.miMa" placeholder="请输入密码" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典下拉" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xiala">
|
||||
<JDictSelectTag type="select" v-model:value="formState.xiala" dictCode="sex" placeholder="请选择字典下拉" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典单选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.danxuan">
|
||||
<JDictSelectTag type="radio" v-model:value="formState.danxuan" dictCode="sex" placeholder="请选择字典单选" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.duoxuan">
|
||||
<JCheckbox v-model:value="formState.duoxuan" dictCode="urgent_level" placeholder="请选择字典多选" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="开关" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.kaiguan">
|
||||
<JSwitch v-model:value="formState.kaiguan" :options="['1', '0']"></JSwitch>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="日期" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.riqi">
|
||||
<a-date-picker placeholder="请选择日期" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD" v-model:value="formState.riqi" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="年月日时分秒" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.nyrsfm">
|
||||
<a-date-picker show-time v-model:value="formState.nyrsfm" style="width: 100%" valueFormat="YYYY-MM-DD HH:mm:ss" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="时间" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shijian">
|
||||
<TimePicker placeholder="请选择时间" v-model:value="formState.shijian" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="文件" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.wenjian">
|
||||
<JUpload v-model:value="formState.wenjian"></JUpload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.tupian">
|
||||
<JImageUpload :fileMax="2" v-model:value="formState.tupian"></JImageUpload>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="多行文本框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.dhwb">
|
||||
<a-textarea v-model:value="formState.dhwb" rows="4" placeholder="请输入多行文本框" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="字典表下拉搜索框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xlss">
|
||||
<JSearchSelect v-model:value="formState.xlss" dict="sys_user,realname,username" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="popup弹窗" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popup">
|
||||
<JPopup
|
||||
v-model:value="formState.popup"
|
||||
:fieldConfig="[
|
||||
{ source: 'name', target: 'popup' },
|
||||
{ source: 'id', target: 'popback' },
|
||||
]"
|
||||
code="report_user"
|
||||
:multi="true"
|
||||
:setFieldsValue="setFieldsValue"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="popback" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popback">
|
||||
<a-input v-model:value="formState.popback" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="分类字典树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.flzds">
|
||||
<JCategorySelect
|
||||
@change="(value) => handleFormChange('flzds', value)"
|
||||
v-model:value="formState.flzds"
|
||||
pcode="B02"
|
||||
placeholder="请选择分类字典树"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="部门选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.bmxz">
|
||||
<JSelectDept v-model:value="formState.bmxz" :multi="true" type="array" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="用户选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yhxz">
|
||||
<JSelectUserByDept v-model:value="formState.yhxz" :multi="true" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="富文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.fwb">
|
||||
<JEditor v-model:value="formState.fwb" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="markdown" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.markdownString">
|
||||
<JMarkdownEditor v-model:value="formState.markdownString"></JMarkdownEditor>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="省市区JAreaSelect" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shq">
|
||||
<JAreaSelect v-model:value="formState.shq" placeholder="请输入省市区" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="省市区JAreaLinkage" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jssq">
|
||||
<JAreaLinkage v-model:value="formState.jssq" placeholder="请输入省市区" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JInputPop" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzje">
|
||||
<JInputPop
|
||||
v-model:value="formState.ldzje"
|
||||
placeholder="请输入JInputPop"
|
||||
@change="(value) => handleFormChange('ldzje', value)"
|
||||
></JInputPop>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JSelectInput" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzjs">
|
||||
<JSelectInput
|
||||
v-model:value="formState.ldzjs"
|
||||
placeholder="请选择JSelectInput"
|
||||
:options="ldzjsOptions"
|
||||
@change="(value) => handleFormChange('ldzjs', value)"
|
||||
></JSelectInput>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="下拉多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zddtjxl">
|
||||
<JSelectMultiple v-model:value="formState.zddtjxl" placeholder="请选择下拉多选" dictCode="sex"></JSelectMultiple>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yongHu">
|
||||
<JSelectUser v-model:value="formState.yongHu" placeholder="请选择用户"></JSelectUser>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="职务" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zhiWu">
|
||||
<JSelectPosition
|
||||
v-model:value="formState.zhiWu"
|
||||
placeholder="请选择职务"
|
||||
@change="(value) => handleFormChange('zhiWu', value)"
|
||||
></JSelectPosition>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="角色" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jueSe">
|
||||
<JSelectRole v-model:value="formState.jueSe" placeholder="请选择角色" @change="(value) => handleFormChange('jueSe', value)"></JSelectRole>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="自定义树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdys">
|
||||
<JTreeSelect
|
||||
ref="treeSelect"
|
||||
placeholder="请选择自定义树"
|
||||
v-model:value="formState.zdys"
|
||||
dict="sys_category,name,id"
|
||||
pidValue="0"
|
||||
loadTriggleChange
|
||||
>
|
||||
</JTreeSelect>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<a-form-item label="数值" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yuanjia">
|
||||
<a-input-number v-model:value="formState.yuanjia" placeholder="请输入double类型" style="width: 100%" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="输入2到10位的字母" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ywzz">
|
||||
<a-input v-model:value="formState.ywzz" placeholder="请输入2到10位的字母"></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JTreeDict" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdbxl">
|
||||
<JTreeDict
|
||||
v-model:value="formState.zdbxl"
|
||||
placeholder="请选择JTreeDict"
|
||||
@change="(value) => handleFormChange('zdbxl', value)"
|
||||
></JTreeDict>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="JCodeEditor" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdmrz">
|
||||
<JCodeEditor
|
||||
v-model:value="formState.zdmrz"
|
||||
placeholder="请输入JCodeEditor"
|
||||
@change="(value) => handleFormChange('zdmrz', value)"
|
||||
></JCodeEditor>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="参数" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jsonParam">
|
||||
<JAddInput v-model:value="formState.jsonParam" placeholder="参数"></JAddInput>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</template>
|
||||
</JFormContainer>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, nextTick } from 'vue';
|
||||
import { ref, reactive, nextTick, computed } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import dayjs from 'dayjs';
|
||||
@ -255,7 +259,15 @@
|
||||
import JCodeEditor from '/@/components/Form/src/jeecg/components/JCodeEditor.vue';
|
||||
import JAddInput from '/@/components/Form/src/jeecg/components/JAddInput.vue';
|
||||
import { getValueType } from '/@/utils';
|
||||
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
||||
|
||||
const props = defineProps({
|
||||
formDisabled: { type: Boolean, default: false },
|
||||
});
|
||||
// 表单禁用
|
||||
const disabled = computed(()=>{
|
||||
return props.formDisabled;
|
||||
});
|
||||
const emit = defineEmits(['register', 'ok']);
|
||||
//update-begin---author:wangshuai ---date:20220616 for:报表示例验证修改--------------
|
||||
const formState = reactive<Record<string, any>>({
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
@cancel="handleCancel"
|
||||
cancelText="关闭"
|
||||
>
|
||||
<OneNativeForm ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></OneNativeForm>
|
||||
<OneNativeForm ref="realForm" @ok="submitCallback" :formDisabled="disableSubmit"></OneNativeForm>
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
@ -61,5 +61,9 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
<style lang="less">
|
||||
/**隐藏样式-modal确定按钮 */
|
||||
.jee-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" :width="500" :minHeight="20" :maxHeight="20">
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" :width="500" :minHeight="20" :maxHeight="100">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
@ -16,7 +16,7 @@
|
||||
const isUpdate = ref(true);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 150,
|
||||
// labelWidth: 150,
|
||||
schemas: ticketFormSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
|
||||
@ -227,6 +227,7 @@ export const ticketFormSchema: FormSchema[] = [
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
getPopupContainer:()=>document.body,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@ -1,92 +1,340 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" title="查看详情" :minHeight="600" :showCancelBtn="false" :showOkBtn="false" :height="88" :destroyOnClose="true">
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
title="查看详情"
|
||||
:width="800"
|
||||
:minHeight="600"
|
||||
:showCancelBtn="false"
|
||||
:showOkBtn="false"
|
||||
:height="88"
|
||||
:destroyOnClose="true"
|
||||
@visible-change="handleVisibleChange"
|
||||
>
|
||||
<div class="print-btn" @click="onPrinter">
|
||||
<Icon icon="ant-design:printer-filled" />
|
||||
<span class="print-text">打印</span>
|
||||
</div>
|
||||
<a-card class="daily-article">
|
||||
<a-card-meta :title="content.titile" :description="'发布人:' + content.sender + ' 发布时间: ' + content.sendTime"> </a-card-meta>
|
||||
<a-card-meta :title="content.titile">
|
||||
<template #description>
|
||||
<div class="article-desc">
|
||||
<span>发布人:{{ content.sender }}</span>
|
||||
<span>发布时间:{{ content.sendTime }}</span>
|
||||
<span v-if="content.visitsNum">
|
||||
<a-tooltip placement="top" title="访问次数" :autoAdjustOverflow="true">
|
||||
<eye-outlined class="item-icon" /> {{ content.visitsNum }}
|
||||
</a-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-card-meta>
|
||||
<a-divider />
|
||||
<div v-html="content.msgContent" class="article-content"></div>
|
||||
<div>
|
||||
<a-button v-if="hasHref" @click="jumpToHandlePage">前往办理<ArrowRightOutlined /></a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
<template v-if="noticeFiles && noticeFiles.length > 0">
|
||||
<div class="files-title">相关附件:</div>
|
||||
<template v-for="(file, index) in noticeFiles" :key="index">
|
||||
<div class="files-area">
|
||||
<div class="files-area-text">
|
||||
<span>
|
||||
<paper-clip-outlined />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:title="file.fileName"
|
||||
:href="getFileAccessHttpUrl(file.filePath)"
|
||||
class="ant-upload-list-item-name"
|
||||
>{{ file.fileName }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class="files-area-operate">
|
||||
<download-outlined class="item-icon" @click="handleDownloadFile(file.filePath)" />
|
||||
<eye-outlined class="item-icon" @click="handleViewFile(file.filePath)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { ArrowRightOutlined } from '@ant-design/icons-vue';
|
||||
import { useRouter } from 'vue-router'
|
||||
import xss from 'xss'
|
||||
import { options } from './XssWhiteList'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
import { ArrowRightOutlined, PaperClipOutlined, DownloadOutlined, EyeOutlined } from '@ant-design/icons-vue';
|
||||
import { addVisitsNum } from '@/views/system/notice/notice.api';
|
||||
import { useRouter } from 'vue-router';
|
||||
import xss from 'xss';
|
||||
import { options } from './XssWhiteList';
|
||||
import { ref, unref } from 'vue';
|
||||
import { getFileAccessHttpUrl } from '@/utils/common/compUtils';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { encryptByBase64 } from '@/utils/cipher';
|
||||
const router = useRouter();
|
||||
const glob = useGlobSetting();
|
||||
const isUpdate = ref(true);
|
||||
const content = ref({});
|
||||
const content = ref<any>({});
|
||||
const noticeFiles = ref([]);
|
||||
const emit = defineEmits(['close', 'register']);
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//data.record.msgContent = '<p>2323</p><input onmouseover=alert(1)>xss test';
|
||||
//update-begin-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
|
||||
if(data.record.msgContent){
|
||||
if (data.record.msgContent) {
|
||||
//update-begin---author:wangshuai---date:2023-11-15---for:【QQYUN-7049】3.6.0版本 通知公告中发布的富文本消息,在我的消息中查看没有样式---
|
||||
data.record.msgContent = xss(data.record.msgContent,options);
|
||||
data.record.msgContent = xss(data.record.msgContent, options);
|
||||
//update-end---author:wangshuai---date:2023-11-15---for:【QQYUN-7049】3.6.0版本 通知公告中发布的富文本消息,在我的消息中查看没有样式---
|
||||
}
|
||||
//update-end-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
|
||||
|
||||
//update-begin-author:liusq---date:2025-06-17--for: [QQYUN-12521]通知公告消息增加访问量
|
||||
if (!data.record?.busId) {
|
||||
await addVisitsNum({ id: data.record.id });
|
||||
}
|
||||
//update-end-author:liusq---date:2025-06-17--for: [QQYUN-12521]通知公告消息增加访问量
|
||||
|
||||
content.value = data.record;
|
||||
console.log('data---------->>>', data);
|
||||
if (data.record?.files && data.record?.files.length > 0) {
|
||||
noticeFiles.value = data.record.files.split(',').map((item) => {
|
||||
return {
|
||||
fileName: item.split('/').pop(),
|
||||
filePath: item,
|
||||
};
|
||||
});
|
||||
}
|
||||
showHrefButton();
|
||||
}
|
||||
});
|
||||
|
||||
const hasHref = ref(false)
|
||||
|
||||
const hasHref = ref(false);
|
||||
//查看消息详情可以跳转
|
||||
function showHrefButton(){
|
||||
if(content.value.busId){
|
||||
function showHrefButton() {
|
||||
if (content.value.busId) {
|
||||
hasHref.value = true;
|
||||
}
|
||||
}
|
||||
//跳转至办理页面
|
||||
function jumpToHandlePage(){
|
||||
let temp:any = content.value
|
||||
if(temp.busId){
|
||||
//这个busId是 任务ID
|
||||
function jumpToHandlePage() {
|
||||
let temp: any = content.value;
|
||||
if (temp.busId) {
|
||||
//这个busId是 任务ID
|
||||
let jsonStr = temp.msgAbstract;
|
||||
let query = {};
|
||||
try {
|
||||
if(jsonStr){
|
||||
let temp = JSON.parse(jsonStr)
|
||||
if(temp){
|
||||
Object.keys(temp).map(k=>{
|
||||
query[k] = temp[k]
|
||||
if (jsonStr) {
|
||||
let temp = JSON.parse(jsonStr);
|
||||
if (temp) {
|
||||
Object.keys(temp).map((k) => {
|
||||
query[k] = temp[k];
|
||||
});
|
||||
}
|
||||
}
|
||||
}catch(e){
|
||||
console.log('参数解析异常', e)
|
||||
} catch (e) {
|
||||
console.log('参数解析异常', e);
|
||||
}
|
||||
|
||||
console.log('query', query, jsonStr)
|
||||
console.log('busId', temp.busId)
|
||||
|
||||
if(Object.keys(query).length>0){
|
||||
|
||||
console.log('query', query, jsonStr);
|
||||
console.log('busId', temp.busId);
|
||||
|
||||
if (Object.keys(query).length > 0) {
|
||||
// taskId taskDefKey procInsId
|
||||
router.push({ path: '/task/handle/' + temp.busId, query: query })
|
||||
}else{
|
||||
router.push({ path: '/task/handle/' + temp.busId })
|
||||
router.push({ path: '/task/handle/' + temp.busId, query: query });
|
||||
} else {
|
||||
router.push({ path: '/task/handle/' + temp.busId });
|
||||
}
|
||||
}
|
||||
closeModal();
|
||||
}
|
||||
|
||||
//打印
|
||||
function onPrinter() {
|
||||
// 获取要打印的内容
|
||||
const printContent = document.querySelector('.daily-article');
|
||||
|
||||
if (!printContent) return;
|
||||
|
||||
// 创建一个iframe来处理打印
|
||||
const printFrame = document.createElement('iframe');
|
||||
printFrame.style.position = 'absolute';
|
||||
printFrame.style.width = '0';
|
||||
printFrame.style.height = '0';
|
||||
printFrame.style.border = 'none';
|
||||
printFrame.style.left = '-9999px';
|
||||
|
||||
printFrame.onload = function () {
|
||||
const frameDoc = printFrame.contentDocument || printFrame.contentWindow?.document;
|
||||
if (!frameDoc) return;
|
||||
|
||||
// 复制内容到iframe
|
||||
const clone = printContent.cloneNode(true);
|
||||
frameDoc.body.appendChild(clone);
|
||||
|
||||
// 添加打印样式
|
||||
const style = frameDoc.createElement('style');
|
||||
style.innerHTML = `
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 15px;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
@page {
|
||||
size: auto;
|
||||
margin: 15mm;
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
frameDoc.head.appendChild(style);
|
||||
|
||||
// 确保图片加载完成
|
||||
const images = frameDoc.getElementsByTagName('img');
|
||||
let imagesToLoad = images.length;
|
||||
|
||||
const printWhenReady = () => {
|
||||
if (imagesToLoad === 0) {
|
||||
setTimeout(() => {
|
||||
printFrame.contentWindow?.focus();
|
||||
printFrame.contentWindow?.print();
|
||||
document.body.removeChild(printFrame);
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
if (imagesToLoad === 0) {
|
||||
printWhenReady();
|
||||
} else {
|
||||
Array.from(images).forEach((img) => {
|
||||
img.onload = () => {
|
||||
imagesToLoad--;
|
||||
printWhenReady();
|
||||
};
|
||||
// 处理可能已经缓存的图片
|
||||
if (img.complete && img.naturalWidth !== 0) {
|
||||
imagesToLoad--;
|
||||
printWhenReady();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
document.body.appendChild(printFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param filePath
|
||||
*/
|
||||
function handleDownloadFile(filePath) {
|
||||
window.open(getFileAccessHttpUrl(filePath), '_blank');
|
||||
}
|
||||
/**
|
||||
* 预览文件
|
||||
* @param filePath
|
||||
*/
|
||||
function handleViewFile(filePath) {
|
||||
if (filePath) {
|
||||
console.log('glob.onlineUrl', glob.viewUrl);
|
||||
let url = encodeURIComponent(encryptByBase64(filePath));
|
||||
let previewUrl = `${glob.viewUrl}?url=` + url;
|
||||
window.open(previewUrl, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
function handleVisibleChange(visible: boolean) {
|
||||
if (!visible) {
|
||||
emit('close');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.daily-article {
|
||||
:deep(.ant-card-meta-detail) {
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
flex-direction: column !important;
|
||||
}
|
||||
:deep(.ant-card-meta-detail .ant-card-meta-title) {
|
||||
font-size: 22px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.print-btn {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
cursor: pointer;
|
||||
color: #a3a3a5;
|
||||
z-index: 999;
|
||||
.print-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
.detail-iframe {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 600px;
|
||||
}
|
||||
.files-title {
|
||||
font-size: 16px;
|
||||
margin: 10px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.files-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin: 6px;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.files-area-text {
|
||||
display: flex;
|
||||
.ant-upload-list-item-name {
|
||||
margin: 0 6px;
|
||||
color: #56befa;
|
||||
}
|
||||
}
|
||||
.files-area-operate {
|
||||
display: flex;
|
||||
margin-left: 10px;
|
||||
.item-icon {
|
||||
cursor: pointer;
|
||||
margin: 0 6px;
|
||||
&:hover {
|
||||
color: #56befa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.article-desc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
span:not(:first-child) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
/* 确保打印内容中的图片有最大宽度限制 */
|
||||
.article-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -33,9 +33,20 @@
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import { useMessageHref } from '/@/views/system/message/components/useSysMessage';
|
||||
const appStore = useAppStore();
|
||||
|
||||
const {goPage} = useMessageHref()
|
||||
|
||||
const router = useRouter();
|
||||
const { currentRoute } = useRouter();
|
||||
const { goPage } = useMessageHref();
|
||||
// update-begin--author:liaozhiyang---date:20250709---for:【QQYUN-13058】我的消息区分类型且支持根据url参数查询类型
|
||||
const querystring = currentRoute.value.query;
|
||||
const findItem: any = searchFormSchema.find((item: any) => item.field === 'msgCategory');
|
||||
if (findItem) {
|
||||
if (querystring?.msgCategory) {
|
||||
findItem.componentProps.defaultValue = querystring.msgCategory
|
||||
} else {
|
||||
findItem.componentProps.defaultValue = null
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20250709---for:【QQYUN-13058】我的消息区分类型且支持根据url参数查询类型
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'mynews-list',
|
||||
tableProps: {
|
||||
@ -48,6 +59,14 @@
|
||||
fieldMapToTime: [['sendTime', ['sendTimeBegin', 'sendTimeEnd'], 'YYYY-MM-DD']],
|
||||
//update-end---author:wangshuai---date:2024-06-11---for:【TV360X-545】我的消息列表不能通过时间范围查询---
|
||||
},
|
||||
beforeFetch: (params) => {
|
||||
// update-begin--author:liaozhiyang---date:20250709---for:【QQYUN-13058】我的消息区分类型且支持根据url参数查询类型
|
||||
if (querystring?.msgCategory) {
|
||||
params.msgCategory = querystring.msgCategory;
|
||||
}
|
||||
return params;
|
||||
// update-end--author:liaozhiyang---date:20250709---for:【QQYUN-13058】我的消息区分类型且支持根据url参数查询类型
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }] = tableContext;
|
||||
|
||||
@ -81,4 +81,16 @@ export const searchFormSchema: FormSchema[] = [
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'msgCategory',
|
||||
label: '消息类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '通知公告', value: '1' },
|
||||
{ label: '系统消息', value: '2' },
|
||||
],
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
></chat>
|
||||
</div>
|
||||
</template>
|
||||
<Spin v-else :spinning="true"></Spin>
|
||||
<Loading :loading="loading" tip="加载中,请稍后"></Loading>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAppInject } from "@/hooks/web/useAppInject";
|
||||
import Loading from '@/components/Loading/src/Loading.vue';
|
||||
|
||||
const router = useRouter();
|
||||
const userId = useUserStore().getUserInfo?.id;
|
||||
@ -67,6 +68,8 @@
|
||||
const chatActiveKey = ref<number>(0);
|
||||
//预置开场白
|
||||
const presetQuestion = ref<string>('');
|
||||
//加载
|
||||
const loading = ref<any>(true);
|
||||
|
||||
const handleToggle = () => {
|
||||
expand.value = !expand.value;
|
||||
@ -179,10 +182,13 @@
|
||||
})
|
||||
.catch(() => {
|
||||
priming();
|
||||
});
|
||||
}).finally(()=>{
|
||||
loading.value = false
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loading.value = true;
|
||||
let params: any = router.currentRoute.value.params;
|
||||
if (params.appId) {
|
||||
appId.value = params.appId;
|
||||
|
||||
@ -84,6 +84,8 @@
|
||||
}
|
||||
//倒计时执行前的函数
|
||||
function sendCodeApi() {
|
||||
return getCaptcha({ mobile: formData.mobile, smsmode: SmsEnum.FORGET_PASSWORD });
|
||||
//update-begin---author:wangshuai---date:2025-07-15---for:【issues/8567】严重:修改密码存在水平越权问题:登录应该用登录模板不应该用忘记密码的模板---
|
||||
return getCaptcha({ mobile: formData.mobile, smsmode: SmsEnum.LOGIN });
|
||||
//update-end---author:wangshuai---date:2025-07-15---for:【issues/8567】严重:修改密码存在水平越权问题:登录应该用登录模板不应该用忘记密码的模板---
|
||||
}
|
||||
</script>
|
||||
|
||||
197
jeecgboot-vue3/src/views/system/appVersion/SysAppVersion.vue
Normal file
@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<PageWrapper contentFullHeight>
|
||||
<a-card :bordered="false" title="版本管理">
|
||||
<!--编辑模式-->
|
||||
<a-spin v-if="active" :spinning="confirmLoading">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="版本" name="appVersion">
|
||||
<a-input v-model:value="model.appVersion" placeholder="请输入版本" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="APP安装apk" name="downloadUrl">
|
||||
<a-input placeholder="设置APP安装apk" v-model:value="model.downloadUrl">
|
||||
<template #addonAfter>
|
||||
<Icon icon="ant-design:upload-outlined" style="cursor: pointer" @click="showUploadModal('apk')" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="APP热更新文件" name="wgtUrl">
|
||||
<a-input placeholder="设置APP热更新文件" v-model:value="model.wgtUrl">
|
||||
<template #addonAfter>
|
||||
<Icon icon="ant-design:upload-outlined" style="cursor: pointer" @click="showUploadModal('wgt')" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="更新内容">
|
||||
<a-textarea :rows="4" v-model:value="model.updateNote" placeholder="请输入更新内容" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<JUploadModal :value="modalValue" :bizPath="filePath" :maxCount="1" @register="registerModel" @change="uploadBack" />
|
||||
</a-spin>
|
||||
<!--详情模式-->
|
||||
<Description v-else class="desc" :column="1" :data="model" :schema="schema" />
|
||||
<!--底部按钮-->
|
||||
<div class="anty-form-btn" v-if="hasPermission('app:edit:version')">
|
||||
<a-button v-if="active" @click="handleSubmit" type="primary" preIcon="ant-design:save-outlined">保存</a-button>
|
||||
<a-button v-else @click="active = true" type="primary" preIcon="ant-design:edit-outlined">开启编辑模式</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="portalapp-sysAppVersion">
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { JUploadModal } from '@/components/Form/src/jeecg/components/JUpload';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import { reactive, ref, toRaw, unref, onMounted } from 'vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { queryAppVersion, saveAppVersion } from './appVersion.api';
|
||||
import { Description, DescItem } from '/@/components/Description/index';
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
const [registerModel, { openModal }] = useModal();
|
||||
const confirmLoading = ref(false);
|
||||
const active = ref(false);
|
||||
const formRef = ref<any>(null);
|
||||
const appKey = 'E0CC280';
|
||||
const filePath = 'appVersion';
|
||||
const uploadType = ref('');
|
||||
const modalValue = ref('');
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 16 },
|
||||
};
|
||||
const model = reactive({
|
||||
id: 'E0CC280',
|
||||
appVersion: '',
|
||||
versionNum: 0,
|
||||
updateNote: '',
|
||||
downloadUrl: '',
|
||||
wgtUrl: '',
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化表单数据
|
||||
* @param record
|
||||
*/
|
||||
async function initFormData() {
|
||||
const appVersion = await queryAppVersion({ key: appKey });
|
||||
if (appVersion) {
|
||||
Object.assign(model, appVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交保存版本信息
|
||||
*/
|
||||
function handleSubmit() {
|
||||
const form = unref(formRef);
|
||||
form.validate().then(async () => {
|
||||
let obj = toRaw(model);
|
||||
if (obj.appVersion.indexOf('.') != -1) {
|
||||
obj.versionNum = Number(obj.appVersion.replace(/\./g, ''));
|
||||
}
|
||||
obj.id = appKey;
|
||||
confirmLoading.value = true;
|
||||
await saveAppVersion(obj);
|
||||
createMessage.success('保存成功');
|
||||
confirmLoading.value = false;
|
||||
active.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示设置弹窗
|
||||
* @param type
|
||||
*/
|
||||
function showUploadModal(type) {
|
||||
uploadType.value = type;
|
||||
modalValue.value = type == 'apk' ? model.downloadUrl : model.wgtUrl;
|
||||
openModal(true, {
|
||||
maxCount: 1,
|
||||
bizPath: filePath,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*上传返回
|
||||
*/
|
||||
function uploadBack(value) {
|
||||
if (unref(uploadType) == 'apk') {
|
||||
model.downloadUrl = value;
|
||||
} else {
|
||||
model.wgtUrl = value;
|
||||
}
|
||||
}
|
||||
//表单校验规则
|
||||
const validatorRules = {
|
||||
appVersion: [{ required: true, message: '版本不能为空', trigger: 'blur' }],
|
||||
downloadUrl: [{ required: true, message: 'APP安装apk不能为空', trigger: 'change' }],
|
||||
wgtUrl: [{ required: true, message: 'APP热更新文件不能为空', trigger: 'change' }],
|
||||
};
|
||||
// 显示字段
|
||||
const schema: DescItem[] = [
|
||||
{
|
||||
field: 'appVersion',
|
||||
label: '版本',
|
||||
},
|
||||
{
|
||||
field: 'downloadUrl',
|
||||
label: 'APP安装apk',
|
||||
},
|
||||
{
|
||||
field: 'wgtUrl',
|
||||
label: 'APP热更新文件',
|
||||
},
|
||||
{
|
||||
field: 'updateNote',
|
||||
label: '更新内容',
|
||||
},
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
initFormData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.anty-form-btn {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.anty-form-btn button {
|
||||
margin: 20px;
|
||||
}
|
||||
.approveDiv span {
|
||||
margin: 0 20px;
|
||||
}
|
||||
.desc {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
:deep(.ant-descriptions-item-label) {
|
||||
width: 30% !important;
|
||||
min-width: 150px !important;
|
||||
}
|
||||
:deep(.ant-descriptions-item-content) {
|
||||
padding: 16px !important;
|
||||
width: 60% !important;
|
||||
}
|
||||
</style>
|
||||
20
jeecgboot-vue3/src/views/system/appVersion/appVersion.api.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
//查询app版本
|
||||
queryAppVersion = '/sys/version/app3version',
|
||||
//保存app版本
|
||||
saveAppVersion = '/sys/version/saveVersion',
|
||||
}
|
||||
/**
|
||||
* 查询APP版本
|
||||
* @param params
|
||||
*/
|
||||
export const queryAppVersion = (params) => defHttp.get({ url: Api.queryAppVersion, params });
|
||||
/**
|
||||
* 保存APP版本
|
||||
* @param params
|
||||
*/
|
||||
export const saveAppVersion = (params) => {
|
||||
return defHttp.post({ url: Api.saveAppVersion, params });
|
||||
};
|
||||
@ -10,6 +10,7 @@ enum Api {
|
||||
wechatEnterpriseToLocal = '/sys/thirdApp/sync/wechatEnterprise/departAndUser/toLocal',
|
||||
getThirdUserBindByWechat = '/sys/thirdApp/getThirdUserBindByWechat',
|
||||
deleteThirdAccount = '/sys/thirdApp/deleteThirdAccount',
|
||||
deleteThirdAppConfig = '/sys/thirdApp/deleteThirdAppConfig',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,4 +67,15 @@ export const getThirdUserBindByWechat = () => {
|
||||
*/
|
||||
export const deleteThirdAccount = (params) => {
|
||||
return defHttp.delete({ url: Api.deleteThirdAccount, params }, { isTransformResponse:false, joinParamsToUrl: true });
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据配置表的id删除第三方配置
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const deleteThirdAppConfig = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteThirdAppConfig, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<a-collapse-panel key="2">
|
||||
<template #header>
|
||||
<div style="width: 100%; justify-content: space-between; display: flex">
|
||||
<div style="font-size: 16px"> 2.对接信息录入</div>
|
||||
<div style="font-size: 16px"> 2.对接信息录入及解绑</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="base-desc">完成步骤1后,填入Agentld、 AppKey、AppSecret后 可对接应用与同步通讯录</div>
|
||||
@ -47,6 +47,7 @@
|
||||
</div>
|
||||
<div style="margin-top: 20px; width: 100%; text-align: right">
|
||||
<a-button @click="dingEditClick">编辑</a-button>
|
||||
<a-button v-if="appConfigData.id" @click="cancelBindClick" danger style="margin-left: 10px">取消绑定</a-button>
|
||||
</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
@ -76,7 +77,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, h, inject, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { getThirdConfigByTenantId, syncDingTalkDepartUserToLocal } from './ThirdApp.api';
|
||||
import { getThirdConfigByTenantId, syncDingTalkDepartUserToLocal, deleteThirdAppConfig } from './ThirdApp.api';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
@ -122,6 +123,8 @@
|
||||
let values = await getThirdConfigByTenantId(params);
|
||||
if (values) {
|
||||
appConfigData.value = values;
|
||||
} else {
|
||||
appConfigData.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,6 +217,25 @@
|
||||
function handleIconClick(){
|
||||
window.open("https://help.qiaoqiaoyun.com/expand/dingdingsyn.html","_target")
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消绑定
|
||||
*/
|
||||
function cancelBindClick() {
|
||||
if(!appConfigData.value.id){
|
||||
createMessage.warning("请先绑定钉钉应用!");
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '取消绑定',
|
||||
content: '是否要解除当前组织的钉钉应用配置绑定?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
deleteThirdAppConfig({ id: appConfigData.value.id }, handleSuccess);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let tenantId = getTenantId();
|
||||
@ -229,6 +251,7 @@
|
||||
syncDingTalk,
|
||||
btnLoading,
|
||||
handleIconClick,
|
||||
cancelBindClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<a-collapse-panel key="2">
|
||||
<template #header>
|
||||
<div style="width: 100%; justify-content: space-between; display: flex">
|
||||
<div style="font-size: 16px"> 2.对接信息录入</div>
|
||||
<div style="font-size: 16px"> 2.对接信息录入及解绑</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex-flow">
|
||||
@ -40,6 +40,7 @@
|
||||
</div>
|
||||
<div style="margin-top: 20px; width: 100%; text-align: right">
|
||||
<a-button @click="weEnterpriseEditClick">编辑</a-button>
|
||||
<a-button v-if="appConfigData.id" @click="cancelBindClick" danger style="margin-left: 10px">取消绑定</a-button>
|
||||
</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
@ -61,7 +62,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref } from 'vue';
|
||||
import { getThirdConfigByTenantId } from './ThirdApp.api';
|
||||
import { getThirdConfigByTenantId, deleteThirdAppConfig } from './ThirdApp.api';
|
||||
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
@ -97,6 +98,8 @@
|
||||
let values = await getThirdConfigByTenantId(params);
|
||||
if (values) {
|
||||
appConfigData.value = values;
|
||||
} else {
|
||||
appConfigData.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,6 +162,25 @@
|
||||
function seeBindWeChat() {
|
||||
openBindModal(true,{ izBind: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消绑定
|
||||
*/
|
||||
function cancelBindClick() {
|
||||
if(!appConfigData.value.id){
|
||||
createMessage.warning("请先绑定企业微信应用!");
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '取消绑定',
|
||||
content: '是否要解除当前组织的企业微信应用配置绑定?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
deleteThirdAppConfig({ id: appConfigData.value.id }, handleSuccess);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let tenantId = getTenantId();
|
||||
@ -175,6 +197,7 @@
|
||||
thirdUserByWechat,
|
||||
handleBindSuccess,
|
||||
seeBindWeChat,
|
||||
cancelBindClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" title="首页配置" @ok="handleSubmit" :width="600">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../home.data';
|
||||
import { saveOrUpdate } from '../home.api';
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(false);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 100,
|
||||
baseRowStyle: { marginTop: '10px' },
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
if (data.values.relationType == 'USER') {
|
||||
data.values.userCode = data.values.roleCode;
|
||||
}
|
||||
await setFieldsValue({
|
||||
...data.values,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
let values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
if(values.relationType == 'USER'){
|
||||
values.roleCode = values.userCode;
|
||||
}
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
55
jeecgboot-vue3/src/views/system/homeConfig/home.api.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/sys/sysRoleIndex/list',
|
||||
save = '/sys/sysRoleIndex/add',
|
||||
edit = '/sys/sysRoleIndex/edit',
|
||||
deleteIndex = '/sys/sysRoleIndex/delete',
|
||||
deleteBatch = '/sys/sysRoleIndex/deleteBatch',
|
||||
queryIndexByCode = '/sys/sysRoleIndex/queryByCode',
|
||||
}
|
||||
/**
|
||||
* 系统角色列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
export const deleteIndex = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteIndex, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除角色
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新首页配置
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
const url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 查询首页配置
|
||||
* @param params
|
||||
*/
|
||||
export const queryIndexByCode = (params) => defHttp.get({ url: Api.queryIndexByCode, params }, { isTransformResponse: false });
|
||||
129
jeecgboot-vue3/src/views/system/homeConfig/home.data.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
|
||||
//列配置
|
||||
export const columns = [
|
||||
{
|
||||
title: '关联类型(用户/角色)',
|
||||
dataIndex: 'relationType_dictText',
|
||||
width: 80,
|
||||
slots: { customRender: 'relationType' },
|
||||
},
|
||||
{
|
||||
title: '用户/角色编码',
|
||||
dataIndex: 'roleCode',
|
||||
width: 80,
|
||||
slots: { customRender: 'roleCode' },
|
||||
},
|
||||
{
|
||||
title: '首页路由',
|
||||
dataIndex: 'url',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '组件地址',
|
||||
dataIndex: 'component',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '是否开启',
|
||||
dataIndex: 'status',
|
||||
slots: { customRender: 'status' },
|
||||
width: 60,
|
||||
},
|
||||
];
|
||||
//查询配置
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'relationType',
|
||||
label: '关联类型',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'relation_type',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'route',
|
||||
label: '是否路由菜单',
|
||||
helpMessage: '非路由菜单设置成首页,需开启',
|
||||
component: 'Switch',
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: 'relationType',
|
||||
label: '关联类型',
|
||||
component: 'JDictSelectTag',
|
||||
required: true,
|
||||
defaultValue: 'ROLE',
|
||||
componentProps: {
|
||||
dictCode: 'relation_type',
|
||||
type: 'radioButton',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '角色编码',
|
||||
field: 'roleCode',
|
||||
component: 'JSelectRole',
|
||||
required: true,
|
||||
componentProps: {
|
||||
rowKey: 'roleCode',
|
||||
isRadioSelection: true,
|
||||
},
|
||||
ifShow: ({ values }) => values.relationType == 'ROLE',
|
||||
},
|
||||
{
|
||||
label: '用户编码',
|
||||
field: 'userCode',
|
||||
component: 'JSelectUser',
|
||||
required: true,
|
||||
componentProps: {
|
||||
isRadioSelection: true,
|
||||
},
|
||||
ifShow: ({ values }) => values.relationType == 'USER',
|
||||
},
|
||||
{
|
||||
label: '首页路由',
|
||||
field: 'url',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '组件地址',
|
||||
field: 'component',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入前端组件',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '优先级',
|
||||
field: 'priority',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
field: 'route',
|
||||
label: '是否路由菜单',
|
||||
helpMessage: '非路由菜单设置成首页,需开启',
|
||||
component: 'Switch',
|
||||
defaultValue: true,
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '是否开启',
|
||||
field: 'status',
|
||||
component: 'JSwitch',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
options: ['1', '0'],
|
||||
},
|
||||
},
|
||||
];
|
||||
126
jeecgboot-vue3/src/views/system/homeConfig/index.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate">新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined" /> 删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button>批量操作<Icon icon="mdi:chevron-down" /></a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
<template #status="{ text }">
|
||||
<a-tag color="pink" v-if="text == 0">禁用</a-tag>
|
||||
<a-tag color="#87d068" v-if="text == 1">启用</a-tag>
|
||||
</template>
|
||||
<template #relationType="{ text, record }">
|
||||
<span>{{ record.roleCode == 'DEF_INDEX_ALL' ? '--' : text }}</span>
|
||||
</template>
|
||||
<template #roleCode="{ text, record }">
|
||||
<span>{{ record.roleCode == 'DEF_INDEX_ALL' ? '菜单默认首页' : text }}</span>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--角色首页配置-->
|
||||
<HomeConfigModal @register="register" @success="reload" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="home-config" setup>
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import HomeConfigModal from './components/HomeConfigModal.vue';
|
||||
import { columns, searchFormSchema } from './home.data';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { list, deleteIndex, batchDelete } from './home.api';
|
||||
|
||||
//弹窗配置
|
||||
const [register, { openModal }] = useModal();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'home-config',
|
||||
tableProps: {
|
||||
title: '首页配置',
|
||||
api: list,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
labelAlign: 'left',
|
||||
labelWidth: 80,
|
||||
schemas: searchFormSchema,
|
||||
baseRowStyle: {
|
||||
marginLeft: '2px',
|
||||
},
|
||||
},
|
||||
actionColumn: {
|
||||
width: 80,
|
||||
},
|
||||
//自定义默认排序
|
||||
defSort: {
|
||||
column: 'id',
|
||||
order: 'desc',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, clearSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
async function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
async function handleEdit(record) {
|
||||
openModal(true, {
|
||||
isUpdate: true,
|
||||
values: record,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteIndex({ id: record.id }, () => {
|
||||
reload();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, () => {
|
||||
clearSelectedRowKeys();
|
||||
reload();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@ -344,7 +344,9 @@
|
||||
return;
|
||||
}
|
||||
//update-begin---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
|
||||
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD }).catch((res) =>{
|
||||
//update-begin---author:wangshuai---date:2025-07-15---for:【issues/8567】严重:修改密码存在水平越权问题:登录应该用登录模板不应该用忘记密码的模板---
|
||||
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.LOGIN }).catch((res) =>{
|
||||
//update-end---author:wangshuai---date:2025-07-15---for:【issues/8567】严重:修改密码存在水平越权问题:登录应该用登录模板不应该用忘记密码的模板---
|
||||
if(res.code === ExceptionEnum.PHONE_SMS_FAIL_CODE){
|
||||
openCaptchaModal(true, {});
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-list item-layout="horizontal" :data-source="messageList">
|
||||
<a-list item-layout="horizontal" :data-source="messageList" :locale="locale">
|
||||
<template #loadMore>
|
||||
<div
|
||||
v-if="messageList && messageList.length > 0 && !loadEndStatus && !loadingMoreStatus"
|
||||
@ -16,12 +16,23 @@
|
||||
</template>
|
||||
|
||||
<template #renderItem="{ item }">
|
||||
<a-list-item>
|
||||
<a-list-item :style="{ background: item?.izTop && item.izTop == 1 ? '#f7f7f7' : 'auto' }">
|
||||
<template #actions>
|
||||
<a-rate :value="item.starFlag=='1'?1:0" :count="1" @click="clickStar(item)" style="cursor: pointer" disabled />
|
||||
</template>
|
||||
|
||||
<a-list-item-meta :description="item.createTime">
|
||||
<!-- update-begin-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接。 -->
|
||||
<a-list-item-meta>
|
||||
<template #description>
|
||||
<div v-if="isFormComment(item)" style="background: #f7f7f7;color: #555;padding: 2px 5px;white-space:nowrap;overflow: hidden">
|
||||
<div v-html="getHtml(item.msgContent)"></div>
|
||||
</div>
|
||||
<div>
|
||||
{{item.createTime}}
|
||||
</div>
|
||||
</template>
|
||||
<!-- update-end-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接。 -->
|
||||
|
||||
<template #title>
|
||||
<div style="position: relative">
|
||||
<!-- <span style="display: inline-block; position: absolute; left: -16px">
|
||||
@ -29,16 +40,17 @@
|
||||
</span>-->
|
||||
|
||||
<span>{{ getMsgCategory(item) }}</span>
|
||||
<span v-if="item.busType == 'bpm'" class="bpm-cuiban-content" v-html="item.msgContent">
|
||||
<span v-if="item.busType == 'bpm' || item.busType == 'bpm_cc' || item.busType == 'msg_node' || item.busType == 'bpm_msg_node'" class="bpm-cuiban-content" v-html="item.msgContent">
|
||||
</span>
|
||||
<a-tooltip v-else>
|
||||
<template #title>
|
||||
<div v-html="item.msgContent"></div>
|
||||
</template>
|
||||
{{ item.titile }}
|
||||
</a-tooltip>
|
||||
<!-- <a-tooltip v-else>-->
|
||||
<!-- <template #title>-->
|
||||
<!-- <div v-html="item.msgContent"></div>-->
|
||||
<!-- </template>-->
|
||||
<!-- {{ item.titile }}-->
|
||||
<!-- </a-tooltip>-->
|
||||
<span v-else>{{ item.titile }}</span>
|
||||
|
||||
<a @click="showMessageDetail(item)" style="margin-left: 16px">查看详情</a>
|
||||
<a @click="showMessageDetail(item)" style="margin-left: 16px">{{ getHrefText(item) }}</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #avatar>
|
||||
@ -62,7 +74,7 @@
|
||||
</a-badge>
|
||||
<a-avatar v-else style="background: #79919d"><alert-outlined style="font-size: 16px"/></a-avatar>
|
||||
</template>
|
||||
|
||||
|
||||
<template v-else>
|
||||
<a-badge dot v-if="noRead(item)" class="msg-no-read">
|
||||
<a-avatar style="background: #79919d"><bell-filled style="font-size: 16px" title="未读消息"/></a-avatar>
|
||||
@ -74,14 +86,21 @@
|
||||
</a-list-item>
|
||||
</template>
|
||||
</a-list>
|
||||
|
||||
<!-- update-begin-author:liusq date:2023-10-26 for: [QQYUN-6713]系统通知打开弹窗修改 -->
|
||||
<keep-alive>
|
||||
<component v-if="currentModal" v-bind="bindParams" :key="currentModal" :is="currentModal" @register="modalRegCache[currentModal].register" />
|
||||
</keep-alive>
|
||||
<!-- update-end-author:liusq date:2023-10-26 for: [QQYUN-6713]系统通知打开弹窗修改 -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { FilterOutlined, CloseOutlined, BellFilled, ExclamationOutlined, MailOutlined,InteractionOutlined, AlertOutlined } from '@ant-design/icons-vue';
|
||||
import { useSysMessage, useMessageHref } from './useSysMessage';
|
||||
|
||||
|
||||
import {getGloablEmojiIndex, useEmojiHtml} from "/@/components/jeecg/comment/useComment";
|
||||
import { ref, h, watch } from "vue";
|
||||
|
||||
export default {
|
||||
name: 'SysMessageList',
|
||||
components: {
|
||||
@ -91,23 +110,41 @@
|
||||
ExclamationOutlined,
|
||||
MailOutlined,
|
||||
InteractionOutlined,
|
||||
AlertOutlined
|
||||
AlertOutlined,
|
||||
},
|
||||
props:{
|
||||
star: {
|
||||
type:Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
isLowApp:{
|
||||
type:Boolean,
|
||||
default: false
|
||||
},
|
||||
messageCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
cancelStarAfterDel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits:['close', 'detail'],
|
||||
emits:['close', 'detail', 'clear', 'close-modal'],
|
||||
setup(props, {emit}){
|
||||
const { messageList,loadEndStatus,loadingMoreStatus,onLoadMore,noRead, getMsgCategory, searchParams, reset, loadData, updateStarMessage } = useSysMessage();
|
||||
|
||||
const { messageList,loadEndStatus,loadingMoreStatus,onLoadMore,noRead, getMsgCategory, getHrefText, searchParams, reset, loadData, updateStarMessage } = useSysMessage(setLocaleText);
|
||||
|
||||
//系统消息
|
||||
const messageCount = ref(0);
|
||||
|
||||
function reload(params){
|
||||
let { fromUser, rangeDateKey, rangeDate } = params;
|
||||
let { fromUser, rangeDateKey, rangeDate, noticeType } = params;
|
||||
searchParams.fromUser = fromUser||'';
|
||||
searchParams.rangeDateKey = rangeDateKey||'';
|
||||
searchParams.rangeDate = rangeDate||[];
|
||||
searchParams.noticeType = noticeType || '';
|
||||
//list列表为空时赋初始值
|
||||
locale.value = { locale: { emptyText: `<a-empty />` }};
|
||||
if(props.star===true){
|
||||
searchParams.starFlag = '1'
|
||||
}else{
|
||||
@ -116,25 +153,84 @@
|
||||
reset();
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
||||
function clickStar(item){
|
||||
console.log(item)
|
||||
updateStarMessage(item);
|
||||
// update-begin--author:liaozhiyang---date:20240717---for:【TV360X-349】通知-标星消息tab列表取消标星后,该条信息从标星列表移除
|
||||
if (item.starFlag == '1' && props.cancelStarAfterDel) {
|
||||
const findIndex = messageList.value.findIndex((item) => item.id === item.id);
|
||||
if (findIndex !== -1) {
|
||||
messageList.value.splice(findIndex, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// update-end--author:liaozhiyang---date:20240717---for:【TV360X-349】通知-标星消息tab列表取消标星后,该条信息从标星列表移除
|
||||
if(item.starFlag=='1'){
|
||||
item.starFlag = '0'
|
||||
}else{
|
||||
item.starFlag = '1'
|
||||
}
|
||||
}
|
||||
|
||||
const { goPage } = useMessageHref(emit);
|
||||
|
||||
|
||||
// update-begin-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
|
||||
const { goPage, currentModal, modalRegCache, bindParams, isFormComment } = useMessageHref(emit, props);
|
||||
//const emojiIndex = inject('$globalEmojiIndex')
|
||||
const emojiIndex = getGloablEmojiIndex()
|
||||
const { getHtml } = useEmojiHtml(emojiIndex);
|
||||
// update-end-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
|
||||
|
||||
function showMessageDetail(record){
|
||||
record.readFlag = '1'
|
||||
goPage(record);
|
||||
emit('close', record.id)
|
||||
//update-begin---author:wangshuai---date:2024-06-11---for:【TV360X-791】收到邮件通知,点击回复,应该把通知公告列表关闭---
|
||||
if(record.busType==='email'){
|
||||
emit('close-modal')
|
||||
}
|
||||
//update-end---author:wangshuai---date:2024-06-11---for:【TV360X-791】收到邮件通知,点击回复,应该把通知公告列表关闭---
|
||||
}
|
||||
|
||||
//返回list列表为空数据时展示的内容
|
||||
const locale = ref({});
|
||||
|
||||
/**
|
||||
* 未读点击事件
|
||||
*/
|
||||
function noReadClick() {
|
||||
emit('clear')
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置list为空的时候提示文本
|
||||
*
|
||||
*/
|
||||
function setLocaleText() {
|
||||
//update-begin---author:wangshuai---date:2024-04-24---for:【QQYUN-9105】未读有问题---
|
||||
let rangeDateKey = searchParams.rangeDateKey;
|
||||
let value = messageCount.value;
|
||||
if (value > 0 && !props.star && rangeDateKey && rangeDateKey === '7day') {
|
||||
//update-end---author:wangshuai---date:2024-04-24---for:【QQYUN-9105】未读有问题---
|
||||
locale.value = {
|
||||
emptyText: h(
|
||||
'span',
|
||||
{
|
||||
style: {'color': 'rgb(255,154,0)', 'cursor': 'pointer', 'text-align': 'left', 'display': 'block'},
|
||||
onClick: () => {
|
||||
noReadClick();
|
||||
},
|
||||
}, `还剩余未读消息(${value > 99 ? '99+' : value})`)
|
||||
}
|
||||
} else {
|
||||
locale.value = { locale: {emptyText: `<a-empty />` }};
|
||||
}
|
||||
}
|
||||
|
||||
//监听信息数量
|
||||
watch(() => props.messageCount, (value) => {
|
||||
messageCount.value = value;
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
messageList,
|
||||
loadEndStatus,
|
||||
@ -142,11 +238,18 @@
|
||||
onLoadMore,
|
||||
noRead,
|
||||
getMsgCategory,
|
||||
getHrefText,
|
||||
reload,
|
||||
clickStar,
|
||||
showMessageDetail
|
||||
}
|
||||
}
|
||||
showMessageDetail,
|
||||
isFormComment,
|
||||
getHtml,
|
||||
modalRegCache,
|
||||
currentModal,
|
||||
bindParams,
|
||||
locale,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
<a-button v-else type="dashed" shape="circle" @click="openSelectPerson">
|
||||
<plus-outlined />
|
||||
</a-button>
|
||||
|
||||
|
||||
</span>
|
||||
</div>
|
||||
<div class="search-date">
|
||||
@ -81,14 +81,32 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-date">
|
||||
<div class="date-label">类型:</div>
|
||||
<div class="date-tags">
|
||||
<div class="tags-container">
|
||||
<div v-for="item in noticeTypeOption" :class="item.active == true ? 'tag active flex' : 'tag flex'" @click="handleClickNoticeType(item)">
|
||||
<img class="notice-type-img" v-if="item.img" :src="item.img" />
|
||||
{{ item.text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<span v-if="conditionStr" class="anticon filtera">
|
||||
<filter-outlined />
|
||||
<span style="font-size:12px;margin-left: 3px">{{conditionStr}}</span>
|
||||
<span style="display: flex;margin:0 5px;"><close-outlined style="font-size: 12px" @click="clearAll"/></span>
|
||||
<img v-if="noticeImg" :src="noticeImg" class="notice-type-header-img">
|
||||
<filter-outlined v-else/>
|
||||
<span style="font-size:12px;margin-left: 3px;position: relative;">{{conditionStr}}</span>
|
||||
<span style="display: flex;margin:0 5px;">
|
||||
<svg @click="clearAll" t="1715689724802" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10694" width="14" height="14"><path d="M624.593455 23.272727a93.090909 93.090909 0 0 1 93.090909 93.090909v168.587637l143.406545 0.023272a116.363636 116.363636 0 0 1 116.247273 111.313455l0.116363 5.050182V861.090909a116.363636 116.363636 0 0 1-116.363636 116.363636H162.909091a116.363636 116.363636 0 0 1-116.363636-116.363636V401.338182a116.363636 116.363636 0 0 1 116.363636-116.363637l146.664727-0.023272V116.363636a93.090909 93.090909 0 0 1 88.459637-92.974545l4.654545-0.116364zM139.636364 581.818182v279.272727a23.272727 23.272727 0 0 0 23.272727 23.272727h302.545454v-162.909091a46.545455 46.545455 0 1 1 93.09091 0v162.909091h93.090909v-162.909091a46.545455 46.545455 0 1 1 93.090909 0v162.909091h116.363636a23.272727 23.272727 0 0 0 23.272727-23.272727V581.818182H139.636364z m0-93.090909h744.727272v-87.389091a23.272727 23.272727 0 0 0-23.272727-23.272727h-166.679273a69.818182 69.818182 0 0 1-69.818181-69.818182V116.363636h-221.905455v191.883637a69.818182 69.818182 0 0 1-69.818182 69.818182H162.909091a23.272727 23.272727 0 0 0-23.272727 23.272727V488.727273z" fill="currentColor" p-id="10695"></path></svg>
|
||||
</span>
|
||||
</span>
|
||||
<filter-outlined v-else/>
|
||||
<div v-else style="align-content: center;">
|
||||
<img v-if="noticeImg" :src="noticeImg" class="notice-type-header-img" style="position: relative;top: -2px">
|
||||
<filter-outlined v-else />
|
||||
</div>
|
||||
</a-popover>
|
||||
<close-outlined @click="closeModal" />
|
||||
</div>
|
||||
@ -103,12 +121,12 @@
|
||||
</template>
|
||||
|
||||
<a-tab-pane tab="全部消息" key="all" forceRender>
|
||||
<sys-message-list ref="allMessageRef" @close="hrefThenClose" @detail="showDetailModal"/>
|
||||
<sys-message-list :isLowApp="isLowApp" ref="allMessageRef" @close="hrefThenClose" @detail="showDetailModal" @clear="clearAll" :messageCount="messageCount" @closeModal="closeModal"/>
|
||||
</a-tab-pane>
|
||||
|
||||
<!-- 标星 -->
|
||||
<a-tab-pane tab="标星消息" key="star" forceRender>
|
||||
<sys-message-list ref="starMessageRef" star @close="hrefThenClose" @detail="showDetailModal"/>
|
||||
<sys-message-list :isLowApp="isLowApp" ref="starMessageRef" star @close="hrefThenClose" @detail="showDetailModal" @clear="clearAll" :messageCount="messageCount" @closeModal="closeModal" :cancelStarAfterDel="true"/>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
@ -116,7 +134,7 @@
|
||||
|
||||
<user-select-modal isRadioSelection :showButton="false" labelKey="realname" rowKey="username" @register="regModal" @getSelectResult="getSelectedUser"></user-select-modal>
|
||||
|
||||
<DetailModal @register="registerDetail" :zIndex="1001"/>
|
||||
<DetailModal @register="registerDetail" :zIndex="1001" @close="handleDetailColse"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -128,7 +146,10 @@
|
||||
import UserSelectModal from '/@/components/Form/src/jeecg/components/modal/UserSelectModal.vue'
|
||||
import DetailModal from '/@/views/monitor/mynews/DetailModal.vue';
|
||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||
|
||||
import calendar from '/@/assets/icons/calendarNotice.png';
|
||||
import folder from '/@/assets/icons/folderNotice.png';
|
||||
import system from '/@/assets/icons/systemNotice.png';
|
||||
import flow from '/@/assets/icons/flowNotice.png';
|
||||
export default {
|
||||
name: 'SysMessageModal',
|
||||
components: {
|
||||
@ -138,16 +159,35 @@
|
||||
BellFilled,
|
||||
ExclamationOutlined,
|
||||
JSelectUser,
|
||||
// update-begin--author:liaozhiyang---date:20240308---for:【QQYUN-8241】emoji-mart-vue-fast库异步加载
|
||||
SysMessageList: createAsyncComponent(() => import('./SysMessageList.vue')),
|
||||
// SysMessageList,
|
||||
// update-end--author:liaozhiyang---date:20240308---for:【QQYUN-8241】emoji-mart-vue-fast库异步加载
|
||||
UserSelectModal,
|
||||
PlusOutlined,
|
||||
DetailModal
|
||||
},
|
||||
props:{
|
||||
messageCount: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
emits:['register', 'refresh'],
|
||||
setup(_p, {emit}) {
|
||||
const allMessageRef = ref();
|
||||
const starMessageRef = ref();
|
||||
const activeKey = ref('all');
|
||||
//通知类型
|
||||
const noticeType = ref('');
|
||||
//通知类型数组
|
||||
const noticeTypeOption = reactive([
|
||||
{ key: 'system', text: '系统通知', active: false, img: system },
|
||||
{ key: 'flow', text: '流程通知', active: false, img: flow },
|
||||
{ key: 'plan', text: '日程通知', active: false, img: calendar },
|
||||
{ key: 'file', text: '知识通知', active: false, img: folder },
|
||||
]);
|
||||
const noticeImg = ref('');
|
||||
function handleChangeTab(e, key) {
|
||||
activeKey.value = key;
|
||||
loadData();
|
||||
@ -155,7 +195,7 @@
|
||||
function handleChangePanel(key) {
|
||||
activeKey.value = key;
|
||||
}
|
||||
|
||||
|
||||
// 查询区域存储值
|
||||
const searchParams = reactive({
|
||||
fromUser: '',
|
||||
@ -169,6 +209,7 @@
|
||||
fromUser: searchParams.fromUser,
|
||||
rangeDateKey: searchParams.rangeDateKey,
|
||||
rangeDate: searchParams.rangeDate,
|
||||
noticeType: noticeType.value ? noticeType.value:''
|
||||
}
|
||||
if(activeKey.value == 'all'){
|
||||
getRefPromise(allMessageRef).then(() => {
|
||||
@ -178,15 +219,36 @@
|
||||
starMessageRef.value.reload(params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const isLowApp = ref(false);
|
||||
//useModalInner
|
||||
const [registerModal, { closeModal }] = useModalInner(async (data) => {
|
||||
showSearch.value = false
|
||||
if(data.noticeType){
|
||||
noticeType.value = data.noticeType;
|
||||
//update-begin---author:wangshuai---date:2025-07-01---for:【QQYUN-12998】点击完聊天的系统图标,再点击系统上面的铃铛就不出数据了---
|
||||
for (const item of noticeTypeOption) {
|
||||
if(item.key === data.noticeType){
|
||||
item.active = true;
|
||||
noticeImg.value = item.img;
|
||||
}else{
|
||||
item.active = false;
|
||||
}
|
||||
}
|
||||
//update-end---author:wangshuai---date:2025-07-01---for:【QQYUN-12998】点击完聊天的系统图标,再点击系统上面的铃铛就不出数据了---
|
||||
delete data.noticeType;
|
||||
}
|
||||
//每次弹窗打开 加载最新的数据
|
||||
loadData();
|
||||
if(data){
|
||||
isLowApp.value = data.isLowApp||false
|
||||
}else{
|
||||
isLowApp.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const showSearch = ref(false);
|
||||
|
||||
|
||||
function handleChangeSearchPerson(value, a) {
|
||||
console.log('选择改变', value, a);
|
||||
showSearch.value = true;
|
||||
@ -239,12 +301,12 @@
|
||||
searchParams.rangeDate = [...dateStringArray]
|
||||
loadData();
|
||||
}
|
||||
|
||||
|
||||
function hrefThenClose(id){
|
||||
emit('refresh', id)
|
||||
// closeModal();
|
||||
}
|
||||
|
||||
|
||||
// 有查询条件值的时候显示该字符串
|
||||
const conditionStr = computed(()=>{
|
||||
const { fromUser, rangeDateKey, realname } = searchParams;
|
||||
@ -273,16 +335,32 @@
|
||||
searchParams.realname = options[0].label;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function openSelectPerson(){
|
||||
openModal(true, {})
|
||||
}
|
||||
|
||||
|
||||
function clearSearchParamsUser(){
|
||||
searchParams.fromUser = ''
|
||||
searchParams.realname = ''
|
||||
}
|
||||
|
||||
function clearAll(){
|
||||
searchParams.fromUser='';
|
||||
searchParams.realname='';
|
||||
searchParams.rangeDateKey='';
|
||||
searchParams.rangeDate=[];
|
||||
for (let a of dateTags) {
|
||||
a.active = false;
|
||||
}
|
||||
noticeType.value = "";
|
||||
noticeImg.value = "";
|
||||
for (const item of noticeTypeOption) {
|
||||
item.active = false;
|
||||
}
|
||||
loadData();
|
||||
}
|
||||
|
||||
function getRefPromise(componentRef) {
|
||||
return new Promise((resolve) => {
|
||||
(function next() {
|
||||
@ -297,22 +375,36 @@
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
function clearAll(){
|
||||
searchParams.fromUser='';
|
||||
searchParams.realname='';
|
||||
searchParams.rangeDateKey='';
|
||||
searchParams.rangeDate=[];
|
||||
for (let a of dateTags) {
|
||||
a.active = false;
|
||||
}
|
||||
loadData();
|
||||
}
|
||||
|
||||
const [registerDetail, { openModal: openDetailModal }] = useModal();
|
||||
function showDetailModal(record){
|
||||
openDetailModal(true, {record: unref(record), isUpdate: true})
|
||||
}
|
||||
|
||||
function handleDetailColse(){
|
||||
loadData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 只是通知
|
||||
* @param item
|
||||
*/
|
||||
function handleClickNoticeType(item) {
|
||||
for (let a of noticeTypeOption) {
|
||||
if(a.key !== item.key){
|
||||
a.active = false;
|
||||
}
|
||||
}
|
||||
item.active = !item.active;
|
||||
if(item.active === false){
|
||||
noticeType.value = "";
|
||||
noticeImg.value = "";
|
||||
}else{
|
||||
noticeType.value = item.key;
|
||||
noticeImg.value = item.img;
|
||||
}
|
||||
loadData();
|
||||
}
|
||||
|
||||
return {
|
||||
conditionStr,
|
||||
regModal,
|
||||
@ -320,7 +412,7 @@
|
||||
openSelectPerson,
|
||||
clearSearchParamsUser,
|
||||
clearAll,
|
||||
|
||||
|
||||
registerModal,
|
||||
activeKey,
|
||||
handleChangePanel,
|
||||
@ -340,8 +432,12 @@
|
||||
allMessageRef,
|
||||
starMessageRef,
|
||||
registerDetail,
|
||||
showDetailModal
|
||||
|
||||
showDetailModal,
|
||||
isLowApp,
|
||||
handleDetailColse,
|
||||
noticeTypeOption,
|
||||
handleClickNoticeType,
|
||||
noticeImg,
|
||||
};
|
||||
},
|
||||
};
|
||||
@ -354,7 +450,7 @@
|
||||
100%{transform:translateY(600px);}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.sys-msg-modal {
|
||||
.ant-modal-header {
|
||||
padding-bottom: 0;
|
||||
@ -383,13 +479,13 @@
|
||||
display: inline-block;
|
||||
width: 220px;
|
||||
vertical-align: top;
|
||||
|
||||
|
||||
.icons {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
|
||||
|
||||
> span.anticon {
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
@ -407,7 +503,7 @@
|
||||
line-height: 25px;
|
||||
//color: #2196f3;
|
||||
display: flex;
|
||||
|
||||
|
||||
>span.anticon{
|
||||
height: auto;
|
||||
line-height: 9px;
|
||||
@ -415,7 +511,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
.ant-tabs-nav-wrap {
|
||||
@ -521,3 +617,23 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped>
|
||||
.notice-type-img{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
margin-right: 1px;
|
||||
}
|
||||
.notice-type-header-img{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
left: 2px;
|
||||
top: 1px;
|
||||
}
|
||||
.flex{
|
||||
display: flex;
|
||||
flex: unset;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, nextTick } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { getDictItemsByCode } from '/@/utils/dict/index';
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
@ -18,8 +18,10 @@ const queryMessageList = (params) => {
|
||||
|
||||
/**
|
||||
* 获取消息列表数据
|
||||
*
|
||||
* setLocaleText 设置未读消息
|
||||
*/
|
||||
export function useSysMessage() {
|
||||
export function useSysMessage(setLocaleText) {
|
||||
const { createMessage } = useMessage();
|
||||
const rangeDateArray = getDictItemsByCode('rangeDate');
|
||||
console.log('+++++++++++++++++++++');
|
||||
@ -29,17 +31,18 @@ export function useSysMessage() {
|
||||
const messageList = ref<any[]>([]);
|
||||
const pageNo = ref(1)
|
||||
let pageSize = 10;
|
||||
|
||||
|
||||
const searchParams = reactive({
|
||||
fromUser: '',
|
||||
rangeDateKey: '',
|
||||
rangeDate: [],
|
||||
starFlag: ''
|
||||
starFlag: '',
|
||||
noticeType: ''
|
||||
});
|
||||
|
||||
|
||||
function getQueryParams() {
|
||||
let { fromUser, rangeDateKey, rangeDate, starFlag } = searchParams;
|
||||
let { fromUser, rangeDateKey, rangeDate, starFlag, noticeType } = searchParams;
|
||||
let params = {
|
||||
fromUser,
|
||||
starFlag,
|
||||
@ -47,7 +50,8 @@ export function useSysMessage() {
|
||||
beginDate: '',
|
||||
endDate: '',
|
||||
pageNo: pageNo.value,
|
||||
pageSize
|
||||
pageSize,
|
||||
noticeType
|
||||
};
|
||||
if (rangeDateKey == 'zdy') {
|
||||
params.beginDate = rangeDate[0]+' 00:00:00';
|
||||
@ -58,7 +62,7 @@ export function useSysMessage() {
|
||||
|
||||
// 数据是否加载完了
|
||||
const loadEndStatus = ref(false);
|
||||
|
||||
|
||||
//请求数据
|
||||
async function loadData() {
|
||||
if(loadEndStatus.value === true){
|
||||
@ -69,6 +73,7 @@ export function useSysMessage() {
|
||||
console.log('获取结果', data);
|
||||
if(!data || data.length<=0){
|
||||
loadEndStatus.value = true;
|
||||
setLocaleText();
|
||||
return;
|
||||
}
|
||||
if(data.length<pageSize){
|
||||
@ -78,6 +83,7 @@ export function useSysMessage() {
|
||||
let temp:any[] = messageList.value;
|
||||
temp.push(...data);
|
||||
messageList.value = temp;
|
||||
setLocaleText();
|
||||
}
|
||||
|
||||
//重置
|
||||
@ -86,7 +92,7 @@ export function useSysMessage() {
|
||||
pageNo.value = 1;
|
||||
loadEndStatus.value = false;
|
||||
}
|
||||
|
||||
|
||||
//标星
|
||||
async function updateStarMessage(item){
|
||||
const url = '/sys/sysAnnouncementSend/edit';
|
||||
@ -139,7 +145,27 @@ export function useSysMessage() {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
// QQYUN-4472 来消息了没有提醒--查看详情改为去处理
|
||||
function getHrefText(item) {
|
||||
if(item.busType === 'bpm'|| item.busType === 'bpm_task' || item.busType === 'tenant_invite'){
|
||||
//判断是否是查看详情
|
||||
if (item.msgAbstract) {
|
||||
try {
|
||||
const json = JSON.parse(item.msgAbstract);
|
||||
if (json.taskDetail) {
|
||||
return '查看详情';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('getHrefText:msgAbstract参数不是JSON格式', item.msgAbstract);
|
||||
}
|
||||
}
|
||||
return '去处理'
|
||||
}else{
|
||||
return '查看详情'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messageList,
|
||||
reset,
|
||||
@ -147,11 +173,11 @@ export function useSysMessage() {
|
||||
loadEndStatus,
|
||||
searchParams,
|
||||
updateStarMessage,
|
||||
|
||||
onLoadMore,
|
||||
noRead,
|
||||
getMsgCategory,
|
||||
|
||||
getHrefText
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@ -159,14 +185,115 @@ export function useSysMessage() {
|
||||
* 用于消息跳转
|
||||
*/
|
||||
export function useMessageHref(emit, props){
|
||||
//const [registerHistoryModal, { openModal: openHistoryModal }] = useModal();
|
||||
//const [registerTaskModal, { openModal: openTaskModal }] = useModal();
|
||||
// 注册表单弹窗
|
||||
//const [registerDesignFormModal, { openModal: openDesignFormModal }] = useModal();
|
||||
const messageHrefArray: any[] = getDictItemsByCode('messageHref');
|
||||
const router = useRouter();
|
||||
const appStore = useAppStore();
|
||||
const rt = useRoute();
|
||||
const { close: closeTab, closeSameRoute } = useTabs();
|
||||
// const defaultPath = '/monitor/mynews';
|
||||
|
||||
//*********************************[QQYUN-6713]系统通知打开弹窗修改,动态设置弹窗begin******************************************
|
||||
//当前表单弹窗
|
||||
const currentModal = ref<string | null>(null);
|
||||
//当前表单参数
|
||||
const modalParams = ref<Recordable>({});
|
||||
//表单注册缓存
|
||||
const modalRegCache = ref<Recordable>({});
|
||||
//组件绑定参数
|
||||
const bindParams = ref<Recordable>({});
|
||||
|
||||
/**
|
||||
* 根据类型打开不同弹窗
|
||||
* @param type
|
||||
* @param params
|
||||
*/
|
||||
async function handleOpenType(type, params) {
|
||||
currentModal.value = null;
|
||||
modalParams.value = { ...params };
|
||||
switch (type) {
|
||||
case 'task':
|
||||
//流程办理
|
||||
bindParams.value = { actionType: 'todo' };
|
||||
currentModal.value = 'ProcessTaskHandleModal';
|
||||
break;
|
||||
case 'history':
|
||||
bindParams.value = {};
|
||||
//历史流程
|
||||
currentModal.value = 'MyTaskHandleModal';
|
||||
break;
|
||||
case 'design':
|
||||
//表单设计
|
||||
currentModal.value = 'DesformViewModal';
|
||||
bindParams.value = {
|
||||
showRecordCopy: false,
|
||||
showRecordShare: false,
|
||||
showRecordSysPrint: false,
|
||||
showDesignFormBtn: false,
|
||||
};
|
||||
break;
|
||||
case 'cgform':
|
||||
//Online表单
|
||||
currentModal.value = 'OnlineAutoModal';
|
||||
bindParams.value = {
|
||||
id: params.formId,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
currentModal.value = null;
|
||||
break;
|
||||
}
|
||||
//注册表单弹窗
|
||||
initModalRegister();
|
||||
await nextTick(() => {
|
||||
if (modalRegCache.value[currentModal.value!]?.isRegister) {
|
||||
console.log('已注冊,走缓存');
|
||||
modalRegCache.value[currentModal.value!].modalMethods.openModal(true, modalParams.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化弹窗注册
|
||||
*/
|
||||
function initModalRegister() {
|
||||
//如果当前选择表单为null,就不处理
|
||||
if (!currentModal.value) {
|
||||
return;
|
||||
}
|
||||
//判断缓存中是否存在,不存在就走缓存逻辑
|
||||
if (!modalRegCache.value[currentModal.value]) {
|
||||
const [registerModal, modalMethods] = useModal();
|
||||
modalRegCache.value[currentModal.value] = {
|
||||
isRegister: false,
|
||||
register: bindRegisterModal(registerModal, modalMethods),
|
||||
modalMethods,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定注册弹窗
|
||||
* @param regFn
|
||||
* @param modalMethod
|
||||
*/
|
||||
function bindRegisterModal(regFn, modalMethod) {
|
||||
return async (...args) => {
|
||||
console.log('开始注册:', currentModal.value);
|
||||
await regFn(...args);
|
||||
console.log('注册完成:', currentModal.value);
|
||||
//打开弹窗
|
||||
modalMethod.openModal(true, modalParams.value);
|
||||
//设置缓存标识
|
||||
modalRegCache.value[currentModal.value!].isRegister = true;
|
||||
};
|
||||
}
|
||||
//*************************************[QQYUN-6713]系统通知打开弹窗修改,动态设置弹窗end*********************************************
|
||||
// const defaultPath = '/monitor/mynews';
|
||||
//const bpmPath = '/task/handle/'
|
||||
|
||||
|
||||
async function goPage(record, openModalFun?){
|
||||
if(!record.busType || record.busType == 'msg_node'){
|
||||
if(!openModalFun){
|
||||
@ -176,8 +303,38 @@ export function useMessageHref(emit, props){
|
||||
// 从消息页面列表点击详情查看 直接打开modal
|
||||
openModalFun()
|
||||
}
|
||||
// update-begin-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
|
||||
}else if(record.busType == 'comment'){
|
||||
// de
|
||||
let msgAbstract = record.msgAbstract;
|
||||
if(msgAbstract){
|
||||
try {
|
||||
let data = JSON.parse(msgAbstract.toString());
|
||||
if(data.type == 'designForm'){
|
||||
showDesignFormModal(data);
|
||||
} else {
|
||||
showOnlineCgformModal(data);
|
||||
}
|
||||
}catch (e) {
|
||||
console.error('打开评论表单,但是msgAbstract参数不是JSON格式', msgAbstract)
|
||||
if(openModalFun){
|
||||
openModalFun();
|
||||
}
|
||||
}
|
||||
}
|
||||
// update-end-author:taoyan date:2023-5-10 for: QQYUN-4744【系统通知】6、系统通知@人后,对方看不到是哪个表单@的,没有超链接
|
||||
}else if(record.busType == 'tenant_invite'){
|
||||
if(props.isLowApp===true){
|
||||
router.push({ name:"myapps-settings-user", query:{ page:'tenantSetting' }})
|
||||
}else{
|
||||
router.push({ name:"system-usersetting", query:{ page:'tenantSetting' }})
|
||||
}
|
||||
}else{
|
||||
await goPageWithBusType(record)
|
||||
if(props && props.isLowApp===true){
|
||||
openLowAppFlowModal(record)
|
||||
}else{
|
||||
await goPageWithBusType(record)
|
||||
}
|
||||
}
|
||||
/* busId: "1562035005173587970"
|
||||
busType: "email"
|
||||
@ -185,6 +342,95 @@ export function useMessageHref(emit, props){
|
||||
openType: "component"*/
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开表单设计器 表单弹窗
|
||||
* @param data
|
||||
*/
|
||||
function showDesignFormModal(data) {
|
||||
handleOpenType('design', {
|
||||
mode: 'detail',
|
||||
desformCode: data.code,
|
||||
dataId: data.dataId,
|
||||
isOnline: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开Online表单 弹窗
|
||||
* @param data
|
||||
*/
|
||||
function showOnlineCgformModal(data) {
|
||||
handleOpenType('cgform', {
|
||||
formId: data.formId,
|
||||
isUpdate: true,
|
||||
disableSubmit: true,
|
||||
record: {
|
||||
id: data.dataId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是不是表单的评论消息
|
||||
* @param record
|
||||
*/
|
||||
function isFormComment(record) {
|
||||
if(record.busType == 'comment'){
|
||||
let msgAbstract = record.msgAbstract;
|
||||
if(msgAbstract){
|
||||
try {
|
||||
let data = JSON.parse(msgAbstract);
|
||||
if(['cgform', 'designForm'].includes(data.type)){
|
||||
return true
|
||||
}
|
||||
}catch (e) {
|
||||
console.error('打开评论表单,但是msgAbstract参数不是JSON格式', msgAbstract)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果是工作流任务 在lowApp中 直接打开modal
|
||||
*/
|
||||
function openLowAppFlowModal(record){
|
||||
const { busType, busId, msgAbstract } = record;
|
||||
let temp = messageHrefArray.filter(item=>item.value === busType);
|
||||
if(!temp || temp.length==0){
|
||||
console.error('当前业务类型不识别', busType);
|
||||
return;
|
||||
}
|
||||
if(busType.indexOf('bpm')<0){
|
||||
console.error('low-app不支持跳转邮箱', busType);
|
||||
return;
|
||||
}
|
||||
//固定参数 detailId 用于查询表单数据
|
||||
let query:any = {
|
||||
detailId: busId
|
||||
};
|
||||
// 额外参数处理
|
||||
if(msgAbstract){
|
||||
try {
|
||||
let json = JSON.parse(msgAbstract);
|
||||
Object.keys(json).map(k=>{
|
||||
query[k] = json[k]
|
||||
});
|
||||
}catch (e) {
|
||||
console.error('msgAbstract参数不是JSON格式', msgAbstract)
|
||||
}
|
||||
}
|
||||
console.log("busType = ", busType)
|
||||
handleOpenType('task', {
|
||||
record: {
|
||||
id: busId,
|
||||
procInsId: query.procInsId,
|
||||
processDefinitionId: query.processDefinitionId,
|
||||
isDetail: query.taskDetail || 'bpm_cc' == busType
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据busType不同跳转不同页面
|
||||
* @param record
|
||||
@ -213,14 +459,19 @@ export function useMessageHref(emit, props){
|
||||
console.error('msgAbstract参数不是JSON格式', msgAbstract)
|
||||
}
|
||||
}
|
||||
// 跳转路由
|
||||
appStore.setMessageHrefParams(query);
|
||||
if(rt.path.indexOf(path)>=0){
|
||||
await closeTab();
|
||||
await router.replace({ path: path, query:{ time: new Date().getTime() } });
|
||||
if(query.taskDetail){
|
||||
// 查看任务详情的弹窗
|
||||
await showHistory(query.procInsId)
|
||||
}else{
|
||||
closeSameRoute(path)
|
||||
await router.push({ path: path });
|
||||
// 跳转路由
|
||||
appStore.setMessageHrefParams(query);
|
||||
if(rt.path.indexOf(path)>=0){
|
||||
await closeTab();
|
||||
await router.replace({ path: path, query:{ time: new Date().getTime() } });
|
||||
}else{
|
||||
closeSameRoute(path)
|
||||
await router.push({ path: path });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,8 +483,84 @@ export function useMessageHref(emit, props){
|
||||
//没有定义业务类型 直接跳转我的消息页面
|
||||
emit('detail', record)
|
||||
}
|
||||
|
||||
|
||||
//===============================================================================================================
|
||||
//update-begin-author:taoyan date:2022-12-31 for: QQYUN-3485 【查看流程】做一个查看页面,非办理页面,只通过流程实例参数即可
|
||||
async function showHistory(processInstanceId) {
|
||||
let { formData, formUrl } = await getTaskInfoForHistory({ processInstanceId });
|
||||
formData['PROCESS_TAB_TYPE'] = 'history';
|
||||
handleOpenType('history', {
|
||||
formData,
|
||||
formUrl,
|
||||
title: '流程历史',
|
||||
});
|
||||
}
|
||||
|
||||
const nodeInfoUrl = '/act/process/extActProcessNode/getHisProcessNodeInfo'
|
||||
const taskNodeInfo = (params) => defHttp.get({ url: nodeInfoUrl, params });
|
||||
|
||||
async function getTaskInfoForHistory(record) {
|
||||
//查询条件
|
||||
let params = { procInstId: record.processInstanceId };
|
||||
const result = await taskNodeInfo(params);
|
||||
console.log('获取历史任务信息', result);
|
||||
let formData: any = {
|
||||
dataId: result.dataId,
|
||||
taskId: record.id,
|
||||
taskDefKey: record.taskId,
|
||||
procInsId: record.processInstanceId,
|
||||
tableName: result.tableName,
|
||||
vars: result.records,
|
||||
};
|
||||
let tempFormUrl = result.formUrl;
|
||||
console.log('获取流程节点表单URL', tempFormUrl);
|
||||
//节点配置表单URL,VUE组件类型对应的拓展参数
|
||||
if (tempFormUrl && tempFormUrl.indexOf('?') != -1 && !isURL(tempFormUrl) && tempFormUrl.indexOf('{{DOMAIN_URL}}') == -1) {
|
||||
tempFormUrl = result.formUrl.split('?')[0];
|
||||
console.log('获取流程节点表单URL(去掉参数)', tempFormUrl);
|
||||
formData.extendUrlParams = getQueryVariable(result.formUrl);
|
||||
}
|
||||
return {
|
||||
formData,
|
||||
formUrl: tempFormUrl,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取URL上参数
|
||||
* @param url
|
||||
*/
|
||||
function getQueryVariable(url) {
|
||||
if (!url) return;
|
||||
|
||||
let t,
|
||||
n,
|
||||
r,
|
||||
i = url.split('?')[1],
|
||||
s = {};
|
||||
(t = i.split('&')), (r = null), (n = null);
|
||||
for (let o in t) {
|
||||
let u = t[o].indexOf('=');
|
||||
u !== -1 && ((r = t[o].substr(0, u)), (n = t[o].substr(u + 1)), (s[r] = n));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL地址
|
||||
* @param {*} s
|
||||
*/
|
||||
function isURL(s) {
|
||||
return /^http[s]?:\/\/.*/.test(s);
|
||||
}
|
||||
//update-end-author:taoyan date:2022-12-31 for: QQYUN-3485 【查看流程】做一个查看页面,非办理页面,只通过流程实例参数即可
|
||||
//===============================================================================================================
|
||||
|
||||
return {
|
||||
goPage
|
||||
goPage,
|
||||
isFormComment,
|
||||
modalRegCache,
|
||||
currentModal,
|
||||
bindParams,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BasicModal @register="registerModal" :title="title" :width="800" v-bind="$attrs" @ok="onSubmit">
|
||||
<BasicModal @register="registerModal" :title="title" :width="600" v-bind="$attrs" @ok="onSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
@ -21,6 +21,15 @@
|
||||
//update-end---author:wangshuai ---date:20221123 for:[VUEN-2807]消息模板加一个查看功能--------------z
|
||||
schemas: formSchemas,
|
||||
showActionButtonGroup: false,
|
||||
baseRowStyle: {
|
||||
marginTop: '10px',
|
||||
},
|
||||
labelCol: {
|
||||
span: 5,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 17,
|
||||
},
|
||||
});
|
||||
// 注册 modal
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
|
||||
@ -86,12 +86,23 @@ export const formSchemas: FormSchema[] = [
|
||||
label: '模板类型',
|
||||
field: 'templateType',
|
||||
component: 'JDictSelectTag',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
dictCode: 'msgType',
|
||||
type: 'radio',
|
||||
placeholder: '请选择模板类型',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '模板分类',
|
||||
field: 'templateCategory',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'msgCategory',
|
||||
placeholder: '请选择模板分类',
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '是否应用',
|
||||
field: 'useStatus',
|
||||
|
||||
@ -1,20 +1,113 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500">
|
||||
<iframe :src="frameSrc" class="detail-iframe" />
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500">
|
||||
<div class="print-btn" @click="onPrinter">
|
||||
<Icon icon="ant-design:printer-filled" />
|
||||
<span class="print-text">打印</span>
|
||||
</div>
|
||||
<iframe ref="iframeRef" :src="frameSrc" class="detail-iframe" @load="onIframeLoad"></iframe>
|
||||
<template v-if="noticeFiles && noticeFiles.length > 0">
|
||||
<div class="files-title">相关附件:</div>
|
||||
<template v-for="(file, index) in noticeFiles" :key="index">
|
||||
<div class="files-area">
|
||||
<div class="files-area-text">
|
||||
<span>
|
||||
<paper-clip-outlined />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:title="file.fileName"
|
||||
:href="getFileAccessHttpUrl(file.filePath)"
|
||||
class="ant-upload-list-item-name"
|
||||
>{{ file.fileName }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class="files-area-operate">
|
||||
<download-outlined class="item-icon" @click="handleDownloadFile(file.filePath)" />
|
||||
<eye-outlined class="item-icon" @click="handleViewFile(file.filePath)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { ref } from 'vue';
|
||||
import { buildUUID } from '@/utils/uuid';
|
||||
import { getFileAccessHttpUrl } from '@/utils/common/compUtils';
|
||||
import { DownloadOutlined, EyeOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
|
||||
import { encryptByBase64 } from '@/utils/cipher';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
const glob = useGlobSetting();
|
||||
// 获取props
|
||||
defineProps({
|
||||
frameSrc: propTypes.string.def(''),
|
||||
});
|
||||
//附件内容
|
||||
const noticeFiles = ref([]);
|
||||
//表单赋值
|
||||
const [registerModal] = useModalInner();
|
||||
const [registerModal] = useModalInner((data) => {
|
||||
noticeFiles.value = [];
|
||||
if (data.record?.files && data.record?.files.length > 0) {
|
||||
noticeFiles.value = data.record.files.split(',').map((item) => {
|
||||
return {
|
||||
fileName: item.split('/').pop(),
|
||||
filePath: item,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
// iframe引用
|
||||
const iframeRef = ref<HTMLIFrameElement>();
|
||||
// 存储当前打印会话ID
|
||||
const printSessionId = ref<string>('');
|
||||
// iframe加载完成后初始化通信
|
||||
const onIframeLoad = () => {
|
||||
printSessionId.value = buildUUID(); // 每次加载生成新的会话ID
|
||||
};
|
||||
//打印
|
||||
function onPrinter() {
|
||||
if (!iframeRef.value) return;
|
||||
console.log('onPrinter', iframeRef.value);
|
||||
iframeRef.value?.contentWindow?.postMessage({ printSessionId: printSessionId.value, type: 'action:print' }, '*');
|
||||
}
|
||||
/**
|
||||
* 下载文件
|
||||
* @param filePath
|
||||
*/
|
||||
function handleDownloadFile(filePath) {
|
||||
window.open(getFileAccessHttpUrl(filePath), '_blank');
|
||||
}
|
||||
/**
|
||||
* 预览文件
|
||||
* @param filePath
|
||||
*/
|
||||
function handleViewFile(filePath) {
|
||||
if (filePath) {
|
||||
let url = encodeURIComponent(encryptByBase64(filePath));
|
||||
let previewUrl = `${glob.viewUrl}?url=` + url;
|
||||
window.open(previewUrl, '_blank');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.print-btn {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
cursor: pointer;
|
||||
color: #a3a3a5;
|
||||
z-index: 999;
|
||||
.print-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
.detail-iframe {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
@ -24,4 +117,37 @@
|
||||
display: block;
|
||||
// -update-end--author:liaozhiyang---date:20240702---for:【TV360X-1685】通知公告查看出现两个滚动条
|
||||
}
|
||||
.files-title {
|
||||
font-size: 16px;
|
||||
margin: 10px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.files-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin: 6px;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.files-area-text {
|
||||
display: flex;
|
||||
.ant-upload-list-item-name {
|
||||
margin: 0 6px;
|
||||
color: #56befa;
|
||||
}
|
||||
}
|
||||
.files-area-operate {
|
||||
display: flex;
|
||||
margin-left: 10px;
|
||||
.item-icon {
|
||||
cursor: pointer;
|
||||
margin: 0 6px;
|
||||
&:hover {
|
||||
color: #56befa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
116
jeecgboot-vue3/src/views/system/notice/NoticeForm.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div style="min-height: 400px">
|
||||
<BasicForm @register="registerForm">
|
||||
<template #msgTemplate="{ model, field }">
|
||||
<a-select v-model:value="model[field]" placeholder="请选择消息模版" :options="templateOption" @change="handleChange" />
|
||||
</template>
|
||||
<template #msgContent="{ model, field }">
|
||||
<div v-html="model[field]" class="article-content"></div>
|
||||
</template>
|
||||
</BasicForm>
|
||||
<div class="footer-btn" v-if="!formDisabled">
|
||||
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 交</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { getBpmFormSchema } from './notice.data';
|
||||
import { getTempList, queryById, saveOrUpdate } from './notice.api';
|
||||
import { computed, ref } from 'vue';
|
||||
// 定义属性
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
//表单禁用
|
||||
const formDisabled = computed(() => {
|
||||
if (props.formData.disabled === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const templateOption = ref([]);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: getBpmFormSchema(props.formData),
|
||||
showActionButtonGroup: false,
|
||||
disabled: formDisabled.value,
|
||||
labelWidth: 100,
|
||||
baseRowStyle: { marginTop: '10px' },
|
||||
baseColProps: { xs: 24, sm: 12, md: 12, lg: 12, xl: 12, xxl: 12 },
|
||||
});
|
||||
|
||||
//表单提交
|
||||
async function submitForm() {
|
||||
let values = await validate();
|
||||
if (values.msgType === 'ALL') {
|
||||
values.userIds = '';
|
||||
} else {
|
||||
values.userIds += ',';
|
||||
}
|
||||
console.log('表单数据', values);
|
||||
await saveOrUpdate(values, true);
|
||||
}
|
||||
//初始化模板
|
||||
async function initTemplate() {
|
||||
const res = await getTempList({ templateCategory: 'notice', pageSize: 100 });
|
||||
console.log('res', res);
|
||||
if (res.records && res.records.length > 0) {
|
||||
templateOption.value = res.records.map((item) => {
|
||||
return {
|
||||
label: item.templateName,
|
||||
value: item.templateCode,
|
||||
content: item.templateContent,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 模版修改
|
||||
* @param val
|
||||
*/
|
||||
function handleChange(val) {
|
||||
const content = templateOption.value.find((item: any) => item.value === val)?.content;
|
||||
if (content) {
|
||||
setFieldsValue({
|
||||
msgContent: content,
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 加载数据
|
||||
*/
|
||||
async function initFormData() {
|
||||
let res = await queryById({ id: props.formData.dataId });
|
||||
if (res.success) {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
const record = res.result;
|
||||
if (record.userIds) {
|
||||
record.userIds = record.userIds.substring(0, record.userIds.length - 1);
|
||||
}
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...record,
|
||||
});
|
||||
}
|
||||
}
|
||||
//加载模版
|
||||
initTemplate();
|
||||
//加载数据
|
||||
initFormData();
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.footer-btn {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.article-content {
|
||||
max-width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,19 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="900px" destroyOnClose>
|
||||
<BasicForm @register="registerForm" />
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
@ok="handleSubmit"
|
||||
:title="title"
|
||||
width="900px"
|
||||
wrapClassName="notice-cls-modal"
|
||||
:maxHeight="800"
|
||||
destroyOnClose
|
||||
>
|
||||
<BasicForm @register="registerForm">
|
||||
<template #msgTemplate="{ model, field }">
|
||||
<a-select v-model:value="model[field]" placeholder="请选择消息模版" :options="templateOption" @change="handleChange" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@ -8,17 +21,24 @@
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from './notice.data';
|
||||
import { saveOrUpdate } from './notice.api';
|
||||
import { getTempList, saveOrUpdate } from './notice.api';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(true);
|
||||
const record = ref<any>({});
|
||||
const templateOption = ref([]);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
labelWidth: 100,
|
||||
baseRowStyle: { marginTop: '10px' },
|
||||
baseColProps: { xs: 24, sm: 12, md: 12, lg: 12, xl: 12, xxl: 12 },
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//加载模版
|
||||
await initTemplate();
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
@ -31,12 +51,13 @@
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
record.value = data.record;
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
//表单提交事件
|
||||
async function handleSubmit(v) {
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
let values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
@ -48,7 +69,7 @@
|
||||
values.userIds += ',';
|
||||
}
|
||||
//update-end-author:liusq---date:20230404--for: [issue#429]新增通知公告提交指定用户参数有undefined ---
|
||||
if (isUpdate.value) {
|
||||
if (isUpdate.value && record.value.sendStatus != '2') {
|
||||
values.sendStatus = '0';
|
||||
}
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
@ -60,4 +81,36 @@
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
//初始化模板
|
||||
async function initTemplate() {
|
||||
const res = await getTempList({ templateCategory: 'notice', pageSize: 100 });
|
||||
console.log('res', res);
|
||||
if (res.records && res.records.length > 0) {
|
||||
templateOption.value = res.records.map((item) => {
|
||||
return {
|
||||
label: item.templateName,
|
||||
value: item.templateCode,
|
||||
content: item.templateContent,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模版修改
|
||||
* @param val
|
||||
*/
|
||||
function handleChange(val) {
|
||||
const content = templateOption.value.find((item: any) => item.value === val)?.content;
|
||||
if (content) {
|
||||
setFieldsValue({
|
||||
msgContent: content,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.notice-cls-modal {
|
||||
top: 20px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -34,17 +34,17 @@
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import NoticeModal from './NoticeModal.vue';
|
||||
import DetailModal from './DetailModal.vue';
|
||||
import { useMethods } from '/@/hooks/system/useMethods';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { columns, searchFormSchema } from './notice.data';
|
||||
import { getList, deleteNotice, batchDeleteNotice, getExportUrl, getImportUrl, doReleaseData, doReovkeData } from './notice.api';
|
||||
import { getList, deleteNotice, batchDeleteNotice,editIzTop, getExportUrl, getImportUrl, doReleaseData, doReovkeData } from './notice.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
const glob = useGlobSetting();
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [register, { openModal: openDetail }] = useModal();
|
||||
const iframeUrl = ref('');
|
||||
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, onExportXls, onImportXls, tableContext, doRequest } = useListPage({
|
||||
designScope: 'notice-template',
|
||||
@ -66,7 +66,8 @@
|
||||
});
|
||||
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
//流程编码
|
||||
const flowCode = 'dev_sys_announcement_001';
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
@ -92,6 +93,12 @@
|
||||
async function handleDelete(record) {
|
||||
await deleteNotice({ id: record.id }, reload);
|
||||
}
|
||||
/**
|
||||
* 置顶操作
|
||||
*/
|
||||
async function handleTop(record, izTop) {
|
||||
await editIzTop({ id: record.id, izTop }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除事件
|
||||
@ -118,8 +125,9 @@
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
|
||||
openDetail(true);
|
||||
openDetail(true, { record });
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作列定义
|
||||
* @param record
|
||||
@ -131,6 +139,11 @@
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: record.sendStatus == 0 || record.sendStatus == '2',
|
||||
},
|
||||
{
|
||||
label: '查看',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
ifShow: record.sendStatus == 1,
|
||||
},
|
||||
];
|
||||
}
|
||||
/**
|
||||
@ -148,7 +161,7 @@
|
||||
},
|
||||
{
|
||||
label: '发布',
|
||||
ifShow: record.sendStatus == 0,
|
||||
ifShow: (!record?.izApproval || record.izApproval == '0') && record.sendStatus == 0,
|
||||
onClick: handleRelease.bind(null, record.id),
|
||||
},
|
||||
{
|
||||
@ -160,8 +173,22 @@
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '查看',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
label: '发布',
|
||||
ifShow: record.sendStatus == '2',
|
||||
popConfirm: {
|
||||
title: '确定要再次发布吗?',
|
||||
confirm: handleRelease.bind(null, record.id),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '置顶',
|
||||
onClick: handleTop.bind(null, record, 1),
|
||||
ifShow: record.sendStatus == 1 && record.izTop == 0,
|
||||
},
|
||||
{
|
||||
label: '取消置顶',
|
||||
onClick: handleTop.bind(null, record, 0),
|
||||
ifShow: record.sendStatus == 1 && record.izTop == 1,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -5,11 +5,17 @@ enum Api {
|
||||
save = '/sys/annountCement/add',
|
||||
edit = '/sys/annountCement/edit',
|
||||
delete = '/sys/annountCement/delete',
|
||||
queryById = '/sys/annountCement/queryById',
|
||||
deleteBatch = '/sys/annountCement/deleteBatch',
|
||||
exportXls = '/sys/annountCement/exportXls',
|
||||
importExcel = '/sys/annountCement/importExcel',
|
||||
releaseData = '/sys/annountCement/doReleaseData',
|
||||
reovkeData = '/sys/annountCement/doReovkeData',
|
||||
editIzTop = '/sys/annountCement/editIzTop',
|
||||
|
||||
addVisitsNum = '/sys/annountCement/addVisitsNumber',
|
||||
|
||||
tempList = '/sys/message/sysMessageTemplate/list',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -21,7 +27,7 @@ export const getExportUrl = Api.exportXls;
|
||||
*/
|
||||
export const getImportUrl = Api.importExcel;
|
||||
/**
|
||||
* 查询租户列表
|
||||
* 查询消息列表
|
||||
* @param params
|
||||
*/
|
||||
export const getList = (params) => {
|
||||
@ -33,7 +39,7 @@ export const getList = (params) => {
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
const url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
@ -46,6 +52,15 @@ export const deleteNotice = (params, handleSuccess) => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 置顶编辑
|
||||
* @param params
|
||||
*/
|
||||
export const editIzTop = (params, handleSuccess) => {
|
||||
return defHttp.post({ url: Api.editIzTop, data: params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量消息公告
|
||||
@ -63,3 +78,26 @@ export const doReleaseData = (params) => defHttp.get({ url: Api.releaseData, par
|
||||
* @param id
|
||||
*/
|
||||
export const doReovkeData = (params) => defHttp.get({ url: Api.reovkeData, params });
|
||||
/**
|
||||
* 新增访问量
|
||||
* @param id
|
||||
*/
|
||||
export const addVisitsNum = (params) => defHttp.get({ url: Api.addVisitsNum, params }, { successMessageMode: 'none' });
|
||||
/**
|
||||
* 根据ID查询数据
|
||||
* @param id
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 发起流程
|
||||
* import { startProcess } from '/@/api/common/api';
|
||||
* @param params
|
||||
*/
|
||||
export const startProcess = (params) => defHttp.post({ url: Api.startProcess, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 查询模板列表
|
||||
* @param params
|
||||
*/
|
||||
export const getTempList = (params) => {
|
||||
return defHttp.get({ url: Api.tempList, params });
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
import { rules } from '/@/utils/helper/validator';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
import { h } from 'vue';
|
||||
import { Tinymce } from '@/components/Tinymce';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
@ -87,9 +88,24 @@ export const formSchema: FormSchema[] = [
|
||||
placeholder: '请选择类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'izTop',
|
||||
label: '是否置顶',
|
||||
defaultValue: '0',
|
||||
component: 'JSwitch',
|
||||
componentProps: {
|
||||
//取值 options
|
||||
options: ['1', '0'],
|
||||
//文本option
|
||||
labelOptions: ['是', '否'],
|
||||
placeholder: '是否置顶',
|
||||
checkedChildren: '是',
|
||||
unCheckedChildren: '否',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'titile',
|
||||
label: '标题',
|
||||
label: '通告标题',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
componentProps: {
|
||||
@ -114,8 +130,15 @@ export const formSchema: FormSchema[] = [
|
||||
},
|
||||
{
|
||||
field: 'msgAbstract',
|
||||
label: '摘要',
|
||||
label: '通告摘要',
|
||||
component: 'InputTextArea',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
autoSize: {
|
||||
minRows: 2,
|
||||
maxRows: 5,
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// {
|
||||
@ -154,9 +177,18 @@ export const formSchema: FormSchema[] = [
|
||||
},
|
||||
ifShow: ({ values }) => values.msgType == 'USER',
|
||||
},
|
||||
{
|
||||
field: 'msgClassify',
|
||||
label: '公告分类',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'notice_type',
|
||||
placeholder: '请选择公告分类',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'priority',
|
||||
label: '优先级',
|
||||
label: '优先级别',
|
||||
defaultValue: 'H',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
@ -166,9 +198,211 @@ export const formSchema: FormSchema[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '内容',
|
||||
field: 'izApproval',
|
||||
label: '是否审批',
|
||||
component: 'RadioGroup',
|
||||
defaultValue: '0',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '是',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '否',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgTemplate',
|
||||
label: '公告模版',
|
||||
component: 'Input',
|
||||
slot: 'msgTemplate',
|
||||
},
|
||||
{
|
||||
field: 'files',
|
||||
label: '通告附件',
|
||||
component: 'JUpload',
|
||||
componentProps: {
|
||||
//是否显示选择按钮
|
||||
text: '文件上传',
|
||||
//最大上传数
|
||||
maxCount: 20,
|
||||
//是否显示下载按钮
|
||||
download: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '通告内容',
|
||||
component: 'Input',
|
||||
colProps: { span: 24 },
|
||||
render: render.renderTinymce,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 流程表单调用这个方法获取formSchema
|
||||
* @param param
|
||||
*/
|
||||
export function getBpmFormSchema(_formData): FormSchema[] {
|
||||
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
|
||||
return [
|
||||
{
|
||||
field: 'id',
|
||||
label: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: 'msgCategory',
|
||||
label: '消息类型',
|
||||
required: true,
|
||||
component: 'JDictSelectTag',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
type: 'radio',
|
||||
dictCode: 'msg_category',
|
||||
placeholder: '请选择类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'izTop',
|
||||
label: '是否置顶',
|
||||
defaultValue: '0',
|
||||
component: 'JSwitch',
|
||||
componentProps: {
|
||||
//取值 options
|
||||
options: ['1', '0'],
|
||||
//文本option
|
||||
labelOptions: ['是', '否'],
|
||||
placeholder: '是否置顶',
|
||||
checkedChildren: '是',
|
||||
unCheckedChildren: '否',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'titile',
|
||||
label: '通告标题',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
componentProps: {
|
||||
placeholder: '请输入标题',
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240701---for:【TV360X-1632】标题过长保存报错,长度校验
|
||||
dynamicRules() {
|
||||
return [
|
||||
{
|
||||
validator: (_, value) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (value.length > 100) {
|
||||
reject('最长100个字符');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240701---for:【TV360X-1632】标题过长保存报错,长度校验
|
||||
},
|
||||
{
|
||||
field: 'msgAbstract',
|
||||
label: '通告摘要',
|
||||
component: 'InputTextArea',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'msgType',
|
||||
label: '接收用户',
|
||||
defaultValue: 'ALL',
|
||||
component: 'JDictSelectTag',
|
||||
required: true,
|
||||
componentProps: {
|
||||
type: 'radio',
|
||||
dictCode: 'msg_type',
|
||||
placeholder: '请选择发布范围',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'userIds',
|
||||
label: '指定用户',
|
||||
component: 'JSelectUserByDepartment',
|
||||
required: true,
|
||||
componentProps: {
|
||||
rowKey: 'id',
|
||||
// update-begin--author:liaozhiyang---date:20240701---for:【TV360X-1627】通知公告用户选择组件没翻译
|
||||
labelKey: 'realname',
|
||||
// update-end--author:liaozhiyang---date:20240701---for:【TV360X-1627】通知公告用户选择组件没翻译
|
||||
},
|
||||
ifShow: ({ values }) => values.msgType == 'USER',
|
||||
},
|
||||
{
|
||||
field: 'msgClassify',
|
||||
label: '公告分类',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'notice_type',
|
||||
placeholder: '请选择公告分类',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'priority',
|
||||
label: '优先级别',
|
||||
defaultValue: 'H',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'priority',
|
||||
type: 'radio',
|
||||
placeholder: '请选择优先级',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgTemplate',
|
||||
label: '公告模版',
|
||||
component: 'Input',
|
||||
slot: 'msgTemplate',
|
||||
},
|
||||
{
|
||||
field: 'files',
|
||||
label: '通告附件',
|
||||
component: 'JUpload',
|
||||
componentProps: {
|
||||
//是否显示选择按钮
|
||||
text: '文件上传',
|
||||
//最大上传数
|
||||
maxCount: 2,
|
||||
//是否显示下载按钮
|
||||
download: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '通告内容',
|
||||
component: 'Input',
|
||||
colProps: { span: 24 },
|
||||
ifShow: ({}) => _formData.disabled == false,
|
||||
render: ({ model, field }) => {
|
||||
return h(Tinymce, {
|
||||
showImageUpload: false,
|
||||
disabled: _formData.disabled !== false,
|
||||
height: 300,
|
||||
value: model[field],
|
||||
onChange: (value: string) => {
|
||||
model[field] = value;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '通告内容',
|
||||
component: 'Input',
|
||||
colProps: { span: 24 },
|
||||
ifShow: ({}) => _formData.disabled !== false,
|
||||
slot: 'msgContent',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -184,10 +184,6 @@
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '首页配置',
|
||||
onClick: handleIndexConfig.bind(null, record.roleCode),
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="用户代理" @ok="handleSubmit" destroyOnClose>
|
||||
<BasicForm @register="registerForm" />
|
||||
<template #insertFooter>
|
||||
<Popconfirm title="确定删除当前配置的代理吗?" @confirm="handleDel">
|
||||
<a-button v-if="agentData.id"><Icon icon="ant-design:clear-outlined" />删除代理</a-button>
|
||||
</Popconfirm>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@ -8,7 +13,8 @@
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formAgentSchema } from './user.data';
|
||||
import { getUserAgent, saveOrUpdateAgent } from './user.api';
|
||||
import { deleteAgent, getUserAgent, saveOrUpdateAgent } from './user.api';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
//表单配置
|
||||
@ -16,6 +22,8 @@
|
||||
schemas: formAgentSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单数据
|
||||
const agentData = ref<any>({});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
@ -24,6 +32,8 @@
|
||||
//查询获取表单数据
|
||||
const res = await getUserAgent({ userName: data.userName });
|
||||
data = res.result ? res.result : data;
|
||||
//代理数据赋值
|
||||
agentData.value = { ...data };
|
||||
//表单赋值
|
||||
await setFieldsValue({ ...data });
|
||||
});
|
||||
@ -42,4 +52,20 @@
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除代理
|
||||
*/
|
||||
async function handleDel() {
|
||||
const reload = async () => {
|
||||
await resetFields();
|
||||
await setFieldsValue({ userName: agentData.value.userName });
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
emit('success');
|
||||
};
|
||||
if (agentData.value.id) {
|
||||
await deleteAgent({ id: agentData.value.id }, reload);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -8,6 +8,7 @@ enum Api {
|
||||
edit = '/sys/user/edit',
|
||||
agentSave = '/sys/sysUserAgent/add',
|
||||
agentEdit = '/sys/sysUserAgent/edit',
|
||||
deleteAgent = '/sys/sysUserAgent/delete',
|
||||
getUserRole = '/sys/user/queryUserRole',
|
||||
duplicateCheck = '/sys/duplicate/check',
|
||||
deleteUser = '/sys/user/delete',
|
||||
@ -208,6 +209,15 @@ export const saveOrUpdateAgent = (params) => {
|
||||
let url = params.id ? Api.agentEdit : Api.agentSave;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 代理删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteAgent = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteAgent, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户离职(新增代理人和用户状态变更操作)
|
||||
|
||||
@ -41,7 +41,11 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
serverOptions.origin = VITE_GLOB_QIANKUN_MICRO_APP_ENTRY!.split('/').slice(0, 3).join('/');
|
||||
}
|
||||
// ----- [end] 【JEECG作为乾坤子应用】 -----
|
||||
|
||||
|
||||
console.log('[init] Start Port: ', VITE_PORT);
|
||||
console.log('[init] Vite Proxy Config: ', VITE_PROXY);
|
||||
|
||||
|
||||
return {
|
||||
base: isQiankunMicro ? VITE_GLOB_QIANKUN_MICRO_APP_ENTRY : VITE_PUBLIC_PATH,
|
||||
root,
|
||||
|
||||