!195 发布 5.3.1-BETA_2.3.0-BETA 公测版本

Merge pull request !195 from 疯狂的狮子Li/dev
This commit is contained in:
疯狂的狮子Li 2025-03-13 05:30:32 +00:00 committed by Gitee
commit b23b123613
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
98 changed files with 576 additions and 484 deletions

View File

@ -1,46 +1,25 @@
{ {
"globals": { "globals": {
"ComponentInternalInstance": true, "Component": true,
"TransferKey": true, "ComponentPublicInstance": true,
"ElFormRules": true, "ComputedRef": true,
"CheckboxValueType": true, "DirectiveBinding": true,
"PropType": true,
"DateModelType": true,
"UploadFile": true,
"ElFormInstance": true,
"ElTableInstance": true,
"ElTreeInstance": true,
"ElTreeSelectInstance": true,
"ElSelectInstance": true,
"ElUploadInstance": true,
"ElCardInstance": true,
"ElDialogInstance": true,
"ElInputInstance": true,
"ElInputNumberInstance": true,
"ElRadioInstance": true,
"ElRadioGroupInstance": true,
"ElRadioButtonInstance": true,
"ElCheckboxInstance": true,
"ElCheckboxGroupInstance": true,
"ElSwitchInstance": true,
"ElDatePickerInstance": true,
"ElTimePickerInstance": true,
"ElTimeSelectInstance": true,
"ElScrollbarInstance": true,
"ElCascaderInstance": true,
"ElColorPickerInstance": true,
"ElRateInstance": true,
"ElSliderInstance": true,
"useRouter": true,
"useRoute": true,
"EffectScope": true, "EffectScope": true,
"ElTable": true, "ElLoading": true,
"ElSelect": true,
"ElUpload": true,
"ElForm": true,
"ElTree": true,
"ElMessage": true, "ElMessage": true,
"ElMessageBox": true, "ElMessageBox": true,
"ElNotification": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"VNode": true,
"WritableComputedRef": true,
"acceptHMRUpdate": true,
"asyncComputed": true, "asyncComputed": true,
"autoResetRef": true, "autoResetRef": true,
"computed": true, "computed": true,
@ -54,36 +33,50 @@
"createEventHook": true, "createEventHook": true,
"createGlobalState": true, "createGlobalState": true,
"createInjectionState": true, "createInjectionState": true,
"createPinia": true,
"createReactiveFn": true, "createReactiveFn": true,
"createReusableTemplate": true,
"createSharedComposable": true, "createSharedComposable": true,
"createTemplatePromise": true,
"createUnrefFn": true, "createUnrefFn": true,
"customRef": true, "customRef": true,
"debouncedRef": true, "debouncedRef": true,
"debouncedWatch": true, "debouncedWatch": true,
"defineAsyncComponent": true, "defineAsyncComponent": true,
"defineComponent": true, "defineComponent": true,
"defineStore": true,
"eagerComputed": true, "eagerComputed": true,
"effectScope": true, "effectScope": true,
"extendRef": true, "extendRef": true,
"getActivePinia": true,
"getCurrentInstance": true, "getCurrentInstance": true,
"getCurrentScope": true, "getCurrentScope": true,
"h": true, "h": true,
"ignorableWatch": true, "ignorableWatch": true,
"inject": true, "inject": true,
"injectLocal": true,
"isDefined": true, "isDefined": true,
"isProxy": true, "isProxy": true,
"isReactive": true, "isReactive": true,
"isReadonly": true, "isReadonly": true,
"isRef": true, "isRef": true,
"makeDestructurable": true, "makeDestructurable": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"markRaw": true, "markRaw": true,
"nextTick": true, "nextTick": true,
"onActivated": true, "onActivated": true,
"onBeforeMount": true, "onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true, "onBeforeUnmount": true,
"onBeforeUpdate": true, "onBeforeUpdate": true,
"onClickOutside": true, "onClickOutside": true,
"onDeactivated": true, "onDeactivated": true,
"onElementRemoval": true,
"onErrorCaptured": true, "onErrorCaptured": true,
"onKeyStroke": true, "onKeyStroke": true,
"onLongPress": true, "onLongPress": true,
@ -95,8 +88,10 @@
"onStartTyping": true, "onStartTyping": true,
"onUnmounted": true, "onUnmounted": true,
"onUpdated": true, "onUpdated": true,
"onWatcherCleanup": true,
"pausableWatch": true, "pausableWatch": true,
"provide": true, "provide": true,
"provideLocal": true,
"reactify": true, "reactify": true,
"reactifyObject": true, "reactifyObject": true,
"reactive": true, "reactive": true,
@ -111,12 +106,14 @@
"refThrottled": true, "refThrottled": true,
"refWithControl": true, "refWithControl": true,
"resolveComponent": true, "resolveComponent": true,
"resolveDirective": true,
"resolveRef": true, "resolveRef": true,
"resolveUnref": true, "resolveUnref": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"shallowReactive": true, "shallowReactive": true,
"shallowReadonly": true, "shallowReadonly": true,
"shallowRef": true, "shallowRef": true,
"storeToRefs": true,
"syncRef": true, "syncRef": true,
"syncRefs": true, "syncRefs": true,
"templateRef": true, "templateRef": true,
@ -126,6 +123,7 @@
"toReactive": true, "toReactive": true,
"toRef": true, "toRef": true,
"toRefs": true, "toRefs": true,
"toValue": true,
"triggerRef": true, "triggerRef": true,
"tryOnBeforeMount": true, "tryOnBeforeMount": true,
"tryOnBeforeUnmount": true, "tryOnBeforeUnmount": true,
@ -136,11 +134,14 @@
"unrefElement": true, "unrefElement": true,
"until": true, "until": true,
"useActiveElement": true, "useActiveElement": true,
"useAnimate": true,
"useArrayDifference": true,
"useArrayEvery": true, "useArrayEvery": true,
"useArrayFilter": true, "useArrayFilter": true,
"useArrayFind": true, "useArrayFind": true,
"useArrayFindIndex": true, "useArrayFindIndex": true,
"useArrayFindLast": true, "useArrayFindLast": true,
"useArrayIncludes": true,
"useArrayJoin": true, "useArrayJoin": true,
"useArrayMap": true, "useArrayMap": true,
"useArrayReduce": true, "useArrayReduce": true,
@ -157,9 +158,11 @@
"useBrowserLocation": true, "useBrowserLocation": true,
"useCached": true, "useCached": true,
"useClipboard": true, "useClipboard": true,
"useClipboardItems": true,
"useCloned": true, "useCloned": true,
"useColorMode": true, "useColorMode": true,
"useConfirmDialog": true, "useConfirmDialog": true,
"useCountdown": true,
"useCounter": true, "useCounter": true,
"useCssModule": true, "useCssModule": true,
"useCssVar": true, "useCssVar": true,
@ -198,6 +201,7 @@
"useFullscreen": true, "useFullscreen": true,
"useGamepad": true, "useGamepad": true,
"useGeolocation": true, "useGeolocation": true,
"useId": true,
"useIdle": true, "useIdle": true,
"useImage": true, "useImage": true,
"useInfiniteScroll": true, "useInfiniteScroll": true,
@ -206,6 +210,7 @@
"useIntervalFn": true, "useIntervalFn": true,
"useKeyModifier": true, "useKeyModifier": true,
"useLastChanged": true, "useLastChanged": true,
"useLink": true,
"useLocalStorage": true, "useLocalStorage": true,
"useMagicKeys": true, "useMagicKeys": true,
"useManualRefHistory": true, "useManualRefHistory": true,
@ -213,6 +218,7 @@
"useMediaQuery": true, "useMediaQuery": true,
"useMemoize": true, "useMemoize": true,
"useMemory": true, "useMemory": true,
"useModel": true,
"useMounted": true, "useMounted": true,
"useMouse": true, "useMouse": true,
"useMouseInElement": true, "useMouseInElement": true,
@ -226,6 +232,8 @@
"useOnline": true, "useOnline": true,
"usePageLeave": true, "usePageLeave": true,
"useParallax": true, "useParallax": true,
"useParentElement": true,
"usePerformanceObserver": true,
"usePermission": true, "usePermission": true,
"usePointer": true, "usePointer": true,
"usePointerLock": true, "usePointerLock": true,
@ -235,10 +243,14 @@
"usePreferredDark": true, "usePreferredDark": true,
"usePreferredLanguages": true, "usePreferredLanguages": true,
"usePreferredReducedMotion": true, "usePreferredReducedMotion": true,
"usePreferredReducedTransparency": true,
"usePrevious": true, "usePrevious": true,
"useRafFn": true, "useRafFn": true,
"useRefHistory": true, "useRefHistory": true,
"useResizeObserver": true, "useResizeObserver": true,
"useRoute": true,
"useRouter": true,
"useSSRWidth": true,
"useScreenOrientation": true, "useScreenOrientation": true,
"useScreenSafeArea": true, "useScreenSafeArea": true,
"useScriptTag": true, "useScriptTag": true,
@ -256,6 +268,7 @@
"useStyleTag": true, "useStyleTag": true,
"useSupported": true, "useSupported": true,
"useSwipe": true, "useSwipe": true,
"useTemplateRef": true,
"useTemplateRefsList": true, "useTemplateRefsList": true,
"useTextDirection": true, "useTextDirection": true,
"useTextSelection": true, "useTextSelection": true,
@ -291,8 +304,10 @@
"watchArray": true, "watchArray": true,
"watchAtMost": true, "watchAtMost": true,
"watchDebounced": true, "watchDebounced": true,
"watchDeep": true,
"watchEffect": true, "watchEffect": true,
"watchIgnorable": true, "watchIgnorable": true,
"watchImmediate": true,
"watchOnce": true, "watchOnce": true,
"watchPausable": true, "watchPausable": true,
"watchPostEffect": true, "watchPostEffect": true,
@ -300,13 +315,6 @@
"watchThrottled": true, "watchThrottled": true,
"watchTriggerable": true, "watchTriggerable": true,
"watchWithFilter": true, "watchWithFilter": true,
"whenever": true, "whenever": true
"ImportOption": true,
"TreeType": true,
"FieldOption": true,
"PageData": true,
"storeToRefs": true,
"DictDataOption": true,
"UploadOption": true
} }
} }

View File

@ -1,86 +0,0 @@
import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginVue from 'eslint-plugin-vue';
import { readFile } from 'node:fs/promises';
import prettier from 'eslint-plugin-prettier';
/**
* https://blog.csdn.net/sayUonly/article/details/123482912
* 自动导入的配置
*/
const autoImportFile = new URL('./.eslintrc-auto-import.json', import.meta.url);
const autoImportGlobals = JSON.parse(await readFile(autoImportFile, 'utf8'));
/** @type {import('eslint').Linter.Config[]} */
export default [
{
/**
* 不需要.eslintignore文件 而是在这里配置
*/
ignores: [
'*.sh',
'node_modules',
'*.md',
'*.woff',
'*.ttf',
'.vscode',
'.idea',
'dist',
'/public',
'/docs',
'.husky',
'.local',
'/bin',
'.eslintrc.cjs',
'prettier.config.js',
'src/assets',
'tailwind.config.js'
]
},
{ files: ['**/*.{js,mjs,cjs,ts,vue}'] },
{
languageOptions: {
globals: globals.browser
}
},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs['flat/essential'],
{
files: ['**/*.vue'],
languageOptions: {
parserOptions: {
parser: tseslint.parser
}
}
},
{
languageOptions: {
globals: {
// 自动导入的配置 undef
...autoImportGlobals.globals,
DialogOption: 'readonly',
LayoutSetting: 'readonly'
}
},
plugins: { prettier },
rules: {
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-this-alias': 'off',
// vue
'vue/multi-word-component-names': 'off',
'vue/valid-define-props': 'off',
'vue/no-v-model-argument': 'off',
'prefer-rest-params': 'off',
// prettier
'prettier/prettier': 'error',
// 允许使用空Object类型 {}
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-unused-expressions': 'off'
}
}
];

44
eslint.config.ts Normal file
View File

