uiDesign.md 42 KB

宠物服务管理系统 — 客户端详细设计文档

1. 技术栈

技术 版本 用途
Vue 3 ^3.5.13 前端框架(Composition API + <script setup>)
Vite ^6.3.5 构建工具
TypeScript ~5.8.3 类型安全
Element Plus ^2.13.6 UI 组件库
Pinia ^3.0.4 状态管理
Pinia Persistedstate ^4.7.1 Store 持久化
Vue Router ^4.6.4 路由管理
Axios ^1.15.2 HTTP 请求
Orval 7.0 OpenAPI → API 代码生成
Prettier ^3.8.3 代码格式化

2. 项目结构(完整)

ui/
├── index.html
├── package.json
├── vite.config.ts              # Vite 配置(代理 /api → localhost:8080)
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
├── orval.config.ts             # Orval 代码生成配置
├── .gitignore
├── public/
│   ├── logo.svg
│   └── vite.svg
├── src/
│   ├── main.ts                 # 入口文件
│   ├── App.vue                 # 根组件(<router-view />)
│   ├── style.css               # 全局样式
│   ├── vite-env.d.ts
│   │
│   ├── type/
│   │   └── index.ts            # 自定义类型定义
│   │       - User { id, name, avatar, role }
│   │       - LoginUser { isLogin, user? }
│   │
│   ├── util/
│   │   ├── index.ts            # 工具函数(当前为空)
│   │   └── axios-instance.ts   # Axios 实例 + 拦截器配置
│   │       - withCredentials: true(自动携带 Cookie)
│   │       - 响应拦截器:统一错误处理 + 401 → /login
│   │       - customAxiosInstance(供 Orval 使用)
│   │
│   ├── api/                    # Orval 生成的 API 代码
│   │   ├── auth-controller.ts  # 认证 API
│   │   ├── user-controller.ts  # 用户管理 API
│   │   ├── pet-controller.ts   # 宠物 API(待生成)
│   │   ├── appointment-controller.ts  # 预约 API(待生成)
│   │   ├── boarding-room-controller.ts # 房态 API(待生成)
│   │   ├── package-controller.ts       # 套餐 API(待生成)
│   │   ├── schedule-controller.ts      # 排班 API(待生成)
│   │   └── models/             # 数据模型类型定义
│   │       ├── index.ts        # 统一导出
│   │       ├── response.ts     # 统一响应
│   │       ├── responseUserVo.ts
│   │       ├── responseBoolean.ts
│   │       ├── responsePageVoListUserVo.ts
│   │       ├── responseListFieldError.ts
│   │       ├── userVo.ts
│   │       ├── userDto.ts
│   │       ├── loginDto.ts
│   │       ├── registerDto.ts
│   │       ├── updateUserPasswordDto.ts
│   │       ├── updateUserAvatarDto.ts
│   │       ├── updateUserStatusDto.ts
│   │       ├── deleteByIdParams.ts
│   │       ├── queryByPageParams.ts
│   │       ├── pageVoListUserVo.ts
│   │       └── fieldError.ts
│   │
│   ├── store/                  # Pinia 状态管理
│   │   ├── index.ts            # 统一导出
│   │   ├── user.ts             # useLoginUserStore
│   │   └── meta.ts             # useMetaStore
│   │
│   ├── router/
│   │   └── index.ts            # 路由配置 + 导航守卫
│   │
│   ├── layout/
│   │   ├── UserLayout.vue      # 用户侧布局(水平 TopNav)
│   │   └── AdminLayout.vue     # 商家后台侧布局(侧边栏 + 顶栏)
│   │
│   ├── view/                   # 页面组件
│   │   ├── HomeView.vue        # 首页
│   │   ├── LoginView.vue       # 登录/注册(tab 切换)
│   │   ├── AboutView.vue       # 关于页面
│   │   ├── UserView.vue        # 用户管理(后台)
│   │   │
│   │   ├── booking/            # 服务预约模块
│   │   │   ├── BookingView.vue           # 预约首页(选择服务类型)
│   │   │   ├── BoardingBookingView.vue   # 寄养预约表单
│   │   │   └── GroomingBookingView.vue   # 洗护预约表单
│   │   │
│   │   ├── order/              # 订单管理模块
│   │   │   ├── OrderListView.vue         # 我的订单列表
│   │   │   └── OrderDetailView.vue       # 订单详情
│   │   │
│   │   ├── pet/                # 宠物档案模块
│   │   │   ├── PetListView.vue           # 宠物列表
│   │   │   ├── PetCreateView.vue         # 新增宠物
│   │   │   ├── PetDetailView.vue         # 宠物详情(含疫苗/驱虫)
│   │   │   └── PetEditView.vue           # 编辑宠物
│   │   │
│   │   ├── profile/            # 个人中心模块
│   │   │   ├── ProfileView.vue           # 个人信息展示
│   │   │   ├── ProfileEditView.vue       # 修改个人资料
│   │   │   └── PasswordEditView.vue      # 修改密码
│   │   │
│   │   └── admin/              # 商家后台模块
│   │       ├── AdminOrderListView.vue     # 订单审核列表
│   │       ├── AdminOrderDetailView.vue   # 订单审核详情
│   │       ├── AdminRoomCalendarView.vue  # 房态日历管理
│   │       ├── AdminScheduleListView.vue  # 排班管理列表
│   │       ├── AdminPackageListView.vue   # 套餐配置列表
│   │       ├── AdminPackageCreateView.vue # 新增套餐
│   │       ├── AdminPackageEditView.vue   # 编辑套餐
│   │       ├── AdminUserListView.vue      # 用户管理列表(复用的 UserView)
│   │       └── AdminUserDetailView.vue    # 用户详情(含宠物档案)
│   │
│   └── components/             # 公共组件
│       ├── PaymentDialog.vue   # 模拟支付弹窗
│       ├── RoomCalendar.vue    # 房态日历组件
│       ├── PetSelector.vue     # 宠物选择器
│       └── ...

