refactor: update component names to PascalCase and improve structure
All checks were successful
CI/CD Pipeline / playwright (push) Successful in 2m17s
CI/CD Pipeline / build-and-deploy (push) Successful in 1m50s

- Changed component names from kebab-case to PascalCase in various files for consistency.
- Updated `<router-view>` and `<transition>` to `<RouterView>` and `<Transition>` respectively in App.vue and base-layout.vue.
- Refactored AppNaiveUIProvider.vue to use PascalCase for Naive UI providers.
- Adjusted language and theme switch buttons to use PascalCase for icon components.
- Updated button components in demo pages to use PascalCase for Naive UI buttons.
- Modified ESLint rules in route message files to use perfectionist/sort-objects for better key sorting.
- Enhanced Vite plugin files to export loadPlugin functions for better plugin management.
- Improved plugin loading logic to handle errors and warnings more effectively.
This commit is contained in:
严浩
2025-12-10 22:52:23 +08:00
parent 3828f12a2d
commit 86920da611
28 changed files with 334 additions and 181 deletions

3
.ignore Normal file
View File

@@ -0,0 +1,3 @@
# VS Code 搜索忽略
pnpm-lock.yaml

41
.vscode/settings.json vendored
View File

@@ -1,19 +1,38 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.autoImportFileExcludePatterns": [
"vue-router$",
"**/src/composables/**",
"**/*-auto-imports.ts",
"**/*-auto-imports.types.ts"
],
"search.exclude": {
"public/report-ui-dist": true
},
// ============================================================
// 代码格式化相关配置
// ============================================================
"prettier.enable": true,
"eslint.enable": true,
"oxc.enable": true,
"stylelint.enable": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit",
"source.fixAll.oxc": "explicit",
"source.organizeImports": "never"
"source.fixAll.stylelint": "explicit",
"source.organizeImports": "explicit"
},
"eslint.enable": true,
"stylelint.enable": true,
"oxc.enable": true,
"editor.formatOnSave": true,
"stylelint.validate": ["css", "less", "postcss", "scss", "vue"],
"scss.lint.unknownAtRules": "ignore",
"css.lint.unknownAtRules": "ignore",
"less.lint.unknownAtRules": "ignore",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
@@ -23,7 +42,10 @@
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
// ============================================================
// i18n-ally 配置
// ============================================================
// >>>>>
"i18n-ally.readonly": false,
"i18n-ally.namespace": false /* @intlify/unplugin-vue-i18n */,
@@ -34,10 +56,7 @@
"i18n-ally.enabledParsers": ["json"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sourceLanguage": "zh-CN", // 翻译源语言 (源文件) 根据此语言文件翻译其他语言文件的变量和内容
"i18n-ally.displayLanguage": "zh-CN", // 显示语言 (显示文件/翻译文件)
"i18n-ally.displayLanguage": "zh-CN" // 显示语言 (显示文件/翻译文件)
// <<<<<
// https://github.com/copilot/share/8a1a019a-0180-80e7-8141-a40be02c4006
// "iconify.customCollectionJsonPaths": ["https://example.com/my-icons.json", "./local/icons.json"],
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.autoImportFileExcludePatterns": ["vue-router/auto$"]
}

4
auto-imports.d.ts vendored
View File

