diff --git a/components.d.ts b/components.d.ts index 60b00bf..e610a0e 100644 --- a/components.d.ts +++ b/components.d.ts @@ -10,8 +10,12 @@ declare module 'vue' { AButton: typeof import('ant-design-vue/es')['Button'] AButtonGroup: typeof import('ant-design-vue/es')['ButtonGroup'] AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider'] + ADatePicker: typeof import('ant-design-vue/es')['DatePicker'] + ARadioButton: typeof import('ant-design-vue/es')['RadioButton'] + ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup'] ASelect: typeof import('ant-design-vue/es')['Select'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] + ATimePicker: typeof import('ant-design-vue/es')['TimePicker'] LoginPage: typeof import('./src/views/Login/LoginPage.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/package.json b/package.json index 97eda08..906c6d4 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@alova/adapter-axios": "^2.0.5", "@ant-design/icons-vue": "^7.0.1", "@types/crypto-js": "^4.2.2", + "@types/json-stringify-safe": "^5.0.3", "@types/node": "^22.1.0", "@types/nprogress": "^0.2.3", "alova": "^3.0.5", @@ -19,18 +20,19 @@ "axios": "^1.7.3", "crypto-js": "^4.2.0", "eslint": "9.x", + "json-stringify-safe": "^5.0.1", "less": "^4.2.0", "localforage": "^1.10.0", "nprogress": "^0.2.0", "pinia": "^2.2.1", - "pinia-plugin-persistedstate": "^3.2.1", + "pinia-plugin-persistedstate-2": "^2.0.23", "unplugin-auto-import": "^0.18.2", "vite-plugin-compression": "^0.5.1", "vite-plugin-html": "^3.2.2", "vite-plugin-node-polyfills": "^0.22.0", "vue": "^3.4.31", - "vue-router": "^4.4.3", - "zipson": "^0.2.12" + "vue-i18n": "^10.0.0-beta.5", + "vue-router": "^4.4.3" }, "devDependencies": { "@eslint/js": "^9.8.0", diff --git a/src/App.vue b/src/App.vue index 68f3299..91dab37 100644 --- a/src/App.vue +++ b/src/App.vue @@ -3,5 +3,5 @@ diff --git a/src/assets/styles/global.scss b/src/assets/styles/global.scss new file mode 100644 index 0000000..3e8b625 --- /dev/null +++ b/src/assets/styles/global.scss @@ -0,0 +1,19 @@ +@import "theme"; + +body { + position: relative; + transition: background-color 0.3s, + color 0.3s; + @include useTheme { + background-color: getModeVar('bgColor'); + color: getModeVar('infoColor'); + } +} + +#nprogress .bar { + background: #48c453 !important; //自定义颜色 +} + +#nprogress .peg { + box-shadow: 0 0 10px cyan, 0 0 5px cyan !important; +} diff --git a/src/assets/styles/scroll-bar.scss b/src/assets/styles/scroll-bar.scss index cb83725..80dbdc4 100644 --- a/src/assets/styles/scroll-bar.scss +++ b/src/assets/styles/scroll-bar.scss @@ -1,4 +1,4 @@ -@import "theme"; + ::-webkit-scrollbar { width: 6px; height: 8px; @@ -21,13 +21,3 @@ ::-webkit-resizer { display: none; } - -body { - position: relative; - transition: background-color 0.3s, - color 0.3s; - @include useTheme { - background-color: getModeVar('bgColor'); - color: getModeVar('infoColor'); - } -} diff --git a/src/assets/vue.svg b/src/assets/vue.svg deleted file mode 100644 index 770e9d3..0000000 --- a/src/assets/vue.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/layout/default/DefaultLayout.vue b/src/layout/default/DefaultLayout.vue new file mode 100644 index 0000000..f6c59a9 --- /dev/null +++ b/src/layout/default/DefaultLayout.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/layout/default/Layout.vue b/src/layout/default/Layout.vue deleted file mode 100644 index dcd0b3e..0000000 --- a/src/layout/default/Layout.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/src/locales/index.ts b/src/locales/index.ts new file mode 100644 index 0000000..d13c2cd --- /dev/null +++ b/src/locales/index.ts @@ -0,0 +1,23 @@ +// index.ts +import {createI18n} from 'vue-i18n'; +import zh from './language/zh.ts'; +import en from './language/en.ts'; + +const messages = { + en, + zh +}; + + +const language = (navigator.language || 'en').toLocaleLowerCase(); // 这是获取浏览器的语言 +const i18n = createI18n({ + legacy: false, + globalInjection: true, + silentTranslationWarn: true, + locale: JSON.parse(localStorage.getItem("lang") as string).lang || language.split('-')[0] || 'zh', // 首先从缓存里拿,没有的话就用浏览器语言, + silentFallbackWarn: true, + missingWarn: true, + fallbackWarn: false, + messages +}); +export default i18n; diff --git a/src/locales/language/en.ts b/src/locales/language/en.ts new file mode 100644 index 0000000..47d51ec --- /dev/null +++ b/src/locales/language/en.ts @@ -0,0 +1,6 @@ +// en.ts +export default { + login: { + test: 'login', + } +}; diff --git a/src/locales/language/zh.ts b/src/locales/language/zh.ts new file mode 100644 index 0000000..485f3df --- /dev/null +++ b/src/locales/language/zh.ts @@ -0,0 +1,9 @@ +// zh.ts +export default { + + login: { + test: '登录', + } + + +}; diff --git a/src/main.ts b/src/main.ts index f6f4cbf..28c684e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,15 +1,13 @@ import {createApp} from 'vue'; import App from './App.vue'; import '@/assets/styles/scroll-bar.scss'; -import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; -//Pinia -import {createPinia, Pinia} from 'pinia'; +import '@/assets/styles/global.scss'; +import i18n from "@/locales/index.ts"; +import {setupStore} from "@/store/pinia.ts"; import router from "@/router/router.ts"; -const pinia: Pinia = createPinia(); -pinia.use(piniaPluginPersistedstate); - -createApp(App) - .use(router) - .use(pinia) - .mount('#app'); +const app = createApp(App); +setupStore(app); +app.use(router); +app.use(i18n); +app.mount('#app'); diff --git a/src/router/modules/test.ts b/src/router/modules/test.ts index d75fd65..94bdef0 100644 --- a/src/router/modules/test.ts +++ b/src/router/modules/test.ts @@ -4,7 +4,7 @@ export default [ name: 'test', component: () => import('@/views/TestTheme.vue'), meta: { - requiresAuth: true, + requiresAuth: false, title: '测试' } } diff --git a/src/store/index.ts b/src/store/index.ts index 90c1fe3..1cb6f3e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,9 +1,11 @@ import {useAuthStore} from '@/store/modules/userStore.ts'; import {useThemeStore} from "@/store/modules/themeStore.ts"; +import {langStore} from "@/store/modules/langStore.ts"; export default function useStore() { return { user: useAuthStore(), - theme: useThemeStore() + theme: useThemeStore(), + lang: langStore() }; } diff --git a/src/store/modules/langStore.ts b/src/store/modules/langStore.ts new file mode 100644 index 0000000..2c4e002 --- /dev/null +++ b/src/store/modules/langStore.ts @@ -0,0 +1,37 @@ +import {defineStore} from 'pinia'; +import {ref} from 'vue'; +import pinia from "@/store/pinia.ts"; + +export const langStore = defineStore( + 'lang', + () => { + const lang = ref(''); + + function setLang(value: string) { + lang.value = value; + } + + function getLang() { + return lang.value; + } + + return { + lang, + setLang, + getLang, + }; + }, + { + // 开启数据持久化 + persistedState: { + key: 'lang', + storage: localStorage, + includePaths: ["lang"], + overwrite: true, + } + } +); + +export function useLangStoreWithOut() { + return langStore(pinia); +} diff --git a/src/store/modules/themeStore.ts b/src/store/modules/themeStore.ts index 6df49f3..677e29d 100644 --- a/src/store/modules/themeStore.ts +++ b/src/store/modules/themeStore.ts @@ -2,8 +2,6 @@ import {defineStore} from 'pinia'; import {computed, ref} from 'vue'; import {theme} from 'ant-design-vue'; import variables from '@/assets/styles/colors.module.scss'; -import {handleLocalforage} from "@/utils/localforage"; -import {parse, stringify} from "zipson/lib"; /** * theme 配置 开启持久化 @@ -41,14 +39,11 @@ export const useThemeStore = defineStore( return {themeName, themeConfig, darkMode, darkModeComp, setThemeName, toggleDarkMode}; }, { - persist: { + persistedState: { key: 'theme', - paths: ['themeName','darkMode'], - storage: handleLocalforage, - serializer: { - deserialize: parse, - serialize: stringify, - }, + storage: localStorage, + includePaths: ["themeName", "darkMode"], + overwrite: true, } } ); diff --git a/src/store/modules/userStore.ts b/src/store/modules/userStore.ts index abce994..425169e 100644 --- a/src/store/modules/userStore.ts +++ b/src/store/modules/userStore.ts @@ -1,8 +1,6 @@ import {defineStore} from 'pinia'; import {ref} from 'vue'; import {User} from "@/types/user"; -import {parse, stringify} from "zipson/lib"; -import {handleLocalforage} from "@/utils/localforage"; export const useAuthStore = defineStore( @@ -31,14 +29,11 @@ export const useAuthStore = defineStore( }, { // 开启数据持久化 - persist: { + persistedState: { key: 'user', - paths: ['user'], - storage: handleLocalforage, - serializer: { - deserialize: parse, - serialize: stringify, - }, + storage: localStorage, + includePaths: ["user"], + overwrite: true, } } ); diff --git a/src/store/pinia.ts b/src/store/pinia.ts new file mode 100644 index 0000000..36181fa --- /dev/null +++ b/src/store/pinia.ts @@ -0,0 +1,17 @@ +import {createPinia, Pinia} from "pinia"; +import {createPersistedStatePlugin} from "pinia-plugin-persistedstate-2"; +import stringify from 'json-stringify-safe'; +import {App} from "vue"; + +const pinia: Pinia = createPinia(); +const installPersistedStatePlugin = createPersistedStatePlugin({ + serialize: (value) => stringify(value), + deserialize: (value) => JSON.parse(value), +}); +pinia.use((context) => installPersistedStatePlugin(context)); + +export function setupStore(app: App) { + app.use(pinia); +} + +export default pinia; diff --git a/src/utils/alova/adapter/localforageStorageAdapter.ts b/src/utils/alova/adapter/localforageStorageAdapter.ts index fc4ade0..721812d 100644 --- a/src/utils/alova/adapter/localforageStorageAdapter.ts +++ b/src/utils/alova/adapter/localforageStorageAdapter.ts @@ -1,17 +1,25 @@ -import {handleLocalforage} from "@/utils/localforage"; +import localforage from "localforage"; + export const localforageStorageAdapter = { set(key: string, value: any) { - handleLocalforage.setItem(key, value); + localforage.setItem(key, value).then(); }, get(key: string) { - const data: string = handleLocalforage.getItem(key); - return data ? JSON.parse(data) : data; + let value; + localforage.getItem(key).then((res: any) => { + if (res === null || res === undefined) { + value = ""; + } else { + value = res; + } + }); + return value ? JSON.parse(value) : value; }, remove(key: any) { - handleLocalforage.removeItem(key); + localforage.removeItem(key).then(); }, clear() { - handleLocalforage.clear().then(); + localforage.clear().then(); } }; diff --git a/src/utils/alova/service.ts b/src/utils/alova/service.ts index 54e7ed0..56d6840 100644 --- a/src/utils/alova/service.ts +++ b/src/utils/alova/service.ts @@ -6,6 +6,8 @@ import {axiosRequestAdapter} from "@alova/adapter-axios"; import {AxiosError, AxiosResponse} from "axios"; import {message} from "ant-design-vue"; import {localforageStorageAdapter} from "@/utils/alova/adapter/localforageStorageAdapter.ts"; +import {handleCode} from "@/utils/errorCode/errorCodeHandler.ts"; + export const service = createAlova({ timeout: 5000, @@ -51,103 +53,4 @@ export const service = createAlova({ } }); -function handleCode(code: number): void { - switch (code) { - case 400: - message - .open({ - content: "请求错误(400)", - type: "error", - }) - .then(); - break; - case 401: - message - .open({ - content: "未授权,请重新登录(401)", - type: "error", - }) - .then(); - break; - case 403: - message - .open({ - content: "拒绝访问(403)", - type: "error", - }) - .then(); - break; - case 404: - message - .open({ - content: "请求出错(404)", - type: "error", - }) - .then(); - break; - case 408: - message - .open({ - content: "请求超时(408)", - type: "error", - }) - .then(); - break; - case 500: - message - .open({ - content: "服务器错误(500)", - type: "error", - }) - .then(); - break; - case 501: - message - .open({ - content: "服务未实现(501)", - type: "error", - }) - .then(); - break; - case 502: - message - .open({ - content: "网络错误(502)", - type: "error", - }) - .then(); - break; - case 503: - message - .open({ - content: "服务不可用(503)", - type: "error", - }) - .then(); - break; - case 504: - message - .open({ - content: "网络超时(504)", - type: "error", - }) - .then(); - break; - case 505: - message - .open({ - content: "HTTP版本不受支持(505)", - type: "error", - }) - .then(); - break; - default: - message - .open({ - content: `连接出错(${code})!`, - type: "error", - }) - .then(); - break; - } -} + diff --git a/src/utils/axios/request.ts b/src/utils/axios/request.ts index 2be48a1..9b2edb4 100644 --- a/src/utils/axios/request.ts +++ b/src/utils/axios/request.ts @@ -3,6 +3,7 @@ import axios, {AxiosInstance, AxiosRequestConfig} from "axios"; import {message} from "ant-design-vue"; import useStore from "@/store"; +import {handleCode} from "@/utils/errorCode/errorCodeHandler.ts"; class Request { private instance: AxiosInstance | undefined; @@ -36,7 +37,7 @@ class Request { (error) => { const {response} = error; if (response) { - this.handleCode(response.status); + handleCode(response.status); } if (!window.navigator.onLine) { message.error("网络连接失败"); @@ -46,107 +47,6 @@ class Request { ); } - handleCode(code: number): void { - switch (code) { - case 400: - message - .open({ - content: "请求错误(400)", - type: "error", - }) - .then(); - break; - case 401: - message - .open({ - content: "未授权,请重新登录(401)", - type: "error", - }) - .then(); - break; - case 403: - message - .open({ - content: "拒绝访问(403)", - type: "error", - }) - .then(); - break; - case 404: - message - .open({ - content: "请求出错(404)", - type: "error", - }) - .then(); - break; - case 408: - message - .open({ - content: "请求超时(408)", - type: "error", - }) - .then(); - break; - case 500: - message - .open({ - content: "服务器错误(500)", - type: "error", - }) - .then(); - break; - case 501: - message - .open({ - content: "服务未实现(501)", - type: "error", - }) - .then(); - break; - case 502: - message - .open({ - content: "网络错误(502)", - type: "error", - }) - .then(); - break; - case 503: - message - .open({ - content: "服务不可用(503)", - type: "error", - }) - .then(); - break; - case 504: - message - .open({ - content: "网络超时(504)", - type: "error", - }) - .then(); - break; - case 505: - message - .open({ - content: "HTTP版本不受支持(505)", - type: "error", - }) - .then(); - break; - default: - message - .open({ - content: `连接出错(${code})!`, - type: "error", - }) - .then(); - break; - } - } - request(config: AxiosRequestConfig): Promise { return new Promise((resolve, reject) => { this.instance diff --git a/src/utils/errorCode/errorCodeHandler.ts b/src/utils/errorCode/errorCodeHandler.ts new file mode 100644 index 0000000..68637b7 --- /dev/null +++ b/src/utils/errorCode/errorCodeHandler.ts @@ -0,0 +1,102 @@ +import {message} from "ant-design-vue"; + +export function handleCode(code: number): void { + switch (code) { + case 400: + message + .open({ + content: "请求错误(400)", + type: "error", + }) + .then(); + break; + case 401: + message + .open({ + content: "未授权,请重新登录(401)", + type: "error", + }) + .then(); + break; + case 403: + message + .open({ + content: "拒绝访问(403)", + type: "error", + }) + .then(); + break; + case 404: + message + .open({ + content: "请求出错(404)", + type: "error", + }) + .then(); + break; + case 408: + message + .open({ + content: "请求超时(408)", + type: "error", + }) + .then(); + break; + case 500: + message + .open({ + content: "服务器错误(500)", + type: "error", + }) + .then(); + break; + case 501: + message + .open({ + content: "服务未实现(501)", + type: "error", + }) + .then(); + break; + case 502: + message + .open({ + content: "网络错误(502)", + type: "error", + }) + .then(); + break; + case 503: + message + .open({ + content: "服务不可用(503)", + type: "error", + }) + .then(); + break; + case 504: + message + .open({ + content: "网络超时(504)", + type: "error", + }) + .then(); + break; + case 505: + message + .open({ + content: "HTTP版本不受支持(505)", + type: "error", + }) + .then(); + break; + default: + message + .open({ + content: `连接出错(${code})!`, + type: "error", + }) + .then(); + break; + } +} diff --git a/src/utils/localforage/index.ts b/src/utils/localforage/index.ts deleted file mode 100644 index ad86797..0000000 --- a/src/utils/localforage/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** @format */ - -import localforage from "localforage"; -import CryptoJS from "crypto-js"; - -const SECRET_KEY = CryptoJS.enc.Utf8.parse("3333e6e143439161"); //十六位十六进制数作为密钥 -const SECRET_IV = CryptoJS.enc.Utf8.parse("e3bbe7e3ba84431a"); //十六位十六进制数作为密钥偏移量 -/** - * 加密 - * @param data - * @param output - */ -export const encrypt = (data: string, output?: undefined) => { - const dataHex = CryptoJS.enc.Utf8.parse(data); - const encrypted = CryptoJS.AES.encrypt(dataHex, SECRET_KEY, { - iv: SECRET_IV, - mode: CryptoJS.mode.CBC, - padding: CryptoJS.pad.Pkcs7, - }); - return encrypted.ciphertext.toString(output); -}; - -/** - * 解密 - * @param data - */ -export const decrypt = (data: string | unknown) => { - if (data === null) { - return; - } - const encryptedHex = CryptoJS.enc.Hex.parse(data as string); - const encryptedHexStr = CryptoJS.enc.Base64.stringify(encryptedHex); - const decrypted = CryptoJS.AES.decrypt(encryptedHexStr, SECRET_KEY, { - iv: SECRET_IV, - mode: CryptoJS.mode.CBC, - padding: CryptoJS.pad.Pkcs7, - }); - const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8); - return decryptedStr.toString(); -}; - -export const handleLocalforage = { - config: async (options?: LocalForageOptions) => localforage.config(options || {}), - setItem: (key: string, value: any) => { - localforage.setItem(key, encrypt(value)); - }, - getItem: (key: string) => { - let value: unknown = null; - localforage.getItem(key).then((res: unknown) => { - value = res; - }); - return decrypt(value) as string; - }, - removeItem: (key: string) => { - localforage.removeItem(key); - }, - clear: async () => { - return await localforage.clear(); - }, - createInstance: async (name: string) => { - return localforage.createInstance({ - name, - }); - }, -}; diff --git a/src/utils/nprogress/nprogress.ts b/src/utils/nprogress/nprogress.ts index 542cdfa..55cb050 100644 --- a/src/utils/nprogress/nprogress.ts +++ b/src/utils/nprogress/nprogress.ts @@ -5,7 +5,7 @@ import 'nprogress/nprogress.css'; NProgress.configure({ easing: 'ease', // 动画方式 speed: 300, // 递增进度条的速度 - showSpinner: false, // 是否显示加载ico + showSpinner: true, // 是否显示加载ico trickleSpeed: 200, // 自动递增间隔 minimum: 0.3, // 更改启动时使用的最小百分比 parent: 'body' //指定进度条的父容器 diff --git a/src/views/Login/LoginPage.vue b/src/views/Login/LoginPage.vue index f76e034..edd893e 100644 --- a/src/views/Login/LoginPage.vue +++ b/src/views/Login/LoginPage.vue @@ -1,20 +1,36 @@ diff --git a/src/views/TestTheme.vue b/src/views/TestTheme.vue index 4408566..d989dc4 100644 --- a/src/views/TestTheme.vue +++ b/src/views/TestTheme.vue @@ -1,28 +1,33 @@