# 活动信息发布模块 · 功能与接口说明 v1 > 武校家校信息发布 —— 活动信息发布子模块。本文档面向后端联调与前端维护,与代码同步维护。 > 前端契约:`src/types/activity.ts`、`src/api/module/activity.ts`;本地 mock:`src/assets/mock/activityapi.ts`。 ## 一、页面与路由 | 页面 | 路由 | 组件 | 关键交互 | | --- | --- | --- | --- | | 我发布的 | `/list` | `ActivityList.vue` | 状态标签(全部/报名中/已截止/已结束/草稿)、时间范围 + 分类 + 关键字筛选、发布活动入口 | | 全部活动 | `/activitylist` | `ActivityList.vue` | 同组件;不传 `scope=user`,展示全量 | | 发布活动 | `/list/new` | `NewActivity.vue` | `?serid=` 编辑、`?fid=` 复用;立即发布 / 存草稿 / 定时发布 | | 活动详情 | `/list/detail`、`/activitylist/detail` | `ActivityDetails.vue` | `type=0` 管理视角(阅读 + 回执进度、报名情况、编辑、复用、打印);`type=1` 查看视角(标读) | | 报名情况 | `/signups` | `Signups.vue` | 活动下拉切换、回执状态筛选、汇总卡、按班级分组名单、回执详情、代为确认/取消、催报名、导出 CSV | | 活动统计 | `/stats` | `ActivityStats.vue` | 总量卡、分类分布、月度趋势、发布人分布、我发布活动的回执表 | | 应用设置 | `/setting` | `ActivitySetting.vue` | 主办部门(拖拽排序 / 启停 / 内联改名)+ 自定义组(组成员设置) | | 活动广场 | `/par/activities` | `ParentActivities.vue` | 家长端;标签(全部/待回执/已报名/已结束)+ 关键字;右侧详情 + 报名回执弹窗 | | 我的报名 | `/par/mine` | `ParentActivities.vue` | 同组件,`meta.initTab=signed` | 菜单 ↔ 路由通过 `meta.modId` 契约绑定(`src/router/routes.ts` 头部注释为唯一口径来源): ``` 2 我发布的 /list 3 全部活动 /activitylist 4 活动统计 /stats 21 应用设置 /setting 25 报名情况 /signups 31 活动广场 /par/activities 32 我的报名 /par/mine 22 发布活动 /list/new (深层子页,parentId=2,不在菜单) 23 活动详情 /list/detail (parentId=2) 24 活动详情 /activitylist/detail (parentId=3) ``` ## 二、枚举口径 | 字段 | 取值 | 含义 | | --- | --- | --- | | `actStatus` | `draft` / `signup` / `closed` / `finished` | 草稿 / 报名中 / 已截止 / 已结束 | | `receiptMode` | `none` / `signup` / `confirm` | 仅通知 / 需报名 / 需确认(打开即自动确认) | | `status`(回执记录) | `none` / `signed` / `confirmed` / `canceled` | 未回执 / 已报名 / 已确认 / 已取消(请假) | 派生量(`ActivityProgress`):`should` 应收、`signed` 已报名、`confirmed` 已确认、`canceled` 已取消、 `unsigned` 未回执、`signupRate` 回执率(%)、`quota` 名额上限、`usedQuota` 已占名额、`full` 是否满额。 `receiptMode = none` 或 `actStatus = draft` 时 `progress` 为 `null`(不产生回执记录,只统计已读)。 ## 三、接口清单 统一响应 `{ code, msg, data }`,`code` 为 0 表示成功,由 `utils/alova/alova-core.ts` 解包为 `data`。 ### 基础 / 布局(`/api/base`) | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/base/GetUserInfo` | 当前登录用户 | | GET | `/api/base/GetUserMod` | 已授权模块(左侧菜单) | | POST | `/api/base/SetRole` | 切换视角 `{ as: "teacher" \| "parent" }`,需在拉取用户信息前调用 | | GET | `/api/base/GetSchoolAll` | 教师组织树(选择用户) | | GET | `/api/base/GetClassTree` | 年级 → 班级树(发布对象到班级一级,叶子带 `studentCount`) | | POST | `/api/base/FileUpload` | 附件上传 | ### 活动域(`/api/activity`) | 方法 | 路径 | 入参 | 说明 | | --- | --- | --- | --- | | GET | `/List` | `ActivityQuery` | 家长端收件箱(已发布 + 面向本班) | | GET | `/SendList` | `ActivityQuery`(`scope=user` 只看自己) | 我发布的 / 全部活动 | | GET | `/Detail` | `serid, type` | `type=1` 标读;`type=0` 不标读(管理视角) | | GET | `/GetDetail` | `serid` | 编辑/复用回显,不标读 | | GET | `/GetNextPrev` | `serid, type` | 上一篇/下一篇 id | | GET | `/ReadDetail` | `serid` | 阅读情况:按年级分组的班级读/未读 | | POST | `/Create` | `ActivityRequest` | 新建,返回活动 id | | POST | `/Edit` | `ActivityRequest`(含 `sourceId`) | 编辑 | | POST | `/Delete` | `number[]` | 批量删除(级联清回执记录) | | POST | `/InitializeRed` | —— | 一键全部已读 | | POST | `/UserPull` | `serid` | 撤回(家长端不可见) | | POST | `/SetTopmost` | `serid, topmost` | 置顶 / 取消置顶 | | POST | `/Expedite` | `serid` | 催办未读,返回 `{ reminded }` | | POST | `/ReceiveClasses` | `serid, classes` | 追加接收班级(补发,自动补回执记录) | | GET | `/Statis` | `startTime?, endTime?` | 活动统计 | | GET | `/Signups` | `serid, signupStatus` | 报名回执名单(按班级分组 + 汇总) | | GET | `/SignupDetail` | `signupId` | 单条回执详情 | | POST | `/Review` | `{ signupId, action: "confirm"\|"cancel"\|"waitlist", remark? }` | 处理回执 | | POST | `/Remind` | `serid` | 催报名,返回 `{ reminded }` | | GET | `/ExportSignups` | `serid` | 导出回执名单(JSON 包装 `{ csv }`,csv 为带 BOM 的 CSV 文本,前端取 csv 字段生成文件下载) | | GET | `/MyActivities` | `ActivityQuery` | 家长端活动广场(含分桶计数 `buckets`) | | GET | `/MySignup` | `serid` | 家长端活动详情 + 我的回执(同时标读) | | POST | `/Signup` | `{ serid, joinCount, guardianName, guardianPhone, remark }` | 家长报名 / 修改回执 | | POST | `/CancelSignup` | `serid` | 取消报名 | ### 字典 / 联系组 | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/dict/List?type=1` | 主办部门下拉(仅启用) | | GET | `/api/dict/ManageList?type=dept` | 主办部门管理列表 | | POST | `/api/dict/Add` / `Update` / `Delete` / `Sort` | 主办部门增删改与排序 | | GET | `/api/contacts/GetGroup` | 自定义组分页 | | POST | `/api/contacts/AddGroup` / `EditGroup` / `DelGroup` | 自定义组增删改 | | GET | `/api/contacts/GetContactsTea` | 组内成员(`page=0&count=0` 取全部) | | POST | `/api/contacts/SetContactsTea` | 设置组内成员 | | GET | `/api/contacts/GetGroupTree` | 组 → 成员树(选人弹窗 tab) | ### 文件 | 方法 | 路径 | 说明 | | --- | --- | --- | | POST | `/api/file/UploadImage` | 富文本内嵌图片上传 | | GET | `/api/file/Preview` | 文件预览 | | GET | `/api/file/Down` | 附件下载 | | GET | `/api/activity/AllFileDown` | 全部附件打包下载 | ## 四、关键实现约定 1. **表单参数传递**:`postForm` 会把参数同时拼进 URL query。后端 `@RequestParam` 都能接收;本地 `vite-plugin-mock` 不解析 `application/x-www-form-urlencoded` body,靠 query 才能取到参数(不影响线上)。 2. **`@RequestBody` 接口**(`Create` / `Edit` / `Delete` / `Signup` / `Review`)走 `postJSON`,mock 侧用 `bodyOf(body, query)` 合并取参。 3. **接收班级**:`receiveList = "ALL"` 或班级 id 逗号串;`targetClassIds()` 统一解析。 4. **已读判定**:以班级为粒度(`classRead: string[]`);应收 / 已读人数按班级 `studentCount` 累加。 5. **端分离**:`App.vue` 依据路由前缀(`/par` → 家长端)调用 `SetRole` 切换视角并重新拉取 `GetUserMod`, 菜单与用户信息随视角变化;家长端菜单提供「发布端(教师)」入口便于返回。 6. **表格高度**:`Utils.useTableHeight({ isSearch, isTabs, isPage, isOperat })`,头部 112(自身 header 56 + 面包屑 56)。 7. **操作列图标**:`Utils.operatingHandle(h, 提示, iconClass, cb)`,图标取自 `src/assets/styles/icons.css` 的 bsch-icons 字体。