v3.8.2 版本前端代码
@ -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.
|
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
|
||||||
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
本软件受适用的国家软件著作权法(包括国际条约)和开源协议 双重保护许可。
|
||||||
|
|
||||||
开源协议中文释意如下:
|
开源协议中文释意如下:
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"electron:build-all": "npm run electron:build-web && npm run electron:build-app",
|
"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-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: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": {
|
"devDependencies": {
|
||||||
"electron": "35.1.4",
|
"electron": "35.1.4",
|
||||||
@ -23,9 +24,9 @@
|
|||||||
"vite-plugin-electron": "^0.29.0",
|
"vite-plugin-electron": "^0.29.0",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 提示:在执行`pnpm install`后如果Electron安装失败,可以尝试运行`npm run electron:install`进行安装
|
||||||
|
|
||||||
# Electron桌面通知示例和代码位置
|
# 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 { Tray, ipcMain, BrowserWindow, app, Notification } from 'electron';
|
||||||
import {openInBrowser} from "../utils";
|
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, ipcMain } from 'electron';
|
||||||
|
|
||||||
import { app, BrowserWindow, Menu } from 'electron';
|
|
||||||
import { isDev } from './env';
|
import { isDev } from './env';
|
||||||
import { createMainWindow, createIndexWindow } from './utils/window';
|
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);
|
Menu.setApplicationMenu(null);
|
||||||
@ -12,6 +12,14 @@ let mainWindow: BrowserWindow | null = null;
|
|||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
mainWindow = createMainWindow();
|
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;
|
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),
|
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 = 系统托盘
|
// tray = 系统托盘
|
||||||
import path from 'path';
|
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 {_PATHS} from '../paths';
|
||||||
import {$env, isDev} from '../env';
|
import {$env, isDev} from '../env';
|
||||||
|
|
||||||
const TrayIcons = {
|
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(),
|
empty: nativeImage.createEmpty(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,7 +67,21 @@ export function useTray(tray: Tray, win: BrowserWindow) {
|
|||||||
}
|
}
|
||||||
tray.setImage(TrayIcons.normal);
|
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() {
|
function sendDesktopNotice() {
|
||||||
// 判断是否支持桌面通知
|
// 判断是否支持桌面通知
|
||||||
@ -75,9 +96,8 @@ export function useTray(tray: Tray, win: BrowserWindow) {
|
|||||||
}
|
}
|
||||||
const ins = new Notification({
|
const ins = new Notification({
|
||||||
title: '通知标题',
|
title: '通知标题',
|
||||||
subtitle: '通知副标题',
|
|
||||||
body: '通知内容第一行\n通知内容第二行',
|
body: '通知内容第一行\n通知内容第二行',
|
||||||
icon: TrayIcons.normal.resize({width: 32, height: 32}),
|
// icon: TrayIcons.normal.resize({width: 32, height: 32}),
|
||||||
});
|
});
|
||||||
|
|
||||||
ins.on('click', () => {
|
ins.on('click', () => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type {BrowserWindowConstructorOptions} from 'electron';
|
import type {BrowserWindowConstructorOptions} from 'electron';
|
||||||
import {BrowserWindow, dialog} from 'electron';
|
import {app, BrowserWindow, dialog} from 'electron';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {_PATHS} from '../paths';
|
import {_PATHS} from '../paths';
|
||||||
import {$env, isDev} from '../env';
|
import {$env, isDev} from '../env';
|
||||||
@ -19,7 +19,13 @@ export function createBrowserWindow(options?: BrowserWindowConstructorOptions) {
|
|||||||
icon: isDev ? _PATHS.appIcon : void 0,
|
icon: isDev ? _PATHS.appIcon : void 0,
|
||||||
...options,
|
...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}) => {
|
win.webContents.setWindowOpenHandler(({url}) => {
|
||||||
const win = createBrowserWindow();
|
const win = createBrowserWindow();
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { resultSuccess, resultError, getRequestToken, requestParams,baseUrl} from '../_util';
|
import { resultSuccess, resultError, getRequestToken, requestParams,baseUrl} from '../_util';
|
||||||
import { MockMethod } from 'vite-plugin-mock';
|
import { MockMethod } from 'vite-plugin-mock';
|
||||||
import { createFakeUserList } from './user';
|
import { createFakeUserList } from './user';
|
||||||
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
|
|
||||||
// single
|
// single
|
||||||
const dashboardRoute = {
|
const dashboardRoute = {
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: 'LAYOUT',
|
component: 'LAYOUT',
|
||||||
redirect: '/dashboard/analysis',
|
redirect: PageEnum.BASE_HOME,
|
||||||
meta: {
|
meta: {
|
||||||
title: 'routes.dashboard.dashboard',
|
title: 'routes.dashboard.dashboard',
|
||||||
hideChildrenInMenu: true,
|
hideChildrenInMenu: true,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { MockMethod } from 'vite-plugin-mock';
|
import { MockMethod } from 'vite-plugin-mock';
|
||||||
import { resultError, resultSuccess, getRequestToken, requestParams, baseUrl } from '../_util';
|
import { resultError, resultSuccess, getRequestToken, requestParams, baseUrl } from '../_util';
|
||||||
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
export function createFakeUserList() {
|
export function createFakeUserList() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -10,7 +11,7 @@ export function createFakeUserList() {
|
|||||||
desc: 'manager',
|
desc: 'manager',
|
||||||
password: '123456',
|
password: '123456',
|
||||||
token: 'fakeToken1',
|
token: 'fakeToken1',
|
||||||
homePath: '/dashboard/analysis',
|
homePath: PageEnum.BASE_HOME,
|
||||||
roles: [
|
roles: [
|
||||||
{
|
{
|
||||||
roleName: 'Super Admin',
|
roleName: 'Super Admin',
|
||||||
@ -26,7 +27,7 @@ export function createFakeUserList() {
|
|||||||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
|
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
|
||||||
desc: 'tester',
|
desc: 'tester',
|
||||||
token: 'fakeToken2',
|
token: 'fakeToken2',
|
||||||
homePath: '/dashboard/workbench',
|
homePath: PageEnum.BASE_HOME,
|
||||||
roles: [
|
roles: [
|
||||||
{
|
{
|
||||||
roleName: 'Tester',
|
roleName: 'Tester',
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"pinstall": "pnpm install",
|
"pinstall": "pnpm install",
|
||||||
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
|
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
|
||||||
"dev": "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:report": "pnpm clean:cache && cross-env REPORT=true npm run build",
|
"build:report": "pnpm clean:cache && cross-env REPORT=true npm run build",
|
||||||
"preview": "npm run build && vite preview",
|
"preview": "npm run build && vite preview",
|
||||||
"reinstall": "rimraf pnpm-lock.yaml && rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run install",
|
"reinstall": "rimraf pnpm-lock.yaml && rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run install",
|
||||||
@ -79,8 +79,8 @@
|
|||||||
"vue-types": "^5.1.3",
|
"vue-types": "^5.1.3",
|
||||||
"vuedraggable": "^4.1.0",
|
"vuedraggable": "^4.1.0",
|
||||||
"vxe-table": "4.13.31",
|
"vxe-table": "4.13.31",
|
||||||
"vxe-table-plugin-antd": "4.0.8",
|
|
||||||
"vxe-pc-ui": "4.6.12",
|
"vxe-pc-ui": "4.6.12",
|
||||||
|
"vxe-table-plugin-antd": "4.0.8",
|
||||||
"xe-utils": "3.5.26",
|
"xe-utils": "3.5.26",
|
||||||
"xss": "^1.0.15"
|
"xss": "^1.0.15"
|
||||||
},
|
},
|
||||||
|
2863
jeecgboot-vue3/pnpm-lock.yaml
generated
@ -15,6 +15,7 @@ enum Api {
|
|||||||
getTableList = '/sys/user/queryUserComponentData',
|
getTableList = '/sys/user/queryUserComponentData',
|
||||||
getCategoryData = '/sys/category/loadAllData',
|
getCategoryData = '/sys/category/loadAllData',
|
||||||
refreshDragCache = '/drag/page/refreshCache',
|
refreshDragCache = '/drag/page/refreshCache',
|
||||||
|
refreshDefaultIndexCache = '/sys/sysRoleIndex/cleanDefaultIndexCache',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,3 +155,8 @@ export const uploadMyFile = (url, data) => {
|
|||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export const refreshDragCache = () => defHttp.get({ url: Api.refreshDragCache }, { isTransformResponse: false });
|
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">
|
<a-menu :class="[`${prefixCls}-menu`]" :selectedKeys="selectedKeys">
|
||||||
<template v-for="item in dropMenuList" :key="`${item.event}`">
|
<template v-for="item in dropMenuList" :key="`${item.event}`">
|
||||||
<a-menu-item
|
<a-menu-item
|
||||||
|
v-if="!item.hide"
|
||||||
v-bind="getAttr(item.event)"
|
v-bind="getAttr(item.event)"
|
||||||
@click="handleClickMenu(item)"
|
@click="handleClickMenu(item)"
|
||||||
:disabled="item.disabled"
|
:disabled="item.disabled"
|
||||||
|
@ -5,5 +5,7 @@ export interface DropMenu {
|
|||||||
event: string | number;
|
event: string | number;
|
||||||
text: string;
|
text: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
// 是否隐藏
|
||||||
|
hide?: boolean;
|
||||||
divider?: boolean;
|
divider?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
:allDefaultValues="defaultValueRef"
|
:allDefaultValues="defaultValueRef"
|
||||||
:formModel="formModel"
|
:formModel="formModel"
|
||||||
:formName="getBindValue.name"
|
:formName="getBindValue.name"
|
||||||
|
:source="getBindValue.source"
|
||||||
:setFormModel="setFormModel"
|
:setFormModel="setFormModel"
|
||||||
:validateFields="validateFields"
|
:validateFields="validateFields"
|
||||||
:clearValidate="clearValidate"
|
: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 getSchema = computed((): FormSchema[] => {
|
||||||
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
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> = {
|
const formActionType: Partial<FormActionType> = {
|
||||||
getFieldsValue,
|
getFieldsValue,
|
||||||
setFieldsValue,
|
setFieldsValue,
|
||||||
@ -318,6 +343,7 @@
|
|||||||
validate,
|
validate,
|
||||||
submit: handleSubmit,
|
submit: handleSubmit,
|
||||||
scrollToField: scrollToField,
|
scrollToField: scrollToField,
|
||||||
|
getSchemaComponentProps,
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -66,6 +66,7 @@ import JEllipsis from './jeecg/components/JEllipsis.vue';
|
|||||||
import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue';
|
import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue';
|
||||||
import JSelectUserByDepartment from './jeecg/components/JSelectUserByDepartment.vue';
|
import JSelectUserByDepartment from './jeecg/components/JSelectUserByDepartment.vue';
|
||||||
import JLinkTableCard from './jeecg/components/JLinkTableCard/JLinkTableCard.vue';
|
import JLinkTableCard from './jeecg/components/JLinkTableCard/JLinkTableCard.vue';
|
||||||
|
|
||||||
import JUpload from './jeecg/components/JUpload/JUpload.vue';
|
import JUpload from './jeecg/components/JUpload/JUpload.vue';
|
||||||
import JSearchSelect from './jeecg/components/JSearchSelect.vue';
|
import JSearchSelect from './jeecg/components/JSearchSelect.vue';
|
||||||
import JAddInput from './jeecg/components/JAddInput.vue';
|
import JAddInput from './jeecg/components/JAddInput.vue';
|
||||||
|
@ -190,7 +190,7 @@
|
|||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
//--@updateBy-begin----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
//--@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值空的情况下需要设置为数组------
|
//--@updateBy-end----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||||
|
|
||||||
//update-begin---author:wangshuai ---date:20230505 for:初始化value值,如果是多选字符串的情况下显示不出来------------
|
//update-begin---author:wangshuai ---date:20230505 for:初始化value值,如果是多选字符串的情况下显示不出来------------
|
||||||
@ -202,7 +202,7 @@
|
|||||||
function initValue() {
|
function initValue() {
|
||||||
let value = props.value;
|
let value = props.value;
|
||||||
// update-begin--author:liaozhiyang---date:20250407---for:【issues/8037】初始化值单选的值被错误地写入数组值
|
// 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') {
|
if (value && typeof value === 'string' && value != 'null' && value != 'undefined') {
|
||||||
state.value = value.split(',');
|
state.value = value.split(',');
|
||||||
} else if (isNumber(value)) {
|
} else if (isNumber(value)) {
|
||||||
|
@ -66,6 +66,10 @@
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
// update-end--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
// update-end--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
||||||
|
source: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props, { slots }) {
|
setup(props, { slots }) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -506,7 +510,7 @@
|
|||||||
<div style="display:flex">
|
<div style="display:flex">
|
||||||
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */}
|
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */}
|
||||||
{/* update-begin--author:liaozhiyang---date:20240510---for:【TV360X-719】表单校验不通过项滚动到可视区内 */}
|
{/* 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】表单校验不通过项滚动到可视区内 */}
|
{/* update-end--author:liaozhiyang---date:20240510---for:【TV360X-719】表单校验不通过项滚动到可视区内 */}
|
||||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
// update-begin--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
// update-begin--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
||||||
const formItemId = ref(null);
|
const formItemId = ref(null);
|
||||||
const props = defineProps(['formName', 'fieldName']);
|
const props = defineProps(['formName', 'fieldName', 'source']);
|
||||||
if (props.formName && props.fieldName) {
|
if (props.formName && props.fieldName && props.source !== 'table-query') {
|
||||||
formItemId.value = `${props.formName}_${props.fieldName}`;
|
formItemId.value = `${props.formName}_${props.fieldName}`;
|
||||||
}
|
}
|
||||||
// update-end--author:liaozhiyang---date:20240625---for:【TV360X-1511】blur不生效
|
// 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) => {
|
let values = form.validate(nameList).then((values) => {
|
||||||
for (let key in values) {
|
for (let key in values) {
|
||||||
if (values[key] instanceof Array) {
|
if (values[key] instanceof Array) {
|
||||||
let valueType = getValueTypeBySchema(form.getSchemaByField(key)!);
|
let valueType = getValueTypeBySchema(form.getSchemaByField(key)!, form);
|
||||||
if (valueType === 'string') {
|
if (valueType === 'string') {
|
||||||
values[key] = values[key].join(',');
|
values[key] = values[key].join(',');
|
||||||
}
|
}
|
||||||
|
@ -595,6 +595,9 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
border-right: 1px solid #e8e8e8;
|
border-right: 1px solid #e8e8e8;
|
||||||
.search-box {
|
.search-box {
|
||||||
|
:deep(.ant-input-affix-wrapper) {
|
||||||
|
border-color: #d9d9d9 !important;
|
||||||
|
}
|
||||||
margin: 0 16px 16px 16px;
|
margin: 0 16px 16px 16px;
|
||||||
}
|
}
|
||||||
:deep(.ant-breadcrumb) {
|
:deep(.ant-breadcrumb) {
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
v-bind="getBindValue"
|
v-bind="getBindValue"
|
||||||
:useSearchForm="true"
|
:useSearchForm="true"
|
||||||
:formConfig="formConfig"
|
:formConfig="formConfig"
|
||||||
:api="getUserList"
|
:api="hasCustomApi ? customListApi : getUserList"
|
||||||
:searchInfo="searchInfo"
|
:searchInfo="searchInfo"
|
||||||
:rowSelection="rowSelection"
|
:rowSelection="rowSelection"
|
||||||
:indexColumnProps="indexColumnProps"
|
:indexColumnProps="indexColumnProps"
|
||||||
@ -54,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<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 { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { getUserList } from '/@/api/common/api';
|
import { getUserList } from '/@/api/common/api';
|
||||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
|
||||||
@ -85,6 +85,11 @@
|
|||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
//update-end---author:wangshuai ---date:20230703 for:【QQYUN-5685】5、离职人员可以选自己------------
|
//update-end---author:wangshuai ---date:20230703 for:【QQYUN-5685】5、离职人员可以选自己------------
|
||||||
|
|
||||||
|
// 查询table数据使用的自定义接口
|
||||||
|
customListApi: {type: Function},
|
||||||
|
// 自定义接口的查询条件是否使用 JInput
|
||||||
|
customApiJInput: {type: Boolean, default: true},
|
||||||
},
|
},
|
||||||
emits: ['register', 'getSelectResult', 'close'],
|
emits: ['register', 'getSelectResult', 'close'],
|
||||||
setup(props, { emit, refs }) {
|
setup(props, { emit, refs }) {
|
||||||
@ -93,6 +98,8 @@
|
|||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const maxHeight = ref(600);
|
const maxHeight = ref(600);
|
||||||
|
|
||||||
|
const hasCustomApi = computed(() => typeof props.customListApi === 'function');
|
||||||
|
|
||||||
//注册弹框
|
//注册弹框
|
||||||
const [register, { closeModal }] = useModalInner(() => {
|
const [register, { closeModal }] = useModalInner(() => {
|
||||||
if (window.innerWidth < 900) {
|
if (window.innerWidth < 900) {
|
||||||
@ -156,12 +163,12 @@
|
|||||||
{
|
{
|
||||||
label: '账号',
|
label: '账号',
|
||||||
field: 'username',
|
field: 'username',
|
||||||
component: 'JInput',
|
component: (hasCustomApi.value && !props.customApiJInput) ? 'Input' : 'JInput',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '姓名',
|
label: '姓名',
|
||||||
field: 'realname',
|
field: 'realname',
|
||||||
component: 'JInput',
|
component: (hasCustomApi.value && !props.customApiJInput) ? 'Input' : 'JInput',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -300,6 +307,7 @@
|
|||||||
handleCancel,
|
handleCancel,
|
||||||
maxHeight,
|
maxHeight,
|
||||||
beforeFetch,
|
beforeFetch,
|
||||||
|
hasCustomApi,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -41,6 +41,7 @@ export interface FormActionType {
|
|||||||
validateFields: (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>;
|
validateFields: (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>;
|
||||||
validate: (nameList?: NamePath[]) => Promise<any>;
|
validate: (nameList?: NamePath[]) => Promise<any>;
|
||||||
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
|
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
|
||||||
|
getSchemaComponentProps: (schema: FormSchema) => Recordable
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RegisterFn = (formInstance: FormActionType) => void;
|
export type RegisterFn = (formInstance: FormActionType) => void;
|
||||||
|
@ -143,6 +143,11 @@
|
|||||||
function scaleFunc(num: number) {
|
function scaleFunc(num: number) {
|
||||||
if (imgState.imgScale <= 0.2 && num < 0) return;
|
if (imgState.imgScale <= 0.2 && num < 0) return;
|
||||||
imgState.imgScale += num;
|
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 }"
|
:class="{ 'table-search-area-hidden': !getBindValues.formConfig?.schemas?.length }"
|
||||||
submitOnReset
|
submitOnReset
|
||||||
v-bind="getFormProps"
|
v-bind="getFormProps"
|
||||||
|
source="table-query"
|
||||||
v-if="getBindValues.useSearchForm"
|
v-if="getBindValues.useSearchForm"
|
||||||
:tableAction="tableAction"
|
:tableAction="tableAction"
|
||||||
@register="registerForm"
|
@register="registerForm"
|
||||||
@ -214,7 +215,7 @@
|
|||||||
onChange && isFunction(onChange) && onChange.call(undefined, ...args);
|
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,
|
getProps,
|
||||||
getPaginationInfo,
|
getPaginationInfo,
|
||||||
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
// update-begin--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
||||||
@ -367,6 +368,9 @@
|
|||||||
getRowSelection,
|
getRowSelection,
|
||||||
getPaginationRef: getPagination,
|
getPaginationRef: getPagination,
|
||||||
getColumns,
|
getColumns,
|
||||||
|
// update-begin--author:liaozhiyang---date:20250722---for:【issues/8529】setColumns后列配置没联动更新
|
||||||
|
getColumnsRef: () => getColumnsRef,
|
||||||
|
// update-end--author:liaozhiyang---date:20250722---for:【issues/8529】setColumns后列配置没联动更新
|
||||||
getCacheColumns,
|
getCacheColumns,
|
||||||
emit,
|
emit,
|
||||||
updateTableData,
|
updateTableData,
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const table = useTableContext();
|
const table = useTableContext();
|
||||||
|
const getColumnsRef = table.getColumnsRef();
|
||||||
const tableFooter = ref<any>(null);
|
const tableFooter = ref<any>(null);
|
||||||
const getDataSource = computed((): Recordable[] => {
|
const getDataSource = computed((): Recordable[] => {
|
||||||
const { summaryFunc, summaryData } = props;
|
const { summaryFunc, summaryData } = props;
|
||||||
@ -71,7 +72,10 @@
|
|||||||
|
|
||||||
const getColumns = computed(() => {
|
const getColumns = computed(() => {
|
||||||
const dataSource = unref(getDataSource);
|
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】表格合计,列自定义隐藏或展示时,合计栏会错位
|
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
||||||
columns = columns.filter((item) => !item.defaultHidden);
|
columns = columns.filter((item) => !item.defaultHidden);
|
||||||
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
// update-begin--author:liaozhiyang---date:220230804---for:【issues/638】表格合计,列自定义隐藏或展示时,合计栏会错位
|
||||||
|
@ -148,7 +148,27 @@
|
|||||||
|
|
||||||
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
|
const options: LabelValueOptions = editComponentProps?.options ?? (unref(optionsRef) || []);
|
||||||
const option = options.find((item) => `${item.value}` === `${value}`);
|
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;
|
return option?.label ?? value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -151,6 +151,9 @@
|
|||||||
// nextTick(() => popoverVisible.value = false);
|
// nextTick(() => popoverVisible.value = false);
|
||||||
// update-end--author:sunjianlei---date:20221101---for: 修复第一次进入时列表配置不能拖拽
|
// update-end--author:sunjianlei---date:20221101---for: 修复第一次进入时列表配置不能拖拽
|
||||||
const defaultRowSelection = omit(table.getRowSelection(), 'selectedRowKeys');
|
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;
|
let inited = false;
|
||||||
|
|
||||||
const cachePlainOptions = ref<Options[]>([]);
|
const cachePlainOptions = ref<Options[]>([]);
|
||||||
@ -219,7 +222,7 @@
|
|||||||
checkSelect.value = !!values.rowSelection;
|
checkSelect.value = !!values.rowSelection;
|
||||||
});
|
});
|
||||||
// update-begin--author:liaozhiyang---date:20240724---for:【issues/6908】多语言无刷新切换时,BasicColumn和FormSchema里面的值不能正常切换
|
// update-begin--author:liaozhiyang---date:20240724---for:【issues/6908】多语言无刷新切换时,BasicColumn和FormSchema里面的值不能正常切换
|
||||||
watch(localeStore, () => {
|
watch([localeStore, getColumnsRef], () => {
|
||||||
const columns = getColumns();
|
const columns = getColumns();
|
||||||
plainOptions.value = columns;
|
plainOptions.value = columns;
|
||||||
plainSortOptions.value = columns;
|
plainSortOptions.value = columns;
|
||||||
@ -230,7 +233,7 @@
|
|||||||
function getColumns() {
|
function getColumns() {
|
||||||
const ret: Options[] = [];
|
const ret: Options[] = [];
|
||||||
// update-begin--author:liaozhiyang---date:20250403---for:【issues/7996】表格列组件取消所有或者只勾选中间,显示非预期
|
// 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) {
|
if (!t.length) {
|
||||||
t = table.getCacheColumns();
|
t = table.getCacheColumns();
|
||||||
}
|
}
|
||||||
@ -249,7 +252,7 @@
|
|||||||
const columns = getColumns();
|
const columns = getColumns();
|
||||||
|
|
||||||
const checkList = table
|
const checkList = table
|
||||||
.getColumns({ ignoreAction: true, ignoreIndex: true })
|
.getColumns({ ignoreAction: true, ignoreIndex: true, ignoreAuth: true, ignoreIfShow: true })
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
if (item.defaultHidden) {
|
if (item.defaultHidden) {
|
||||||
return '';
|
return '';
|
||||||
@ -341,7 +344,7 @@
|
|||||||
// state.checkedList = [...state.defaultCheckList];
|
// state.checkedList = [...state.defaultCheckList];
|
||||||
// update-begin--author:liaozhiyang---date:20231103---for:【issues/825】tabel的列设置隐藏列保存后切换路由问题[重置没勾选]
|
// update-begin--author:liaozhiyang---date:20231103---for:【issues/825】tabel的列设置隐藏列保存后切换路由问题[重置没勾选]
|
||||||
state.checkedList = table
|
state.checkedList = table
|
||||||
.getColumns({ ignoreAction: true })
|
.getColumns({ ignoreAction: true, ignoreAuth: true, ignoreIfShow: true })
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return item.dataIndex || item.title;
|
return item.dataIndex || item.title;
|
||||||
})
|
})
|
||||||
|
@ -285,7 +285,7 @@ export function useColumns(
|
|||||||
// update-end--author:sunjianlei---date:20220523---for: 【VUEN-1089】合并vben最新版代码,解决表格字段排序问题
|
// update-end--author:sunjianlei---date:20220523---for: 【VUEN-1089】合并vben最新版代码,解决表格字段排序问题
|
||||||
|
|
||||||
function getColumns(opt?: GetColumnsParams) {
|
function getColumns(opt?: GetColumnsParams) {
|
||||||
const { ignoreIndex, ignoreAction, sort } = opt || {};
|
const { ignoreIndex, ignoreAction, ignoreAuth, ignoreIfShow, sort } = opt || {};
|
||||||
let columns = toRaw(unref(getColumnsRef));
|
let columns = toRaw(unref(getColumnsRef));
|
||||||
if (ignoreIndex) {
|
if (ignoreIndex) {
|
||||||
columns = columns.filter((item) => item.flag !== INDEX_COLUMN_FLAG);
|
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);
|
columns = columns.filter((item) => item.key !== CUS_SEL_COLUMN_KEY);
|
||||||
// update-enb--author:sunjianlei---date:220230630---for:【QQYUN-5571】自封装选择列,解决数据行选择卡顿问题
|
// 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) {
|
if (sort) {
|
||||||
columns = sortFixedColumn(columns);
|
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 { PaginationProps } from './pagination';
|
||||||
import type { FormProps } from '/@/components/Form';
|
import type { FormProps } from '/@/components/Form';
|
||||||
import type { TableRowSelection as ITableRowSelection } from 'ant-design-vue/lib/table/interface';
|
import type { TableRowSelection as ITableRowSelection } from 'ant-design-vue/lib/table/interface';
|
||||||
@ -80,6 +80,10 @@ export interface FetchParams {
|
|||||||
export interface GetColumnsParams {
|
export interface GetColumnsParams {
|
||||||
ignoreIndex?: boolean;
|
ignoreIndex?: boolean;
|
||||||
ignoreAction?: 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;
|
sort?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +120,7 @@ export interface TableActionType {
|
|||||||
setShowPagination: (show: boolean) => Promise<void>;
|
setShowPagination: (show: boolean) => Promise<void>;
|
||||||
getShowPagination: () => boolean;
|
getShowPagination: () => boolean;
|
||||||
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void;
|
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void;
|
||||||
|
getColumnsRef: () => ComputedRef<BasicColumn[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchSetting {
|
export interface FetchSetting {
|
||||||
|
@ -151,6 +151,28 @@
|
|||||||
toolbar,
|
toolbar,
|
||||||
menubar: false,
|
menubar: false,
|
||||||
plugins,
|
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_url: publicPath + 'resource/tinymce/langs/' + langName.value + '.js',
|
||||||
language: langName.value,
|
language: langName.value,
|
||||||
branding: false,
|
branding: false,
|
||||||
|
@ -10,10 +10,10 @@ export const plugins = [
|
|||||||
export const toolbar =
|
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';
|
'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 = [
|
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';
|
export const menubar = 'file edit insert view format table';
|
||||||
|
@ -316,4 +316,10 @@ html[data-theme='dark'] {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
-webkit-line-clamp: 3;
|
-webkit-line-clamp: 3;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-action-item {
|
||||||
|
&.color-red {
|
||||||
|
color: red !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import type {App} from "vue";
|
import type {App} from "vue";
|
||||||
import {router} from "@/router";
|
import {router} from "@/router";
|
||||||
import {useGlobSetting} from "@/hooks/setting";
|
import {useGlobSetting} from "@/hooks/setting";
|
||||||
|
import { ElectronEnum } from '/@/enums/jeecgEnum'
|
||||||
const glob = useGlobSetting();
|
const glob = useGlobSetting();
|
||||||
|
|
||||||
const _PRELOAD_UTILS = '_ELECTRON_PRELOAD_UTILS_';
|
const _PRELOAD_UTILS = ElectronEnum.ELECTRON_API;
|
||||||
|
|
||||||
export const $electron = {
|
export const $electron = {
|
||||||
// 当前是否为Electron平台
|
// 当前是否为Electron平台
|
||||||
@ -38,8 +38,16 @@ export function setupElectron(_: App) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hookWindowOpen();
|
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() {
|
function hookWindowOpen() {
|
||||||
// 保存原生方法引用
|
// 保存原生方法引用
|
||||||
const originFunc = window.open;
|
const originFunc = window.open;
|
||||||
@ -62,4 +70,4 @@ function hookWindowOpen() {
|
|||||||
// 自定义逻辑
|
// 自定义逻辑
|
||||||
return originFunc(url, windowName, windowFeatures)
|
return originFunc(url, windowName, windowFeatures)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,3 +21,7 @@ export enum JDragConfigEnum {
|
|||||||
//拖拽缓存前缀
|
//拖拽缓存前缀
|
||||||
DRAG_CACHE_PREFIX = 'drag-cache:',
|
DRAG_CACHE_PREFIX = 'drag-cache:',
|
||||||
}
|
}
|
||||||
|
// electron 枚举
|
||||||
|
export enum ElectronEnum {
|
||||||
|
ELECTRON_API = '_ELECTRON_PRELOAD_UTILS_',
|
||||||
|
}
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
// components
|
// components
|
||||||
import { Dropdown, Menu } from 'ant-design-vue';
|
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';
|
import { SITE_URL } from '/@/settings/siteSetting';
|
||||||
|
|
||||||
@ -57,9 +57,9 @@
|
|||||||
import { removeAuthCache, setAuthCache } from '/src/utils/auth';
|
import { removeAuthCache, setAuthCache } from '/src/utils/auth';
|
||||||
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||||
import { getRefPromise } from '/@/utils/index';
|
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();
|
const { createMessage } = useMessage();
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'UserDropdown',
|
name: 'UserDropdown',
|
||||||
@ -82,6 +82,7 @@
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const go = useGo();
|
const go = useGo();
|
||||||
const passwordVisible = ref(false);
|
const passwordVisible = ref(false);
|
||||||
|
const homeSelectVisible = ref(false);
|
||||||
const lockActionVisible = ref(false);
|
const lockActionVisible = ref(false);
|
||||||
const lockActionRef = ref(null);
|
const lockActionRef = ref(null);
|
||||||
|
|
||||||
@ -123,9 +124,8 @@
|
|||||||
// 清除缓存
|
// 清除缓存
|
||||||
async function clearCache() {
|
async function clearCache() {
|
||||||
const result = await refreshCache();
|
const result = await refreshCache();
|
||||||
//TODO 当前版本还不支持刷新缓存,需要等jimibi升级
|
const dragRes = await refreshDragCache();
|
||||||
// const dragRes = await refreshDragCache();
|
console.log('dragRes', dragRes);
|
||||||
// console.log('dragRes', dragRes);
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const res = await queryAllDictItems();
|
const res = await queryAllDictItems();
|
||||||
removeAuthCache(DB_DICT_DATA_KEY);
|
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>
|
</style>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
import { useTabDropdown } from '../useTabDropdown';
|
import { useTabDropdown } from '../useTabDropdown';
|
||||||
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
|
||||||
import { useLocaleStore } from '/@/store/modules/locale';
|
import { useLocaleStore } from '/@/store/modules/locale';
|
||||||
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'TabContent',
|
name: 'TabContent',
|
||||||
@ -61,7 +62,7 @@
|
|||||||
const prefixIconType = computed(() => {
|
const prefixIconType = computed(() => {
|
||||||
if (props.tabItem.meta.icon) {
|
if (props.tabItem.meta.icon) {
|
||||||
return 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 此处可能需要动态判断首页路径
|
// 当是首页时返回 home 图标 TODO 此处可能需要动态判断首页路径
|
||||||
return 'ant-design:home-outlined';
|
return 'ant-design:home-outlined';
|
||||||
} else {
|
} 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 { RouteLocationNormalized, useRouter } from 'vue-router';
|
||||||
import { useTabs } from '/@/hooks/web/useTabs';
|
import { useTabs } from '/@/hooks/web/useTabs';
|
||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { useHideHomeDesign } from './useHideHomeDesign';
|
||||||
|
|
||||||
export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
|
export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: ComputedRef<boolean>) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@ -23,6 +24,10 @@ export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: Comp
|
|||||||
const getTargetTab = computed((): RouteLocationNormalized => {
|
const getTargetTab = computed((): RouteLocationNormalized => {
|
||||||
return unref(getIsTabs) ? tabContentProps.tabItem : unref(currentRoute);
|
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
|
* @description: drop-down list
|
||||||
@ -65,6 +70,10 @@ export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: Comp
|
|||||||
// Close right
|
// Close right
|
||||||
const closeRightDisabled = index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0;
|
const closeRightDisabled = index === tabStore.getTabList.length - 1 && tabStore.getLastDragEndIndex >= 0;
|
||||||
// update-end--author:liaozhiyang---date:20240605---for:【TV360X-732】非当前页右键关闭左侧、关闭右侧、关闭其它功能正常使用
|
// 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[] = [
|
const dropMenuList: DropMenu[] = [
|
||||||
{
|
{
|
||||||
icon: 'jam:refresh-reverse',
|
icon: 'jam:refresh-reverse',
|
||||||
@ -76,7 +85,8 @@ export function useTabDropdown(tabContentProps: TabContentProps, getIsTabs: Comp
|
|||||||
icon: 'ant-design:setting-outlined',
|
icon: 'ant-design:setting-outlined',
|
||||||
event: MenuEventEnum.HOME_DESIGN,
|
event: MenuEventEnum.HOME_DESIGN,
|
||||||
text: t('layout.multipleTab.homeDesign'),
|
text: t('layout.multipleTab.homeDesign'),
|
||||||
disabled: path !== '/PortalView',
|
disabled: !/^\/portal-view\/[^/]+$/.test(path),
|
||||||
|
hide: isHideHomeDesign.value,
|
||||||
divider: true,
|
divider: true,
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
|
@ -8,6 +8,7 @@ export default {
|
|||||||
dropdownItemSwitchDepart: 'Switch Department',
|
dropdownItemSwitchDepart: 'Switch Department',
|
||||||
dropdownItemRefreshCache: 'Clean cache',
|
dropdownItemRefreshCache: 'Clean cache',
|
||||||
dropdownItemSwitchAccount: 'Account Setting',
|
dropdownItemSwitchAccount: 'Account Setting',
|
||||||
|
dropdownItemSwitchDefaultHomePage: 'Switch Home Page',
|
||||||
|
|
||||||
tooltipErrorLog: 'Error log',
|
tooltipErrorLog: 'Error log',
|
||||||
tooltipLock: 'Lock screen',
|
tooltipLock: 'Lock screen',
|
||||||
|
@ -8,6 +8,7 @@ export default {
|
|||||||
dropdownItemSwitchDepart: '切换部门',
|
dropdownItemSwitchDepart: '切换部门',
|
||||||
dropdownItemRefreshCache: '刷新缓存',
|
dropdownItemRefreshCache: '刷新缓存',
|
||||||
dropdownItemSwitchAccount: '账户设置',
|
dropdownItemSwitchAccount: '账户设置',
|
||||||
|
dropdownItemSwitchDefaultHomePage: '切换首页',
|
||||||
|
|
||||||
// tooltip
|
// tooltip
|
||||||
tooltipErrorLog: '错误日志',
|
tooltipErrorLog: '错误日志',
|
||||||
@ -34,7 +35,7 @@ export default {
|
|||||||
closeRight: '关闭右侧',
|
closeRight: '关闭右侧',
|
||||||
closeOther: '关闭其它',
|
closeOther: '关闭其它',
|
||||||
closeAll: '关闭全部',
|
closeAll: '关闭全部',
|
||||||
homeDesign: '设计模式',
|
homeDesign: '门户设计',
|
||||||
},
|
},
|
||||||
setting: {
|
setting: {
|
||||||
// content mode
|
// content mode
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { AppRouteModule } from '/@/router/types';
|
import type { AppRouteModule } from '/@/router/types';
|
||||||
|
import { PageEnum } from '/@/enums/pageEnum';
|
||||||
import { LAYOUT } from '/@/router/constant';
|
import { LAYOUT } from '/@/router/constant';
|
||||||
import { t } from '/@/hooks/web/useI18n';
|
import { t } from '/@/hooks/web/useI18n';
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ const dashboard: AppRouteModule = {
|
|||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'Dashboard',
|
name: 'Dashboard',
|
||||||
component: LAYOUT,
|
component: LAYOUT,
|
||||||
redirect: '/dashboard/analysis',
|
redirect: PageEnum.BASE_HOME,
|
||||||
meta: {
|
meta: {
|
||||||
orderNo: 10,
|
orderNo: 10,
|
||||||
icon: 'ion:grid-outline',
|
icon: 'ion:grid-outline',
|
||||||
|
@ -67,7 +67,9 @@ export const defIndexApi = {
|
|||||||
async update(url: string, component: string, isRoute: boolean) {
|
async update(url: string, component: string, isRoute: boolean) {
|
||||||
let apiUrl = '/sys/sysRoleIndex/updateDefIndex'
|
let apiUrl = '/sys/sysRoleIndex/updateDefIndex'
|
||||||
apiUrl += '?url=' + url
|
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
|
apiUrl += '&isRoute=' + isRoute
|
||||||
return await defHttp.put({url: apiUrl});
|
return await defHttp.put({url: apiUrl});
|
||||||
},
|
},
|
||||||
|
@ -232,6 +232,15 @@ export const useMultipleTabStore = defineStore({
|
|||||||
curTab.fullPath = fullPath || curTab.fullPath;
|
curTab.fullPath = fullPath || curTab.fullPath;
|
||||||
this.tabList.splice(updateIndex, 1, curTab);
|
this.tabList.splice(updateIndex, 1, curTab);
|
||||||
} else {
|
} 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
|
// Add tab
|
||||||
// 获取动态路由打开数,超过 0 即代表需要控制打开数
|
// 获取动态路由打开数,超过 0 即代表需要控制打开数
|
||||||
const dynamicLevel = meta?.dynamicLevel ?? -1;
|
const dynamicLevel = meta?.dynamicLevel ?? -1;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
|
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
|
||||||
import type { App, Plugin } from 'vue';
|
import type { App, Plugin } from 'vue';
|
||||||
import type { FormSchema } from "@/components/Form";
|
import type { FormSchema, FormActionType } from "@/components/Form";
|
||||||
|
|
||||||
import { unref } from 'vue';
|
import { unref } from 'vue';
|
||||||
import { isObject, isFunction, isString } from '/@/utils/is';
|
import { isObject, isFunction, isString } from '/@/utils/is';
|
||||||
@ -110,11 +110,12 @@ export function getValueType(props, field) {
|
|||||||
/**
|
/**
|
||||||
* 获取表单字段值数据类型
|
* 获取表单字段值数据类型
|
||||||
* @param schema
|
* @param schema
|
||||||
|
* @param formAction
|
||||||
*/
|
*/
|
||||||
export function getValueTypeBySchema(schema: FormSchema) {
|
export function getValueTypeBySchema(schema: FormSchema, formAction: FormActionType) {
|
||||||
let valueType = 'string';
|
let valueType = 'string';
|
||||||
if (schema) {
|
if (schema) {
|
||||||
const componentProps = schema.componentProps as Recordable;
|
const componentProps = formAction.getSchemaComponentProps(schema);
|
||||||
valueType = componentProps?.valueType ? componentProps?.valueType : valueType;
|
valueType = componentProps?.valueType ? componentProps?.valueType : valueType;
|
||||||
}
|
}
|
||||||
return valueType;
|
return valueType;
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
<a @click="handleDetail(record)">详情</a>
|
<a @click="handleDetail(record)">详情</a>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<Popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
|
<Popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)" placement="left">
|
||||||
<a>删除</a>
|
<a>删除</a>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
@ -1,230 +1,234 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-spin :spinning="confirmLoading">
|
<a-spin :spinning="confirmLoading">
|
||||||
<a-form class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
|
<JFormContainer :disabled="disabled">
|
||||||
<a-row>
|
<template #detail>
|
||||||
<a-col :span="24">
|
<a-form class="antd-modal-form" ref="formRef" :model="formState" :rules="validatorRules">
|
||||||
<a-form-item label="文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.name">
|
<a-row>
|
||||||
<a-input v-model:value="formState.name" placeholder="请输入文本"></a-input>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.name">
|
||||||
</a-col>
|
<a-input v-model:value="formState.name" placeholder="请输入文本"></a-input>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.miMa">
|
</a-col>
|
||||||
<a-input-password v-model:value="formState.miMa" placeholder="请输入密码" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="密码" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.miMa">
|
||||||
</a-col>
|
<a-input-password v-model:value="formState.miMa" placeholder="请输入密码" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="字典下拉" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xiala">
|
</a-col>
|
||||||
<JDictSelectTag type="select" v-model:value="formState.xiala" dictCode="sex" placeholder="请选择字典下拉" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="字典下拉" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xiala">
|
||||||
</a-col>
|
<JDictSelectTag type="select" v-model:value="formState.xiala" dictCode="sex" placeholder="请选择字典下拉" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="字典单选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.danxuan">
|
</a-col>
|
||||||
<JDictSelectTag type="radio" v-model:value="formState.danxuan" dictCode="sex" placeholder="请选择字典单选" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="字典单选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.danxuan">
|
||||||
</a-col>
|
<JDictSelectTag type="radio" v-model:value="formState.danxuan" dictCode="sex" placeholder="请选择字典单选" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="字典多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.duoxuan">
|
</a-col>
|
||||||
<JCheckbox v-model:value="formState.duoxuan" dictCode="urgent_level" placeholder="请选择字典多选" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="字典多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.duoxuan">
|
||||||
</a-col>
|
<JCheckbox v-model:value="formState.duoxuan" dictCode="urgent_level" placeholder="请选择字典多选" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="开关" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.kaiguan">
|
</a-col>
|
||||||
<JSwitch v-model:value="formState.kaiguan" :options="['1', '0']"></JSwitch>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="开关" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.kaiguan">
|
||||||
</a-col>
|
<JSwitch v-model:value="formState.kaiguan" :options="['1', '0']"></JSwitch>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="日期" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.riqi">
|
</a-col>
|
||||||
<a-date-picker placeholder="请选择日期" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD" v-model:value="formState.riqi" style="width: 100%" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="日期" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.riqi">
|
||||||
</a-col>
|
<a-date-picker placeholder="请选择日期" format="YYYY-MM-DD" valueFormat="YYYY-MM-DD" v-model:value="formState.riqi" style="width: 100%" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="年月日时分秒" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.nyrsfm">
|
</a-col>
|
||||||
<a-date-picker show-time v-model:value="formState.nyrsfm" style="width: 100%" valueFormat="YYYY-MM-DD HH:mm:ss" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="年月日时分秒" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.nyrsfm">
|
||||||
</a-col>
|
<a-date-picker show-time v-model:value="formState.nyrsfm" style="width: 100%" valueFormat="YYYY-MM-DD HH:mm:ss" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="时间" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shijian">
|
</a-col>
|
||||||
<TimePicker placeholder="请选择时间" v-model:value="formState.shijian" style="width: 100%" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="时间" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shijian">
|
||||||
</a-col>
|
<TimePicker placeholder="请选择时间" v-model:value="formState.shijian" style="width: 100%" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="文件" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.wenjian">
|
</a-col>
|
||||||
<JUpload v-model:value="formState.wenjian"></JUpload>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="文件" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.wenjian">
|
||||||
</a-col>
|
<JUpload v-model:value="formState.wenjian"></JUpload>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.tupian">
|
</a-col>
|
||||||
<JImageUpload :fileMax="2" v-model:value="formState.tupian"></JImageUpload>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="图片" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.tupian">
|
||||||
</a-col>
|
<JImageUpload :fileMax="2" v-model:value="formState.tupian"></JImageUpload>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="多行文本框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.dhwb">
|
</a-col>
|
||||||
<a-textarea v-model:value="formState.dhwb" rows="4" placeholder="请输入多行文本框" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="多行文本框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.dhwb">
|
||||||
</a-col>
|
<a-textarea v-model:value="formState.dhwb" rows="4" placeholder="请输入多行文本框" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="字典表下拉搜索框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xlss">
|
</a-col>
|
||||||
<JSearchSelect v-model:value="formState.xlss" dict="sys_user,realname,username" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="字典表下拉搜索框" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.xlss">
|
||||||
</a-col>
|
<JSearchSelect v-model:value="formState.xlss" dict="sys_user,realname,username" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="popup弹窗" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popup">
|
</a-col>
|
||||||
<JPopup
|
<a-col :span="24">
|
||||||
v-model:value="formState.popup"
|
<a-form-item label="popup弹窗" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popup">
|
||||||
:fieldConfig="[
|
<JPopup
|
||||||
{ source: 'name', target: 'popup' },
|
v-model:value="formState.popup"
|
||||||
{ source: 'id', target: 'popback' },
|
:fieldConfig="[
|
||||||
]"
|
{ source: 'name', target: 'popup' },
|
||||||
code="report_user"
|
{ source: 'id', target: 'popback' },
|
||||||
:multi="true"
|
]"
|
||||||
:setFieldsValue="setFieldsValue"
|
code="report_user"
|
||||||
/>
|
:multi="true"
|
||||||
</a-form-item>
|
:setFieldsValue="setFieldsValue"
|
||||||
</a-col>
|
/>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="popback" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popback">
|
</a-col>
|
||||||
<a-input v-model:value="formState.popback" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="popback" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.popback">
|
||||||
</a-col>
|
<a-input v-model:value="formState.popback" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="分类字典树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.flzds">
|
</a-col>
|
||||||
<JCategorySelect
|
<a-col :span="24">
|
||||||
@change="(value) => handleFormChange('flzds', value)"
|
<a-form-item label="分类字典树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.flzds">
|
||||||
v-model:value="formState.flzds"
|
<JCategorySelect
|
||||||
pcode="B02"
|
@change="(value) => handleFormChange('flzds', value)"
|
||||||
placeholder="请选择分类字典树"
|
v-model:value="formState.flzds"
|
||||||
/>
|
pcode="B02"
|
||||||
</a-form-item>
|
placeholder="请选择分类字典树"
|
||||||
</a-col>
|
/>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="部门选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.bmxz">
|
</a-col>
|
||||||
<JSelectDept v-model:value="formState.bmxz" :multi="true" type="array" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="部门选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.bmxz">
|
||||||
</a-col>
|
<JSelectDept v-model:value="formState.bmxz" :multi="true" type="array" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="用户选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yhxz">
|
</a-col>
|
||||||
<JSelectUserByDept v-model:value="formState.yhxz" :multi="true" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="用户选择" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yhxz">
|
||||||
</a-col>
|
<JSelectUserByDept v-model:value="formState.yhxz" :multi="true" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="富文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.fwb">
|
</a-col>
|
||||||
<JEditor v-model:value="formState.fwb" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="富文本" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.fwb">
|
||||||
</a-col>
|
<JEditor v-model:value="formState.fwb" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="markdown" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.markdownString">
|
</a-col>
|
||||||
<JMarkdownEditor v-model:value="formState.markdownString"></JMarkdownEditor>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="markdown" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.markdownString">
|
||||||
</a-col>
|
<JMarkdownEditor v-model:value="formState.markdownString"></JMarkdownEditor>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="省市区JAreaSelect" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shq">
|
</a-col>
|
||||||
<JAreaSelect v-model:value="formState.shq" placeholder="请输入省市区" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="省市区JAreaSelect" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.shq">
|
||||||
</a-col>
|
<JAreaSelect v-model:value="formState.shq" placeholder="请输入省市区" />
|
||||||
|
</a-form-item>
|
||||||
<a-col :span="24">
|
</a-col>
|
||||||
<a-form-item label="省市区JAreaLinkage" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jssq">
|
|
||||||
<JAreaLinkage v-model:value="formState.jssq" placeholder="请输入省市区" />
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="省市区JAreaLinkage" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jssq">
|
||||||
</a-col>
|
<JAreaLinkage v-model:value="formState.jssq" placeholder="请输入省市区" />
|
||||||
|
</a-form-item>
|
||||||
<a-col :span="24">
|
</a-col>
|
||||||
<a-form-item label="JInputPop" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzje">
|
|
||||||
<JInputPop
|
<a-col :span="24">
|
||||||
v-model:value="formState.ldzje"
|
<a-form-item label="JInputPop" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzje">
|
||||||
placeholder="请输入JInputPop"
|
<JInputPop
|
||||||
@change="(value) => handleFormChange('ldzje', value)"
|
v-model:value="formState.ldzje"
|
||||||
></JInputPop>
|
placeholder="请输入JInputPop"
|
||||||
</a-form-item>
|
@change="(value) => handleFormChange('ldzje', value)"
|
||||||
</a-col>
|
></JInputPop>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="JSelectInput" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzjs">
|
</a-col>
|
||||||
<JSelectInput
|
<a-col :span="24">
|
||||||
v-model:value="formState.ldzjs"
|
<a-form-item label="JSelectInput" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ldzjs">
|
||||||
placeholder="请选择JSelectInput"
|
<JSelectInput
|
||||||
:options="ldzjsOptions"
|
v-model:value="formState.ldzjs"
|
||||||
@change="(value) => handleFormChange('ldzjs', value)"
|
placeholder="请选择JSelectInput"
|
||||||
></JSelectInput>
|
:options="ldzjsOptions"
|
||||||
</a-form-item>
|
@change="(value) => handleFormChange('ldzjs', value)"
|
||||||
</a-col>
|
></JSelectInput>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="下拉多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zddtjxl">
|
</a-col>
|
||||||
<JSelectMultiple v-model:value="formState.zddtjxl" placeholder="请选择下拉多选" dictCode="sex"></JSelectMultiple>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="下拉多选" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zddtjxl">
|
||||||
</a-col>
|
<JSelectMultiple v-model:value="formState.zddtjxl" placeholder="请选择下拉多选" dictCode="sex"></JSelectMultiple>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yongHu">
|
</a-col>
|
||||||
<JSelectUser v-model:value="formState.yongHu" placeholder="请选择用户"></JSelectUser>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="用户" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yongHu">
|
||||||
</a-col>
|
<JSelectUser v-model:value="formState.yongHu" placeholder="请选择用户"></JSelectUser>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="职务" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zhiWu">
|
</a-col>
|
||||||
<JSelectPosition
|
<a-col :span="24">
|
||||||
v-model:value="formState.zhiWu"
|
<a-form-item label="职务" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zhiWu">
|
||||||
placeholder="请选择职务"
|
<JSelectPosition
|
||||||
@change="(value) => handleFormChange('zhiWu', value)"
|
v-model:value="formState.zhiWu"
|
||||||
></JSelectPosition>
|
placeholder="请选择职务"
|
||||||
</a-form-item>
|
@change="(value) => handleFormChange('zhiWu', value)"
|
||||||
</a-col>
|
></JSelectPosition>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="角色" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jueSe">
|
</a-col>
|
||||||
<JSelectRole v-model:value="formState.jueSe" placeholder="请选择角色" @change="(value) => handleFormChange('jueSe', value)"></JSelectRole>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="角色" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jueSe">
|
||||||
</a-col>
|
<JSelectRole v-model:value="formState.jueSe" placeholder="请选择角色" @change="(value) => handleFormChange('jueSe', value)"></JSelectRole>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="自定义树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdys">
|
</a-col>
|
||||||
<JTreeSelect
|
<a-col :span="24">
|
||||||
ref="treeSelect"
|
<a-form-item label="自定义树" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdys">
|
||||||
placeholder="请选择自定义树"
|
<JTreeSelect
|
||||||
v-model:value="formState.zdys"
|
ref="treeSelect"
|
||||||
dict="sys_category,name,id"
|
placeholder="请选择自定义树"
|
||||||
pidValue="0"
|
v-model:value="formState.zdys"
|
||||||
loadTriggleChange
|
dict="sys_category,name,id"
|
||||||
>
|
pidValue="0"
|
||||||
</JTreeSelect>
|
loadTriggleChange
|
||||||
</a-form-item>
|
>
|
||||||
</a-col>
|
</JTreeSelect>
|
||||||
|
</a-form-item>
|
||||||
<a-col :span="24">
|
</a-col>
|
||||||
<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-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="数值" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.yuanjia">
|
||||||
</a-col>
|
<a-input-number v-model:value="formState.yuanjia" placeholder="请输入double类型" style="width: 100%" />
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="输入2到10位的字母" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ywzz">
|
</a-col>
|
||||||
<a-input v-model:value="formState.ywzz" placeholder="请输入2到10位的字母"></a-input>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="输入2到10位的字母" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.ywzz">
|
||||||
</a-col>
|
<a-input v-model:value="formState.ywzz" placeholder="请输入2到10位的字母"></a-input>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="JTreeDict" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdbxl">
|
</a-col>
|
||||||
<JTreeDict
|
<a-col :span="24">
|
||||||
v-model:value="formState.zdbxl"
|
<a-form-item label="JTreeDict" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdbxl">
|
||||||
placeholder="请选择JTreeDict"
|
<JTreeDict
|
||||||
@change="(value) => handleFormChange('zdbxl', value)"
|
v-model:value="formState.zdbxl"
|
||||||
></JTreeDict>
|
placeholder="请选择JTreeDict"
|
||||||
</a-form-item>
|
@change="(value) => handleFormChange('zdbxl', value)"
|
||||||
</a-col>
|
></JTreeDict>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="JCodeEditor" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdmrz">
|
</a-col>
|
||||||
<JCodeEditor
|
<a-col :span="24">
|
||||||
v-model:value="formState.zdmrz"
|
<a-form-item label="JCodeEditor" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.zdmrz">
|
||||||
placeholder="请输入JCodeEditor"
|
<JCodeEditor
|
||||||
@change="(value) => handleFormChange('zdmrz', value)"
|
v-model:value="formState.zdmrz"
|
||||||
></JCodeEditor>
|
placeholder="请输入JCodeEditor"
|
||||||
</a-form-item>
|
@change="(value) => handleFormChange('zdmrz', value)"
|
||||||
</a-col>
|
></JCodeEditor>
|
||||||
<a-col :span="24">
|
</a-form-item>
|
||||||
<a-form-item label="参数" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jsonParam">
|
</a-col>
|
||||||
<JAddInput v-model:value="formState.jsonParam" placeholder="参数"></JAddInput>
|
<a-col :span="24">
|
||||||
</a-form-item>
|
<a-form-item label="参数" :labelCol="labelCol" :wrapperCol="wrapperCol" v-bind="validateInfos.jsonParam">
|
||||||
</a-col>
|
<JAddInput v-model:value="formState.jsonParam" placeholder="参数"></JAddInput>
|
||||||
</a-row>
|
</a-form-item>
|
||||||
</a-form>
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
</JFormContainer>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, nextTick } from 'vue';
|
import { ref, reactive, nextTick, computed } from 'vue';
|
||||||
import { defHttp } from '/@/utils/http/axios';
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@ -255,7 +259,15 @@
|
|||||||
import JCodeEditor from '/@/components/Form/src/jeecg/components/JCodeEditor.vue';
|
import JCodeEditor from '/@/components/Form/src/jeecg/components/JCodeEditor.vue';
|
||||||
import JAddInput from '/@/components/Form/src/jeecg/components/JAddInput.vue';
|
import JAddInput from '/@/components/Form/src/jeecg/components/JAddInput.vue';
|
||||||
import { getValueType } from '/@/utils';
|
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']);
|
const emit = defineEmits(['register', 'ok']);
|
||||||
//update-begin---author:wangshuai ---date:20220616 for:报表示例验证修改--------------
|
//update-begin---author:wangshuai ---date:20220616 for:报表示例验证修改--------------
|
||||||
const formState = reactive<Record<string, any>>({
|
const formState = reactive<Record<string, any>>({
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
@cancel="handleCancel"
|
@cancel="handleCancel"
|
||||||
cancelText="关闭"
|
cancelText="关闭"
|
||||||
>
|
>
|
||||||
<OneNativeForm ref="realForm" @ok="submitCallback" :disabled="disableSubmit"></OneNativeForm>
|
<OneNativeForm ref="realForm" @ok="submitCallback" :formDisabled="disableSubmit"></OneNativeForm>
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -61,5 +61,9 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less">
|
||||||
|
/**隐藏样式-modal确定按钮 */
|
||||||
|
.jee-hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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" />
|
<BasicForm @register="registerForm" />
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
const isUpdate = ref(true);
|
const isUpdate = ref(true);
|
||||||
//表单配置
|
//表单配置
|
||||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||||
labelWidth: 150,
|
// labelWidth: 150,
|
||||||
schemas: ticketFormSchema,
|
schemas: ticketFormSchema,
|
||||||
showActionButtonGroup: false,
|
showActionButtonGroup: false,
|
||||||
});
|
});
|
||||||
|
@ -227,6 +227,7 @@ export const ticketFormSchema: FormSchema[] = [
|
|||||||
component: 'DatePicker',
|
component: 'DatePicker',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
valueFormat: 'YYYY-MM-DD',
|
valueFormat: 'YYYY-MM-DD',
|
||||||
|
getPopupContainer:()=>document.body,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,92 +1,340 @@
|
|||||||
<template>
|
<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 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 />
|
<a-divider />
|
||||||
<div v-html="content.msgContent" class="article-content"></div>
|
<div v-html="content.msgContent" class="article-content"></div>
|
||||||
<div>
|
<div>
|
||||||
<a-button v-if="hasHref" @click="jumpToHandlePage">前往办理<ArrowRightOutlined /></a-button>
|
<a-button v-if="hasHref" @click="jumpToHandlePage">前往办理<ArrowRightOutlined /></a-button>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</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>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { ArrowRightOutlined, PaperClipOutlined, DownloadOutlined, EyeOutlined } from '@ant-design/icons-vue';
|
||||||
import { ArrowRightOutlined } from '@ant-design/icons-vue';
|
import { addVisitsNum } from '@/views/system/notice/notice.api';
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router';
|
||||||
import xss from 'xss'
|
import xss from 'xss';
|
||||||
import { options } from './XssWhiteList'
|
import { options } from './XssWhiteList';
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
import { ref, unref } from 'vue';
|
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 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) => {
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
isUpdate.value = !!data?.isUpdate;
|
isUpdate.value = !!data?.isUpdate;
|
||||||
if (unref(isUpdate)) {
|
if (unref(isUpdate)) {
|
||||||
//data.record.msgContent = '<p>2323</p><input onmouseover=alert(1)>xss test';
|
//data.record.msgContent = '<p>2323</p><input onmouseover=alert(1)>xss test';
|
||||||
//update-begin-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
|
//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版本 通知公告中发布的富文本消息,在我的消息中查看没有样式---
|
//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:wangshuai---date:2023-11-15---for:【QQYUN-7049】3.6.0版本 通知公告中发布的富文本消息,在我的消息中查看没有样式---
|
||||||
}
|
}
|
||||||
//update-end-author:taoyan date:2022-7-14 for: VUEN-1702 【禁止问题】sql注入漏洞
|
//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;
|
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();
|
showHrefButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const hasHref = ref(false)
|
const hasHref = ref(false);
|
||||||
//查看消息详情可以跳转
|
//查看消息详情可以跳转
|
||||||
function showHrefButton(){
|
function showHrefButton() {
|
||||||
if(content.value.busId){
|
if (content.value.busId) {
|
||||||
hasHref.value = true;
|
hasHref.value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//跳转至办理页面
|
//跳转至办理页面
|
||||||
function jumpToHandlePage(){
|
function jumpToHandlePage() {
|
||||||
let temp:any = content.value
|
let temp: any = content.value;
|
||||||
if(temp.busId){
|
if (temp.busId) {
|
||||||
//这个busId是 任务ID
|
//这个busId是 任务ID
|
||||||
let jsonStr = temp.msgAbstract;
|
let jsonStr = temp.msgAbstract;
|
||||||
let query = {};
|
let query = {};
|
||||||
try {
|
try {
|
||||||
if(jsonStr){
|
if (jsonStr) {
|
||||||
let temp = JSON.parse(jsonStr)
|
let temp = JSON.parse(jsonStr);
|
||||||
if(temp){
|
if (temp) {
|
||||||
Object.keys(temp).map(k=>{
|
Object.keys(temp).map((k) => {
|
||||||
query[k] = temp[k]
|
query[k] = temp[k];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch(e){
|
} catch (e) {
|
||||||
console.log('参数解析异常', e)
|
console.log('参数解析异常', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('query', query, jsonStr)
|
console.log('query', query, jsonStr);
|
||||||
console.log('busId', temp.busId)
|
console.log('busId', temp.busId);
|
||||||
|
|
||||||
if(Object.keys(query).length>0){
|
if (Object.keys(query).length > 0) {
|
||||||
// taskId taskDefKey procInsId
|
// taskId taskDefKey procInsId
|
||||||
router.push({ path: '/task/handle/' + temp.busId, query: query })
|
router.push({ path: '/task/handle/' + temp.busId, query: query });
|
||||||
}else{
|
} else {
|
||||||
router.push({ path: '/task/handle/' + temp.busId })
|
router.push({ path: '/task/handle/' + temp.busId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closeModal();
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<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 {
|
.detail-iframe {
|
||||||
border: 0;
|
border: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 600px;
|
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>
|
</style>
|
||||||
|
@ -33,9 +33,20 @@
|
|||||||
import { useAppStore } from '/@/store/modules/app';
|
import { useAppStore } from '/@/store/modules/app';
|
||||||
import { useMessageHref } from '/@/views/system/message/components/useSysMessage';
|
import { useMessageHref } from '/@/views/system/message/components/useSysMessage';
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
const router = useRouter();
|
||||||
const {goPage} = useMessageHref()
|
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({
|
const { prefixCls, tableContext } = useListPage({
|
||||||
designScope: 'mynews-list',
|
designScope: 'mynews-list',
|
||||||
tableProps: {
|
tableProps: {
|
||||||
@ -48,6 +59,14 @@
|
|||||||
fieldMapToTime: [['sendTime', ['sendTimeBegin', 'sendTimeEnd'], 'YYYY-MM-DD']],
|
fieldMapToTime: [['sendTime', ['sendTimeBegin', 'sendTimeEnd'], 'YYYY-MM-DD']],
|
||||||
//update-end---author:wangshuai---date:2024-06-11---for:【TV360X-545】我的消息列表不能通过时间范围查询---
|
//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;
|
const [registerTable, { reload }] = tableContext;
|
||||||
|
@ -81,4 +81,16 @@ export const searchFormSchema: FormSchema[] = [
|
|||||||
},
|
},
|
||||||
colProps: { span: 6 },
|
colProps: { span: 6 },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'msgCategory',
|
||||||
|
label: '消息类型',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{ label: '通知公告', value: '1' },
|
||||||
|
{ label: '系统消息', value: '2' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
colProps: { span: 6 },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
></chat>
|
></chat>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<Spin v-else :spinning="true"></Spin>
|
<Loading :loading="loading" tip="加载中,请稍后"></Loading>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -48,6 +48,7 @@
|
|||||||
import { defHttp } from '/@/utils/http/axios';
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useAppInject } from "@/hooks/web/useAppInject";
|
import { useAppInject } from "@/hooks/web/useAppInject";
|
||||||
|
import Loading from '@/components/Loading/src/Loading.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const userId = useUserStore().getUserInfo?.id;
|
const userId = useUserStore().getUserInfo?.id;
|
||||||
@ -67,6 +68,8 @@
|
|||||||
const chatActiveKey = ref<number>(0);
|
const chatActiveKey = ref<number>(0);
|
||||||
//预置开场白
|
//预置开场白
|
||||||
const presetQuestion = ref<string>('');
|
const presetQuestion = ref<string>('');
|
||||||
|
//加载
|
||||||
|
const loading = ref<any>(true);
|
||||||
|
|
||||||
const handleToggle = () => {
|
const handleToggle = () => {
|
||||||
expand.value = !expand.value;
|
expand.value = !expand.value;
|
||||||
@ -179,10 +182,13 @@
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
priming();
|
priming();
|
||||||
});
|
}).finally(()=>{
|
||||||
|
loading.value = false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
loading.value = true;
|
||||||
let params: any = router.currentRoute.value.params;
|
let params: any = router.currentRoute.value.params;
|
||||||
if (params.appId) {
|
if (params.appId) {
|
||||||
appId.value = params.appId;
|
appId.value = params.appId;
|
||||||
|
@ -84,6 +84,8 @@
|
|||||||
}
|
}
|
||||||
//倒计时执行前的函数
|
//倒计时执行前的函数
|
||||||
function sendCodeApi() {
|
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>
|
</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',
|
wechatEnterpriseToLocal = '/sys/thirdApp/sync/wechatEnterprise/departAndUser/toLocal',
|
||||||
getThirdUserBindByWechat = '/sys/thirdApp/getThirdUserBindByWechat',
|
getThirdUserBindByWechat = '/sys/thirdApp/getThirdUserBindByWechat',
|
||||||
deleteThirdAccount = '/sys/thirdApp/deleteThirdAccount',
|
deleteThirdAccount = '/sys/thirdApp/deleteThirdAccount',
|
||||||
|
deleteThirdAppConfig = '/sys/thirdApp/deleteThirdAppConfig',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,4 +67,15 @@ export const getThirdUserBindByWechat = () => {
|
|||||||
*/
|
*/
|
||||||
export const deleteThirdAccount = (params) => {
|
export const deleteThirdAccount = (params) => {
|
||||||
return defHttp.delete({ url: Api.deleteThirdAccount, params }, { isTransformResponse:false, joinParamsToUrl: true });
|
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">
|
<a-collapse-panel key="2">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div style="width: 100%; justify-content: space-between; display: flex">
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="base-desc">完成步骤1后,填入Agentld、 AppKey、AppSecret后 可对接应用与同步通讯录</div>
|
<div class="base-desc">完成步骤1后,填入Agentld、 AppKey、AppSecret后 可对接应用与同步通讯录</div>
|
||||||
@ -47,6 +47,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 20px; width: 100%; text-align: right">
|
<div style="margin-top: 20px; width: 100%; text-align: right">
|
||||||
<a-button @click="dingEditClick">编辑</a-button>
|
<a-button @click="dingEditClick">编辑</a-button>
|
||||||
|
<a-button v-if="appConfigData.id" @click="cancelBindClick" danger style="margin-left: 10px">取消绑定</a-button>
|
||||||
</div>
|
</div>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
</a-collapse>
|
</a-collapse>
|
||||||
@ -76,7 +77,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, h, inject, onMounted, reactive, ref, watch } from 'vue';
|
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 { useModal } from '/@/components/Modal';
|
||||||
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
||||||
import { Modal } from 'ant-design-vue';
|
import { Modal } from 'ant-design-vue';
|
||||||
@ -122,6 +123,8 @@
|
|||||||
let values = await getThirdConfigByTenantId(params);
|
let values = await getThirdConfigByTenantId(params);
|
||||||
if (values) {
|
if (values) {
|
||||||
appConfigData.value = values;
|
appConfigData.value = values;
|
||||||
|
} else {
|
||||||
|
appConfigData.value = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +217,25 @@
|
|||||||
function handleIconClick(){
|
function handleIconClick(){
|
||||||
window.open("https://help.qiaoqiaoyun.com/expand/dingdingsyn.html","_target")
|
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(() => {
|
onMounted(() => {
|
||||||
let tenantId = getTenantId();
|
let tenantId = getTenantId();
|
||||||
@ -229,6 +251,7 @@
|
|||||||
syncDingTalk,
|
syncDingTalk,
|
||||||
btnLoading,
|
btnLoading,
|
||||||
handleIconClick,
|
handleIconClick,
|
||||||
|
cancelBindClick,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<a-collapse-panel key="2">
|
<a-collapse-panel key="2">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div style="width: 100%; justify-content: space-between; display: flex">
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="flex-flow">
|
<div class="flex-flow">
|
||||||
@ -40,6 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 20px; width: 100%; text-align: right">
|
<div style="margin-top: 20px; width: 100%; text-align: right">
|
||||||
<a-button @click="weEnterpriseEditClick">编辑</a-button>
|
<a-button @click="weEnterpriseEditClick">编辑</a-button>
|
||||||
|
<a-button v-if="appConfigData.id" @click="cancelBindClick" danger style="margin-left: 10px">取消绑定</a-button>
|
||||||
</div>
|
</div>
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
</a-collapse>
|
</a-collapse>
|
||||||
@ -61,7 +62,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onMounted, ref } from 'vue';
|
import { defineComponent, onMounted, ref } from 'vue';
|
||||||
import { getThirdConfigByTenantId } from './ThirdApp.api';
|
import { getThirdConfigByTenantId, deleteThirdAppConfig } from './ThirdApp.api';
|
||||||
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
||||||
import { useModal } from '/@/components/Modal';
|
import { useModal } from '/@/components/Modal';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
@ -97,6 +98,8 @@
|
|||||||
let values = await getThirdConfigByTenantId(params);
|
let values = await getThirdConfigByTenantId(params);
|
||||||
if (values) {
|
if (values) {
|
||||||
appConfigData.value = values;
|
appConfigData.value = values;
|
||||||
|
} else {
|
||||||
|
appConfigData.value = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +162,25 @@
|
|||||||
function seeBindWeChat() {
|
function seeBindWeChat() {
|
||||||
openBindModal(true,{ izBind: true })
|
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(() => {
|
onMounted(() => {
|
||||||
let tenantId = getTenantId();
|
let tenantId = getTenantId();
|
||||||
@ -175,6 +197,7 @@
|
|||||||
thirdUserByWechat,
|
thirdUserByWechat,
|
||||||
handleBindSuccess,
|
handleBindSuccess,
|
||||||
seeBindWeChat,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
//update-begin---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
|
//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){
|
if(res.code === ExceptionEnum.PHONE_SMS_FAIL_CODE){
|
||||||
openCaptchaModal(true, {});
|
openCaptchaModal(true, {});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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" />
|
<BasicForm @register="registerForm" />
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
@ -21,6 +21,15 @@
|
|||||||
//update-end---author:wangshuai ---date:20221123 for:[VUEN-2807]消息模板加一个查看功能--------------z
|
//update-end---author:wangshuai ---date:20221123 for:[VUEN-2807]消息模板加一个查看功能--------------z
|
||||||
schemas: formSchemas,
|
schemas: formSchemas,
|
||||||
showActionButtonGroup: false,
|
showActionButtonGroup: false,
|
||||||
|
baseRowStyle: {
|
||||||
|
marginTop: '10px',
|
||||||
|
},
|
||||||
|
labelCol: {
|
||||||
|
span: 5,
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
span: 17,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
// 注册 modal
|
// 注册 modal
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
@ -86,12 +86,23 @@ export const formSchemas: FormSchema[] = [
|
|||||||
label: '模板类型',
|
label: '模板类型',
|
||||||
field: 'templateType',
|
field: 'templateType',
|
||||||
component: 'JDictSelectTag',
|
component: 'JDictSelectTag',
|
||||||
|
defaultValue: '1',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
dictCode: 'msgType',
|
dictCode: 'msgType',
|
||||||
|
type: 'radio',
|
||||||
placeholder: '请选择模板类型',
|
placeholder: '请选择模板类型',
|
||||||
},
|
},
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '模板分类',
|
||||||
|
field: 'templateCategory',
|
||||||
|
component: 'JDictSelectTag',
|
||||||
|
componentProps: {
|
||||||
|
dictCode: 'msgCategory',
|
||||||
|
placeholder: '请选择模板分类',
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: '是否应用',
|
label: '是否应用',
|
||||||
field: 'useStatus',
|
field: 'useStatus',
|
||||||
|
@ -1,20 +1,113 @@
|
|||||||
<template>
|
<template>
|
||||||
<BasicModal v-bind="$attrs" @register="registerModal" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500">
|
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500">
|
||||||
<iframe :src="frameSrc" class="detail-iframe" />
|
<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>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
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
|
// 获取props
|
||||||
defineProps({
|
defineProps({
|
||||||
frameSrc: propTypes.string.def(''),
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<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 {
|
.detail-iframe {
|
||||||
border: 0;
|
border: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -24,4 +117,37 @@
|
|||||||
display: block;
|
display: block;
|
||||||
// -update-end--author:liaozhiyang---date:20240702---for:【TV360X-1685】通知公告查看出现两个滚动条
|
// -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>
|
</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>
|
<template>
|
||||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="900px" destroyOnClose>
|
<BasicModal
|
||||||
<BasicForm @register="registerForm" />
|
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>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -8,17 +21,24 @@
|
|||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
import { formSchema } from './notice.data';
|
import { formSchema } from './notice.data';
|
||||||
import { saveOrUpdate } from './notice.api';
|
import { getTempList, saveOrUpdate } from './notice.api';
|
||||||
// 声明Emits
|
// 声明Emits
|
||||||
const emit = defineEmits(['register', 'success']);
|
const emit = defineEmits(['register', 'success']);
|
||||||
const isUpdate = ref(true);
|
const isUpdate = ref(true);
|
||||||
|
const record = ref<any>({});
|
||||||
|
const templateOption = ref([]);
|
||||||
//表单配置
|
//表单配置
|
||||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||||
schemas: formSchema,
|
schemas: formSchema,
|
||||||
showActionButtonGroup: false,
|
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) => {
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
|
//加载模版
|
||||||
|
await initTemplate();
|
||||||
//重置表单
|
//重置表单
|
||||||
await resetFields();
|
await resetFields();
|
||||||
setModalProps({ confirmLoading: false });
|
setModalProps({ confirmLoading: false });
|
||||||
@ -31,12 +51,13 @@
|
|||||||
await setFieldsValue({
|
await setFieldsValue({
|
||||||
...data.record,
|
...data.record,
|
||||||
});
|
});
|
||||||
|
record.value = data.record;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//设置标题
|
//设置标题
|
||||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||||
//表单提交事件
|
//表单提交事件
|
||||||
async function handleSubmit(v) {
|
async function handleSubmit() {
|
||||||
try {
|
try {
|
||||||
let values = await validate();
|
let values = await validate();
|
||||||
setModalProps({ confirmLoading: true });
|
setModalProps({ confirmLoading: true });
|
||||||
@ -48,7 +69,7 @@
|
|||||||
values.userIds += ',';
|
values.userIds += ',';
|
||||||
}
|
}
|
||||||
//update-end-author:liusq---date:20230404--for: [issue#429]新增通知公告提交指定用户参数有undefined ---
|
//update-end-author:liusq---date:20230404--for: [issue#429]新增通知公告提交指定用户参数有undefined ---
|
||||||
if (isUpdate.value) {
|
if (isUpdate.value && record.value.sendStatus != '2') {
|
||||||
values.sendStatus = '0';
|
values.sendStatus = '0';
|
||||||
}
|
}
|
||||||
await saveOrUpdate(values, isUpdate.value);
|
await saveOrUpdate(values, isUpdate.value);
|
||||||
@ -60,4 +81,36 @@
|
|||||||
setModalProps({ confirmLoading: false });
|
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>
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.notice-cls-modal {
|
||||||
|
top: 20px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -34,17 +34,17 @@
|
|||||||
import { useModal } from '/@/components/Modal';
|
import { useModal } from '/@/components/Modal';
|
||||||
import NoticeModal from './NoticeModal.vue';
|
import NoticeModal from './NoticeModal.vue';
|
||||||
import DetailModal from './DetailModal.vue';
|
import DetailModal from './DetailModal.vue';
|
||||||
import { useMethods } from '/@/hooks/system/useMethods';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
import { useGlobSetting } from '/@/hooks/setting';
|
import { useGlobSetting } from '/@/hooks/setting';
|
||||||
import { getToken } from '/@/utils/auth';
|
import { getToken } from '/@/utils/auth';
|
||||||
import { columns, searchFormSchema } from './notice.data';
|
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';
|
import { useListPage } from '/@/hooks/system/useListPage';
|
||||||
const glob = useGlobSetting();
|
const glob = useGlobSetting();
|
||||||
const [registerModal, { openModal }] = useModal();
|
const [registerModal, { openModal }] = useModal();
|
||||||
const [register, { openModal: openDetail }] = useModal();
|
const [register, { openModal: openDetail }] = useModal();
|
||||||
const iframeUrl = ref('');
|
const iframeUrl = ref('');
|
||||||
|
const { createMessage, createConfirm } = useMessage();
|
||||||
// 列表页面公共参数、方法
|
// 列表页面公共参数、方法
|
||||||
const { prefixCls, onExportXls, onImportXls, tableContext, doRequest } = useListPage({
|
const { prefixCls, onExportXls, onImportXls, tableContext, doRequest } = useListPage({
|
||||||
designScope: 'notice-template',
|
designScope: 'notice-template',
|
||||||
@ -66,7 +66,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||||
|
//流程编码
|
||||||
|
const flowCode = 'dev_sys_announcement_001';
|
||||||
/**
|
/**
|
||||||
* 新增事件
|
* 新增事件
|
||||||
*/
|
*/
|
||||||
@ -92,6 +93,12 @@
|
|||||||
async function handleDelete(record) {
|
async function handleDelete(record) {
|
||||||
await deleteNotice({ id: record.id }, reload);
|
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) {
|
function handleDetail(record) {
|
||||||
iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
|
iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
|
||||||
openDetail(true);
|
openDetail(true, { record });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作列定义
|
* 操作列定义
|
||||||
* @param record
|
* @param record
|
||||||
@ -131,6 +139,11 @@
|
|||||||
onClick: handleEdit.bind(null, record),
|
onClick: handleEdit.bind(null, record),
|
||||||
ifShow: record.sendStatus == 0 || record.sendStatus == '2',
|
ifShow: record.sendStatus == 0 || record.sendStatus == '2',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: '查看',
|
||||||
|
onClick: handleDetail.bind(null, record),
|
||||||
|
ifShow: record.sendStatus == 1,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -148,7 +161,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '发布',
|
label: '发布',
|
||||||
ifShow: record.sendStatus == 0,
|
ifShow: (!record?.izApproval || record.izApproval == '0') && record.sendStatus == 0,
|
||||||
onClick: handleRelease.bind(null, record.id),
|
onClick: handleRelease.bind(null, record.id),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -160,8 +173,22 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '查看',
|
label: '发布',
|
||||||
onClick: handleDetail.bind(null, record),
|
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',
|
save = '/sys/annountCement/add',
|
||||||
edit = '/sys/annountCement/edit',
|
edit = '/sys/annountCement/edit',
|
||||||
delete = '/sys/annountCement/delete',
|
delete = '/sys/annountCement/delete',
|
||||||
|
queryById = '/sys/annountCement/queryById',
|
||||||
deleteBatch = '/sys/annountCement/deleteBatch',
|
deleteBatch = '/sys/annountCement/deleteBatch',
|
||||||
exportXls = '/sys/annountCement/exportXls',
|
exportXls = '/sys/annountCement/exportXls',
|
||||||
importExcel = '/sys/annountCement/importExcel',
|
importExcel = '/sys/annountCement/importExcel',
|
||||||
releaseData = '/sys/annountCement/doReleaseData',
|
releaseData = '/sys/annountCement/doReleaseData',
|
||||||
reovkeData = '/sys/annountCement/doReovkeData',
|
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;
|
export const getImportUrl = Api.importExcel;
|
||||||
/**
|
/**
|
||||||
* 查询租户列表
|
* 查询消息列表
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export const getList = (params) => {
|
export const getList = (params) => {
|
||||||
@ -33,7 +39,7 @@ export const getList = (params) => {
|
|||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export const saveOrUpdate = (params, isUpdate) => {
|
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 });
|
return defHttp.post({ url: url, params });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,6 +52,15 @@ export const deleteNotice = (params, handleSuccess) => {
|
|||||||
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
|
* @param id
|
||||||
*/
|
*/
|
||||||
export const doReovkeData = (params) => defHttp.get({ url: Api.reovkeData, params });
|
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 { BasicColumn, FormSchema } from '/@/components/Table';
|
||||||
import { rules } from '/@/utils/helper/validator';
|
|
||||||
import { render } from '/@/utils/common/renderUtils';
|
import { render } from '/@/utils/common/renderUtils';
|
||||||
|
import { h } from 'vue';
|
||||||
|
import { Tinymce } from '@/components/Tinymce';
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
@ -87,9 +88,24 @@ export const formSchema: FormSchema[] = [
|
|||||||
placeholder: '请选择类型',
|
placeholder: '请选择类型',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'izTop',
|
||||||
|
label: '是否置顶',
|
||||||
|
defaultValue: '0',
|
||||||
|
component: 'JSwitch',
|
||||||
|
componentProps: {
|
||||||
|
//取值 options
|
||||||
|
options: ['1', '0'],
|
||||||
|
//文本option
|
||||||
|
labelOptions: ['是', '否'],
|
||||||
|
placeholder: '是否置顶',
|
||||||
|
checkedChildren: '是',
|
||||||
|
unCheckedChildren: '否',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'titile',
|
field: 'titile',
|
||||||
label: '标题',
|
label: '通告标题',
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
required: true,
|
required: true,
|
||||||
componentProps: {
|
componentProps: {
|
||||||
@ -114,8 +130,15 @@ export const formSchema: FormSchema[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'msgAbstract',
|
field: 'msgAbstract',
|
||||||
label: '摘要',
|
label: '通告摘要',
|
||||||
component: 'InputTextArea',
|
component: 'InputTextArea',
|
||||||
|
componentProps: {
|
||||||
|
allowClear: true,
|
||||||
|
autoSize: {
|
||||||
|
minRows: 2,
|
||||||
|
maxRows: 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
@ -154,9 +177,18 @@ export const formSchema: FormSchema[] = [
|
|||||||
},
|
},
|
||||||
ifShow: ({ values }) => values.msgType == 'USER',
|
ifShow: ({ values }) => values.msgType == 'USER',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'msgClassify',
|
||||||
|
label: '公告分类',
|
||||||
|
component: 'JDictSelectTag',
|
||||||
|
componentProps: {
|
||||||
|
dictCode: 'notice_type',
|
||||||
|
placeholder: '请选择公告分类',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'priority',
|
field: 'priority',
|
||||||
label: '优先级',
|
label: '优先级别',
|
||||||
defaultValue: 'H',
|
defaultValue: 'H',
|
||||||
component: 'JDictSelectTag',
|
component: 'JDictSelectTag',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
@ -166,9 +198,211 @@ export const formSchema: FormSchema[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'msgContent',
|
field: 'izApproval',
|
||||||
label: '内容',
|
label: '是否审批',
|
||||||
|
component: 'RadioGroup',
|
||||||
|
defaultValue: '0',
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '是',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '否',
|
||||||
|
value: '0',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'msgTemplate',
|
||||||
|
label: '公告模版',
|
||||||
component: 'Input',
|
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,
|
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),
|
confirm: handleDelete.bind(null, record),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '首页配置',
|
|
||||||
onClick: handleIndexConfig.bind(null, record.roleCode),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="用户代理" @ok="handleSubmit" destroyOnClose>
|
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="用户代理" @ok="handleSubmit" destroyOnClose>
|
||||||
<BasicForm @register="registerForm" />
|
<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>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@ -8,7 +13,8 @@
|
|||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||||
import { formAgentSchema } from './user.data';
|
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
|
// 声明Emits
|
||||||
const emit = defineEmits(['success', 'register']);
|
const emit = defineEmits(['success', 'register']);
|
||||||
//表单配置
|
//表单配置
|
||||||
@ -16,6 +22,8 @@
|
|||||||
schemas: formAgentSchema,
|
schemas: formAgentSchema,
|
||||||
showActionButtonGroup: false,
|
showActionButtonGroup: false,
|
||||||
});
|
});
|
||||||
|
//表单数据
|
||||||
|
const agentData = ref<any>({});
|
||||||
//表单赋值
|
//表单赋值
|
||||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||||
//重置表单
|
//重置表单
|
||||||
@ -24,6 +32,8 @@
|
|||||||
//查询获取表单数据
|
//查询获取表单数据
|
||||||
const res = await getUserAgent({ userName: data.userName });
|
const res = await getUserAgent({ userName: data.userName });
|
||||||
data = res.result ? res.result : data;
|
data = res.result ? res.result : data;
|
||||||
|
//代理数据赋值
|
||||||
|
agentData.value = { ...data };
|
||||||
//表单赋值
|
//表单赋值
|
||||||
await setFieldsValue({ ...data });
|
await setFieldsValue({ ...data });
|
||||||
});
|
});
|
||||||
@ -42,4 +52,20 @@
|
|||||||
setModalProps({ confirmLoading: false });
|
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>
|
</script>
|
||||||
|
@ -8,6 +8,7 @@ enum Api {
|
|||||||
edit = '/sys/user/edit',
|
edit = '/sys/user/edit',
|
||||||
agentSave = '/sys/sysUserAgent/add',
|
agentSave = '/sys/sysUserAgent/add',
|
||||||
agentEdit = '/sys/sysUserAgent/edit',
|
agentEdit = '/sys/sysUserAgent/edit',
|
||||||
|
deleteAgent = '/sys/sysUserAgent/delete',
|
||||||
getUserRole = '/sys/user/queryUserRole',
|
getUserRole = '/sys/user/queryUserRole',
|
||||||
duplicateCheck = '/sys/duplicate/check',
|
duplicateCheck = '/sys/duplicate/check',
|
||||||
deleteUser = '/sys/user/delete',
|
deleteUser = '/sys/user/delete',
|
||||||
@ -208,6 +209,15 @@ export const saveOrUpdateAgent = (params) => {
|
|||||||
let url = params.id ? Api.agentEdit : Api.agentSave;
|
let url = params.id ? Api.agentEdit : Api.agentSave;
|
||||||
return defHttp.post({ url: url, params });
|
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('/');
|
serverOptions.origin = VITE_GLOB_QIANKUN_MICRO_APP_ENTRY!.split('/').slice(0, 3).join('/');
|
||||||
}
|
}
|
||||||
// ----- [end] 【JEECG作为乾坤子应用】 -----
|
// ----- [end] 【JEECG作为乾坤子应用】 -----
|
||||||
|
|
||||||
|
console.log('[init] Start Port: ', VITE_PORT);
|
||||||
|
console.log('[init] Vite Proxy Config: ', VITE_PROXY);
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
base: isQiankunMicro ? VITE_GLOB_QIANKUN_MICRO_APP_ENTRY : VITE_PUBLIC_PATH,
|
base: isQiankunMicro ? VITE_GLOB_QIANKUN_MICRO_APP_ENTRY : VITE_PUBLIC_PATH,
|
||||||
root,
|
root,
|
||||||
|