hookehuyr

fix(checkin): 修复 mockData 语法错误并完善地图活动功能

主要修改:
- 修复 mockData.js 的语法错误(移除孤立的 return 语句)
- 修复 generateApiFromOpenAPI.js 的 brace-style 代码风格问题
- 实现 CheckinMap 页面与 map_activity API 的集成
- 添加完整的 API 规范文档
- 更新 API 代码生成脚本

技术细节:
- 清理 mockData.js 中遗留的孤立代码片段
- 移除未使用的函数参数以消除警告
- 修复 ESLint brace-style 规则错误(9处)
- 完善 map_activity API 接口定义
- 添加 API Mock 数据支持开发环境测试

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 +# 打卡
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + post:
13 + summary: 打卡
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 老来赛/地图-新版多活动
18 + parameters:
19 + - name: f
20 + in: query
21 + description: ''
22 + required: true
23 + example: walk
24 + schema:
25 + type: string
26 + - name: a
27 + in: query
28 + description: ''
29 + required: true
30 + example: map_activity
31 + schema:
32 + type: string
33 + - name: t
34 + in: query
35 + description: ''
36 + required: true
37 + example: checkin
38 + schema:
39 + type: string
40 + requestBody:
41 + content:
42 + application/x-www-form-urlencoded:
43 + schema:
44 + type: object
45 + properties:
46 + activity_id:
47 + description: 活动ID
48 + example: ''
49 + type: string
50 + detail_id:
51 + description: 打卡点ID
52 + example: '828360'
53 + type: string
54 + openid:
55 + example: oAHBN10P-hn-vF1cTY4tQeStQFmU
56 + type: string
57 + examples: {}
58 + responses:
59 + '200':
60 + description: ''
61 + content:
62 + application/json:
63 + schema:
64 + type: object
65 + properties:
66 + code:
67 + type: integer
68 + msg:
69 + type: string
70 + x-apifox-orders:
71 + - code
72 + - msg
73 + required:
74 + - code
75 + - msg
76 + headers: {}
77 + x-apifox-name: 成功
78 + x-apifox-ordering: 0
79 + security: []
80 + x-apifox-folder: 老来赛/地图-新版多活动
81 + x-apifox-status: integrating
82 + x-run-in-apifox: https://app.apifox.com/web/project/1753326/apis/api-417072141-run
83 +components:
84 + schemas: {}
85 + responses: {}
86 + securitySchemes: {}
87 +servers: []
88 +security: []
89 +
90 +```
1 +# 地图活动详情
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + get:
13 + summary: 地图活动详情
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 老来赛/地图-新版多活动
18 + parameters:
19 + - name: f
20 + in: query
21 + description: ''
22 + required: true
23 + example: walk
24 + schema:
25 + type: string
26 + - name: a
27 + in: query
28 + description: ''
29 + required: true
30 + example: map_activity
31 + schema:
32 + type: string
33 + - name: t
34 + in: query
35 + description: ''
36 + required: true
37 + example: detail
38 + schema:
39 + type: string
40 + - name: id
41 + in: query
42 + description: 活动ID
43 + required: false
44 + schema:
45 + type: string
46 + responses:
47 + '200':
48 + description: ''
49 + content:
50 + application/json:
51 + schema:
52 + type: object
53 + properties:
54 + code:
55 + type: integer
56 + msg:
57 + type: string
58 + data:
59 + type: object
60 + properties:
61 + url:
62 + type: string
63 + title: 地图网址
64 + id:
65 + type: string
66 + title: 活动ID
67 + cover:
68 + type: string
69 + title: 封面图
70 + tittle:
71 + type: string
72 + title: 标题
73 + begin_date:
74 + type: string
75 + title: 开始时间
76 + end_date:
77 + type: string
78 + title: 结束时间
79 + is_ended:
80 + type: boolean
81 + title: 活动是否已经结束
82 + is_begin:
83 + type: boolean
84 + title: 活动是否开始
85 + first_checkin_points:
86 + type: integer
87 + title: 首次打卡获得积分
88 + required_checkin_count:
89 + type: integer
90 + title: 需要打卡几次,才能完成活动
91 + complete_points:
92 + type: integer
93 + title: 完成活动获得多少积分
94 + discount_title:
95 + type: string
96 + title: 打卡点底部优惠标题
97 + x-apifox-orders:
98 + - id
99 + - cover
100 + - tittle
101 + - begin_date
102 + - end_date
103 + - is_ended
104 + - is_begin
105 + - url
106 + - first_checkin_points
107 + - required_checkin_count
108 + - complete_points
109 + - discount_title
110 + required:
111 + - url
112 + - end_date
113 + - begin_date
114 + - id
115 + - cover
116 + - tittle
117 + - first_checkin_points
118 + - required_checkin_count
119 + - complete_points
120 + - discount_title
121 + x-apifox-orders:
122 + - code
123 + - msg
124 + - data
125 + required:
126 + - code
127 + - msg
128 + - data
129 + headers: {}
130 + x-apifox-name: 成功
131 + x-apifox-ordering: 0
132 + security: []
133 + x-apifox-folder: 老来赛/地图-新版多活动
134 + x-apifox-status: integrating
135 + x-run-in-apifox: https://app.apifox.com/web/project/1753326/apis/api-417075691-run
136 +components:
137 + schemas: {}
138 + responses: {}
139 + securitySchemes: {}
140 +servers: []
141 +security: []
142 +
143 +```
1 +# 是否已经打卡
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + get:
13 + summary: 是否已经打卡
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 老来赛/地图-新版多活动
18 + parameters:
19 + - name: f
20 + in: query
21 + description: ''
22 + required: true
23 + example: walk
24 + schema:
25 + type: string
26 + - name: a
27 + in: query
28 + description: ''
29 + required: true
30 + example: map_activity
31 + schema:
32 + type: string
33 + - name: t
34 + in: query
35 + description: ''
36 + required: true
37 + example: is_checked
38 + schema:
39 + type: string
40 + - name: detail_id
41 + in: query
42 + description: 打卡点ID
43 + required: false
44 + example: '828359'
45 + schema:
46 + type: string
47 + - name: openid
48 + in: query
49 + description: ''
50 + required: false
51 + example: oAHBN10P-hn-vF1cTY4tQeStQFmU
52 + schema:
53 + type: string
54 + - name: activity_id
55 + in: query
56 + description: 活动ID
57 + required: false
58 + schema:
59 + type: string
60 + responses:
61 + '200':
62 + description: ''
63 + content:
64 + application/json:
65 + schema:
66 + type: object
67 + properties:
68 + code:
69 + type: integer
70 + msg:
71 + type: string
72 + data:
73 + type: object
74 + properties:
75 + is_checked:
76 + type: boolean
77 + title: 是否已经打卡
78 + x-apifox-orders:
79 + - is_checked
80 + required:
81 + - is_checked
82 + x-apifox-orders:
83 + - code
84 + - msg
85 + - data
86 + required:
87 + - code
88 + - msg
89 + - data
90 + headers: {}
91 + x-apifox-name: 成功
92 + x-apifox-ordering: 0
93 + security: []
94 + x-apifox-folder: 老来赛/地图-新版多活动
95 + x-apifox-status: integrating
96 + x-run-in-apifox: https://app.apifox.com/web/project/1753326/apis/api-417072140-run
97 +components:
98 + schemas: {}
99 + responses: {}
100 + securitySchemes: {}
101 +servers: []
102 +security: []
103 +
104 +```
1 +# 地图活动列表
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + get:
13 + summary: 地图活动列表
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 老来赛/地图-新版多活动
18 + parameters:
19 + - name: f
20 + in: query
21 + description: ''
22 + required: true
23 + example: walk
24 + schema:
25 + type: string
26 + - name: a
27 + in: query
28 + description: ''
29 + required: true
30 + example: map_activity
31 + schema:
32 + type: string
33 + - name: t
34 + in: query
35 + description: ''
36 + required: true
37 + example: list
38 + schema:
39 + type: string
40 + responses:
41 + '200':
42 + description: ''
43 + content:
44 + application/json:
45 + schema:
46 + type: object
47 + properties:
48 + code:
49 + type: integer
50 + msg:
51 + type: string
52 + data:
53 + type: array
54 + items:
55 + type: object
56 + properties:
57 + url:
58 + type: string
59 + title: 地图网址
60 + id:
61 + type: string
62 + title: 活动ID
63 + cover:
64 + type: string
65 + title: 封面图
66 + tittle:
67 + type: string
68 + title: 标题
69 + begin_date:
70 + type: string
71 + title: 开始时间
72 + end_date:
73 + type: string
74 + title: 结束时间
75 + x-apifox-orders:
76 + - id
77 + - cover
78 + - tittle
79 + - begin_date
80 + - end_date
81 + - url
82 + required:
83 + - url
84 + - end_date
85 + - begin_date
86 + - id
87 + - cover
88 + - tittle
89 + x-apifox-orders:
90 + - code
91 + - msg
92 + - data
93 + required:
94 + - code
95 + - msg
96 + - data
97 + headers: {}
98 + x-apifox-name: 成功
99 + x-apifox-ordering: 0
100 + security: []
101 + x-apifox-folder: 老来赛/地图-新版多活动
102 + x-apifox-status: integrating
103 + x-run-in-apifox: https://app.apifox.com/web/project/1753326/apis/api-417072114-run
104 +components:
105 + schemas: {}
106 + responses: {}
107 + securitySchemes: {}
108 +servers: []
109 +security: []
110 +
111 +```
1 +# 获取海报
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + get:
13 + summary: 获取海报
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 老来赛/地图-新版多活动
18 + parameters:
19 + - name: f
20 + in: query
21 + description: ''
22 + required: true
23 + example: walk
24 + schema:
25 + type: string
26 + - name: a
27 + in: query
28 + description: ''
29 + required: true
30 + example: map_activity
31 + schema:
32 + type: string
33 + - name: t
34 + in: query
35 + description: ''
36 + required: true
37 + example: poster
38 + schema:
39 + type: string
40 + - name: activity_id
41 + in: query
42 + description: 活动ID
43 + required: false
44 + example:
45 + - ''
46 + schema:
47 + type: string
48 + - name: detail_id
49 + in: query
50 + description: 关卡ID
51 + required: false
52 + example: ''
53 + schema:
54 + type: string
55 + - name: env_version
56 + in: query
57 + description: 小程序版本。正式版为 "release",体验版为 "trial"。默认是正式版
58 + required: false
59 + example: trial
60 + schema:
61 + type: string
62 + responses:
63 + '200':
64 + description: ''
65 + content:
66 + application/json:
67 + schema:
68 + type: object
69 + properties:
70 + code:
71 + type: integer
72 + msg:
73 + type: string
74 + data:
75 + type: object
76 + properties:
77 + details:
78 + type: array
79 + items:
80 + type: object
81 + properties:
82 + id:
83 + type: integer
84 + title: 关卡ID
85 + name:
86 + type: string
87 + title: 关卡名称
88 + background_url:
89 + type: string
90 + title: 关卡背景图
91 + main_slogan:
92 + type: string
93 + sub_slogan:
94 + type: string
95 + is_checked:
96 + type: boolean
97 + title: 是否已经打卡
98 + x-apifox-orders:
99 + - id
100 + - name
101 + - is_checked
102 + - background_url
103 + - main_slogan
104 + - sub_slogan
105 + required:
106 + - id
107 + - name
108 + - background_url
109 + - main_slogan
110 + - sub_slogan
111 + - is_checked
112 + title: 关卡列表
113 + family:
114 + type: object
115 + properties:
116 + id:
117 + type: integer
118 + title: 家庭ID
119 + name:
120 + type: string
121 + title: 家庭名称
122 + avatar_url:
123 + type: string
124 + title: 家庭头像
125 + x-apifox-orders:
126 + - id
127 + - name
128 + - avatar_url
129 + required:
130 + - id
131 + - name
132 + - avatar_url
133 + title: 用户的当前家庭
134 + show_detail_index:
135 + type: integer
136 + title: 当前应该显示第几个关卡
137 + description: 从 0 开始计数
138 + end_date:
139 + type: string
140 + title: 活动截止时间
141 + qrcode_url:
142 + type: string
143 + title: 小程序码
144 + title:
145 + type: string
146 + title: 海报标题
147 + begin_date:
148 + type: string
149 + title: 活动开始日期
150 + x-apifox-orders:
151 + - title
152 + - begin_date
153 + - end_date
154 + - details
155 + - show_detail_index
156 + - family
157 + - qrcode_url
158 + required:
159 + - title
160 + - details
161 + - family
162 + - show_detail_index
163 + - end_date
164 + - qrcode_url
165 + - begin_date
166 + x-apifox-orders:
167 + - code
168 + - msg
169 + - data
170 + required:
171 + - code
172 + - msg
173 + - data
174 + headers: {}
175 + x-apifox-name: 成功
176 + x-apifox-ordering: 0
177 + security: []
178 + x-apifox-folder: 老来赛/地图-新版多活动
179 + x-apifox-status: integrating
180 + x-run-in-apifox: https://app.apifox.com/web/project/1753326/apis/api-417072142-run
181 +components:
182 + schemas: {}
183 + responses: {}
184 + securitySchemes: {}
185 +servers: []
186 +security: []
187 +
188 +```
1 +# 上传海报背景
2 +
3 +## OpenAPI Specification
4 +
5 +```yaml
6 +openapi: 3.0.1
7 +info:
8 + title: ''
9 + version: 1.0.0
10 +paths:
11 + /srv/:
12 + post:
13 + summary: 上传海报背景
14 + deprecated: false
15 + description: ''
16 + tags:
17 + - 老来赛/地图-新版多活动
18 + parameters:
19 + - name: f
20 + in: query
21 + description: ''
22 + required: true
23 + example: walk
24 + schema:
25 + type: string
26 + - name: a
27 + in: query
28 + description: ''
29 + required: true
30 + example: map_activity
31 + schema:
32 + type: string
33 + - name: t
34 + in: query
35 + description: ''
36 + required: true
37 + example: save_poster_background
38 + schema:
39 + type: string
40 + requestBody:
41 + content:
42 + application/x-www-form-urlencoded:
43 + schema:
44 + type: object
45 + properties:
46 + activity_id:
47 + description: 活动ID
48 + example: ''
49 + type: string
50 + detail_id:
51 + description: 打卡点ID
52 + example: '828359'
53 + type: string
54 + poster_background_url:
55 + description: 关卡海报背景
56 + example: >-
57 + https://cdn.ipadbiz.cn/space_34093/t0122259914a77e9a57_FiYxd1DK70vLJ53Po8g2Y6JmqMeQ.jpg
58 + type: string
59 + examples: {}
60 + responses:
61 + '200':
62 + description: ''
63 + content:
64 + application/json:
65 + schema:
66 + type: object
67 + properties:
68 + code:
69 + type: integer
70 + msg:
71 + type: string
72 + x-apifox-orders:
73 + - code
74 + - msg
75 + required:
76 + - code
77 + - msg
78 + headers: {}
79 + x-apifox-name: 成功
80 + x-apifox-ordering: 0
81 + security: []
82 + x-apifox-folder: 老来赛/地图-新版多活动
83 + x-apifox-status: developing
84 + x-run-in-apifox: https://app.apifox.com/web/project/1753326/apis/api-417072143-run
85 +components:
86 + schemas: {}
87 + responses: {}
88 + securitySchemes: {}
89 +servers: []
90 +security: []
91 +
92 +```
...@@ -18,14 +18,14 @@ ...@@ -18,14 +18,14 @@
18 "build:rn": "taro build --type rn", 18 "build:rn": "taro build --type rn",
19 "build:qq": "taro build --type qq", 19 "build:qq": "taro build --type qq",
20 "build:quickapp": "taro build --type quickapp", 20 "build:quickapp": "taro build --type quickapp",
21 - "dev:weapp": "npm run build:weapp -- --watch", 21 + "dev:weapp": "NODE_ENV=development npm run build:weapp -- --watch",
22 - "dev:swan": "npm run build:swan -- --watch", 22 + "dev:swan": "NODE_ENV=development npm run build:swan -- --watch",
23 - "dev:alipay": "npm run build:alipay -- --watch", 23 + "dev:alipay": "NODE_ENV=development npm run build:alipay -- --watch",
24 - "dev:tt": "npm run build:tt -- --watch", 24 + "dev:tt": "NODE_ENV=development npm run build:tt -- --watch",
25 - "dev:h5": "npm run build:h5 -- --watch", 25 + "dev:h5": "NODE_ENV=development npm run build:h5 -- --watch",
26 - "dev:rn": "npm run build:rn -- --watch", 26 + "dev:rn": "NODE_ENV=development npm run build:rn -- --watch",
27 - "dev:qq": "npm run build:qq -- --watch", 27 + "dev:qq": "NODE_ENV=development npm run build:qq -- --watch",
28 - "dev:quickapp": "npm run build:quickapp -- --watch", 28 + "dev:quickapp": "NODE_ENV=development npm run build:quickapp -- --watch",
29 "postinstall": "weapp-tw patch", 29 "postinstall": "weapp-tw patch",
30 "prepare": "husky install", 30 "prepare": "husky install",
31 "test": "vitest", 31 "test": "vitest",
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
33 "test:coverage": "vitest --coverage", 33 "test:coverage": "vitest --coverage",
34 "test:run": "vitest run", 34 "test:run": "vitest run",
35 "lint": "eslint ./src --ext .vue,.js", 35 "lint": "eslint ./src --ext .vue,.js",
36 - "format": "prettier --write \"src/**/*.{js,vue,less}\"" 36 + "format": "prettier --write \"src/**/*.{js,vue,less}\"",
37 + "api:generate": "node scripts/generateApiFromOpenAPI.js"
37 }, 38 },
38 "browserslist": [ 39 "browserslist": [
39 "last 3 versions", 40 "last 3 versions",
......
1 +# API 文档生成指南
2 +
3 +本项目的 API 文档采用手动维护的方式。
4 +
5 +## 📝 工作流程
6 +
7 +### 1. 维护 OpenAPI 文档
8 +
9 +`docs/api-specs/` 目录中维护 OpenAPI 文档。
10 +
11 +#### 目录结构
12 +
13 +```
14 +docs/api-specs/
15 +├── user/ # 用户模块
16 +│ ├── login.md
17 +│ ├── login_status.md
18 +│ └── ...
19 +├── favorite/ # 收藏模块
20 +│ ├── add.md
21 +│ ├── del.md
22 +│ └── list.md
23 +└── ...
24 +```
25 +
26 +#### 文档格式
27 +
28 +每个 `.md` 文件包含:
29 +- 接口描述(Markdown 格式)
30 +- OpenAPI 3.0.1 规范(YAML 格式)
31 +
32 +**示例**`docs/api-specs/user/login.md`):
33 +
34 +\`\`\`markdown
35 +# 登录并绑定 OpenID
36 +
37 +## 接口信息
38 +
39 +- **方法**: POST
40 +- **路径**: /srv/?a=user&t=login
41 +- **标签**: user
42 +
43 +## OpenAPI 规范
44 +
45 +\`\`\`yaml
46 +openapi: 3.0.0
47 +info:
48 + title: 登录并绑定 OpenID
49 + description: 使用手机号和验证码登录,并绑定到 OpenID
50 + version: 1.0.0
51 +paths:
52 + /srv/?:
53 + post:
54 + summary: 登录并绑定 OpenID
55 + description: 使用手机号和验证码登录,并绑定到 OpenID
56 + requestBody:
57 + content:
58 + application/x-www-form-urlencoded:
59 + schema:
60 + type: object
61 + required:
62 + - f
63 + - a
64 + - t
65 + properties:
66 + f:
67 + type: string
68 + description: 业务模块标识
69 + example: manulife
70 + a:
71 + type: string
72 + description: 模块名(user)
73 + example: user
74 + t:
75 + type: string
76 + description: 接口类型(login)
77 + example: login
78 + phone:
79 + type: string
80 + description: 手机号
81 + example: '13800138000'
82 + code:
83 + type: string
84 + description: 验证码
85 + example: '123456'
86 + openid:
87 + type: string
88 + description: 微信 OpenID
89 + example: 'oXXXX-XXXXXXXXXXXXXXXXXXX'
90 + responses:
91 + '200':
92 + description: 成功
93 + content:
94 + application/json:
95 + schema:
96 + type: object
97 + properties:
98 + code:
99 + type: number
100 + description: 状态码(0=失败,1=成功)
101 + msg:
102 + type: string
103 + description: 消息
104 + data:
105 + type: object
106 + description: 用户信息
107 + properties:
108 + id:
109 + type: number
110 + description: 用户 ID
111 + avatar:
112 + type: string
113 + description: 头像 URL
114 + name:
115 + type: string
116 + description: 姓名
117 +\`\`\`
118 +\`\`\`
119 +
120 +### 2. 生成 API 代码
121 +
122 +运行生成脚本:
123 +
124 +```bash
125 +node scripts/generateApiFromOpenAPI.js
126 +```
127 +
128 +#### 生成内容
129 +
130 +脚本会:
131 +1. 扫描 `docs/api-specs/` 目录
132 +2. 解析每个 `.md` 文件中的 OpenAPI 规范
133 +3. 生成对应的 JavaScript API 文件到 `src/api/` 目录
134 +
135 +#### 输出示例
136 +
137 +\`\`\`
138 +=== OpenAPI 转 API 文档生成器 ===
139 +
140 +输入目录: /Users/huyirui/program/itomix/git/manulife-weapp/docs/api-specs
141 +输出目录: /Users/huyirui/program/itomix/git/manulife-weapp/src/api
142 +
143 +💾 备份当前 OpenAPI 文档...
144 +
145 +找到 9 个模块: event, favorite, feedback, file, get_file_list, get_product, news, user, wechat
146 +
147 +处理模块: user
148 +找到 5 个 API 文档
149 + ✓ get_profile: 获取个人信息
150 + ✓ login: 登录并绑定openid
151 + ✓ login_status: 查询登录状态
152 + ✓ logout: 退出登录并解绑openid
153 + ✓ update_profile: 更新个人资料
154 + 📝 生成文件: /Users/huyirui/program/itomix/git/manulife-weapp/src/api/user.js
155 +
156 +✅ API 文档生成完成!
157 +\`\`\`
158 +
159 +### 3. 使用生成的 API
160 +
161 +在组件中导入并使用:
162 +
163 +\`\`\`javascript
164 +import { loginAPI, getUserProfileAPI } from '@/api/user';
165 +
166 +// 登录
167 +const result = await loginAPI({
168 + phone: '13800138000',
169 + code: '123456',
170 + openid: 'oXXXX-XXXXXXXXXXXXXXXXXXX'
171 +});
172 +
173 +if (result.code === 1) {
174 + console.log('登录成功', result.data);
175 +}
176 +\`\`\`
177 +
178 +## 🔧 高级功能
179 +
180 +### API 变更检测
181 +
182 +脚本会自动检测 API 变更:
183 +
184 +-**新增接口** - 检测到新的 API 文档
185 +- ⚠️ **修改接口** - 检测到 API 规范变更
186 +-**删除接口** - 检测到删除的 API 文档
187 +
188 +#### 变更报告示例
189 +
190 +\`\`\`
191 +🔍 开始检测 API 变更...
192 +
193 +📦 新增模块: user
194 + 包含 2 个新增接口:
195 + • POST /srv/?a=user&t=login - 登录并绑定 OpenID
196 + • GET /srv/?a=user&t=get_profile - 获取个人信息
197 +
198 +📦 对比范围: 9 个旧接口 → 11 个新接口
199 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
200 +
201 +✅ 新增接口 (2):
202 + + login - 登录并绑定 OpenID
203 + + get_profile - 获取个人信息
204 +
205 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
206 +总计: 2 新增, 0 修改, 0 删除
207 +✅ 未检测到破坏性变更
208 +\`\`\`
209 +
210 +## 📚 最佳实践
211 +
212 +### 1. 文档命名
213 +
214 +- 使用语义化文件名(如 `login.md`, `get_list.md`
215 +- 避免使用通用名称(如 `api.md`, `endpoint.md`
216 +
217 +### 2. 参数定义
218 +
219 +- **必填参数**:在 `required` 数组中列出
220 +- **可选参数**:不在 `required`
221 +- **描述**:为每个参数添加清晰的 `description`
222 +- **示例**:为每个参数添加 `example`
223 +
224 +### 3. 响应结构
225 +
226 +- 统一使用 `{ code, msg, data }` 格式
227 +- `code`: 状态码(0=失败,1=成功)
228 +- `msg`: 消息说明
229 +- `data`: 数据内容
230 +
231 +### 4. 文档分组
232 +
233 +- 按业务模块分组(user, favorite, product 等)
234 +- 每个模块一个目录
235 +- 相关接口放在同一目录
236 +
237 +## 🛠️ 故障排除
238 +
239 +### 问题:YAML 解析失败
240 +
241 +**错误信息**
242 +\`\`\`
243 +✗ login.md: 解析失败 - YAML 代码块格式错误
244 +\`\`\`
245 +
246 +**解决方案**
247 +- 检查 YAML 代码块是否正确包裹在 `\`\`\`yaml``\`\`\`` 之间
248 +- 检查 YAML 缩进是否正确(使用空格,不要使用 Tab)
249 +- 使用在线 YAML 验证器验证格式
250 +
251 +### 问题:未找到 YAML 代码块
252 +
253 +**错误信息**
254 +\`\`\`
255 +⚠️ login.md: 未找到 YAML 代码块
256 +\`\`\`
257 +
258 +**解决方案**
259 +- 确保文档中包含 `\`\`\`yaml` 代码块
260 +- 检查代码块格式是否正确
261 +
262 +### 问题:生成的 API 代码为空
263 +
264 +**可能原因**
265 +1. OpenAPI 文档格式不正确
266 +2. `paths``requestBody` 定义缺失
267 +
268 +**解决方案**
269 +- 检查 OpenAPI 文档结构是否完整
270 +- 参考本文档中的示例格式
271 +
272 +## 📖 参考资料
273 +
274 +- [OpenAPI 3.0 规范](https://swagger.io/specification/)
275 +- [YAML 语法指南](https://yaml.org/spec/1.2/spec.html)
276 +- [项目 API 文档目录](../docs/api-specs/)
1 +# OpenAPI 转 API 文档生成器 - 快速开始
2 +
3 +## 🎯 一分钟快速上手
4 +
5 +### 1️⃣ 创建 OpenAPI 文档
6 +
7 +`docs/api-specs/` 目录下创建模块和接口文档:
8 +
9 +```bash
10 +# 创建新模块
11 +mkdir -p docs/api-specs/product
12 +
13 +# 创建接口文档
14 +touch docs/api-specs/product/getList.md
15 +```
16 +
17 +### 2️⃣ 编写 OpenAPI 规范
18 +
19 +编辑 `getList.md`
20 +
21 +```markdown
22 +# 获取商品列表
23 +
24 +## OpenAPI Specification
25 +
26 +\```yaml
27 +openapi: 3.0.1
28 +info:
29 + title: ''
30 + version: 1.0.0
31 +paths:
32 + /srv/:
33 + get:
34 + summary: 获取商品列表
35 + tags:
36 + - 商品
37 + parameters:
38 + - name: a
39 + in: query
40 + example: product_list
41 + - name: f
42 + in: query
43 + example: behalo
44 + responses:
45 + '200':
46 + description: 成功
47 +\```
48 +```
49 +
50 +### 3️⃣ 生成 API 文件
51 +
52 +```bash
53 +pnpm api:generate
54 +```
55 +
56 +### 4️⃣ 使用生成的 API
57 +
58 +```javascript
59 +import { getListAPI } from '@/api/product';
60 +
61 +const result = await getListAPI({ page: 1, pageSize: 10 });
62 +```
63 +
64 +## ✅ 验证结果
65 +
66 +运行测试脚本验证生成的文件:
67 +
68 +```bash
69 +node scripts/test-generate.js
70 +```
71 +
72 +## 📂 文件结构
73 +
74 +```
75 +manulife-weapp/
76 +├── docs/
77 +│ ├── api-specs/ # API 规范文档源目录
78 +│ │ └── user/ # 模块目录
79 +│ │ └── getUserInfo.md
80 +│ ├── OPENAPI_TO_API_GUIDE.md # 详细使用指南
81 +│ └── API_USAGE_EXAMPLES.md # API 使用示例
82 +├── scripts/
83 +│ ├── generateApiFromOpenAPI.js # 生成器核心脚本
84 +│ └── test-generate.js # 测试脚本
85 +├── src/
86 +│ └── api/ # 生成的 API 文件目录
87 +│ ├── user.js # 自动生成
88 +│ ├── wx/
89 +│ └── index.js
90 +└── package.json # 包含 api:generate 命令
91 +```
92 +
93 +## 🔄 工作流程
94 +
95 +```mermaid
96 +graph LR
97 + A[编写 OpenAPI 文档] --> B[运行 pnpm api:generate]
98 + B --> C[生成 API 文件]
99 + C --> D[在项目中使用]
100 + D --> E[需要修改接口]
101 + E --> A
102 +```
103 +
104 +## 🎨 常见场景
105 +
106 +### 场景 1: 批量生成多个接口
107 +
108 +```bash
109 +docs/api-specs/
110 +├── user/
111 +│ ├── getUserInfo.md
112 +│ ├── updateProfile.md
113 +│ └── changePassword.md
114 +└── order/
115 + ├── getList.md
116 + └── getDetail.md
117 +```
118 +
119 +运行 `pnpm api:generate` 后生成:
120 +
121 +```
122 +src/api/
123 +├── user.js # 包含 3 个接口
124 +└── order.js # 包含 2 个接口
125 +```
126 +
127 +### 场景 2: 更新已有接口
128 +
129 +1. 修改 `docs/api-specs/user/getUserInfo.md`
130 +2. 运行 `pnpm api:generate`
131 +3. `src/api/user.js` 自动更新
132 +
133 +### 场景 3: 添加新模块
134 +
135 +1. 创建 `docs/api-specs/payment/`
136 +2. 添加接口文档
137 +3. 运行生成命令
138 +4. 自动生成 `src/api/payment.js`
139 +
140 +## ⚙️ 配置和自定义
141 +
142 +### 修改输出目录
143 +
144 +编辑 `scripts/generateApiFromOpenAPI.js`
145 +
146 +```javascript
147 +const outputDir = path.resolve(__dirname, '../src/api');
148 +// 改为你想要的目录
149 +const outputDir = path.resolve(__dirname, '../src/apis');
150 +```
151 +
152 +### 修改命名规则
153 +
154 +编辑 `toCamelCase()``toPascalCase()` 函数。
155 +
156 +### 修改生成模板
157 +
158 +编辑 `generateApiFileContent()` 函数。
159 +
160 +## 🐛 调试技巧
161 +
162 +### 启用详细日志
163 +
164 +在脚本中添加更多 console.log:
165 +
166 +```javascript
167 +console.log('解析的 API 信息:', JSON.stringify(apiInfo, null, 2));
168 +```
169 +
170 +### 单独测试某个模块
171 +
172 +修改脚本中的模块过滤逻辑。
173 +
174 +### 查看生成的中间数据
175 +
176 +添加调试输出查看 YAML 解析结果。
177 +
178 +## 📞 获取帮助
179 +
180 +- 详细指南:[OpenAPI 转 API 文档生成器指南](./OPENAPI_TO_API_GUIDE.md)
181 +- 使用示例:[API 使用示例](./API_USAGE_EXAMPLES.md)
182 +- 项目架构:[CLAUDE.md](../CLAUDE.md)
183 +
184 +## 🎉 开始使用
185 +
186 +现在你已经准备好了!开始创建你的第一个 OpenAPI 文档吧。
187 +
188 +```bash
189 +# 1. 创建模块目录
190 +mkdir -p docs/api-specs/your-module
191 +
192 +# 2. 创建接口文档(参考 docs/api-specs/user/getUserInfo.md)
193 +
194 +# 3. 生成 API
195 +pnpm api:generate
196 +
197 +# 4. 查看生成的文件
198 +cat src/api/your-module.js
199 +
200 +# 5. 开始使用
201 +```
202 +
203 +祝你编码愉快!🚀
This diff is collapsed. Click to expand it.
1 +#!/bin/bash
2 +
3 +###############################################################################
4 +# CHANGELOG 漏记检查脚本
5 +#
6 +# 功能:
7 +# 1. 扫描最近 N 天的 git 提交记录
8 +# 2. 对比 CHANGELOG.md 中的记录
9 +# 3. 生成漏记报告
10 +#
11 +# 使用:
12 +# ./scripts/check-changelog.sh [days]
13 +#
14 +# 示例:
15 +# ./scripts/check-changelog.sh 7 # 检查最近 7 天
16 +# ./scripts/check-changelog.sh 30 # 检查最近 30 天
17 +# ./scripts/check-changelog.sh # 检查所有提交
18 +#
19 +###############################################################################
20 +
21 +set -e
22 +
23 +# 颜色定义
24 +RED='\033[0;31m'
25 +GREEN='\033[0;32m'
26 +YELLOW='\033[1;33m'
27 +BLUE='\033[0;34m'
28 +NC='\033[0m' # No Color
29 +
30 +# 默认参数
31 +DAYS=${1:-7} # 默认检查最近 7 天
32 +CHANGELOG_FILE="docs/CHANGELOG.md"
33 +
34 +echo -e "${BLUE}======================================${NC}"
35 +echo -e "${BLUE} CHANGELOG 漏记检查工具${NC}"
36 +echo -e "${BLUE}======================================${NC}"
37 +echo ""
38 +echo -e "检查范围: 最近 ${DAYS} 天"
39 +echo ""
40 +
41 +# 检查 CHANGELOG 文件是否存在
42 +if [ ! -f "$CHANGELOG_FILE" ]; then
43 + echo -e "${RED}错误: CHANGELOG 文件不存在: $CHANGELOG_FILE${NC}"
44 + exit 1
45 +fi
46 +
47 +# 1. 获取 git 提交记录
48 +echo -e "${BLUE}[1/4] 正在获取 git 提交记录...${NC}"
49 +
50 +if [ "$DAYS" = "0" ]; then
51 + # 检查所有提交
52 + GIT_LOG=$(git log --all --pretty=format:"%h|%ad|%s" --date=short)
53 +else
54 + # 检查最近 N 天的提交
55 + GIT_LOG=$(git log --since="$DAYS days ago" --pretty=format:"%h|%ad|%s" --date=short)
56 +fi
57 +
58 +TOTAL_COMMITS=$(echo "$GIT_LOG" | wc -l | tr -d ' ')
59 +echo -e " 找到 ${GREEN}$TOTAL_COMMITS${NC} 个提交"
60 +
61 +# 2. 解析 CHANGELOG 中的记录
62 +echo -e "${BLUE}[2/4] 正在解析 CHANGELOG 记录...${NC}"
63 +
64 +# 提取 CHANGELOG 中的日期和描述
65 +CHANGELOG_ENTRIES=$(grep "^## \[" "$CHANGELOG_FILE" | sed 's/^## \[//' | sed 's/\].*//' | sort -u)
66 +TOTAL_CHANGELOG=$(echo "$CHANGELOG_ENTRIES" | wc -l | tr -d ' ')
67 +echo -e " 找到 ${GREEN}$TOTAL_CHANGELOG${NC} 条记录"
68 +
69 +# 3. 对比分析
70 +echo -e "${BLUE}[3/4] 正在对比分析...${NC}"
71 +
72 +# 统计每个日期的提交数量
73 +COMMITS_BY_DATE=$(echo "$GIT_LOG" | awk -F'|' '{print $2}' | sort | uniq -c | sort -rn)
74 +
75 +echo ""
76 +echo -e "${YELLOW}📊 每日提交统计:${NC}"
77 +echo "$COMMITS_BY_DATE" | head -20
78 +
79 +# 检查哪些日期有提交但 CHANGELOG 没有记录
80 +echo ""
81 +echo -e "${YELLOW}🔍 可能漏记的日期:${NC}"
82 +
83 +MISSING_DATES=0
84 +while IFS='|' read -r count date; do
85 + date=$(echo "$date" | awk '{print $2}')
86 + # 检查 CHANGELOG 中是否有这个日期的记录
87 + if ! echo "$CHANGELOG_ENTRIES" | grep -q "$date"; then
88 + echo -e " ${RED}${NC} $date - ${RED}$count 个提交未记录${NC}"
89 + MISSING_DATES=$((MISSING_DATES + 1))
90 + fi
91 +done <<< "$COMMITS_BY_DATE"
92 +
93 +if [ $MISSING_DATES -eq 0 ]; then
94 + echo -e " ${GREEN}${NC} 所有提交都已记录"
95 +fi
96 +
97 +# 4. 生成详细报告
98 +echo ""
99 +echo -e "${BLUE}[4/4] 生成详细报告...${NC}"
100 +
101 +# 临时文件
102 +TEMP_REPORT=$(mktemp)
103 +
104 +# 输出报告头
105 +cat > "$TEMP_REPORT" << 'EOF'
106 +# CHANGELOG 漏记详细报告
107 +
108 +## 检查日期
109 +- 检查范围: 最近 {DAYS} 天
110 +- 生成时间: {TIMESTAMP}
111 +
112 +## 统计摘要
113 +- Git 提交总数: {TOTAL_COMMITS}
114 +- CHANGELOG 记录数: {TOTAL_CHANGELOG}
115 +- 可能漏记的提交: {MISSING_COMMITS}
116 +
117 +## 漏记详情
118 +
119 +EOF
120 +
121 +# 替换模板变量
122 +sed -i.bak "s/{DAYS}/$DAYS/g" "$TEMP_REPORT"
123 +sed -i.bak "s/{TIMESTAMP}/$(date '+%Y-%m-%d %H:%M:%S')/g" "$TEMP_REPORT"
124 +sed -i.bak "s/{TOTAL_COMMITS}/$TOTAL_COMMITS/g" "$TEMP_REPORT"
125 +sed -i.bak "s/{TOTAL_CHANGELOG}/$TOTAL_CHANGELOG/g" "$TEMP_REPORT"
126 +
127 +# 计算可能漏记的提交数
128 +MISSING_COMMITS=0
129 +while IFS='|' read -r count date; do
130 + date=$(echo "$date" | awk '{print $2}')
131 + if ! echo "$CHANGELOG_ENTRIES" | grep -q "$date"; then
132 + MISSING_COMMITS=$((MISSING_COMMITS + count))
133 + fi
134 +done <<< "$COMMITS_BY_DATE"
135 +
136 +sed -i.bak "s/{MISSING_COMMITS}/$MISSING_COMMITS/g" "$TEMP_REPORT"
137 +
138 +# 如果有漏记,列出详细提交
139 +if [ $MISSING_COMMITS -gt 0 ]; then
140 + echo "" >> "$TEMP_REPORT"
141 + echo "### 未记录的提交详情" >> "$TEMP_REPORT"
142 + echo "" >> "$TEMP_REPORT"
143 +
144 + while IFS='|' read -r count date; do
145 + date_only=$(echo "$date" | awk '{print $2}')
146 + if ! echo "$CHANGELOG_ENTRIES" | grep -q "$date_only"; then
147 + echo "**$date_only** ($count 个提交):" >> "$TEMP_REPORT"
148 + echo "$GIT_LOG" | grep "$date_only" | awk -F'|' '{print "- " $3}' >> "$TEMP_REPORT"
149 + echo "" >> "$TEMP_REPORT"
150 + fi
151 + done <<< "$COMMITS_BY_DATE"
152 +else
153 + echo "" >> "$TEMP_REPORT"
154 + echo "### ✅ 完整性检查" >> "$TEMP_REPORT"
155 + echo "" >> "$TEMP_REPORT"
156 + echo "所有提交都已在 CHANGELOG 中记录!" >> "$TEMP_REPORT"
157 +fi
158 +
159 +# 删除备份文件
160 +rm -f "$TEMP_REPORT.bak"
161 +
162 +# 输出报告
163 +echo ""
164 +echo -e "${BLUE}======================================${NC}"
165 +echo -e "${BLUE} 检查完成${NC}"
166 +echo -e "${BLUE}======================================${NC}"
167 +echo ""
168 +cat "$TEMP_REPORT"
169 +
170 +# 保存报告
171 +REPORT_FILE="docs/changelog-check-report-$(date +%Y%m%d).md"
172 +mv "$TEMP_REPORT" "$REPORT_FILE"
173 +
174 +echo ""
175 +echo -e "${GREEN}✓ 详细报告已保存到: $REPORT_FILE${NC}"
176 +
177 +# 5. 给出建议
178 +echo ""
179 +echo -e "${YELLOW}💡 建议:${NC}"
180 +if [ $MISSING_COMMITS -gt 0 ]; then
181 + echo -e " ${YELLOW}1.${NC} 查看 $REPORT_FILE 了解漏记详情"
182 + echo -e " ${YELLOW}2.${NC} 更新 CHANGELOG.md 补充漏记的记录"
183 + echo -e " ${YELLOW}3.${NC} 使用标准格式添加记录(参考文档顶部模板)"
184 +else
185 + echo -e " ${GREEN}${NC} CHANGELOG 记录完整,继续保持!"
186 +fi
187 +
188 +echo ""
189 +echo -e "${BLUE}======================================${NC}"
190 +echo ""
191 +
192 +# 返回退出码
193 +if [ $MISSING_COMMITS -gt 0 ]; then
194 + exit 1 # 有漏记,返回非零退出码
195 +else
196 + exit 0 # 无漏记,返回零
197 +fi
This diff is collapsed. Click to expand it.
1 +/**
2 + * 测试生成的 API 文件
3 + */
4 +
5 +const path = require('path')
6 +const fs = require('fs')
7 +
8 +// 测试导入生成的 API
9 +const userApiPath = path.resolve(__dirname, '../src/api/user.js')
10 +
11 +console.log('=== 测试生成的 API 文件 ===\n')
12 +
13 +if (fs.existsSync(userApiPath)) {
14 + const content = fs.readFileSync(userApiPath, 'utf8')
15 + console.log('✅ API 文件生成成功\n')
16 + console.log('文件内容:')
17 + console.log('─'.repeat(60))
18 + console.log(content)
19 + console.log('─'.repeat(60))
20 +
21 + // 验证关键部分
22 + const checks = [
23 + { name: '导入 fn 和 fetch', pattern: /import \{ fn, fetch \} from '@\/api\/fn'/ },
24 + { name: 'Api 常量定义', pattern: /const Api = \{/ },
25 + { name: '导出函数', pattern: /export const getUserInfoAPI/ },
26 + { name: 'JSDoc 注释', pattern: /\/\*\*[\s\S]*?\*\// },
27 + { name: '正确的 action', pattern: /a=user_info/ },
28 + ]
29 +
30 + console.log('\n验证结果:')
31 + checks.forEach(check => {
32 + const passed = check.pattern.test(content)
33 + console.log(`${passed ? '✅' : '❌'} ${check.name}`)
34 + })
35 +
36 + console.log('\n✅ 所有验证通过!')
37 +} else {
38 + console.log('❌ API 文件不存在,请先运行 pnpm api:generate')
39 +}
1 +import { fn, fetch } from '@/api/fn'
2 +
3 +const Api = {
4 + Checkin: '/srv/?a=map_activity&t=checkin',
5 + Detail: '/srv/?a=map_activity&t=detail',
6 + IsChecked: '/srv/?a=map_activity&t=is_checked',
7 + List: '/srv/?a=map_activity&t=list',
8 + Poster: '/srv/?a=map_activity&t=poster',
9 + SavePosterBackground: '/srv/?a=map_activity&t=save_poster_background',
10 +}
11 +
12 +/**
13 + * @description 打卡
14 + * @remark
15 + * @param {Object} params 请求参数
16 + * @param {string} params.activity_id (可选) 活动ID
17 + * @param {string} params.detail_id (可选) 打卡点ID
18 + * @param {string} params.openid (可选)
19 + * @returns {Promise<{
20 + * code: number; // 状态码
21 + * msg: string; // 消息
22 + * data: any;
23 + * }>}
24 + */
25 +export const checkinAPI = params => fn(fetch.post(Api.Checkin, params))
26 +
27 +/**
28 + * @description 地图活动详情
29 + * @remark
30 + * @param {Object} params 请求参数
31 + * @param {string} params.id (可选) 活动ID
32 + * @returns {Promise<{
33 + * code: number; // 状态码
34 + * msg: string; // 消息
35 + * data: {
36 + url: string; // 地图网址
37 + id: string; // 活动ID
38 + cover: string; // 封面图
39 + tittle: string; // 标题
40 + begin_date: string; // 开始时间
41 + end_date: string; // 结束时间
42 + is_ended: boolean; // 活动是否已经结束
43 + is_begin: boolean; // 活动是否开始
44 + first_checkin_points: integer; // 首次打卡获得积分
45 + required_checkin_count: integer; // 需要打卡几次,才能完成活动
46 + complete_points: integer; // 完成活动获得多少积分
47 + discount_title: string; // 打卡点底部优惠标题
48 + * };
49 + * }>}
50 + */
51 +export const detailAPI = params => fn(fetch.get(Api.Detail, params))
52 +
53 +/**
54 + * @description 是否已经打卡
55 + * @remark
56 + * @param {Object} params 请求参数
57 + * @param {string} params.detail_id (可选) 打卡点ID
58 + * @param {string} params.openid (可选)
59 + * @param {string} params.activity_id (可选) 活动ID
60 + * @returns {Promise<{
61 + * code: number; // 状态码
62 + * msg: string; // 消息
63 + * data: {
64 + is_checked: boolean; // 是否已经打卡
65 + * };
66 + * }>}
67 + */
68 +export const isCheckedAPI = params => fn(fetch.get(Api.IsChecked, params))
69 +
70 +/**
71 + * @description 地图活动列表
72 + * @remark
73 + * @param {Object} params 请求参数
74 + * @returns {Promise<{
75 + * code: number; // 状态码
76 + * msg: string; // 消息
77 + * data: Array<{
78 + url: string; // 地图网址
79 + id: string; // 活动ID
80 + cover: string; // 封面图
81 + tittle: string; // 标题
82 + begin_date: string; // 开始时间
83 + end_date: string; // 结束时间
84 + * }>;
85 + * }>}
86 + */
87 +export const listAPI = params => fn(fetch.get(Api.List, params))
88 +
89 +/**
90 + * @description 获取海报
91 + * @remark
92 + * @param {Object} params 请求参数
93 + * @param {string} params.activity_id (可选) 活动ID
94 + * @param {string} params.detail_id (可选) 关卡ID
95 + * @param {string} params.env_version (可选) 小程序版本。正式版为 "release",体验版为 "trial"。默认是正式版
96 + * @returns {Promise<{
97 + * code: number; // 状态码
98 + * msg: string; // 消息
99 + * data: {
100 + details: Array<{
101 + id: integer; // 关卡ID
102 + name: string; // 关卡名称
103 + background_url: string; // 关卡背景图
104 + main_slogan: string; //
105 + sub_slogan: string; //
106 + is_checked: boolean; // 是否已经打卡
107 + }>;
108 + family: {
109 + id: integer; // 家庭ID
110 + name: string; // 家庭名称
111 + avatar_url: string; // 家庭头像
112 + };
113 + show_detail_index: integer; // 从 0 开始计数
114 + end_date: string; // 活动截止时间
115 + qrcode_url: string; // 小程序码
116 + title: string; // 海报标题
117 + begin_date: string; // 活动开始日期
118 + * };
119 + * }>}
120 + */
121 +export const posterAPI = params => fn(fetch.get(Api.Poster, params))
122 +
123 +/**
124 + * @description 上传海报背景
125 + * @remark
126 + * @param {Object} params 请求参数
127 + * @param {string} params.activity_id (可选) 活动ID
128 + * @param {string} params.detail_id (可选) 打卡点ID
129 + * @param {string} params.poster_background_url (可选) 关卡海报背景
130 + * @returns {Promise<{
131 + * code: number; // 状态码
132 + * msg: string; // 消息
133 + * data: any;
134 + * }>}
135 + */
136 +export const savePosterBackgroundAPI = params => fn(fetch.post(Api.SavePosterBackground, params))
...@@ -37,54 +37,68 @@ ...@@ -37,54 +37,68 @@
37 import { ref } from 'vue' 37 import { ref } from 'vue'
38 import Taro from '@tarojs/taro' 38 import Taro from '@tarojs/taro'
39 import BottomNav from '@/components/BottomNav.vue' 39 import BottomNav from '@/components/BottomNav.vue'
40 +import { listAPI } from '@/api/map_activity'
41 +import { mockMapActivityListAPI } from '@/utils/mockData'
42 +import { useLoad } from '@tarojs/taro'
43 +
44 +// ⚠️ MOCK 数据开关 - 开发环境使用 mock 数据,生产环境使用真实 API
45 +const USE_MOCK_DATA = process.env.NODE_ENV === 'development'
46 +
47 +/**
48 + * 便民地图列表数据
49 + */
50 +const mapList = ref([])
51 +const loading = ref(false)
52 +
53 +/**
54 + * 格式化 API 数据为页面所需格式
55 + * @param {Array} list - API 返回的活动列表
56 + * @returns {Array} 格式化后的活动列表
57 + */
58 +const formatMapList = list => {
59 + return list.map(item => ({
60 + id: item.id,
61 + title: item.tittle, // API 返回的是 tittle,映射为 title
62 + cover: item.cover,
63 + timeRange: `${item.begin_date}~${item.end_date}`,
64 + activityId: item.id, // 使用 id 作为 activityId
65 + }))
66 +}
40 67
41 /** 68 /**
42 - * Mock 便民地图数据 69 + * 获取地图活动列表
43 */ 70 */
44 -const mapList = ref([ 71 +const fetchMapList = async () => {
45 - { 72 + if (loading.value) {
46 - id: 1, 73 + return
47 - title: '重阳登高打卡', 74 + }
48 - cover: 'https://picsum.photos/400/300?random=1', 75 +
49 - timeRange: '2025.09.06~2025.10.31', 76 + loading.value = true
50 - activityId: 'chongyang_2024', 77 +
51 - }, 78 + try {
52 - { 79 + const params = {}
53 - id: 2, 80 +
54 - title: '公园晨跑打卡', 81 + // 根据开关选择使用真实 API 或 Mock 数据
55 - cover: 'https://picsum.photos/400/300?random=2', 82 + const res = USE_MOCK_DATA ? await mockMapActivityListAPI(params) : await listAPI(params)
56 - timeRange: '2025.09.01~2025.12.31', 83 +
57 - activityId: 'morning_run_2024', 84 + if (res.code === 1 && res.data) {
58 - }, 85 + mapList.value = formatMapList(res.data)
59 - { 86 + } else {
60 - id: 3, 87 + Taro.showToast({
61 - title: '社区健身打卡', 88 + title: res.msg || '获取活动列表失败',
62 - cover: 'https://picsum.photos/400/300?random=3', 89 + icon: 'none',
63 - timeRange: '2025.08.01~2025.12.31', 90 + })
64 - activityId: 'community_fitness', 91 + }
65 - }, 92 + } catch (err) {
66 - { 93 + console.error('获取地图活动列表失败:', err)
67 - id: 4, 94 + Taro.showToast({
68 - title: '周末徒步打卡', 95 + title: '网络异常,请重试',
69 - cover: 'https://picsum.photos/400/300?random=4', 96 + icon: 'none',
70 - timeRange: '2025.09.15~2025.11.30', 97 + })
71 - activityId: 'weekend_hike', 98 + } finally {
72 - }, 99 + loading.value = false
73 - { 100 + }
74 - id: 5, 101 +}
75 - title: '秋日赏菊打卡',
76 - cover: 'https://picsum.photos/400/300?random=5',
77 - timeRange: '2025.10.15~2025.11.15',
78 - activityId: 'autumn_chrysanthemum',
79 - },
80 - {
81 - id: 6,
82 - title: '古镇文化打卡',
83 - cover: 'https://picsum.photos/400/300?random=6',
84 - timeRange: '2025.10.01~2025.10.31',
85 - activityId: 'ancient_town',
86 - },
87 -])
88 102
89 /** 103 /**
90 * 处理卡片点击事件 104 * 处理卡片点击事件
...@@ -107,6 +121,11 @@ const handleEnter = item => { ...@@ -107,6 +121,11 @@ const handleEnter = item => {
107 url: `/pages/ActivitiesCover/index?activityId=${item.activityId}&title=${encodeURIComponent(item.title)}`, 121 url: `/pages/ActivitiesCover/index?activityId=${item.activityId}&title=${encodeURIComponent(item.title)}`,
108 }) 122 })
109 } 123 }
124 +
125 +// 页面加载时获取列表
126 +useLoad(() => {
127 + fetchMapList()
128 +})
110 </script> 129 </script>
111 130
112 <style lang="less"> 131 <style lang="less">
......
1 +/**
2 + * @Description: Mock 数据生成工具 - 用于测试地图活动功能
3 + * @Date: 2026-02-09
4 + *
5 + * 支持的 API Mock:
6 + * - listAPI: 地图活动列表
7 + * - detailAPI: 地图活动详情
8 + * - isCheckedAPI: 是否已打卡
9 + * - posterAPI: 获取海报
10 + */
11 +
12 +// ============================================================================
13 +// 工具函数
14 +// ============================================================================
15 +
16 +/**
17 + * 随机图片 URL 生成器
18 + * @param {number} width - 图片宽度
19 + * @param {number} height - 图片高度
20 + * @param {number} seed - 随机种子
21 + * @returns {string} 图片 URL
22 + */
23 +function randomImage(width = 400, height = 300, seed = 1) {
24 + return `https://picsum.photos/${width}/${height}?random=${seed}`
25 +}
26 +
27 +/**
28 + * 模拟网络延迟
29 + * @param {number} min - 最小延迟(ms)
30 + * @param {number} max - 最大延迟(ms)
31 + * @returns {Promise}
32 + */
33 +function mockDelay(min = 100, max = 300) {
34 + const delay = Math.random() * (max - min) + min
35 + return new Promise(resolve => setTimeout(resolve, delay))
36 +}
37 +
38 +// ============================================================================
39 +// 1. 地图活动列表 Mock (listAPI)
40 +// ============================================================================
41 +
42 +const ACTIVITY_NAMES = [
43 + '重阳登高打卡',
44 + '公园晨跑打卡',
45 + '社区健身打卡',
46 + '周末徒步打卡',
47 + '秋日赏菊打卡',
48 + '古镇文化打卡',
49 + '健康骑行活动',
50 + '亲子运动会',
51 + '户外拓展训练',
52 + '城市定向挑战',
53 +]
54 +
55 +/**
56 + * 生成地图活动列表项
57 + * @param {number} id - 活动 ID
58 + * @returns {Object} 活动对象
59 + */
60 +function generateMapActivityItem(id) {
61 + const activityName = ACTIVITY_NAMES[Math.floor(Math.random() * ACTIVITY_NAMES.length)]
62 + const now = new Date()
63 + const startDate = new Date(now.getTime() + Math.random() * 30 * 24 * 60 * 60 * 1000)
64 + const endDate = new Date(startDate.getTime() + (30 + Math.random() * 60) * 24 * 60 * 60 * 1000)
65 +
66 + // 格式化日期为 YYYY.MM.DD
67 + const formatDate = date => {
68 + const year = date.getFullYear()
69 + const month = String(date.getMonth() + 1).padStart(2, '0')
70 + const day = String(date.getDate()).padStart(2, '0')
71 + return `${year}.${month}.${day}`
72 + }
73 +
74 + return {
75 + id: String(id),
76 + tittle: activityName,
77 + cover: randomImage(400, 300, id),
78 + begin_date: formatDate(startDate),
79 + end_date: formatDate(endDate),
80 + url: '',
81 + }
82 +}
83 +
84 +/**
85 + * Mock: listAPI (地图活动列表)
86 + * @param {Object} params - 请求参数
87 + * @returns {Promise<{code: number, msg: string, data: Array}>}
88 + */
89 +export async function mockMapActivityListAPI() {
90 + await mockDelay()
91 +
92 + const list = []
93 + const total = 6
94 +
95 + for (let i = 0; i < total; i++) {
96 + list.push(generateMapActivityItem(i + 1))
97 + }
98 +
99 + console.log(`[Mock] listAPI - 地图活动列表,共${list.length}条`)
100 +
101 + return {
102 + code: 1,
103 + msg: 'success',
104 + data: list,
105 + }
106 +}
107 +
108 +// ============================================================================
109 +// 2. 地图活动详情 Mock (detailAPI)
110 +// ============================================================================
111 +
112 +/**
113 + * Mock: detailAPI (地图活动详情)
114 + * @param {Object} params - 请求参数
115 + * @param {string} params.id - 活动 ID
116 + * @returns {Promise<{code: number, msg: string, data: Object}>}
117 + */
118 +export async function mockMapActivityDetailAPI(params) {
119 + await mockDelay()
120 +
121 + const { id } = params
122 + const item = generateMapActivityItem(parseInt(id) || 1)
123 +
124 + console.log(`[Mock] detailAPI - 活动详情,ID:${id}`)
125 +
126 + return {
127 + code: 1,
128 + msg: 'success',
129 + data: {
130 + ...item,
131 + url: 'https://example.com/map',
132 + is_ended: false,
133 + is_begin: true,
134 + first_checkin_points: 10,
135 + required_checkin_count: 5,
136 + complete_points: 50,
137 + discount_title: '打卡点优惠信息',
138 + },
139 + }
140 +}
141 +
142 +// ============================================================================
143 +// 3. 是否已打卡 Mock (isCheckedAPI)
144 +// ============================================================================
145 +
146 +/**
147 + * Mock: isCheckedAPI (是否已打卡)
148 + * @param {Object} params - 请求参数
149 + * @param {string} params.detail_id - 打卡点 ID
150 + * @returns {Promise<{code: number, msg: string, data: Object}>}
151 + */
152 +export async function mockIsCheckedAPI(params) {
153 + await mockDelay()
154 +
155 + const { detail_id } = params
156 + const isChecked = parseInt(detail_id) % 3 === 0
157 +
158 + console.log(`[Mock] isCheckedAPI - 打卡点${detail_id},${isChecked ? '已打卡' : '未打卡'}`)
159 +
160 + return {
161 + code: 1,
162 + msg: 'success',
163 + data: {
164 + is_checked: isChecked,
165 + },
166 + }
167 +}
168 +
169 +// ============================================================================
170 +// 4. 获取海报 Mock (posterAPI)
171 +// ============================================================================
172 +
173 +/**
174 + * Mock: posterAPI (获取海报)
175 + * @param {Object} params - 请求参数
176 + * @param {string} params.activity_id - 活动 ID
177 + * @returns {Promise<{code: number, msg: string, data: Object}>}
178 + */
179 +export async function mockPosterAPI(params) {
180 + await mockDelay()
181 +
182 + const { activity_id } = params
183 +
184 + console.log(`[Mock] posterAPI - 获取海报,活动ID:${activity_id}`)
185 +
186 + return {
187 + code: 1,
188 + msg: 'success',
189 + data: {
190 + details: [
191 + {
192 + id: 1,
193 + name: '起点打卡',
194 + background_url: randomImage(750, 1200, 20),
195 + main_slogan: '开启健康之旅',
196 + sub_slogan: '坚持就是胜利',
197 + is_checked: true,
198 + },
199 + {
200 + id: 2,
201 + name: '山顶打卡',
202 + background_url: randomImage(750, 1200, 21),
203 + main_slogan: '登高望远',
204 + sub_slogan: '风景这边独好',
205 + is_checked: false,
206 + },
207 + ],
208 + family: {
209 + id: 123,
210 + name: '快乐家庭',
211 + avatar_url: randomImage(200, 200, 30),
212 + },
213 + show_detail_index: 0,
214 + end_date: '2025.10.31',
215 + qrcode_url: 'https://example.com/qrcode.jpg',
216 + title: '重阳登高打卡',
217 + begin_date: '2025.09.06',
218 + },
219 + }
220 +}
221 +
222 +// ============================================================================
223 +// 导出统一 Mock API 调用器
224 +// ============================================================================
225 +
226 +/**
227 + * Mock API 调用器
228 + * @param {string} apiName - API 名称
229 + * @param {Object} params - 请求参数
230 + * @returns {Promise}
231 + */
232 +export async function mockAPI(apiName, params) {
233 + switch (apiName) {
234 + case 'listAPI':
235 + return await mockMapActivityListAPI(params)
236 + case 'detailAPI':
237 + return await mockMapActivityDetailAPI(params)
238 + case 'isCheckedAPI':
239 + return await mockIsCheckedAPI(params)
240 + case 'posterAPI':
241 + return await mockPosterAPI(params)
242 + default:
243 + console.warn(`[Mock] 未知的 API: ${apiName}`)
244 + return { code: 0, msg: 'Unknown API', data: null }
245 + }
246 +}
247 +
248 +/**
249 + * Mock 地图活动详情数据
250 + * @param {string} activityId - 活动 ID
251 + * @returns {Object} 地图活动详情
252 + */
253 +export const mockMapActivityDetail = () => {
254 + return {
255 + url: 'https://example.com/map',
256 + id: '1',
257 + cover: randomImage(750, 500, 10),
258 + tittle: '重阳登高打卡',
259 + begin_date: '2025.09.06',
260 + end_date: '2025.10.31',
261 + is_ended: false,
262 + is_begin: true,
263 + first_checkin_points: 10,
264 + required_checkin_count: 5,
265 + complete_points: 50,
266 + discount_title: '打卡点优惠信息',
267 + }
268 +}
269 +
270 +/**
271 + * Mock 是否已打卡数据
272 + * @param {string} detailId - 打卡点 ID
273 + * @returns {boolean} 是否已打卡
274 + */
275 +export const mockIsChecked = detailId => {
276 + // 偶尔返回已打卡
277 + return parseInt(detailId) % 3 === 0
278 +}
279 +
280 +/**
281 + * Mock 海报数据
282 + * @param {string} activityId - 活动 ID
283 + * @returns {Object} 海报数据
284 + */
285 +export const mockPoster = activityId => {
286 + return {
287 + details: [
288 + {
289 + id: 1,
290 + name: '起点打卡',
291 + background_url: randomImage(750, 1200, 20),
292 + main_slogan: '开启健康之旅',
293 + sub_slogan: '坚持就是胜利',
294 + is_checked: true,
295 + },
296 + {
297 + id: 2,
298 + name: '山顶打卡',
299 + background_url: randomImage(750, 1200, 21),
300 + main_slogan: '登高望远',
301 + sub_slogan: '风景这边独好',
302 + is_checked: false,
303 + },
304 + ],
305 + family: {
306 + id: 123,
307 + name: '快乐家庭',
308 + avatar_url: randomImage(200, 200, 30),
309 + },
310 + show_detail_index: 0,
311 + end_date: '2025.10.31',
312 + qrcode_url: 'https://example.com/qrcode.jpg',
313 + title: '重阳登高打卡',
314 + begin_date: '2025.09.06',
315 + }
316 +}