# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 项目定位 **爱上萍乡**用户端微信小程序(C端),基于 uni-app + Vue 3 + TypeScript + Pinia。仅包含用户端功能,不含管理端。 ## 技术栈 | 技术 | 版本 | 说明 | |------|------|------| | Vue | 3.5.x | 核心框架 | | uni-app | 3.0.0-alpha | 跨平台框架(当前仅编译微信小程序) | | TypeScript | 4.9.x | 类型系统 | | Pinia | 3.x | 状态管理(仅 user store) | | Vite | 5.2.8 | 构建工具 | | @dcloudio/uni-ui | 1.5.x | UI 组件库(easycom 自动导入) | | sass | 1.101.x | 样式预处理 | ## 运行命令 ```bash pnpm install # 安装依赖 pnpm run dev:mp-weixin # 微信小程序开发构建 pnpm run build:mp-weixin # 微信小程序生产构建 pnpm run type-check # TypeScript 类型检查(vue-tsc --noEmit) ``` 构建产物在 `dist/build/mp-weixin/`,用微信开发者工具导入此目录。 ## 目录结构 ``` src/ ├── api/ # API 接口层 │ ├── request.ts # HTTP 封装(uni.request + Token 注入 + 401 处理) │ ├── types.ts # 公共类型定义 │ ├── user.ts # 微信登录(两种方式) │ ├── card.ts # 年卡接口 │ └── order.ts # 订单接口 ├── components/ # 公共组件 │ ├── mc-glass.vue # 毛玻璃卡片 │ ├── card-item.vue # 年卡列表项 │ ├── empty-state.vue # 空状态占位 │ ├── announcement-modal.vue # 公告弹窗 │ ├── confirm-modal.vue # 确认弹窗 │ ├── design-button.vue # 设计系统按钮 │ ├── design-card.vue # 设计系统卡片 │ ├── design-input.vue # 设计系统输入框 │ └── section-label.vue # 区块标题 ├── config/ │ └── index.ts # API_BASE / TOKEN_KEY / 环境变量 ├── mock/ # Mock 数据(VITE_USE_MOCK=true 时启用) │ ├── index.ts # USE_MOCK 开关 │ ├── images.ts # 图片 URL │ ├── notice.ts # 公告数据 │ ├── scenic.ts # 景区列表数据 │ └── scenic-detail.ts # 景区详情数据 ├── pages/ # 主包页面 │ ├── index/index.vue # 首页(轮播 + 热门景区 + 精选活动) │ ├── qrcode/index.vue # 入园码(tabBar 旅游卡) │ ├── login/login.vue # 登录页(微信手机号授权) │ ├── login/agreement.vue # 服务条款 │ ├── login/privacy.vue # 隐私条款 │ └── profile/index.vue # 个人中心(tabBar) ├── packages/user/ # 分包:用户相关(年卡、订单、预约) │ ├── api/ │ │ ├── card.ts # 年卡 API │ │ └── order.ts # 订单 API │ ├── pages/ │ │ ├── card/list.vue # 年卡列表 │ │ ├── card/detail.vue # 年卡详情 │ │ ├── card/buy.vue # 年卡购买 │ │ ├── card/activate.vue # 年卡激活 │ │ ├── card/qrcode.vue # 入园码 │ │ ├── card/bind.vue # 年卡绑定 │ │ ├── bind.vue # 绑卡激活 │ │ ├── buy.vue # 超级玩家卡购买 │ │ ├── union-buy.vue # 工会购买 │ │ ├── card-notice.vue # 用卡须知 │ │ ├── order/list.vue # 订单列表 │ │ ├── order/detail.vue # 订单详情 │ │ ├── reserve/index.vue # 景区预约 │ │ ├── reserve/success.vue # 预约成功/详情 │ │ └── reserve/list.vue # 预约/使用记录 │ └── mock/ │ └── order.ts # 订单 mock 数据 ├── packages/content/ # 分包:内容展示(景区、公告、帮助) │ └── pages/ │ ├── scenic-list.vue # 景区列表(custom navbar) │ ├── scenic-detail.vue # 景区详情 │ ├── notice-list.vue # 通知公告 │ ├── usage-guide.vue # 使用说明 │ └── faq.vue # 常见问题 ├── store/ │ └── user.ts # 用户状态(token 持久化 + 登录判断) ├── styles/ # 设计系统样式 │ ├── main.scss # 入口(全局样式) │ ├── _tokens.scss # 设计令牌(对齐 uni.scss) │ ├── _mixins.scss # 混入(text-display / text-body / text-mono 等) │ ├── _animations.scss # 动画 │ └── _utilities.scss # 工具类 ├── static/ # 静态资源(tabBar 图标、logo 等) ├── utils/ │ └── index.ts # 工具函数(showToast / navigateTo 等) ├── App.vue # 根组件(隐私协议检查) ├── main.ts # 入口(createSSRApp + Pinia) ├── manifest.json # uni-app 配置(AppID) ├── pages.json # 路由 + tabBar + 分包 + easycom └── uni.scss # 全局 SCSS 变量(自动注入到每个组件) ``` ## 架构设计 ### 分层 ``` 页面(.vue) → API 层(api/*.ts) → request.ts → uni.request → 后端 ↕ Store(store/user.ts) ← 仅管理 token + 登录状态 ``` - **页面直接调用 API**,不经过 store(年卡、订单等模块) - **只有 user 模块使用 store**,因为需要跨页面共享 token 和登录状态 - **request.ts** 统一处理 Token 注入、401 跳转、响应格式解析(兼容 `code`/`errcode` 两种业务状态码) ### 路由 - 3 个 tabBar 页面:首页、旅游卡(入园码)、我的 - 主包:首页、登录、隐私/服务条款、个人中心 - 分包 `packages/user`:年卡、订单、预约功能 - 分包 `packages/content`:景区列表/详情、公告、使用说明、FAQ ### 微信登录 两种登录方式并存: 1. **OAuth2 登录**(当前使用):`wx.login()` → `encryptedData` + `iv` → `POST /open-api/auth/oauth2` → 返回 `openId` 作为 token 2. **手机号登录**(旧方式):`button[open-type=getPhoneNumber]` → `phoneCode` + `loginCode` → `POST /mp-api/auth/wx-login` ### 后端对接 - 后端项目:`jxxx-dscp`(Spring Boot 2.7 + MyBatis-Plus) - 路由渠道:`RouteChannel.MP_API`(`/mp-api`) - 认证方式:Bearer Token(`Authorization: Bearer {accessToken}`) - 响应格式:`{ code, msg, data, errcode, errmsg }`(`code === 200` 或 `errcode === 0` 视为成功) - 用户表:`member` 表,`channel = 99`(Channel_CY,产研小程序) - Token 表:`system_oauth2_access_token`,`clientId = "mp-99"` ### Mock 系统 通过环境变量 `VITE_USE_MOCK=true` 启用。各页面在 `onLoad` 中检查 `USE_MOCK` 标志,为 true 时直接从 mock 文件渲染数据,不发起网络请求。 ## 设计系统 样式体系基于 **uv-ui 设计系统**(`uv-*` 变量命名),通过 `uni.scss` 全局注入 SCSS 变量,每个组件无需额外 import 即可使用。 ### 核心变量 | 类别 | 变量前缀 | 示例 | |------|----------|------| | 品牌色 | `$uv-primary` / `$color-accent` | `#3c9cff` | | 语义色 | `$uv-error` / `$uv-success` / `$uv-warning` | 红/绿/橙 | | 中性色 | `$uv-main-color` / `$uv-bg-color` / `$uv-border-color` | 黑/灰/白 | | 字体 | `$font-family-display` / `$font-family-body` | 思源宋体 / PingFang | | 字号 | `$font-size-*` | `xxs: 18rpx` ~ `display: 72rpx` | | 间距 | `$spacing-*` | `0` ~ `160rpx` | | 圆角 | `$radius-*` | `sm: 8rpx` ~ `full: 9999rpx` | | 阴影 | `$shadow-*` | `sm` ~ `xl` + `accent` | ### 字体 - 展示字体:`SourceHanSerifCN`(思源宋体),用于标题 - 正文字体:系统字体栈(`-apple-system, PingFang SC, Helvetica Neue`) - 等宽字体:`Menlo, Monaco, Courier New` ### 样式文件 - `uni.scss` — **source of truth**,自动注入到每个组件 - `src/styles/_tokens.scss` — 兼容层,对齐 `uni.scss` 的值,供 `main.scss` 使用 - `src/styles/main.scss` — 全局样式入口,在 `App.vue` 中通过 `@use` 导入 - 另外还有 `_mixins.scss`、`_animations.scss`、`_utilities.scss` ## 环境配置 | 文件 | API 地址 | 用途 | |------|---------|------| | `.env.local` | `http://localhost:48080` | 本地开发(配合后端 local profile) | | `.env.dev` | `https://dscp-dev.hn12301.net` | 开发环境 | | `.env.uat` | `https://dscp-uat.hn12301.net` | UAT 测试 | ## Git 远程 - `gitee` → `https://gitee.com/jacobxu666/zhy-mp-test.git`(唯一远程,`main` 跟踪此分支) - 当前分支:`xuchao` ## 开发注意事项 1. **API 前缀**:所有接口走 `/mp-api`(不是 `/manage-api`,那是管理后台) 2. **Token 管理**:`app_token` 存在 `uni.storage` 中,通过 `request.ts` 的 `getToken/setToken/removeToken` 管理 3. **分包策略**:年卡/订单/预约放 `packages/user`,景区内容放 `packages/content`,主包仅放首页/登录/个人中心/入园码 4. **条件编译**:`#ifdef MP-WEIXIN` 包裹微信特有逻辑 5. **隐私协议**:`App.vue` 中 `wx.getPrivacySetting` 检查,未同意前不能调授权 API 6. **微信开发者工具调试**:需勾选「不校验合法域名」才能请求 localhost 7. **Mock 模式**:设置 `VITE_USE_MOCK=true` 可离线开发,不依赖后端 8. **样式对齐**:`uni.scss` 是设计令牌的 source of truth,`src/styles/_tokens.scss` 仅供 `main.scss` 兼容使用,新增样式变量优先在 `uni.scss` 中定义