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>
Showing
16 changed files
with
1969 additions
and
54 deletions
docs/api-specs/map_activity/checkin.md
0 → 100644
| 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 | +``` |
docs/api-specs/map_activity/detail.md
0 → 100644
| 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 | +``` |
docs/api-specs/map_activity/is_checked.md
0 → 100644
| 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 | +``` |
docs/api-specs/map_activity/list.md
0 → 100644
| 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 | +``` |
docs/api-specs/map_activity/poster.md
0 → 100644
| 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", | ... | ... |
scripts/API_GUIDE.md
0 → 100644
| 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/) |
scripts/QUICKSTART.md
0 → 100644
| 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 | +祝你编码愉快!🚀 |
scripts/apiDiff.js
0 → 100644
This diff is collapsed. Click to expand it.
scripts/check-changelog.sh
0 → 100755
| 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 |
scripts/generateApiFromOpenAPI.js
0 → 100644
This diff is collapsed. Click to expand it.
scripts/test-generate.js
0 → 100644
| 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 | +} |
src/api/map_activity.js
0 → 100644
| 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"> | ... | ... |
src/utils/mockData.js
0 → 100644
| 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 | +} |
-
Please register or login to post a comment