@@ -42,6 +42,7 @@ declare global {
const debouncedWatch: typeof import('@vueuse/core').debouncedWatch
const deepFreeze: typeof import('deep-freeze-es6').default
const defineAsyncComponent: typeof import('vue').defineAsyncComponent
const defineBasicLoader: typeof import('unplugin-vue-router/data-loaders/basic').defineBasicLoader
const defineComponent: typeof import('vue').defineComponent
const defineStore: typeof import('pinia').defineStore
const eagerComputed: typeof import('@vueuse/core').eagerComputed
@@ -222,7 +223,6 @@ declare global {
const useIntervalFn: typeof import('@vueuse/core').useIntervalFn
const useKeyModifier: typeof import('@vueuse/core').useKeyModifier
const useLastChanged: typeof import('@vueuse/core').useLastChanged
const useLink: typeof import('vue-router/auto').useLink
const useLoadingBar: typeof import('naive-ui').useLoadingBar
const useLocalStorage: typeof import('@vueuse/core').useLocalStorage
const useMagicKeys: typeof import('@vueuse/core').useMagicKeys
@@ -388,6 +388,7 @@ declare module 'vue' {
readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
readonly deepFreeze: UnwrapRef<typeof import('deep-freeze-es6')['default']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineBasicLoader: UnwrapRef<typeof import('unplugin-vue-router/data-loaders/basic')['defineBasicLoader']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
@@ -568,7 +569,6 @@ declare module 'vue' {
readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
readonly useLink: UnwrapRef<typeof import('vue-router/auto')['useLink']>
readonly useLoadingBar: UnwrapRef<typeof import('naive-ui')['useLoadingBar']>
readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>

View File

@@ -1,9 +1,11 @@
import type { UserConfig } from '@commitlint/types';
const Configuration: UserConfig = {
extends: ['@commitlint/config-conventional'],
formatter: '@commitlint/format',
rules: {
'body-max-line-length': [2, 'always', 500],
},
};
export default Configuration;

View File

@@ -10,6 +10,7 @@ import {
import pluginImport from 'eslint-plugin-import';
import pluginJsonc from 'eslint-plugin-jsonc';
import pluginOxlint from 'eslint-plugin-oxlint';
import pluginPerfectionist from 'eslint-plugin-perfectionist';
import pluginPlaywright from 'eslint-plugin-playwright';
import pluginVue from 'eslint-plugin-vue';
import { globalIgnores } from 'eslint/config';
@@ -24,7 +25,14 @@ export default defineConfigWithVueTs(
files: ['**/*.{ts,mts,tsx,vue}'],
},
globalIgnores(['worker-configuration.d.ts', '**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
globalIgnores([
'worker-configuration.d.ts',
'**/dist/**',
'**/dist-ssr/**',
'**/coverage/**',
'**/public/**',
'**/-----TEMP-----/**',
]),
pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
@@ -45,6 +53,13 @@ export default defineConfigWithVueTs(
{
rules: {
'@intlify/vue-i18n/no-raw-text': 'off',
'@intlify/vue-i18n/no-unused-keys': [
'error',
{
src: './src',
extensions: ['.js', '.ts', '.tsx', '.vue'],
},
],
},
settings: {
'vue-i18n': {
@@ -54,9 +69,7 @@ export default defineConfigWithVueTs(
},
},
{
plugins: {
import: pluginImport,
},
plugins: { import: pluginImport },
rules: {
'import/first': 'error',
'import/no-duplicates': 'error',
@@ -70,6 +83,8 @@ export default defineConfigWithVueTs(
},
},
{ plugins: { perfectionist: pluginPerfectionist } },
{
/**
* 启用 sort-keys 规则以强制对象键按字母顺序排序
@@ -102,7 +117,11 @@ export default defineConfigWithVueTs(
'vue/attributes-order': 'error',
'vue/multi-word-component-names': 'off',
'vue/padding-line-between-blocks': ['error', 'always'],
'vue/component-name-in-template-casing': [
'error',
'PascalCase',
{ registeredComponentsOnly: false, ignores: [] },
],
// '@stylistic/padding-line-between-statements': [
// 'error',
// { blankLine: 'always', prev: '*', next: ['const', 'let', 'var'] },

View File

@@ -14,7 +14,7 @@
},
"scripts": {
"all": "run-s lint format:prettier build-only type-check test:unit:DisableWatch",
"dev": "vite --port 4730 --host --strictPort",
"dev": "nodemon -w 'vite-plugins/**/*.ts' -e .ts -x vite --port 4730 --host --strictPort",
"build": "run-p type-check \"build-only {@}\" --",
"build-only": "vite build",
"preview": "vite preview --port 4731 --host --strictPort",
@@ -111,6 +111,7 @@
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsonc": "^2.21.0",
"eslint-plugin-oxlint": "~1.29.0",
"eslint-plugin-perfectionist": "^4.15.1",
"eslint-plugin-playwright": "^2.3.0",
"eslint-plugin-vue": "~10.6.0",
"happy-dom": "^20.0.10",
@@ -118,6 +119,7 @@
"husky": "^9.1.7",
"jsdom": "^27.2.0",
"lint-staged": "^16.2.7",
"nodemon": "^3.1.11",
"npm-run-all2": "^8.0.4",
"nprogress": "^0.2.0",
"oxlint": "~1.29.0",

133
pnpm-lock.yaml generated
View File

@@ -174,6 +174,9 @@ importers:
eslint-plugin-oxlint:
specifier: ~1.29.0
version: 1.29.0
eslint-plugin-perfectionist:
specifier: ^4.15.1
version: 4.15.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
eslint-plugin-playwright:
specifier: ^2.3.0
version: 2.3.0(eslint@9.39.1(jiti@2.6.1))
@@ -198,6 +201,9 @@ importers:
node:
specifier: runtime:^24.11.1
version: runtime:24.11.1
nodemon:
specifier: ^3.1.11
version: 3.1.11
npm-run-all2:
specifier: ^8.0.4
version: 8.0.4
@@ -3464,6 +3470,12 @@ packages:
eslint-plugin-oxlint@1.29.0:
resolution: {integrity: sha512-VmaZ1I0lXJVJokOpnV8F7e339hcFPln5EWY8KGCdTkBnrkRmAeH25GRO6F37lZEDO9e+px5xjqbkq9g3lejBdg==}
eslint-plugin-perfectionist@4.15.1:
resolution: {integrity: sha512-MHF0cBoOG0XyBf7G0EAFCuJJu4I18wy0zAoT1OHfx2o6EOx1EFTIzr2HGeuZa1kDcusoX0xJ9V7oZmaeFd773Q==}
engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
eslint: '>=8.45.0'
eslint-plugin-playwright@2.3.0:
resolution: {integrity: sha512-7UeUuIb5SZrNkrUGb2F+iwHM97kn33/huajcVtAaQFCSMUYGNFvjzRPil5C0OIppslPfuOV68M/zsisXx+/ZvQ==}
engines: {node: '>=16.9.0'}
@@ -3810,6 +3822,10 @@ packages:
resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}
engines: {node: '>= 0.4'}
has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
@@ -3884,6 +3900,9 @@ packages:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
ignore-by-default@1.0.1:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -4492,6 +4511,10 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
natural-orderby@5.0.0:
resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==}
engines: {node: '>=18'}
neverthrow@8.2.0:
resolution: {integrity: sha512-kOCT/1MCPAxY5iUV3wytNFUMUolzuwd/VF/1KCx7kf6CutrOsTie+84zTGTpgQycjvfLdBBdvBvFLqFD2c0wkQ==}
engines: {node: '>=18'}
@@ -4598,6 +4621,11 @@ packages:
version: 24.11.1
hasBin: true
nodemon@3.1.11:
resolution: {integrity: sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==}
engines: {node: '>=10'}
hasBin: true
nopt@7.2.1:
resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -4905,6 +4933,9 @@ packages:
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
pstree.remy@1.1.8:
resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@@ -5214,6 +5245,10 @@ packages:
simple-swizzle@0.2.4:
resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==}
simple-update-notifier@2.0.0:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
engines: {node: '>=10'}
simplebar-core@1.3.2:
resolution: {integrity: sha512-qKgTTuTqapjsFGkNhCjyPhysnbZGpQqNmjk0nOYjFN5ordC/Wjvg+RbYCyMSnW60l/Z0ZS82GbNltly6PMUH1w==}
@@ -5419,6 +5454,10 @@ packages:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@@ -5518,6 +5557,10 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
touch@3.1.1:
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
hasBin: true
tough-cookie@6.0.0:
resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==}
engines: {node: '>=16'}
@@ -5599,6 +5642,9 @@ packages:
unconfig@7.4.1:
resolution: {integrity: sha512-uyQ7LElcGizrOGZyIq9KU+xkuEjcRf9IpmDTkCSYv5mEeZzrXSj6rb51C0L+WTedsmAoVxW9WKrLWhSwebIM9Q==}
undefsafe@2.0.5:
resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -6288,7 +6334,7 @@ snapshots:
'@babel/types': 7.28.5
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
@@ -6454,7 +6500,7 @@ snapshots:
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.5
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
globals: 11.12.0
transitivePeerDependencies:
- supports-color
@@ -6467,7 +6513,7 @@ snapshots:
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.5
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
@@ -6943,7 +6989,7 @@ snapshots:
'@eslint/config-array@0.21.1':
dependencies:
'@eslint/object-schema': 2.1.7
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
@@ -6959,7 +7005,7 @@ snapshots:
'@eslint/eslintrc@3.3.1':
dependencies:
ajv: 6.12.6
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
espree: 10.4.0
globals: 14.0.0
ignore: 5.3.2
@@ -7015,7 +7061,7 @@ snapshots:
'@antfu/install-pkg': 1.1.0
'@antfu/utils': 9.3.0
'@iconify/types': 2.0.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
globals: 15.15.0
kolorist: 1.8.0
local-pkg: 1.1.2
@@ -7218,7 +7264,7 @@ snapshots:
'@eslint/eslintrc': 3.3.1
'@intlify/core-base': 11.2.2
'@intlify/message-compiler': 11.2.2
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
eslint: 9.39.1(jiti@2.6.1)
eslint-compat-utils: 0.6.5(eslint@9.39.1(jiti@2.6.1))
glob: 10.5.0
@@ -7254,7 +7300,7 @@ snapshots:
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@typescript-eslint/scope-manager': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
fast-glob: 3.3.3
pathe: 2.0.3
picocolors: 1.1.1
@@ -7820,7 +7866,7 @@ snapshots:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.47.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
eslint: 9.39.1(jiti@2.6.1)
typescript: 5.9.3
transitivePeerDependencies:
@@ -7830,7 +7876,7 @@ snapshots:
dependencies:
'@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3)
'@typescript-eslint/types': 8.47.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -7849,7 +7895,7 @@ snapshots:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
eslint: 9.39.1(jiti@2.6.1)
ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3
@@ -7864,7 +7910,7 @@ snapshots:
'@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3)
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/visitor-keys': 8.47.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
fast-glob: 3.3.3
is-glob: 4.0.3
minimatch: 9.0.5
@@ -9063,9 +9109,11 @@ snapshots:
dependencies:
ms: 2.1.3
debug@4.4.3:
debug@4.4.3(supports-color@5.5.0):
dependencies:
ms: 2.1.3
optionalDependencies:
supports-color: 5.5.0
decimal.js@10.6.0: {}
@@ -9448,6 +9496,16 @@ snapshots:
dependencies:
jsonc-parser: 3.3.1
eslint-plugin-perfectionist@4.15.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3):
dependencies:
'@typescript-eslint/types': 8.47.0
'@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.1(jiti@2.6.1)
natural-orderby: 5.0.0
transitivePeerDependencies:
- supports-color
- typescript
eslint-plugin-playwright@2.3.0(eslint@9.39.1(jiti@2.6.1)):
dependencies:
eslint: 9.39.1(jiti@2.6.1)
@@ -9502,7 +9560,7 @@ snapshots:
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.6
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
escape-string-regexp: 4.0.0
eslint-scope: 8.4.0
eslint-visitor-keys: 4.2.1
@@ -9817,6 +9875,8 @@ snapshots:
has-bigints@1.1.0: {}
has-flag@3.0.0: {}
has-flag@4.0.0: {}
has-property-descriptors@1.0.2:
@@ -9875,14 +9935,14 @@ snapshots:
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
@@ -9892,6 +9952,8 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
ignore-by-default@1.0.1: {}
ignore@5.3.2: {}
ignore@7.0.5: {}
@@ -10474,6 +10536,8 @@ snapshots:
natural-compare@1.4.0: {}
natural-orderby@5.0.0: {}
neverthrow@8.2.0:
optionalDependencies:
'@rollup/rollup-linux-x64-gnu': 4.53.3
@@ -10492,6 +10556,19 @@ snapshots:
node@runtime:24.11.1: {}
nodemon@3.1.11:
dependencies:
chokidar: 3.6.0
debug: 4.4.3(supports-color@5.5.0)
ignore-by-default: 1.0.1
minimatch: 3.1.2
pstree.remy: 1.1.8
semver: 7.7.3
simple-update-notifier: 2.0.0
supports-color: 5.5.0
touch: 3.1.1
undefsafe: 2.0.5
nopt@7.2.1:
dependencies:
abbrev: 2.0.0
@@ -10831,6 +10908,8 @@ snapshots:
proxy-from-env@1.1.0: {}
pstree.remy@1.1.8: {}
punycode.js@2.3.1: {}
punycode@2.3.1: {}
@@ -11201,6 +11280,10 @@ snapshots:
dependencies:
is-arrayish: 0.3.4
simple-update-notifier@2.0.0:
dependencies:
semver: 7.7.3
simplebar-core@1.3.2:
dependencies:
lodash: 4.17.21
@@ -11412,7 +11495,7 @@ snapshots:
cosmiconfig: 9.0.0(typescript@5.9.3)
css-functions-list: 3.2.3
css-tree: 3.1.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
fast-glob: 3.3.3
fastest-levenshtein: 1.0.16
file-entry-cache: 11.1.1
@@ -11450,6 +11533,10 @@ snapshots:
supports-color@10.2.2: {}
supports-color@5.5.0:
dependencies:
has-flag: 3.0.0
supports-color@7.2.0:
dependencies:
has-flag: 4.0.0
@@ -11542,6 +11629,8 @@ snapshots:
totalist@3.0.1: {}
touch@3.1.1: {}
tough-cookie@6.0.0:
dependencies:
tldts: 7.0.18
@@ -11649,6 +11738,8 @@ snapshots:
quansync: 0.2.11
unconfig-core: 7.4.1
undefsafe@2.0.5: {}
undici-types@6.21.0: {}
undici-types@7.16.0: {}
@@ -11739,7 +11830,7 @@ snapshots:
dependencies:
'@antfu/install-pkg': 1.1.0
'@iconify/utils': 3.0.2
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
local-pkg: 1.1.2
unplugin: 2.3.11
optionalDependencies:
@@ -11755,7 +11846,7 @@ snapshots:
unplugin-vue-components@30.0.0(@babel/parser@7.28.5)(vue@3.5.25(typescript@5.9.3)):
dependencies:
chokidar: 4.0.3
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
local-pkg: 1.1.2
magic-string: 0.30.21
mlly: 1.8.0
@@ -11898,7 +11989,7 @@ snapshots:
vite-plugin-inspect@11.3.3(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.1)(sass-embedded@1.93.3)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.2)):
dependencies:
ansis: 4.2.0
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
error-stack-parser-es: 1.0.5
ohash: 2.0.11
open: 10.2.0
@@ -12033,7 +12124,7 @@ snapshots:
vue-eslint-parser@10.2.0(eslint@9.39.1(jiti@2.6.1)):
dependencies:
debug: 4.4.3
debug: 4.4.3(supports-color@5.5.0)
eslint: 9.39.1(jiti@2.6.1)
eslint-scope: 8.4.0
eslint-visitor-keys: 4.2.1

View File

@@ -9,10 +9,10 @@ import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
<Toast style="z-index: 5000" />
<AppNaiveUIProvider>
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<RouterView v-slot="{ Component }">
<Transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</Transition>
</RouterView>
</AppNaiveUIProvider>
</template>

View File

@@ -42,17 +42,17 @@ declare global {
:theme="appStore.isDark ? darkTheme : null"
abstract
>
<n-loading-bar-provider>
<n-message-provider>
<n-notification-provider>
<n-modal-provider>
<n-dialog-provider>
<NLoadingBarProvider>
<NMessageProvider>
<NNotificationProvider>
<NModalProvider>
<NDialogProvider>
<slot></slot>
<ContextHolder />
</n-dialog-provider>
</n-modal-provider>
</n-notification-provider>
</n-message-provider>
</n-loading-bar-provider>
</NDialogProvider>
</NModalProvider>
</NNotificationProvider>
</NMessageProvider>
</NLoadingBarProvider>
</NConfigProvider>
</template>

View File

@@ -25,7 +25,7 @@ function handleSelect(key: string) {
<NDropdown trigger="hover" placement="bottom-end" :options="options" @select="handleSelect">
<NButton quaternary class="flex items-center gap-1">
<template #icon>
<icon-clarity-language-line w-4.5 h-4.5 />
<IconClarityLanguageLine w-4.5 h-4.5 />
</template>
<span>{{ languageLabels[locale] }}</span>
</NButton>

View File

@@ -13,17 +13,17 @@ const themeLabels: Record<AppThemeMode, string> = {
{{ themeLabels[appStore.themeMode] }}
<template #trigger>
<NButton quaternary @click="appStore.cycleTheme()">
<icon-line-md-sunny-filled-loop-to-moon-filled-loop-transition
<IconLineMdSunnyFilledLoopToMoonFilledLoopTransition
v-if="appStore.themeMode === 'light'"
w-4.5
h-4.5
/>
<icon-line-md-moon-filled-to-sunny-filled-loop-transition
<IconLineMdMoonFilledToSunnyFilledLoopTransition
v-else-if="appStore.themeMode === 'dark'"
w-4.5
h-4.5
/>
<icon-line-md-computer v-else w-4.5 h-4.5 />
<IconLineMdComputer v-else w-4.5 h-4.5 />
</NButton>
</template>
</NTooltip>

View File

@@ -15,8 +15,8 @@ function toggleCollapsed() {
{{ appStore.sidebarCollapsed ? '展开菜单' : '收起菜单' }}
<template #trigger>
<NButton ref="buttonRef" quaternary @click="toggleCollapsed">
<icon-line-md-menu-fold-right v-if="appStore.sidebarCollapsed" w-4.5 h-4.5 />
<icon-line-md-menu-fold-left v-else w-4.5 h-4.5 />
<IconLineMdMenuFoldRight v-if="appStore.sidebarCollapsed" w-4.5 h-4.5 />
<IconLineMdMenuFoldLeft v-else w-4.5 h-4.5 />
</NButton>
</template>
</NTooltip>

View File

@@ -39,7 +39,7 @@ function handleSelect(key: string) {
<template>
<NDropdown :options="options" placement="bottom-end" @select="handleSelect">
<NButton quaternary circle>
<icon-material-symbols-account-circle w-5 h-5 />
<IconMaterialSymbolsAccountCircle w-5 h-5 />
</NButton>
</NDropdown>
</template>

View File

@@ -29,11 +29,11 @@ const appStore = useAppStore();
<BaseLayoutSider />
</template>
<!-- <div>GlobalContent</div> -->
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<RouterView v-slot="{ Component }">
<Transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</Transition>
</RouterView>
<!-- <div>ThemeDrawer</div> -->
<template #footer>
<div

View File

@@ -1,9 +1,12 @@
/*eslint sort-keys: "error"*/
/*eslint perfectionist/sort-objects: "error"*/
/**
* 启用 sort-keys 规则以强制对象键按字母顺序排序
* 启用 perfectionist/sort-objects 规则以强制对象键按字母顺序排序
* 原因:
* 1. 减少多人协作时的合并冲突
* 2. 保持代码一致性,提高可维护性
*
* 运行以下命令自动修复排序:
* pnpm exec eslint --fix --no-ignore src/locales-utils/route-messages/
*/
export default {

View File

@@ -1,9 +1,12 @@
/*eslint sort-keys: "error"*/
/*eslint perfectionist/sort-objects: "error"*/
/**
* 启用 sort-keys 规则以强制对象键按字母顺序排序
* 启用 perfectionist/sort-objects 规则以强制对象键按字母顺序排序
* 原因:
* 1. 减少多人协作时的合并冲突
* 2. 保持代码一致性,提高可维护性
*
* 运行以下命令自动修复排序:
* pnpm exec eslint --fix --no-ignore src/locales-utils/route-messages/
*/
export default {

View File

@@ -128,7 +128,7 @@ const resetCount = () => {
</button>
<!-- Naive UI 按钮 -->
<n-button
<NButton
type="warning"
size="large"
block
@@ -148,7 +148,7 @@ const resetCount = () => {
</svg>
</template>
点击 +1 (Naive UI)
</n-button>
</NButton>
<!-- 重置按钮 -->
<button

View File

@@ -9,29 +9,29 @@ function setLocale(newLocale: 'en-US' | 'zh-CN') {
<template>
<div class="p-4">
<n-h1>{{ t('page.i18n-demo.title') }}</n-h1>
<NH1>{{ t('page.i18n-demo.title') }}</NH1>
<n-card :title="t('page.i18n-demo.change-language')">
<n-p>
<NCard :title="t('page.i18n-demo.change-language')">
<NP>
{{ t('page.i18n-demo.current-language') }}:
<span class="font-bold">{{ locale }}</span>
</n-p>
</NP>
<n-p>
<NP>
{{ t('page.i18n-demo.hello', { name: 'Kilo' }) }}
</n-p>
</NP>
<n-space>
<n-button type="primary" @click="setLocale('en-US')"> English </n-button>
<n-button type="success" @click="setLocale('zh-CN')"> 简体中文 </n-button>
</n-space>
</n-card>
<NSpace>
<NButton type="primary" @click="setLocale('en-US')"> English </NButton>
<NButton type="success" @click="setLocale('zh-CN')"> 简体中文 </NButton>
</NSpace>
</NCard>
<!-- 这里响应式有问题: -->
<n-p> $route.meta.title: {{ $route.meta.title }} </n-p>
<NP> $route.meta.title: {{ $route.meta.title }} </NP>
<!-- 这样才正常 -->
<n-p>
<NP>
routeI18nInstance.global.t($route.name): {{ routeI18nInstance.global.t($route.name) }}
</n-p>
</NP>
</div>
</template>

View File

@@ -2,6 +2,6 @@
<template>
<div>
<n-button @click="$router.push({ name: 'DemosCreate' })">DemosCreate</n-button>
<NButton @click="$router.push({ name: 'DemosCreate' })">DemosCreate</NButton>
</div>
</template>

View File

@@ -17,5 +17,12 @@
"@/*": ["./src/*"],
"~/*": ["./src/*"]
}
},
"vueCompilerOptions": {
"plugins": [
"vue-macros/volar",
"unplugin-vue-router/volar/sfc-route-blocks",
"unplugin-vue-router/volar/sfc-typed-router"
]
}
}

View File

@@ -2,25 +2,27 @@ import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { getPascalCaseRouteName } from 'unplugin-vue-router';
import vueRouter from 'unplugin-vue-router/vite';
import type { PluginOption } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import VueMacros from 'vue-macros/vite';
export default [
VueMacros({
plugins: {
vue: vue({ include: [/\.vue$/, /\.md$/] }),
vueJsx: vueJsx(),
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
return [
VueMacros({
plugins: {
vue: vue({ include: [/\.vue$/, /\.md$/] }),
vueJsx: vueJsx(),
// https://uvr.esm.is/guide/configuration.html
// https://github.com/posva/unplugin-vue-router
// ⚠️ Vue must be placed after VueRouter()
vueRouter: vueRouter({
exclude: ['**/__*', '**/__*/**/*'],
extensions: ['.page.vue', '.page.md'],
getRouteName: (routeNode) => getPascalCaseRouteName(routeNode),
logs: false,
routesFolder: 'src/pages',
}),
},
}),
] satisfies PluginOption;
// https://uvr.esm.is/guide/configuration.html
// https://github.com/posva/unplugin-vue-router
// ⚠️ Vue must be placed after VueRouter()
vueRouter: vueRouter({
exclude: ['**/__*', '**/__*/**/*'],
extensions: ['.page.vue', '.page.md'],
getRouteName: (routeNode) => getPascalCaseRouteName(routeNode),
logs: false,
routesFolder: 'src/pages',
}),
},
}),
];
}

View File

@@ -1,10 +1,12 @@
import type { PluginOption } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import UnoCSS from 'unocss/vite';
export default [
// https://github.com/antfu/unocss
// see uno.config.ts for config
UnoCSS({
checkImport: true,
}),
] satisfies PluginOption;
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
return [
// https://github.com/antfu/unocss
// see uno.config.ts for config
UnoCSS({
checkImport: true,
}),
];
}

View File

@@ -1,18 +1,20 @@
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
import type { PluginOption } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
export default [
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
VueI18nPlugin({
/* options */
// locale messages resource pre-compile option
include: ['src/locales/**'],
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
return [
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n
VueI18nPlugin({
/* options */
// locale messages resource pre-compile option
include: ['src/locales/**'],
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#transformi18nblock
// transformI18nBlock(src) {
// console.debug(`src :>> `, src);
// console.debug(`typeof src :>> `, typeof src);
// return src as string;
// },
}),
] satisfies PluginOption;
// https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n#transformi18nblock
// transformI18nBlock(src) {
// console.debug(`src :>> `, src);
// console.debug(`typeof src :>> `, typeof src);
// return src as string;
// },
}),
];
}

View File

@@ -1,9 +1,11 @@
import type { PluginOption } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import Markdown from 'unplugin-vue-markdown/vite';
export default [
// https://github.com/unplugin/unplugin-vue-markdown
Markdown({
headEnabled: true,
}),
] satisfies PluginOption;
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
return [
// https://github.com/unplugin/unplugin-vue-markdown
Markdown({
headEnabled: true,
}),
];
}

View File

@@ -1,17 +1,19 @@
import type { PluginOption } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import MetaLayouts from 'vite-plugin-vue-meta-layouts';
export default [
// https://github.com/dishait/vite-plugin-vue-meta-layouts
MetaLayouts({
target: 'src/layouts',
excludes: ['**/!(the-)*.vue'], // 排除非 the- 开头的文件。
metaName: 'layout',
// defaultLayout: 'sakai-vue/AppLayout',
// defaultLayout: 'naive-ui/AppLayout',
defaultLayout: 'base-layout/the-base-layout',
// !⬇️: 当设置为 `sync` 时,注意`import 'virtual:uno.css'`的顺序问题。
// importMode: 'sync', // 默认为自动处理SSG 时为 sync,非 SSG 时为 async
skipTopLevelRouteLayout: true, // 打开修复 https://github.com/JohnCampionJr/vite-plugin-vue-layouts/issues/134默认为 false 关闭
}),
] satisfies PluginOption;
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
return [
// https://github.com/dishait/vite-plugin-vue-meta-layouts
MetaLayouts({
target: 'src/layouts',
excludes: ['**/!(the-)*.vue'], // 排除非 the- 开头的文件。
metaName: 'layout',
// defaultLayout: 'sakai-vue/AppLayout',
// defaultLayout: 'naive-ui/AppLayout',
defaultLayout: 'base-layout/the-base-layout',
// !⬇️: 当设置`sync` 时,注意`import 'virtual:uno.css'`的顺序问题。
// importMode: 'sync', // 默认为自动处理SSG 时为 sync非 SSG 时为 async
skipTopLevelRouteLayout: true, // 打开修复 https://github.com/JohnCampionJr/vite-plugin-vue-layouts/issues/134默认为 false 关闭
}),
];
}

View File

@@ -76,7 +76,7 @@ export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
createUtils4uAutoImports(['primevue']),
{
'consola/browser': ['consola'],
'vue-router/auto': ['useLink'],
'unplugin-vue-router/data-loaders/basic': ['defineBasicLoader'],
'naive-ui': [
'useModal',
'useDialog',

View File

@@ -1,9 +1,11 @@
import type { PluginOption } from 'vite';
import type { ConfigEnv, PluginOption } from 'vite';
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
export default [
// https://github.com/FatehAK/vite-plugin-image-optimizer?tab=readme-ov-file#default-configuration
ViteImageOptimizer({
/* pass your config */
}),
] satisfies PluginOption;
export function loadPlugin(_configEnv: ConfigEnv): PluginOption {
return [
// https://github.com/FatehAK/vite-plugin-image-optimizer?tab=readme-ov-file#default-configuration
ViteImageOptimizer({
/* pass your config */
}),
];
}

View File

@@ -18,6 +18,8 @@ export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]>
'**/*.d.ts',
'**/*.disabled.ts',
'**/x-*.ts', // 禁用以 x- 开头的插件文件
'**/*-x.ts', // 禁用以 -x 结尾的插件文件
'**/*-X.ts', // 禁用以 -X 结尾的插件文件
'**/_*',
],
});
@@ -33,32 +35,22 @@ export async function loadPlugins(configEnv: ConfigEnv): Promise<PluginOption[]>
const imported = await import(pathToFileURL(entry).href);
const loadPlugin = imported.loadPlugin as LoadPluginFunction | undefined;
let plugin: PluginOption | undefined;
let loadMethod = '';
// 优先使用 loadPlugin 函数(接收 configEnv 参数)
if (loadPlugin && typeof loadPlugin === 'function') {
plugin = loadPlugin(configEnv);
loadMethod = 'loadPlugin';
} else if (imported.default) {
plugin = imported.default;
loadMethod = 'default';
} else {
consola.warn(`插件未导出有效内容: ${paddedName}`);
continue; // 跳过无效插件
if (!loadPlugin || typeof loadPlugin !== 'function') {
consola.warn(`插件未导出 loadPlugin 函数: ${paddedName}`);
continue;
}
if (plugin) {
const pluginArray = Array.isArray(plugin) ? plugin : [plugin];
const validPlugins = pluginArray.filter(Boolean); // 过滤掉 null/undefined
const pluginCount = validPlugins.length;
const plugin = loadPlugin(configEnv);
const pluginArray = Array.isArray(plugin) ? plugin : [plugin];
const validPlugins = pluginArray.filter(Boolean);
const pluginCount = validPlugins.length;
if (pluginCount > 0) {
plugins.push(...validPlugins);
consola.success(`${paddedName}${pluginCount} 个实例 (${loadMethod})`);
} else {
consola.info(`${paddedName} 返回了空数组或无效值`);
}
if (pluginCount > 0) {
plugins.push(...validPlugins);
consola.success(`${paddedName}${pluginCount} 个实例`);
} else {
consola.info(`${paddedName} 返回了空数组或无效值`);
}
}