3. 路由详细设计

3.1 路由配置

// router/index.ts
const routes = [
  // 公共路由
  {
    path: '/login',
    name: 'login',
    component: LoginView
  },

  // 用户侧路由(嵌套在 UserLayout 下)
  {
    path: '/',
    component: UserLayout,
    children: [
      { path: '', name: 'home', component: HomeView },
      { path: 'about', name: 'about', component: AboutView },
      // 预约
      { path: 'booking', name: 'booking', component: BookingView },
      { path: 'booking/boarding', name: 'boardingBooking', component: BoardingBookingView },
      { path: 'booking/grooming', name: 'groomingBooking', component: GroomingBookingView },
      // 订单
      { path: 'orders', name: 'orderList', component: OrderListView },
      { path: 'orders/:id', name: 'orderDetail', component: OrderDetailView },
      // 宠物
      { path: 'pets', name: 'petList', component: PetListView },
      { path: 'pets/new', name: 'petCreate', component: PetCreateView },
      { path: 'pets/:id', name: 'petDetail', component: PetDetailView },
      { path: 'pets/:id/edit', name: 'petEdit', component: PetEditView },
      // 个人中心
      { path: 'profile', name: 'profile', component: ProfileView },
      { path: 'profile/edit', name: 'profileEdit', component: ProfileEditView },
      { path: 'profile/password', name: 'passwordEdit', component: PasswordEditView },
    ]
  },

  // 商家后台路由(嵌套在 AdminLayout 下)
  {
    path: '/admin',
    component: AdminLayout,
    meta: { requiresAdmin: true },
    children: [
      { path: '', name: 'adminDashboard', component: AdminDashboardView },
      { path: 'orders', name: 'adminOrderList', component: AdminOrderListView },
      { path: 'orders/:id', name: 'adminOrderDetail', component: AdminOrderDetailView },
      { path: 'rooms', name: 'adminRooms', component: AdminRoomCalendarView },
      { path: 'schedules', name: 'adminSchedules', component: AdminScheduleListView },
      { path: 'packages', name: 'adminPackageList', component: AdminPackageListView },
      { path: 'packages/new', name: 'adminPackageCreate', component: AdminPackageCreateView },
      { path: 'packages/:id/edit', name: 'adminPackageEdit', component: AdminPackageEditView },
      { path: 'users', name: 'adminUsers', component: AdminUserListView },
      { path: 'users/:id', name: 'adminUserDetail', component: AdminUserDetailView },
    ]
  }
]

3.2 导航守卫

