diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index e74db40bfcd94e703617d0de83d00b004ab7132a..0000000000000000000000000000000000000000 --- a/.eslintignore +++ /dev/null @@ -1,17 +0,0 @@ -*.sh -node_modules -*.md -*.woff -*.ttf -.vscode -.idea -dist -/public -/docs -.husky -.local -/bin -.eslintrc.cjs -prettier.config.js -src/assets -tailwind.config.js diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000000000000000000000000000000000000..8b67e9edbaaf71149c57fab255b66622105bb108 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,86 @@ +import globals from 'globals'; +import pluginJs from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import pluginVue from 'eslint-plugin-vue'; +import { readFile } from 'node:fs/promises'; +import prettier from 'eslint-plugin-prettier'; + +/** + * https://blog.csdn.net/sayUonly/article/details/123482912 + * 自动导入的配置 + */ +const autoImportFile = new URL('./.eslintrc-auto-import.json', import.meta.url); +const autoImportGlobals = JSON.parse(await readFile(autoImportFile, 'utf8')); + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { + /** + * 不需要.eslintignore文件 而是在这里配置 + */ + ignores: [ + '*.sh', + 'node_modules', + '*.md', + '*.woff', + '*.ttf', + '.vscode', + '.idea', + 'dist', + '/public', + '/docs', + '.husky', + '.local', + '/bin', + '.eslintrc.cjs', + 'prettier.config.js', + 'src/assets', + 'tailwind.config.js' + ] + }, + { files: ['**/*.{js,mjs,cjs,ts,vue}'] }, + { + languageOptions: { + globals: globals.browser + } + }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + ...pluginVue.configs['flat/essential'], + { + files: ['**/*.vue'], + languageOptions: { + parserOptions: { + parser: tseslint.parser + } + } + }, + { + languageOptions: { + globals: { + // 自动导入的配置 undef + ...autoImportGlobals.globals, + DialogOption: 'readonly', + LayoutSetting: 'readonly' + } + }, + plugins: { prettier }, + rules: { + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-this-alias': 'off', + + // vue + 'vue/multi-word-component-names': 'off', + 'vue/valid-define-props': 'off', + 'vue/no-v-model-argument': 'off', + 'prefer-rest-params': 'off', + // prettier + 'prettier/prettier': 'error', + // 允许使用空Object类型 {} + '@typescript-eslint/no-empty-object-type': 'off', + '@typescript-eslint/no-unused-expressions': 'off' + } + } +]; diff --git a/package.json b/package.json index 9726ee5fcf17fbe4cf8867f5444f033659d0568e..04ca0b3dd829926967e88e53fa104282001fdf60 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "$schema": "https://json.schemastore.org/tsconfig", "name": "ruoyi-vue-plus", "version": "5.2.3", "description": "RuoYi-Vue-Plus多租户管理系统", @@ -10,7 +11,8 @@ "build:prod": "vite build --mode production", "build:dev": "vite build --mode development", "preview": "vite preview", - "lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ", + "lint:eslint": "eslint", + "lint:eslint:fix": "eslint --fix", "prettier": "prettier --write ." }, "repository": { @@ -34,7 +36,7 @@ "file-saver": "2.0.5", "fuse.js": "7.0.0", "highlight.js": "11.9.0", - "image-conversion": "^2.1.1", + "image-conversion": "2.1.1", "js-cookie": "3.0.5", "jsencrypt": "3.3.2", "nprogress": "0.2.0", @@ -49,6 +51,7 @@ "vxe-table": "4.5.22" }, "devDependencies": { + "@eslint/js": "9.15.0", "@iconify/json": "2.2.276", "@intlify/unplugin-vue-i18n": "3.0.1", "@types/crypto-js": "4.2.2", @@ -56,27 +59,22 @@ "@types/js-cookie": "3.0.6", "@types/node": "18.18.2", "@types/nprogress": "0.2.3", - "@typescript-eslint/eslint-plugin": "7.18.0", - "@typescript-eslint/parser": "7.18.0", "@unocss/preset-attributify": "0.64.1", "@unocss/preset-icons": "0.64.1", "@unocss/preset-uno": "0.64.1", "@vitejs/plugin-vue": "5.0.4", "@vue/compiler-sfc": "3.4.23", "autoprefixer": "10.4.18", - "eslint": "8.57.0", - "eslint-config-prettier": "9.1.0", - "eslint-define-config": "2.1.0", - "eslint-plugin-import": "2.31.0", - "eslint-plugin-node": "11.1.0", - "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-promise": "7.2.0", + "eslint": "9.15.0", + "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-vue": "9.31.0", "fast-glob": "3.3.2", + "globals": "15.12.0", "postcss": "8.4.36", "prettier": "3.2.5", "sass": "1.72.0", "typescript": "5.7.2", + "typescript-eslint": "8.16.0", "unocss": "0.64.1", "unplugin-auto-import": "0.17.5", "unplugin-icons": "0.18.5", @@ -86,7 +84,6 @@ "vite-plugin-compression": "0.5.1", "vite-plugin-svg-icons": "2.0.1", "vitest": "1.5.0", - "vue-eslint-parser": "9.4.2", "vue-tsc": "2.0.13" } } diff --git a/src/layout/components/TopBar/search.vue b/src/layout/components/TopBar/search.vue index cf4b024fcb548759155be300c2966ceb9f9a2423..182e84a840de4a07d1da796af2fc284bd77cceed 100644 --- a/src/layout/components/TopBar/search.vue +++ b/src/layout/components/TopBar/search.vue @@ -66,7 +66,7 @@ const closeSearch = () => { state.isShowSearch = false; }; // 菜单搜索数据过滤 -const menuSearch = (queryString: string, cb: Function) => { +const menuSearch = (queryString: string, cb: (options: any[]) => void) => { let options = state.menuList.filter((item) => { return item.title.indexOf(queryString) > -1; }); diff --git a/src/permission.ts b/src/permission.ts index 125438bd4fae8308740115c4b88686cd914727df..51a928a434dfc2c5a0e29ab0d3cab4c3a366a0c3 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -40,7 +40,7 @@ router.beforeEach(async (to, from, next) => { router.addRoute(route); // 动态添加可访问路由表 } }); - // @ts-ignore + // @ts-expect-error hack方法 确保addRoutes已完成 next({ path: to.path, replace: true, params: to.params, query: to.query, hash: to.hash, name: to.name as string }); // hack方法 确保addRoutes已完成 } } else { diff --git a/src/views/register.vue b/src/views/register.vue index 4e67a67cd882f16fb2928f9fdc505c8b568b8fca..83f7a272ec6ab62261a7426bf5a49592be7ee3b0 100644 --- a/src/views/register.vue +++ b/src/views/register.vue @@ -92,7 +92,7 @@ const registerRules: ElFormRules = { password: [ { required: true, trigger: 'blur', message: '请输入您的密码' }, { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }, - { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\\ |', trigger: 'blur' } + { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' } ], confirmPassword: [ { required: true, trigger: 'blur', message: '请再次输入您的密码' }, diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index d75e760be5b0ec7ac0074283aeb954035913e41f..9597ca1a200fc221a80a98b367eded5104c00c5b 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -393,7 +393,7 @@ const initData: PageData = { message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }, - { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\\ |', trigger: 'blur' } + { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' } ], email: [ { @@ -506,7 +506,7 @@ const handleResetPwd = async (row: UserVO) => { inputErrorMessage: '用户密码长度必须介于 5 和 20 之间', inputValidator: (value) => { if (/<|>|"|'|\||\\/.test(value)) { - return '不能包含非法字符:< > " \' \\\ |'; + return '不能包含非法字符:< > " \' \\ |'; } } }) diff --git a/src/views/system/user/profile/resetPwd.vue b/src/views/system/user/profile/resetPwd.vue index aae5ef8c20ff17d45088ed3f226da39b22c09919..3ca5ee9f003b2d0a51da12429caaf1d1171226d5 100644 --- a/src/views/system/user/profile/resetPwd.vue +++ b/src/views/system/user/profile/resetPwd.vue @@ -45,7 +45,7 @@ const rules = ref({ message: '长度在 6 到 20 个字符', trigger: 'blur' }, - { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\\ |', trigger: 'blur' } + { pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\ |', trigger: 'blur' } ], confirmPassword: [ { required: true, message: '确认密码不能为空', trigger: 'blur' }, diff --git a/src/views/tool/gen/importTable.vue b/src/views/tool/gen/importTable.vue index e0f524eb6efb74e87c831965121ee55b48fd982d..f6e75cc333ac34e145e072bd88ac0ced513f0206 100644 --- a/src/views/tool/gen/importTable.vue +++ b/src/views/tool/gen/importTable.vue @@ -63,7 +63,7 @@ const emit = defineEmits(['ok']); /** 查询参数列表 */ const show = (dataName: string) => { - getDataNames().then(res => { + getDataNames().then((res) => { if (res.code == 200) { dataNameList.value = res.data; if (dataName) {