Update CLAUDE.md

This commit is contained in:
jacobxu666
2026-07-29 13:54:13 +08:00
parent 45a74578fc
commit 8cc76dec6c
+141 -146
View File
@@ -4,72 +4,111 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## 项目定位
## 项目定位
**湖南12301文旅专区**用户端微信小程序(C端),基于 uni-app + Vue 3 + TypeScript + Pinia。仅包含用户端功能,不含管理端。
**爱上萍乡**用户端微信小程序(C端),基于 uni-app + Vue 3 + TypeScript + Pinia。仅包含用户端功能,不含管理端。
## 技术栈
| 技术 | 版本 | 说明 |
|------|------|------|
| Vue | 3.5.x | 核心框架 |
| uni-app | 3.0.0 | 跨平台框架(当前仅编译微信小程序) |
| uni-app | 3.0.0-alpha | 跨平台框架(当前仅编译微信小程序) |
| TypeScript | 4.9.x | 类型系统 |
| Pinia | 3.x | 状态管理(仅 user store) |
| Vite | 5.2.8 | 构建工具 |
| @dcloudio/uni-ui | 1.5.12 | UI 组件库(easycom 自动导入) |
| @dcloudio/uni-ui | 1.5.x | UI 组件库(easycom 自动导入) |
| sass | 1.101.x | 样式预处理 |
## 微信小程序配置
## 运行命令
- **AppID**: `wx636bc46a6570e9fd`
- **后端接口前缀**: `/mp-api`(对应后端 `RouteChannel.MP_API`)
- **API 基础地址**: 由 `.env.*` 文件的 `VITE_API_BASE_URL` 控制
```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/`,用微信开发者工具导入此目录。
## 目录结构
```
zhy-test/
├── src/
│ ├── api/ # API 接口层
│ │ ├── request.ts # HTTP 封装(uni.request + Token 注入 + 401 处理)
│ │ ├── types.ts # TypeScript 类型定义
│ │ ├── user.ts # 微信登录 + 用户信息
│ │ ├── card.ts # 年卡列表/详情/激活/绑定/入园码
│ │ └── order.ts # 订单创建/支付/查询
│ ├── components/ # 公共组件
│ │ ├── McGlass.vue # 毛玻璃卡片
│ │ ├── card-item.vue # 年卡列表项
│ │ └── empty-state.vue # 空状态占位
│ ├── config/
│ │ └── index.ts # API_BASE / TOKEN_KEY / REFRESH_TOKEN_KEY
│ ├── pages/ # 主包页面
│ │ ├── index/index.vue # 首页(轮播 + 热门景区 + 精选活动)
│ │ ├── login/login.vue # 登录页(微信手机号授权登录)
│ │ └── profile/index.vue # 个人中心(tabBar)
│ ├── packages/user/pages/card/ # 分包:年卡功能(减小主包体积)
│ │ ├── list.vue # 年卡列表(搜索 + 分类筛选)
│ │ ├── detail.vue # 年卡详情(权益 + 景区 + 富文本)
│ │ ├── buy.vue # 购买确认 + 模拟支付
│ │ ├── activate.vue # 实名激活(姓名 + 身份证 + 手机)
│ │ ├── qrcode.vue # 入园码(60秒自动刷新)
│ │ └── bind.vue # 卡号绑定
│ ├── static/ # 静态资源(logo + tabBar 图标)
│ ├── store/
│ │ └── user.ts # 用户状态(token 持久化 + 登录判断)
│ ├── utils/
│ │ └── index.ts # 工具函数(showToast / navigateTo 等)
│ ├── App.vue # 根组件(隐私协议检查 + 自动获取用户信息)
│ ├── main.ts # 入口(createSSRApp + Pinia)
│ ├── manifest.json # uni-app 配置(AppID)
│ ├── pages.json # 路由 + tabBar + 分包 + easycom
│ └── uni.scss # 全局 SCSS 变量
├── .env.local # 本地开发环境
├── .env.dev # 开发环境
├── .env.uat # UAT 环境
├── package.json
├── project.config.json # 微信开发者工具配置
├── vite.config.ts
└── tsconfig.json
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 变量(自动注入到每个组件)
```
## 架构设计
@@ -77,136 +116,92 @@ zhy-test/
### 分层
```
页面(.vue) → API 层(api/*.ts) → HTTP 封装(request.ts) → uni.request → 后端
页面(.vue) → API 层(api/*.ts) → request.ts → uni.request → 后端
↕
Store(store/user.ts) ← 仅管理 token + 登录状态
```
- **页面直接调用 API**,不经过 store(年卡、订单等模块)
- **只有 user 模块使用 store**,因为需要跨页面共享 token 和登录状态
- **request.ts** 统一处理 Token 注入、401 跳转、响应格式解析
- **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}`)
- 响应格式:`{ errcode, errmsg, data, traceid }`(框架自动包装 `ResDto`)
- 响应格式:`{ code, msg, data, errcode, errmsg }`(`code === 200` 或 `errcode === 0` 视为成功)
- 用户表:`member` 表,`channel = 99`(Channel_CY,产研小程序)
- Token 表:`system_oauth2_access_token`,`clientId = "mp-99"`
### 微信登录流程
### Mock 系统
```
前端 button[open-type=getPhoneNumber]
→ phoneCode + wx.login() → loginCode
→ POST /mp-api/auth/wx-login { loginCode, phoneCode }
→ 后端 jscode2session → openId
→ 后端 getuserphonenumber → phoneNumber
→ 查找/创建 member → 创建 token
→ 返回 LoginResponse { accessToken, refreshToken, userId, openId, mobile }
```
通过环境变量 `VITE_USE_MOCK=true` 启用。各页面在 `onLoad` 中检查 `USE_MOCK` 标志,为 true 时直接从 mock 文件渲染数据,不发起网络请求。
## 运行命令
## 设计系统
```bash
# 安装依赖
pnpm install
样式体系基于 **uv-ui 设计系统**(`uv-*` 变量命名),通过 `uni.scss` 全局注入 SCSS 变量,每个组件无需额外 import 即可使用。
# 微信小程序开发构建
pnpm run dev:mp-weixin
### 核心变量
# 微信小程序生产构建
pnpm run build:mp-weixin
| 类别 | 变量前缀 | 示例 |
|------|----------|------|
| 品牌色 | `$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` |
# TypeScript 类型检查
pnpm run type-check
### 字体
# 构建产物目录
dist/build/mp-weixin/ # 用微信开发者工具导入此目录
```
- 展示字体:`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` | 本地开发(配合后端 `--spring.profiles.active=local`) |
| `.env.local` | `http://localhost:48080` | 本地开发(配合后端 local profile) |
| `.env.dev` | `https://dscp-dev.hn12301.net` | 开发环境 |
| `.env.uat` | `https://dscp-uat.hn12301.net` | UAT 测试 |
## 数据库环境
## Git 远程
| 环境 | 地址 | 数据库 |
|------|------|--------|
| 本地(local profile) | `localhost:3306` | `dscp_business_dev` |
| 开发(dev) | `120.26.254.65:3306` | `dscp_business_dev` |
| UAT | `47.99.164.129:3306` | `dscp_business` |
- `gitee` → `https://gitee.com/jacobxu666/zhy-mp-test.git`(唯一远程,`main` 跟踪此分支)
- 当前分支:`xuchao`
## 开发注意事项
1. **API 前缀**:所有接口走 `/mp-api`(不是 `/manage-api`,那是管理后台)
2. **Token 管理**:`app_token` / `app_refresh_token` 存在 `uni.storage` 中
3. **分包策略**:年卡功能放分包(`packages/user`),首页/登录/个人中心在主包
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
<frontend_aesthetics>
You tend to converge toward generic, "on distribution" outputs.
In frontend design, this creates what users call the "AI slop"
aesthetic. Avoid this: make creative, distinctive frontends that
surprise and delight. Focus on:
Typography: Choose fonts that are beautiful, unique, and interesting.
Avoid generic fonts like Arial and Inter; opt instead for distinctive
choices that elevate the frontend's aesthetics.
Color & Theme: Commit to a cohesive aesthetic. Use CSS variables for
consistency. Dominant colors with sharp accents outperform timid,
evenly-distributed palettes.
Motion: Use animations for effects and micro-interactions.
Focus on high-impact moments: one well-orchestrated page load
with staggered reveals creates more delight than scattered
micro-interactions.
Backgrounds: Create atmosphere and depth rather than defaulting
to solid colors. Layer CSS gradients, use geometric patterns,
or add contextual effects.
Avoid generic AI-generated aesthetics:
- Overused font families (Inter, Roboto, Arial, system fonts)
- Clichéd color schemes (particularly purple gradients on white)
- Predictable layouts and component patterns
- Cookie-cutter design that lacks context-specific character
Interpret creatively and make unexpected choices that feel
genuinely designed for the context.
</frontend_aesthetics>
<use_interesting_fonts>
Typography instantly signals quality. Avoid boring, generic fonts.
Never use: Inter, Roboto, Open Sans, Lato, default system fonts
Impact choices:
- Code aesthetic: JetBrains Mono, Fira Code, Space Grotesk
- Editorial: Playfair Display, Crimson Pro, Fraunces
- Startup: Clash Display, Satoshi, Cabinet Grotesk
- Technical: IBM Plex family, Source Sans 3
- Distinctive: Bricolage Grotesque, Obviously, Newsreader
Pairing principle: High contrast = interesting.
Display + monospace, serif + geometric sans.
Use extremes: 100/200 weight vs 800/900, not 400 vs 600.
Size jumps of 3x+, not 1.5x.
</use_interesting_fonts>
# Design System
Always refer to DESIGN.md when generating or modifying any UI component.
Use only colors, fonts, and spacing values defined in DESIGN.md.
Do not invent new values or use defaults from any framework.
Match component states (hover, focus, active, disabled) to patterns
in DESIGN.md.
7. **Mock 模式**:设置 `VITE_USE_MOCK=true` 可离线开发,不依赖后端
8. **样式对齐**:`uni.scss` 是设计令牌的 source of truth,`src/styles/_tokens.scss` 仅供 `main.scss` 兼容使用,新增样式变量优先在 `uni.scss` 中定义