From 57fe499080678a0672b04ba6cb6828bd9b4238e0 Mon Sep 17 00:00:00 2001 From: puzvv <1@> Date: Sat, 20 Dec 2025 01:37:06 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90=E4=BA=86?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=9B=B8=E5=85=B3=E5=89=8D=E7=AB=AF=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=9A=84=E7=BC=96=E5=86=99,=E7=BB=8F=E8=BF=87?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=83=BD=E5=A4=9F=E5=AE=9E=E7=8E=B0=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auto-imports.d.ts | 126 ++++++------ package.json | 1 + src/apis/product.ts | 14 ++ src/apis/user.ts | 96 ++++++++- src/layouts/AuthLayout.vue | 112 ++++++++++ src/layouts/MainLayout.vue | 276 +++++++++++++++++++++++++ src/main.ts | 4 +- src/pages/AboutPage.vue | 19 -- src/pages/HelpPage.vue | 77 ------- src/pages/HomePage.vue | 207 ++++++++++++++++++- src/pages/panel/MePage.vue | 15 -- src/pages/user/AddressPage.vue | 352 ++++++++++++++++++++++++++++++++ src/pages/user/LoginPage.vue | 161 +++++++++++++++ src/pages/user/ProfilePage.vue | 242 ++++++++++++++++++++++ src/pages/user/RegisterPage.vue | 172 ++++++++++++++++ src/router/index.ts | 15 +- src/stores/UserStore.ts | 16 +- src/types/address.ts | 27 +++ src/types/http.d.ts | 1 + src/types/user.ts | 36 ++++ src/utils/http.ts | 34 ++- 21 files changed, 1800 insertions(+), 203 deletions(-) create mode 100644 src/apis/product.ts create mode 100644 src/layouts/AuthLayout.vue create mode 100644 src/layouts/MainLayout.vue delete mode 100644 src/pages/AboutPage.vue delete mode 100644 src/pages/HelpPage.vue delete mode 100644 src/pages/panel/MePage.vue create mode 100644 src/pages/user/AddressPage.vue create mode 100644 src/pages/user/LoginPage.vue create mode 100644 src/pages/user/ProfilePage.vue create mode 100644 src/pages/user/RegisterPage.vue create mode 100644 src/types/address.ts create mode 100644 src/types/user.ts diff --git a/auto-imports.d.ts b/auto-imports.d.ts index cb86568..72370df 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -6,69 +6,69 @@ // biome-ignore lint: disable export {} declare global { - const EffectScope: typeof import('vue')['EffectScope'] - const computed: typeof import('vue')['computed'] - const createApp: typeof import('vue')['createApp'] - const customRef: typeof import('vue')['customRef'] - const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] - const defineComponent: typeof import('vue')['defineComponent'] - const effectScope: typeof import('vue')['effectScope'] - const getCurrentInstance: typeof import('vue')['getCurrentInstance'] - const getCurrentScope: typeof import('vue')['getCurrentScope'] - const getCurrentWatcher: typeof import('vue')['getCurrentWatcher'] - const h: typeof import('vue')['h'] - const inject: typeof import('vue')['inject'] - const isProxy: typeof import('vue')['isProxy'] - const isReactive: typeof import('vue')['isReactive'] - const isReadonly: typeof import('vue')['isReadonly'] - const isRef: typeof import('vue')['isRef'] - const isShallow: typeof import('vue')['isShallow'] - const markRaw: typeof import('vue')['markRaw'] - const nextTick: typeof import('vue')['nextTick'] - const onActivated: typeof import('vue')['onActivated'] - const onBeforeMount: typeof import('vue')['onBeforeMount'] - const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] - const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] - const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] - const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] - const onDeactivated: typeof import('vue')['onDeactivated'] - const onErrorCaptured: typeof import('vue')['onErrorCaptured'] - const onMounted: typeof import('vue')['onMounted'] - const onRenderTracked: typeof import('vue')['onRenderTracked'] - const onRenderTriggered: typeof import('vue')['onRenderTriggered'] - const onScopeDispose: typeof import('vue')['onScopeDispose'] - const onServerPrefetch: typeof import('vue')['onServerPrefetch'] - const onUnmounted: typeof import('vue')['onUnmounted'] - const onUpdated: typeof import('vue')['onUpdated'] - const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] - const provide: typeof import('vue')['provide'] - const reactive: typeof import('vue')['reactive'] - const readonly: typeof import('vue')['readonly'] - const ref: typeof import('vue')['ref'] - const resolveComponent: typeof import('vue')['resolveComponent'] - const shallowReactive: typeof import('vue')['shallowReactive'] - const shallowReadonly: typeof import('vue')['shallowReadonly'] - const shallowRef: typeof import('vue')['shallowRef'] - const toRaw: typeof import('vue')['toRaw'] - const toRef: typeof import('vue')['toRef'] - const toRefs: typeof import('vue')['toRefs'] - const toValue: typeof import('vue')['toValue'] - const triggerRef: typeof import('vue')['triggerRef'] - const unref: typeof import('vue')['unref'] - const useAttrs: typeof import('vue')['useAttrs'] - const useCssModule: typeof import('vue')['useCssModule'] - const useCssVars: typeof import('vue')['useCssVars'] - const useId: typeof import('vue')['useId'] - const useLink: typeof import('vue-router')['useLink'] - const useModel: typeof import('vue')['useModel'] - const useRoute: typeof import('vue-router')['useRoute'] - const useRouter: typeof import('vue-router')['useRouter'] - const useSlots: typeof import('vue')['useSlots'] - const useTemplateRef: typeof import('vue')['useTemplateRef'] - const watch: typeof import('vue')['watch'] - const watchEffect: typeof import('vue')['watchEffect'] - const watchPostEffect: typeof import('vue')['watchPostEffect'] - const watchSyncEffect: typeof import('vue')['watchSyncEffect'] + const EffectScope: typeof import('vue').EffectScope + const computed: typeof import('vue').computed + const createApp: typeof import('vue').createApp + const customRef: typeof import('vue').customRef + const defineAsyncComponent: typeof import('vue').defineAsyncComponent + const defineComponent: typeof import('vue').defineComponent + const effectScope: typeof import('vue').effectScope + const getCurrentInstance: typeof import('vue').getCurrentInstance + const getCurrentScope: typeof import('vue').getCurrentScope + const getCurrentWatcher: typeof import('vue').getCurrentWatcher + const h: typeof import('vue').h + const inject: typeof import('vue').inject + const isProxy: typeof import('vue').isProxy + const isReactive: typeof import('vue').isReactive + const isReadonly: typeof import('vue').isReadonly + const isRef: typeof import('vue').isRef + const isShallow: typeof import('vue').isShallow + const markRaw: typeof import('vue').markRaw + const nextTick: typeof import('vue').nextTick + const onActivated: typeof import('vue').onActivated + const onBeforeMount: typeof import('vue').onBeforeMount + const onBeforeRouteLeave: typeof import('vue-router').onBeforeRouteLeave + const onBeforeRouteUpdate: typeof import('vue-router').onBeforeRouteUpdate + const onBeforeUnmount: typeof import('vue').onBeforeUnmount + const onBeforeUpdate: typeof import('vue').onBeforeUpdate + const onDeactivated: typeof import('vue').onDeactivated + const onErrorCaptured: typeof import('vue').onErrorCaptured + const onMounted: typeof import('vue').onMounted + const onRenderTracked: typeof import('vue').onRenderTracked + const onRenderTriggered: typeof import('vue').onRenderTriggered + const onScopeDispose: typeof import('vue').onScopeDispose + const onServerPrefetch: typeof import('vue').onServerPrefetch + const onUnmounted: typeof import('vue').onUnmounted + const onUpdated: typeof import('vue').onUpdated + const onWatcherCleanup: typeof import('vue').onWatcherCleanup + const provide: typeof import('vue').provide + const reactive: typeof import('vue').reactive + const readonly: typeof import('vue').readonly + const ref: typeof import('vue').ref + const resolveComponent: typeof import('vue').resolveComponent + const shallowReactive: typeof import('vue').shallowReactive + const shallowReadonly: typeof import('vue').shallowReadonly + const shallowRef: typeof import('vue').shallowRef + const toRaw: typeof import('vue').toRaw + const toRef: typeof import('vue').toRef + const toRefs: typeof import('vue').toRefs + const toValue: typeof import('vue').toValue + const triggerRef: typeof import('vue').triggerRef + const unref: typeof import('vue').unref + const useAttrs: typeof import('vue').useAttrs + const useCssModule: typeof import('vue').useCssModule + const useCssVars: typeof import('vue').useCssVars + const useId: typeof import('vue').useId + const useLink: typeof import('vue-router').useLink + const useModel: typeof import('vue').useModel + const useRoute: typeof import('vue-router').useRoute + const useRouter: typeof import('vue-router').useRouter + const useSlots: typeof import('vue').useSlots + const useTemplateRef: typeof import('vue').useTemplateRef + const watch: typeof import('vue').watch + const watchEffect: typeof import('vue').watchEffect + const watchPostEffect: typeof import('vue').watchPostEffect + const watchSyncEffect: typeof import('vue').watchSyncEffect } // for type re-export declare global { diff --git a/package.json b/package.json index ca8a668..3b4f562 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@vueuse/core": "^13.9.0", "axios": "^1.11.0", "daisyui": "^5.0.50", + "element-plus": "^2.12.0", "motion-v": "^1.6.1", "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.4.1", diff --git a/src/apis/product.ts b/src/apis/product.ts new file mode 100644 index 0000000..29a1c78 --- /dev/null +++ b/src/apis/product.ts @@ -0,0 +1,14 @@ +import http from "../utils/http"; + +export const addProduct = (data: { + name: string; + price: number; + description: string; + image: string; +}) => { + return http({ + url: "/product", + method: "post", + data, + }); +}; diff --git a/src/apis/user.ts b/src/apis/user.ts index 51c890e..c6ca5b5 100644 --- a/src/apis/user.ts +++ b/src/apis/user.ts @@ -1,19 +1,97 @@ import http from "../utils/http"; +import { + LoginRequest, + LoginResponse, + RegisterRequest, + UserInfo, +} from "@/types/user.ts"; +import { UserAddress, UserAddressForm } from "@/types/address.ts"; /** * This is an example, please remove if not needed */ -export const getUserList = () => { - return http({ - url: "/user/list", - method: "get", - }); -}; +// export const getUserList = () => { +// return http({ +// url: "/user/list", +// method: "get", +// }); +// }; +// +// export const insertUser = (data: { account: string; password: string }) => { +// return http({ +// url: "/user/insert", +// method: "post", +// data, +// }); +// }; -export const insertUser = (data: { account: string; passowrd: string }) => { - return http({ - url: "/user/insert", +// 用户登录 +export const userLogin = (data: LoginRequest) => { + return http({ + url: "/user/login", method: "post", data, }); }; + +// 用户注册 +export const userRegister = (data: RegisterRequest) => { + return http({ + url: "/user/register", + method: "post", + data, + }); +}; + +// 获取用户信息 +export const getUserProfile = (id: number) => { + return http({ + url: `/user/profile/${id}`, + method: "get", + }); +}; + +// 获取用户地址列表 +export const getAddressList = (userId: number) => { + return http({ + url: "/user/address", + method: "get", + params: { userId }, + }); +}; + +// 添加地址 +export const addAddress = (data: UserAddressForm) => { + return http({ + url: "/user/address", + method: "post", + data, + }); +}; + +// 更新地址 +export const updateAddress = (data: UserAddressForm) => { + return http({ + url: "/user/address", + method: "put", + data, + }); +}; + +// 删除地址 +export const deleteAddress = (id: number, userId: number) => { + return http({ + url: `/user/address/${id}`, + method: "delete", + params: { userId }, + }); +}; + +// 设置默认地址 +export const setDefaultAddress = (id: number, userId: number) => { + return http({ + url: `/user/address/${id}/default`, + method: "put", + params: { userId }, + }); +}; diff --git a/src/layouts/AuthLayout.vue b/src/layouts/AuthLayout.vue new file mode 100644 index 0000000..d0869d0 --- /dev/null +++ b/src/layouts/AuthLayout.vue @@ -0,0 +1,112 @@ +NEW_FILE_CODE + + + + + diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue new file mode 100644 index 0000000..4a101bc --- /dev/null +++ b/src/layouts/MainLayout.vue @@ -0,0 +1,276 @@ + + + + + diff --git a/src/main.ts b/src/main.ts index 10fb360..c32ff21 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,8 +4,10 @@ import App from "./App.vue"; import router from "./router"; import { createPinia } from "pinia"; import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; +import ElementPlus from "element-plus"; +import "element-plus/dist/index.css"; const pinia = createPinia(); pinia.use(piniaPluginPersistedstate); -createApp(App).use(router).use(pinia).mount("#app"); +createApp(App).use(router).use(pinia).use(ElementPlus).mount("#app"); diff --git a/src/pages/AboutPage.vue b/src/pages/AboutPage.vue deleted file mode 100644 index 9016e75..0000000 --- a/src/pages/AboutPage.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/src/pages/HelpPage.vue b/src/pages/HelpPage.vue deleted file mode 100644 index 17cbabb..0000000 --- a/src/pages/HelpPage.vue +++ /dev/null @@ -1,77 +0,0 @@ - - - - - diff --git a/src/pages/HomePage.vue b/src/pages/HomePage.vue index cad4e86..6fff3c3 100644 --- a/src/pages/HomePage.vue +++ b/src/pages/HomePage.vue @@ -1,18 +1,207 @@ diff --git a/src/pages/panel/MePage.vue b/src/pages/panel/MePage.vue deleted file mode 100644 index 507d6fe..0000000 --- a/src/pages/panel/MePage.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/src/pages/user/AddressPage.vue b/src/pages/user/AddressPage.vue new file mode 100644 index 0000000..de79b51 --- /dev/null +++ b/src/pages/user/AddressPage.vue @@ -0,0 +1,352 @@ + + + + + diff --git a/src/pages/user/LoginPage.vue b/src/pages/user/LoginPage.vue new file mode 100644 index 0000000..ed547b4 --- /dev/null +++ b/src/pages/user/LoginPage.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/src/pages/user/ProfilePage.vue b/src/pages/user/ProfilePage.vue new file mode 100644 index 0000000..9830af0 --- /dev/null +++ b/src/pages/user/ProfilePage.vue @@ -0,0 +1,242 @@ + + + + + diff --git a/src/pages/user/RegisterPage.vue b/src/pages/user/RegisterPage.vue new file mode 100644 index 0000000..2cad414 --- /dev/null +++ b/src/pages/user/RegisterPage.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/src/router/index.ts b/src/router/index.ts index 32a25ef..0889fa2 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -90,9 +90,22 @@ function generateRoutesFromPages(): RouteRecordRaw[] { // Generate routes from pages directory const routes: RouteRecordRaw[] = generateRoutesFromPages(); +// 添加额外的路由配置,特别是带参数的路由 +const extraRoutes: RouteRecordRaw[] = [ + { + path: "/user/profile/:id", + name: "UserProfile", + component: () => import("@/pages/user/ProfilePage.vue"), + }, + // 可以在这里添加其他需要特殊配置的路由 +]; + +// 合并自动生成的路由和额外的路由 +const allRoutes = [...routes, ...extraRoutes]; + const router = createRouter({ history: createWebHashHistory(), - routes, + routes: allRoutes, }); export default router; diff --git a/src/stores/UserStore.ts b/src/stores/UserStore.ts index 247a0a0..d2001c1 100644 --- a/src/stores/UserStore.ts +++ b/src/stores/UserStore.ts @@ -1,18 +1,32 @@ import { ref } from "vue"; import { defineStore } from "pinia"; +import type { UserInfo } from "@/types/user"; export const useUserStore = defineStore( "user", () => { - const token = ref(""); + const token = ref(""); + const userInfo = ref(null); const setToken = (newToken: string) => { token.value = newToken; }; + const setUserInfo = (info: UserInfo) => { + userInfo.value = info; + }; + + const clearUserInfo = () => { + token.value = ""; + userInfo.value = null; + }; + return { token, + userInfo, setToken, + setUserInfo, + clearUserInfo, }; }, { diff --git a/src/types/address.ts b/src/types/address.ts new file mode 100644 index 0000000..3e2b113 --- /dev/null +++ b/src/types/address.ts @@ -0,0 +1,27 @@ +// 用户地址实体 +export interface UserAddress { + id: number; + userId: number; + receiverName: string; + receiverPhone: string; + province: string; + city: string; + district: string; + detailAddress: string; + isDefault: number; // 0-非默认,1-默认 + createTime?: string; + updateTime?: string; +} + +// 用户地址表单 +export interface UserAddressForm { + id?: number; // 地址ID,新增时可不传,修改时必传 + userId: number; // 用户ID + receiverName: string; // 收货人姓名 + receiverPhone: string; // 收货人手机号 + province: string; // 省 + city: string; // 市 + district: string; // 区/县 + detailAddress: string; // 详细地址 + isDefault: number; // 是否默认(0-非默认,1-默认) +} diff --git a/src/types/http.d.ts b/src/types/http.d.ts index b1df28d..3b0886a 100644 --- a/src/types/http.d.ts +++ b/src/types/http.d.ts @@ -2,4 +2,5 @@ declare interface Result { code: number; message: string; data: T; + timestamp: string; } diff --git a/src/types/user.ts b/src/types/user.ts new file mode 100644 index 0000000..c4a1f2c --- /dev/null +++ b/src/types/user.ts @@ -0,0 +1,36 @@ +// src/types/user.ts +// 登录请求参数类型 +export interface LoginRequest { + username: string; + password: string; +} + +// 注册请求参数类型 +export interface RegisterRequest { + username: string; + password: string; + phone: string; + email: string; +} + +// 登录响应数据类型 +export interface LoginResponse { + id: number; + username: string; + nickname: string; + token: string; +} + +// 用户信息类型 +export interface UserInfo { + id: number; + username: string; + nickname?: string; + phone?: string; + email?: string; + avatar?: string; + gender?: number; + status?: number; + createTime?: string; + updateTime?: string; +} diff --git a/src/utils/http.ts b/src/utils/http.ts index f299700..5c1cbf7 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -1,5 +1,6 @@ import axios, { type AxiosRequestConfig } from "axios"; -import { useUserStore } from "@/stores/UserStore.ts"; +import { useUserStore } from "@/stores/UserStore"; +import { ElMessage } from "element-plus"; const instance = axios.create({ baseURL: import.meta.env.VITE_SERVER, @@ -10,17 +11,34 @@ instance.interceptors.request.use((config) => { if (!store.token) { return config; } - const token = store.token; - if (!token) { - return config; - } - config.headers["token"] = token; + + // 确保 token 被正确添加到请求头 + config.headers.token = store.token; return config; }); +// 响应拦截器 +instance.interceptors.response.use( + (response) => { + return response; + }, + (error) => { + // 处理错误响应 + if (error.response?.status === 401) { + // token过期或无效 + const store = useUserStore(); + store.clearUserInfo(); + ElMessage.error("登录已过期,请重新登录"); + } else { + ElMessage.error(error.message || "请求失败"); + } + return Promise.reject(error); + }, +); + const http = async (config: AxiosRequestConfig): Promise> => { - const { data } = await instance.request>(config); - return data; + const response = await instance.request>(config); + return response.data; }; export default http;