diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..7d2af0e
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,4 @@
+# 开发环境配置
+VITE_ENV=development
+VITE_API_URL=/api
+VITE_APP_TITLE=Template Admin (Dev)
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..8238f7d
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,4 @@
+# 生产环境配置
+VITE_ENV=production
+VITE_API_URL=/prod-api
+VITE_APP_TITLE=Template Admin
diff --git a/src/api/auth/index.ts b/src/api/auth/index.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/api/index.ts b/src/api/index.ts
deleted file mode 100644
index 09c7dc9..0000000
--- a/src/api/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// API 请求封装
-export const fetchData = async (url: string) => {
- const response = await fetch(url);
- return response.json();
-};
-
diff --git a/src/components.d.ts b/src/components.d.ts
deleted file mode 100644
index faa543c..0000000
--- a/src/components.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-/* eslint-disable */
-// @ts-nocheck
-// Generated by unplugin-vue-components
-// Read more: https://github.com/vuejs/core/pull/3399
-// biome-ignore lint: disable
-export {}
-
-/* prettier-ignore */
-declare module 'vue' {
- export interface GlobalComponents {
- AdminLayout: typeof import('./components/layout/AdminLayout.vue')['default']
- AdvancedForm: typeof import('./components/form/AdvancedForm.vue')['default']
- AdvancedTable: typeof import('./components/table/AdvancedTable.vue')['default']
- Breadcrumb: typeof import('./components/common/Breadcrumb.vue')['default']
- FooterBar: typeof import('./components/layout/FooterBar.vue')['default']
- HeaderNav: typeof import('./components/layout/HeaderNav.vue')['default']
- MainContent: typeof import('./components/layout/MainContent.vue')['default']
- RouterLink: typeof import('vue-router')['RouterLink']
- RouterView: typeof import('vue-router')['RouterView']
- SideMenu: typeof import('./components/layout/SideMenu.vue')['default']
- TabsBar: typeof import('./components/layout/TabsBar.vue')['default']
- YourComponent: typeof import('./components/YourComponent.vue')['default']
- }
-}
diff --git a/src/components/fallingTable/components/searchBox.vue b/src/components/fallingTable/components/searchBox.vue
new file mode 100644
index 0000000..b03e25a
--- /dev/null
+++ b/src/components/fallingTable/components/searchBox.vue
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 重置
+
+
+
+
+
+ 搜索
+
+
+
+
+
+
+
+
+
diff --git a/src/components/fallingTable/index.vue b/src/components/fallingTable/index.vue
new file mode 100644
index 0000000..b900d3a
--- /dev/null
+++ b/src/components/fallingTable/index.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/enum/componentsEnum.ts b/src/enum/componentsEnum.ts
new file mode 100644
index 0000000..9fc74b0
--- /dev/null
+++ b/src/enum/componentsEnum.ts
@@ -0,0 +1,4 @@
+export enum ComponentsEnum {
+ Input = 'Input',
+ Select = 'Select'
+}
diff --git a/src/request/index.ts b/src/request/index.ts
new file mode 100644
index 0000000..5a2751b
--- /dev/null
+++ b/src/request/index.ts
@@ -0,0 +1,130 @@
+import type { AxiosError, AxiosInstance, AxiosRequestConfig } from 'axios'
+import axios from 'axios'
+
+// 对应后端的Result结构
+export interface Result {
+ code: number
+ msg: string
+ data: T
+ isSuccess?: boolean
+}
+
+// 对应后端的ResultCode枚举
+export enum ResultCode {
+ SUCCESS = 200,
+ BAD_REQUEST = 400,
+ UNAUTHORIZED = 401,
+ FORBIDDEN = 403,
+ NOT_FOUND = 404,
+ INTERNAL_SERVER_ERROR = 500,
+ SERVICE_UNAVAILABLE = 503,
+}
+
+// 创建axios实例
+const service: AxiosInstance = axios.create({
+ baseURL: import.meta.env.VITE_API_URL, // 从环境变量获取API基础URL
+ timeout: 10000, // 请求超时时间
+})
+
+// 请求拦截器
+service.interceptors.request.use(
+ (config) => {
+ // 在发送请求之前做些什么,例如添加token
+ const token = localStorage.getItem('token')
+ if (token) {
+ config.headers = config.headers || {}
+ config.headers['Authorization'] = token
+ }
+ return config
+ },
+ (error: AxiosError) => {
+ // 对请求错误做些什么
+ return Promise.reject(error)
+ },
+)
+
+// 响应拦截器
+service.interceptors.response.use(
+ (response) => {
+ const res = response.data
+
+ // 如果自定义code不是200,则判断为错误
+ if (res.code !== ResultCode.SUCCESS) {
+ // 处理特定的错误码
+ switch (res.code) {
+ case ResultCode.UNAUTHORIZED:
+ // 未授权,跳转到登录页
+ window.location.href = '/login'
+ break
+ case ResultCode.FORBIDDEN:
+ // 无权限,显示提示
+ console.error('无权限访问')
+ break
+ default:
+ console.error(res.msg || '请求失败')
+ }
+ return Promise.reject(new Error(res.msg || 'Error'))
+ } else {
+ // 成功请求,标记isSuccess为true
+ res.isSuccess = true
+ return res
+ }
+ },
+ (error: AxiosError) => {
+ // 对响应错误做点什么
+ let message = error.message
+ if (error.response) {
+ // 处理HTTP状态码
+ switch (error.response.status) {
+ case 400:
+ message = '请求参数错误'
+ break
+ case 401:
+ message = '未授权,请登录'
+ window.location.href = '/login'
+ break
+ case 403:
+ message = '拒绝访问'
+ break
+ case 404:
+ message = '请求资源不存在'
+ break
+ case 500:
+ message = '服务器内部错误'
+ break
+ case 503:
+ message = '服务不可用'
+ break
+ }
+ }
+ console.error(message)
+ return Promise.reject(error)
+ },
+)
+
+// 封装通用请求方法
+export function request(config: AxiosRequestConfig): Promise> {
+ return service(config)
+}
+
+// 封装GET请求
+export function get(url: string, params?: any): Promise> {
+ return request({ method: 'GET', url, params })
+}
+
+// 封装POST请求
+export function post(url: string, data?: any): Promise> {
+ return request({ method: 'POST', url, data })
+}
+
+// 封装PUT请求
+export function put(url: string, data?: any): Promise> {
+ return request({ method: 'PUT', url, data })
+}
+
+// 封装DELETE请求
+export function del(url: string, params?: any): Promise> {
+ return request({ method: 'DELETE', url, params })
+}
+
+export default service
diff --git a/src/auto-imports.d.ts b/src/types/auto-imports.d.ts
similarity index 98%
rename from src/auto-imports.d.ts
rename to src/types/auto-imports.d.ts
index 0088a0a..bd5b8f3 100644
--- a/src/auto-imports.d.ts
+++ b/src/types/auto-imports.d.ts
@@ -66,7 +66,7 @@ declare global {
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
- const useCounterStore: typeof import('./stores/counter')['useCounterStore']
+ const useCounterStore: typeof import('../stores/counter')['useCounterStore']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
@@ -153,7 +153,7 @@ declare module 'vue' {
readonly triggerRef: UnwrapRef
readonly unref: UnwrapRef
readonly useAttrs: UnwrapRef
- readonly useCounterStore: UnwrapRef
+ readonly useCounterStore: UnwrapRef
readonly useCssModule: UnwrapRef
readonly useCssVars: UnwrapRef
readonly useId: UnwrapRef
diff --git a/src/types/components.d.ts b/src/types/components.d.ts
new file mode 100644
index 0000000..c2fbbf5
--- /dev/null
+++ b/src/types/components.d.ts
@@ -0,0 +1,47 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+// biome-ignore lint: disable
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+ export interface GlobalComponents {
+ ABadge: typeof import('ant-design-vue/es')['Badge']
+ ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
+ ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
+ AButton: typeof import('ant-design-vue/es')['Button']
+ ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
+ ACol: typeof import('ant-design-vue/es')['Col']
+ AdminLayout: typeof import('./../components/layout/AdminLayout.vue')['default']
+ ADropdown: typeof import('ant-design-vue/es')['Dropdown']
+ AForm: typeof import('ant-design-vue/es')['Form']
+ AFormItem: typeof import('ant-design-vue/es')['FormItem']
+ AInput: typeof import('ant-design-vue/es')['Input']
+ AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
+ ALayout: typeof import('ant-design-vue/es')['Layout']
+ ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
+ ALayoutFooter: typeof import('ant-design-vue/es')['LayoutFooter']
+ ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
+ ALayoutSider: typeof import('ant-design-vue/es')['LayoutSider']
+ AMenu: typeof import('ant-design-vue/es')['Menu']
+ AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
+ AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
+ ARow: typeof import('ant-design-vue/es')['Row']
+ ASpace: typeof import('ant-design-vue/es')['Space']
+ ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
+ ATabPane: typeof import('ant-design-vue/es')['TabPane']
+ ATabs: typeof import('ant-design-vue/es')['Tabs']
+ Breadcrumb: typeof import('./../components/common/Breadcrumb.vue')['default']
+ FallingTable: typeof import('./../components/fallingTable/index.vue')['default']
+ FooterBar: typeof import('./../components/layout/FooterBar.vue')['default']
+ HeaderNav: typeof import('./../components/layout/HeaderNav.vue')['default']
+ MainContent: typeof import('./../components/layout/MainContent.vue')['default']
+ RouterLink: typeof import('vue-router')['RouterLink']
+ RouterView: typeof import('vue-router')['RouterView']
+ SearchBox: typeof import('./../components/fallingTable/components/searchBox.vue')['default']
+ SideMenu: typeof import('./../components/layout/SideMenu.vue')['default']
+ TabsBar: typeof import('./../components/layout/TabsBar.vue')['default']
+ }
+}
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 913b8f2..a445c1d 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -4,7 +4,7 @@
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-
+ "module": "es2020",
"paths": {
"@/*": ["./src/*"]
}
diff --git a/vite.config.ts b/vite.config.ts
index f4412f6..d398728 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -6,6 +6,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
+import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers'
// https://vite.dev/config/
export default defineConfig({
@@ -14,34 +15,34 @@ export default defineConfig({
vueJsx(),
vueDevTools(),
AutoImport({
- // 自动导入Vue相关API
imports: [
'vue',
'vue-router',
'pinia',
- // 可以添加更多需要自动导入的库
],
- // 生成自动导入的TS声明文件
- dts: 'src/auto-imports.d.ts',
- // 自动导入目录下的模块
+ resolvers: [
+ AntDesignVueResolver({
+ importStyle: 'less', // 可选: 'css' | 'less',根据你是否启用了 less 主题定制
+ }),
+ ],
+ dts: 'src/types/auto-imports.d.ts',
dirs: [
- 'src/composables',
+ 'src/components',
'src/stores',
],
- // 自动导入的API前缀
vueTemplate: true,
}),
Components({
- // 指定组件所在目录,默认为 src/components
dirs: ['src/components'],
- // 组件的有效文件扩展名
extensions: ['vue', 'tsx'],
- // 配置文件生成位置
- dts: 'src/components.d.ts',
- // 搜索子目录
+ dts: 'src/types/components.d.ts',
deep: true,
- // 允许子目录作为组件的命名空间前缀
directoryAsNamespace: false,
+ resolvers: [
+ AntDesignVueResolver({
+ importStyle: 'less', // 保持与 AutoImport 中一致
+ }),
+ ],
}),
],
resolve: {