router.beforeEach((to, _from, next) => {
  // 检查是否需要管理员权限
  if (to.matched.some(record => record.meta.requiresAdmin)) {
    const loginUserStore = useLoginUserStore()
    if (!loginUserStore.loginUser.isLogin) {
      // 未登录 → 跳转登录页,携带 redirect
      ElMessage.warning('请先登录')
      next({ path: '/login', query: { redirect: to.fullPath } })
    } else if (loginUserStore.loginUser.user?.role !== 'admin') {
      // 非管理员 → 跳转首页
      ElMessage.error('无权访问')
      next('/')
    } else {
      next() // 放行
    }
  } else {
    next() // 无需权限 → 放行
  }
})

3.3 路由元信息

route meta.title meta.icon meta.requiresAdmin
/ 首页 HomeFilled -
/about 关于 Menu -
/admin/users 用户管理 User true
/admin/other 其他 Menu true

其余路由的 meta 待补充完整。


4. 布局详细设计

4.1 UserLayout(用户侧布局)

┌─────────────────────────────────────────────────────────┐
│  [Logo]  标题        [首页] [关于]   [后台管理]  [登录]  │  ← el-header(水平)
├─────────────────────────────────────────────────────────┤
│                                                         │
│                    <router-view />                       │  ← el-main(内容区)
│                                                         │
├─────────────────────────────────────────────────────────┤
│                       Footer                            │  ← el-footer
└─────────────────────────────────────────────────────────┘

功能说明:

  • 顶部导航栏:左侧 Logo + 标题,中间水平导航菜单(从 userRoutes 动态渲染),右侧用户状态(登录显示头像+下拉菜单/未登录显示登录注册按钮)
  • 管理员用户额外显示"后台管理"入口
  • 内容区渲染子路由

状态判断:

const login = computed(() => loginUserStore.loginUser.isLogin)
const isAdmin = computed(() => loginUserStore.loginUser.user?.role === 'admin')

4.2 AdminLayout(商家后台侧布局)

┌──────────────────────────────────────────────────────────┐
│  [Logo]  标题         后台管理          [用户名 ▼]       │  ← el-header
├──────────┬───────────────────────────────────────────────┤
│  可折叠   │                                              │
│  侧边栏   │            <router-view />                   │  ← el-main
│  导航菜单  │                                              │
│          │                                              │
└──────────┴───────────────────────────────────────────────┘

功能说明:

  • 顶部栏:左侧 Logo+标题,中间"后台管理"标题,右侧用户信息下拉
  • 左侧可折叠菜单(从 adminRoutes 动态渲染)
  • 内容区渲染子路由

可折叠菜单:

const isCollapse = ref(false)
// el-menu 的 :collapse="isCollapse" 控制展开/收起

5. 状态管理详细设计(Pinia Store)

5.1 useLoginUserStore

// store/user.ts
export const useLoginUserStore = defineStore('loginUser', () => {
  // === State ===
  const loginUser = reactive<LoginUser>({
    isLogin: false,
    user: {
      id: '',
      name: '未登录',
      role: 'guest'
    }
  })

  // === Getters ===
  const userId = computed(() => loginUser.user?.id)

  // === Actions ===
  function updateUser(user: User) {
    loginUser.user = { ...user }
  }
  function loginSuccess(user: User) {
    updateUser(user)
    loginUser.isLogin = true
  }
  function logoutUser() {
    loginUser.isLogin = false
    loginUser.user = { id: '', name: '未登录', role: 'guest' }
    // 清除登录状态(服务端 session 通过 logout API 销毁)
    // 前端仅清除本地 store 状态
  }

  return { loginUser, userId, updateUser, loginSuccess, logoutUser }
}, { persist: true })  // pinia-plugin-persistedstate

持久化存储:

  • 通过 pinia-plugin-persistedstate 自动持久化到 localStorage
  • 刷新页面后登录状态自动恢复

5.2 useMetaStore

// store/meta.ts
export const useMetaStore = defineStore('meta', () => {
  const title = ref('标题')          // 网站标题
  const logo = ref('/logo.svg')     // 网站 Logo
  const baseUrl = ref('http://localhost:8080/')  // 后端地址

  return { title, logo, baseUrl }
}, { persist: true })

5.3 新建 Store 规划

Store 名称 用途 状态字段
useAppointmentStore 预约流程状态 currentPackage, selectedPet, selectedRoom, dateRange
usePetStore 宠物列表缓存 pets: PetVo[]

6. Axios 配置详细设计

// util/axios-instance.ts

const axiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout: 30000,
  withCredentials: true,  // 跨域请求自动携带 Cookie(JSESSIONID)
  headers: { 'Content-Type': 'application/json' }
})