@ -0,0 +1,44 @@
import pluginVue from 'eslint-plugin-vue';
import globals from 'globals';
import prettier from 'eslint-plugin-prettier';
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript';
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting';
export default defineConfigWithVueTs(
{
name: 'app/files-to-lint',
files: ['**/*.{js,cjs,ts,mts,tsx,vue}']
},
{
name: 'app/files-to-ignore',
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**']
},
{
languageOptions: {
globals: globals.browser
}
},
pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
skipFormatting,
{
plugins: { prettier },
rules: {
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-this-alias': 'off',
// vue
'vue/multi-word-component-names': 'off',
'vue/valid-define-props': 'off',
'vue/no-v-model-argument': 'off',
'prefer-rest-params': 'off',
// prettier
'prettier/prettier': 'error',
// 允许使用空Object类型 {}
'@typescript-eslint/no-empty-object-type': 'off',
'@typescript-eslint/no-unused-expressions': 'off'
}
}
);

View File

@ -1,7 +1,7 @@
{ {
"$schema": "https://json.schemastore.org/tsconfig", "$schema": "https://json.schemastore.org/package",
"name": "ruoyi-vue-plus", "name": "ruoyi-vue-plus",
"version": "5.3.0", "version": "5.3.1-BETA_2.3.0-BETA",
"description": "RuoYi-Vue-Plus多租户管理系统", "description": "RuoYi-Vue-Plus多租户管理系统",
"author": "LionLi", "author": "LionLi",
"license": "MIT", "license": "MIT",
@ -23,13 +23,11 @@
"@element-plus/icons-vue": "2.3.1", "@element-plus/icons-vue": "2.3.1",
"@highlightjs/vue-plugin": "2.1.0", "@highlightjs/vue-plugin": "2.1.0",
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "11.3.0", "@vueuse/core": "12.7.0",
"animate.css": "4.1.1", "animate.css": "4.1.1",
"await-to-js": "3.0.0", "await-to-js": "3.0.0",
"axios": "1.7.8", "axios": "1.7.8",
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"diagram-js": "12.3.0",
"didi": "9.0.2",
"echarts": "5.5.0", "echarts": "5.5.0",
"element-plus": "2.8.8", "element-plus": "2.8.8",
"file-saver": "2.0.5", "file-saver": "2.0.5",
@ -50,38 +48,47 @@
"vxe-table": "4.5.22" "vxe-table": "4.5.22"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.15.0",
"@iconify/json": "2.2.276", "@iconify/json": "2.2.276",
"@types/crypto-js": "4.2.2", "@types/crypto-js": "4.2.2",
"@types/file-saver": "2.0.7", "@types/file-saver": "2.0.7",
"@types/js-cookie": "3.0.6", "@types/js-cookie": "3.0.6",
"@types/node": "18.18.2", "@types/node": "^22.13.4",
"@types/nprogress": "0.2.3", "@types/nprogress": "0.2.3",
"@unocss/preset-attributify": "0.64.1", "@unocss/preset-attributify": "66.0.0",
"@unocss/preset-icons": "0.64.1", "@unocss/preset-icons": "66.0.0",
"@unocss/preset-uno": "0.64.1", "@unocss/preset-uno": "66.0.0",
"@vitejs/plugin-vue": "5.0.4", "@vitejs/plugin-vue": "5.2.1",
"@vue/compiler-sfc": "3.4.23", "@vue/compiler-sfc": "3.4.23",
"autoprefixer": "10.4.18", "@vue/eslint-config-prettier": "10.2.0",
"eslint": "9.15.0", "@vue/eslint-config-typescript": "14.4.0",
"eslint-plugin-prettier": "^5.2.1", "autoprefixer": "10.4.20",
"eslint-plugin-vue": "9.31.0", "eslint": "9.21.0",
"fast-glob": "3.3.2", "eslint-plugin-prettier": "5.2.3",
"globals": "15.12.0", "eslint-plugin-vue": "9.32.0",
"postcss": "8.4.36", "globals": "16.0.0",
"prettier": "3.2.5", "prettier": "3.5.2",
"sass": "1.72.0", "sass": "1.84.0",
"typescript": "5.7.2", "typescript": "~5.7.3",
"typescript-eslint": "8.16.0", "unocss": "66.0.0",
"unocss": "0.64.1",
"unplugin-auto-import": "0.17.5", "unplugin-auto-import": "0.17.5",
"unplugin-icons": "0.18.5", "unplugin-icons": "0.18.5",
"unplugin-vue-components": "0.26.0", "unplugin-vue-components": "28.0.0",
"unplugin-vue-setup-extend-plus": "1.0.1", "unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "5.4.11", "vite": "5.4.11",
"vite-plugin-compression": "0.5.1", "vite-plugin-compression": "0.5.1",
"vite-plugin-svg-icons": "2.0.1", "vite-plugin-svg-icons-ng": "^1.2.2",
"vitest": "1.5.0", "vite-plugin-vue-devtools": "7.7.1",
"vue-tsc": "2.0.13" "vitest": "3.0.5",
} "vue-tsc": "^2.2.2"
},
"engines": {
"node": ">=18.18.0",
"npm": ">=8.9.0"
},
"browserslist": [
"Chrome >= 87",
"Edge >= 88",
"Safari >= 14",
"Firefox >= 78"
]
} }

View File

@ -5,9 +5,9 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import { handleThemeStyle } from '@/utils/theme'; import { handleThemeStyle } from '@/utils/theme';
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
const appStore = useAppStore(); const appStore = useAppStore();

View File

@ -19,6 +19,7 @@ export interface UserQuery extends PageQuery {
status?: string; status?: string;
deptId?: string | number; deptId?: string | number;
roleId?: string | number; roleId?: string | number;
userIds?: string;
} }
/** /**

View File

@ -6,7 +6,6 @@ export interface CategoryTreeVO {
children: CategoryTreeVO[]; children: CategoryTreeVO[];
} }
export interface CategoryVO { export interface CategoryVO {
/** /**
* ID * ID
*/ */
@ -39,7 +38,6 @@ export interface CategoryVO {
} }
export interface CategoryForm extends BaseEntity { export interface CategoryForm extends BaseEntity {
/** /**
* ID * ID
*/ */
@ -59,14 +57,11 @@ export interface CategoryForm extends BaseEntity {
* *
*/ */
orderNum?: number; orderNum?: number;
} }
export interface CategoryQuery { export interface CategoryQuery {
/** /**
* *
*/ */
categoryName?: string; categoryName?: string;
} }

View File

@ -178,3 +178,16 @@ export const currentTaskAllUser = (taskId: string | number) => {
method: 'get' method: 'get'
}); });
}; };
/**
*
* @param data参数
* @returns
*/
export const getNextNodeList = (data: any): any => {
return request({
url: '/workflow/task/getNextNodeList',
method: 'post',
data: data
});
};

View File

