diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..d707131 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +VITE_API_BASE_URL_DEV=http://localhost:3000/api \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..53ff7e0 --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +VITE_API_BASE_URL_PROD=https://api.yourdomain.com \ No newline at end of file diff --git a/package.json b/package.json index 54c690d..3c380e4 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "format": "prettier --write src/" }, "dependencies": { + "axios": "^1.7.7", "lru-cache": "^11.0.1", "lucide-vue-next": "^0.445.0", "pinia": "^2.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3f3f4f..1c9524e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,6 +12,7 @@ specifiers: '@vue/eslint-config-typescript': ^13.0.0 '@vue/tsconfig': ^0.5.1 autoprefixer: ^10.4.20 + axios: ^1.7.7 eslint: ^8.57.1 eslint-plugin-vue: ^9.28.0 glob: ^11.0.0 @@ -32,6 +33,7 @@ specifiers: vue-tsc: ^2.1.6 dependencies: + axios: 1.7.7 lru-cache: 11.0.1 lucide-vue-next: 0.445.0_vue@3.5.8 pinia: 2.2.2_typescript@5.4.5+vue@3.5.8 @@ -1391,6 +1393,10 @@ packages: engines: {node: '>=8'} dev: true + /asynckit/0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /autoprefixer/10.4.20_postcss@8.4.47: resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -1407,6 +1413,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /axios/1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -1529,6 +1545,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /commander/4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1609,6 +1632,11 @@ packages: engines: {node: '>=12'} dev: true + /delayed-stream/1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /didyoumean/1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} dev: true @@ -1929,6 +1957,16 @@ packages: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} dev: true + /follow-redirects/1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + /foreground-child/3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -1937,6 +1975,15 @@ packages: signal-exit: 4.1.0 dev: true + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fraction.js/4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true @@ -2365,6 +2412,18 @@ packages: picomatch: 2.3.1 dev: true + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /mimic-fn/4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} @@ -2731,6 +2790,10 @@ packages: hasBin: true dev: true + /proxy-from-env/1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /punycode/2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} diff --git a/src/assets/font/DingTalk.ttf b/src/assets/font/DingTalk.ttf new file mode 100644 index 0000000..a5b78e6 Binary files /dev/null and b/src/assets/font/DingTalk.ttf differ diff --git a/src/assets/main.css b/src/assets/main.css index bd6213e..1755ca5 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,3 +1,12 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file +@import 'tailwindcss/base'; +@import 'tailwindcss/components'; +@import 'tailwindcss/utilities'; + +@font-face { + font-family: 'DingTalk'; + src: url('../assets/font/DingTalk.ttf') format('truetype'); +} + +* { + font-family: 'DingTalk', sans-serif !important; +} diff --git a/src/components/AlertComponent.vue b/src/components/AlertComponent.vue new file mode 100644 index 0000000..3f93489 --- /dev/null +++ b/src/components/AlertComponent.vue @@ -0,0 +1,124 @@ + + + + + \ No newline at end of file diff --git a/src/utils/api.ts b/src/utils/api.ts new file mode 100644 index 0000000..8cacc8d --- /dev/null +++ b/src/utils/api.ts @@ -0,0 +1,66 @@ +import axios from 'axios' + +// 从环境变量中获取 API 基础 URL +const baseURL = + import.meta.env.MODE === 'production' + ? import.meta.env.VITE_API_BASE_URL_PROD + : import.meta.env.VITE_API_BASE_URL_DEV +console.log(baseURL) +console.log(import.meta.env.MODE) + +// 创建 axios 实例 +const api = axios.create({ + baseURL, + timeout: 10000, // 请求超时时间 + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +api.interceptors.request.use( + (config) => { + // 从 localStorage 获取 token + const token = localStorage.getItem('token') + if (token) { + config.headers['Authorization'] = `Bearer ${token}` + } + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 +api.interceptors.response.use( + (response) => { + return response + }, + (error) => { + // 处理错误响应 + if (error.response) { + switch (error.response.status) { + case 401: + // 未授权,可能需要重新登录 + console.error('未授权,请重新登录') + break + case 403: + // 禁止访问 + console.error('禁止访问') + break + case 404: + // 未找到 + console.error('请求的资源不存在') + break + default: + console.error('发生错误:', error.response.data) + } + } else { + console.error('发生错误:', error.message) + } + return Promise.reject(error) + } +) + +export default api diff --git a/src/views/SendFileView.vue b/src/views/SendFileView.vue index 9568bc2..4a0e4d4 100644 --- a/src/views/SendFileView.vue +++ b/src/views/SendFileView.vue @@ -1,10 +1,12 @@