// 响应拦截器
axiosInstance.interceptors.response.use(
  (response) => {
    // 后端返回格式: { code, message, data }
    if (response.data.code !== 0 && response.data.code !== 200) {
      return Promise.reject(new Error(response.data.message || '请求失败'))
    }
    return response.data  // 直接返回 data,不需要 .data.data
  },
  (error) => {
    if (error.response?.status === 401) {
      // Session 过期或未登录,跳转登录页
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

// Orval 使用的自定义实例
export const customAxiosInstance = <T>(config: CustomInstanceConfig): Promise<T> => {
  return axiosInstance(config)
}

7. 页面详细设计

7.1 登录/注册页(LoginView)

功能:

  • Tab 切换:登录 / 注册
  • 登录表单:账号 + 密码
  • 注册表单:账号 + 用户名 + 密码 + 确认密码
  • 表单校验(Element Plus Form Rules)
  • 登录成功:服务端将用户信息存入 HttpSession,前端更新 Pinia store → 跳转首页/redirect
  • 注册成功:自动切换到登录 tab

状态管理:

  • activeTab: ref('login') — 当前激活的 tab
  • loginForm: reactive({ account, password })
  • registerForm: reactive({ account, username, password, confirmPassword })
  • loginLoading, registerLoading: ref(false)

校验规则:

  • 登录:account 非空, password 非空且≥4位
  • 注册:account 4-20位, username 2-32位, password 4-20位, confirmPassword 需与 password 一致

交互流程:

用户输入 → 点击登录/注册 → validate() → API 调用
  → 成功 → 更新 store(服务端已存入 Session) → 跳转
  → 失败 → ElMessage.error 显示错误信息

7.2 首页(HomeView)

功能:

  • 展示宠物服务管理系统的品牌介绍
  • 快速入口:寄养服务、洗护服务、我的订单、宠物档案

布局建议:

┌──────────────────────────────────────┐
│  品牌 Banner + 宣传语                  │
├────────────┬──────────┬──────────────┤
│ 寄养服务    │ 洗护服务  │ 更多服务      │  ← 功能卡片入口
├────────────┴──────────┴──────────────┤
│  功能介绍 / 优势展示                    │
└──────────────────────────────────────┘

7.3 服务预约页(BookingView / BoardingBookingView / GroomingBookingView)

7.3.1 BookingView(服务类型选择)

┌──────────────────────────────────────┐
│  选择服务类型                          │
│                                      │
│  ┌──────────┐  ┌──────────┐          │
│  │  寄养服务  │  │  洗护服务  │          │  ← 两大服务卡片
│  │  🏠       │  │  ✂️       │          │
│  │  查看详情  │  │  查看详情  │          │
│  └──────────┘  └──────────┘          │
└──────────────────────────────────────┘

7.3.2 BoardingBookingView(寄养预约)

步骤流程(Stepper 组件):

Step 1: 选择寄养套餐
  → GET /api/packages?type=BOARDING
  → 卡片列表展示套餐(名称、价格、天数、描述)
  → 用户选择一个套餐

Step 2: 选择房型与日期
  → GET /api/boarding-rooms
  → 选择房型 → GET /api/boarding-rooms/{id}/status?month=YYYY-MM
  → 日历展示房态(绿色=空闲,红色=占用)
  → 用户选择入住/离店日期
  → 实时计算总价(每晚价格 × 天数)

Step 3: 选择宠物
  → GET /api/pets
  → 下拉选择或卡片选择已有的宠物

Step 4: 确认提交
  → 展示订单摘要:套餐、房型、日期、宠物、总价
  → 点击"提交预约"
  → POST /api/appointments
  → 成功 → 弹出 PaymentDialog(支付定金)

7.3.3 GroomingBookingView(洗护预约)

步骤流程:

Step 1: 选择洗护套餐
  → GET /api/packages?type=GROOMING
  → 卡片列表展示

Step 2: 选择预约时间
  → GET /api/admin/schedules?month=YYYY-MM
  → 日历展示设计师排班(可选的日期+时段)
  → 选择时间段

Step 3: 选择宠物
  → GET /api/pets
  → 选择宠物

Step 4: 确认提交
  → 提交预约 → 支付定金

7.4 订单管理(OrderListView / OrderDetailView)

7.4.1 OrderListView

┌──────────────────────────────────────┐
│  我的预约           [状态筛选 Tab]      │
├──────────────────────────────────────┤
│  ┌──────────────────────────────────┐│
│  │ 订单卡片:                        ││
│  │ 宠物名 | 套餐名 | 日期            ││
│  │ 状态标签 | 总价                   ││
│  │ [申请取消] [查看详情]              ││
│  └──────────────────────────────────┘│
│  ┌──────────────────────────────────┐│
│  │ 订单卡片 2...                     ││
│  └──────────────────────────────────┘│
│            ... 分页 ...              │
└──────────────────────────────────────┘

7.4.2 OrderDetailView

┌──────────────────────────────────────┐
│  ← 返回                              │
├──────────────────────────────────────┤
│  订单编号:xxx                        │
│  状态:[PENDING/CONFIRMED/CANCELLED]  │
│                                      │
│  服务类型:寄养/洗护                    │
│  套餐名称:xxx                        │
│  宠物:xxx(品种/年龄)                │
│  房型:xxx(仅寄养)                   │
│  日期:2026-06-01 ~ 2026-06-03        │
│  总价:¥600                           │
│  定金:¥180(已支付/未支付)            │
│  创建时间:2026-06-01 10:00           │
│                                      │
│  [申请取消] [支付定金] [联系客服]        │
└──────────────────────────────────────┘

条件按钮逻辑:

  • 显示"支付定金":仅当 deposit_paid = false 且 status = PENDING
  • 显示"申请取消":仅当 status 为 PENDING 或 CONFIRMED
  • 显示弹窗填写取消原因

7.5 宠物档案(PetListView / PetCreateView / PetDetailView / PetEditView)

7.5.1 PetListView

┌──────────────────────────────────────┐
│  宠物档案          [+ 新增宠物]        │
├──────────────────────────────────────┤
│  ┌──────────────────────────────────┐│
│  │ [头像] 宠物名 - 品种              ││
│  │ 年龄: 2岁 | 性别: 公             ││
│  │ [编辑] [删除] [查看详情]          ││
│  └──────────────────────────────────┘│
└──────────────────────────────────────┘

7.5.2 PetDetailView

┌──────────────────────────────────────┐
│  ← 返回          [编辑] [删除]       │
├──────────────────────────────────────┤
│  基本信息                            │
│  名称: 旺财 | 品种: 金毛             │
│  年龄: 2岁 | 体重: 25kg             │
│  性别: 公   | 备注: 活泼好动         │
├──────────────────────────────────────┤
│  疫苗记录          [+ 新增]          │
│  ┌──────────────────────────────────┐│
│  │ 狂犬疫苗  2026-01-01  2027-01-01 ││
│  │ 接种机构: 安心宠物医院            ││
│  └──────────────────────────────────┘│
├──────────────────────────────────────┤
│  驱虫记录          [+ 新增]          │
│  ┌──────────────────────────────────┐│
│  │ 体外驱虫  2026-03-15  2026-06-15 ││
│  │ 药物: 福来恩                      ││
│  └──────────────────────────────────┘│
└──────────────────────────────────────┘

7.6 个人中心(ProfileView / ProfileEditView / PasswordEditView)

7.6.1 ProfileView

┌──────────────────────────────────────┐
│  个人中心                             │
│                                      │
│  [大头像]  用户名                     │
│  角色:普通用户                       │
├──────────────────────────────────────┤
│  账号:xxx                   [不可改] │
│  昵称:xxx                   [编辑]   │
│  手机:138xxxxxxx           [编辑]   │
│  邮箱:xxx@xxx.com         [编辑]   │
├──────────────────────────────────────┤
│  [修改密码]                           │
└──────────────────────────────────────┘

7.6.2 PasswordEditView

┌──────────────────────────────────────┐
│  ← 个人中心                           │
├──────────────────────────────────────┤
│  原密码:[input]                      │
│  新密码:[input]                      │
│  确认密码:[input]                     │
│                                      │
│  [确认修改]                           │
└──────────────────────────────────────┘

7.7 商家后台页面

7.7.1 AdminOrderListView

┌──────────────────────────────────────┐
│  订单审核            [状态筛选] [搜索] │
├──────────────────────────────────────┤
│  ┌──────────────────────────────────┐│
│  │ 表格:                            ││
│  │ ID | 用户 | 宠物 | 套餐 | 类型     ││
│  │ 日期 | 总价 | 定金 | 状态 | 操作   ││
│  │ 操作:[审核] [详情]               ││
│  └──────────────────────────────────┘│
│  ... 分页 ...                        │
└──────────────────────────────────────┘

操作:

  • 审核按钮:仅对 PENDING 状态的订单 → 打开审核对话框(通过/拒绝+原因)
  • 处理取消按钮:仅对 CANCEL_REQUESTED 状态的订单 → 打开处理对话框(同意/拒绝+原因)

7.7.2 AdminOrderDetailView

展示订单全部信息 + 审核操作按钮 + 订单状态变更历史。

7.7.3 AdminRoomCalendarView

┌──────────────────────────────────────┐
│  房态管理          [房型选择] [月份选择]│
├──────────────────────────────────────┤
│  ┌──────────────────────────────────┐│
│  │  日历视图:                       ││
│  │  日  一  二  三  四  五  六       ││
│  │             1     2     3     4  ││
│  │   5     6     7     8     9  10  ││
│  │  ...                             ││
│  │  点击日期切换: [空闲] [占用]       ││
│  └──────────────────────────────────┘│
└──────────────────────────────────────┘

交互:

  • 选择房型 → 日历刷新显示该房型月状态
  • 点击某天 → 切换空闲/占用状态
  • 颜色标识:绿色=空闲,红色=占用

7.7.4 AdminScheduleListView

┌──────────────────────────────────────┐
│  排班管理          [月份选择] [+ 新增] │
├──────────────────────────────────────┤
│  ┌──────────────────────────────────┐│
│  │ 表格:                            ││
│  │ 设计师 | 日期 | 时段 | 状态 | 操作 ││
│  │ 张三   | 06-01 | 上午  | 可用 | [删]│
│  │ 李四   | 06-01 | 全天  | 可用 | [删]│
│  └──────────────────────────────────┘│
└──────────────────────────────────────┘

新增弹窗:

  • 设计师姓名(输入)
  • 日期(日期选择器)
  • 时段(下拉:上午/下午/全天)
  • 是否可用(开关)

7.7.5 AdminPackageListView / AdminPackageCreateView / AdminPackageEditView

┌──────────────────────────────────────┐
│  套餐配置          [+ 新增套餐]       │
├──────────────────────────────────────┤
│  ┌──────────────────────────────────┐│
│  │ 表格:                            ││
│  │ 名称 | 类型 | 价格 | 天数 | 状态 | 操 │
│  │ 标准寄养 | 寄养 | ¥100/天 | 1-7 | ✅ | [编辑][删]│
│  └──────────────────────────────────┘│
└──────────────────────────────────────┘

新增/编辑表单:

  • 套餐类型(寄养/洗护 → radio)
  • 套餐名称(input)
  • 价格(input number)
  • 描述/项目内容(textarea)
  • 寄养天数(input number,仅寄养时显示)
  • 是否启用(switch)

7.7.6 AdminUserListView

复用现有的 UserView.vue 组件,功能包括:

  • 搜索筛选(用户名/账号/角色/状态)
  • 表格展示(ID/用户名/账号/角色/状态/头像/操作)
  • 新增/编辑用户弹窗
  • 启用/禁用用户开关
  • 批量删除

7.7.7 AdminUserDetailView

┌──────────────────────────────────────┐
│  ← 用户管理                           │
├──────────────────────────────────────┤
│  用户信息                             │
│  [头像] 用户名 | 账号 | 角色 | 状态    │
│  注册时间: 2026-01-01                 │
├──────────────────────────────────────┤
│  该用户的宠物档案                      │
│  ┌──────────────────────────────────┐│
│  │ 宠物名 | 品种 | 年龄 | 操作       ││
│  │ 旺财   | 金毛 | 2岁 | [查看详情]  ││
│  └──────────────────────────────────┘│
└──────────────────────────────────────┘

8. 公共组件详细设计

8.1 PaymentDialog(模拟支付弹窗)

<!-- 用法 -->
<PaymentDialog v-model:visible="showPayment" :amount="deposit" :order-id="orderId"
  @success="onPaymentSuccess" @close="onPaymentClose" />

功能:

  • 显示定金金额
  • 支付方式选择:微信支付 / 支付宝(纯 UI 模拟)
  • 点击"确认支付" → POST /api/appointments/{orderId}/pay-deposit
  • 成功 → 显示支付成功动画/提示 → emit('success')
  • 失败 → 显示错误提示

8.2 RoomCalendar(房态日历组件)

<!-- 用法 -->
<RoomCalendar :room-id="roomId" :month="currentMonth" :status-list="statusList"
  @date-click="handleDateClick" />

功能:

  • 展示月历视图(7列 × 6行)
  • 每天显示状态(AVAILABLE=绿色, OCCUPIED=红色)
  • 点击某天 → emit('date-click', date, currentStatus)
  • 支持切换月份

8.3 PetSelector(宠物选择器)

<!-- 用法 -->
<PetSelector :pet-list="pets" v-model:selected="selectedPet" />

功能:

  • 卡片列表展示用户的宠物
  • 点击选择一只宠物(高亮选中状态)

9. API 调用模式

9.1 Orval 生成代码的使用

// 调用认证 API
import { getAuthController } from '@/api/auth-controller'

const authApi = getAuthController()
const res = await authApi.login({ account, password })

// res 已经是解包后的数据(响应拦截器已处理)
// 登录成功后服务端已将用户信息存入 HttpSession
// 前端仅需更新 Pinia store
if (res.code === 200) {
  loginUserStore.loginSuccess({
    id: String(res.data.id),
    name: res.data.username,
    role: res.data.role
  })
  // 后续请求通过 Cookie(JSESSIONID)自动携带 Session
}

9.2 新建 API 控制器规划

按模块拆分,每个模块一个文件:

文件 包含接口
auth-controller.ts register, login
user-controller.ts queryByPage, add, edit, delete, updateStatus, updatePassword, updateAvatar, queryById
pet-controller.ts list, add, getById, update, delete, getVaccinations, addVaccination, getDeworming, addDeworming
appointment-controller.ts create, list, getById, cancel, payDeposit
admin-appointment-controller.ts listAll, review, handleCancel
boarding-room-controller.ts listRooms, getStatus
admin-boarding-room-controller.ts updateStatus
package-controller.ts listPackages, getPackageById
admin-package-controller.ts createPackage, updatePackage, deletePackage
admin-schedule-controller.ts listSchedules, createSchedule, deleteSchedule
admin-user-controller.ts listUsers, getUserDetail

10. 设计主题

10.1 主题色

变量 值 用途
--el-color-primary #e34889 Element Plus 主色调
--el-color-primary-light #f06292 浅色变体
--el-color-primary-dark #c2185b 深色变体
渐变 linear-gradient(135deg, #db2777, #be185d) 按钮/重点元素

10.2 已在 LoginView 中的设计模式

  • 背景:渐变色 linear-gradient(135deg, #fdf2f8, #fce7f3, #fbcfe8)
  • 卡片:毛玻璃效果(background: rgba(255,255,255,0.9) + backdrop-filter)
  • 输入框:粉色边框 rgba(219, 39, 119, 0.15)
  • 按钮:粉色渐变
  • 装饰:浮动渐变色圆形装饰

11. 构建与开发配置

11.1 Vite 代理配置

// vite.config.ts
server: {
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, '')
    }
  }
}

注意:后端 context-path 也设为 /api,所以 Vite 代理会将 /api/xxx 转发到 http://localhost:8080/xxx。当后端 context-path 与前端代理前缀都为 /api 时,rewrite 会剥离一个 /api,导致请求变为 http://localhost:8080/auth/login 而非 http://localhost:8080/api/auth/login。需确认后端实际路径。

11.2 开发命令

命令 说明
npm run dev 启动开发服务器(HMR)
npm run build 类型检查 + 生产构建
npm run preview 预览生产构建
npm run api:gen 从 OpenAPI 规范生成 API 代码

11.3 Orval 配置

// orval.config.ts
export default defineConfig({
  'your-api': {
    input: {
      target: 'http://localhost:8080/v3/api-docs',  // OpenAPI JSON 地址
    },
    output: {
      mode: 'tags',           // 按标签拆分
      client: 'axios',
      target: './src/api/client.ts',
      schemas: './src/api/models',
      clean: true,
      override: {
        mutator: {
          path: './src/util/axios-instance.ts',
          name: 'customAxiosInstance',
        },
      },
    },
    hooks: {
      afterAllFilesWrite: 'prettier --write',
    },
  },
})

12. 现有代码适配说明

12.1 当前已实现的功能

模块 已实现 待实现
路由 userRoutes + adminRoutes 基础结构 完整路由表(预约/订单/宠物/个人中心)
布局 UserLayout(顶部导航) + AdminLayout(侧边栏+顶栏) 完善菜单项
登录 LoginView(登录+注册 tab) -
用户管理 UserView(CRUD + 搜索 + 分页 + 状态切换) -
状态管理 useLoginUserStore + useMetaStore -
API auth-controller + user-controller pet/appointment/boarding-room/package/schedule controllers
导航守卫 requiresAdmin 校验 普通页面登录校验

12.2 待实现模块优先级

优先级 模块 说明
P0 服务预约(寄养+洗护) 核心业务
P0 订单管理(用户侧+后台) 核心业务
P0 宠物档案 CRUD 核心业务
P1 房态管理(后台日历) 商家必备
P1 套餐配置(后台) 商家必备
P1 排班管理(后台) 商家必备
P2 个人中心 用户信息管理
P2 商家用户详情 查看用户宠物

13. 组件交互数据流

13.1 寄养预约完整数据流

BookingView
  └─→ 用户点击"寄养服务"
      └─→ router.push('/booking/boarding')
          └─→ BoardingBookingView (Step 1: 选择套餐)
              ├─→ API: GET /api/packages?type=BOARDING
              ├─→ 用户选择套餐 → 保存到局部状态
              └─→ Step 2: 选择房型与日期
                  ├─→ API: GET /api/boarding-rooms
                  ├─→ RoomCalendar 组件展示房态
                  │   └─→ 用户选择日期
                  ├─→ 实时计算总价
                  └─→ Step 3: 选择宠物
                      ├─→ API: GET /api/pets
                      ├─→ PetSelector 组件
                      └─→ Step 4: 确认提交
                          ├─→ API: POST /api/appointments
                          └─→ PaymentDialog 弹窗
                              └─→ API: POST /api/appointments/{id}/pay-deposit
                                  └─→ 成功 → router.push('/orders')

13.2 订单取消数据流

OrderListView
  └─→ 用户点击"申请取消"
      └─→ ElMessageBox.prompt("请输入取消原因")
          └─→ 确认 → API: POST /api/appointments/{id}/cancel
              └─→ 成功 → ElMessage.success → 刷新列表

13.3 后台审核数据流

AdminOrderListView
  └─→ 管理员点击"审核"
      └─→ 对话框:通过(默认)/ 拒绝 + 填写原因
          └─→ 确认 → API: PUT /api/admin/appointments/{id}/review
              └─→ 成功 → ElMessage.success → 刷新列表

14. 类型定义汇总

14.1 自定义类型(type/index.ts)

// 当前已定义
export interface User {
  id: string
  name: string
  avatar?: string
  role: 'admin' | 'user' | 'guest'
}

export interface LoginUser {
  isLogin: boolean
  user?: User
}

14.2 待补充类型

注意: 后端 Java 实体类 Package 已重命名为 ServicePackage(与 java.lang.Package 冲突),dto/package/ 和 vo/package/ 已重命名为 servicePackage/(package 为 Java 关键字)。但这些变更不影响 API 端点路径(仍为 /api/packages/**)和 Orval 生成的 TypeScript 类型,前端无需调整。

// 宠物相关
export interface Pet {
  id: string
  name: string
  breed: string
  age: number
  weight: number
  gender: 'MALE' | 'FEMALE'
  notes?: string
}

// 套餐相关
export interface Package {
  id: string
  type: 'BOARDING' | 'GROOMING'
  name: string
  price: number
  description?: string
  durationDays?: number
  isActive: boolean
}

// 房型相关
export interface BoardingRoom {
  id: string
  name: string
  capacity: number
  pricePerNight: number
  description?: string
}

// 房态相关
export interface RoomStatus {
  date: string
  status: 'AVAILABLE' | 'OCCUPIED'
}

// 预约订单相关
export interface Appointment {
  id: string
  userId: string
  petId: string
  packageId: string
  roomId?: string
  type: 'BOARDING' | 'GROOMING'
  startDate?: string
  endDate?: string
  appointmentTime?: string
  status: 'PENDING' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED' | 'CANCEL_REQUESTED'
  deposit: number
  depositPaid: boolean
  totalPrice: number
  cancelReason?: string
  rejectReason?: string
  createdAt: string
}

// 排班相关
export interface Schedule {
  id: string
  designerName: string
  workDate: string
  timeSlot: 'MORNING' | 'AFTERNOON' | 'FULL_DAY'
  isAvailable: boolean
}