@lichidental/saas-cli 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,442 @@
1
+ openapi: 3.0.3
2
+ info:
3
+ title: 励齿 SaaS 预约相关接口(实测校准版)
4
+ version: 1.0.0
5
+ description: |
6
+ ## 目标读者
7
+ - **AI 工具 / 程序**:作为接口的机器可读权威规范直接消费(写对接代码、生成请求)
8
+ - **后端工程师**:手工核对接口参数与响应字段时参考(人类友好的导读见 接口说明.md)
9
+
10
+ ## 来源与可信度
11
+ - 本文档由前端调用行为(前端仓库 src/api/*.ts)+ 真实实测响应整理而成
12
+ - 采集时间:2026-10-12,环境:test.saas.lichidental.com;
13
+ 每个接口的请求体与响应均与 docs/samples/ 下的实测样本一一对应
14
+ - 本规范为逆向整理(后端未提供正式文档);与后端实现如有出入,以后端为准
15
+ - sendCustomMarkSms 接口未实测(标记 x-untested: true)
16
+
17
+ ## 通用约定
18
+ - 所有接口均为 POST + JSON 请求体;HTTP 状态码恒为 200,业务结果看响应体 status 字段
19
+ - 请求头:token(必填,登录凭据)、Version(前端构建版本号,如 v26.09.2.0)、channel: html
20
+ - 客户端对 POST 请求不携带 clinicId query 参数;诊所归属由 token 决定
21
+ - 请求体中的时间为 `YYYY-MM-DD HH:mm:ss` 字符串(本地时间,非 ISO)
22
+ - 响应体中的时间为 ISO 格式(形如 `2026-11-01T11:00:00`,注意带 T)
23
+
24
+ ## 响应包装(所有接口一致)
25
+ - 成功:`{"status":200,"code":"SUCCESS","message":"处理成功","data":...}`
26
+ - 失败:`{"status":<错误码>,"code":"<错误标识>","message":"<错误描述>"}`(401 无 data 字段)
27
+ servers:
28
+ - url: https://test.saas.lichidental.com
29
+ description: 测试环境(本文档样本采集环境)
30
+ - url: https://pre.saas.lichidental.com
31
+ description: 预发环境(地址来自前端 .env,未实测)
32
+ - url: https://saas.lichidental.com
33
+ description: 生产环境(地址来自前端 .env,未实测)
34
+
35
+ security:
36
+ - tokenAuth: []
37
+
38
+ tags:
39
+ - name: 员工
40
+ - name: 患者
41
+ - name: 预约项目
42
+ - name: 预约
43
+
44
+ paths:
45
+ /user/saas/t-lichi-user-store/getStoreUserListByParam:
46
+ post:
47
+ tags: [员工]
48
+ operationId: getStoreUserListByParam
49
+ summary: 医生列表
50
+ description: |
51
+ 返回"在职(0)+ 试用(2)"状态、岗位为"医生(1)"的员工列表。
52
+ 实测样本:docs/samples/getStoreUserListByParam.json(19 条)
53
+ requestBody:
54
+ required: true
55
+ content:
56
+ application/json:
57
+ schema:
58
+ type: object
59
+ required: [delFlags, storeUserPostIds]
60
+ properties:
61
+ delFlags:
62
+ type: array
63
+ items: { type: integer }
64
+ description: "在职状态过滤:0=在职, 1=离职, 2=试用"
65
+ example: [0, 2]
66
+ storeUserPostIds:
67
+ type: array
68
+ items: { type: integer }
69
+ description: "岗位过滤:1=医生, 2=管理员, 3=洁牙师, 4=咨询师, 5=助理, 6=护士, 7=前台, 8=技师, 9=行政, 10=财务, 11=客服, 12=网店营销, 13=采购, 14=库管, 15=学生, 16=销售"
70
+ example: [1]
71
+ responses:
72
+ '200':
73
+ description: 成功时 data 为员工对象数组(关键字段见下;完整字段见样本文件)
74
+ content:
75
+ application/json:
76
+ schema:
77
+ type: object
78
+ properties:
79
+ status: { type: integer, example: 200 }
80
+ code: { type: string, example: SUCCESS }
81
+ message: { type: string, example: 处理成功 }
82
+ data:
83
+ type: array
84
+ items:
85
+ type: object
86
+ properties:
87
+ userUid:
88
+ type: string
89
+ description: 员工唯一标识(创建预约的 doctorId 用此值)
90
+ example: "26051131994"
91
+ storeUserName:
92
+ type: string
93
+ description: 员工姓名
94
+ example: 李医生
95
+ storeUserPostIds:
96
+ description: 岗位 id 列表(元素为字符串,如 ["1"])
97
+ type: array
98
+ items: { type: string }
99
+ delFlag: { type: integer, description: 在职状态(0 在职 / 1 离职 / 2 试用) }
100
+ additionalProperties: true
101
+
102
+ /user/saas/custom/customParamPageList:
103
+ post:
104
+ tags: [患者]
105
+ operationId: customParamPageList
106
+ summary: 搜索患者(分页)
107
+ description: |
108
+ 按关键词搜索患者(paramText 支持姓名 / 手机号 / 病历号)。
109
+ 实测样本:docs/samples/customParamPageList.json
110
+ requestBody:
111
+ required: true
112
+ content:
113
+ application/json:
114
+ schema:
115
+ type: object
116
+ required: [pageNum, pageSize]
117
+ properties:
118
+ pageNum: { type: integer, example: 1 }
119
+ pageSize: { type: integer, example: 20 }
120
+ paramText:
121
+ type: string
122
+ description: 搜索关键词(姓名 / 手机号 / 病历号);不传则返回全部
123
+ example: "张"
124
+ dateType:
125
+ type: integer
126
+ description: 固定传 3(前端既有写法);实测其他取值未验证
127
+ example: 3
128
+ responses:
129
+ '200':
130
+ description: 成功时 data.list 为患者数组,data.total 为匹配总数
131
+ content:
132
+ application/json:
133
+ schema:
134
+ type: object
135
+ properties:
136
+ status: { type: integer, example: 200 }
137
+ code: { type: string, example: SUCCESS }
138
+ message: { type: string, example: 处理成功 }
139
+ data:
140
+ type: object
141
+ properties:
142
+ total: { type: integer, description: 匹配总数, example: 9 }
143
+ pageNum: { type: integer }
144
+ pages: { type: integer }
145
+ list:
146
+ type: array
147
+ items:
148
+ type: object
149
+ properties:
150
+ customCode:
151
+ type: string
152
+ description: 患者编码(创建预约的 customCode 用此值)
153
+ example: YONGCE26073100001
154
+ customName: { type: string, example: 张三 }
155
+ customPhone: { type: string, description: 手机号,可能为空字符串, example: "16326432746" }
156
+ codeNum: { type: string, description: 病历号, example: "YONGCE26073100142" }
157
+ sex: { type: integer, description: 性别(1=男, 2=女) }
158
+ customSourceName: { type: string, description: 患者来源 }
159
+ lableConfigDTOS: { description: 患者标签, type: array, items: { type: object, additionalProperties: true } }
160
+ additionalProperties: true
161
+
162
+ /user/saas/treat-item/getTreatItemList:
163
+ post:
164
+ tags: [预约项目]
165
+ operationId: getTreatItemList
166
+ summary: 预约项目列表
167
+ description: |
168
+ 返回全部预约项目(平铺数组,无分页、无请求参数)。
169
+ level=1 为一级分类,level=2 为二级项目(通过 upTreatItemId 关联一级分类的 id)。
170
+ 实测样本:docs/samples/getTreatItemList.json(共 42 个,其中一级分类 10 个)
171
+ requestBody:
172
+ required: false
173
+ content:
174
+ application/json:
175
+ schema:
176
+ type: object
177
+ description: 无参数,传空对象 {} 或不传均可
178
+ responses:
179
+ '200':
180
+ description: 成功时 data 为项目平铺数组
181
+ content:
182
+ application/json:
183
+ schema:
184
+ type: object
185
+ properties:
186
+ status: { type: integer, example: 200 }
187
+ code: { type: string, example: SUCCESS }
188
+ message: { type: string, example: 处理成功 }
189
+ data:
190
+ type: array
191
+ items:
192
+ type: object
193
+ properties:
194
+ id: { type: integer, description: 项目 id(level=2 时用于组装 treatItemJson 的 id), example: 84050 }
195
+ treatItemName: { type: string, description: 项目名称, example: 口腔检查 }
196
+ treatItemTitle: { type: string }
197
+ upTreatItemId:
198
+ type: integer
199
+ description: 上级分类 id(level=1 的分类行为 0)
200
+ example: 84048
201
+ level: { type: integer, description: 层级:1=一级分类, 2=二级项目, enum: [1, 2], example: 2 }
202
+ orderNum: { type: integer }
203
+ itemNum: { type: integer }
204
+ additionalProperties: true
205
+
206
+ /user/saas/custom-mark/customMarkInfoByCustom:
207
+ post:
208
+ tags: [预约]
209
+ operationId: customMarkInfoByCustom
210
+ summary: 按患者识别就诊类型(初诊/复诊)
211
+ description: |
212
+ 根据患者的历史预约 / 就诊记录返回本次就诊类型。前端在"新建预约"选择患者后调用。
213
+ 实测样本:docs/samples/customMarkInfoByCustom.json(visitType=0)
214
+ requestBody:
215
+ required: true
216
+ content:
217
+ application/json:
218
+ schema:
219
+ type: object
220
+ required: [customCode]
221
+ properties:
222
+ customCode: { type: string, description: 患者编码, example: YONGCE26073100001 }
223
+ responses:
224
+ '200':
225
+ description: 成功时 data.visitType 为就诊类型
226
+ content:
227
+ application/json:
228
+ schema:
229
+ type: object
230
+ properties:
231
+ status: { type: integer, example: 200 }
232
+ code: { type: string, example: SUCCESS }
233
+ message: { type: string, example: 处理成功 }
234
+ data:
235
+ type: object
236
+ properties:
237
+ visitType:
238
+ type: integer
239
+ description: 就诊类型:1=初诊, 0=复诊(注意:创建预约时 boolFirst 需转成字符串 "1"/"0")
240
+ enum: [0, 1]
241
+ example: 0
242
+ customMarkDtos:
243
+ type: array
244
+ description: 患者历史预约记录(结构见样本文件;本工具未使用)
245
+ items: { type: object, additionalProperties: true }
246
+ additionalProperties: true
247
+
248
+ /user/saas/custom-mark/customMarkListByCustom:
249
+ post:
250
+ tags: [预约]
251
+ operationId: customMarkListByCustom
252
+ summary: 按患者 + 时间范围查询预约记录(列表展示用,推荐)
253
+ description: |
254
+ 按患者 + 时间范围查询预约记录。前端患者详情「就诊记录」与卡片「下次预约」tab 使用本接口;CLI 的 reservation list 亦使用它。
255
+ 实测:startTime/endTime 服务端过滤生效;返回已按 markStartTime 降序排序(前端不排序,依赖后端顺序)。
256
+ 实测样本:docs/samples/customMarkListByCustom.json
257
+ requestBody:
258
+ required: true
259
+ content:
260
+ application/json:
261
+ schema:
262
+ type: object
263
+ required: [customCode]
264
+ properties:
265
+ customCode:
266
+ type: string
267
+ description: 患者编码(精确过滤)
268
+ example: YONGCE26073100001
269
+ startTime: { type: string, description: "开始时间 YYYY-MM-DD HH:mm:ss(实测生效)", example: "2026-10-15 00:00:00" }
270
+ endTime: { type: string, description: "结束时间 YYYY-MM-DD HH:mm:ss(实测生效)", example: "2026-10-15 23:59:59" }
271
+ pageSize: { type: integer, description: "每页条数(前端用 10;取全部可用 999)", example: 999 }
272
+ time: { type: string, description: 分页游标:上一页最后一条的 markStartTime }
273
+ additionalProperties: true
274
+ responses:
275
+ '200':
276
+ description: 成功时 data.cmList 为预约数组(已按 markStartTime 降序)
277
+ content:
278
+ application/json:
279
+ schema:
280
+ type: object
281
+ properties:
282
+ status: { type: integer, example: 200 }
283
+ code: { type: string, example: SUCCESS }
284
+ message: { type: string, example: 处理成功 }
285
+ data:
286
+ type: object
287
+ properties:
288
+ cmList:
289
+ type: array
290
+ items:
291
+ type: object
292
+ properties:
293
+ id: { type: integer, example: 1260615 }
294
+ clinicId: { type: integer }
295
+ customCode: { type: string }
296
+ doctorId: { type: string, description: 医生 userUid(字符串) }
297
+ status: { type: integer, description: "预约状态数字:1=已预约, 9=已确认, 2=已到店, 3/4=治疗中/待收费, 5=治疗完成, 6=已离店" }
298
+ visitStatus: { type: integer, description: "就诊状态(前端显示状态的主键):1=预约未到, 2=待分诊, 3=治疗中, 4=待收费, 5=已完成, 6=已离店" }
299
+ boolFirst: { type: integer, description: "就诊类型(数字):1=初诊 / 0=复诊" }
300
+ isMark: { type: integer, description: 是否预约(0/1) }
301
+ isRegister: { type: integer, description: "是否挂号(0/1);前端按 !(isMark===0 && isRegister===1) 剔除「仅挂号」" }
302
+ markDate: { type: string }
303
+ markStartTime: { type: string, description: "ISO 格式(带 T)", example: "2026-10-15T10:00:00" }
304
+ markEndTime: { type: string }
305
+ markTimeLength: { type: integer }
306
+ treatItemJson: { type: string }
307
+ remark: { type: string }
308
+ additionalProperties: true
309
+ additionalProperties: true
310
+
311
+ /user/saas/custom-mark/addCustomMark:
312
+ post:
313
+ tags: [预约]
314
+ operationId: addCustomMark
315
+ summary: 新建预约
316
+ description: |
317
+ **写操作**,调用即真实创建预约。
318
+ 实测样本:docs/samples/addCustomMark.json(成功创建 id=1260617)。
319
+ 注意:前端类型定义声称响应 data 只有 updateNum,但实测响应同时包含 id(预约 id)。
320
+ requestBody:
321
+ required: true
322
+ content:
323
+ application/json:
324
+ schema:
325
+ $ref: '#/components/schemas/AddCustomMarkRequest'
326
+ responses:
327
+ '200':
328
+ description: 成功时 data 含 id(预约 id)与 updateNum
329
+ content:
330
+ application/json:
331
+ schema:
332
+ type: object
333
+ properties:
334
+ status: { type: integer, example: 200 }
335
+ code: { type: string, example: SUCCESS }
336
+ message: { type: string, example: 处理成功 }
337
+ data:
338
+ type: object
339
+ properties:
340
+ id: { type: integer, description: 新建预约的 id, example: 1260617 }
341
+ updateNum: { type: integer, example: 1 }
342
+ additionalProperties: true
343
+
344
+ /user/saas/custom-mark/sendCustomMarkSms:
345
+ post:
346
+ tags: [预约]
347
+ operationId: sendCustomMarkSms
348
+ summary: 发送预约短信给患者
349
+ x-untested: true
350
+ description: |
351
+ **写操作(会给患者手机发短信)**。本接口未实测(避免给真实号码发短信);
352
+ 参数与前端调用一致,首次使用时请自行验证。工具对应参数:`reservation create --sms`。
353
+ requestBody:
354
+ required: true
355
+ content:
356
+ application/json:
357
+ schema:
358
+ type: object
359
+ required: [customCode, markStartTime]
360
+ properties:
361
+ customCode: { type: string, description: 患者编码 }
362
+ markStartTime:
363
+ type: string
364
+ description: 预约开始时间。注意与 addCustomMark 不同:此接口格式为 "YYYY-MM-DD HH:mm"(不带秒;见前端 sendCustomMarkSmsApi 调用)
365
+ example: "2026-11-01 11:00"
366
+ responses:
367
+ '200':
368
+ description: 成功(响应结构未经实测;前端仅依据 status 判断,失败码 30002=短信发送失败、410=短信余额不足)
369
+ content:
370
+ application/json:
371
+ schema:
372
+ type: object
373
+ properties:
374
+ status: { type: integer, example: 200 }
375
+ code: { type: string }
376
+ message: { type: string }
377
+ data: { nullable: true }
378
+ additionalProperties: true
379
+
380
+ components:
381
+ securitySchemes:
382
+ tokenAuth:
383
+ type: apiKey
384
+ in: header
385
+ name: token
386
+ description: 登录凭据(token 头的值即 SaaS 浏览器登录后的 localStorage.userInfo.token)
387
+
388
+ schemas:
389
+ AddCustomMarkRequest:
390
+ type: object
391
+ required: [customCode, doctorId, markStartTime, markTimeLength, treatItemJson]
392
+ properties:
393
+ customCode:
394
+ type: string
395
+ description: 患者编码(来自 customParamPageList 的 data.list[].customCode)
396
+ example: YONGCE26073100001
397
+ doctorId:
398
+ type: string
399
+ description: 医生 userUid(来自 getStoreUserListByParam 的 data[].userUid)。字符串类型,不要传数字
400
+ example: "26051131994"
401
+ markStartTime:
402
+ type: string
403
+ description: 预约开始时间。格式严格为 "YYYY-MM-DD HH:mm:ss"(本地时间;不要用 ISO 的 T 分隔)
404
+ example: "2026-11-01 11:00:00"
405
+ markTimeLength:
406
+ type: integer
407
+ minimum: 15
408
+ maximum: 480
409
+ description: |
410
+ 持续时长(分钟)。前端下拉可选值:15/30/45/60/75/90/105/120/135/150/165/180/195/210/225/240/300/360/420/480。
411
+ 前端看板框选上限 480 分钟;超出范围的取值未验证
412
+ example: 30
413
+ treatItemJson:
414
+ type: string
415
+ description: |
416
+ 预约项目的 **JSON 字符串**(不是数组本身)。元素结构见 TreatItemJsonItem。
417
+ 组装来源:getTreatItemList 中 level=2 的项目(id/treatItemName)与其父分类(upTreatItemId 对应 level=1 的 id/treatItemName)
418
+ example: '[{"up_id":84048,"up_title":"口腔","id":84050,"title":"口腔检查"}]'
419
+ boolFirst:
420
+ type: string
421
+ enum: ["1", "0"]
422
+ description: 就诊类型。1=初诊,0=复诊。**字符串**(不是数字);可用 customMarkInfoByCustom 的 data.visitType 转成字符串
423
+ example: "0"
424
+ definitionCreateTime:
425
+ type: string
426
+ description: 创建时间,格式同 markStartTime。前端与 CLI 均传当前时间;省略该字段的行为未验证
427
+ example: "2026-10-12 11:01:51"
428
+ remark:
429
+ type: string
430
+ description: 备注,可为空字符串
431
+ example: ""
432
+ additionalProperties: false
433
+
434
+ TreatItemJsonItem:
435
+ type: object
436
+ description: treatItemJson 字符串解析后的单个元素
437
+ required: [up_id, up_title, id, title]
438
+ properties:
439
+ up_id: { type: integer, description: 一级分类 id(level=1 的 id), example: 84048 }
440
+ up_title: { type: string, description: 一级分类名称, example: 口腔 }
441
+ id: { type: integer, description: 二级项目 id(level=2 的 id), example: 84050 }
442
+ title: { type: string, description: 二级项目名称, example: 口腔检查 }