refactor(frontend): 清理无用依赖和配置,优化代码格式

移除未使用的依赖如vxe-table和lodash-es
删除冗余的lint和prettier配置文件
统一代码格式,简化模板语法
调整表格列宽和操作按钮布局
修复profile页面性别默认值问题
This commit is contained in:
zhangtao
2025-07-19 13:57:46 +08:00
parent df2c0a76c5
commit 5d888f287c
32 changed files with 1553 additions and 5365 deletions
+2 -7
View File
@@ -19,10 +19,5 @@ frontend/.idea
frontend/.DS_Store frontend/.DS_Store
frontend/node_modules frontend/node_modules
frontend/dist frontend/dist
frontend/dist
uni-app/__pycache__ frontend/.husky
uni-app/.vscode
uni-app/.idea
uni-app/.DS_Store
uni-app/node_modules
uni-app/dist
Binary file not shown.
-315
View File
@@ -1,315 +0,0 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"ElMessage": true,
"ElMessageBox": true,
"ElNotification": true,
"InjectionKey": true,
"PropType": true,
"Ref": true,
"VNode": true,
"asyncComputed": true,
"autoResetRef": true,
"computed": true,
"computedAsync": true,
"computedEager": true,
"computedInject": true,
"computedWithControl": true,
"controlledComputed": true,
"controlledRef": true,
"createApp": true,
"createEventHook": true,
"createGlobalState": true,
"createInjectionState": true,
"createReactiveFn": true,
"createReusableTemplate": true,
"createSharedComposable": true,
"createTemplatePromise": true,
"createUnrefFn": true,
"customRef": true,
"debouncedRef": true,
"debouncedWatch": true,
"defineAsyncComponent": true,
"defineComponent": true,
"eagerComputed": true,
"effectScope": true,
"extendRef": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"ignorableWatch": true,
"inject": true,
"isDefined": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"makeDestructurable": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onClickOutside": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onKeyStroke": true,
"onLongPress": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onStartTyping": true,
"onUnmounted": true,
"onUpdated": true,
"pausableWatch": true,
"provide": true,
"reactify": true,
"reactifyObject": true,
"reactive": true,
"reactiveComputed": true,
"reactiveOmit": true,
"reactivePick": true,
"readonly": true,
"ref": true,
"refAutoReset": true,
"refDebounced": true,
"refDefault": true,
"refThrottled": true,
"refWithControl": true,
"resolveComponent": true,
"resolveRef": true,
"resolveUnref": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"syncRef": true,
"syncRefs": true,
"templateRef": true,
"throttledRef": true,
"throttledWatch": true,
"toRaw": true,
"toReactive": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"tryOnBeforeMount": true,
"tryOnBeforeUnmount": true,
"tryOnMounted": true,
"tryOnScopeDispose": true,
"tryOnUnmounted": true,
"unref": true,
"unrefElement": true,
"until": true,
"useActiveElement": true,
"useAnimate": true,
"useArrayDifference": true,
"useArrayEvery": true,
"useArrayFilter": true,
"useArrayFind": true,
"useArrayFindIndex": true,
"useArrayFindLast": true,
"useArrayIncludes": true,
"useArrayJoin": true,
"useArrayMap": true,
"useArrayReduce": true,
"useArraySome": true,
"useArrayUnique": true,
"useAsyncQueue": true,
"useAsyncState": true,
"useAttrs": true,
"useBase64": true,
"useBattery": true,
"useBluetooth": true,
"useBreakpoints": true,
"useBroadcastChannel": true,
"useBrowserLocation": true,
"useCached": true,
"useClipboard": true,
"useCloned": true,
"useColorMode": true,
"useConfirmDialog": true,
"useCounter": true,
"useCssModule": true,
"useCssVar": true,
"useCssVars": true,
"useCurrentElement": true,
"useCycleList": true,
"useDark": true,
"useDateFormat": true,
"useDebounce": true,
"useDebounceFn": true,
"useDebouncedRefHistory": true,
"useDeviceMotion": true,
"useDeviceOrientation": true,
"useDevicePixelRatio": true,
"useDevicesList": true,
"useDisplayMedia": true,
"useDocumentVisibility": true,
"useDraggable": true,
"useDropZone": true,
"useElementBounding": true,
"useElementByPoint": true,
"useElementHover": true,
"useElementSize": true,
"useElementVisibility": true,
"useEventBus": true,
"useEventListener": true,
"useEventSource": true,
"useEyeDropper": true,
"useFavicon": true,
"useFetch": true,
"useFileDialog": true,
"useFileSystemAccess": true,
"useFocus": true,
"useFocusWithin": true,
"useFps": true,
"useFullscreen": true,
"useGamepad": true,
"useGeolocation": true,
"useIdle": true,
"useImage": true,
"useInfiniteScroll": true,
"useIntersectionObserver": true,
"useInterval": true,
"useIntervalFn": true,
"useKeyModifier": true,
"useLastChanged": true,
"useLocalStorage": true,
"useMagicKeys": true,
"useManualRefHistory": true,
"useMediaControls": true,
"useMediaQuery": true,
"useMemoize": true,
"useMemory": true,
"useMounted": true,
"useMouse": true,
"useMouseInElement": true,
"useMousePressed": true,
"useMutationObserver": true,
"useNavigatorLanguage": true,
"useNetwork": true,
"useNow": true,
"useObjectUrl": true,
"useOffsetPagination": true,
"useOnline": true,
"usePageLeave": true,
"useParallax": true,
"useParentElement": true,
"usePerformanceObserver": true,
"usePermission": true,
"usePointer": true,
"usePointerLock": true,
"usePointerSwipe": true,
"usePreferredColorScheme": true,
"usePreferredContrast": true,
"usePreferredDark": true,
"usePreferredLanguages": true,
"usePreferredReducedMotion": true,
"usePrevious": true,
"useRafFn": true,
"useRefHistory": true,
"useResizeObserver": true,
"useScreenOrientation": true,
"useScreenSafeArea": true,
"useScriptTag": true,
"useScroll": true,
"useScrollLock": true,
"useSessionStorage": true,
"useShare": true,
"useSlots": true,
"useSorted": true,
"useSpeechRecognition": true,
"useSpeechSynthesis": true,
"useStepper": true,
"useStorage": true,
"useStorageAsync": true,
"useStyleTag": true,
"useSupported": true,
"useSwipe": true,
"useTemplateRefsList": true,
"useTextDirection": true,
"useTextSelection": true,
"useTextareaAutosize": true,
"useThrottle": true,
"useThrottleFn": true,
"useThrottledRefHistory": true,
"useTimeAgo": true,
"useTimeout": true,
"useTimeoutFn": true,
"useTimeoutPoll": true,
"useTimestamp": true,
"useTitle": true,
"useToNumber": true,
"useToString": true,
"useToggle": true,
"useTransition": true,
"useUrlSearchParams": true,
"useUserMedia": true,
"useVModel": true,
"useVModels": true,
"useVibrate": true,
"useVirtualList": true,
"useWakeLock": true,
"useWebNotification": true,
"useWebWorker": true,
"useWebWorkerFn": true,
"useWindowFocus": true,
"useWindowScroll": true,
"useWindowSize": true,
"watch": true,
"watchArray": true,
"watchAtMost": true,
"watchDebounced": true,
"watchDeep": true,
"watchEffect": true,
"watchIgnorable": true,
"watchImmediate": true,
"watchOnce": true,
"watchPausable": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"watchThrottled": true,
"watchTriggerable": true,
"watchWithFilter": true,
"useRoute": true,
"useRouter": true,
"storeToRefs": true,
"whenever": true,
"DirectiveBinding": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"WritableComputedRef": true,
"acceptHMRUpdate": true,
"createPinia": true,
"defineStore": true,
"getActivePinia": true,
"injectLocal": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onWatcherCleanup": true,
"provideLocal": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"useClipboardItems": true,
"useI18n": true,
"useId": true,
"useLink": true,
"useModel": true,
"useTemplateRef": true
}
}
-12
View File
@@ -1,12 +0,0 @@
dist
node_modules
public
.husky
.vscode
.idea
*.sh
*.md
src/assets
stats.html
pnpm-lock.yaml
-41
View File
@@ -1,41 +0,0 @@
# 在单参数箭头函数中始终添加括号
arrowParens: "always"
# JSX 多行元素的闭合标签另起一行
bracketSameLine: false
# 对象字面量中的括号之间添加空格
bracketSpacing: true
# 自动格式化嵌入的代码(如 Markdown 和 HTML 内的代码)
embeddedLanguageFormatting: "auto"
# 忽略 HTML 空白敏感度,将空白视为非重要内容
htmlWhitespaceSensitivity: "ignore"
# 不插入 @prettier 的 pragma 注释
insertPragma: false
# 在 JSX 中使用双引号
jsxSingleQuote: false
# 每行代码的最大长度限制为 100 字符
printWidth: 100
# 在 Markdown 中保留原有的换行格式
proseWrap: "preserve"
# 仅在必要时添加对象属性的引号
quoteProps: "as-needed"
# 不要求文件开头插入 @prettier 的 pragma 注释
requirePragma: false
# 在语句末尾添加分号
semi: true
# 使用双引号而不是单引号
singleQuote: false
# 缩进使用 2 个空格
tabWidth: 2
# 在多行元素的末尾添加逗号(ES5 支持的对象、数组等)
trailingComma: "es5"
# 使用空格而不是制表符缩进
useTabs: false
# Vue 文件中的 <script> 和 <style> 不增加额外的缩进
vueIndentScriptAndStyle: false
# 根据系统自动检测换行符
endOfLine: "auto"
# 对 HTML 文件应用特定格式化规则
overrides:
- files: "*.html"
options:
parser: "html"
-38
View File
@@ -1,38 +0,0 @@
module.exports = {
extends: [
"stylelint-config-recommended",
"stylelint-config-recommended-scss",
"stylelint-config-recommended-vue/scss",
"stylelint-config-html/vue",
"stylelint-config-recess-order",
],
plugins: [
"stylelint-prettier", // 统一代码风格,格式冲突时以 Prettier 规则为准
],
overrides: [
{
files: ["**/*.{vue,html}"],
customSyntax: "postcss-html",
},
{
files: ["**/*.{css,scss}"],
customSyntax: "postcss-scss",
},
],
rules: {
"prettier/prettier": true, // 强制执行 Prettier 格式化规则(需配合 .prettierrc 配置文件)
"no-empty-source": null, // 允许空的样式文件
"declaration-property-value-no-unknown": null, // 允许非常规数值格式 ,如 height: calc(100% - 50)
// 允许使用未知伪类
"selector-pseudo-class-no-unknown": [
true,
{
ignorePseudoClasses: ["global", "export", "deep"],
},
],
// 允许使用未知伪元素
"at-rule-no-unknown": null, // 禁用默认的未知 at-rule 检查
"scss/at-rule-no-unknown": true, // 启用 SCSS 特定的 at-rule 检查
},
};
-93
View File
@@ -1,93 +0,0 @@
module.exports = {
// 继承的规则
extends: ["@commitlint/config-conventional"],
// 自定义规则
rules: {
// @see https://commitlint.js.org/#/reference-rules
// 提交类型枚举,git提交type必须是以下类型
"type-enum": [
2,
"always",
[
"feat", // 新增功能
"fix", // 修复缺陷
"docs", // 文档变更
"style", // 代码格式(不影响功能,例如空格、分号等格式修正)
"refactor", // 代码重构(不包括 bug 修复、功能新增)
"perf", // 性能优化
"test", // 添加疏漏测试或已有测试改动
"build", // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
"ci", // 修改 CI 配置、脚本
"revert", // 回滚 commit
"chore", // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
"wip", // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
],
],
"subject-case": [0], // subject大小写不做校验
},
prompt: {
messages: {
type: "选择你要提交的类型 :",
scope: "选择一个提交范围(可选):",
customScope: "请输入自定义的提交范围 :",
subject: "填写简短精炼的变更描述 :\n",
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
footerPrefixesSelect: "选择关联issue前缀(可选):",
customFooterPrefix: "输入自定义issue前缀 :",
footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
generatingByAI: "正在通过 AI 生成你的提交简短描述...",
generatedSelectByAI: "选择一个 AI 生成的简短描述:",
confirmCommit: "是否提交或修改commit ?",
},
// prettier-ignore
types: [
{ value: "feat", name: "特性: ✨ 新增功能", emoji: ":sparkles:" },
{ value: "fix", name: "修复: 🐛 修复缺陷", emoji: ":bug:" },
{ value: "docs", name: "文档: 📝 文档变更(更新README文件,或者注释)", emoji: ":memo:" },
{ value: "style", name: "格式: 🌈 代码格式(空格、格式化、缺失的分号等)", emoji: ":lipstick:" },
{ value: "refactor", name: "重构: 🔄 代码重构(不修复错误也不添加特性的代码更改)", emoji: ":recycle:" },
{ value: "perf", name: "性能: 🚀 性能优化", emoji: ":zap:" },
{ value: "test", name: "测试: 🧪 添加疏漏测试或已有测试改动", emoji: ":white_check_mark:"},
{ value: "build", name: "构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)", emoji: ":package:"},
{ value: "ci", name: "集成: ⚙️ 修改 CI 配置、脚本", emoji: ":ferris_wheel:"},
{ value: "revert", name: "回退: ↩️ 回滚 commit",emoji: ":rewind:"},
{ value: "chore", name: "其他: 🛠️ 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)", emoji: ":hammer:"},
{ value: "wip", name: "开发中: 🚧 开发阶段临时提交", emoji: ":construction:"},
],
useEmoji: true,
emojiAlign: "center",
useAI: false,
aiNumber: 1,
themeColorCode: "",
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: "bottom",
customScopesAlias: "custom",
emptyScopesAlias: "empty",
upperCaseSubject: false,
markBreakingChangeMode: false,
allowBreakingChanges: ["feat", "fix"],
breaklineNumber: 100,
breaklineChar: "|",
skipQuestions: [],
issuePrefixes: [{ value: "closed", name: "closed: ISSUES has been processed" }],
customIssuePrefixAlign: "top",
emptyIssuePrefixAlias: "skip",
customIssuePrefixAlias: "custom",
allowCustomIssuePrefix: true,
allowEmptyIssuePrefix: true,
confirmColorize: true,
maxHeaderLength: Infinity,
maxSubjectLength: Infinity,
minSubjectLength: 0,
scopeOverrides: undefined,
defaultBody: "",
defaultIssues: "",
defaultScope: "",
defaultSubject: "",
},
};
-216
View File
@@ -1,216 +0,0 @@
// https://eslint.org/docs/latest/use/configure/configuration-files-new
import eslint from "@eslint/js";
import pluginVue from "eslint-plugin-vue";
import * as typescriptEslint from "typescript-eslint";
import vueParser from "vue-eslint-parser";
import globals from "globals";
import configPrettier from "eslint-config-prettier";
// 解析自动导入配置
import fs from "node:fs";
let autoImportGlobals = {};
try {
autoImportGlobals =
JSON.parse(fs.readFileSync("./.eslintrc-auto-import.json", "utf-8")).globals || {};
} catch (error) {
// 文件不存在或解析错误时使用空对象
console.warn("Could not load auto-import globals", error);
}
// Element Plus组件
const elementPlusComponents = {
// Element Plus 组件添加为全局变量,避免 no-undef 报错
ElInput: "readonly",
ElSelect: "readonly",
ElSwitch: "readonly",
ElCascader: "readonly",
ElInputNumber: "readonly",
ElTimePicker: "readonly",
ElTimeSelect: "readonly",
ElDatePicker: "readonly",
ElTreeSelect: "readonly",
ElText: "readonly",
ElRadioGroup: "readonly",
ElCheckboxGroup: "readonly",
ElOption: "readonly",
ElRadio: "readonly",
ElCheckbox: "readonly",
ElInputTag: "readonly",
ElForm: "readonly",
ElFormItem: "readonly",
ElTable: "readonly",
ElTableColumn: "readonly",
ElButton: "readonly",
ElDialog: "readonly",
ElPagination: "readonly",
ElMessage: "readonly",
ElMessageBox: "readonly",
ElNotification: "readonly",
ElTree: "readonly",
};
export default [
// 忽略文件配置
{
ignores: [
"**/node_modules/**",
"**/dist/**",
"**/*.min.*",
"**/auto-imports.d.ts",
"**/components.d.ts",
],
},
// 基础 JavaScript 配置
eslint.configs.recommended,
// Vue 推荐配置
...pluginVue.configs["flat/recommended"],
// TypeScript 推荐配置
...typescriptEslint.configs.recommended,
// 全局配置
{
// 指定要检查的文件
files: ["**/*.{js,mjs,cjs,ts,mts,cts,vue}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
...globals.browser, // 浏览器环境全局变量
...globals.node, // Node.js 环境全局变量
...globals.es2022, // ES2022 全局对象
...autoImportGlobals, // 自动导入的 API 函数
...elementPlusComponents, // Element Plus 组件
// 全局类型定义,解决 TypeScript 中定义但 ESLint 不识别的问题
PageQuery: "readonly",
PageResult: "readonly",
OptionType: "readonly",
ApiResponse: "readonly",
ExcelResult: "readonly",
TagView: "readonly",
AppSettings: "readonly",
__APP_INFO__: "readonly",
},
},
plugins: {
vue: pluginVue,
"@typescript-eslint": typescriptEslint.plugin,
},
rules: {
// 基础规则
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
// ES6+ 规则
"prefer-const": "error",
"no-var": "error",
"object-shorthand": "error",
// 最佳实践
eqeqeq: "off",
"no-multi-spaces": "error",
"no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }],
// 禁用与 TypeScript 冲突的规则
"no-unused-vars": "off",
"no-undef": "off",
"no-redeclare": "off",
"@typescript-eslint/ban-ts-comment": "off",
},
},
// Vue 文件特定配置
{
files: ["**/*.vue"],
languageOptions: {
parser: vueParser,
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
parser: typescriptEslint.parser,
extraFileExtensions: [".vue"],
},
},
rules: {
// Vue 规则
"vue/multi-word-component-names": "off",
"vue/no-v-html": "off",
"vue/require-default-prop": "off",
"vue/require-explicit-emits": "error",
"vue/no-unused-vars": "error",
"vue/no-mutating-props": "off",
"vue/valid-v-for": "warn",
"vue/no-template-shadow": "warn",
"vue/return-in-computed-property": "warn",
"vue/block-order": [
"error",
{
order: ["template", "script", "style"],
},
],
"vue/html-self-closing": [
"error",
{
html: {
void: "always",
normal: "never",
component: "always",
},
svg: "always",
math: "always",
},
],
"vue/component-name-in-template-casing": ["error", "PascalCase"],
"@typescript-eslint/no-explicit-any": "off",
},
},
// TypeScript 文件特定配置
{
files: ["**/*.{ts,tsx,mts,cts}"],
languageOptions: {
parser: typescriptEslint.parser,
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// TypeScript 规则
"@typescript-eslint/no-explicit-any": "off", // 允许使用any类型,方便开发
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": "warn", // 降级为警告
"@typescript-eslint/no-unused-expressions": "warn", // 降级为警告
"@typescript-eslint/consistent-type-imports": "off", // 关闭强制使用type import
"@typescript-eslint/no-import-type-side-effects": "error",
},
},
// .d.ts 文件配置
{
files: ["**/*.d.ts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
},
},
// CURD 组件配置
{
files: ["**/components/CURD/**/*.{ts,vue}"],
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
},
},
// Prettier 集成(必须放在最后)
configPrettier,
];
+1019 -3749
View File
File diff suppressed because it is too large Load Diff
+6 -54
View File
@@ -1,51 +1,14 @@
{ {
"name": "vue3-element-admin", "name": "fastapi-vue3-admin",
"description": "Vue3 + Vite + TypeScript + Element-Plus 的后台管理模板,vue-element-admin 的 Vue3 版本", "description": "Vue3 + Vite + TypeScript + Element-Plus 的后台管理模板",
"version": "3.0.0", "version": "2.0.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"i": "pnpm install",
"dev": "vite", "dev": "vite",
"prod": "vite --mode prod", "prod": "vite --mode prod",
"build": "vue-tsc --noEmit & vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview"
"build-only": "vite build",
"type-check": "vue-tsc --noEmit",
"lint:eslint": "eslint --cache \"src/**/*.{vue,ts,js}\" --fix",
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,css,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache \"**/*.{css,scss,vue}\" --fix",
"lint:lint-staged": "lint-staged",
"lint": "npm run lint:eslint && npm run lint:prettier && npm run lint:stylelint",
"preinstall": "npx only-allow pnpm",
"prepare": "husky",
"commit": "git-cz"
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
"lint-staged": {
"*.{js,ts}": [
"eslint --fix",
"prettier --write"
],
"*.{cjs,json}": [
"prettier --write"
],
"*.{vue,html}": [
"eslint --fix",
"prettier --write",
"stylelint --fix"
],
"*.{scss,css}": [
"stylelint --fix",
"prettier --write"
],
"*.md": [
"prettier --write"
]
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",
@@ -61,7 +24,7 @@
"echarts": "^5.6.0", "echarts": "^5.6.0",
"element-plus": "^2.10.2", "element-plus": "^2.10.2",
"exceljs": "^4.4.0", "exceljs": "^4.4.0",
"lodash-es": "^4.17.21", "glob": "^11.0.3",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"path-to-regexp": "^8.2.0", "path-to-regexp": "^8.2.0",
@@ -73,7 +36,6 @@
"vue-draggable-plus": "^0.6.0", "vue-draggable-plus": "^0.6.0",
"vue-i18n": "^11.1.7", "vue-i18n": "^11.1.7",
"vue-router": "^4.5.1", "vue-router": "^4.5.1",
"vxe-table": "~4.6.25",
"vue3-cron-plus-picker": "^1.0.2" "vue3-cron-plus-picker": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
@@ -82,7 +44,6 @@
"@eslint/js": "^9.30.0", "@eslint/js": "^9.30.0",
"@iconify/utils": "^2.3.0", "@iconify/utils": "^2.3.0",
"@types/codemirror": "^5.60.16", "@types/codemirror": "^5.60.16",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.15.34", "@types/node": "^22.15.34",
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@types/path-browserify": "^1.0.3", "@types/path-browserify": "^1.0.3",
@@ -93,13 +54,11 @@
"@vitejs/plugin-vue": "^5.2.4", "@vitejs/plugin-vue": "^5.2.4",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"commitizen": "^4.3.1", "commitizen": "^4.3.1",
"cz-git": "^1.11.2",
"eslint": "^9.30.0", "eslint": "^9.30.0",
"eslint-config-prettier": "^10.1.5", "eslint-config-prettier": "^10.1.5",
"eslint-plugin-prettier": "^5.5.1", "eslint-plugin-prettier": "^5.5.1",
"eslint-plugin-vue": "^10.2.0", "eslint-plugin-vue": "^10.2.0",
"globals": "^15.15.0", "globals": "^15.15.0",
"husky": "^9.1.7",
"lint-staged": "^15.5.2", "lint-staged": "^15.5.2",
"postcss": "^8.5.4", "postcss": "^8.5.4",
"postcss-html": "^1.8.0", "postcss-html": "^1.8.0",
@@ -107,12 +66,6 @@
"prettier": "^3.6.2", "prettier": "^3.6.2",
"sass": "^1.89.2", "sass": "^1.89.2",
"stylelint": "^16.21.0", "stylelint": "^16.21.0",
"stylelint-config-html": "^1.1.0",
"stylelint-config-recess-order": "^6.1.0",
"stylelint-config-recommended": "^15.0.0",
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-config-recommended-vue": "^1.6.1",
"stylelint-prettier": "^5.0.3",
"terser": "^5.43.0", "terser": "^5.43.0",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.35.0", "typescript-eslint": "^8.35.0",
@@ -120,7 +73,6 @@
"unplugin-auto-import": "^19.3.0", "unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.8.0", "unplugin-vue-components": "^28.8.0",
"vite": "^6.3.5", "vite": "^6.3.5",
"vite-plugin-mock-dev-server": "^1.9.1",
"vue-eslint-parser": "^10.1.4", "vue-eslint-parser": "^10.1.4",
"vue-tsc": "^2.2.10" "vue-tsc": "^2.2.10"
}, },
+48 -49
View File
@@ -1,54 +1,54 @@
<template> <template>
<div> <div>
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="4"> <el-col :span="4">
<el-form-item label="秒"> <el-form-item label="秒">
<el-select v-model:value="crontabValueObj.second" placeholder="秒"> <el-select v-model:value="crontabValueObj.second" placeholder="秒">
<el-option v-for="second in seconds" :key="second" :value="second">{{ second }}</el-option> <el-option v-for="second in seconds" :key="second" :value="second">{{ second }}</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-form-item label="分"> <el-form-item label="分">
<el-select v-model:value="crontabValueObj.min" placeholder="分"> <el-select v-model:value="crontabValueObj.min" placeholder="分">
<el-option v-for="min in minutes" :key="min" :value="min">{{ min }}</el-option> <el-option v-for="min in minutes" :key="min" :value="min">{{min}}</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-form-item label="时"> <el-form-item label="时">
<el-select v-model:value="crontabValueObj.hour" placeholder="时"> <el-select v-model:value="crontabValueObj.hour" placeholder="时">
<el-option v-for="hour in hours" :key="hour" :value="hour">{{ hour }}</el-option> <el-option v-for="hour in hours" :key="hour" :value="hour">{{hour}}</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-form-item label="天"> <el-form-item label="天">
<el-select v-model:value="crontabValueObj.day" placeholder="天"> <el-select v-model:value="crontabValueObj.day" placeholder="天">
<el-option v-for="day in days" :key="day" :value="day">{{ day }}</el-option> <el-option v-for="day in days" :key="day" :value="day">{{day}}</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="4"> <el-col :span="4">
<el-form-item label="周"> <el-form-item label="周">
<el-select v-model:value="crontabValueObj.week" placeholder="周"> <el-select v-model:value="crontabValueObj.week" placeholder="周">
<el-option v-for="week in weeks" :key="week" :value="week">{{ week }}</el-option> <el-option v-for="week in weeks" :key="week" :value="week">{{week}}</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from "vue";
const crontabValueObj = ref({ const crontabValueObj = ref({
second: "*", second: "*",
min: "*", min: "*",
hour: "*", hour: "*",
day: "*", day: "*",
week: "*", week: "*",
}); });
const seconds = ref(Array.from({ length: 60 }, (_, i) => i.toString())); const seconds = ref(Array.from({ length: 60 }, (_, i) => i.toString()));
@@ -58,13 +58,12 @@ const days = ref(Array.from({ length: 31 }, (_, i) => (i + 1).toString()));
const weeks = ref(["*", "1", "2", "3", "4", "5", "6", "7"]); const weeks = ref(["*", "1", "2", "3", "4", "5", "6", "7"]);
const handleConfirm = () => { const handleConfirm = () => {
const obj = crontabValueObj.value; const obj = crontabValueObj.value;
return `${obj.second} ${obj.min} ${obj.hour} ${obj.day} ${obj.week}` return `${obj.second} ${obj.min} ${obj.hour} ${obj.day} ${obj.week}`;
}; };
// 暴露方法和属性给父组件 // 暴露方法和属性给父组件
defineExpose({ handleConfirm, crontabValueObj }) defineExpose({ handleConfirm, crontabValueObj });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -50,8 +50,7 @@
</template> </template>
</el-dropdown> </el-dropdown>
<el-dialog v-model="noticeDialogVisible" :title="noticeDetail?.notice_title ?? '通知详情'" width="800px" <el-dialog v-model="noticeDialogVisible" :title="noticeDetail?.notice_title ?? '通知详情'" width="800px" custom-class="notification-detail">
custom-class="notification-detail">
<div v-if="noticeDetail" class="p-x-20px"> <div v-if="noticeDetail" class="p-x-20px">
<div class="flex-y-center mb-16px text-13px text-color-secondary"> <div class="flex-y-center mb-16px text-13px text-color-secondary">
<span class="flex-y-center"> <span class="flex-y-center">
@@ -4,7 +4,6 @@
<router-link :key="+collapse" class="wh-full flex-center" to="/"> <router-link :key="+collapse" class="wh-full flex-center" to="/">
<img :src="configStore.configData.sys_web_logo.config_value" class="w20px h20px" /> <img :src="configStore.configData.sys_web_logo.config_value" class="w20px h20px" />
<span v-if="!collapse" class="title"> <span v-if="!collapse" class="title">
<!-- {{ defaultSettings.title }} -->
{{ configStore.configData.sys_web_title.config_value }} {{ configStore.configData.sys_web_title.config_value }}
</span> </span>
</router-link> </router-link>
@@ -13,9 +12,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defaultSettings } from "@/settings";
import { useConfigStore } from "@/store"; import { useConfigStore } from "@/store";
// import logo from "@/assets/logo.png";
const configStore = useConfigStore(); const configStore = useConfigStore();
defineProps({ defineProps({
@@ -1,4 +1,4 @@
import { computed, watch } from "vue"; import { computed } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useAppStore, usePermissionStore } from "@/store"; import { useAppStore, usePermissionStore } from "@/store";
-1
View File
@@ -5,7 +5,6 @@ import setupPlugins from "@/plugins";
// 暗黑主题样式 // 暗黑主题样式
import "element-plus/theme-chalk/dark/css-vars.css"; import "element-plus/theme-chalk/dark/css-vars.css";
import "element-plus/dist/index.css"; import "element-plus/dist/index.css";
import "vxe-table/lib/style.css";
// 暗黑模式自定义变量 // 暗黑模式自定义变量
import "@/styles/dark/css-vars.css"; import "@/styles/dark/css-vars.css";
import "@/styles/index.scss"; import "@/styles/index.scss";
-6
View File
@@ -1,6 +0,0 @@
// https://github.com/sockjs/sockjs-client/issues/565
declare module "sockjs-client/dist/sockjs.min.js" {
import Client from "sockjs-client";
export default Client;
}
+5 -7
View File
@@ -19,8 +19,7 @@
</el-avatar> </el-avatar>
<el-button type="info" class="avatar-edit-btn" circle icon="Camera" size="small" @click="handleUpload" /> <el-button type="info" class="avatar-edit-btn" circle icon="Camera" size="small" @click="handleUpload" />
<div class="avatar-upload-overlay"> <div class="avatar-upload-overlay">
<el-upload v-model:file-list="fileList" name="avatar" list-type="picture-card" :show-upload-list="false" <el-upload v-model:file-list="fileList" name="avatar" list-type="picture-card" :show-upload-list="false" :before-upload="beforeUpload" :custom-request="handleUploadCustomRequest">
:before-upload="beforeUpload" :custom-request="handleUploadCustomRequest">
<div> <div>
<!-- <loading-outlined v-if="loading"></loading-outlined> <!-- <loading-outlined v-if="loading"></loading-outlined>
<plus-outlined v-else></plus-outlined> --> <plus-outlined v-else></plus-outlined> -->
@@ -31,8 +30,7 @@
</div> </div>
<span class="user-name"> <span class="user-name">
{{ infoFormState.name }} {{ infoFormState.name }}
<el-button type="primary" link :loading="infoSubmitting" icon="edit" <el-button type="primary" link :loading="infoSubmitting" icon="edit" @click="handleOpenDialog(DialogType.ACCOUNT)" />
@click="handleOpenDialog(DialogType.ACCOUNT)" />
</span> </span>
<el-text>{{infoFormState.roles.map(item => item.name).join('、')}}</el-text> <el-text>{{infoFormState.roles.map(item => item.name).join('、')}}</el-text>
@@ -141,7 +139,7 @@
<el-form-item label="性别" name="gender"> <el-form-item label="性别" name="gender">
<el-radio-group v-model:value="infoFormState.gender"> <el-radio-group v-model:value="infoFormState.gender">
<el-radio v-for="item in DictDataStore['sys_user_sex']" :value="item.dict_value"> <el-radio v-for="item in DictDataStore['sys_user_sex']" :key="item.dict_value" :value="item.dict_value" >
{{ item.dict_label }} {{ item.dict_label }}
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
@@ -229,7 +227,7 @@ const infoSubmitting = ref(false);
// 用户基础信息表单 // 用户基础信息表单
const infoFormState = reactive<InfoFormState>({ const infoFormState = reactive<InfoFormState>({
name: '', name: '',
gender: null, gender: 1,
mobile: '', mobile: '',
email: '', email: '',
username: '', username: '',
@@ -326,7 +324,7 @@ const resetPasswordRules = {
}, },
{ {
validator: (_: any, value: string) => { validator: (_: any, value: string) => {
return value === model.value.new_password; return value === passwordFormState.newPassword;
}, },
trigger: "blur", trigger: "blur",
message: t("login.message.password.inconformity"), message: t("login.message.password.inconformity"),
+3 -6
View File
@@ -287,8 +287,7 @@
<template #header> <template #header>
<div class="flex-x-between"> <div class="flex-x-between">
<span class="header-title">最新动态</span> <span class="header-title">最新动态</span>
<el-link type="primary" underline="never" href="https://gitee.com/youlaiorg/vue3-element-admin/releases" <el-link type="primary" underline="never" href="https://gitee.com/youlaiorg/vue3-element-admin/releases" target="_blank">
target="_blank">
完整记录 完整记录
<el-icon class="link-icon"> <el-icon class="link-icon">
<TopRight /> <TopRight />
@@ -299,8 +298,7 @@
<el-scrollbar height="400px"> <el-scrollbar height="400px">
<el-timeline class="p-3"> <el-timeline class="p-3">
<el-timeline-item v-for="(item, index) in vesionList" :key="index" :timestamp="item.date" placement="top" <el-timeline-item v-for="(item, index) in vesionList" :key="index" :timestamp="item.date" placement="top" :color="index === 0 ? '#67C23A' : '#909399'" :hollow="index !== 0" size="large">
:color="index === 0 ? '#67C23A' : '#909399'" :hollow="index !== 0" size="large">
<div class="version-item" :class="{ 'latest-item': index === 0 }"> <div class="version-item" :class="{ 'latest-item': index === 0 }">
<div> <div>
<el-text tag="strong">{{ item.title }}</el-text> <el-text tag="strong">{{ item.title }}</el-text>
@@ -312,8 +310,7 @@
<el-text class="version-content">{{ item.content }}</el-text> <el-text class="version-content">{{ item.content }}</el-text>
<div v-if="item.link"> <div v-if="item.link">
<el-link :type="index === 0 ? 'primary' : 'info'" :href="item.link" target="_blank" <el-link :type="index === 0 ? 'primary' : 'info'" :href="item.link" target="_blank" underline="never">
underline="never">
详情 详情
<el-icon class="link-icon"> <el-icon class="link-icon">
<TopRight /> <TopRight />
+72 -73
View File
@@ -9,10 +9,14 @@
<el-card shadow="hover"> <el-card shadow="hover">
<template #header> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<el-icon><Monitor /></el-icon> <el-icon>
<Monitor />
</el-icon>
<span>Redis监控信息</span> <span>Redis监控信息</span>
<el-tooltip content="展示Redis监控信息详情"> <el-tooltip content="展示Redis监控信息详情">
<el-icon><QuestionFilled /></el-icon> <el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
</template> </template>
@@ -36,7 +40,8 @@
{{ cache.info?.used_memory_human || '-' }} {{ cache.info?.used_memory_human || '-' }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="使用CPU"> <el-descriptions-item label="使用CPU">
{{ cache.info?.used_cpu_user_children ? parseFloat(cache.info.used_cpu_user_children).toFixed(2) : '-' }} {{ cache.info?.used_cpu_user_children ? parseFloat(cache.info.used_cpu_user_children).toFixed(2) : '-'
}}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="内存配置"> <el-descriptions-item label="内存配置">
{{ cache.info?.maxmemory_human || '-' }} {{ cache.info?.maxmemory_human || '-' }}
@@ -51,7 +56,8 @@
{{ cache.db_size || 0 }} {{ cache.db_size || 0 }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="网络入口/出口"> <el-descriptions-item label="网络入口/出口">
{{ `${cache.info?.instantaneous_input_kbps || 0}kps/${cache.info?.instantaneous_output_kbps || 0}kps` }} {{ `${cache.info?.instantaneous_input_kbps || 0}kps/${cache.info?.instantaneous_output_kbps || 0}kps`
}}
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
</el-card> </el-card>
@@ -62,10 +68,14 @@
<el-card shadow="hover"> <el-card shadow="hover">
<template #header> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<el-icon><Stopwatch /></el-icon> <el-icon>
<Stopwatch />
</el-icon>
<span class="title">命令统计</span> <span class="title">命令统计</span>
<el-tooltip content="展示命令统计详情"> <el-tooltip content="展示命令统计详情">
<el-icon><QuestionFilled /></el-icon> <el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
</template> </template>
@@ -77,10 +87,14 @@
<el-card shadow="hover"> <el-card shadow="hover">
<template #header> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<el-icon><Stopwatch /></el-icon> <el-icon>
<Stopwatch />
</el-icon>
<span>内存信息</span> <span>内存信息</span>
<el-tooltip content="展示内存信息详情"> <el-tooltip content="展示内存信息详情">
<el-icon><QuestionFilled /></el-icon> <el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
</template> </template>
@@ -95,14 +109,18 @@
<el-row :gutter="16"> <el-row :gutter="16">
<!-- 缓存列表 --> <!-- 缓存列表 -->
<el-col :span="8"> <el-col :span="8">
<el-card :loading="loading" shadow="hover" > <el-card :loading="loading" shadow="hover">
<template #header> <template #header>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<el-icon><Tickets /></el-icon> <el-icon>
<Tickets />
</el-icon>
<span class="flex items-center gap-2">缓存列表</span> <span class="flex items-center gap-2">缓存列表</span>
<el-tooltip content="展示缓存列表详情"> <el-tooltip content="展示缓存列表详情">
<el-icon><QuestionFilled /></el-icon> <el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
<div> <div>
@@ -110,16 +128,10 @@
</div> </div>
</div> </div>
</template> </template>
<el-table <el-table :loading="loading" :data="cacheNames" row-key="cache_name" height="600" border>
:loading="loading" <template #empty>
:data="cacheNames" <el-empty :image-size="80" description="暂无数据" />
row-key="cache_name" </template>
height="600"
border
>
<template #empty>
<el-empty :image-size="80" description="暂无数据" />
</template>
<el-table-column prop="cache_name" label="缓存名称" show-overflow-tooltip> <el-table-column prop="cache_name" label="缓存名称" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="getCacheKeyList(row)">{{ row.cache_name }}</el-button> <el-button type="primary" link @click="getCacheKeyList(row)">{{ row.cache_name }}</el-button>
@@ -128,12 +140,7 @@
<el-table-column prop="remark" label="备注" show-overflow-tooltip /> <el-table-column prop="remark" label="备注" show-overflow-tooltip />
<el-table-column label="操作" width="60" align="center"> <el-table-column label="操作" width="60" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-popconfirm <el-popconfirm class="box-item" :title="`确认删除缓存 ${row.cache_name} 吗?`" placement="top" @confirm="handleClearCacheName(row)">
class="box-item"
:title="`确认删除缓存 ${row.cache_name} 吗?`"
placement="top"
@confirm="handleClearCacheName(row)"
>
<template #reference> <template #reference>
<el-button type="danger" size="small" link icon="delete" /> <el-button type="danger" size="small" link icon="delete" />
</template> </template>
@@ -146,14 +153,18 @@
<!-- 键名列表 --> <!-- 键名列表 -->
<el-col :span="8"> <el-col :span="8">
<el-card :loading="loading" shadow="hover"> <el-card :loading="loading" shadow="hover">
<template #header> <template #header>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<el-icon><Key /></el-icon> <el-icon>
<Key />
</el-icon>
<span class="flex items-center gap-2">键名列表</span> <span class="flex items-center gap-2">键名列表</span>
<el-tooltip content="展示键名列表详情"> <el-tooltip content="展示键名列表详情">
<el-icon><QuestionFilled /></el-icon> <el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
<div> <div>
@@ -161,29 +172,19 @@
</div> </div>
</div> </div>
</template> </template>
<el-table <el-table :loading="subLoading" :data="cacheKeys.map(key => ({ cacheKey: key }))" height="600" row-key="cacheKey" border>
:loading="subLoading"
:data="cacheKeys.map(key => ({ cacheKey: key }))"
height="600"
row-key="cacheKey"
border
>
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column prop="cacheKey" label="缓存键名" show-overflow-tooltip> <el-table-column prop="cacheKey" label="缓存键名" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="handleCacheValue(row.cacheKey)">{{ row.cacheKey }}</el-button> <el-button type="primary" link @click="handleCacheValue(row.cacheKey)">{{ row.cacheKey
}}</el-button>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="60" align="center"> <el-table-column label="操作" width="60" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-popconfirm <el-popconfirm class="box-item" :title="`确认删除键 ${row.cacheKey} 吗?`" placement="top" @confirm="handleClearCacheKey(row.cacheKey)">
class="box-item"
:title="`确认删除键 ${row.cacheKey} 吗?`"
placement="top"
@confirm="handleClearCacheKey(row.cacheKey)"
>
<template #reference> <template #reference>
<el-button type="danger" size="small" link icon="delete" /> <el-button type="danger" size="small" link icon="delete" />
</template> </template>
@@ -196,14 +197,18 @@
<!-- 缓存内容 --> <!-- 缓存内容 -->
<el-col :span="8"> <el-col :span="8">
<el-card :loading="loading" shadow="hover"> <el-card :loading="loading" shadow="hover">
<template #header> <template #header>
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<el-icon><Key /></el-icon> <el-icon>
<Key />
</el-icon>
<span class="flex items-center gap-2">缓存内容</span> <span class="flex items-center gap-2">缓存内容</span>
<el-tooltip content="展示缓存内容详情"> <el-tooltip content="展示缓存内容详情">
<el-icon><QuestionFilled /></el-icon> <el-icon>
<QuestionFilled />
</el-icon>
</el-tooltip> </el-tooltip>
</div> </div>
<div> <div>
@@ -219,12 +224,7 @@
<el-input v-model="cacheForm.cache_key" readonly /> <el-input v-model="cacheForm.cache_key" readonly />
</el-form-item> </el-form-item>
<el-form-item label="缓存内容:"> <el-form-item label="缓存内容:">
<el-input <el-input v-model="cacheForm.cache_value" type="textarea" :rows="18" readonly />
v-model="cacheForm.cache_value"
type="textarea"
:rows="18"
readonly
/>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@@ -236,7 +236,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import CacheAPI, {type CacheInfo, type CacheForm, type CacheMonitor, type RedisInfo } from "@/api/monitor/cache"; import CacheAPI, { type CacheInfo, type CacheForm, type CacheMonitor, type RedisInfo } from "@/api/monitor/cache";
import * as echarts from 'echarts'; import * as echarts from 'echarts';
// 响应式状态定义 // 响应式状态定义
@@ -327,7 +327,7 @@ const refreshCacheKeys = () => {
}; };
// 清理缓存键名 // 清理缓存键名
async function handleClearCacheKey (cacheKey: string) { async function handleClearCacheKey(cacheKey: string) {
try { try {
await CacheAPI.deleteCacheKey(cacheKey); await CacheAPI.deleteCacheKey(cacheKey);
getCacheKeyList(); getCacheKeyList();
@@ -337,7 +337,7 @@ async function handleClearCacheKey (cacheKey: string) {
}; };
// 缓存内容相关方法 // 缓存内容相关方法
async function handleCacheValue (cacheKey: string) { async function handleCacheValue(cacheKey: string) {
try { try {
loading.value = true; loading.value = true;
const response = await CacheAPI.getCacheValue(nowCacheName.value, cacheKey) const response = await CacheAPI.getCacheValue(nowCacheName.value, cacheKey)
@@ -360,17 +360,17 @@ const handleClearCacheAll = async () => {
type: 'warning', type: 'warning',
} }
) )
.then(async () => { .then(async () => {
return await CacheAPI.deleteCacheAll(); return await CacheAPI.deleteCacheAll();
}) })
.then(() => { .then(() => {
getCacheNameList(); getCacheNameList();
}) })
.catch((error) => { .catch((error) => {
if (error !== 'cancel') { if (error !== 'cancel') {
console.error('清理全部缓存失败:', error); console.error('清理全部缓存失败:', error);
} }
}); });
}; };
// 监控数据获取 // 监控数据获取
@@ -379,11 +379,11 @@ const getInfo = async () => {
loading.value = true; loading.value = true;
const response = await CacheAPI.getCacheInfo() const response = await CacheAPI.getCacheInfo()
cache.value = response.data.data || { cache.value = response.data.data || {
info: {}, info: {},
command_stats: [], command_stats: [],
dbSize: 0 dbSize: 0
}; };
initCharts(); initCharts();
} catch (error) { } catch (error) {
console.error('获取缓存监控数据失败:', error); console.error('获取缓存监控数据失败:', error);
} finally { } finally {
@@ -452,7 +452,6 @@ onUnmounted(() => {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.chart-container { .chart-container {
height: 365px; height: 365px;
} }
+129 -175
View File
@@ -57,8 +57,7 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
</div> </div>
<div class="data-table__toolbar--tools"> <div class="data-table__toolbar--tools">
<el-tooltip content="导出"> <el-tooltip content="导出">
@@ -70,67 +69,41 @@
<el-tooltip content="刷新"> <el-tooltip content="刷新">
<el-button type="primary" icon="refresh" circle @click="handleRefresh" /> <el-button type="primary" icon="refresh" circle @click="handleRefresh" />
</el-tooltip> </el-tooltip>
<el-tooltip content="列表筛选">
<el-dropdown trigger="click">
<el-button type="default" icon="operation" circle />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="column in tableColumns" :key="column.prop"
:command="column">
<el-checkbox v-model="column.show">{{ column.label }}</el-checkbox>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-tooltip>
</div> </div>
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" class="data-table__content"
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange"> highlight-current-row height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" <el-table-column type="selection" align="center" min-width="55" />
min-width="55" align="center" /> <el-table-column type="index" label="序号" fixed min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed <el-table-column label="任务名称" prop="name" min-width="140" />
label="序号" min-width="60" /> <el-table-column label="执行函数" prop="func" min-width="140" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="任务名称" <el-table-column label="触发器" prop="trigger" min-width="100" />
prop="name" min-width="140" /> <el-table-column label="存储器" prop="jobstore" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'func')?.show" key="func" label="执行函数" <el-table-column label="执行器" prop="executor" min-width="100" />
prop="func" min-width="140" /> <el-table-column label="并发执行" prop="coalesce" min-width="100">
<el-table-column v-if="tableColumns.find(col => col.prop === 'trigger')?.show" key="trigger" label="触发器"
prop="trigger" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'jobstore')?.show" key="jobstore"
label="存储器" prop="jobstore" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'executor')?.show" key="executor"
label="执行器" prop="executor" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'coalesce')?.show" key="coalesce"
label="并发执行" prop="coalesce" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.coalesce === true ? 'success' : 'danger'"> <el-tag :type="scope.row.coalesce === true ? 'success' : 'danger'">
{{ scope.row.coalesce === true ? "是" : "否" }} {{ scope.row.coalesce === true ? "是" : "否" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态" <el-table-column label="状态" prop="status" min-width="100">
prop="status" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status === true ? "启用" : "停用" }} {{ scope.row.status === true ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" <el-table-column label="描述" prop="description" min-width="100" />
label="描述" prop="description" min-width="100" /> <el-table-column label="创建时间" prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" <el-table-column label="更新时间" prop="updated_at" min-width="200" sortable />
label="创建时间" prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at"
label="更新时间" prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" <el-table-column fixed="right" label="操作" min-width="240">
label="操作" min-width="240">
<template #default="scope"> <template #default="scope">
<el-button type="info" size="small" link icon="document" <el-button type="info" size="small" link icon="document"
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
@@ -139,9 +112,7 @@
<el-button type="danger" size="small" link icon="delete" <el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button> @click="handleDelete([scope.row.id])">删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" size="small" link icon="ArrowDown"> <el-button type="default" size="small" link icon="ArrowDown">更多</el-button>
更多
</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleOption(scope.row, 1)">暂停</el-dropdown-item> <el-dropdown-item icon="Check" @click="handleOption(scope.row, 1)">暂停</el-dropdown-item>
@@ -156,8 +127,7 @@
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
v-model:limit="queryFormData.page_size" @pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -175,30 +145,29 @@
<el-descriptions-item label="位置参数" :span="2">{{ detailFormData.args }}</el-descriptions-item> <el-descriptions-item label="位置参数" :span="2">{{ detailFormData.args }}</el-descriptions-item>
<el-descriptions-item label="关键字参数" :span="2">{{ detailFormData.kwargs }}</el-descriptions-item> <el-descriptions-item label="关键字参数" :span="2">{{ detailFormData.kwargs }}</el-descriptions-item>
<el-descriptions-item label="并发执行" :span="2"> <el-descriptions-item label="并发执行" :span="2">
<el-tag v-if="detailFormData.coalesce === true" type="success">是</el-tag> <el-tag :type="detailFormData.coalesce ? 'success' : 'danger'">
<el-tag v-else type="danger">否</el-tag> {{ detailFormData.coalesce ? '是' : '否' }}
</el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="最大实例数" :span="2">{{ detailFormData.max_instances <el-descriptions-item label="状态" :span="2">
}}</el-descriptions-item> <el-tag :type="detailFormData.status ? 'success' : 'danger'">
<el-descriptions-item label="触发器参数" :span="2">{{ detailFormData.trigger_args {{ detailFormData.status ? '启用' : '停用' }}
}}</el-descriptions-item> </el-tag>
</el-descriptions-item>
<el-descriptions-item label="最大实例数" :span="2">{{ detailFormData.max_instances }}</el-descriptions-item>
<el-descriptions-item label="触发器参数" :span="2">{{ detailFormData.trigger_args }}</el-descriptions-item>
<el-descriptions-item label="开始时间" :span="2">{{ detailFormData.start_date }}</el-descriptions-item> <el-descriptions-item label="开始时间" :span="2">{{ detailFormData.start_date }}</el-descriptions-item>
<el-descriptions-item label="结束时间" :span="2">{{ detailFormData.end_date }}</el-descriptions-item> <el-descriptions-item label="结束时间" :span="2">{{ detailFormData.end_date }}</el-descriptions-item>
<el-descriptions-item label="日志信息" :span="2">{{ detailFormData.message }}</el-descriptions-item> <el-descriptions-item label="日志信息" :span="2">{{ detailFormData.message }}</el-descriptions-item>
<el-descriptions-item label="状态" :span="2"> <el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name }}</el-descriptions-item>
<el-tag v-if="detailFormData.status" type="success">启用</el-tag>
<el-tag v-else type="danger">停用</el-tag>
</el-descriptions-item>
<el-descriptions-item label="描述" :span="2">{{ detailFormData.description }}</el-descriptions-item>
<el-descriptions-item label="创建时间" :span="2">{{ detailFormData.created_at }}</el-descriptions-item> <el-descriptions-item label="创建时间" :span="2">{{ detailFormData.created_at }}</el-descriptions-item>
<el-descriptions-item label="更新时间" :span="2">{{ detailFormData.updated_at }}</el-descriptions-item> <el-descriptions-item label="更新时间" :span="2">{{ detailFormData.updated_at }}</el-descriptions-item>
<el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name <el-descriptions-item label="描述" :span="4">{{ detailFormData.description }}</el-descriptions-item>
}}</el-descriptions-item>
</el-descriptions> </el-descriptions>
</template> </template>
<!-- 新增、编辑表单 --> <!-- 新增、编辑表单 -->
<template v-else> <template v-else>
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-suffix=":" label-width="100px"> <el-form ref="dataFormRef" :model="formData" :rules="rules" label-suffix=":" label-width="100px" >
<el-form-item label="任务名称" prop="name"> <el-form-item label="任务名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入任务名称" :maxlength="50" /> <el-input v-model="formData.name" placeholder="请输入任务名称" :maxlength="50" />
</el-form-item> </el-form-item>
@@ -232,7 +201,7 @@
</el-form-item> </el-form-item>
<el-form-item label="最大实例数" prop="max_instances"> <el-form-item label="最大实例数" prop="max_instances">
<el-input-number v-model="formData.max_instances" controls-position="right" :min="1" <el-input-number v-model="formData.max_instances" controls-position="right" :min="1"
:max="100" /> :max="10" />
</el-form-item> </el-form-item>
<el-form-item label="触发器" prop="trigger"> <el-form-item label="触发器" prop="trigger">
<el-select v-model="formData.trigger" placeholder="请选择触发器"> <el-select v-model="formData.trigger" placeholder="请选择触发器">
@@ -271,7 +240,6 @@
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束日期" style="width: 100%" /> value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择结束日期" style="width: 100%" />
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit
type="textarea" placeholder="请输入描述" /> type="textarea" placeholder="请输入描述" />
@@ -296,11 +264,10 @@
<IntervalTab ref="intervalTabRef" /> <IntervalTab ref="intervalTabRef" />
</el-dialog> </el-dialog>
<!-- core组件是由element-plus封装的vue3组件,所以需要使用element-plus --> <!-- core组件 -->
<el-dialog v-model="openCron"> <el-dialog v-model="openCron">
<Vue3CronPlusPicker :expression="expression" @hide="closeDialog" @fill="fillValue" /> <Vue3CronPlusPicker :expression="expression" @hide="closeDialog" @fill="fillValue" />
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@@ -314,9 +281,9 @@ import JobAPI, { JobTable, JobForm, JobPageQuery } from "@/api/monitor/job";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core"; import { useDebounceFn } from "@vueuse/core";
import IntervalTab from '@/components/IntervalTab/index.vue'; import IntervalTab from "@/components/IntervalTab/index.vue";
import 'vue3-cron-plus-picker/style.css'; import "vue3-cron-plus-picker/style.css";
import { Vue3CronPlusPicker } from 'vue3-cron-plus-picker'; import { Vue3CronPlusPicker } from "vue3-cron-plus-picker";
import { useDictStore } from "@/store/index"; import { useDictStore } from "@/store/index";
const dictStore = useDictStore(); const dictStore = useDictStore();
@@ -339,8 +306,8 @@ const isExpandable = ref(true);
// const tableLoading = ref(false); // const tableLoading = ref(false);
// const openModal = ref(false); // const openModal = ref(false);
const openCron = ref(false); const openCron = ref(false);
const cronMode = ref('create'); const cronMode = ref("create");
const modalTitle = ref(''); const modalTitle = ref("");
// const modalSubmitLoading = ref(false); // const modalSubmitLoading = ref(false);
// const detailStateLoading = ref(false); // const detailStateLoading = ref(false);
// const dataSource = ref<tableJobType[]>([]); // const dataSource = ref<tableJobType[]>([]);
@@ -354,23 +321,6 @@ const expression = ref();
// 分页表单 // 分页表单
const pageTableData = ref<JobTable[]>([]); const pageTableData = ref<JobTable[]>([]);
// 表格列配置
const tableColumns = ref([
{ prop: 'selection', label: '选择框', show: true },
{ prop: 'index', label: '序号', show: true },
{ prop: 'name', label: '任务名称', show: true },
{ prop: 'func', label: '执行函数', show: true },
{ prop: 'trigger', label: '触发器', show: true },
{ prop: 'jobstore', label: '存储器', show: true },
{ prop: 'executor', label: '执行器', show: true },
{ prop: 'coalesce', label: '并发执行', show: true },
{ prop: 'status', label: '状态', show: true },
{ prop: 'description', label: '描述', show: true },
{ prop: 'created_at', label: '创建时间', show: true },
{ prop: 'updated_at', label: '更新时间', show: true },
{ prop: 'operation', label: '操作', show: true }
])
// 详情表单 // 详情表单
const detailFormData = ref<JobTable>({}); const detailFormData = ref<JobTable>({});
@@ -402,13 +352,13 @@ const formData = reactive<JobForm>({
status: undefined, status: undefined,
message: undefined, message: undefined,
description: undefined, description: undefined,
}) });
// 弹窗状态 // 弹窗状态
const dialogVisible = reactive({ const dialogVisible = reactive({
title: "", title: "",
visible: false, visible: false,
type: 'create' as 'create' | 'update' | 'detail', type: "create" as "create" | "update" | "detail",
}); });
// 表单验证规则 // 表单验证规则
@@ -434,11 +384,9 @@ async function loadingData() {
const response = await JobAPI.getJobList(queryFormData); const response = await JobAPI.getJobList(queryFormData);
pageTableData.value = response.data.data.items; pageTableData.value = response.data.data.items;
total.value = response.data.data.total; total.value = response.data.data.total;
} } catch (error: any) {
catch (error: any) {
ElMessage.error(error.message); ElMessage.error(error.message);
} } finally {
finally {
loading.value = false; loading.value = false;
} }
} }
@@ -475,14 +423,17 @@ async function handleCloseDialog() {
} }
// 打开弹窗 // 打开弹窗
async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: number) { async function handleOpenDialog(
type: "create" | "update" | "detail",
id?: number,
) {
dialogVisible.type = type; dialogVisible.type = type;
if (id) { if (id) {
const response = await JobAPI.getJobDetail(id); const response = await JobAPI.getJobDetail(id);
if (type === 'detail') { if (type === "detail") {
dialogVisible.title = "任务详情"; dialogVisible.title = "任务详情";
Object.assign(detailFormData.value, response.data.data); Object.assign(detailFormData.value, response.data.data);
} else if (type === 'update') { } else if (type === "update") {
dialogVisible.title = "修改任务"; dialogVisible.title = "修改任务";
Object.assign(formData, response.data.data); Object.assign(formData, response.data.data);
} }
@@ -503,7 +454,7 @@ async function handleSubmit() {
const id = formData.id; const id = formData.id;
if (id) { if (id) {
try { try {
await JobAPI.updateJob(formData) await JobAPI.updateJob(formData);
dialogVisible.visible = false; dialogVisible.visible = false;
resetForm(); resetForm();
handleCloseDialog(); handleCloseDialog();
@@ -515,7 +466,7 @@ async function handleSubmit() {
} }
} else { } else {
try { try {
await JobAPI.createJob(formData) await JobAPI.createJob(formData);
dialogVisible.visible = false; dialogVisible.visible = false;
resetForm(); resetForm();
handleCloseDialog(); handleCloseDialog();
@@ -536,73 +487,74 @@ async function handleDelete(ids: number[]) {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning", type: "warning",
}).then(async () => { })
try { .then(async () => {
loading.value = true; try {
await JobAPI.deleteJob(ids); loading.value = true;
handleResetQuery(); await JobAPI.deleteJob(ids);
} catch (error: any) { handleResetQuery();
ElMessage.error(error.message); } catch (error: any) {
} finally { ElMessage.error(error.message);
loading.value = false; } finally {
} loading.value = false;
}).catch(() => { }
ElMessage.info('已取消删除'); })
}); .catch(() => {
ElMessage.info("已取消删除");
});
} }
// 导出 // 导出
async function handleExport() { async function handleExport() {
ElMessageBox.confirm('是否确认导出当前任务配置?', '警告', { ElMessageBox.confirm("是否确认导出当前任务配置?", "警告", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'warning' type: "warning",
}).then(async () => { })
try { .then(async () => {
loading.value = true; try {
const body = { loading.value = true;
...queryFormData, const body = {
page_no: 1, ...queryFormData,
page_size: total.value page_no: 1,
}; page_size: total.value,
ElMessage.warning('正在导出数据,请稍候...'); };
ElMessage.warning("正在导出数据,请稍候...");
const response = await JobAPI.exportJob(body); const response = await JobAPI.exportJob(body);
const blob = new Blob([JSON.stringify(response.data.data)], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' }); const blob = new Blob([JSON.stringify(response.data.data)], {
// 从响应头获取文件名 type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8",
const contentDisposition = response.headers['content-disposition']; });
let fileName = '系统配置.xlsx'; // 从响应头获取文件名
if (contentDisposition) { const contentDisposition = response.headers["content-disposition"];
const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/); let fileName = "系统配置.xlsx";
if (fileNameMatch) { if (contentDisposition) {
fileName = decodeURIComponent(fileNameMatch[1]); const fileNameMatch = contentDisposition.match(/filename=(.*?)(;|$)/);
if (fileNameMatch) {
fileName = decodeURIComponent(fileNameMatch[1]);
}
} }
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = fileName;
document.body.appendChild(link);
link.click();
} catch (error: any) {
ElMessage.error("文件处理失败", error.message);
console.error("导出错误:", error);
} finally {
loading.value = false;
} }
const url = window.URL.createObjectURL(blob); })
const link = document.createElement('a'); .catch(() => {
link.href = url; ElMessage.info("已取消导出");
link.download = fileName; });
document.body.appendChild(link);
link.click();
} catch (error: any) {
ElMessage.error('文件处理失败', error.message);
console.error('导出错误:', error);
} finally {
loading.value = false;
}
}).catch(() => {
ElMessage.info('已取消导出');
});
}
const getOptions = async () => {
const dictOptions = await dictStore.getDict(['sys_job_group', 'sys_job_executor', 'sys_job_function', 'sys_job_trigger'])
return dictOptions
} }
function openIntervalTabHandle(value: any) { function openIntervalTabHandle(value: any) {
openIntervalTab.value = true; openIntervalTab.value = true;
modalTitle.value = value modalTitle.value = value;
} }
function handleIntervalConfirm() { function handleIntervalConfirm() {
@@ -613,15 +565,15 @@ function handleIntervalConfirm() {
const handleShowCron = () => { const handleShowCron = () => {
openCron.value = true; openCron.value = true;
expression.value = formData.trigger_args; expression.value = formData.trigger_args;
} };
const closeDialog = () => { const closeDialog = () => {
openCron.value = false; openCron.value = false;
} };
const fillValue = (cronValue: string) => { const fillValue = (cronValue: string) => {
formData.trigger_args = cronValue; formData.trigger_args = cronValue;
} };
// 清空按钮操作 // 清空按钮操作
const handleClear = () => { const handleClear = () => {
@@ -629,28 +581,30 @@ const handleClear = () => {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning", type: "warning",
}).then(async () => { })
try { .then(async () => {
loading.value = true; try {
await JobAPI.clearJob(); loading.value = true;
ElMessage.success("清空成功"); await JobAPI.clearJob();
handleResetQuery(); ElMessage.success("清空成功");
} catch (error: any) { handleResetQuery();
ElMessage.error(error.message); } catch (error: any) {
} finally { ElMessage.error(error.message);
loading.value = false; } finally {
} loading.value = false;
}).catch(() => { }
ElMessage.info('已取消清空'); })
}); .catch(() => {
} ElMessage.info("已取消清空");
});
};
// 操作按钮:操作类型 1: 暂停 2: 恢复 3: 重启(暂时移除重启) // 操作按钮:操作类型 1: 暂停 2: 恢复 3: 重启(暂时移除重启)
const handleOption = (id: number, option: number) => { const handleOption = (id: number, option: number) => {
JobAPI.OptionJob({ id, option }).then(() => { JobAPI.OptionJob({ id, option }).then(() => {
loadingData(); loadingData();
}) });
} };
onMounted(() => { onMounted(() => {
loadingData(); loadingData();
+12 -24
View File
@@ -59,37 +59,26 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'session_id')?.show" key="session_id" label="会话编号" prop="session_id" min-width="250" show-overflow-tooltip/>
min-width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'ipaddr')?.show" key="ipaddr" label="IP地址" prop="ipaddr" min-width="120">
<el-table-column v-if="tableColumns.find(col => col.prop === 'session_id')?.show" key="session_id" label="会话编号"
prop="session_id" min-width="250" show-overflow-tooltip/>
<el-table-column v-if="tableColumns.find(col => col.prop === 'ipaddr')?.show" key="ipaddr" label="IP地址"
prop="ipaddr" min-width="120">
<template #default="scope"> <template #default="scope">
<el-text>{{ scope.row.ipaddr }}</el-text> <el-text>{{ scope.row.ipaddr }}</el-text>
<CopyButton v-if="scope.row.ipaddr" :text="scope.row.ipaddr" style="margin-left: 2px" /> <CopyButton v-if="scope.row.ipaddr" :text="scope.row.ipaddr" style="margin-left: 2px" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="用户名" prop="name" <el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="用户名" prop="name" min-width="80" />
min-width="80" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'user_name')?.show" key="user_name" label="用户姓名" prop="user_name" min-width="80" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'user_name')?.show" key="user_name" label="用户姓名" <el-table-column v-if="tableColumns.find(col => col.prop === 'login_location')?.show" key="login_location" label="登录位置" prop="login_location" min-width="80" />
prop="user_name" min-width="80" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'os')?.show" key="os" label="操作系统" prop="os" min-width="80" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'login_location')?.show" key="login_location" <el-table-column v-if="tableColumns.find(col => col.prop === 'login_time')?.show" key="login_time" label="登录时间" prop="login_time" min-width="180" />
label="登录位置" prop="login_location" min-width="80" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" key="operation" fixed="right" label="操作" min-width="100">
<el-table-column v-if="tableColumns.find(col => col.prop === 'os')?.show" key="os" label="操作系统" prop="os"
min-width="80" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'login_time')?.show" key="login_time" label="登录时间"
prop="login_time" min-width="180" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" key="operation" fixed="right"
label="操作" min-width="100">
<template #default="scope"> <template #default="scope">
<el-button type="danger" size="small" link icon="delete" @click="handleSubmit(scope.row.session_id)">强退 <el-button type="danger" size="small" link icon="delete" @click="handleSubmit(scope.row.session_id)">强退
</el-button> </el-button>
@@ -99,8 +88,7 @@
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
+19 -38
View File
@@ -18,8 +18,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
<el-button type="primary" icon="search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="search" @click="handleQuery">查询</el-button>
@@ -59,8 +58,7 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
</div> </div>
<div class="data-table__toolbar--tools"> <div class="data-table__toolbar--tools">
<el-tooltip content="导出"> <el-tooltip content="导出">
@@ -85,57 +83,41 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'config_name')?.show" key="config_name" label="配置名称" prop="config_name" min-width="100" />
min-width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'config_key')?.show" key="config_key" label="配置键" prop="config_key" min-width="200" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'config_name')?.show" key="config_name" <el-table-column v-if="tableColumns.find(col => col.prop === 'config_value')?.show" key="config_value" label="配置值" prop="config_value" min-width="120" show-overflow-tooltip />
label="配置名称" prop="config_name" min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'config_type')?.show" key="config_type" label="系统内置" prop="config_type" min-width="100">
<el-table-column v-if="tableColumns.find(col => col.prop === 'config_key')?.show" key="config_key" label="配置键"
prop="config_key" min-width="200" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'config_value')?.show" key="config_value"
label="配置值" prop="config_value" min-width="120" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'config_type')?.show" key="config_type"
label="系统内置" prop="config_type" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag v-if="scope.row.config_type" type="success">是</el-tag> <el-tag v-if="scope.row.config_type" type="success">是</el-tag>
<el-tag v-else type="danger">否</el-tag> <el-tag v-else type="danger">否</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" prop="description" min-width="120" />
prop="description" min-width="120" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人" <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间" prop="updated_at" min-width="200" sortable />
min-width="120"> <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人" min-width="120">
<template #default="scope"> <template #default="scope">
{{ scope.row.creator?.name }} {{ scope.row.creator?.name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="200">
prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间"
prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center"
min-width="200">
<template #default="scope"> <template #default="scope">
<el-button type="info" size="small" link icon="document" <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="primary" size="small" link icon="edit" <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -176,8 +158,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
+21 -42
View File
@@ -15,8 +15,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -57,12 +56,9 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">更多</el-button>
更多
</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item> <el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item>
@@ -91,47 +87,31 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" row-key="id" :data="pageTableData" :tree-props="{ <el-table ref="dataTableRef" v-loading="loading" row-key="id" :data="pageTableData" :tree-props="{children: 'children',hasChildren: 'hasChildren'}" highlight-current-row class="data-table__content" height="540" border stripe @selection-change="handleSelectionChange">
children: 'children',
hasChildren: 'hasChildren',
}" highlight-current-row class="data-table__content" height="540" border stripe
@selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="部门名称" prop="name" min-width="120" />
width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态" prop="status" min-width="60">
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="部门名称" prop="name"
min-width="120" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态"
prop="status" min-width="60">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status ? "启用" : "停用" }} {{ scope.row.status ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'order')?.show" key="order" label="排序" prop="order" <el-table-column v-if="tableColumns.find(col => col.prop === 'order')?.show" key="order" label="排序" prop="order" min-width="60" show-overflow-tooltip />
min-width="60" show-overflow-tooltip /> <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" prop="description" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" prop="created_at" min-width="120" sortable />
prop="description" min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间" prop="updated_at" min-width="120" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间"
prop="created_at" min-width="120" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间"
prop="updated_at" min-width="120" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="200">
min-width="200">
<template #default="scope"> <template #default="scope">
<el-button type="success" size="small" link icon="plus" @click="handleOpenDialog('create', undefined, scope.row.id)">新增</el-button> <el-button type="success" size="small" link icon="plus" @click="handleOpenDialog('create', undefined, scope.row.id)">新增</el-button>
<el-button type="info" size="small" link icon="document" <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="primary" size="small" link icon="edit" <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -146,8 +126,9 @@
<el-descriptions-item label="部门名称" :span="2">{{ detailFormData.name }}</el-descriptions-item> <el-descriptions-item label="部门名称" :span="2">{{ detailFormData.name }}</el-descriptions-item>
<el-descriptions-item label="上级部门" :span="2">{{ detailFormData.parent_name }}</el-descriptions-item> <el-descriptions-item label="上级部门" :span="2">{{ detailFormData.parent_name }}</el-descriptions-item>
<el-descriptions-item label="状态" :span="2"> <el-descriptions-item label="状态" :span="2">
<el-tag v-if="detailFormData.status" type="success">启用</el-tag> <el-tag :type="detailFormData.status ? 'success' : 'danger'">
<el-tag v-else type="danger">停用</el-tag> {{ detailFormData.status ? '启用' : '停用' }}
</el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="排序" :span="2">{{ detailFormData.order }}</el-descriptions-item> <el-descriptions-item label="排序" :span="2">{{ detailFormData.order }}</el-descriptions-item>
<el-descriptions-item label="创建时间" :span="2">{{ detailFormData.created_at }}</el-descriptions-item> <el-descriptions-item label="创建时间" :span="2">{{ detailFormData.created_at }}</el-descriptions-item>
@@ -162,8 +143,7 @@
<el-input v-model="formData.name" placeholder="请输入部门名称" :maxlength="50" /> <el-input v-model="formData.name" placeholder="请输入部门名称" :maxlength="50" />
</el-form-item> </el-form-item>
<el-form-item label="上级部门" prop="parent_id"> <el-form-item label="上级部门" prop="parent_id">
<el-tree-select v-model="formData.parent_id" placeholder="请选择上级部门" :data="deptOptions" filterable <el-tree-select v-model="formData.parent_id" placeholder="请选择上级部门" :data="deptOptions" filterable check-strictly :render-after-expand="false" />
check-strictly :render-after-expand="false" />
</el-form-item> </el-form-item>
<el-form-item label="排序" prop="order"> <el-form-item label="排序" prop="order">
<el-input-number v-model="formData.order" controls-position="right" :min="1" :max="999" /> <el-input-number v-model="formData.order" controls-position="right" :min="1" :max="999" />
@@ -175,8 +155,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
@@ -16,8 +16,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -58,12 +57,9 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">更多</el-button>
更多
</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item> <el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item>
@@ -95,77 +91,55 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="460" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="460" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'dict_label')?.show" key="dict_label" label="标签" prop="dict_label" min-width="100" show-overflow-tooltip />
min-width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态" prop="status" min-width="100" show-overflow-tooltip>
<el-table-column v-if="tableColumns.find(col => col.prop === 'dict_label')?.show" key="dict_label" label="标签"
prop="dict_label" min-width="100" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态"
prop="status" min-width="100" show-overflow-tooltip>
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status ? "启用" : "停用" }} {{ scope.row.status ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'dict_type')?.show" key="dict_type" label="类型" <el-table-column v-if="tableColumns.find(col => col.prop === 'dict_type')?.show" key="dict_type" label="类型" prop="dict_type" min-width="100" show-overflow-tooltip>
prop="dict_type" min-width="100" show-overflow-tooltip>
<template #default="scope"> <template #default="scope">
<el-tag type="primary">{{ scope.row.dict_type }}</el-tag> <el-tag type="primary">{{ scope.row.dict_type }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'dict_value')?.show" key="dict_value" label="值" <el-table-column v-if="tableColumns.find(col => col.prop === 'dict_value')?.show" key="dict_value" label="值" prop="dict_value" min-width="100" show-overflow-tooltip />
prop="dict_value" min-width="100" show-overflow-tooltip /> <el-table-column v-if="tableColumns.find(col => col.prop === 'css_class')?.show" key="css_class" label="样式属性" prop="css_class" min-width="100" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'css_class')?.show" key="css_class" label="样式属性" <el-table-column v-if="tableColumns.find(col => col.prop === 'list_class')?.show" key="list_class" label="列表类样式" prop="list_class" min-width="100" show-overflow-tooltip />
prop="css_class" min-width="100" show-overflow-tooltip /> <el-table-column v-if="tableColumns.find(col => col.prop === 'dict_sort')?.show" key="dict_sort" label="排序" prop="dict_sort" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'list_class')?.show" key="list_class" label="列表类样式" <el-table-column v-if="tableColumns.find(col => col.prop === 'is_default')?.show" key="is_default" label="是否默认" prop="is_default" min-width="100">
prop="list_class" min-width="100" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'dict_sort')?.show" key="dict_sort" label="排序"
prop="dict_sort" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'is_default')?.show" key="is_default" label="是否默认"
prop="is_default" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag v-if="scope.row.is_default" type="success">是</el-tag> <el-tag v-if="scope.row.is_default" type="success">是</el-tag>
<el-tag v-else type="danger">否</el-tag> <el-tag v-else type="danger">否</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" prop="description" min-width="100" />
prop="description" min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" label="创建人" prop="creator" <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间" prop="updated_at" min-width="200" sortable />
min-width="100"> <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" label="创建人" prop="creator" min-width="100">
<template #default="scope"> <template #default="scope">
{{ scope.row.creator?.name }} {{ scope.row.creator?.name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="200">
prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间"
prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center"
min-width="200">
<template #default="scope"> <template #default="scope">
<el-button type="info" size="small" link icon="document" <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="primary" size="small" link icon="edit" <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -229,13 +203,11 @@
<el-input-number v-model="formData.dict_sort" controls-position="right" :min="1" /> <el-input-number v-model="formData.dict_sort" controls-position="right" :min="1" />
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-switch v-model="formData.status" inline-prompt :active-icon="Check" :inactive-icon="Close" <el-switch v-model="formData.status" inline-prompt :active-icon="Check" :inactive-icon="Close" active-text="启用" inactive-text="停用" active-value="true" inactive-value="false" />
active-text="启用" inactive-text="停用" active-value="true" inactive-value="false" />
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
+19 -40
View File
@@ -18,8 +18,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -60,8 +59,7 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">
更多 更多
@@ -97,60 +95,42 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'dict_name')?.show" key="dict_name" label="字典名称" prop="dict_name" min-width="120" />
min-width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'dict_type')?.show" key="dict_type" label="字典类型" prop="dict_type" min-width="160" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'dict_name')?.show" key="dict_name" label="字典名称" <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态" prop="status" min-width="80">
prop="dict_name" min-width="120" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'dict_type')?.show" key="dict_type" label="字典类型"
prop="dict_type" min-width="160">
</el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态"
prop="status" min-width="60">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status ? "启用" : "停用" }} {{ scope.row.status ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" prop="description" min-width="140" />
prop="description" min-width="140" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" label="创建人" prop="creator" <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间" prop="updated_at" min-width="200" sortable />
min-width="120"> <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" label="创建人" prop="creator" min-width="120">
<template #default="scope"> <template #default="scope">
{{ scope.row.creator?.name }} {{ scope.row.creator?.name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="260">
prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间"
prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center"
min-width="260">
<template #default="scope"> <template #default="scope">
<el-button type="warning" size="small" link icon="document" <el-button type="warning" size="small" link icon="document" @click="handleDictDataDrawer(scope.row.dict_type, scope.row.dict_name)">字典</el-button>
@click="handleDictDataDrawer(scope.row.dict_type, scope.row.dict_name)">字典</el-button> <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
<el-button type="info" size="small" link icon="document" <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
<el-button type="primary" size="small" link icon="edit"
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -189,8 +169,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
+20 -78
View File
@@ -12,8 +12,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -53,8 +52,7 @@
<!-- 功能区域 --> <!-- 功能区域 -->
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
</div> </div>
<div class="data-table__toolbar--tools"> <div class="data-table__toolbar--tools">
<el-tooltip content="导出"> <el-tooltip content="导出">
@@ -79,70 +77,54 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" prop='selection' <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" prop='selection' type="selection" min-width="55" align="center" />
type="selection" min-width="55" align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'request_path')?.show" label="请求路径" prop="request_path" min-width="200" show-overflow-tooltip />
min-width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'request_method')?.show" label="请求方法" prop="request_method" min-width="100">
<el-table-column v-if="tableColumns.find(col => col.prop === 'request_path')?.show" label="请求路径"
prop="request_path" min-width="200" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'request_method')?.show" label="请求方法"
prop="request_method" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="getMethodType(scope.row.request_method)"> <el-tag :type="getMethodType(scope.row.request_method)">
{{ scope.row.request_method }} {{ scope.row.request_method }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'response_code')?.show" label="状态码" <el-table-column v-if="tableColumns.find(col => col.prop === 'response_code')?.show" label="状态码" prop="response_code" min-width="100">
prop="response_code" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="getStatusCodeType(scope.row.response_code)"> <el-tag :type="getStatusCodeType(scope.row.response_code)">
{{ scope.row.response_code }} {{ scope.row.response_code }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'request_ip')?.show" label="请求IP" prop="request_ip" <el-table-column v-if="tableColumns.find(col => col.prop === 'request_ip')?.show" label="请求IP" prop="request_ip" min-width="150">
min-width="150">
<template #default="scope"> <template #default="scope">
<el-text>{{ scope.row.request_ip }}</el-text> <el-text>{{ scope.row.request_ip }}</el-text>
<CopyButton v-if="scope.row.request_ip" :text="scope.row.request_ip" style="margin-left: 2px" /> <CopyButton v-if="scope.row.request_ip" :text="scope.row.request_ip" style="margin-left: 2px" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'process_time')?.show" label="处理时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'process_time')?.show" label="处理时间" prop="process_time" min-width="200" />
prop="process_time" min-width="200" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'request_browser')?.show" label="浏览器" prop="request_browser" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'request_browser')?.show" label="浏览器" <el-table-column v-if="tableColumns.find(col => col.prop === 'request_os')?.show" label="系统" prop="request_os" min-width="100" />
prop="request_browser" min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" label="描述" prop="description" min-width="120" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'request_os')?.show" label="系统" prop="request_os" <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" label="创建时间" prop="created_at" min-width="200" sortable />
min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" label="创建人" prop="creator" min-width="120">
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" label="描述" prop="description"
min-width="120" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" label="创建时间" prop="created_at"
min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" label="创建人" prop="creator"
min-width="120">
<template #default="scope"> <template #default="scope">
{{ scope.row.creator?.name }} {{ scope.row.creator?.name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" fixed="right" align="center" min-width="150"> <el-table-column label="操作" fixed="right" align="center" min-width="150">
<template #default="scope"> <template #default="scope">
<el-button type="info" size="small" link icon="document" <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -164,25 +146,10 @@
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="请求IP" :span="2">{{ detailFormData.request_ip }}</el-descriptions-item> <el-descriptions-item label="请求IP" :span="2">{{ detailFormData.request_ip }}</el-descriptions-item>
<el-descriptions-item label="请求参数" :span="4"> <el-descriptions-item label="请求参数" :span="4">
<el-input v-model="detailFormData.request_payload" type="textarea" :rows="3" readonly <el-input v-model="detailFormData.request_payload" type="textarea" :rows="3" readonly class="long-text-editor" />
class="long-text-editor" />
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="响应数据" :span="4"> <el-descriptions-item label="响应数据" :span="4">
<el-input v-model="detailFormData.response_json" type="textarea" :rows="5" readonly <el-input v-model="detailFormData.response_json" type="textarea" :rows="5" readonly class="long-text-editor" />
class="long-text-editor" />
<!-- <el-scrollbar max-height="72vh">
<div class="absolute z-36 right-5 top-2">
<el-link type="primary" @click="handleCopyCode">
<el-icon>
<CopyDocument />
</el-icon>
一键复制
</el-link>
</div>
<Codemirror ref="cmRef" v-model:value="code" placeholder="请输入代码" :options="cmOptions" border
:readonly="true" :width="700" :height="100" />
</el-scrollbar> -->
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="处理时间" :span="2">{{ detailFormData.process_time }}</el-descriptions-item> <el-descriptions-item label="处理时间" :span="2">{{ detailFormData.process_time }}</el-descriptions-item>
<el-descriptions-item label="浏览器" :span="2">{{ detailFormData.request_browser }}</el-descriptions-item> <el-descriptions-item label="浏览器" :span="2">{{ detailFormData.request_browser }}</el-descriptions-item>
@@ -213,15 +180,10 @@ defineOptions({
inheritAttrs: false, inheritAttrs: false,
}); });
import "codemirror/mode/javascript/javascript.js";
import Codemirror, { type CmComponentRef } from "codemirror-editor-vue3";
import type { EditorConfiguration } from "codemirror";
import LogAPI, { LogTable, LogPageQuery } from "@/api/system/log"; import LogAPI, { LogTable, LogPageQuery } from "@/api/system/log";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import { useDebounceFn } from "@vueuse/core"; import { useDebounceFn } from "@vueuse/core";
const { copy, copied } = useClipboard();
const queryFormRef = ref(); const queryFormRef = ref();
const dataFormRef = ref(); const dataFormRef = ref();
const total = ref(0); const total = ref(0);
@@ -365,7 +327,6 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id: number
if (type === 'detail') { if (type === 'detail') {
dialogVisible.title = "日志详情"; dialogVisible.title = "日志详情";
Object.assign(detailFormData.value, response.data.data); Object.assign(detailFormData.value, response.data.data);
code.value = response.data.data.response_json
} }
} }
dialogVisible.visible = true; dialogVisible.visible = true;
@@ -437,25 +398,6 @@ async function handleExport() {
}); });
} }
const cmOptions: EditorConfiguration = {
mode: "text/javascript",
};
const code = ref();
const cmRef = ref<CmComponentRef>();
/** 一键复制 */
const handleCopyCode = () => {
if (code.value) {
copy(code.value);
}
};
watch(copied, () => {
if (copied.value) {
ElMessage.success("复制成功");
}
});
onMounted(() => { onMounted(() => {
loadingData(); loadingData();
}); });
+16 -39
View File
@@ -15,8 +15,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -57,12 +56,9 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">更多</el-button>
更多
</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item> <el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item>
@@ -79,17 +75,12 @@
</div> </div>
<!-- 表格区域 --> <!-- 表格区域 -->
<el-table ref="dataTableRef" v-loading="loading" row-key="id" :data="pageTableData" :tree-props="{ <el-table ref="dataTableRef" v-loading="loading" row-key="id" :data="pageTableData" :tree-props="{children: 'children',hasChildren: 'hasChildren'}" class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange" @row-click="handleRowClick">
children: 'children',
hasChildren: 'hasChildren',
}" class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange"
@row-click="handleRowClick">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" min-width="55" align="center" />
<el-table-column type="index" fixed label="序号" <el-table-column type="index" fixed label="序号" min-width="60" />
width="60" />
<el-table-column label="菜单名称" prop="name" min-width="120"> <el-table-column label="菜单名称" prop="name" min-width="120">
<template #default="scope"> <template #default="scope">
{{ scope.row.name }} {{ scope.row.name }}
@@ -161,31 +152,22 @@
<el-table-column fixed="right" label="操作" align="center" min-width="260"> <el-table-column fixed="right" label="操作" align="center" min-width="260">
<template #default="scope"> <template #default="scope">
<el-button v-if="scope.row.type == MenuTypeEnum.CATALOG || scope.row.type == MenuTypeEnum.MENU" <el-button v-if="scope.row.type == MenuTypeEnum.CATALOG || scope.row.type == MenuTypeEnum.MENU" type="success" link size="small" icon="plus" @click.stop="handleOpenDialog(scope.row.id)">新增</el-button>
type="success" link size="small" icon="plus" @click.stop="handleOpenDialog(scope.row.id)"> <el-button type="info" size="small" link icon="document" @click.stop="handleOpenDialog('detail', scope.row.id)">详情</el-button>
新增 <el-button type="primary" size="small" link icon="edit" @click.stop="handleOpenDialog('update', scope.row.id)">编辑</el-button>
</el-button> <el-button type="danger" size="small" link icon="delete" @click.stop="handleDelete([scope.row.id])">删除</el-button>
<el-button type="info" size="small" link icon="document"
@click.stop="handleOpenDialog('detail', scope.row.id)">详情</el-button>
<el-button type="primary" size="small" link icon="edit"
@click.stop="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click.stop="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-if="total > 0" v-model:total="total" v-model:page="queryFormData.page_no" <pagination v-if="total > 0" v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
v-model:limit="queryFormData.page_size" @pagination="loadingData" />
</template> </template>
</el-card> </el-card>
<!-- 弹窗区域 --> <!-- 弹窗区域 -->
<el-drawer v-model="dialogVisible.visible" :title="dialogVisible.title" :size="drawerSize" <el-drawer v-model="dialogVisible.visible" :title="dialogVisible.title" :size="drawerSize" @close="handleCloseDialog">
@close="handleCloseDialog">
<!-- 详情 --> <!-- 详情 -->
<template v-if="dialogVisible.type === 'detail'"> <template v-if="dialogVisible.type === 'detail'">
<el-descriptions :column="4" border> <el-descriptions :column="4" border>
@@ -244,8 +226,7 @@
<template v-else> <template v-else>
<el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="100px"> <el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="100px">
<el-form-item label="父级菜单" prop="parent_id"> <el-form-item label="父级菜单" prop="parent_id">
<el-tree-select v-model="formData.parent_id" placeholder="选择上级菜单" :data="menuOptions" filterable <el-tree-select v-model="formData.parent_id" placeholder="选择上级菜单" :data="menuOptions" filterable check-strictly :render-after-expand="false" />
check-strictly :render-after-expand="false" />
</el-form-item> </el-form-item>
<el-form-item label="菜单名称" prop="name"> <el-form-item label="菜单名称" prop="name">
@@ -282,8 +263,7 @@
<el-input v-model="formData.route_name" placeholder="User" /> <el-input v-model="formData.route_name" placeholder="User" />
</el-form-item> </el-form-item>
<el-form-item v-if="formData.type == MenuTypeEnum.CATALOG || formData.type == MenuTypeEnum.MENU" <el-form-item v-if="formData.type == MenuTypeEnum.CATALOG || formData.type == MenuTypeEnum.MENU" prop="routePath">
prop="routePath">
<template #label> <template #label>
<div class="flex-y-center"> <div class="flex-y-center">
路由路径 路由路径
@@ -352,13 +332,10 @@
<el-input v-model="item.value" placeholder="参数值" style="width: 100px" /> <el-input v-model="item.value" placeholder="参数值" style="width: 100px" />
<el-icon v-if="formData.params.indexOf(item) === formData.params.length - 1" <el-icon v-if="formData.params.indexOf(item) === formData.params.length - 1" class="ml-2 cursor-pointer color-[var(--el-color-success)]" style="vertical-align: -0.15em" @click="formData.params.push({ key: '', value: '' })">
class="ml-2 cursor-pointer color-[var(--el-color-success)]" style="vertical-align: -0.15em"
@click="formData.params.push({ key: '', value: '' })">
<CirclePlusFilled /> <CirclePlusFilled />
</el-icon> </el-icon>
<el-icon class="ml-2 cursor-pointer color-[var(--el-color-danger)]" style="vertical-align: -0.15em" <el-icon class="ml-2 cursor-pointer color-[var(--el-color-danger)]" style="vertical-align: -0.15em" @click="formData.params.splice(formData.params.indexOf(item), 1)">
@click="formData.params.splice(formData.params.indexOf(item), 1)">
<DeleteFilled /> <DeleteFilled />
</el-icon> </el-icon>
</div> </div>
+31 -57
View File
@@ -21,8 +21,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -66,16 +65,10 @@
<!-- 功能区域 --> <!-- 功能区域 -->
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')"> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
新增 <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">
批量删除
</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">更多</el-button>
更多
</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item> <el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item>
@@ -109,62 +102,49 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'notice_title')?.show" label="通知标题" prop="notice_title" min-width="140" />
min-width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" label="状态" prop="status" min-width="80">
<el-table-column v-if="tableColumns.find(col => col.prop === 'notice_title')?.show" label="通知标题"
prop="notice_title" min-width="140" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" label="状态" prop="status"
min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status === true ? "启用" : "停用" }} {{ scope.row.status === true ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'notice_content')?.show" label="通知内容" <el-table-column v-if="tableColumns.find(col => col.prop === 'notice_type')?.show" label="类型" prop="notice_type" min-width="80">
prop="notice_content" min-width="100" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'notice_type')?.show" label="通知类型"
prop="notice_type" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.notice_type === '1' ? 'primary' : 'warning'"> <el-tag :type="scope.row.notice_type === '1' ? 'primary' : 'warning'">
{{ scope.row.notice_type === '1' ? "通知" : "公告" }} {{ scope.row.notice_type === '1' ? "通知" : "公告" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" label="描述" prop="description" <el-table-column v-if="tableColumns.find(col => col.prop === 'notice_content')?.show" label="内容" prop="notice_content" min-width="100" show-overflow-tooltip />
min-width="140" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" label="描述" prop="description" min-width="140" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" label="创建时间" prop="created_at" <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" label="创建时间" prop="created_at" min-width="180" sortable />
min-width="200" sortable /> <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" label="更新时间" prop="updated_at" min-width="180" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" label="更新时间" prop="updated_at" <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人" min-width="100">
min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center"
min-width="200">
<template #default="scope"> <template #default="scope">
<el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)"> {{ scope.row.creator?.name }}
详情 </template>
</el-button> </el-table-column>
<el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">
编辑 <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="200">
</el-button> <template #default="scope">
<el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])"> <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
删除 <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
</el-button> <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -229,8 +209,7 @@
<WangEditor v-model="formData.notice_content" /> <WangEditor v-model="formData.notice_content" />
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
@@ -252,13 +231,11 @@
</el-dialog> </el-dialog>
<!-- 导出弹窗 --> <!-- 导出弹窗 -->
<el-dialog v-model="exportsModalVisible" :align-center="true" title="导出数据" width="600px" style="padding-right: 0" <el-dialog v-model="exportsModalVisible" :align-center="true" title="导出数据" width="600px" style="padding-right: 0" @close="handleCloseExportsModal">
@close="handleCloseExportsModal">
<!-- 滚动 --> <!-- 滚动 -->
<el-scrollbar max-height="60vh"> <el-scrollbar max-height="60vh">
<!-- 表单 --> <!-- 表单 -->
<el-form ref="exportsFormRef" style="padding-right: var(--el-dialog-padding-primary)" :model="exportsFormData" <el-form ref="exportsFormRef" style="padding-right: var(--el-dialog-padding-primary)" :model="exportsFormData" :rules="exportsFormRules">
:rules="exportsFormRules">
<el-form-item label="文件名" prop="filename"> <el-form-item label="文件名" prop="filename">
<el-input v-model="exportsFormData.filename" clearable /> <el-input v-model="exportsFormData.filename" clearable />
</el-form-item> </el-form-item>
@@ -268,10 +245,8 @@
<el-form-item label="数据源" prop="origin"> <el-form-item label="数据源" prop="origin">
<el-select v-model="exportsFormData.origin"> <el-select v-model="exportsFormData.origin">
<el-option label="当前数据 (当前页的数据)" :value="ExportsOriginEnum.CURRENT" /> <el-option label="当前数据 (当前页的数据)" :value="ExportsOriginEnum.CURRENT" />
<el-option label="选中数据 (所有选中的数据)" :value="ExportsOriginEnum.SELECTED" <el-option label="选中数据 (所有选中的数据)" :value="ExportsOriginEnum.SELECTED" :disabled="selectionData.length <= 0" />
:disabled="selectionData.length <= 0" /> <el-option label="全量数据 (所有分页的数据)" :value="ExportsOriginEnum.REMOTE" :disabled="contentConfig.exportsAction === undefined" />
<el-option label="全量数据 (所有分页的数据)" :value="ExportsOriginEnum.REMOTE"
:disabled="contentConfig.exportsAction === undefined" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="字段" prop="fields"> <el-form-item label="字段" prop="fields">
@@ -292,8 +267,7 @@
</template> </template>
</el-dialog> </el-dialog>
<!-- 导入弹窗 --> <!-- 导入弹窗 -->
<el-dialog v-model="importModalVisible" :align-center="true" title="导入数据" width="600px" style="padding-right: 0" <el-dialog v-model="importModalVisible" :align-center="true" title="导入数据" width="600px" style="padding-right: 0" @close="handleCloseImportModal">
@close="handleCloseImportModal">
<!-- 滚动 --> <!-- 滚动 -->
<el-scrollbar max-height="60vh"> <el-scrollbar max-height="60vh">
<!-- 表单 --> <!-- 表单 -->
+19 -39
View File
@@ -15,8 +15,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -57,12 +56,9 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">更多</el-button>
更多
</el-button>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item> <el-dropdown-item icon="Check" @click="handleMoreClick(true)">批量启用</el-dropdown-item>
@@ -94,57 +90,42 @@
</div> </div>
<!-- 表格区域:系统配置列表 --> <!-- 表格区域:系统配置列表 -->
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="岗位名称" prop="name" min-width="100" />
width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态" prop="status" min-width="80">
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="岗位名称" prop="name"
min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态"
prop="status" min-width="80">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status === true ? "启用" : "停用" }} {{ scope.row.status === true ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'order')?.show" key="order" label="岗位排序" <el-table-column v-if="tableColumns.find(col => col.prop === 'order')?.show" key="order" label="岗位排序" prop="order" min-width="80" show-overflow-tooltip />
prop="order" min-width="80" show-overflow-tooltip /> <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" prop="description" min-width="120" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" prop="created_at" min-width="200" sortable />
prop="description" min-width="120" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间" prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人" min-width="100">
prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间"
prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人"
min-width="120">
<template #default="scope"> <template #default="scope">
{{ scope.row.creator?.name }} {{ scope.row.creator?.name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="200">
min-width="200">
<template #default="scope"> <template #default="scope">
<el-button type="info" size="small" link icon="document" <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="primary" size="small" link icon="edit" <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -183,8 +164,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
</template> </template>
+42 -48
View File
@@ -15,8 +15,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -57,8 +56,7 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">
更多 更多
@@ -93,61 +91,44 @@
</div> </div>
</div> </div>
<el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataTableRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" width="55" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" width="55" align="center" />
align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="角色名称" prop="name" min-width="100" />
width="60" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'data_scope')?.show" key="data_scope" label="数据权限" prop="data_scope" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" key="name" label="角色名称" prop="name" <el-table-column v-if="tableColumns.find(col => col.prop === 'order')?.show" key="order" label="排序" prop="order" min-width="80" show-overflow-tooltip />
min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态" prop="status" min-width="60">
<el-table-column v-if="tableColumns.find(col => col.prop === 'data_scope')?.show" key="data_scope" label="数据权限"
prop="data_scope" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'order')?.show" key="order" label="排序" prop="order"
min-width="80" show-overflow-tooltip />
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" key="status" label="状态"
prop="status" min-width="60">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status === true ? "启用" : "停用" }} {{ scope.row.status === true ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" <el-table-column v-if="tableColumns.find(col => col.prop === 'description')?.show" key="description" label="描述" prop="description" min-width="100" />
prop="description" min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" prop="created_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" key="created_at" label="创建时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间" prop="updated_at" min-width="200" sortable />
prop="created_at" min-width="200" sortable /> <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人" min-width="120">
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" key="updated_at" label="更新时间"
prop="updated_at" min-width="200" sortable />
<el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人"
min-width="120">
<template #default="scope"> <template #default="scope">
{{ scope.row.creator?.name }} {{ scope.row.creator?.name }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="280">
min-width="280">
<template #default="scope"> <template #default="scope">
<el-button type="primary" size="small" link icon="position" <el-button type="primary" size="small" link icon="position" @click="handleOpenAssignPermDialog(scope.row)">分配权限</el-button>
@click="handleOpenAssignPermDialog(scope.row)">分配权限</el-button> <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
<el-button type="info" size="small" link icon="document" <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
<el-button type="primary" size="small" link icon="edit"
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
<el-button type="danger" size="small" link icon="delete"
@click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
@pagination="loadingData" />
</template> </template>
</el-card> </el-card>
@@ -164,8 +145,9 @@
{{ detailFormData.data_scope }} {{ detailFormData.data_scope }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="状态" :span="2"> <el-descriptions-item label="状态" :span="2">
<el-tag v-if="detailFormData.status" type="success">启用</el-tag> <el-tag :type="detailFormData.status ? 'success' : 'danger'">
<el-tag v-else type="danger">停用</el-tag> {{ detailFormData.status ? '启用' : '停用' }}
</el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="描述" :span="2">{{ detailFormData.description }}</el-descriptions-item> <el-descriptions-item label="描述" :span="2">{{ detailFormData.description }}</el-descriptions-item>
<el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name }}</el-descriptions-item> <el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name }}</el-descriptions-item>
@@ -192,8 +174,7 @@
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" <el-input v-model="formData.description" :rows="4" :maxlength="100" show-word-limit type="textarea" placeholder="请输入描述" />
placeholder="请输入描述" />
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -239,9 +220,14 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-tree v-if="permissionState.data_scope === 5 && deptTreeData.length" <el-tree
:checked-keys="permissionState.dept_ids" :row-key="record => record.id" :tree-data="deptTreeData" v-if="permissionState.data_scope === 5 && deptTreeData.length"
:default-expand-all=true :field-names="{ children: 'children', title: 'name', key: 'id' }" checkable :checked-keys="permissionState.dept_ids"
:row-key="record => record.id"
:tree-data="deptTreeData"
:default-expand-all=true
:field-names="{ children: 'children', title: 'name', key: 'id' }"
checkable
check-strictly style="margin-top: 15px; height: calc(100% - 100px); overflow: auto;" check-strictly style="margin-top: 15px; height: calc(100% - 100px); overflow: auto;"
@check="deptTreeCheck" /> @check="deptTreeCheck" />
</el-col> </el-col>
@@ -279,9 +265,17 @@
</div> </div>
</div> </div>
<el-tree ref="permTreeRef" node-key="value" show-checkbox :data="menuTreeData" <el-tree
:filter-node-method="handlePermFilter" :default-expand-all="true" :check-strictly="!parentChildLinked" ref="permTreeRef"
class="mt-5" style="height: calc(100% - 60px); overflow: auto;"> node-key="value"
show-checkbox
:data="menuTreeData"
:filter-node-method="handlePermFilter"
:default-expand-all="true"
:check-strictly="!parentChildLinked"
class="mt-5"
style="height: calc(100% - 60px);
overflow: auto;">
<template #default="{ data }"> <template #default="{ data }">
{{ data.label }} {{ data.label }}
</template> </template>
+36 -52
View File
@@ -26,8 +26,7 @@
</el-form-item> </el-form-item>
<!-- 时间范围,收起状态下隐藏 --> <!-- 时间范围,收起状态下隐藏 -->
<el-form-item v-if="isExpand" prop="start_time" label="创建时间"> <el-form-item v-if="isExpand" prop="start_time" label="创建时间">
<el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" <el-date-picker v-model="queryFormData.start_time" type="daterange" value-format="yyyy-MM-dd" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
</el-form-item> </el-form-item>
<!-- 查询、重置、展开/收起按钮 --> <!-- 查询、重置、展开/收起按钮 -->
<el-form-item class="search-buttons"> <el-form-item class="search-buttons">
@@ -67,8 +66,7 @@
<div class="data-table__toolbar"> <div class="data-table__toolbar">
<div class="data-table__toolbar--actions"> <div class="data-table__toolbar--actions">
<el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button> <el-button type="success" icon="plus" @click="handleOpenDialog('create')">新增</el-button>
<el-button type="danger" icon="delete" :disabled="selectIds.length === 0" <el-button type="danger" icon="delete" :disabled="selectIds.length === 0" @click="handleDelete(selectIds)">批量删除</el-button>
@click="handleDelete(selectIds)">批量删除</el-button>
<el-dropdown trigger="click"> <el-dropdown trigger="click">
<el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown"> <el-button type="default" :disabled="selectIds.length === 0" icon="ArrowDown">
更多 更多
@@ -117,35 +115,27 @@
</div> </div>
<!-- 表格区域 --> <!-- 表格区域 -->
<el-table ref="dataFormRef" v-loading="loading" :data="pageTableData" highlight-current-row <el-table ref="dataFormRef" v-loading="loading" :data="pageTableData" highlight-current-row class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
class="data-table__content" height="450" border stripe @selection-change="handleSelectionChange">
<template #empty> <template #empty>
<el-empty :image-size="80" description="暂无数据" /> <el-empty :image-size="80" description="暂无数据" />
</template> </template>
<el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" <el-table-column v-if="tableColumns.find(col => col.prop === 'selection')?.show" type="selection" min-width="55" align="center" />
min-width="55" align="center" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" align="center" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'index')?.show" type="index" fixed label="序号" <el-table-column v-if="tableColumns.find(col => col.prop === 'avatar')?.show" label="头像" prop="avatar" min-width="80" align="center">
align="center" min-width="60" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'avatar')?.show" label="头像" prop="avatar"
min-width="80" align="center">
<template #default="scope"> <template #default="scope">
<el-avatar :src="scope.row.avatar" /> <el-avatar size="small" :src="scope.row.avatar" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'username')?.show" label="账号" prop="username" <el-table-column v-if="tableColumns.find(col => col.prop === 'username')?.show" label="账号" prop="username" min-width="100" />
min-width="100" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" label="用户名" prop="name" min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'name')?.show" label="用户名" prop="name" <el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" label="状态" prop="status" min-width="100">
min-width="100" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'status')?.show" label="状态" prop="status"
min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.status === true ? 'success' : 'danger'"> <el-tag :type="scope.row.status === true ? 'success' : 'danger'">
{{ scope.row.status === true ? "启用" : "停用" }} {{ scope.row.status === true ? "启用" : "停用" }}
</el-tag> </el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'is_superuser')?.show" label="是否超管" <el-table-column v-if="tableColumns.find(col => col.prop === 'is_superuser')?.show" label="是否超管" prop="is_superuser" min-width="100">
prop="is_superuser" min-width="100">
<template #default="scope"> <template #default="scope">
<el-tag :type="scope.row.is_superuser ? 'success' : 'info'"> <el-tag :type="scope.row.is_superuser ? 'success' : 'info'">
{{ scope.row.is_superuser ? '是' : '否' }} {{ scope.row.is_superuser ? '是' : '否' }}
@@ -158,42 +148,35 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column v-if="tableColumns.find(col => col.prop === 'mobile')?.show" label="手机号" prop="mobile" <el-table-column v-if="tableColumns.find(col => col.prop === 'mobile')?.show" label="手机号" prop="mobile" min-width="160" />
min-width="160" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'email')?.show" label="邮箱" prop="email" min-width="160" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'email')?.show" label="邮箱" prop="email" <el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" label="创建时间" prop="created_at" min-width="200" />
min-width="160" /> <el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" label="更新时间" prop="updated_at" min-width="200" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'created_at')?.show" label="创建时间" <el-table-column v-if="tableColumns.find(col => col.prop === 'creator')?.show" key="creator" label="创建人" min-width="120">
prop="created_at" min-width="200" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'updated_at')?.show" label="更新时间"
prop="updated_at" min-width="200" />
<el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center"
min-width="280">
<template #default="scope"> <template #default="scope">
<el-button type="primary" icon="RefreshLeft" size="small" link @click="hancleResetPassword(scope.row)"> {{ scope.row.creator?.name }}
重置密码 </template>
</el-button> </el-table-column>
<el-button type="info" size="small" link icon="document" <el-table-column v-if="tableColumns.find(col => col.prop === 'operation')?.show" fixed="right" label="操作" align="center" min-width="280">
@click="handleOpenDialog('detail', scope.row.id)">详情</el-button> <template #default="scope">
<el-button type="primary" size="small" link icon="edit" <el-button type="warning" icon="RefreshLeft" size="small" link @click="hancleResetPassword(scope.row)">重置密码</el-button>
@click="handleOpenDialog('update', scope.row.id)">编辑</el-button> <el-button type="info" size="small" link icon="document" @click="handleOpenDialog('detail', scope.row.id)">详情</el-button>
<el-button type="danger" size="small" link icon="delete" <el-button type="primary" size="small" link icon="edit" @click="handleOpenDialog('update', scope.row.id)">编辑</el-button>
@click="handleDelete([scope.row.id])">删除</el-button> <el-button type="danger" size="small" link icon="delete" @click="handleDelete([scope.row.id])">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页区域 --> <!-- 分页区域 -->
<template #footer> <template #footer>
<pagination v-model:total="total" v-model:page="queryFormData.page_no" <pagination v-model:total="total" v-model:page="queryFormData.page_no" v-model:limit="queryFormData.page_size" @pagination="loadingData" />
v-model:limit="queryFormData.page_size" @pagination="loadingData" />
</template> </template>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<!-- 弹窗区域 --> <!-- 弹窗区域 -->
<el-drawer v-model="dialogVisible.visible" :title="dialogVisible.title" append-to-body :size="drawerSize" <el-drawer v-model="dialogVisible.visible" :title="dialogVisible.title" append-to-body :size="drawerSize" @close="handleCloseDialog">
@close="handleCloseDialog">
<!-- 详情 --> <!-- 详情 -->
<template v-if="dialogVisible.type === 'detail'"> <template v-if="dialogVisible.type === 'detail'">
<el-descriptions :column="2" border> <el-descriptions :column="2" border>
@@ -212,12 +195,14 @@
<el-descriptions-item label="邮箱" :span="2">{{ detailFormData.email }}</el-descriptions-item> <el-descriptions-item label="邮箱" :span="2">{{ detailFormData.email }}</el-descriptions-item>
<el-descriptions-item label="手机号" :span="2">{{ detailFormData.mobile }}</el-descriptions-item> <el-descriptions-item label="手机号" :span="2">{{ detailFormData.mobile }}</el-descriptions-item>
<el-descriptions-item label="是否超管" :span="2"> <el-descriptions-item label="是否超管" :span="2">
<el-tag v-if="detailFormData.is_superuser" type="success">是</el-tag> <el-tag :type="detailFormData.is_superuser ? 'success' : 'info'">
<el-tag v-else type="info">否</el-tag> {{ detailFormData.is_superuser ? '是' : '否' }}
</el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="状态" :span="2"> <el-descriptions-item label="状态" :span="2">
<el-tag v-if="detailFormData.status" type="success">启用</el-tag> <el-tag :type="detailFormData.status ? 'success' : 'danger'">
<el-tag v-else type="danger">停用</el-tag> {{ detailFormData.status ? '启用' : '停用' }}
</el-tag>
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="上次登录时间" :span="2">{{ detailFormData.last_login }}</el-descriptions-item> <el-descriptions-item label="上次登录时间" :span="2">{{ detailFormData.last_login }}</el-descriptions-item>
<el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name }}</el-descriptions-item> <el-descriptions-item label="创建人" :span="2">{{ detailFormData.creator?.name }}</el-descriptions-item>
@@ -250,8 +235,7 @@
</el-form-item> </el-form-item>
<el-form-item label="部门" prop="dept_id"> <el-form-item label="部门" prop="dept_id">
<el-tree-select v-model="formData.dept_id" placeholder="请选择所属部门" :data="deptOptions" filterable <el-tree-select v-model="formData.dept_id" placeholder="请选择所属部门" :data="deptOptions" filterable check-strictly :render-after-expand="false" />
check-strictly :render-after-expand="false" />
</el-form-item> </el-form-item>
<el-form-item label="角色" prop="role_ids"> <el-form-item label="角色" prop="role_ids">
@@ -289,8 +273,7 @@
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<!-- 详情弹窗不需要确定按钮的提交逻辑 --> <!-- 详情弹窗不需要确定按钮的提交逻辑 -->
<el-button v-if="dialogVisible.type === 'create' || dialogVisible.type === 'update'" type="primary" <el-button v-if="dialogVisible.type === 'create' || dialogVisible.type === 'update'" type="primary" @click="handleSubmit">确定</el-button>
@click="handleSubmit">确定</el-button>
<el-button v-else type="primary" @click="handleCloseDialog">确定</el-button> <el-button v-else type="primary" @click="handleCloseDialog">确定</el-button>
<el-button @click="handleCloseDialog">取消</el-button> <el-button @click="handleCloseDialog">取消</el-button>
</div> </div>
@@ -368,6 +351,7 @@ const tableColumns = ref([
{ prop: 'description', label: '描述', show: true }, { prop: 'description', label: '描述', show: true },
{ prop: 'created_at', label: '创建时间', show: true }, { prop: 'created_at', label: '创建时间', show: true },
{ prop: 'updated_at', label: '更新时间', show: true }, { prop: 'updated_at', label: '更新时间', show: true },
{ prop: 'creator', label: '创建人', show: true },
{ prop: 'operation', label: '操作', show: true } { prop: 'operation', label: '操作', show: true }
]) ])
+1 -1
View File
@@ -28,6 +28,6 @@
"types": ["node", "vite/client", "element-plus/global"] "types": ["node", "vite/client", "element-plus/global"]
}, },
"include": ["mock/**/*.ts", "src/**/*.ts", "src/**/*.vue", "vite.config.ts", "eslint.config.ts"], "include": ["mock/**/*.ts", "src/**/*.ts", "src/**/*.vue", "vite.config.ts"],
"exclude": ["node_modules", "dist"] "exclude": ["node_modules", "dist"]
} }