|
@@ -0,0 +1,359 @@
|
|
|
|
|
+# 院区「探访公告」后端接口文档
|
|
|
|
|
+
|
|
|
|
|
+- 版本:v1.0
|
|
|
|
|
+- 日期:2026-09-21
|
|
|
|
|
+- 状态:**待评审 / 供后端开发**(前端已按此契约完成编码,如路径或字段需调整请同步告知前端)
|
|
|
|
|
+- 适用端:Web 管理后台(admin-api) + 家属端小程序(app-api)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 1. 背景与目标
|
|
|
|
|
+
|
|
|
|
|
+家属端小程序「探访」页面需要展示一段**院区自定义的探访公告**(探视时间、探视须知、注意事项等)。
|
|
|
|
|
+
|
|
|
|
|
+- 公告内容由**各院区在 Web 管理后台自行维护**,每个院区维护一份。
|
|
|
|
|
+- 保存后小程序端实时读取并展示,**无需审核、无历史版本**。
|
|
|
|
|
+- 公告为纯文本,按换行符拆分为多条展示。
|
|
|
|
|
+- 小程序端公告按 `noticeType` 区分:`APPOINTMENT` 为本文新增的院区自定义公告(后台可维护);`VISIT` 为原有系统固定数据,**本次不改动、保持现状**。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 2. 名词约定
|
|
|
|
|
+
|
|
|
|
|
+| 名词 | 含义 |
|
|
|
|
|
+| --- | --- |
|
|
|
|
|
+| 院区 | 系统中的机构/租户,即 `tenant_id`。集团账号下有多个院区,普通院区账号仅有一个 |
|
|
|
|
|
+| 探访公告 | 本文描述的业务对象,对应表 `elderly_notice_customer` |
|
|
|
|
|
+| 后台接口 | 前缀 `/admin-api`,Web 管理后台调用,需登录鉴权 |
|
|
|
|
|
+| C 端接口 | 前缀 `/app-api`,家属端小程序调用 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 3. 接口清单
|
|
|
|
|
+
|
|
|
|
|
+| 编号 | 名称 | 方法 | 路径 | 调用方 |
|
|
|
|
|
+| --- | --- | --- | --- | --- |
|
|
|
|
|
+| API-1 | 查询院区探访公告 | GET | `/admin-api/elderly/notice-customer/get` | Web 后台 |
|
|
|
|
|
+| API-2 | 保存院区探访公告(新增/更新) | POST | `/admin-api/elderly/notice-customer/save` | Web 后台 |
|
|
|
|
|
+| API-3 | 小程序获取探访公告(按类型) | GET | `/app-api/elderly/notice-customer/get` | 家属端小程序 |
|
|
|
|
|
+
|
|
|
|
|
+> API-3 通过 `noticeType` 区分场景:
|
|
|
|
|
+> - `noticeType=APPOINTMENT`:走院区自定义公告(即本文第 4 章的表数据,由后台维护);
|
|
|
|
|
+> - `noticeType=VISIT`:维持现状,返回系统固定数据,不读该表。
|
|
|
|
|
+>
|
|
|
|
|
+> 接口路径前缀沿用项目现有 elderly 模块风格(如 `/elderly/visit/appointment/page`)。若后端命名规范不同,请统一告知,前端改一处常量即可:`src/api/elderly/elder/notice-customer/index.ts` 中的 `API_PREFIX`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 4. 数据字典
|
|
|
|
|
+
|
|
|
|
|
+### 4.1 表结构(MySQL)
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+CREATE TABLE `elderly_notice_customer` (
|
|
|
|
|
+ `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
|
|
|
|
+ `tenant_id` bigint NOT NULL COMMENT '院区(租户)id',
|
|
|
|
|
+ `notice` text NULL COMMENT '公告内容,纯文本,换行符 \n 分隔多条',
|
|
|
|
|
+ `creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
|
|
|
|
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
|
|
|
+ `updater` varchar(64) DEFAULT '' COMMENT '更新者',
|
|
|
|
|
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
|
|
|
+ `deleted` bit(1) DEFAULT b'0' COMMENT '逻辑删除',
|
|
|
|
|
+ PRIMARY KEY (`id`),
|
|
|
|
|
+ UNIQUE KEY `uk_tenant_id` (`tenant_id`, `deleted`)
|
|
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='院区探访公告';
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4.2 字段说明
|
|
|
|
|
+
|
|
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
|
|
+| --- | --- | --- | --- |
|
|
|
|
|
+| `id` | Long | 是 | 主键,保存时为空=新增,有值=更新 |
|
|
|
|
|
+| `tenantId` | Long | 是 | 院区(租户)id,唯一约束:一个院区仅一条公告 |
|
|
|
|
|
+| `notice` | String | 否 | 公告内容,纯文本,最大 2000 字符;空串表示清空公告。对应 C 端 `noticeType=APPOINTMENT` 返回的内容 |
|
|
|
|
|
+| `createTime` | LocalDateTime | - | 创建时间 |
|
|
|
|
|
+| `updateTime` | LocalDateTime | - | 更新时间 |
|
|
|
|
|
+| `creator` / `updater` | String | - | 创建人 / 更新人 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 5. 接口详情
|
|
|
|
|
+
|
|
|
|
|
+### 5.1 API-1 查询院区探访公告
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+GET /admin-api/elderly/notice-customer/get
|
|
|
|
|
+Content-Type: application/x-www-form-urlencoded(query)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**请求参数**
|
|
|
|
|
+
|
|
|
|
|
+| 参数 | 位置 | 类型 | 必填 | 说明 |
|
|
|
|
|
+| --- | --- | --- | --- | --- |
|
|
|
|
|
+| `tenantId` | query | Long | 是 | 院区 id |
|
|
|
|
|
+
|
|
|
|
|
+**响应**(`CommonResult<NoticeCustomerRespVO>`)
|
|
|
|
|
+
|
|
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
|
|
+| --- | --- | --- |
|
|
|
|
|
+| `id` | Long | 主键;**该院区未配置公告时为 null** |
|
|
|
|
|
+| `tenantId` | Long | 院区 id |
|
|
|
|
|
+| `notice` | String | 公告内容;无配置时为 null 或空串 |
|
|
|
|
|
+| `createTime` | String | yyyy-MM-dd HH:mm:ss |
|
|
|
|
|
+| `updateTime` | String | yyyy-MM-dd HH:mm:ss |
|
|
|
|
|
+
|
|
|
|
|
+**响应示例(已配置)**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "id": 12,
|
|
|
|
|
+ "tenantId": 195,
|
|
|
|
|
+ "notice": "探视时间:每日 09:00-11:30、14:30-17:00\n每位老人每日限 2 位访客\n请配合前台登记并佩戴口罩",
|
|
|
|
|
+ "createTime": "2026-09-21 10:12:33",
|
|
|
|
|
+ "updateTime": "2026-09-21 15:40:02"
|
|
|
|
|
+ },
|
|
|
|
|
+ "msg": ""
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例(未配置)**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{ "code": 0, "data": null, "msg": "" }
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> 未配置时请返回 `code=0` + `data=null`(或 `data` 中 `notice` 为空),**不要返回业务错误码**,前端会展示空内容等待编辑。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 5.2 API-2 保存院区探访公告
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+POST /admin-api/elderly/notice-customer/save
|
|
|
|
|
+Content-Type: application/json
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**请求体**(`NoticeCustomerSaveReqVO`)
|
|
|
|
|
+
|
|
|
|
|
+| 字段 | 类型 | 必填 | 校验 | 说明 |
|
|
|
|
|
+| --- | --- | --- | --- | --- |
|
|
|
|
|
+| `id` | Long | 否 | - | 有值则更新,无值则按 `tenantId` 做 upsert |
|
|
|
|
|
+| `tenantId` | Long | 是 | `@NotNull` | 院区 id |
|
|
|
|
|
+| `notice` | String | 是 | `@Size(max = 2000)` | 公告内容;可为空串(清空公告) |
|
|
|
|
|
+
|
|
|
|
|
+**请求示例**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "id": 12,
|
|
|
|
|
+ "tenantId": 195,
|
|
|
|
|
+ "notice": "探视时间:每日 09:00-11:30、14:30-17:00\n每位老人每日限 2 位访客"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应**(`CommonResult<Long>`,返回公告主键 id)
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{ "code": 0, "data": 12, "msg": "" }
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+### 5.3 API-3 小程序获取探访公告
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+GET /app-api/elderly/notice-customer/get?tenantId=195¬iceType=APPOINTMENT
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**请求参数**
|
|
|
|
|
+
|
|
|
|
|
+| 参数 | 位置 | 类型 | 必填 | 说明 |
|
|
|
|
|
+| --- | --- | --- | --- | --- |
|
|
|
|
|
+| `tenantId` | query | Long | 是 | 院区 id;若小程序已通过登录态确定院区,可改为从 token 中解析(见「待确认」) |
|
|
|
|
|
+| `noticeType` | query | String | 是 | 公告类型枚举:`APPOINTMENT` / `VISIT` |
|
|
|
|
|
+
|
|
|
|
|
+**`noticeType` 枚举与数据来源**
|
|
|
|
|
+
|
|
|
|
|
+| 值 | 含义 | 数据来源 | 行为 |
|
|
|
|
|
+| --- | --- | --- | --- |
|
|
|
|
|
+| `APPOINTMENT` | 预约(探访预约)公告 | **院区自定义**:读 `elderly_notice_customer` 表(后台维护) | 按 `tenantId` 查询该院区公告,返回维护内容 |
|
|
|
|
|
+| `VISIT` | 探访公告 | **系统固定数据**(后端固定返回,不读该表) | **保持现状不变**,与 `tenantId`、后台维护内容无关 |
|
|
|
|
|
+
|
|
|
|
|
+**处理逻辑**
|
|
|
|
|
+
|
|
|
|
|
+1. `noticeType = APPOINTMENT`:按 `tenantId` 查询 `elderly_notice_customer`,返回该院区维护的公告。
|
|
|
|
|
+2. `noticeType = VISIT`:**沿用现有固定的返回数据,本次不做任何改动**(不查 `elderly_notice_customer`,忽略院区配置)。
|
|
|
|
|
+3. `noticeType` 缺失或非法值:返回 `400` 参数错误。**不要默认按 `APPOINTMENT` 处理**,避免前端漏传时误展示自定义内容。
|
|
|
|
|
+
|
|
|
|
|
+**响应结构**(两种类型结构一致,仅 `notice` 内容来源不同)
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "notice": "探视时间:每日 09:00-11:30、14:30-17:00\n每位老人每日限 2 位访客"
|
|
|
|
|
+ },
|
|
|
|
|
+ "msg": ""
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例(`noticeType=APPOINTMENT`,院区已配置)**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "notice": "探视时间:每日 09:00-11:30、14:30-17:00\n每位老人每日限 2 位访客"
|
|
|
|
|
+ },
|
|
|
|
|
+ "msg": ""
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例(`noticeType=APPOINTMENT`,院区未配置)**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{ "code": 0, "data": { "notice": "" }, "msg": "" }
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例(`noticeType=VISIT`)**
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "notice": "(沿用现有固定文案,内容与现状完全一致)"
|
|
|
|
|
+ },
|
|
|
|
|
+ "msg": ""
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> `notice` 为 null 或空串时,小程序端隐藏对应公告模块(`APPOINTMENT` 且院区未配置即为此情况)。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 6. 通用响应结构
|
|
|
|
|
+
|
|
|
|
|
+沿用项目 yudao/若依约定:
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{ "code": 0, "data": {}, "msg": "" }
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+`code = 0` 表示成功,非 0 为业务/系统错误。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 7. 业务与校验规则(后端必须实现)
|
|
|
|
|
+
|
|
|
|
|
+1. **一个院区仅一条公告**:`tenant_id` 唯一索引;`save` 接口实现 **upsert**
|
|
|
|
|
+ - `id` 有值 → 按 id 更新(需校验 id 对应记录的 `tenant_id` 与入参一致)
|
|
|
|
|
+ - `id` 无值 → 按 `tenantId` 查询,存在则更新,不存在则新增
|
|
|
|
|
+2. **越权校验**:`tenantId` 必须在当前登录账号可见的机构范围内(集团账号取其关联机构列表;普通院区账号只能操作自己院区),不在范围内返回 `code=403`「无权操作该院区」。**不可信任前端传参**。
|
|
|
|
|
+3. **长度校验**:`notice` 最长 **2000** 字符,超出返回参数错误。
|
|
|
|
|
+4. **清空公告**:`notice` 传空串视为清空(前端已强制非空,此处仅说明后端不做非空强校验亦可,请二选一并保持一致)→ **建议后端允许空串**,避免院区无法下架公告。
|
|
|
|
|
+5. **展示规则**:公告为纯文本,`\n` 视为一条;小程序端与后台预览均按行拆分渲染,**后端不做富文本解析**。
|
|
|
|
|
+6. **租户隔离**:沿用现有租户体系;查询/保存均带租户条件,使用逻辑删除 `deleted`。
|
|
|
|
|
+7. **审计字段**:新增写 `creator/createTime`,更新写 `updater/updateTime`。
|
|
|
|
|
+8. **无需审批流**:保存即生效,C 端实时读取(如 C 端有缓存,需保证 5 分钟内失效或提供刷新)。
|
|
|
|
|
+9. **C 端按 `noticeType` 分支**:
|
|
|
|
|
+ - `APPOINTMENT` → 院区自定义公告(本文维护的数据),与后台配置联动;
|
|
|
|
|
+ - `VISIT` → 系统固定数据,**保持现状**,不读表、不受后台维护影响;
|
|
|
|
|
+ - 后台接口(API-1 / API-2)只维护 `APPOINTMENT` 对应的公告,无需传 `noticeType`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 8. 权限标识建议
|
|
|
|
|
+
|
|
|
|
|
+| 标识 | 说明 | 前端位置 |
|
|
|
|
|
+| --- | --- | --- |
|
|
|
|
|
+| `elderly:notice-customer:query` | 查看院区探访公告 | 页面进入 / 重新加载 |
|
|
|
|
|
+| `elderly:notice-customer:save` | 保存院区探访公告 | 「保存」按钮 |
|
|
|
|
|
+
|
|
|
|
|
+> 若后端不配置权限,前端页面默认对所有可见该菜单的角色开放;如需按钮级控制请回复,前端补充 `v-hasPermi`。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 9. 错误码
|
|
|
|
|
+
|
|
|
|
|
+| code | 含义 | 触发场景 |
|
|
|
|
|
+| --- | --- | --- |
|
|
|
|
|
+| 0 | 成功 | - |
|
|
|
|
|
+| 400 | 参数错误 | `tenantId` 为空 / `notice` 超 2000 字符 / `noticeType` 缺失或非枚举值 |
|
|
|
|
|
+| 401 | 未登录 | token 失效 |
|
|
|
|
|
+| 403 | 无权限 | 操作了非本账号可见的院区 |
|
|
|
|
|
+| 404 | 数据不存在 | 按 `id` 更新时记录不存在或已删除 |
|
|
|
|
|
+| 500 | 系统异常 | - |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 10. 后端实现骨架(yudao 风格,供参考)
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+@RestController
|
|
|
|
|
+@RequestMapping("/elderly/notice-customer")
|
|
|
|
|
+@Validated
|
|
|
|
|
+public class NoticeCustomerController {
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private NoticeCustomerService noticeCustomerService;
|
|
|
|
|
+
|
|
|
|
|
+ @GetMapping("/get")
|
|
|
|
|
+ @PreAuthorize("@ss.hasPermission('elderly:notice-customer:query')")
|
|
|
|
|
+ public CommonResult<NoticeCustomerRespVO> getNoticeCustomer(@RequestParam("tenantId") Long tenantId) {
|
|
|
|
|
+ // 1. 校验 tenantId 在当前账号可见机构范围内
|
|
|
|
|
+ return success(noticeCustomerService.getByTenantId(tenantId));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @PostMapping("/save")
|
|
|
|
|
+ @PreAuthorize("@ss.hasPermission('elderly:notice-customer:save')")
|
|
|
|
|
+ public CommonResult<Long> saveNoticeCustomer(@RequestBody @Valid NoticeCustomerSaveReqVO reqVO) {
|
|
|
|
|
+ // 1. 校验 tenantId 可见范围 2. upsert 3. 返回 id
|
|
|
|
|
+ return success(noticeCustomerService.saveNoticeCustomer(reqVO));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+public class NoticeCustomerSaveReqVO {
|
|
|
|
|
+ private Long id;
|
|
|
|
|
+ @NotNull(message = "院区不能为空")
|
|
|
|
|
+ private Long tenantId;
|
|
|
|
|
+ @Size(max = 2000, message = "公告内容不能超过 2000 个字符")
|
|
|
|
|
+ private String notice;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+public class NoticeCustomerRespVO {
|
|
|
|
|
+ private Long id;
|
|
|
|
|
+ private Long tenantId;
|
|
|
|
|
+ private String notice;
|
|
|
|
|
+ private LocalDateTime createTime;
|
|
|
|
|
+ private LocalDateTime updateTime;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 11. 前端现状(已按本文实现)
|
|
|
|
|
+
|
|
|
|
|
+| 内容 | 位置 |
|
|
|
|
|
+| --- | --- |
|
|
|
|
|
+| 接口文档(本文) | `src/api/elderly/elder/notice-customer/notice-customer-api.md` |
|
|
|
|
|
+| 接口封装 | `src/api/elderly/elder/notice-customer/index.ts`(`getNoticeCustomer` / `saveNoticeCustomer`) |
|
|
|
|
|
+| 页面 | `src/views/elderly/elder/notice-customer/index.vue`(院区选择 + 公告编辑 + 小程序预览) |
|
|
|
|
|
+| 院区选择规则 | 集团账号(`orgTenant.multiple = true`)可切换院区;普通院区账号固定为当前院区,选择器禁用 |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 12. 待确认问题
|
|
|
|
|
+
|
|
|
|
|
+1. 接口路径与表名:`elderly/notice-customer`、`elderly_notice_customer` 是否 OK?
|
|
|
|
|
+2. **公告是否保持纯文本 + 换行展示**,还是未来需要富文本/多条结构化(标题 + 内容)?
|
|
|
|
|
+3. C 端接口 `tenantId` 由前端传参,还是由登录态(token)解析?
|
|
|
|
|
+4. 是否需要「公告生效时间 / 上下架开关」?
|
|
|
|
|
+5. 是否需要操作日志或变更记录?
|
|
|
|
|
+6. 权限标识是否按第 8 节配置?
|
|
|
|
|
+7. `notice` 是否允许为空串(清空公告)?
|
|
|
|
|
+8. `noticeType` 枚举值是否就定为 `APPOINTMENT` / `VISIT`(大小写敏感,需与小程序端完全一致)?
|
|
|
|
|
+9. `noticeType=VISIT` 的固定数据目前维护在何处(代码常量 / 配置文件 / 数据字典)?是否也需要后续纳入后台维护?
|