Browse Source

Merge branch 'master' into ai_dev

# Conflicts:
#	package.json
ai_dev
zhouhaibin 2 months ago
parent
commit
59bf04245d
  1. 32
      CHANGELOG.md
  2. 12
      README.md
  3. 2
      internal/vite-config/package.json
  4. 13
      package.json
  5. 2
      packages/hooks/package.json
  6. 2
      src/api/monitor/online/index.ts
  7. 13
      src/api/system/tenant/index.ts
  8. 22
      src/components/Application/src/AppTenantToggle.vue
  9. 2
      src/components/Table/src/components/settings/index.vue
  10. 9
      src/layouts/default/menu/index.vue
  11. 10
      src/layouts/default/sider/MixSider.vue
  12. 54
      src/locales/lang/en/menu.json
  13. 54
      src/locales/lang/zh-CN/menu.json
  14. 42
      src/logics/error-handle/index.ts
  15. 5
      src/router/helper/menuHelper.ts
  16. 26
      src/router/helper/routeHelper.ts
  17. 2
      src/router/routes/modules/dashboard.ts
  18. 12
      src/store/modules/dict.ts
  19. 42
      src/utils/dict.ts
  20. 3
      src/views/monitor/cache/components/MemoryChart.vue
  21. 3
      src/views/monitor/logininfor/LoginInfoModal.vue
  22. 2
      src/views/system/config/config.data.ts
  23. 13
      src/views/system/dict/type/DictType.vue
  24. 6
      src/views/system/menu/index.vue
  25. 5
      src/views/system/menu/menu.data.ts
  26. 2
      src/views/system/post/index.vue
  27. 2
      src/views/system/role/RoleAuthModal.vue
  28. 13
      src/views/system/role/RoleDrawer.vue
  29. 1
      src/views/system/role/role.data.ts
  30. 18
      src/views/system/tenant/index.vue
  31. 6
      src/views/system/tenantPackage/TenantPackageDrawer.vue
  32. 1
      src/views/system/user/DeptTree.vue
  33. 20
      src/views/system/user/UserDrawer.vue
  34. 4
      src/views/system/user/user.data.ts
  35. 22
      src/views/tool/gen/ImportTableModal.vue
  36. 1
      src/views/workflow/components/UserSelectModal/index.vue
  37. 8
      src/views/演示使用自行删除/wechat/index.vue

32
CHANGELOG.md

@ -1,3 +1,35 @@
# 1.4.6
**Other**
- 升级部分核心依赖 如ant-design-vue/vue等
# 1.4.5
**Refactor**
使用其他方案重构`路由参数`的处理
**Fix**
超级管理员切换租户后 字典丢失并且不会重新加载
部门树超过屏幕高度后无法滚动 -> 设置固定高度
用户管理 更新时岗位选择option无法正常显示
**Feature**
某些人不按规范使用也从不看控制台导致的页面白屏 增加提示信息
增加菜单名称i18n功能
**Other**
升级ant-design-vue至最新版本(v4.2.5)
用户管理 优化岗位选择placeholder
# 1.4.4
**Feature**

12
README.md

