From 10be0c150354f5fa9db0a0b5b9c7d9600333a29c Mon Sep 17 00:00:00 2001 From: Wisdom Date: Sun, 28 Apr 2024 11:32:46 +0800 Subject: [PATCH] =?UTF-8?q?=E2=8C=9B=20chore:=20support=20stylistic=20esli?= =?UTF-8?q?nt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy.yml | 4 +- .github/workflows/unit-testing.yml | 4 +- .stylelintrc.cjs | 7 + eslint.config.js | 57 +++- package.json | 13 +- pnpm-lock.yaml | 182 +++++++++++++ src/components/index.ts | 16 +- src/modules/HomeFront/pages/index.vue | 22 +- .../components/MemberAssignCard.vue | 11 +- src/modules/Project/pages/list.vue | 4 +- src/utils/fileHandler.ts | 4 +- src/widgets/WorkTabs/Tabs.vue | 4 +- src/widgets/WorkTabs/store.ts | 243 +++++++++--------- src/widgets/WorkTabs/types.ts | 4 +- 14 files changed, 400 insertions(+), 175 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index bccf640..3bdea28 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -21,9 +21,9 @@ jobs: with: node-version: 16.15.x - - uses: pnpm/action-setup@v2.4.0 + - uses: pnpm/action-setup@v3 with: - version: 7.29.x + version: 8 - name: Install dependencies run: pnpm install diff --git a/.github/workflows/unit-testing.yml b/.github/workflows/unit-testing.yml index 4f279e7..3090d21 100644 --- a/.github/workflows/unit-testing.yml +++ b/.github/workflows/unit-testing.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: pnpm/action-setup@v2.4.0 + - uses: pnpm/action-setup@v3 with: - version: 7.x + version: 8 - name: Install dependencies run: pnpm i diff --git a/.stylelintrc.cjs b/.stylelintrc.cjs index 4501ba1..08523aa 100644 --- a/.stylelintrc.cjs +++ b/.stylelintrc.cjs @@ -5,6 +5,7 @@ module.exports = { 'stylelint-config-recommended-vue', 'stylelint-config-recommended-vue/scss' ], + 'plugins': ['@stylistic/stylelint-plugin'], 'ignoreFiles': ['**/*.js', '**/*.ts'], 'defaultSeverity': 'error', 'rules': { @@ -12,6 +13,12 @@ module.exports = { 'rem', 'pt' ], + '@stylistic/indentation': [ + 2, + { + 'baseIndentLevel': 0 + } + ], 'no-empty-source': null, 'block-no-empty': null, 'declaration-block-no-duplicate-custom-properties': null, diff --git a/eslint.config.js b/eslint.config.js index 867f7b7..962c529 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,31 +2,52 @@ // export default antfu() import globals from 'globals' -import { defineFlatConfig } from 'eslint-define-config'; +import { defineFlatConfig } from 'eslint-define-config' -import * as parserTypeScript from '@typescript-eslint/parser'; -import pluginTypeScript from '@typescript-eslint/eslint-plugin'; +import * as parserTypeScript from '@typescript-eslint/parser' +import pluginTypeScript from '@typescript-eslint/eslint-plugin' + +import * as parserVue from 'vue-eslint-parser' +import pluginVue from 'eslint-plugin-vue' +import js from '@eslint/js' + +import stylistic from '@stylistic/eslint-plugin' -import * as parserVue from 'vue-eslint-parser'; -import pluginVue from 'eslint-plugin-vue'; -import js from '@eslint/js'; function renameRules(rules, map) { return Object.fromEntries( Object.entries(rules).map(([key, value]) => { for (const [from, to] of Object.entries(map)) { if (key.startsWith(`${from}/`)) - return [to + key.slice(from.length), value]; + return [to + key.slice(from.length), value] } - return [key, value]; + return [key, value] }) - ); + ) } export default defineFlatConfig([ + { + ignores: [ + 'public', + 'build', + 'dist', + 'node_modules', + 'coverage', + 'src/assets/**' + ] + }, + { + plugins: { + '@stylistic': stylistic + }, + rules: { + '@stylistic/semi': ['error', 'never'], + '@stylistic/no-extra-semi': 'error' + } + }, { ...js.configs.recommended, - ignores: ['public', 'build', 'dist', 'node_modules', 'coverage', 'src/assets/**'], languageOptions: { ecmaVersion: 2022, globals: { @@ -54,7 +75,7 @@ export default defineFlatConfig([ 'constructor-super': 'error', 'default-case-last': 'error', 'dot-notation': ['error', { allowKeywords: true }], - 'eqeqeq': ['error', 'smart'], + 'eqeqeq': ['error', 'always'], 'new-cap': ['error', { capIsNew: false, newIsCap: true, properties: true }], 'no-alert': 'error', 'no-array-constructor': 'error', @@ -164,6 +185,9 @@ export default defineFlatConfig([ 'no-useless-return': 'error', 'no-var': 'error', 'no-with': 'error', + 'key-spacing': 'error', + 'space-infix-ops': 'error', + 'object-curly-spacing': ['error', 'always'], 'object-shorthand': [ 'error', 'always', @@ -239,6 +263,11 @@ export default defineFlatConfig([ } } }, + settings: { + 'import/core-modules': [ + 'uno.css' + ] + }, plugins: { '@typescript-eslint': pluginTypeScript }, @@ -252,6 +281,7 @@ export default defineFlatConfig([ '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-unused-vars': 1, + '@typescript-eslint/no-namespace': 0, '@typescript-eslint/member-delimiter-style': [ 'error', { @@ -266,8 +296,7 @@ export default defineFlatConfig([ } ], '@typescript-eslint/no-empty-function': 0, - '@typescript-eslint/no-non-null-assertion': 0, - '@typescript-eslint/semi': ['error', 'never'] + '@typescript-eslint/no-non-null-assertion': 0 } }, { @@ -325,4 +354,4 @@ export default defineFlatConfig([ }] } } -]); +]) diff --git a/package.json b/package.json index 6bcc10c..f5a5054 100644 --- a/package.json +++ b/package.json @@ -10,17 +10,17 @@ "build": "vite build", "deploy:gh-pages": "cross-env VITE_ROUTER_MODE=hash pnpm build", "preview": "vite preview --host", - "lint": "eslint ./src", - "lint:fix": "eslint --fix ./src", + "lint": "eslint .", + "lint:fix": "eslint --fix .", "test": "vitest", "test:coverage": "vitest run --coverage", "stylelint": "stylelint .scss, .vue ./src", "stylelint:fix": "stylelint --fix .scss, .vue ./src" }, "engines": { - "node": ">= 16.15.x" + "node": ">= 16.15.x", + "pnpm": ">= 8.14.x" }, - "packageManager": "pnpm@8.15.4", "keywords": [ "vue", "vue3", @@ -78,6 +78,8 @@ "@babel/core": "^7.24.4", "@babel/preset-env": "^7.24.4", "@eslint/js": "^9.0.0", + "@stylistic/eslint-plugin": "^1.7.2", + "@stylistic/stylelint-plugin": "^2.1.1", "@types/js-cookie": "^3.0.6", "@types/lodash-es": "^4.17.12", "@types/node": "^20.12.7", @@ -115,6 +117,7 @@ "unplugin-vue-components": "^0.26.0", "vite": "^5.2.9", "vite-svg-loader": "^5.1.0", - "vitest": "^1.5.0" + "vitest": "^1.5.0", + "vue-eslint-parser": "^9.4.2" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05799e0..d5b3bc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,6 +91,12 @@ devDependencies: '@eslint/js': specifier: ^9.0.0 version: 9.0.0 + '@stylistic/eslint-plugin': + specifier: ^1.7.2 + version: 1.7.2(eslint@9.0.0)(typescript@5.4.5) + '@stylistic/stylelint-plugin': + specifier: ^2.1.1 + version: 2.1.1(stylelint@16.3.1) '@types/js-cookie': specifier: ^3.0.6 version: 3.0.6 @@ -205,6 +211,9 @@ devDependencies: vitest: specifier: ^1.5.0 version: 1.5.0(@types/node@20.12.7)(jsdom@24.0.0)(sass@1.75.0) + vue-eslint-parser: + specifier: ^9.4.2 + version: 9.4.2(eslint@9.0.0) packages: @@ -2083,6 +2092,94 @@ packages: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true + /@stylistic/eslint-plugin-js@1.7.2(eslint@9.0.0): + resolution: {integrity: sha512-ZYX7C5p7zlHbACwFLU+lISVh6tdcRP/++PWegh2Sy0UgMT5kU0XkPa2tKWEtJYzZmPhJxu9LxbnWcnE/tTwSDQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: '>=8.40.0' + dependencies: + '@types/eslint': 8.56.10 + acorn: 8.11.3 + escape-string-regexp: 4.0.0 + eslint: 9.0.0 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + dev: true + + /@stylistic/eslint-plugin-jsx@1.7.2(eslint@9.0.0): + resolution: {integrity: sha512-lNZR5PR0HLJPs+kY0y8fy6KroKlYqA5PwsYWpVYWzqZWiL5jgAeUo4s9yLFYjJjzildJ5MsTVMy/xP81Qz6GXg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: '>=8.40.0' + dependencies: + '@stylistic/eslint-plugin-js': 1.7.2(eslint@9.0.0) + '@types/eslint': 8.56.10 + eslint: 9.0.0 + estraverse: 5.3.0 + picomatch: 4.0.2 + dev: true + + /@stylistic/eslint-plugin-plus@1.7.2(eslint@9.0.0)(typescript@5.4.5): + resolution: {integrity: sha512-luUfRVbBVtt0+/FNt8/76BANJEzb/nHWasHD7UUjyMrch2U9xUKpObrkTCzqBuisKek+uFupwGjqXqDP07+fQw==} + peerDependencies: + eslint: '*' + dependencies: + '@types/eslint': 8.56.10 + '@typescript-eslint/utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + eslint: 9.0.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@stylistic/eslint-plugin-ts@1.7.2(eslint@9.0.0)(typescript@5.4.5): + resolution: {integrity: sha512-szX89YPocwCe4T0eT3alj7MwEzDHt5+B+kb/vQfSSLIjI9CGgoWrgj50zU8PtaDctTh4ZieFBzU/lRmkSUo0RQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: '>=8.40.0' + dependencies: + '@stylistic/eslint-plugin-js': 1.7.2(eslint@9.0.0) + '@types/eslint': 8.56.10 + '@typescript-eslint/utils': 6.21.0(eslint@9.0.0)(typescript@5.4.5) + eslint: 9.0.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@stylistic/eslint-plugin@1.7.2(eslint@9.0.0)(typescript@5.4.5): + resolution: {integrity: sha512-TesaPR4AOCeD4unwu9gZCdTe8SsUpykriICuwXV8GFBgESuVbfVp+S8g6xTWe9ntVR803bNMtnr2UhxHW0iFqg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: '>=8.40.0' + dependencies: + '@stylistic/eslint-plugin-js': 1.7.2(eslint@9.0.0) + '@stylistic/eslint-plugin-jsx': 1.7.2(eslint@9.0.0) + '@stylistic/eslint-plugin-plus': 1.7.2(eslint@9.0.0)(typescript@5.4.5) + '@stylistic/eslint-plugin-ts': 1.7.2(eslint@9.0.0)(typescript@5.4.5) + '@types/eslint': 8.56.10 + eslint: 9.0.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@stylistic/stylelint-plugin@2.1.1(stylelint@16.3.1): + resolution: {integrity: sha512-xqHTmQZN7EbnFDW7jw0rAsdFNO4IRqvXhrh3qhUlIwF/x09Zm7kgs/ADktHxsTJYcw346PpGihsB0t4pZhpeHw==} + engines: {node: ^18.12 || >=20.9} + peerDependencies: + stylelint: ^16.0.2 + dependencies: + '@csstools/css-parser-algorithms': 2.6.1(@csstools/css-tokenizer@2.2.4) + '@csstools/css-tokenizer': 2.2.4 + '@csstools/media-query-list-parser': 2.1.9(@csstools/css-parser-algorithms@2.6.1)(@csstools/css-tokenizer@2.2.4) + is-plain-object: 5.0.0 + postcss-selector-parser: 6.0.16 + postcss-value-parser: 4.2.0 + style-search: 0.1.0 + stylelint: 16.3.1(typescript@5.4.5) + dev: true + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -2117,6 +2214,13 @@ packages: '@babel/types': 7.24.0 dev: true + /@types/eslint@8.56.10: + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} + dependencies: + '@types/estree': 1.0.5 + '@types/json-schema': 7.0.15 + dev: true + /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true @@ -2216,6 +2320,14 @@ packages: - supports-color dev: true + /@typescript-eslint/scope-manager@6.21.0: + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + dev: true + /@typescript-eslint/scope-manager@7.7.0: resolution: {integrity: sha512-/8INDn0YLInbe9Wt7dK4cXLDYp0fNHP5xKLHvZl3mOT5X17rK/YShXaiNmorl+/U4VKCVIjJnx4Ri5b0y+HClw==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2244,11 +2356,38 @@ packages: - supports-color dev: true + /@typescript-eslint/types@6.21.0: + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + engines: {node: ^16.0.0 || >=18.0.0} + dev: true + /@typescript-eslint/types@7.7.0: resolution: {integrity: sha512-G01YPZ1Bd2hn+KPpIbrAhEWOn5lQBrjxkzHkWvP6NucMXFtfXoevK82hzQdpfuQYuhkvFDeQYbzXCjR1z9Z03w==} engines: {node: ^18.18.0 || >=20.0.0} dev: true + /@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.5): + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.6.0 + ts-api-utils: 1.3.0(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/typescript-estree@7.7.0(typescript@5.4.5): resolution: {integrity: sha512-8p71HQPE6CbxIBy2kWHqM1KGrC07pk6RJn40n0DSc6bMOBBREZxSDJ+BmRzc8B5OdaMh1ty3mkuWRg4sCFiDQQ==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2271,6 +2410,25 @@ packages: - supports-color dev: true + /@typescript-eslint/utils@6.21.0(eslint@9.0.0)(typescript@5.4.5): + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.0.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) + eslint: 9.0.0 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/utils@7.7.0(eslint@9.0.0)(typescript@5.4.5): resolution: {integrity: sha512-LKGAXMPQs8U/zMRFXDZOzmMKgFv3COlxUQ+2NMPhbqgVm6R1w+nU1i4836Pmxu9jZAuIeyySNrN/6Rc657ggig==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2290,6 +2448,14 @@ packages: - typescript dev: true + /@typescript-eslint/visitor-keys@6.21.0: + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + engines: {node: ^16.0.0 || >=18.0.0} + dependencies: + '@typescript-eslint/types': 6.21.0 + eslint-visitor-keys: 3.4.3 + dev: true + /@typescript-eslint/visitor-keys@7.7.0: resolution: {integrity: sha512-h0WHOj8MhdhY8YWkzIF30R379y0NqyOHExI9N9KCzvmu05EgG4FumeYa3ccfKUSphyWkWQE1ybVrgz/Pbam6YA==} engines: {node: ^18.18.0 || >=20.0.0} @@ -4888,6 +5054,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.4: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} @@ -5212,6 +5385,11 @@ packages: engines: {node: '>=8.6'} dev: true + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + /pinia@2.1.7(typescript@5.4.5)(vue@3.4.23): resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==} peerDependencies: @@ -5725,6 +5903,10 @@ packages: js-tokens: 9.0.0 dev: true + /style-search@0.1.0: + resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} + dev: true + /stylelint-config-html@1.1.0(postcss-html@1.6.0)(stylelint@16.3.1): resolution: {integrity: sha512-IZv4IVESjKLumUGi+HWeb7skgO6/g4VMuAYrJdlqQFndgbj6WJAXPhaysvBiXefX79upBdQVumgYcdd17gCpjQ==} engines: {node: ^12 || >=14} diff --git a/src/components/index.ts b/src/components/index.ts index 5bf1806..84d4b44 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -5,14 +5,6 @@ import LayoutArea from '@/components/Layout/LayoutArea.vue' import LayoutSection from '@/components/Layout/LayoutSection.vue' import Footer from '@/components/Footer/index.vue' -const Components = { - install (app: App) { - componentList.forEach((Comp) => { - app.component(Comp.name, Comp) - }) - } -} - const componentList = [ IconFont, LayoutArea, @@ -20,4 +12,12 @@ const componentList = [ Footer ] +const Components = { + install (app: App) { + componentList.forEach((Comp) => { + app.component(Comp.name!, Comp) + }) + } +} + export default Components diff --git a/src/modules/HomeFront/pages/index.vue b/src/modules/HomeFront/pages/index.vue index 91ef217..5825dfc 100755 --- a/src/modules/HomeFront/pages/index.vue +++ b/src/modules/HomeFront/pages/index.vue @@ -76,6 +76,15 @@ defineOptions({ const router = useRouter() +const handlerPreviewDetail = (row: ProjectItem) => { + router.push({ + name: 'GroupProjectDetail', + params: { + projectId: row.id + } + }) +} + const tableData = ref>([]) const createColumns = (): DataTableColumns => { @@ -140,15 +149,6 @@ const createColumns = (): DataTableColumns => { } const tableColumns = createColumns() -const handlerPreviewDetail = (row: ProjectItem) => { - router.push({ - name: 'GroupProjectDetail', - params: { - projectId: row.id - } - }) -} - const tableLoading = ref(true) @@ -197,7 +197,7 @@ const handleCreateProject = () => { async onPositiveClick() { const isValid = await instanceRef.value.validateRules() if (!isValid) { - return Promise.reject() + return Promise.reject(new Error('请填写完整')) } dd.loading = true @@ -206,7 +206,7 @@ const handleCreateProject = () => { dd.positiveText = _positiveText dd.loading = false - return Promise.reject() + return Promise.reject(new Error('提交失败')) } }) } diff --git a/src/modules/MemberTeam/components/MemberAssignCard.vue b/src/modules/MemberTeam/components/MemberAssignCard.vue index 43916b9..0a12e49 100644 --- a/src/modules/MemberTeam/components/MemberAssignCard.vue +++ b/src/modules/MemberTeam/components/MemberAssignCard.vue @@ -122,6 +122,12 @@ const props = defineProps({ */ const selectedMembers = props.modelValue.slice() +/** + * 左侧多选表格-选中行 + */ +const checkedRowKeysRef = ref>([]) +const checkedRowsRef = ref>([]) + /** * 初始化已经勾选过的行状态 */ @@ -138,11 +144,6 @@ initSelectedMembers() */ const getRowKey = (row: TypesMemberTeam.TypeMemberPerson) => row.userId -/** - * 左侧多选表格-选中行 - */ -const checkedRowKeysRef = ref>([]) -const checkedRowsRef = ref>([]) const handleUpdateCheckedRows = (keys, rows: Array, meta) => { const isChecked = meta.action === 'check' diff --git a/src/modules/Project/pages/list.vue b/src/modules/Project/pages/list.vue index 52823a3..c9bd897 100755 --- a/src/modules/Project/pages/list.vue +++ b/src/modules/Project/pages/list.vue @@ -100,7 +100,7 @@ export default defineComponent({ positiveText: '创建', async onPositiveClick () { const isValid = await testRef.value.validateRules() - if (!isValid) return Promise.reject() + if (!isValid) return Promise.reject(new Error('表单校验失败')) dd.loading = true const { error, data } = await projectStore.createProject(formData) @@ -108,7 +108,7 @@ export default defineComponent({ dd.loading = false if (error) { - return Promise.reject() + return Promise.reject(new Error('创建失败')) } projectStore.getProjectList() diff --git a/src/utils/fileHandler.ts b/src/utils/fileHandler.ts index 41c46e5..b1ef2f3 100644 --- a/src/utils/fileHandler.ts +++ b/src/utils/fileHandler.ts @@ -28,11 +28,11 @@ export const base64UrlToFile = async (url: string, filename: string, mimeType?: while(n--){ u8arr[n] = bstr.charCodeAt(n) } - const file = new File([u8arr], filename, {type:mime || mimeType}) + const file = new File([u8arr], filename, { type: mime || mimeType }) return Promise.resolve(file) } return fetch(url) .then(res => res.arrayBuffer()) - .then(buf => new File([buf], filename, {type:mimeType})) + .then(buf => new File([buf], filename, { type: mimeType })) } diff --git a/src/widgets/WorkTabs/Tabs.vue b/src/widgets/WorkTabs/Tabs.vue index e48a351..8246652 100644 --- a/src/widgets/WorkTabs/Tabs.vue +++ b/src/widgets/WorkTabs/Tabs.vue @@ -88,6 +88,9 @@ const updateFocusActiveTab = () => { }) } + +const hasBothShadow = ref(false) + // 更新两端阴影 const updateShadow = useDebounceFn(() => { const { clientWidth, scrollWidth } = refTabList.value! @@ -110,7 +113,6 @@ watch( } ) -const hasBothShadow = ref(false) useMutationObserver(refTabList, () => { updateShadow() }, { diff --git a/src/widgets/WorkTabs/store.ts b/src/widgets/WorkTabs/store.ts index 61bb81e..77a85f3 100644 --- a/src/widgets/WorkTabs/store.ts +++ b/src/widgets/WorkTabs/store.ts @@ -78,6 +78,15 @@ const useWorkTabsStore = defineStore('work-tabs', } ) + /** + * TODO: 可能由多个值组合生成 key + * 项目 ID + baseKey + */ + const createNewCacheSpaceKey = (dynamicCacheSpacePrefixKey: string, baseKey: string) => { + // '项目ID: projectId' + baseKey + return dynamicCacheSpacePrefixKey + baseKey + } + /** * 查询某个缓存空间中是否存在目标 tab,若存在则返回 tab 数据 */ @@ -134,16 +143,61 @@ const useWorkTabsStore = defineStore('work-tabs', return tabData1.tabKey === tabData2.tabKey } + /** + * 构造一个 tab 页签数据 + */ + const createFactoryTabData = ( + { + label, + customLabel, + route + }: { + label: string + customLabel?: string | null | undefined + route: RouteLocationNormalizedLoaded + } + ): WorkTab => { + return { + label: label ?? '', + customLabel: customLabel ?? '', + tabKey: route.path, + link: route.fullPath, + routeName: route.name! + } + } /** - * TODO: 可能由多个值组合生成 key - * 项目 ID + baseKey + * 切换缓存空间 */ - const createNewCacheSpaceKey = (dynamicCacheSpacePrefixKey: string, baseKey: string) => { - // '项目ID: projectId' + baseKey - return dynamicCacheSpacePrefixKey + baseKey + const changeOtherCacheSpace = (targetCacheSpace: CacheSpace) => { + activeCacheSpaceKey.value = targetCacheSpace.cacheSpaceKey + } + + /** + * 在缓存空间内切换 tab 页签 + */ + const changeTabByCacheSpace = (tabData: WorkTab) => { + const cacheSpace = currentCacheSpace.value! + cacheSpace.activeTabKey = tabData.tabKey + router.push(tabData.link) } + /** + * 初始化构造一个缓存空间数据 + */ + const createFactoryCacheSpace = (dynamicCacheSpacePrefixKey: string, targetCacheSpace: BaseCacheSpace): CacheSpace => { + return { + + cacheSpaceKey: createNewCacheSpaceKey( + dynamicCacheSpacePrefixKey, + targetCacheSpace.cacheSpaceKey + ), + activeTabKey: null, + tabs: [] + } + } + + /** * 添加一个新的缓存空间 */ @@ -163,12 +217,6 @@ const useWorkTabsStore = defineStore('work-tabs', return cacheSpace } - /** - * 切换缓存空间 - */ - const changeOtherCacheSpace = (targetCacheSpace: CacheSpace) => { - activeCacheSpaceKey.value = targetCacheSpace.cacheSpaceKey - } /** * 将一个新的 tab 页签绑定到缓存空间中 @@ -252,6 +300,69 @@ const useWorkTabsStore = defineStore('work-tabs', changeTabByCacheSpace(_tabsMap[_tabsMap.length - 1]) } + const __subscribingClosedTab = ref>([]) + + /** + * 订阅关闭选项卡事件(按需, 若需要钩子阻止关闭 Tab 则再订阅) + */ + const registerCloseTabEvent = (beforeCloseFunction: BeforeCloseFunction) => { + + const workTab = currentActiveTabInCurrentCacheSpace.value + + const targetClosedTab = __subscribingClosedTab.value.find( + closedTabItem => ( + isEqualTab(workTab, closedTabItem.workTab) + ) + ) + + if (targetClosedTab) { + return + } + + __subscribingClosedTab.value.push({ + workTab, + beforeCloseFunction + }) + } + + /** + * 在关闭某个 Tab 前通知对应组件 Component + */ + const notifyBeforeCloseTabEvent = (workTab: WorkTab): Promise => { + const targetClosedTab = __subscribingClosedTab.value.find( + closedTabItem => ( + isEqualTab(workTab, closedTabItem.workTab) + ) + ) + const targetClosedTabIndex = __subscribingClosedTab.value.findIndex( + closedTabItem => ( + isEqualTab(workTab, closedTabItem.workTab) + ) + ) + + const SUCCESS_CLOSED = true + + if (!targetClosedTab) { + return Promise.resolve(SUCCESS_CLOSED) + } + + const p = targetClosedTab.beforeCloseFunction() + + return new Promise((resolve, reject) => { + p.then( + () => { + __subscribingClosedTab.value.splice(targetClosedTabIndex, 1) + resolve(SUCCESS_CLOSED) + } + ) + p.catch( + err => reject( + new Error(err || '关闭 Tab 失败') + ) + ) + }) + } + /** * 在缓存空间中移除某个 tab 页签 */ @@ -305,53 +416,6 @@ const useWorkTabsStore = defineStore('work-tabs', tabs.splice(0, tabs.length, onlyOneTab) } - /** - * 在缓存空间内切换 tab 页签 - */ - const changeTabByCacheSpace = (tabData: WorkTab) => { - const cacheSpace = currentCacheSpace.value! - cacheSpace.activeTabKey = tabData.tabKey - router.push(tabData.link) - } - - /** - * 初始化构造一个缓存空间数据 - */ - const createFactoryCacheSpace = (dynamicCacheSpacePrefixKey: string, targetCacheSpace: BaseCacheSpace): CacheSpace => { - return { - - cacheSpaceKey: createNewCacheSpaceKey( - dynamicCacheSpacePrefixKey, - targetCacheSpace.cacheSpaceKey - ), - activeTabKey: null, - tabs: [] - } - } - - /** - * 构造一个 tab 页签数据 - */ - const createFactoryTabData = ( - { - label, - customLabel, - route - }: { - label: string - customLabel?: string | null | undefined - route: RouteLocationNormalizedLoaded - } - ): WorkTab => { - return { - label: label ?? '', - customLabel: customLabel ?? '', - tabKey: route.path, - link: route.fullPath, - routeName: route.name! - } - } - /** ---------------------- Closed Tab Hooks | 关闭 Tab 相关钩子 ---------------------- **/ @@ -373,69 +437,6 @@ const useWorkTabsStore = defineStore('work-tabs', ) */ - const __subscribingClosedTab = ref>([]) - - /** - * 订阅关闭选项卡事件(按需, 若需要钩子阻止关闭 Tab 则再订阅) - */ - const registerCloseTabEvent = (beforeCloseFunction: BeforeCloseFunction) => { - - const workTab = currentActiveTabInCurrentCacheSpace.value - - const targetClosedTab = __subscribingClosedTab.value.find( - closedTabItem => ( - isEqualTab(workTab, closedTabItem.workTab) - ) - ) - - if (targetClosedTab) { - return - } - - __subscribingClosedTab.value.push({ - workTab, - beforeCloseFunction - }) - } - - /** - * 在关闭某个 Tab 前通知对应组件 Component - */ - const notifyBeforeCloseTabEvent = (workTab: WorkTab): Promise => { - const targetClosedTab = __subscribingClosedTab.value.find( - closedTabItem => ( - isEqualTab(workTab, closedTabItem.workTab) - ) - ) - const targetClosedTabIndex = __subscribingClosedTab.value.findIndex( - closedTabItem => ( - isEqualTab(workTab, closedTabItem.workTab) - ) - ) - - const SUCCESS_CLOSED = true - - if (!targetClosedTab) { - return Promise.resolve(SUCCESS_CLOSED) - } - - const p = targetClosedTab.beforeCloseFunction() - - return new Promise((resolve, reject) => { - p.then( - () => { - __subscribingClosedTab.value.splice(targetClosedTabIndex, 1) - resolve(SUCCESS_CLOSED) - } - ) - p.catch( - err => reject( - new Error(err || '关闭 Tab 失败') - ) - ) - }) - } - // TODO: 待实现,针对右侧关闭其他所有 Tabs 按钮的钩子的处理 /** ---------------------- Closed Tab Hooks | 关闭 Tab 相关钩子 ---------------------- **/ diff --git a/src/widgets/WorkTabs/types.ts b/src/widgets/WorkTabs/types.ts index 0cf3f3c..c2753e5 100644 --- a/src/widgets/WorkTabs/types.ts +++ b/src/widgets/WorkTabs/types.ts @@ -37,6 +37,8 @@ export interface MultipleLinkItem { export type MultipleLinks = Array +export type BeforeCloseFunction = () => Promise + /** * Closed Tab Caches | 关闭 Tab 之前的钩子缓存 @@ -45,5 +47,3 @@ export interface SubScribingClosedTabOptions { workTab: WorkTab beforeCloseFunction: BeforeCloseFunction } - -export type BeforeCloseFunction = () => Promise