From d348a8cc375f9702e4ead675133b20a41eee026b Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Mon, 27 May 2024 14:48:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=9A=80=20=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=A8=80=E9=85=8D=E7=BD=AE=EF=BC=8C=E4=BF=AE=E5=A4=8Dvite?= =?UTF-8?q?=E6=89=93=E5=8C=85=E6=97=A0=E6=B3=95=E8=B7=B3=E8=BD=AC=E8=B7=AF?= =?UTF-8?q?=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 126 +- .prettierrc.js | 70 +- .stylelintrc.js | 118 +- commitlint.config.js | 210 +- lint-staged.config.js | 14 +- package-lock.json | 4931 ++++++++------------------------ package.json | 8 +- src/App.vue | 31 +- src/api/mock/i18n.ts | 9 + src/i18n/index.ts | 18 +- src/i18n/modules/en.ts | 18 - src/i18n/modules/zh_CN.ts | 18 - src/main.ts | 21 +- src/mock/i18n/index.ts | 13 + src/mock/i18n/modules/en.ts | 18 + src/mock/i18n/modules/zh_cn.ts | 19 + src/service/request-mock.ts | 25 +- src/service/request.ts | 33 +- src/store/i18n.ts | 21 + src/views/layout.vue | 53 +- vite.config.ts | 185 +- 21 files changed, 1830 insertions(+), 4129 deletions(-) create mode 100644 src/api/mock/i18n.ts delete mode 100644 src/i18n/modules/en.ts delete mode 100644 src/i18n/modules/zh_CN.ts create mode 100644 src/mock/i18n/index.ts create mode 100644 src/mock/i18n/modules/en.ts create mode 100644 src/mock/i18n/modules/zh_cn.ts create mode 100644 src/store/i18n.ts diff --git a/.eslintrc.js b/.eslintrc.js index aebb857..b35949f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,69 +1,67 @@ // @see: http://eslint.cn - module.exports = { - root: true, - env: { - browser: true, - node: true, - es6: true, - }, - /* 指定如何解析语法 */ - parser: 'vue-eslint-parser', - /* 优先级低于 parse 的语法解析配置 */ - parserOptions: { - parser: '@typescript-eslint/parser', - ecmaVersion: 2020, - sourceType: 'module', - jsxPragma: 'React', - ecmaFeatures: { - jsx: true, - }, - }, - /* 继承某些已有的规则 */ - extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:prettier/recommended'], - /* - * "off" 或 0 ==> 关闭规则 - * "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行) - * "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) - */ - rules: { - // eslint (http://eslint.cn/docs/rules) - 'no-var': 'error', // 要求使用 let 或 const 而不是 var - 'no-multiple-empty-lines': ['error', { max: 1 }], // 不允许多个空行 - 'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们 - 'prefer-const': 'off', // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const - 'no-irregular-whitespace': 'off', // 禁止不规则的空白 + root: true, + env: { + browser: true, + node: true, + es6: true + }, + /* 指定如何解析语法 */ + parser: "vue-eslint-parser", + /* 优先级低于 parse 的语法解析配置 */ + parserOptions: { + parser: "@typescript-eslint/parser", + ecmaVersion: 2020, + sourceType: "module", + jsxPragma: "React", + ecmaFeatures: { + jsx: true + } + }, + /* 继承某些已有的规则 */ + extends: ["plugin:vue/vue3-recommended", "plugin:@typescript-eslint/recommended", "prettier", "plugin:prettier/recommended"], + /* + * "off" 或 0 ==> 关闭规则 + * "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行) + * "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) + */ + rules: { + // eslint (http://eslint.cn/docs/rules) + "no-var": "error", // 要求使用 let 或 const 而不是 var + "no-multiple-empty-lines": ["error", { max: 1 }], // 不允许多个空行 + "no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们 + "prefer-const": "off", // 此规则旨在标记使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const + "no-irregular-whitespace": "off", // 禁止不规则的空白 - // typeScript (https://typescript-eslint.io/rules) - '@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量 - '@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore - '@typescript-eslint/no-inferrable-types': 'off', // 可以轻松推断的显式类型可能会增加不必要的冗长 - '@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。 - '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型 - '@typescript-eslint/ban-types': 'off', // 禁止使用特定类型 - '@typescript-eslint/explicit-function-return-type': 'off', // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明 - '@typescript-eslint/no-var-requires': 'off', // 不允许在 import 语句中使用 require 语句 - '@typescript-eslint/no-empty-function': 'off', // 禁止空函数 - '@typescript-eslint/no-use-before-define': 'off', // 禁止在变量定义之前使用它们 - '@typescript-eslint/ban-ts-comment': 'off', // 禁止 @ts- 使用注释或要求在指令后进行描述 - '@typescript-eslint/no-non-null-assertion': 'off', // 不允许使用后缀运算符的非空断言(!) - '@typescript-eslint/explicit-module-boundary-types': 'off', // 要求导出函数和类的公共类方法的显式返回和参数类型 - '@typescript-eslint/no-unused-vars': 'off', + // typeScript (https://typescript-eslint.io/rules) + "@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore + "@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长 + "@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间。 + "@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 类型 + "@typescript-eslint/ban-types": "off", // 禁止使用特定类型 + "@typescript-eslint/explicit-function-return-type": "off", // 不允许对初始化为数字、字符串或布尔值的变量或参数进行显式类型声明 + "@typescript-eslint/no-var-requires": "off", // 不允许在 import 语句中使用 require 语句 + "@typescript-eslint/no-empty-function": "off", // 禁止空函数 + "@typescript-eslint/no-use-before-define": "off", // 禁止在变量定义之前使用它们 + "@typescript-eslint/ban-ts-comment": "off", // 禁止 @ts- 使用注释或要求在指令后进行描述 + "@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!) + "@typescript-eslint/explicit-module-boundary-types": "off", // 要求导出函数和类的公共类方法的显式返回和参数类型 + "@typescript-eslint/no-unused-vars": "off", - // vue (https://eslint.vuejs.org/rules) - 'vue/no-v-html': 'off', // 禁止使用 v-html - 'vue/script-setup-uses-vars': 'error', // 防止 - + + diff --git a/src/api/mock/i18n.ts b/src/api/mock/i18n.ts new file mode 100644 index 0000000..eadd323 --- /dev/null +++ b/src/api/mock/i18n.ts @@ -0,0 +1,9 @@ +import Request from "@/service/request-mock.ts"; + +export const fetchGetI18n = () => { + return Request({ + url: "/getI18n", + method: "GET" + }); +}; + diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 9ae3236..7b91edc 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -1,12 +1,16 @@ -import { createI18n } from 'vue-i18n'; -import en from './modules/en'; -import zh_CN from './modules/zh_CN'; +import { createI18n } from "vue-i18n"; +// ? 从本地存储中获取数据 +const languageData = localStorage.getItem("i18nStore"); + +// 配置多语言 const i18n = createI18n({ - legacy: false, // 如果要支持 compositionAPI,此项必须设置为 false - locale: 'zh_CN', // 设置语言类型 - globalInjection: true, // 全局注册$t方法 - messages: { zh_CN, en }, + // 如果要支持 compositionAPI,此项必须设置为 false + legacy: false, + // ? 全局注册$t方法 + globalInjection: true, + // 本地内容存在时,首次加载如果本地存储没有多语言需要再刷新 + messages: languageData ? JSON.parse(languageData).i18n : {} }); export default i18n; diff --git a/src/i18n/modules/en.ts b/src/i18n/modules/en.ts deleted file mode 100644 index 76245ed..0000000 --- a/src/i18n/modules/en.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default { - login: { - reset: 'reset', - register: 'register', - }, - home: {}, - tabs: {}, - header: { - fullScreen: 'Full Screen', - exitFullScreen: 'Exit Full Screen', - personalData: 'Personal Data', - changePassword: 'Change Password', - logout: 'Logout', - }, - tip: { - loading: 'Loading...', - }, -}; diff --git a/src/i18n/modules/zh_CN.ts b/src/i18n/modules/zh_CN.ts deleted file mode 100644 index e924748..0000000 --- a/src/i18n/modules/zh_CN.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default { - login: { - reset: '重置', - register: '登录', - }, - home: {}, - tabs: {}, - header: { - fullScreen: '全屏', - exitFullScreen: '退出全屏', - personalData: '个人信息', - changePassword: '修改密码', - logout: '退出登录', - }, - tip: { - loading: '加载中...', - }, -}; diff --git a/src/main.ts b/src/main.ts index 7201dc3..d8d010a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,12 @@ -import directives from '@/directives'; -import i18n from '@/i18n/index.ts'; -import { createPinia } from 'pinia'; -import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; -import { createApp } from 'vue'; -import App from './App.vue'; -import './assets/css/index.scss'; -import './assets/css/reset.css'; -import router from './router'; +import directives from "@/directives"; +import i18n from "@/i18n/index.ts"; +import { createPinia } from "pinia"; +import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; +import { createApp } from "vue"; +import App from "./App.vue"; +import "./assets/css/index.scss"; +import "./assets/css/reset.css"; +import router from "./router"; const pinia = createPinia(); const app = createApp(App); @@ -15,4 +15,5 @@ const app = createApp(App); pinia.use(piniaPluginPersistedstate); app.use(router).use(pinia).use(i18n).use(directives); -app.mount('#app'); +app.mount("#app"); + diff --git a/src/mock/i18n/index.ts b/src/mock/i18n/index.ts new file mode 100644 index 0000000..55db185 --- /dev/null +++ b/src/mock/i18n/index.ts @@ -0,0 +1,13 @@ +import { MockMethod } from "vite-plugin-mock"; +import { zh_cn } from "@/mock/i18n/modules/zh_cn.ts"; +import { en } from "@/mock/i18n/modules/en.ts"; + +const list: MockMethod[] = [ + { + url: "/mock/getI18n", + method: "get", + response: () => ({ data: { zh_cn, en, local: "zh_cn" } }) + } +]; + +export default list; \ No newline at end of file diff --git a/src/mock/i18n/modules/en.ts b/src/mock/i18n/modules/en.ts new file mode 100644 index 0000000..0ca0c34 --- /dev/null +++ b/src/mock/i18n/modules/en.ts @@ -0,0 +1,18 @@ +export const en = { + login: { + reset: "reset", + register: "register" + }, + home: {}, + tabs: {}, + header: { + fullScreen: "Full Screen", + exitFullScreen: "Exit Full Screen", + personalData: "Personal Data", + changePassword: "Change Password", + logout: "Logout" + }, + tip: { + loading: "Loading..." + } +}; \ No newline at end of file diff --git a/src/mock/i18n/modules/zh_cn.ts b/src/mock/i18n/modules/zh_cn.ts new file mode 100644 index 0000000..c043d35 --- /dev/null +++ b/src/mock/i18n/modules/zh_cn.ts @@ -0,0 +1,19 @@ +export const zh_cn = { + login: { + reset: "重置", + register: "登录" + }, + home: {}, + tabs: {}, + header: { + fullScreen: "全屏", + exitFullScreen: "退出全屏", + personalData: "个人信息", + changePassword: "修改密码", + logout: "退出登录" + }, + tip: { + loading: "加载中..." + } +}; + diff --git a/src/service/request-mock.ts b/src/service/request-mock.ts index aeaf0fa..d072275 100644 --- a/src/service/request-mock.ts +++ b/src/service/request-mock.ts @@ -1,25 +1,26 @@ -import { ResultEnum } from '@/enums/httpEnum'; -import axios from 'axios'; -import { BASE_MOCK } from './config/servicePort'; +import { ResultEnum } from "@/enums/httpEnum"; +import axios from "axios"; +import { BASE_MOCK } from "./config/servicePort"; const request = axios.create({ - baseURL: BASE_MOCK, - timeout: ResultEnum.TIMEOUT as number, + baseURL: BASE_MOCK, + timeout: ResultEnum.TIMEOUT as number }); // 请求拦截器 request.interceptors.request.use(config => { - return config; + return config; }); // 响应拦截器 request.interceptors.response.use( - response => { - return response.data; - }, - error => { - return Promise.reject(new Error('网络错误')); - }, + response => { + return response.data; + }, + error => { + console.log(error); + return Promise.reject(new Error("网络错误")); + } ); export default request; diff --git a/src/service/request.ts b/src/service/request.ts index a540153..6a58bbe 100644 --- a/src/service/request.ts +++ b/src/service/request.ts @@ -1,29 +1,30 @@ -import { ResultEnum } from '@/enums/httpEnum'; -import axios from 'axios'; -import { BASE_API } from './config/servicePort'; +import { ResultEnum } from "@/enums/httpEnum"; +import axios from "axios"; +import { BASE_API } from "./config/servicePort"; const request = axios.create({ - // 默认请求地址 - baseURL: BASE_API, - // 设置超时时间 - timeout: ResultEnum.TIMEOUT as number, - // 跨域允许携带凭证 - // withCredentials: true, + // 默认请求地址 + baseURL: BASE_API, + // 设置超时时间 + timeout: ResultEnum.TIMEOUT as number + // 跨域允许携带凭证 + // withCredentials: true, }); // 请求拦截器 request.interceptors.request.use(config => { - return config; + return config; }); // 响应拦截器 request.interceptors.response.use( - response => { - return response.data; - }, - error => { - return Promise.reject(new Error('网络错误')); - }, + response => { + return response.data; + }, + error => { + console.log(error); + return Promise.reject(new Error("网络错误")); + } ); export default request; diff --git a/src/store/i18n.ts b/src/store/i18n.ts new file mode 100644 index 0000000..95f7fbc --- /dev/null +++ b/src/store/i18n.ts @@ -0,0 +1,21 @@ +import { defineStore } from "pinia"; +import { fetchGetI18n } from "@/api/mock/i18n.ts"; + +export const userI18nStore = defineStore("i18nStore", { + persist: true, + state() { + return { + // ? 多语言内容 + i18n: {} as any + }; + }, + getters: {}, + actions: { + async fetchI18n() { + this.i18n = (await fetchGetI18n()).data; + } + } +}); + + + diff --git a/src/views/layout.vue b/src/views/layout.vue index d5ec34c..e70474b 100644 --- a/src/views/layout.vue +++ b/src/views/layout.vue @@ -1,30 +1,47 @@ + diff --git a/vite.config.ts b/vite.config.ts index 0b1bfcf..358d775 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,90 +1,101 @@ -import vue from '@vitejs/plugin-vue'; -import { resolve } from 'path'; -import { defineConfig, UserConfig } from 'vite'; -import legacy from '@vitejs/plugin-legacy'; -import vueJsx from '@vitejs/plugin-vue2-jsx'; -import { compression } from 'vite-plugin-compression2'; +import vue from "@vitejs/plugin-vue"; +import { resolve } from "path"; +import { defineConfig, UserConfig } from "vite"; +import legacy from "@vitejs/plugin-legacy"; +import vueJsx from "@vitejs/plugin-vue2-jsx"; +import { compression } from "vite-plugin-compression2"; +import cdn from "vite-plugin-cdn-import"; +import { viteMockServe } from "vite-plugin-mock"; export default defineConfig( - (): UserConfig => ({ - // base: './', // ? 在每个文件前加上这个前缀 - // publicDir: './static',// ? 设置静态资源目录 - envPrefix: 'BUNNY', - resolve: { - alias: { - '@': resolve(__dirname, './src'), - 'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js', - }, - }, - server: { - host: '0.0.0.0', - port: 6261, - open: true, - cors: true, - proxy: { - '/api': { - target: process.env.BUNNY_APP_URL, - changeOrigin: true, - rewrite: (path: string) => path.replace(/^\/api/, '/api'), - }, - '/mock': { - target: process.env.BUNNY_APP_URL, - changeOrigin: true, - rewrite: (path: string) => path.replace(/^\/mock/, '/mock'), - }, - }, - }, - plugins: [vue(), legacy({ targets: ['defaults', 'not IE 11'] }), vueJsx(), compression()], - esbuild: { - pure: ['console.log', 'debugger'], - jsxFactory: 'h', - jsxFragment: 'Fragment', - jsxInject: "import { h } from 'vue';", - }, - // 配置构建过程的选项,例如是否生成压缩文件和源映射 - build: { - assetsInlineLimit: 20000, - // 构建输出的目录,默认值为"dist" - outDir: 'dist', - // 用于指定使用的代码压缩工具。在这里,minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser - // esbuild 打包更快,但是不能去除 console.log,terser打包慢,但能去除 console.log - minify: 'terser', - // 用于配置 Terser 的选项 - terserOptions: { - // 用于配置压缩选项 - compress: { - drop_console: true, // 是否删除代码中的 console 语句, 默认值false - drop_debugger: true, // 是否删除代码中的 debugger 语句, 默认值false - }, - }, - // 禁用 gzip 压缩大小报告,可略微减少打包时间 - reportCompressedSize: false, - // 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时,构建过程不会生成源映射文件 - sourcemap: false, - // 用于配置 CommonJS 模块的选项 - commonjsOptions: { - // 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时,构建过程会保留 CommonJS 模块中的 try-catch 语句 - ignoreTryCatch: false, - }, - // 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时,Vite 会发出警告 - chunkSizeWarningLimit: 2000, - // 用于配置 Rollup 打包工具的选项 - rollupOptions: { - // 用于配置输出选项 - output: { - // 静态资源分类和包装 - chunkFileNames: 'js/[name]-[hash].js', // 用于指定代码分块的输出文件名格式 - entryFileNames: 'js/[name]-[hash].js', // 用于指定入口文件的输出文件名格式 - assetFileNames: 'assets/[ext]/[name]-[hash].[ext]', // 用于指定静态资源的输出文件名格式 - // ? 配置文件生成方式 - manualChunks: (id, meta) => { - // 如果是包含在包中则打包成 vendor - if (id.includes('mode_modules')) { - return 'vendor'; - } - }, - }, - }, - }, - }), + (): UserConfig => ({ + // base: './', // ? 在每个文件前加上这个前缀 + // publicDir: './static',// ? 设置静态资源目录 + envPrefix: "BUNNY", + resolve: { + alias: { + "@": resolve(__dirname, "./src"), + "vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js" + } + }, + server: { + host: "0.0.0.0", + port: 6261, + open: true, + cors: true, + proxy: { + "/api": { + target: process.env.BUNNY_APP_URL, + changeOrigin: true, + rewrite: (path: string) => path.replace(/^\/api/, "/api") + }, + "/mock": { + target: process.env.BUNNY_APP_URL, + changeOrigin: true, + rewrite: (path: string) => path.replace(/^\/mock/, "/mock") + } + } + }, + plugins: [ + vue(), + legacy({ targets: ["defaults", "not IE 11"] }), + vueJsx(), + compression(), + cdn({ + modules: [] + }), + viteMockServe({ mockPath: "src/mock" }) + ], + esbuild: { + pure: ["console.log", "debugger"], + jsxFactory: "h", + jsxFragment: "Fragment", + jsxInject: "import { h } from 'vue';" + }, + // 配置构建过程的选项,例如是否生成压缩文件和源映射 + build: { + assetsInlineLimit: 20000, + // 构建输出的目录,默认值为"dist" + outDir: "dist", + // 用于指定使用的代码压缩工具。在这里,minify 被设置为 'terser',表示使用 Terser 进行代码压缩。默认值terser + // esbuild 打包更快,但是不能去除 console.log,terser打包慢,但能去除 console.log + minify: "terser", + // 用于配置 Terser 的选项 + terserOptions: { + // 用于配置压缩选项 + compress: { + drop_console: true, // 是否删除代码中的 console 语句, 默认值false + drop_debugger: true // 是否删除代码中的 debugger 语句, 默认值false + } + }, + // 禁用 gzip 压缩大小报告,可略微减少打包时间 + reportCompressedSize: false, + // 用于指定是否生成源映射文件。源映射文件可以帮助调试和定位源代码中的错误。当设置为false时,构建过程不会生成源映射文件 + sourcemap: false, + // 用于配置 CommonJS 模块的选项 + commonjsOptions: { + // 用于指定是否忽略 CommonJS 模块中的 try-catch 语句。当设置为false时,构建过程会保留 CommonJS 模块中的 try-catch 语句 + ignoreTryCatch: false + }, + // 规定触发警告的 chunk 大小, 当某个代码分块的大小超过该限制时,Vite 会发出警告 + chunkSizeWarningLimit: 2000, + // 用于配置 Rollup 打包工具的选项 + rollupOptions: { + // 用于配置输出选项 + output: { + // 静态资源分类和包装 + chunkFileNames: "js/[name]-[hash].js", // 用于指定代码分块的输出文件名格式 + entryFileNames: "js/[name]-[hash].js", // 用于指定入口文件的输出文件名格式 + assetFileNames: "assets/[ext]/[name]-[hash].[ext]", // 用于指定静态资源的输出文件名格式 + // ? 配置文件生成方式 + manualChunks: (id, meta) => { + // 如果是包含在包中则打包成 vendor + if (id.includes("node_modules")) { + return "vendor"; + } + } + } + } + } + }) );