@ -2,11 +2,11 @@
## 提示
该仓库为老版本 **[vben2]** 目前follow后端版本 vben5官方组件完善后此仓库不再进行开发
<h3>该仓库为老版本[vben2]已不再进行维护/更新</h3>
适配最新的 **[vben5]** 移步[gitee地址](https://gitee.com/dapppp/ruoyi-plus-vben5) vben5版本等待官方组件中
最后支持后端版本 **5.2.3/2.2.3**
根据白嫖率会不定期关闭fork😅
适配最新的 **[vben5]** 移步[gitee地址](https://gitee.com/dapppp/ruoyi-plus-vben5)
## 简介
@ -15,7 +15,7 @@
| 组件/框架 | 版本 |
| :------------- | :----- |
| vben | 2.11.4 |
| ant-design-vue | 4.2.1 |
| ant-design-vue | 4.2.5 |
| vue | 3.4.37 |
对应后端项目: **(分布式 5.X 分支 微服务 2.分支)**
@ -30,10 +30,6 @@ admin 账号: admin admin123
[预览地址点这里](http://plus.dapdap.top)
## WX Group
暂不开放
## 文档
[vben 文档地址](https://doc.vvbin.cn/)

2
internal/vite-config/package.json

@ -39,7 +39,7 @@
"@types/fs-extra": "11.0.4",
"@vitejs/plugin-vue": "5.0.4",
"@vitejs/plugin-vue-jsx": "3.1.0",
"ant-design-vue": "4.2.1",
"ant-design-vue": "4.2.6",
"dayjs": "1.11.10",
"dotenv": "16.4.5",
"fs-extra": "11.2.0",

13
package.json

@ -1,6 +1,7 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"name": "ruoyi-plus-vben",
"version": "1.4.4",
"version": "1.4.5",
"homepage": "https://gitee.com/dapppp/ruoyi-plus-vben.git",
"bugs": {
"url": "https://gitee.com/dapppp/ruoyi-plus-vben/issues"
@ -76,7 +77,7 @@
"@vue/shared": "3.4.37",
"@vueuse/core": "^10.11.1",
"@zxcvbn-ts/core": "3.0.4",
"ant-design-vue": "4.2.3",
"ant-design-vue": "4.2.6",
"axios": "1.7.4",
"bpmn-js": "17.5.0",
"bpmn-js-token-simulation": "0.34.1",
@ -107,7 +108,7 @@
"tinymce": "7.3.0",
"unocss": "0.62.1",
"vditor": "3.10.5",
"vue": "3.4.37",
"vue": "3.5.13",
"vue-i18n": "9.13.1",
"vue-json-pretty": "2.4.0",
"vue-router": "4.4.3",
@ -122,7 +123,7 @@
"devDependencies": {
"@commitlint/cli": "19.3.0",
"@commitlint/config-conventional": "19.2.2",
"@iconify/json": "2.2.203",
"@iconify/json": "2.2.276",
"@purge-icons/generated": "0.10.0",
"@types/codemirror": "5.60.15",
"@types/crypto-js": "4.2.2",
@ -137,6 +138,8 @@
"@vben/ts-config": "workspace:*",
"@vben/types": "workspace:*",
"@vben/vite-config": "workspace:*",
"@vue/compiler-sfc": "3.5.13",
"@vue/test-utils": "2.4.6",
"@vue/compiler-sfc": "3.4.37",
"@vue/test-utils": "2.4.5",
"@microsoft/fetch-event-source":"2.0.1",
@ -157,6 +160,8 @@
"typescript": "5.5.4",
"unbuild": "2.0.0",
"vite": "5.4.0",
"vite-plugin-vue-devtools": "7.6.5",
"vue-tsc": "2.1.10"
"vite-plugin-vue-devtools": "7.3.8",
"vue-tsc": "2.0.29",
"layer-vue":"2.0.0-alpha.0",

2
packages/hooks/package.json

@ -32,7 +32,7 @@
"dependencies": {
"@vueuse/core": "10.11.0",
"lodash-es": "4.17.21",
"vue": "3.4.37"
"vue": "3.5.13"
},
"devDependencies": {
"@vben/types": "workspace:*"

2
src/api/monitor/online/index.ts

@ -29,5 +29,5 @@ export function forceLogout(tokenId: string) {
* @returns
*/
export function forceLogout2(tokenId: string) {
return defHttp.post<void>({ url: Api.root + '/' + tokenId });
return defHttp.post<void>({ url: Api.root + 'myself/' + tokenId });
}

13
src/api/system/tenant/index.ts

@ -10,6 +10,7 @@ enum Api {
tenantDynamic = '/system/tenant/dynamic',
tenantDynamicClear = '/system/tenant/dynamic/clear',
tenantSyncPackage = '/system/tenant/syncTenantPackage',
dictSync = '/system/tenant/syncTenantDict',
}
export function tenantList(params?: PageQuery) {
@ -68,3 +69,15 @@ export function tenantSyncPackage(tenantId: string, packageId: string, showMsg =
{ successMessageMode: showMsg ? 'message' : 'none' },
);
}
/**
*
* @param tenantId ID
* @returns void
*/
export function dictSyncTenant(tenantId?: string) {
return defHttp.get<void>(
{ url: Api.dictSync, params: { tenantId } },
{ successMessageMode: 'message' },
);
}

22
src/components/Application/src/AppTenantToggle.vue

@ -45,6 +45,7 @@
import { storeToRefs } from 'pinia';
import { useAppInject } from '@/hooks/web/useAppInject';
import Icon from '@/components/Icon/Icon.vue';
import type { SelectHandler } from 'ant-design-vue/es/vc-select/Select';
const SelectOption = Select.Option;
@ -76,37 +77,36 @@
const { closeAll } = useTabs();
const { createMessage } = useMessage();
function close(checked: boolean) {
async function close(checked: boolean) {
// store
setChecked(checked);
//
closeAll();
await closeAll();
//
go(PageEnum.BASE_HOME);
}
const dictStore = useDictStore();
/**
* 为什么要用any ide报错😅 实际类型为string
*/
async function onSelected(tenantId: any, option: any) {
const onSelected: SelectHandler = async (tenantId: string, option: any) => {
if (unref(lastSelected) === tenantId) {
// createMessage.info('');
return;
}
await tenantDynamicToggle(tenantId);
lastSelected.value = tenantId;
dictStore.resetCache();
createMessage.success('切换当前租户为: ' + option.title);
close(true);
}
await close(true);
// (unknown)
setTimeout(() => dictStore.resetCache());
};
async function onDeselect() {
await tenantDynamicClear();
dictStore.resetCache();
createMessage.success('还原为默认租户');
lastSelected.value = '';
close(false);
await close(false);
// (unknown)
setTimeout(() => dictStore.resetCache());
}
</script>

2
src/components/Table/src/components/settings/index.vue

@ -39,7 +39,7 @@
redo: true,
size: true,
setting: true,
settingCache: true,
settingCache: false,
fullScreen: false,
...props.setting,
};

9
src/layouts/default/menu/index.vue

@ -19,6 +19,8 @@
import { useRootSetting } from '@/hooks/setting/useRootSetting';
import { useAppInject } from '@/hooks/web/useAppInject';
import { useDesign } from '@/hooks/web/useDesign';
import { useRouter } from 'vue-router';
import { isPlainObject } from 'lodash-es';
export default defineComponent({
name: 'LayoutMenu',
@ -110,7 +112,14 @@
* @param menu
*/
const currentRoutes = useRouter().getRoutes();
function handleMenuClick(path: string) {
//
const found = currentRoutes.find((item) => item.path === path);
if (found && isPlainObject(found.meta.query)) {
go({ path: path as any, query: found.meta.query });
return;
}
go(path);
}

10
src/layouts/default/sider/MixSider.vue

@ -87,7 +87,7 @@
import type { Menu } from '@/router/types';
import type { CSSProperties } from 'vue';
import { computed, onMounted, ref, unref, watch } from 'vue';
import type { RouteLocationNormalized } from 'vue-router';
import { useRouter, type RouteLocationNormalized } from 'vue-router';
import { ScrollContainer } from '@/components/Container';
import { SimpleMenu } from '@/components/SimpleMenu';
import Icon from '@/components/Icon/Icon.vue';
@ -107,6 +107,7 @@
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
import { theme } from 'ant-design-vue';
import { isPlainObject } from 'lodash-es';
const SimpleMenuTag = createAsyncComponent(
() => import('@/components/SimpleMenu/src/SimpleMenuTag.vue'),
@ -279,7 +280,14 @@
}
}
const currentRoutes = useRouter().getRoutes();
function handleMenuClick(path: string) {
//
const found = currentRoutes.find((item) => item.path === path);
if (found && isPlainObject(found.meta.query)) {
go({ path: path as any, query: found.meta.query });
return;
}
go(path);
}

54
src/locales/lang/en/menu.json

@ -0,0 +1,54 @@
{
"system": {
"root": "System",
"user": "User",
"role": "Role",
"menu": "Menu",
"dept": "Department",
"post": "Post",
"dict": "Dictionary",
"config": "Parameter Settings",
"notice": "Notifications",
"log": {
"root": "Log",
"operation": "Operation Log",
"login": "Login Log"
},
"oss": "File",
"client": "Client"
},
"tenant": {
"root": "Tenant",
"package": "Package"
},
"monitor": {
"root": "System Monitoring",
"online": "Online Users",
"cache": "Cache Monitoring",
"admin": "Admin Monitoring",
"job": "Task Scheduling Center"
},
"tool": {
"root": "System Tools",
"gen": "Code Generation"
},
"workflow": {
"root": "Workflow",
"category": "Process Category",
"model": "Model",
"define": "Process Definition",
"monitor": {
"root": "Process Monitoring",
"instance": "Process Instance",
"todo": "Pending Tasks"
},
"form": "Form"
},
"task": {
"root": "My Tasks",
"apply": "My Initiated Tasks",
"todo": "My Pending Tasks",
"done": "My Completed Tasks",
"cc": "My CC"
}
}

54
src/locales/lang/zh-CN/menu.json

@ -0,0 +1,54 @@
{
"system": {
"root": "系统管理",
"user": "用户管理",
"role": "角色管理",
"menu": "菜单管理",
"dept": "部门管理",
"post": "岗位管理",
"dict": "字典管理",
"config": "参数设置",
"notice": "通知公告",
"log": {
"root": "日志管理",
"operation": "操作日志",
"login": "登录日志"
},
"oss": "文件管理",
"client": "客户端管理"
},
"tenant": {
"root": "租户管理",
"package": "套餐管理"
},
"monitor": {
"root": "系统监控",
"online": "在线用户",
"cache": "缓存监控",
"admin": "Admin监控",
"job": "任务调度中心"
},
"tool": {
"root": "系统工具",
"gen": "代码生成"
},
"workflow": {
"root": "工作流",
"category": "流程分类",
"model": "模型管理",
"define": "流程定义",
"monitor": {
"root": "流程监控",
"instance": "流程实例",
"todo": "待办任务"
},
"form": "表单管理"
},
"task": {
"root": "我的任务",
"apply": "我发起的",
"todo": "我的待办",
"done": "我的已办",
"cc": "我的抄送"
}
}

42
src/logics/error-handle/index.ts

@ -7,8 +7,9 @@ import type { ErrorLogInfo } from '#/store';
import { useErrorLogStoreWithOut } from '@/store/modules/errorLog';
import { ErrorTypeEnum } from '@/enums/exceptionEnum';
import { App } from 'vue';
import { App, h } from 'vue';
import projectSetting from '@/settings/projectSetting';
import { notification } from 'ant-design-vue';
/**
* Handling error stack information
@ -76,6 +77,43 @@ function vueErrorHandler(err: unknown, vm: any, info: string) {
});
}
/**
* <Transition> 使
* @param msg
* @param vm
* @param trace
*/
function vueWarnHandler(msg: string, _vm: any, trace: string) {
console.warn(`[Vue warn msg]: ${msg}`);
console.warn(`[Vue warn trace]: ${trace}`);
if (msg.includes('Component inside <Transition>')) {
const msg1 = '我猜你现在白屏了💩';
const msg2 = '不看文档就一直白屏吧🤣';
const msg3 = '套一层<div>很难吗?🤗';
const msg4 =
'<Transition> 仅支持单个元素或组件作为其插槽内容。如果内容是一个组件,这个组件必须仅有一个根元素。';
for (let i = 0; i < 10; i++) {
notification.error({
message: '错误',
description: h('div', null, [
h('div', null, msg1),
h('div', null, msg2),
h('div', null, msg3),
h(
'a',
{
href: 'https://cn.vuejs.org/guide/built-ins/transition#the-transition-component',
target: '_blank',
},
msg4,
),
]),
duration: null,
});
}
}
}
/**
* Configure script error handling function
*/
@ -165,6 +203,8 @@ function registerResourceErrorHandler() {
* @param app
*/
export function setupErrorHandle(app: App) {
// 这个会影响堆栈打印 不需要可以注释/删除
app.config.warnHandler = vueWarnHandler;
const { useErrorHandle } = projectSetting;
if (!useErrorHandle) {
return;

5
src/router/helper/menuHelper.ts

@ -5,7 +5,6 @@ import { cloneDeep } from 'lodash-es';
import { isHttpUrl } from '@/utils/is';
import { RouteParams } from 'vue-router';
import { toRaw } from 'vue';
import { setObjToUrlParams } from '@/utils';
export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
@ -33,10 +32,6 @@ function joinParentPath(menus: Menu[], parentPath = '') {
if (menu?.children?.length) {
joinParentPath(menu.children, menu.meta?.hidePathForChildren ? parentPath : menu.path);
}
// 添加query参数
if (menu.meta && menu.meta.query) {
menu.path += setObjToUrlParams('', menu.meta.query);
}
}
}

26
src/router/helper/routeHelper.ts

@ -2,11 +2,13 @@ import type { AppRouteModule, AppRouteRecordRaw } from '@/router/types';
import type { Router, RouteRecordNormalized } from 'vue-router';
import { getParentLayout, LAYOUT, EXCEPTION_COMPONENT } from '@/router/constant';
import { cloneDeep, omit } from 'lodash-es';
import { cloneDeep, isPlainObject, omit } from 'lodash-es';
import { warn } from '@/utils/log';
import { createRouter, createWebHashHistory } from 'vue-router';
import type { Menu } from '@/api/auth/model';
import { createCustomNameComponent } from '@/utils/factory/createCustomNameComponent';
import { setObjToUrlParams } from '@/utils';
import { useMessage } from '@/hooks/web/useMessage';
export type LayoutMapKey = 'LAYOUT';
const IFRAME = () => import('@/layouts/components/iframe/FrameBlank.vue');
@ -60,7 +62,10 @@ export function transformToAppRoutes(menuList: Menu[]) {
const query = JSON.parse(item.query);
appRoute.meta.query = query;
} catch (e) {
console.error('错误的路由参数类型, 必须为json格式', e);
const message = `[${item.path}]错误的路由参数类型, 必须为json格式`;
const { createMessage } = useMessage();
createMessage.error(message);
console.error(message, e);
}
}
/**
@ -98,15 +103,24 @@ export function transformToAppRoutes(menuList: Menu[]) {
/**
* & redirect到一级路由
*
* (Layout)
* @param appRoutes transformToAppRoutes转换而来
* @warning & 使
* @warning & 使
* @warning & 使
*/
export function addRootRedirect(appRoutes: AppRouteRecordRaw[]) {
appRoutes.forEach((item) => {
if (item.children && item.children.length > 0) {
/**
* &
*
*
*/
const query = item.children[0].meta?.query;
if (isPlainObject(query)) {
const redirect = setObjToUrlParams(`${item.path}/${item.children[0].path}`, query);
item.redirect = redirect;
return;
}
// 不包含query 直接拼接
item.redirect = `${item.path}/${item.children[0].path}`;
}
});

2
src/router/routes/modules/dashboard.ts

@ -20,6 +20,7 @@ const dashboard: AppRouteModule = {
component: () => import('@/layouts/local/dashboard/analysis/index.vue'),
meta: {
// affix: true,
icon: 'ant-design:area-chart-outlined',
title: t('routes.dashboard.analysis'),
},
},
@ -28,6 +29,7 @@ const dashboard: AppRouteModule = {
name: 'Workbench',
component: () => import('@/layouts/local/dashboard/workbench/index.vue'),
meta: {
icon: 'ant-design:desktop-outlined',
title: t('routes.dashboard.workbench'),
},
},

12
src/store/modules/dict.ts

@ -33,8 +33,16 @@ export const useDictStore = defineStore('dict', {
},
actions: {
setDictInfo(dictName: string, dictValue: DictData[]): void {
this.dictMap.set(dictName, dictValue);
this.dictOptionsMap.set(dictName, dictToOptions(dictValue));
if (this.dictMap.has(dictName) && this.dictMap.get(dictName)?.length === 0) {
this.dictMap.get(dictName)?.push(...dictValue);
} else {
this.dictMap.set(dictName, dictValue);
}
if (this.dictOptionsMap.has(dictName) && this.dictOptionsMap.get(dictName)?.length === 0) {
this.dictOptionsMap.get(dictName)?.push(...dictToOptions(dictValue));
} else {
this.dictOptionsMap.set(dictName, dictToOptions(dictValue));
}
},
getDict(dictName: string): DictData[] {
if (!dictName) return [];

42
src/utils/dict.ts

@ -1,4 +1,4 @@
import { useDictStoreWithOut, Option, dictToOptions } from '@/store/modules/dict';
import { useDictStoreWithOut, Option } from '@/store/modules/dict';
import { dictDataInfo } from '@/api/system/dict/dictData';
import { DictData } from '@/api/system/dict/dictData.model';
@ -7,25 +7,27 @@ import { DictData } from '@/api/system/dict/dictData.model';
*
* api的问题(abortController )
* index表单 modal drawer总共会请求三次
*
* todo store
*/
const dictRequestCache = new Map<string, Promise<void | DictData[]>>();
const dictRequestCache = new Map<string, Promise<DictData[] | void>>();
export function getDict(dictName: string): DictData[] {
const { getDict, setDictInfo } = useDictStoreWithOut();
// 这里拿到
const dictList: DictData[] = getDict(dictName);
if (dictList.length === 0) {
// 检查请求状态缓存
if (!dictRequestCache[dictName]) {
dictRequestCache[dictName] = dictDataInfo(dictName).then((resp) => {
const dictList = getDict(dictName);
// 检查请求状态缓存
if (dictList.length === 0 && !dictRequestCache.has(dictName)) {
dictRequestCache.set(
dictName,
dictDataInfo(dictName).then((resp) => {
// 缓存到store 这样就不用重复获取了
// 内部处理了push的逻辑 这里不用push
setDictInfo(dictName, resp);
// 这里不可用dictList = resp
dictList.push(...resp);
// 移除请求状态缓存
dictRequestCache.delete(dictName);
});
}
}),
);
}
return dictList;
}
@ -33,20 +35,18 @@ export function getDict(dictName: string): DictData[] {
export function getDictOptions(dictName: string): Option[] {
const { getDictOptions, setDictInfo } = useDictStoreWithOut();
const dictOptionList = getDictOptions(dictName);
if (dictOptionList.length === 0) {
// 检查请求状态缓存
if (!dictRequestCache[dictName]) {
dictRequestCache[dictName] = dictDataInfo(dictName).then((resp) => {
// 检查请求状态缓存
if (dictOptionList.length === 0 && !dictRequestCache.has(dictName)) {
dictRequestCache.set(
dictName,
dictDataInfo(dictName).then((resp) => {
// 缓存到store 这样就不用重复获取了
// 内部处理了push的逻辑 这里不用push
setDictInfo(dictName, resp);
// 转为options
const option = dictToOptions(resp);
// 这里不可用dictOptionList = option
dictOptionList.push(...option);
// 移除请求状态缓存
dictRequestCache.delete(dictName);
});
}
}),
);
}
return dictOptionList;
}

3
src/views/monitor/cache/components/MemoryChart.vue

@ -52,6 +52,9 @@
},
series: [
{
progress: {
show: true,
},
animation: true,
animationDuration: 1000,
name: '峰值',

3
src/views/monitor/logininfor/LoginInfoModal.vue

@ -1,7 +1,6 @@
<template>
<BasicModal v-bind="$attrs" title="查看登录日志" @register="registerModal">
<BasicModal v-bind="$attrs" title="查看登录日志" @register="registerModal" :footer="null">
<Description @register="registerDescription" />
<template #footer> </template>
</BasicModal>
</template>

2
src/views/system/config/config.data.ts

@ -85,7 +85,7 @@ export const modalSchemas: FormSchema[] = [
{
field: 'configValue',
label: '参数键值',
component: 'Input',
component: 'InputTextArea',
required: true,
},
{

13
src/views/system/dict/type/DictType.vue

@ -3,13 +3,15 @@
<BasicTable @register="tableRegister" @row-click="handleRowClick">
<template #toolbar>
<Space>
<a-button class="<sm:hidden" v-auth="'system:dict:edit'" @click="handleRefreshCache">
刷新缓存
</a-button>
<a-button
class="<sm:hidden"
v-auth="'system:dict:export'"
@click="downloadExcel(dictExport, '字典信息', getForm().getFieldsValue())"
>导出</a-button
>
<a-button @click="handleRefreshCache" v-auth="'system:dict:query'"> 刷新缓存 </a-button>
<a-button
class="<sm:hidden"
type="primary"
@ -59,18 +61,18 @@
</template>
<script setup lang="ts">
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { BasicTable, TableAction, useTable } from '@/components/Table';
import {
dictList,
dictExport,
refreshDictTypeCache,
dictList,
dictTypeRemove,
refreshDictTypeCache,
} from '@/api/system/dict/dictType';
import { Space } from 'ant-design-vue';
import { useModal } from '@/components/Modal';
import { downloadExcel } from '@/utils/file/download';
import DictTypeModal from './DictTypeModal.vue';
import { formSchemas, columns } from './dictType.data';
import { columns, formSchemas } from './dictType.data';
import { IconEnum } from '@/enums/appEnum';
defineOptions({ name: 'DictType' });
@ -106,7 +108,6 @@
key: 'action',
},
});
function handleRowClick(record: Recordable) {
const { dictType } = record;
emit('getDictType', dictType);

6
src/views/system/menu/index.vue

@ -3,6 +3,12 @@
<BasicTable @register="tableRegister" @row-db-click="handleDoubleClick">
<template #toolbar>
<Space>
<a
href="https://dapdap.top/components/%E5%9B%BE%E6%A0%87.html#%E8%8F%9C%E5%8D%95%E6%A0%8F%E5%9B%BE%E6%A0%87"
target="_blank"
class="<sm:hidden"
>🤔如何替换图标</a
>
<Tooltip title="修改后是否刷新菜单栏">
<Switch id="refreshMenu" v-model:checked="refreshMenuRef" />
</Tooltip>

5
src/views/system/menu/menu.data.ts

@ -4,6 +4,7 @@ import { FormSchema } from '@/components/Form';
import { getDictOptions } from '@/utils/dict';
import { DictEnum } from '@/enums/dictEnum';
import { isUrl } from '@/utils/is';
import { useI18n } from '@/hooks/web/useI18n';
// (M目录 C菜单 F按钮)
const menuTypes = {
@ -17,6 +18,10 @@ export const tableColumns: BasicColumn[] = [
{
title: '菜单名称',
dataIndex: 'menuName',
customRender: ({ value }) => {
const { t } = useI18n();
return t(value);
},
},
{
title: '图标',

2
src/views/system/post/index.vue

@ -56,7 +56,7 @@
ifShow: record.userId !== 1,
popConfirm: {
placement: 'left',
title: `是否删除用户[${record.userName}]-${record.nickName}?`,
title: `是否删除岗位[${record.postName}]?`,
confirm: handleDelete.bind(null, record),
},
},

2
src/views/system/role/RoleAuthModal.vue

@ -3,7 +3,7 @@
v-bind="$attrs"
title="分配权限"
:width="600"
:min-height="350"
:min-height="450"
@register="registerInnerModal"
@ok="handleSubmit"
@cancel="resetForm"

13
src/views/system/role/RoleDrawer.vue

@ -43,9 +43,10 @@
import { Card, FormItemRest } from 'ant-design-vue';
import { BasicTree } from '@/components/Tree';
import { modalSchemas, excludeIds } from './role.data';
import { findGroupParentIds, findAllIds, filter } from '@/utils/helper/treeHelper';
import { findGroupParentIds, findAllIds, filter, eachTree } from '@/utils/helper/treeHelper';
import { CheckInfo } from 'ant-design-vue/es/vc-tree/props';
import { useMaxWidthOrDefault } from '@/hooks/web/useSize';
import { useI18n } from '@/hooks/web/useI18n';
defineOptions({ name: 'RoleDrawer' });
@ -68,6 +69,8 @@
const [registerInnerDrawer, { drawerLoading, closeDrawer }] = useDrawerInner(
async (data: { record?: Recordable; update: boolean }) => {
drawerLoading(true);
const { t } = useI18n();
// update
menuCheckStrictly.value = false;
const { record, update } = data;
@ -83,6 +86,10 @@
//
const excludeMenus = transformMenu(menus);
// support i18n
eachTree(excludeMenus, (item) => {
item.label = t(item.label);
});
//
roleMenuTree.value = excludeMenus;
@ -107,6 +114,10 @@
const menus = await menuTreeSelect();
//
const excludeMenus = transformMenu(menus);
// support i18n
eachTree(excludeMenus, (item) => {
item.label = t(item.label);
});
roleMenuTree.value = excludeMenus;
}

1
src/views/system/role/role.data.ts

@ -141,6 +141,7 @@ export const authScopeOptions = [
{ label: '本部门数据权限', value: '3', color: 'orange' },
{ label: '本部门及以下数据权限', value: '4', color: 'cyan' },
{ label: '仅本人数据权限', value: '5', color: 'error' },
{ label: '部门及以下或本人数据权限', value: '6', color: 'default' },
];
export const authSchemas: FormSchema[] = [

18
src/views/system/tenant/index.vue

@ -2,6 +2,9 @@
<PageWrapper dense>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button class="<sm:hidden" v-auth="'system:tenant:edit'" @click="handleSyncTenantDict">
同步租户字典
</a-button>
<a-button
class="<sm:hidden"
v-auth="'system:tenant:export'"
@ -84,6 +87,7 @@
tenantSyncPackage,
tenantStatusChange,
tenantExport,
dictSyncTenant,
} from '@/api/system/tenant';
import { BasicTable, useTable, TableAction, TableSwitch } from '@/components/Table';
import { columns, formSchemas } from './tenant.data';
@ -141,7 +145,7 @@
});
const [registerDrawer, { openDrawer }] = useDrawer();
const { createMessage } = useMessage();
const { createMessage, createConfirm } = useMessage();
async function handleAdd() {
//
@ -175,5 +179,17 @@
// store
await initTenant();
}
function handleSyncTenantDict() {
createConfirm({
title: '提示',
iconType: 'warning',
content: '确认同步租户字典?',
onOk: async () => {
await dictSyncTenant();
await reload();
},
});
}
</script>
<style scoped></style>

6
src/views/system/tenantPackage/TenantPackageDrawer.vue

@ -52,6 +52,7 @@
import { useMaxWidthOrDefault } from '@/hooks/web/useSize';
import { DataNode } from 'ant-design-vue/lib/tree';
import TreeItem from './TreeItem';
import { useI18n } from '@/hooks/web/useI18n';
defineOptions({ name: 'TenantPackageDrawer' });
@ -126,6 +127,11 @@
});
// ()
const afterTransform = transformMenu(excludeIconMenu);
const { t } = useI18n();
// support i18n
afterTransform.forEach((item) => {
item.menuName = t(item.menuName);
});
const tree = listToTree(afterTransform, { id: 'menuId' });
menuTree.value = tree;
}

1
src/views/system/user/DeptTree.vue

@ -1,6 +1,7 @@
<template>
<Skeleton active :paragraph="{ rows: 8 }" :loading="showTreeSkeleton">
<BasicTree
:height="350"
v-if="deptTreeArray.length"
:fieldNames="{ title: 'label', key: 'id' }"
:tree-data="deptTreeArray"

20
src/views/system/user/UserDrawer.vue

@ -6,16 +6,17 @@
:show-footer="true"
@register="registerInnerDrawer"
@ok="handleSubmit"
@close="resetForm"
@close="handleCancel"
>
<BasicForm @register="registerForm">
<template #postIds="{ model, field }">
<!-- optionLabelProp为回填到输入框中的属性 -->
<!-- optionFilterProp为搜索的属性 -->
<Select
:get-popup-container="getPopupContainer"
v-model:value="model[field]"
optionFilterProp="title"
placeholder="请选择岗位"
:placeholder="postPlaceholder"
mode="multiple"
optionLabelProp="title"
>
@ -34,6 +35,7 @@
</template>
<template #roleIds="{ model, field }">
<Select
:get-popup-container="getPopupContainer"
v-model:value="model[field]"
optionFilterProp="title"
placeholder="请选择角色"
@ -71,6 +73,7 @@
import { Select, Tag } from 'ant-design-vue';
import { Role, Post } from '@/api/system/user/model';
import { authScopeOptions } from '@/views/system/role/role.data';
import { getPopupContainer } from '@/utils';
const SelectOption = Select.Option;
@ -86,6 +89,7 @@
/** 岗位select 自定义下拉框 */
const postList = ref<Post[]>([]);
const postPlaceholder = ref('选择部门后显示岗位');
/** 角色select 自定义下拉框 */
const roleList = ref<Role[]>([]);
@ -114,6 +118,7 @@
if (user) {
user.postIds = postIds;
user.roleIds = roleIds;
postList.value = posts;
}
//
roleList.value = roles;
@ -149,6 +154,11 @@
async onSelect(deptId: string | number) {
/** 根据部门ID加载岗位 */
const postListResp = await postOptionSelect(deptId);
if (postListResp.length > 0) {
postPlaceholder.value = '请选择岗位';
} else {
postPlaceholder.value = '该部门下暂无岗位';
}
postList.value = postListResp;
/** 变化后需要重新选择岗位 */
formModel.postIds = [];
@ -192,6 +202,12 @@
drawerLoading(false);
}
}
async function handleCancel() {
await resetForm();
postList.value = [];
postPlaceholder.value = '选择部门后显示岗位';
}
</script>
<style lang="less" scoped>

4
src/views/system/user/user.data.ts

@ -4,6 +4,7 @@ import { getDictOptions } from '@/utils/dict';
import { DictEnum } from '@/enums/dictEnum';
import { useRender } from '@/hooks/component/useRender';
import { IconEnum } from '@/enums/appEnum';
import { getPopupContainer } from '@/utils';
export const columns: BasicColumn[] = [
{
@ -106,6 +107,9 @@ export const drawerSchemas: FormSchema[] = [
field: 'deptId',
required: true,
component: 'TreeSelect',
componentProps: {
getPopupContainer,
},
helpMessage: ['注意绑定的角色要带相应的部门权限, 否则无法正常登录'],
},
{

22
src/views/tool/gen/ImportTableModal.vue

@ -26,18 +26,16 @@
const [registerInnerModal, { modalLoading, closeModal }] = useModalInner(openModalCallback);
async function openModalCallback() {
async () => {
//
await reload();
const ret = await getDataSourceNames();
const dataSourceOptions = ret.map((item) => ({ label: item, value: item }));
await getForm().updateSchema({
field: 'dataName',
componentProps: {
options: dataSourceOptions,
},
});
};
//
await reload();
const ret = await getDataSourceNames();
const dataSourceOptions = ret.map((item) => ({ label: item, value: item }));
await getForm().updateSchema({
field: 'dataName',
componentProps: {
options: dataSourceOptions,
},
});
}
const columns: BasicColumn[] = [

1
src/views/workflow/components/UserSelectModal/index.vue

@ -13,6 +13,7 @@
<Col v-bind="{ xs: 24, sm: 24, md: 24, lg: 4 }" class="h-[calc(100vh-80px)]">
<Skeleton :active="true" :paragraph="{ rows: 8 }" :loading="showTreeSkeleton">
<BasicTree
:height="350"
v-if="data.tree.length"
:fieldNames="{ title: 'label', key: 'id' }"
:tree-data="data.tree as any"

8
src/views/演示使用自行删除/wechat/index.vue

@ -2,7 +2,7 @@
<PageWrapper dense>
<div class="flex flex-row">
<div class="<sm:hidden">
<h3 class="text-center">当前微信群</h3>
<h3 class="text-center">人数已满, 需要手动拉人👇</h3>
<Image
:src="'data:image/png;base64,' + currentImage"
:width="360"
@ -27,12 +27,6 @@
message="该功能只是为了方便上传gitee微信群图片, 勿乱操作(会禁止登录)"
type="warning"
/>
<Alert
class="h-30px <sm:hidden"
show-icon
message="群聊达到上限 需要手动拉人进群 感谢群友@莫愁"
type="success"
/>
</Space>
</template>
<template #bodyCell="{ column, record }">

Loading…
Cancel
Save