@ -29,8 +29,14 @@ export interface FlowTaskVO {
nodeType: number; nodeType: number;
nodeRatio: string | number; nodeRatio: string | number;
version?: string; version?: string;
applyNode?: boolean;
buttonList?: buttonList[];
} }
export interface buttonList {
code: string;
show: boolean;
}
export interface VariableVo { export interface VariableVo {
key: string; key: string;
value: string; value: string;

View File

@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></path></svg> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,4 +1,4 @@
@import './variables.module.scss'; @use './variables.module.scss' as *;
@mixin colorBtn($color) { @mixin colorBtn($color) {
background: $color; background: $color;

View File

@ -1,12 +1,12 @@
@import './variables.module.scss'; @use './variables.module.scss' as *;
@import './mixin.scss'; @use './mixin.scss';
@import './transition.scss'; @use './transition.scss';
@import './element-ui.scss'; @use './element-ui.scss';
@import './sidebar.scss'; @use './sidebar.scss';
@import './btn.scss'; @use './btn.scss';
@import './ruoyi.scss'; @use './ruoyi.scss';
@import 'animate.css'; @use 'animate.css';
@import 'element-plus/dist/index.css'; @use 'element-plus/dist/index.css';
body { body {
height: 100%; height: 100%;
@ -162,10 +162,6 @@ aside {
position: relative; position: relative;
} }
.pagination-container {
margin-top: 30px;
}
.text-center { .text-center {
text-align: center; text-align: center;
} }

View File

@ -1,3 +1,5 @@
@use './variables.module.scss' as *;
/** /**
* 通用css样式布局处理 * 通用css样式布局处理
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
@ -114,10 +116,9 @@ h6 {
/** 表格布局 **/ /** 表格布局 **/
.pagination-container { .pagination-container {
// position: relative; display: flex;
height: 25px; justify-content: flex-end;
margin-bottom: 10px; margin-top: 20px;
margin-top: 15px;
padding: 10px 20px !important; padding: 10px 20px !important;
} }
@ -130,11 +131,6 @@ h6 {
width: 100%; width: 100%;
} }
.pagination-container .el-pagination {
//right: 0;
//position: absolute;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.pagination-container .el-pagination > .el-pagination__jump { .pagination-container .el-pagination > .el-pagination__jump {
display: none !important; display: none !important;
@ -201,8 +197,6 @@ h6 {
} }
.card-box { .card-box {
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px; margin-bottom: 10px;
} }

View File

@ -1,3 +1,5 @@
@use './variables.module.scss' as *;
#app { #app {
.main-container { .main-container {
height: 100%; height: 100%;

View File

@ -11,7 +11,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { RouteLocationMatched } from 'vue-router'; import { RouteLocationMatched } from 'vue-router';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();

View File

@ -87,7 +87,7 @@ const handleArray = (array: Array<string | number>) => {
}; };
</script> </script>
<style scoped> <style lang="scss" scoped>
.el-tag + .el-tag { .el-tag + .el-tag {
margin-left: 10px; margin-left: 10px;
} }

View File

@ -7,18 +7,20 @@
:before-upload="handleBeforeUpload" :before-upload="handleBeforeUpload"
:file-list="fileList" :file-list="fileList"
:limit="limit" :limit="limit"
:accept="fileAccept"
:on-error="handleUploadError" :on-error="handleUploadError"
:on-exceed="handleExceed" :on-exceed="handleExceed"
:on-success="handleUploadSuccess" :on-success="handleUploadSuccess"
:show-file-list="false" :show-file-list="false"
:headers="headers" :headers="headers"
class="upload-file-uploader" class="upload-file-uploader"
v-if="!disabled"
> >
<!-- 上传按钮 --> <!-- 上传按钮 -->
<el-button type="primary">选取文件</el-button> <el-button type="primary">选取文件</el-button>
</el-upload> </el-upload>
<!-- 上传提示 --> <!-- 上传提示 -->
<div v-if="showTip" class="el-upload__tip"> <div v-if="showTip && !disabled" class="el-upload__tip">
请上传 请上传
<template v-if="fileSize"> <template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
@ -35,7 +37,7 @@
<span class="el-icon-document"> {{ getFileName(file.name) }} </span> <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link> </el-link>
<div class="ele-upload-list__item-content-action"> <div class="ele-upload-list__item-content-action">
<el-button type="danger" link @click="handleDelete(index)">删除</el-button> <el-button type="danger" v-if="!disabled" link @click="handleDelete(index)">删除</el-button>
</div> </div>
</li> </li>
</transition-group> </transition-group>
@ -57,9 +59,11 @@ const props = defineProps({
// (MB) // (MB)
fileSize: propTypes.number.def(5), fileSize: propTypes.number.def(5),
// , ['png', 'jpg', 'jpeg'] // , ['png', 'jpg', 'jpeg']
fileType: propTypes.array.def(['doc', 'xls', 'ppt', 'txt', 'pdf']), fileType: propTypes.array.def(['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'pdf']),
// //
isShowTip: propTypes.bool.def(true) isShowTip: propTypes.bool.def(true),
//
disabled: propTypes.bool.def(false)
}); });
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -76,6 +80,9 @@ const showTip = computed(() => props.isShowTip && (props.fileType || props.fileS
const fileUploadRef = ref<ElUploadInstance>(); const fileUploadRef = ref<ElUploadInstance>();
// fileType fileAccept
const fileAccept = computed(() => props.fileType.map((type) => `.${type}`).join(','));
watch( watch(
() => props.modelValue, () => props.modelValue,
async (val) => { async (val) => {
@ -209,7 +216,7 @@ const listToString = (list: any[], separator?: string) => {
}; };
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.upload-file-uploader { .upload-file-uploader {
margin-bottom: 5px; margin-bottom: 5px;
} }

View File

@ -21,7 +21,7 @@
import Fuse from 'fuse.js'; import Fuse from 'fuse.js';
import { getNormalPath } from '@/utils/ruoyi'; import { getNormalPath } from '@/utils/ruoyi';
import { isHttp } from '@/utils/validate'; import { isHttp } from '@/utils/validate';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
type Router = Array<{ type Router = Array<{
@ -36,7 +36,7 @@ const show = ref(false);
const fuse = ref(); const fuse = ref();
const headerSearchSelectRef = ref<ElSelectInstance>(); const headerSearchSelectRef = ref<ElSelectInstance>();
const router = useRouter(); const router = useRouter();
const routes = computed(() => usePermissionStore().getRoutes()); const routes = computed(() => usePermissionStore().getDefaultRoutes());
const click = () => { const click = () => {
show.value = !show.value; show.value = !show.value;

View File

@ -65,7 +65,7 @@ const selectedIcon = (iconName: string) => {
}; };
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.el-scrollbar { .el-scrollbar {
max-height: calc(50vh - 100px) !important; max-height: calc(50vh - 100px) !important;
overflow-y: auto; overflow-y: auto;

View File

@ -1,13 +1,14 @@
<template> <template>
<div class="component-upload-image"> <div class="component-upload-image">
<el-upload <el-upload
ref="imageUpload" ref="imageUploadRef"
multiple multiple
:action="uploadImgUrl" :action="uploadImgUrl"
list-type="picture-card" list-type="picture-card"
:on-success="handleUploadSuccess" :on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload" :before-upload="handleBeforeUpload"
:limit="limit" :limit="limit"
:accept="fileAccept"
:on-error="handleUploadError" :on-error="handleUploadError"
:on-exceed="handleExceed" :on-exceed="handleExceed"
:before-remove="handleDelete" :before-remove="handleDelete"
@ -87,6 +88,9 @@ const showTip = computed(() => props.isShowTip && (props.fileType || props.fileS
const imageUploadRef = ref<ElUploadInstance>(); const imageUploadRef = ref<ElUploadInstance>();
// fileType fileAccept
const fileAccept = computed(() => props.fileType.map((type) => `.${type}`).join(','));
watch( watch(
() => props.modelValue, () => props.modelValue,
async (val: string) => { async (val: string) => {
@ -230,7 +234,7 @@ const listToString = (list: any[], separator?: string) => {
}; };
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
// .el-upload--picture-card // .el-upload--picture-card
:deep(.hide .el-upload--picture-card) { :deep(.hide .el-upload--picture-card) {
display: none; display: none;

View File

@ -14,13 +14,7 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup name="Pagination" lang="ts">
export default {
name: 'Pagination'
};
</script>
<script setup lang="ts">
import { scrollTo } from '@/utils/scroll-to'; import { scrollTo } from '@/utils/scroll-to';
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';
@ -28,10 +22,7 @@ const props = defineProps({
total: propTypes.number, total: propTypes.number,
page: propTypes.number.def(1), page: propTypes.number.def(1),
limit: propTypes.number.def(20), limit: propTypes.number.def(20),
pageSizes: { pageSizes: { type: Array<number>, default: () => [10, 20, 30, 50] },
type: Array,
default: () => [10, 20, 30, 50]
},
// 5 // 5
pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7), pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'), layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
@ -77,7 +68,6 @@ function handleCurrentChange(val: number) {
<style lang="scss" scoped> <style lang="scss" scoped>
.pagination-container { .pagination-container {
padding: 32px 16px;
.el-pagination { .el-pagination {
float: v-bind(float); float: v-bind(float);
} }

View File

@ -72,7 +72,7 @@
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { flowImage } from '@/api/workflow/instance'; import { flowImage } from '@/api/workflow/instance';
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';
import { listByIds } from '@/api/system/oss'; import { listByIds } from '@/api/system/oss';

View File

@ -49,7 +49,7 @@
</el-dialog> </el-dialog>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';
import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types'; import { FlowTaskVO, TaskOperationBo } from '@/api/workflow/task/types';
import UserSelect from '@/components/UserSelect'; import UserSelect from '@/components/UserSelect';

View File

@ -11,12 +11,23 @@
<el-form-item v-if="task.flowStatus === 'waiting'" label="附件"> <el-form-item v-if="task.flowStatus === 'waiting'" label="附件">
<fileUpload v-model="form.fileId" :file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']" :file-size="20" /> <fileUpload v-model="form.fileId" :file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']" :file-size="20" />
</el-form-item> </el-form-item>
<el-form-item label="抄送"> <el-form-item label="抄送" v-if="task.flowStatus === 'waiting' && buttonObj.copy">
<el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" /> <el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" />
<el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)"> <el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)">
{{ user.nickName }} {{ user.nickName }}
</el-tag> </el-tag>
</el-form-item> </el-form-item>
<el-form-item v-if="buttonObj.pop && nestNodeList && nestNodeList.length > 0" label="下一步审批人" prop="assigneeMap">
<div v-for="(item, index) in nestNodeList" :key="index" style="margin-bottom: 5px; width: 500px">
<span>{{ item.nodeName }}</span>
<el-input v-if="false" v-model="form.assigneeMap[item.nodeCode]" />
<el-input placeholder="请选择审批人" readonly v-model="nickName[item.nodeCode]">
<template v-slot:append>
<el-button @click="choosePeople(item)" icon="search">选择</el-button>
</template>
</el-input>
</div>
</el-form-item>
<el-form-item v-if="task.flowStatus === 'waiting'" label="审批意见"> <el-form-item v-if="task.flowStatus === 'waiting'" label="审批意见">
<el-input v-model="form.message" type="textarea" resize="none" /> <el-input v-model="form.message" type="textarea" resize="none" />
</el-form-item> </el-form-item>
@ -24,10 +35,14 @@
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> 提交 </el-button> <el-button :disabled="buttonDisabled" type="primary" @click="handleCompleteTask"> 提交 </el-button>
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openDelegateTask"> 委托 </el-button> <el-button v-if="task.flowStatus === 'waiting' && buttonObj.trust" :disabled="buttonDisabled" type="primary" @click="openDelegateTask">
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="primary" @click="openTransferTask"> 转办 </el-button> 委托
</el-button>
<el-button v-if="task.flowStatus === 'waiting' && buttonObj.transfer" :disabled="buttonDisabled" type="primary" @click="openTransferTask">
转办
</el-button>
<el-button <el-button
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0" v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0 && buttonObj.addSign"
:disabled="buttonDisabled" :disabled="buttonDisabled"
type="primary" type="primary"
@click="openMultiInstanceUser" @click="openMultiInstanceUser"
@ -35,15 +50,24 @@
加签 加签
</el-button> </el-button>
<el-button <el-button
v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0" v-if="task.flowStatus === 'waiting' && Number(task.nodeRatio) > 0 && buttonObj.subSign"
:disabled="buttonDisabled" :disabled="buttonDisabled"
type="primary" type="primary"
@click="handleTaskUser" @click="handleTaskUser"
> >
减签 减签
</el-button> </el-button>
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleTerminationTask"> 终止 </el-button> <el-button
<el-button v-if="task.flowStatus === 'waiting'" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen"> 退回 </el-button> v-if="task.flowStatus === 'waiting' && buttonObj.termination"
:disabled="buttonDisabled"
type="danger"
@click="handleTerminationTask"
>
终止
</el-button>
<el-button v-if="task.flowStatus === 'waiting' && buttonObj.back" :disabled="buttonDisabled" type="danger" @click="handleBackProcessOpen">
退回
</el-button>
<el-button :disabled="buttonDisabled" @click="cancel">取消</el-button> <el-button :disabled="buttonDisabled" @click="cancel">取消</el-button>
</span> </span>
</template> </template>
@ -55,6 +79,8 @@
<UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect> <UserSelect ref="delegateTaskRef" :multiple="false" @confirm-call-back="handleDelegateTask"></UserSelect>
<!-- 加签组件 --> <!-- 加签组件 -->
<UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect> <UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
<!-- 弹窗选人 -->
<UserSelect ref="porUserRef" :multiple="true" :userIds="popUserIds" @confirm-call-back="handlePopUser"></UserSelect>
<!-- 驳回开始 --> <!-- 驳回开始 -->
<el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false"> <el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false">
@ -72,7 +98,11 @@
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item v-if="task.flowStatus === 'waiting'" label="附件"> <el-form-item v-if="task.flowStatus === 'waiting'" label="附件">
<fileUpload v-model="backForm.fileId" :file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']" :file-size="20" /> <fileUpload
v-model="backForm.fileId"
:file-type="['png', 'jpg', 'jpeg', 'doc', 'docx', 'xlsx', 'xls', 'ppt', 'txt', 'pdf']"
:file-size="20"
/>
</el-form-item> </el-form-item>
<el-form-item label="审批意见"> <el-form-item label="审批意见">
<el-input v-model="backForm.message" type="textarea" resize="none" /> <el-input v-model="backForm.message" type="textarea" resize="none" />
@ -102,11 +132,20 @@
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { ComponentInternalInstance } from 'vue'; import { ComponentInternalInstance } from 'vue';
import { ElForm } from 'element-plus'; import { ElForm } from 'element-plus';
import { completeTask, backProcess, getTask, taskOperation, terminationTask, getBackTaskNode, currentTaskAllUser } from '@/api/workflow/task'; import {
completeTask,
backProcess,
getTask,
taskOperation,
terminationTask,
getBackTaskNode,
currentTaskAllUser,
getNextNodeList
} from '@/api/workflow/task';
import UserSelect from '@/components/UserSelect'; import UserSelect from '@/components/UserSelect';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -117,6 +156,7 @@ const userSelectCopyRef = ref<InstanceType<typeof UserSelect>>();
const transferTaskRef = ref<InstanceType<typeof UserSelect>>(); const transferTaskRef = ref<InstanceType<typeof UserSelect>>();
const delegateTaskRef = ref<InstanceType<typeof UserSelect>>(); const delegateTaskRef = ref<InstanceType<typeof UserSelect>>();
const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>(); const multiInstanceUserRef = ref<InstanceType<typeof UserSelect>>();
const porUserRef = ref<InstanceType<typeof UserSelect>>();
const props = defineProps({ const props = defineProps({
taskVariables: { taskVariables: {
@ -136,12 +176,28 @@ const selectCopyUserList = ref<UserVO[]>([]);
const selectCopyUserIds = ref<string>(undefined); const selectCopyUserIds = ref<string>(undefined);
// //
const deleteUserList = ref<any>([]); const deleteUserList = ref<any>([]);
//id
const popUserIds = ref<any>([]);
// //
const backVisible = ref(false); const backVisible = ref(false);
const backLoading = ref(true); const backLoading = ref(true);
const backButtonDisabled = ref(true); const backButtonDisabled = ref(true);
// //
const taskNodeList = ref([]); const taskNodeList = ref([]);
const nickName = ref({});
//
const nodeCode = ref<string>('');
const buttonObj = ref<any>({
pop: false,
trust: false,
transfer: false,
addSign: false,
subSign: false,
termination: false,
back: false
});
//
const nestNodeList = ref([]);
// //
const task = ref<FlowTaskVO>({ const task = ref<FlowTaskVO>({
id: undefined, id: undefined,
@ -159,7 +215,9 @@ const task = ref<FlowTaskVO>({
formCustom: undefined, formCustom: undefined,
formPath: undefined, formPath: undefined,
nodeType: undefined, nodeType: undefined,
nodeRatio: undefined nodeRatio: undefined,
applyNode: false,
buttonList: []
}); });
const dialog = reactive<DialogOption>({ const dialog = reactive<DialogOption>({
visible: false, visible: false,
@ -170,6 +228,7 @@ const deleteSignatureVisible = ref(false);
const form = ref<Record<string, any>>({ const form = ref<Record<string, any>>({
taskId: undefined, taskId: undefined,
message: undefined, message: undefined,
assigneeMap: {},
variables: {}, variables: {},
messageType: ['1'], messageType: ['1'],
flowCopyList: [] flowCopyList: []
@ -181,8 +240,9 @@ const backForm = ref<Record<string, any>>({
variables: {}, variables: {},
messageType: ['1'] messageType: ['1']
}); });
// //
const openDialog = (id?: string) => { const openDialog = async (id?: string) => {
selectCopyUserIds.value = undefined; selectCopyUserIds.value = undefined;
selectCopyUserList.value = []; selectCopyUserList.value = [];
form.value.fileId = undefined; form.value.fileId = undefined;
@ -191,13 +251,20 @@ const openDialog = (id?: string) => {
dialog.visible = true; dialog.visible = true;
loading.value = true; loading.value = true;
buttonDisabled.value = true; buttonDisabled.value = true;
nextTick(() => { const response = await getTask(taskId.value);
getTask(taskId.value).then((response) => { task.value = response.data;
task.value = response.data; buttonObj.value = {};
loading.value = false; task.value.buttonList.forEach((e) => {
buttonDisabled.value = false; buttonObj.value[e.code] = e.show;
});
}); });
buttonDisabled.value = false;
const data = {
taskId: taskId.value,
variables: props.taskVariables
};
const nextData = await getNextNodeList(data);
nestNodeList.value = nextData.data;
loading.value = false;
}; };
onMounted(() => {}); onMounted(() => {});
@ -207,10 +274,29 @@ const emits = defineEmits(['submitCallback', 'cancelCallback']);
const handleCompleteTask = async () => { const handleCompleteTask = async () => {
form.value.taskId = taskId.value; form.value.taskId = taskId.value;
form.value.taskVariables = props.taskVariables; form.value.taskVariables = props.taskVariables;
let verify = false;
if (buttonObj.value.pop && nestNodeList.value && nestNodeList.value.length > 0) {
nestNodeList.value.forEach((e) => {
if (
Object.keys(form.value.assigneeMap).length === 0 ||
form.value.assigneeMap[e.nodeCode] === '' ||
form.value.assigneeMap[e.nodeCode] === null ||
form.value.assigneeMap[e.nodeCode] === undefined
) {
verify = true;
}
});
if (verify) {
proxy?.$modal.msgWarning('请选择审批人!');
return false;
}
} else {
form.value.assigneeMap = {};
}
if (selectCopyUserList.value && selectCopyUserList.value.length > 0) { if (selectCopyUserList.value && selectCopyUserList.value.length > 0) {
let flowCopyList = []; const flowCopyList = [];
selectCopyUserList.value.forEach((e) => { selectCopyUserList.value.forEach((e) => {
let copyUser = { const copyUser = {
userId: e.userId, userId: e.userId,
userName: e.nickName userName: e.nickName
}; };
@ -239,7 +325,7 @@ const handleBackProcessOpen = async () => {
backVisible.value = true; backVisible.value = true;
backLoading.value = true; backLoading.value = true;
backButtonDisabled.value = true; backButtonDisabled.value = true;
let data = await getBackTaskNode(task.value.definitionId, task.value.nodeCode); const data = await getBackTaskNode(task.value.definitionId, task.value.nodeCode);
taskNodeList.value = data.data; taskNodeList.value = data.data;
backLoading.value = false; backLoading.value = false;
backButtonDisabled.value = false; backButtonDisabled.value = false;
@ -266,6 +352,8 @@ const handleBackProcess = async () => {
const cancel = async () => { const cancel = async () => {
dialog.visible = false; dialog.visible = false;
buttonDisabled.value = false; buttonDisabled.value = false;
nickName.value = {};
form.value.assigneeMap = {};
emits('cancelCallback'); emits('cancelCallback');
}; };
// //
@ -386,7 +474,7 @@ const handleDelegateTask = async (data) => {
}; };
// //
const handleTerminationTask = async () => { const handleTerminationTask = async () => {
let params = { const params = {
taskId: taskId.value, taskId: taskId.value,
comment: form.value.message comment: form.value.message
}; };
@ -402,7 +490,7 @@ const handleTerminationTask = async () => {
proxy?.$modal.msgSuccess('操作成功'); proxy?.$modal.msgSuccess('操作成功');
}; };
const handleTaskUser = async () => { const handleTaskUser = async () => {
let data = await currentTaskAllUser(taskId.value); const data = await currentTaskAllUser(taskId.value);
deleteUserList.value = data.data; deleteUserList.value = data.data;
if (deleteUserList.value && deleteUserList.value.length > 0) { if (deleteUserList.value && deleteUserList.value.length > 0) {
deleteUserList.value.forEach((e) => { deleteUserList.value.forEach((e) => {
@ -411,6 +499,26 @@ const handleTaskUser = async () => {
} }
deleteSignatureVisible.value = true; deleteSignatureVisible.value = true;
}; };
//
const choosePeople = async (data) => {
if (!data.permissionFlag) {
proxy?.$modal.msgError('没有可选择的人员,请联系管理员!');
}
popUserIds.value = data.permissionFlag;
nodeCode.value = data.nodeCode;
porUserRef.value.open();
};
//
const handlePopUser = async (userList) => {
const userIds = userList.map((item) => {
return item.userId;
});
const nickNames = userList.map((item) => {
return item.nickName;
});
form.value.assigneeMap[nodeCode.value] = userIds.join(',');
nickName.value[nodeCode.value] = nickNames.join(',');
};
/** /**
* 对外暴露子组件方法 * 对外暴露子组件方法

View File

@ -16,7 +16,7 @@
:data="columns" :data="columns"
show-checkbox show-checkbox
node-key="key" node-key="key"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
@check="columnChange" @check="columnChange"
></el-tree> ></el-tree>
<template #reference> <template #reference>

View File

@ -4,7 +4,7 @@
</div> </div>
</template> </template>
<script setup> <script setup lang="ts">
const url = ref('https://plus-doc.dromara.org/'); const url = ref('https://plus-doc.dromara.org/');
function goto() { function goto() {

View File

@ -4,7 +4,7 @@
</div> </div>
</template> </template>
<script setup> <script setup lang="ts">
const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus'); const url = ref('https://gitee.com/dromara/RuoYi-Vue-Plus');
function goto() { function goto() {

View File

@ -16,7 +16,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
const appStore = useAppStore(); const appStore = useAppStore();
const size = computed(() => appStore.size); const size = computed(() => appStore.size);

View File

@ -21,7 +21,7 @@ const svgClass = computed(() => {
}); });
</script> </script>
<style scope lang="scss"> <style lang="scss" scoped>
.sub-el-icon, .sub-el-icon,
.nav-icon { .nav-icon {
display: inline-block; display: inline-block;

View File

@ -22,9 +22,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { constantRoutes } from '@/router'; import { constantRoutes } from '@/router';
import { isHttp } from '@/utils/validate'; import { isHttp } from '@/utils/validate';
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
// //

View File

@ -6,7 +6,7 @@
style="width: 100%" style="width: 100%"
:filterable="true" :filterable="true"
:clearable="true" :clearable="true"
:filter-method="selectFilterData" :filter-method="selectFilterData as any"
:placeholder="placeholder" :placeholder="placeholder"
@clear="clearHandle" @clear="clearHandle"
> >
@ -16,7 +16,7 @@
ref="selectTree" ref="selectTree"
:accordion="accordion" :accordion="accordion"
:data="options" :data="options"
:props="objMap" :props="objMap as any"
:node-key="objMap.value" :node-key="objMap.value"
:expand-on-click-node="false" :expand-on-click-node="false"
:default-expanded-keys="defaultExpandedKey" :default-expanded-keys="defaultExpandedKey"

View File

@ -11,7 +11,7 @@
class="mt-2" class="mt-2"
node-key="id" node-key="id"
:data="deptOptions" :data="deptOptions"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
highlight-current highlight-current
@ -108,11 +108,13 @@ interface PropType {
modelValue?: UserVO[] | UserVO | undefined; modelValue?: UserVO[] | UserVO | undefined;
multiple?: boolean; multiple?: boolean;
data?: string | number | (string | number)[] | undefined; data?: string | number | (string | number)[] | undefined;
userIds?: string | number | (string | number)[] | undefined;
} }
const prop = withDefaults(defineProps<PropType>(), { const prop = withDefaults(defineProps<PropType>(), {
multiple: true, multiple: true,
modelValue: undefined, modelValue: undefined,
data: undefined data: undefined,
userIds: undefined
}); });
const emit = defineEmits(['update:modelValue', 'confirmCallBack']); const emit = defineEmits(['update:modelValue', 'confirmCallBack']);
@ -143,7 +145,8 @@ const queryParams = ref<UserQuery>({
phonenumber: '', phonenumber: '',
status: '', status: '',
deptId: '', deptId: '',
roleId: '' roleId: '',
userIds: ''
}); });
const defaultSelectUserIds = computed(() => computedIds(prop.data)); const defaultSelectUserIds = computed(() => computedIds(prop.data));
@ -166,7 +169,7 @@ const confirm = () => {
const computedIds = (data) => { const computedIds = (data) => {
if (data instanceof Array) { if (data instanceof Array) {
return data.map(item => String(item)); return data.map((item) => String(item));
} else if (typeof data === 'string') { } else if (typeof data === 'string') {
return data.split(','); return data.split(',');
} else if (typeof data === 'number') { } else if (typeof data === 'number') {
@ -192,6 +195,7 @@ const getTreeSelect = async () => {
/** 查询用户列表 */ /** 查询用户列表 */
const getList = async () => { const getList = async () => {
loading.value = true; loading.value = true;
queryParams.value.userIds = prop.userIds;
const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value)); const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
loading.value = false; loading.value = false;
userList.value = res.rows; userList.value = res.rows;
@ -302,5 +306,3 @@ defineExpose({
close: userDialog.closeDialog close: userDialog.closeDialog
}); });
</script> </script>
<style lang="scss" scoped></style>

View File

@ -1,5 +1,5 @@
import { Directive, DirectiveBinding } from 'vue'; import { Directive, DirectiveBinding } from 'vue';
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
/** /**
* *
*/ */

View File

@ -1,12 +1,12 @@
<template> <template>
<section class="app-main"> <section class="app-main">
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<transition v-if="!route.meta.noCache" :enter-active-class="animante" mode="out-in"> <transition v-if="!route.meta.noCache" :enter-active-class="animate" mode="out-in">
<keep-alive v-if="!route.meta.noCache" :include="tagsViewStore.cachedViews"> <keep-alive v-if="!route.meta.noCache" :include="tagsViewStore.cachedViews">
<component :is="Component" v-if="!route.meta.link" :key="route.path" /> <component :is="Component" v-if="!route.meta.link" :key="route.path" />
</keep-alive> </keep-alive>
</transition> </transition>
<transition v-if="route.meta.noCache" :enter-active-class="animante" mode="out-in"> <transition v-if="route.meta.noCache" :enter-active-class="animate" mode="out-in">
<component :is="Component" v-if="!route.meta.link && route.meta.noCache" :key="route.path" /> <component :is="Component" v-if="!route.meta.link && route.meta.noCache" :key="route.path" />
</transition> </transition>
</router-view> </router-view>
@ -15,8 +15,8 @@
</template> </template>
<script setup name="AppMain" lang="ts"> <script setup name="AppMain" lang="ts">
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import useTagsViewStore from '@/store/modules/tagsView'; import { useTagsViewStore } from '@/store/modules/tagsView';
import IframeToggle from './IframeToggle/index.vue'; import IframeToggle from './IframeToggle/index.vue';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -24,16 +24,16 @@ const route = useRoute();
const tagsViewStore = useTagsViewStore(); const tagsViewStore = useTagsViewStore();
// //
const animante = ref<string>(''); const animate = ref<string>('');
const animationEnable = ref(useSettingsStore().animationEnable); const animationEnable = ref(useSettingsStore().animationEnable);
watch( watch(
() => useSettingsStore().animationEnable, () => useSettingsStore().animationEnable,
(val: boolean) => { (val: boolean) => {
animationEnable.value = val; animationEnable.value = val;
if (val) { if (val) {
animante.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string; animate.value = proxy?.animate.animateList[Math.round(Math.random() * proxy?.animate.animateList.length)] as string;
} else { } else {
animante.value = proxy?.animate.defaultAnimate as string; animate.value = proxy?.animate.defaultAnimate as string;
} }
}, },
{ immediate: true } { immediate: true }

View File

@ -11,7 +11,7 @@
<script setup lang="ts"> <script setup lang="ts">
import InnerLink from '../InnerLink/index.vue'; import InnerLink from '../InnerLink/index.vue';
import useTagsViewStore from '@/store/modules/tagsView'; import { useTagsViewStore } from '@/store/modules/tagsView';
const route = useRoute(); const route = useRoute();
const tagsViewStore = useTagsViewStore(); const tagsViewStore = useTagsViewStore();

View File

@ -90,15 +90,16 @@
<script setup lang="ts"> <script setup lang="ts">
import SearchMenu from './TopBar/search.vue'; import SearchMenu from './TopBar/search.vue';
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import useNoticeStore from '@/store/modules/notice'; import { useNoticeStore } from '@/store/modules/notice';
import { getTenantList } from '@/api/login'; import { getTenantList } from '@/api/login';
import { dynamicClear, dynamicTenant } from '@/api/system/tenant'; import { dynamicClear, dynamicTenant } from '@/api/system/tenant';
import { TenantVO } from '@/api/types'; import { TenantVO } from '@/api/types';
import notice from './notice/index.vue'; import notice from './notice/index.vue';
import router from '@/router'; import router from '@/router';
import {ElMessageBoxOptions} from "element-plus/es/components/message-box/src/message-box.type";
const appStore = useAppStore(); const appStore = useAppStore();
const userStore = useUserStore(); const userStore = useUserStore();
@ -128,8 +129,8 @@ const dynamicTenantEvent = async (tenantId: string) => {
await dynamicTenant(tenantId); await dynamicTenant(tenantId);
dynamic.value = true; dynamic.value = true;
await proxy?.$router.push('/'); await proxy?.$router.push('/');
await proxy?.proxy.$tab.closeAllPage(); await proxy?.$tab.closeAllPage();
await proxy?.proxy.$tab.refreshPage(); await proxy?.$tab.refreshPage();
} }
}; };
@ -137,8 +138,8 @@ const dynamicClearEvent = async () => {
await dynamicClear(); await dynamicClear();
dynamic.value = false; dynamic.value = false;
await proxy?.$router.push('/'); await proxy?.$router.push('/');
await proxy?.proxy.$tab.closeAllPage(); await proxy?.$tab.closeAllPage();
await proxy?.proxy.$tab.refreshPage(); await proxy?.$tab.refreshPage();
}; };
/** 租户列表 */ /** 租户列表 */
@ -163,7 +164,7 @@ const logout = async () => {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}); } as ElMessageBoxOptions);
userStore.logout().then(() => { userStore.logout().then(() => {
router.replace({ router.replace({
path: '/login', path: '/login',

View File

@ -89,9 +89,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { useDynamicTitle } from '@/utils/dynamicTitle'; import { useDynamicTitle } from '@/utils/dynamicTitle';
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import { handleThemeStyle } from '@/utils/theme'; import { handleThemeStyle } from '@/utils/theme';
import { SideThemeEnum } from '@/enums/SideThemeEnum'; import { SideThemeEnum } from '@/enums/SideThemeEnum';
import defaultSettings from '@/settings'; import defaultSettings from '@/settings';

View File

@ -24,7 +24,7 @@
<script setup lang="ts"> <script setup lang="ts">
import variables from '@/assets/styles/variables.module.scss'; import variables from '@/assets/styles/variables.module.scss';
import logo from '@/assets/logo/logo.png'; import logo from '@/assets/logo/logo.png';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
defineProps({ defineProps({

View File

@ -24,9 +24,9 @@
import Logo from './Logo.vue'; import Logo from './Logo.vue';
import SidebarItem from './SidebarItem.vue'; import SidebarItem from './SidebarItem.vue';
import variables from '@/assets/styles/variables.module.scss'; import variables from '@/assets/styles/variables.module.scss';
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;

View File

@ -6,7 +6,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { RouteLocationNormalized } from 'vue-router'; import { RouteLocationNormalized } from 'vue-router';
import useTagsViewStore from '@/store/modules/tagsView'; import { useTagsViewStore } from '@/store/modules/tagsView';
const tagAndTagSpacing = ref(4); const tagAndTagSpacing = ref(4);

View File

@ -32,9 +32,9 @@
<script setup lang="ts"> <script setup lang="ts">
import ScrollPane from './ScrollPane.vue'; import ScrollPane from './ScrollPane.vue';
import { getNormalPath } from '@/utils/ruoyi'; import { getNormalPath } from '@/utils/ruoyi';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import useTagsViewStore from '@/store/modules/tagsView'; import { useTagsViewStore } from '@/store/modules/tagsView';
import { RouteRecordRaw, RouteLocationNormalized } from 'vue-router'; import { RouteRecordRaw, RouteLocationNormalized } from 'vue-router';
const visible = ref(false); const visible = ref(false);

View File

@ -28,7 +28,7 @@
<script setup lang="ts" name="layoutBreadcrumbSearch"> <script setup lang="ts" name="layoutBreadcrumbSearch">
import { getNormalPath } from '@/utils/ruoyi'; import { getNormalPath } from '@/utils/ruoyi';
import { isHttp } from '@/utils/validate'; import { isHttp } from '@/utils/validate';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
type Router = Array<{ type Router = Array<{
path: string; path: string;
@ -130,7 +130,7 @@ defineExpose({
}); });
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.layout-search-dialog { .layout-search-dialog {
position: relative; position: relative;
:deep(.el-dialog) { :deep(.el-dialog) {

View File

@ -25,7 +25,7 @@
<script setup lang="ts" name="layoutBreadcrumbUserNews"> <script setup lang="ts" name="layoutBreadcrumbUserNews">
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import useNoticeStore from '@/store/modules/notice'; import { useNoticeStore } from '@/store/modules/notice';
const noticeStore = storeToRefs(useNoticeStore()); const noticeStore = storeToRefs(useNoticeStore());
const { readAll } = useNoticeStore(); const { readAll } = useNoticeStore();
@ -65,7 +65,7 @@ onMounted(() => {
}); });
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.layout-navbars-breadcrumb-user-news { .layout-navbars-breadcrumb-user-news {
.head-box { .head-box {
display: flex; display: flex;

View File

@ -24,8 +24,8 @@
<script setup lang="ts"> <script setup lang="ts">
import SideBar from './components/Sidebar/index.vue'; import SideBar from './components/Sidebar/index.vue';
import { AppMain, Navbar, Settings, TagsView } from './components'; import { AppMain, Navbar, Settings, TagsView } from './components';
import useAppStore from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import { initWebSocket } from '@/utils/websocket'; import { initWebSocket } from '@/utils/websocket';
import { initSSE } from '@/utils/sse'; import { initSSE } from '@/utils/sse';
@ -68,7 +68,7 @@ onMounted(() => {
}); });
onMounted(() => { onMounted(() => {
let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket'); initWebSocket(protocol + window.location.host + import.meta.env.VITE_APP_BASE_API + '/resource/websocket');
}); });
@ -86,11 +86,11 @@ const setLayout = () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/styles/mixin.scss'; @use '@/assets/styles/mixin.scss';
@import '@/assets/styles/variables.module.scss'; @use '@/assets/styles/variables.module.scss' as *;
.app-wrapper { .app-wrapper {
@include clearfix; @include mixin.clearfix;
position: relative; position: relative;
height: 100%; height: 100%;
width: 100%; width: 100%;

View File

@ -5,9 +5,10 @@ import 'nprogress/nprogress.css';
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import { isHttp, isPathMatch } from '@/utils/validate'; import { isHttp, isPathMatch } from '@/utils/validate';
import { isRelogin } from '@/utils/request'; import { isRelogin } from '@/utils/request';
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import useSettingsStore from '@/store/modules/settings'; import { useSettingsStore } from '@/store/modules/settings';
import usePermissionStore from '@/store/modules/permission'; import { usePermissionStore } from '@/store/modules/permission';
import { ElMessage } from 'element-plus/es';
NProgress.configure({ showSpinner: false }); NProgress.configure({ showSpinner: false });
const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*']; const whiteList = ['/login', '/register', '/social-callback', '/register*', '/register/*'];
@ -19,7 +20,7 @@ const isWhiteList = (path: string) => {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start(); NProgress.start();
if (getToken()) { if (getToken()) {
to.meta.title && useSettingsStore().setTitle(to.meta.title); to.meta.title && useSettingsStore().setTitle(to.meta.title as string);
/* has token*/ /* has token*/
if (to.path === '/login') { if (to.path === '/login') {
next({ path: '/' }); next({ path: '/' });

View File

@ -1,4 +1,4 @@
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
const authPermission = (permission: string): boolean => { const authPermission = (permission: string): boolean => {
const all_permission = '*:*:*'; const all_permission = '*:*:*';

View File

@ -1,6 +1,6 @@
import router from '@/router'; import router from '@/router';
import { RouteLocationMatched, RouteLocationNormalized, RouteLocationRaw } from 'vue-router'; import { RouteLocationMatched, RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import useTagsViewStore from '@/store/modules/tagsView'; import { useTagsViewStore } from '@/store/modules/tagsView';
export default { export default {
/** /**

View File

@ -50,13 +50,29 @@ const setting: DefaultSettings = {
*/ */
errorLog: 'production', errorLog: 'production',
/**
*
*/
animationEnable: false, animationEnable: false,
/**
*
*/
dark: false, dark: false,
/**
*
*/
language: LanguageEnum.zh_CN, language: LanguageEnum.zh_CN,
/**
*
*/
size: 'default', size: 'default',
/**
*
*/
layout: '' layout: ''
}; };
export default setting; export default setting;

View File

@ -1,3 +1,5 @@
import { createPinia } from "pinia";
const store = createPinia(); const store = createPinia();
export default store; export default store;

View File

@ -1,5 +1,8 @@
import zhCN from 'element-plus/es/locale/lang/zh-cn'; import zhCN from 'element-plus/es/locale/lang/zh-cn';
import enUS from 'element-plus/es/locale/lang/en'; import enUS from 'element-plus/es/locale/lang/en';
import { defineStore } from 'pinia';
import { useStorage } from '@vueuse/core';
import { ref, reactive, computed } from 'vue';
export const useAppStore = defineStore('app', () => { export const useAppStore = defineStore('app', () => {
const sidebarStatus = useStorage('sidebarStatus', '1'); const sidebarStatus = useStorage('sidebarStatus', '1');
@ -68,5 +71,3 @@ export const useAppStore = defineStore('app', () => {
toggleSideBarHide toggleSideBarHide
}; };
}); });
export default useAppStore;

View File

@ -1,3 +1,5 @@
import { defineStore } from 'pinia';
export const useDictStore = defineStore('dict', () => { export const useDictStore = defineStore('dict', () => {
const dict = ref<Map<string, DictDataOption[]>>(new Map()); const dict = ref<Map<string, DictDataOption[]>>(new Map());
@ -61,5 +63,3 @@ export const useDictStore = defineStore('dict', () => {
cleanDict cleanDict
}; };
}); });
export default useDictStore;

View File

@ -1,4 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { reactive } from 'vue';
interface NoticeItem { interface NoticeItem {
title?: string; title?: string;
@ -38,5 +39,3 @@ export const useNoticeStore = defineStore('notice', () => {
clearNotice clearNotice
}; };
}); });
export default useNoticeStore;

View File

@ -4,11 +4,10 @@ import store from '@/store';
import { getRouters } from '@/api/menu'; import { getRouters } from '@/api/menu';
import auth from '@/plugins/auth'; import auth from '@/plugins/auth';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
import Layout from '@/layout/index.vue'; import Layout from '@/layout/index.vue';
import ParentView from '@/components/ParentView/index.vue'; import ParentView from '@/components/ParentView/index.vue';
import InnerLink from '@/layout/components/InnerLink/index.vue'; import InnerLink from '@/layout/components/InnerLink/index.vue';
import { ref } from 'vue';
import { createCustomNameComponent } from '@/utils/createCustomNameComponent'; import { createCustomNameComponent } from '@/utils/createCustomNameComponent';
// 匹配views里面所有的.vue文件 // 匹配views里面所有的.vue文件
@ -23,6 +22,9 @@ export const usePermissionStore = defineStore('permission', () => {
const getRoutes = (): RouteRecordRaw[] => { const getRoutes = (): RouteRecordRaw[] => {
return routes.value as RouteRecordRaw[]; return routes.value as RouteRecordRaw[];
}; };
const getDefaultRoutes = (): RouteRecordRaw[] => {
return defaultRoutes.value as RouteRecordRaw[];
};
const getSidebarRoutes = (): RouteRecordRaw[] => { const getSidebarRoutes = (): RouteRecordRaw[] => {
return sidebarRouters.value as RouteRecordRaw[]; return sidebarRouters.value as RouteRecordRaw[];
}; };
@ -97,29 +99,14 @@ export const usePermissionStore = defineStore('permission', () => {
}; };
const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => { const filterChildren = (childrenMap: RouteRecordRaw[], lastRouter?: RouteRecordRaw): RouteRecordRaw[] => {
let children: RouteRecordRaw[] = []; let children: RouteRecordRaw[] = [];
childrenMap.forEach((el) => { childrenMap.forEach(el => {
if (el.children && el.children.length) { el.path = lastRouter ? lastRouter.path + '/' + el.path : el.path;
if (el.component?.toString() === 'ParentView' && !lastRouter) { if (el.children && el.children.length && el.component?.toString() === 'ParentView') {
el.children.forEach((c) => { children = children.concat(filterChildren(el.children, el));
c.path = el.path + '/' + c.path; } else {
if (c.children && c.children.length) { children.push(el);
children = children.concat(filterChildren(c.children, c));
return;
}
children.push(c);
});
return;
}
} }
if (lastRouter) { })
el.path = lastRouter.path + '/' + el.path;
if (el.children && el.children.length) {
children = children.concat(filterChildren(el.children, el));
return;
}
}
children = children.concat(el);
});
return children; return children;
}; };
return { return {
@ -129,6 +116,7 @@ export const usePermissionStore = defineStore('permission', () => {
defaultRoutes, defaultRoutes,
getRoutes, getRoutes,
getDefaultRoutes,
getSidebarRoutes, getSidebarRoutes,
getTopbarRoutes, getTopbarRoutes,
@ -217,5 +205,3 @@ function duplicateRouteChecker(localRoutes: Route[], routes: Route[]) {
nameList.push(route.name.toString()); nameList.push(route.name.toString());
}); });
} }
export default usePermissionStore;

View File

@ -1,8 +1,11 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import defaultSettings from '@/settings'; import defaultSettings from '@/settings';
import { useDynamicTitle } from '@/utils/dynamicTitle'; import { useDynamicTitle } from '@/utils/dynamicTitle';
import { useStorage } from '@vueuse/core';
import { ref } from 'vue';
export const useSettingsStore = defineStore('setting', () => { export const useSettingsStore = defineStore('setting', () => {
// @ts-ignore
const storageSetting = useStorage<LayoutSetting>('layout-setting', { const storageSetting = useStorage<LayoutSetting>('layout-setting', {
topNav: defaultSettings.topNav, topNav: defaultSettings.topNav,
tagsView: defaultSettings.tagsView, tagsView: defaultSettings.tagsView,
@ -43,5 +46,3 @@ export const useSettingsStore = defineStore('setting', () => {
setTitle setTitle
}; };
}); });
export default useSettingsStore;

View File

@ -1,4 +1,6 @@
import { RouteLocationNormalized } from 'vue-router'; import { RouteLocationNormalized } from 'vue-router';
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useTagsViewStore = defineStore('tagsView', () => { export const useTagsViewStore = defineStore('tagsView', () => {
const visitedViews = ref<RouteLocationNormalized[]>([]); const visitedViews = ref<RouteLocationNormalized[]>([]);
@ -230,4 +232,3 @@ export const useTagsViewStore = defineStore('tagsView', () => {
delIframeView delIframeView
}; };
}); });
export default useTagsViewStore;

View File

@ -3,7 +3,8 @@ import { getToken, removeToken, setToken } from '@/utils/auth';
import { login as loginApi, logout as logoutApi, getInfo as getUserInfo } from '@/api/login'; import { login as loginApi, logout as logoutApi, getInfo as getUserInfo } from '@/api/login';
import { LoginData } from '@/api/types'; import { LoginData } from '@/api/types';
import defAva from '@/assets/images/profile.jpg'; import defAva from '@/assets/images/profile.jpg';
import store from '@/store'; import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useUserStore = defineStore('user', () => { export const useUserStore = defineStore('user', () => {
const token = ref(getToken()); const token = ref(getToken());
@ -83,9 +84,3 @@ export const useUserStore = defineStore('user', () => {
setAvatar setAvatar
}; };
}); });
export default useUserStore;
// 非setup
export function useUserStoreHook() {
return useUserStore(store);
}

View File

@ -1,4 +1,4 @@
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
/** /**
* *

View File

@ -167,39 +167,21 @@ export const handleTree = <T>(data: any[], id?: string, parentId?: string, child
}; };
const childrenListMap: any = {}; const childrenListMap: any = {};
const nodeIds: any = {};
const tree: T[] = []; const tree: T[] = [];
for (const d of data) { for (const d of data) {
const parentId = d[config.parentId]; const id = d[config.id];
if (childrenListMap[parentId] == null) { childrenListMap[id] = d;
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
} }
for (const d of data) { for (const d of data) {
const parentId = d[config.parentId]; const parentId = d[config.parentId];
if (nodeIds[parentId] == null) { const parentObj = childrenListMap[parentId]
if (!parentObj) {
tree.push(d); tree.push(d);
} else {
parentObj[config.childrenList].push(d)
} }
} }
const adaptToChildrenList = (o: any) => {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
};
for (const t of tree) {
adaptToChildrenList(t);
}
return tree; return tree;
}; };

View File

@ -1,6 +1,6 @@
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import { ElNotification } from 'element-plus'; import { ElNotification } from 'element-plus';
import useNoticeStore from '@/store/modules/notice'; import { useNoticeStore } from '@/store/modules/notice';
// 初始化 // 初始化
export const initSSE = (url: any) => { export const initSSE = (url: any) => {

View File

@ -1,6 +1,6 @@
import { getToken } from '@/utils/auth'; import { getToken } from '@/utils/auth';
import { ElNotification } from 'element-plus'; import { ElNotification } from 'element-plus';
import useNoticeStore from '@/store/modules/notice'; import { useNoticeStore } from '@/store/modules/notice';
// 初始化socket // 初始化socket
export const initWebSocket = (url: any) => { export const initWebSocket = (url: any) => {

View File

@ -62,7 +62,7 @@
<el-tree-select <el-tree-select
v-model="form.parentId" v-model="form.parentId"
:data="treeOptions" :data="treeOptions"
:props="{ value: 'id', label: 'treeName', children: 'children' }" :props="{ value: 'id', label: 'treeName', children: 'children' } as any"
value-key="id" value-key="id"
placeholder="请选择父id" placeholder="请选择父id"
check-strictly check-strictly

View File

@ -33,7 +33,7 @@
* 部署方式 Docker 容器编排 一键部署业务集群<br /> * 部署方式 Docker 容器编排 一键部署业务集群<br />
* 国际化 SpringMessage Spring标准国际化方案<br /> * 国际化 SpringMessage Spring标准国际化方案<br />
</p> </p>
<p><b>当前版本:</b> <span>v5.3.0</span></p> <p><b>当前版本:</b> <span>v5.3.1</span></p>
<p> <p>
<el-tag type="danger">&yen;免费开源</el-tag> <el-tag type="danger">&yen;免费开源</el-tag>
</p> </p>
@ -100,7 +100,7 @@ const goTarget = (url: string) => {
}; };
</script> </script>
<style scoped lang="scss"> <style lang="scss" scoped>
.home { .home {
blockquote { blockquote {
padding: 10px 20px; padding: 10px 20px;

View File

@ -73,7 +73,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span>Copyright © 2018-2024 疯狂的狮子Li All Rights Reserved.</span> <span>Copyright © 2018-2025 疯狂的狮子Li All Rights Reserved.</span>
</div> </div>
</div> </div>
</template> </template>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="p-2"> <div class="p-2">
<el-row> <el-row :gutter="10">
<el-col :span="24" class="card-box"> <el-col :span="24" class="card-box">
<el-card shadow="hover"> <el-card shadow="hover">
<template #header> <template #header>

View File

@ -95,7 +95,7 @@ const typeFormat = (row: OperLogForm) => {
}; };
</script> </script>
<style scoped> <style lang="scss" scoped>
/** /**
label宽度固定 label宽度固定
*/ */

View File

@ -2,7 +2,7 @@
<div></div> <div></div>
</template> </template>
<script setup> <script setup lang="ts">
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
const route = useRoute(); const route = useRoute();

View File

@ -67,7 +67,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-register-footer"> <div class="el-register-footer">
<span>Copyright © 2018-2024 疯狂的狮子Li All Rights Reserved.</span> <span>Copyright © 2018-2025 疯狂的狮子Li All Rights Reserved.</span>
</div> </div>
</div> </div>
</template> </template>

View File

@ -2,7 +2,7 @@
<div class="p-2"> <div class="p-2">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="search"> <div v-show="showSearch" class="search">
<el-form ref="queryFormRef" :model="queryParams" :inline="true"> <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="85px">
<el-form-item label="客户端key" prop="clientKey"> <el-form-item label="客户端key" prop="clientKey">
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable @keyup.enter="handleQuery" /> <el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable @keyup.enter="handleQuery" />
</el-form-item> </el-form-item>

View File

@ -82,7 +82,7 @@
<el-tree-select <el-tree-select
v-model="form.parentId" v-model="form.parentId"
:data="deptOptions" :data="deptOptions"
:props="{ value: 'deptId', label: 'deptName', children: 'children' }" :props="{ value: 'deptId', label: 'deptName', children: 'children' } as any"
value-key="deptId" value-key="deptId"
placeholder="选择上级部门" placeholder="选择上级部门"
check-strictly check-strictly

View File

@ -126,7 +126,7 @@
</template> </template>
<script setup name="Data" lang="ts"> <script setup name="Data" lang="ts">
import useDictStore from '@/store/modules/dict'; import { useDictStore } from '@/store/modules/dict';
import { optionselect as getDictOptionselect, getType } from '@/api/system/dict/type'; import { optionselect as getDictOptionselect, getType } from '@/api/system/dict/type';
import { listData, getData, delData, addData, updateData } from '@/api/system/dict/data'; import { listData, getData, delData, addData, updateData } from '@/api/system/dict/data';
import { DictTypeVO } from '@/api/system/dict/type/types'; import { DictTypeVO } from '@/api/system/dict/type/types';

View File

@ -108,7 +108,7 @@
</template> </template>
<script setup name="Dict" lang="ts"> <script setup name="Dict" lang="ts">
import useDictStore from '@/store/modules/dict'; import { useDictStore } from '@/store/modules/dict';
import { listType, getType, delType, addType, updateType, refreshCache } from '@/api/system/dict/type'; import { listType, getType, delType, addType, updateType, refreshCache } from '@/api/system/dict/type';
import { DictTypeForm, DictTypeQuery, DictTypeVO } from '@/api/system/dict/type/types'; import { DictTypeForm, DictTypeQuery, DictTypeVO } from '@/api/system/dict/type/types';

View File

@ -85,7 +85,7 @@
<el-tree-select <el-tree-select
v-model="form.parentId" v-model="form.parentId"
:data="menuOptions" :data="menuOptions"
:props="{ value: 'menuId', label: 'menuName', children: 'children' }" :props="{ value: 'menuId', label: 'menuName', children: 'children' } as any"
value-key="menuId" value-key="menuId"
placeholder="选择上级菜单" placeholder="选择上级菜单"
check-strictly check-strictly

View File

@ -10,7 +10,7 @@
class="mt-2" class="mt-2"
node-key="id" node-key="id"
:data="deptOptions" :data="deptOptions"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
highlight-current highlight-current
@ -43,7 +43,7 @@
<el-tree-select <el-tree-select
v-model="queryParams.deptId" v-model="queryParams.deptId"
:data="deptOptions" :data="deptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" :props="{ value: 'id', label: 'label', children: 'children' } as any"
value-key="id" value-key="id"
placeholder="请选择部门" placeholder="请选择部门"
check-strictly check-strictly
@ -133,7 +133,7 @@
<el-tree-select <el-tree-select
v-model="form.deptId" v-model="form.deptId"
:data="deptOptions" :data="deptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" :props="{ value: 'id', label: 'label', children: 'children' } as any"
value-key="id" value-key="id"
placeholder="请选择部门" placeholder="请选择部门"
check-strictly check-strictly

View File

@ -156,5 +156,3 @@ onMounted(() => {
getList(); getList();
}); });
</script> </script>
<style lang="scss" scoped></style>

View File

@ -135,7 +135,7 @@
node-key="id" node-key="id"
:check-strictly="!form.menuCheckStrictly" :check-strictly="!form.menuCheckStrictly"
empty-text="加载中,请稍候" empty-text="加载中,请稍候"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
></el-tree> ></el-tree>
</el-form-item> </el-form-item>
<el-form-item label="备注"> <el-form-item label="备注">
@ -177,7 +177,7 @@
node-key="id" node-key="id"
:check-strictly="!form.deptCheckStrictly" :check-strictly="!form.deptCheckStrictly"
empty-text="加载中,请稍候" empty-text="加载中,请稍候"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
></el-tree> ></el-tree>
</el-form-item> </el-form-item>
</el-form> </el-form>

View File

@ -128,5 +128,3 @@ defineExpose({
show show
}); });
</script> </script>
<style scoped></style>

View File

@ -155,7 +155,7 @@ import {
syncTenantDict syncTenantDict
} from '@/api/system/tenant'; } from '@/api/system/tenant';
import { selectTenantPackage } from '@/api/system/tenantPackage'; import { selectTenantPackage } from '@/api/system/tenantPackage';
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types'; import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
import { TenantPkgVO } from '@/api/system/tenantPackage/types'; import { TenantPkgVO } from '@/api/system/tenantPackage/types';

View File

@ -82,7 +82,7 @@
node-key="id" node-key="id"
:check-strictly="!form.menuCheckStrictly" :check-strictly="!form.menuCheckStrictly"
empty-text="加载中,请稍候" empty-text="加载中,请稍候"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
></el-tree> ></el-tree>
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark"> <el-form-item label="备注" prop="remark">

View File

@ -10,7 +10,7 @@
class="mt-2" class="mt-2"
node-key="id" node-key="id"
:data="deptOptions" :data="deptOptions"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
highlight-current highlight-current
@ -81,8 +81,9 @@
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item> <el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
<el-dropdown-item v-has-permi="['system:user:import']" icon="Top" @click="handleImport">导入数据</el-dropdown-item> <!-- 注意 由于el-dropdown-item标签是延迟加载的 所以v-has-permi自定义标签不生效 需要使用v-if调用方法执行 -->
<el-dropdown-item v-has-permi="['system:user:export']" icon="Download" @click="handleExport">导出数据</el-dropdown-item> <el-dropdown-item v-if="checkPermi(['system:user:import'])" icon="Top" @click="handleImport">导入数据</el-dropdown-item>
<el-dropdown-item v-if="checkPermi(['system:user:export'])" icon="Download" @click="handleExport">导出数据</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
@ -155,7 +156,7 @@
<el-tree-select <el-tree-select
v-model="form.deptId" v-model="form.deptId"
:data="enabledDeptOptions" :data="enabledDeptOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" :props="{ value: 'id', label: 'label', children: 'children' } as any"
value-key="id" value-key="id"
placeholder="请选择归属部门" placeholder="请选择归属部门"
check-strictly check-strictly
@ -287,13 +288,15 @@
<script setup name="User" lang="ts"> <script setup name="User" lang="ts">
import api from '@/api/system/user'; import api from '@/api/system/user';
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types'; import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
import {DeptTreeVO, DeptVO} from '@/api/system/dept/types'; import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
import { RoleVO } from '@/api/system/role/types'; import { RoleVO } from '@/api/system/role/types';
import { PostQuery, PostVO } from '@/api/system/post/types'; import { PostQuery, PostVO } from '@/api/system/post/types';
import { treeselect } from '@/api/system/dept'; import { treeselect } from '@/api/system/dept';
import { globalHeaders } from '@/utils/request'; import { globalHeaders } from '@/utils/request';
import { to } from 'await-to-js'; import { to } from 'await-to-js';
import { optionselect } from '@/api/system/post'; import { optionselect } from '@/api/system/post';
import { hasPermi } from '@/directive/permission';
import { checkPermi } from '@/utils/permission';
const router = useRouter(); const router = useRouter();
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -450,7 +453,7 @@ const getDeptTree = async () => {
/** 过滤禁用的部门 */ /** 过滤禁用的部门 */
const filterDisabledDept = (deptList: DeptTreeVO[]) => { const filterDisabledDept = (deptList: DeptTreeVO[]) => {
return deptList.filter(dept => { return deptList.filter((dept) => {
if (dept.disabled) { if (dept.disabled) {
return false; return false;
} }
@ -660,5 +663,3 @@ async function handleDeptChange(value: number | string) {
form.value.postIds = []; form.value.postIds = [];
} }
</script> </script>
<style lang="scss" scoped></style>

View File

@ -26,7 +26,7 @@
</div> </div>
</template> </template>
<script name="Online" lang="ts" setup> <script setup name="Online" lang="ts">
import { delOnline } from '@/api/monitor/online'; import { delOnline } from '@/api/monitor/online';
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';

View File

@ -55,10 +55,10 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { authUnlock, authBinding } from '@/api/system/social/auth'; import { authUnlock, authBinding } from '@/api/system/social/auth';
import { propTypes } from '@/utils/propTypes'; import { propTypes } from '@/utils/propTypes';
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -94,7 +94,7 @@ const authUrl = (source: string) => {
}; };
</script> </script>
<style type="text/css"> <style lang="scss" scoped>
.user-bind .third-app { .user-bind .third-app {
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
@ -128,8 +128,9 @@ a {
} }
.provider-desc { .provider-desc {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', font-family:
'Liberation Sans', 'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, SimSun, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Liberation Sans',
'PingFang SC', 'Microsoft YaHei', 'Hiragino Sans GB', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti', SimHei, SimSun,
'WenQuanYi Zen Hei Sharp', sans-serif; 'WenQuanYi Zen Hei Sharp', sans-serif;
font-size: 1.071rem; font-size: 1.071rem;
} }

View File

@ -59,7 +59,7 @@
import 'vue-cropper/dist/index.css'; import 'vue-cropper/dist/index.css';
import { VueCropper } from 'vue-cropper'; import { VueCropper } from 'vue-cropper';
import { uploadAvatar } from '@/api/system/user'; import { uploadAvatar } from '@/api/system/user';
import useUserStore from '@/store/modules/user'; import { useUserStore } from '@/store/modules/user';
import { UploadRawFile } from 'element-plus'; import { UploadRawFile } from 'element-plus';
interface Options { interface Options {

View File

@ -89,7 +89,7 @@
</el-table-column> </el-table-column>
<el-table-column label="字典类型" min-width="12%"> <el-table-column label="字典类型" min-width="12%">
<template #default="scope"> <template #default="scope">
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择"> <el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择" value-on-clear="">
<el-option v-for="dict in dictOptions" :key="dict.dictType" :label="dict.dictName" :value="dict.dictType"> <el-option v-for="dict in dictOptions" :key="dict.dictType" :label="dict.dictName" :value="dict.dictType">
<span style="float: left">{{ dict.dictName }}</span> <span style="float: left">{{ dict.dictName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span> <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>

View File

@ -70,7 +70,7 @@
<el-tree-select <el-tree-select
v-model="infoForm.parentMenuId" v-model="infoForm.parentMenuId"
:data="menuOptions" :data="menuOptions"
:props="{ value: 'menuId', label: 'menuName', children: 'children' }" :props="{ value: 'menuId', label: 'menuName', children: 'children' } as any"
value-key="menuId" value-key="menuId"
node-key="menuId" node-key="menuId"
placeholder="选择上级菜单" placeholder="选择上级菜单"

View File

@ -58,7 +58,7 @@
<el-tree-select <el-tree-select
v-model="form.parentId" v-model="form.parentId"
:data="categoryOptions" :data="categoryOptions"
:props="{ value: 'categoryId', label: 'categoryName', children: 'children' }" :props="{ value: 'categoryId', label: 'categoryName', children: 'children' } as any"
value-key="categoryId" value-key="categoryId"
placeholder="请选择上级分类" placeholder="请选择上级分类"
check-strictly check-strictly

View File

@ -111,6 +111,10 @@ const flowCodeOptions = [
{ {
value: 'leave5', value: 'leave5',
label: '请假申请-并行会签网关' label: '请假申请-并行会签网关'
},
{
value: 'leave6',
label: '请假申请-排他并行会签'
} }
]; ];

View File

@ -10,7 +10,7 @@
class="mt-2" class="mt-2"
node-key="id" node-key="id"
:data="categoryOptions" :data="categoryOptions"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
highlight-current highlight-current
@ -131,7 +131,7 @@
<el-tree-select <el-tree-select
v-model="selectCategory" v-model="selectCategory"
:data="categoryOptions" :data="categoryOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" :props="{ value: 'id', label: 'label', children: 'children' } as any"
filterable filterable
value-key="id" value-key="id"
:render-after-expand="false" :render-after-expand="false"
@ -163,7 +163,7 @@
<el-tree-select <el-tree-select
v-model="form.category" v-model="form.category"
:data="categoryOptions" :data="categoryOptions"
:props="{ value: 'id', label: 'label', children: 'children' }" :props="{ value: 'id', label: 'label', children: 'children' } as any"
filterable filterable
value-key="id" value-key="id"
:render-after-expand="false" :render-after-expand="false"
@ -177,7 +177,7 @@
<el-form-item label="流程名称" prop="flowName"> <el-form-item label="流程名称" prop="flowName">
<el-input v-model="form.flowName" placeholder="请输入流程名称" maxlength="100" show-word-limit /> <el-input v-model="form.flowName" placeholder="请输入流程名称" maxlength="100" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item label="表单路径" prop="flowName"> <el-form-item label="表单路径" prop="formPath">
<el-input v-model="form.formPath" placeholder="请输入表单路径" maxlength="100" show-word-limit /> <el-input v-model="form.formPath" placeholder="请输入表单路径" maxlength="100" show-word-limit />
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -190,12 +190,13 @@
</div> </div>
</template> </template>
<script lang="ts" setup name="processDefinition"> <script setup name="processDefinition" lang="ts">
import { listDefinition, deleteDefinition, active, importDef, unPublishList, publish, add, edit, getInfo, copy } from '@/api/workflow/definition'; import { listDefinition, deleteDefinition, active, importDef, unPublishList, publish, add, edit, getInfo, copy } from '@/api/workflow/definition';
import { categoryTree } from '@/api/workflow/category'; import { categoryTree } from '@/api/workflow/category';
import { CategoryTreeVO } from '@/api/workflow/category/types'; import { CategoryTreeVO } from '@/api/workflow/category/types';
import { FlowDefinitionQuery, FlowDefinitionVo, FlowDefinitionForm } from '@/api/workflow/definition/types'; import { FlowDefinitionQuery, FlowDefinitionVo, FlowDefinitionForm } from '@/api/workflow/definition/types';
import { UploadRequestOptions, TabsPaneContext } from 'element-plus'; import { UploadRequestOptions, TabsPaneContext } from 'element-plus';
import { ElMessageBoxOptions } from "element-plus/es/components/message-box/src/message-box.type";
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
@ -324,9 +325,9 @@ const handleSelectionChange = (selection: any) => {
}; };
// //
const getPageList = async () => { const getPageList = async () => {
console.log(proxy.$route.query.activeName) let query = proxy.$route.query;
if (proxy.$route.query.activeName) { if (query.activeName) {
activeName.value = proxy.$route.query.activeName; activeName.value = query.activeName;
} }
if (activeName.value === '0') { if (activeName.value === '0') {
getList(); getList();
@ -370,7 +371,7 @@ const handlePublish = async (row?: FlowDefinitionVo) => {
loading.value = true; loading.value = true;
await publish(row.id).finally(() => (loading.value = false)); await publish(row.id).finally(() => (loading.value = false));
processDefinitionDialog.visible = false; processDefinitionDialog.visible = false;
activeName.value = "0" activeName.value = '0';
await handleQuery(); await handleQuery();
proxy?.$modal.msgSuccess('发布成功'); proxy?.$modal.msgSuccess('发布成功');
}; };
@ -417,7 +418,7 @@ const handlerImportDefinition = (data: UploadRequestOptions): XMLHttpRequest =>
.then(() => { .then(() => {
uploadDialog.visible = false; uploadDialog.visible = false;
proxy?.$modal.msgSuccess('部署成功'); proxy?.$modal.msgSuccess('部署成功');
activeName.value = "1" activeName.value = '1';
handleQuery(); handleQuery();
}) })
.finally(() => { .finally(() => {
@ -482,9 +483,9 @@ const handleSubmit = async () => {
if (valid) { if (valid) {
loading.value = true; loading.value = true;
if (form.value.id) { if (form.value.id) {
await edit(form.value).finally(() => loading.value = false); await edit(form.value).finally(() => (loading.value = false));
} else { } else {
await add(form.value).finally(() => loading.value = false); await add(form.value).finally(() => (loading.value = false));
} }
proxy?.$modal.msgSuccess('操作成功'); proxy?.$modal.msgSuccess('操作成功');
modelDialog.visible = false; modelDialog.visible = false;
@ -498,15 +499,17 @@ const handleCopyDef = async (row: FlowDefinitionVo) => {
confirmButtonText: '确认', confirmButtonText: '确认',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { } as ElMessageBoxOptions).then(() => {
loading.value = true; loading.value = true;
copy(row.id).then((resp) => { copy(row.id)
if (resp.code === 200) { .then((resp) => {
proxy?.$modal.msgSuccess('操作成功'); if (resp.code === 200) {
activeName.value = "1" proxy?.$modal.msgSuccess('操作成功');
handleQuery(); activeName.value = '1';
} handleQuery();
}).finally(() => loading.value = false); }
})
.finally(() => (loading.value = false));
}); });
}; };

View File

@ -10,7 +10,7 @@
class="mt-2" class="mt-2"
node-key="id" node-key="id"
:data="categoryOptions" :data="categoryOptions"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
highlight-current highlight-current
@ -174,7 +174,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { pageByRunning, pageByFinish, deleteByInstanceIds, instanceVariable, invalid } from '@/api/workflow/instance'; import { pageByRunning, pageByFinish, deleteByInstanceIds, instanceVariable, invalid } from '@/api/workflow/instance';
import { categoryTree } from '@/api/workflow/category'; import { categoryTree } from '@/api/workflow/category';
import { CategoryTreeVO } from '@/api/workflow/category/types'; import { CategoryTreeVO } from '@/api/workflow/category/types';

View File

@ -97,14 +97,14 @@
</el-card> </el-card>
<!-- 选人组件 --> <!-- 选人组件 -->
<UserSelect ref="userSelectRef" :multiple="false" @confirm-call-back="submitCallback"></UserSelect> <UserSelect ref="userSelectRef" :multiple="false" @confirm-call-back="submitCallback"></UserSelect>
<!-- 选人组件 --> <!-- 流程干预组件 -->
<processMeddle ref="processMeddleRef" @submitCallback="getWaitingList"></processMeddle> <processMeddle ref="processMeddleRef" @submitCallback="getWaitingList"></processMeddle>
<!-- 申请人 --> <!-- 申请人 -->
<UserSelect ref="applyUserSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect> <UserSelect ref="applyUserSelectRef" :multiple="true" :data="selectUserIds" @confirm-call-back="userSelectCallBack"></UserSelect>
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { pageByAllTaskWait, pageByAllTaskFinish, updateAssignee } from '@/api/workflow/task'; import { pageByAllTaskWait, pageByAllTaskFinish, updateAssignee } from '@/api/workflow/task';
import UserSelect from '@/components/UserSelect'; import UserSelect from '@/components/UserSelect';
import { TaskQuery } from '@/api/workflow/task/types'; import { TaskQuery } from '@/api/workflow/task/types';

View File

@ -10,7 +10,7 @@
class="mt-2" class="mt-2"
node-key="id" node-key="id"
:data="categoryOptions" :data="categoryOptions"
:props="{ label: 'label', children: 'children' }" :props="{ label: 'label', children: 'children' } as any"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
highlight-current highlight-current
@ -101,7 +101,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { pageByCurrent, deleteByInstanceIds, cancelProcessApply } from '@/api/workflow/instance'; import { pageByCurrent, deleteByInstanceIds, cancelProcessApply } from '@/api/workflow/instance';
import { categoryTree } from '@/api/workflow/category'; import { categoryTree } from '@/api/workflow/category';
import { CategoryTreeVO } from '@/api/workflow/category/types'; import { CategoryTreeVO } from '@/api/workflow/category/types';

View File

@ -59,7 +59,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { pageByTaskCopy } from '@/api/workflow/task'; import { pageByTaskCopy } from '@/api/workflow/task';
import { TaskQuery } from '@/api/workflow/task/types'; import { TaskQuery } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon'; import workflowCommon from '@/api/workflow/workflowCommon';

View File

@ -80,7 +80,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { pageByTaskFinish } from '@/api/workflow/task'; import { pageByTaskFinish } from '@/api/workflow/task';
import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types'; import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon'; import workflowCommon from '@/api/workflow/workflowCommon';

View File

@ -77,7 +77,7 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script setup lang="ts">
import { pageByTaskWait } from '@/api/workflow/task'; import { pageByTaskWait } from '@/api/workflow/task';
import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types'; import { TaskQuery, FlowTaskVO } from '@/api/workflow/task/types';
import workflowCommon from '@/api/workflow/workflowCommon'; import workflowCommon from '@/api/workflow/workflowCommon';

View File

@ -1,31 +1,42 @@
{ {
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": { "compilerOptions": {
"target": "esnext", "baseUrl": ".",
"module": "esnext", // https://vite.dev/config/build-options.html#build-target
// "useDefineForClassFields": true, "target": "ES2020",
"moduleResolution": "bundler", "module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
// This setting lets you specify a file for storing incremental compilation information as a part of composite projects which enables faster building of larger TypeScript codebases.
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
"strict": true, "strict": true,
"allowJs": true,
"jsx": "preserve", "jsx": "preserve",
"strictNullChecks": false,
"sourceMap": true, "sourceMap": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"esModuleInterop": true, "esModuleInterop": true,
"strictFunctionTypes": false, "noEmit": true,
"lib": ["esnext", "dom"],
"noImplicitAny": false,
"baseUrl": ".",
"allowJs": true,
"experimentalDecorators": true,
"paths": { "paths": {
"@/*": ["src/*"] "@/*": ["./src/*"]
}, },
"types": ["vite/client"], "types": ["node", "vite/client"],
"skipLibCheck": true, //
"removeComments": true, "noImplicitAny": false, // any
// "removeComments": true, // ts
"allowSyntheticDefaultImports": true, "experimentalDecorators": true, //
"forceConsistentCasingInFileNames": true "strictFunctionTypes": false, //
"strictNullChecks": false, //
"allowSyntheticDefaultImports": true, //
"forceConsistentCasingInFileNames": true // 使
}, },
"include": ["src/**/*.ts", "src/**/*.vue", "src/types/**/*.d.ts", "vite.config.ts"], "include": [
"exclude": ["node_modules", "dist", "**/*.js", "**/*.md", "src/**/*.md"] "src/**/*.ts",
"src/**/*.vue",
"vite.config.ts",
"vitest.config.ts",
"eslint.config.ts",
"src/**/*.d.ts"
],
"exclude": ["node_modules", "dist", "src/**/__tests__/*"]
} }

View File

@ -1,9 +1,9 @@
import { UserConfig, ConfigEnv, loadEnv, defineConfig } from 'vite'; import { defineConfig, loadEnv } from 'vite';
import createPlugins from './vite/plugins'; import createPlugins from './vite/plugins';
import autoprefixer from 'autoprefixer'; // css自动添加兼容性前缀
import path from 'path'; import path from 'path';
export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd()); const env = loadEnv(mode, process.cwd());
return { return {
// 部署生产环境和开发环境下的URL。 // 部署生产环境和开发环境下的URL。
@ -12,7 +12,6 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
base: env.VITE_APP_CONTEXT_PATH, base: env.VITE_APP_CONTEXT_PATH,
resolve: { resolve: {
alias: { alias: {
'~': path.resolve(__dirname, './'),
'@': path.resolve(__dirname, './src') '@': path.resolve(__dirname, './src')
}, },
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
@ -35,18 +34,20 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
css: { css: {
preprocessorOptions: { preprocessorOptions: {
scss: { scss: {
javascriptEnabled: true // additionalData: '@use "@/assets/styles/variables.module.scss as *";'
// javascriptEnabled: true
api: 'modern-compiler'
} }
}, },
postcss: { postcss: {
plugins: [ plugins: [
// 浏览器兼容性
autoprefixer(),
{ {
postcssPlugin: 'internal:charset-removal', postcssPlugin: 'internal:charset-removal',
AtRule: { AtRule: {
charset: (atRule) => { charset: (atRule) => {
if (atRule.name === 'charset') { atRule.remove();
atRule.remove();
}
} }
} }
} }

View File

@ -1,22 +1,18 @@
import AutoImport from 'unplugin-auto-import/vite'; import AutoImport from 'unplugin-auto-import/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import IconsResolver from 'unplugin-icons/resolver';
export default (path: any) => { export default (path: any) => {
return AutoImport({ return AutoImport({
// 自动导入 Vue 相关函数 // 自动导入 Vue 相关函数
imports: ['vue', 'vue-router', '@vueuse/core', 'pinia'], imports: ['vue', 'vue-router', '@vueuse/core', 'pinia'],
eslintrc: { eslintrc: {
enabled: false, enabled: true,
filepath: './.eslintrc-auto-import.json', filepath: './.eslintrc-auto-import.json',
globalsPropValue: true globalsPropValue: true
}, },
resolvers: [ resolvers: [
// 自动导入 Element Plus 相关函数ElMessage, ElMessageBox... (带样式) // 自动导入 Element Plus 相关函数ElMessage, ElMessageBox... (带样式)
ElementPlusResolver(), ElementPlusResolver()
IconsResolver({
prefix: 'Icon'
})
], ],
vueTemplate: true, // 是否在 vue 模板中自动导入 vueTemplate: true, // 是否在 vue 模板中自动导入
dts: path.resolve(path.resolve(__dirname, '../../src'), 'types', 'auto-imports.d.ts') dts: path.resolve(path.resolve(__dirname, '../../src'), 'types', 'auto-imports.d.ts')

View File

@ -1,4 +1,6 @@
import vue from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue';
import vueDevTools from 'vite-plugin-vue-devtools';
import createUnoCss from './unocss'; import createUnoCss from './unocss';
import createAutoImport from './auto-import'; import createAutoImport from './auto-import';
import createComponents from './components'; import createComponents from './components';
@ -11,12 +13,13 @@ import path from 'path';
export default (viteEnv: any, isBuild = false): [] => { export default (viteEnv: any, isBuild = false): [] => {
const vitePlugins: any = []; const vitePlugins: any = [];
vitePlugins.push(vue()); vitePlugins.push(vue());
vitePlugins.push(vueDevTools());
vitePlugins.push(createUnoCss()); vitePlugins.push(createUnoCss());
vitePlugins.push(createAutoImport(path)); vitePlugins.push(createAutoImport(path));
vitePlugins.push(createComponents(path)); vitePlugins.push(createComponents(path));
vitePlugins.push(createCompression(viteEnv)); vitePlugins.push(createCompression(viteEnv));
vitePlugins.push(createIcons()); vitePlugins.push(createIcons());
vitePlugins.push(createSvgIconsPlugin(path, isBuild)); vitePlugins.push(createSvgIconsPlugin(path));
vitePlugins.push(createSetupExtend()); vitePlugins.push(createSetupExtend());
return vitePlugins; return vitePlugins;
}; };

View File

@ -1,10 +1,10 @@
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; import { createSvgIconsPlugin } from 'vite-plugin-svg-icons-ng';
export default (path: any, isBuild: boolean) => {
export default (path: any) => {
return createSvgIconsPlugin({ return createSvgIconsPlugin({
// 指定需要缓存的图标文件夹 // 指定需要缓存的图标文件夹
iconDirs: [path.resolve(path.resolve(__dirname, '../../src'), 'assets/icons/svg')], iconDirs: [path.resolve(path.resolve(__dirname, '../../src'), 'assets/icons/svg')],
// 指定symbolId格式 // 指定symbolId格式
symbolId: 'icon-[dir]-[name]', symbolId: 'icon-[dir]-[name]'
svgoOptions: isBuild
}); });
}; };