/** * 武校家校信息发布 · 活动信息发布模块 前端类型契约 * * 与后端 VO/DTO 一一对齐(Jackson 默认驼峰序列化,详情 VO 保留旧字段名): * - ActivityVo → 活动列表项 * - ActivityDetailVo → 活动详情(@JsonProperty 保留 Contents / DeptName 等旧字段名) * - SignupsResultVo → 某活动的报名回执情况 * - ActivityStatisticsVo → 活动统计 * - ActivityRequest → 发布/编辑入参 * - ActivityQuery → 列表查询入参 * * 业务要点(武校家校场景): * 1. 发布对象到「班级」一级:receiveList = "ALL" 或 班级 id 逗号串; * 应收人数、已读人数按班级学生数累加(家长即挂在学生档案上的联系人)。 * 2. 回执方式 receiptMode: * - none 仅通知(无需回执,只统计已读;家长端「阅读即知悉」) * - signup 需报名(家长填报参加人数,可带随行) * - confirm 需确认(家长端**打开活动即自动确认**,无需点击) * 3. 活动流程状态 status:draft 草稿 → signup 报名中 → closed 已截止 → finished 已结束。 */ // ============================ 分页外壳 ============================ /** 统一分页响应外壳 */ export interface BasePageResult { total: number; content: T[]; pageIndex: number; pageSize: number; totalPages: number; hasNext: boolean; } /** 活动分页结果(扩展当前视角未读数) */ export interface ActivityPageResult extends BasePageResult { /** 当前用户未读活动总数 */ unreadCount: number; } // ============================ 枚举 ============================ /** 活动流程状态 */ export type ActivityStatus = "draft" | "signup" | "closed" | "finished"; /** 回执方式:none 仅通知(阅读即知悉)/ signup 需报名 / confirm 需确认(打开即自动确认) */ export type ReceiptMode = "none" | "signup" | "confirm"; /** 单条回执(报名)状态 */ export type SignupStatus = "none" | "signed" | "confirmed" | "canceled"; /** 当前视角角色(家长端以学生身份登录,不单列) */ export type ViewerRole = "teacher" | "parent"; // ============================ 回执进度 ============================ /** 活动回执/报名进度(草稿或仅通知为 null) */ export interface ActivityProgress { /** 应收人数 */ should: number; /** 已报名人数 */ signed: number; /** 已确认人数 */ confirmed: number; /** 已取消/请假人数 */ canceled: number; /** 未回执人数 */ unsigned: number; /** 回执率(%) */ signupRate: number; /** 名额上限,0 表示不限 */ quota: number; /** 已用名额(按随行人数合计) */ usedQuota: number; /** 是否名额已满 */ full: boolean; } // ============================ 活动列表项 ============================ /** 活动视图对象(列表用) */ export interface ActivityVo { id: number; title: string; content: string; /** 活动分类(存分类名称,选项来自「应用设置-活动分类」字典,存 sys_dict dict_type=category) */ category: string; /** 活动地点 */ venue: string; /** 活动开始时间 yyyy-MM-dd HH:mm:ss */ startTime: string | null; /** 活动结束时间 */ endTime: string | null; /** 报名截止时间 */ signupDeadline: string | null; /** 回执方式 */ receiptMode: ReceiptMode; receiptModeDesc: string; /** 名额上限(0 不限) */ quota: number; /** 是否允许家长随行 */ allowAccompany: number; /** 活动费用(元) */ cost: number; /** 发布人ID(平台用户ID;家长端=学生ID) */ publisherId: number; publisherName: string; /** 主办部门 */ deptId: string; deptName: string; status: number; statusDesc: string; /** 活动流程状态 */ actStatus: ActivityStatus; actStatusDesc: string; topmost: number; /** 已读人数 */ readCount: number; /** 应读人数 */ allowCount: number; /** 当前用户是否已读 */ read: boolean; /** 是否撤回:0 否 / 1 是 */ isPulled: number; /** 定时发送时间 */ timingSendTime: string | null; /** 短信发送标记 */ smsFlag: number; /** 接收对象类型:class=班级 */ receiveType?: string; /** 接收列表:"all" 或 班级 id 逗号串 */ receiveList: string | null; /** 接收对象可读文本 */ receiveText?: string; /** 覆盖班级数 */ classCount?: number; /** 回执/报名进度(草稿或仅通知为 null) */ progress?: ActivityProgress | null; createBy: string | null; createTime: string | null; updateBy: string | null; updateTime: string | null; } // ============================ 活动详情 ============================ /** 活动详情视图对象(保留旧字段名,便于复用既有详情排版) */ export interface ActivityDetailVo { serid: number; title: string; /** 活动内容(旧字段名 Contents) */ Contents: string; /** 主办部门ID(旧字段名 DeptID) */ DeptID: string; /** 主办部门名称(旧字段名 DeptName) */ DeptName: string; /** 发布人姓名(旧字段名 TeaName) */ TeaName: string; /** 发布时间(旧字段名 EditDate,已格式化为字符串) */ EditDate: string; /** 应读人数 */ numcount: number; /** 已读人数 */ readnumcount: number; /** 接收人列表 */ ReceiveList: string | null; /** 定时发送时间(旧字段名 DsfsTime) */ DsfsTime: string | null; /** 是否定时发送 */ isDsfs: boolean; /** 活动分类 */ category: string; /** 活动地点 */ venue: string; startTime: string | null; endTime: string | null; signupDeadline: string | null; receiptMode: ReceiptMode; receiptModeDesc: string; quota: number; allowAccompany: number; cost: number; actStatus: ActivityStatus; actStatusDesc: string; progress: ActivityProgress | null; /** 附件列表(旧字段名 ChaoSend) */ ChaoSend: ActivityDetailFileItem[]; /** 接收对象列表:"all" 或 班级 id 数组 */ tlist: string | string[]; receiveType?: string; /** 接收对象可读文本 */ receiveText?: string; } /** 活动详情附件项 */ export interface ActivityDetailFileItem { id: number; name: string; size: number; fileid: number; filename: string; } // ============================ 文件上传 ============================ /** 文件上传结果 */ export interface UpFileResultVo { fileid: number; name: string; fileurl: string; host: string; type: string; size: number; } /** 附件视图对象 */ export interface UpFileVo { id: number; fileTrueName: string; fileName: string; fileSize: number; fileType: string; topicId: number; topicType: string; } // ============================ 一键已读 ============================ /** 一键已读结果 */ export interface InitializeRedVo { count: number; } // ============================ 上一篇/下一篇 ============================ /** 上一篇/下一篇活动ID */ export interface NextPrevVo { prevId: number; nextId: number; } // ============================ 阅读情况 ============================ /** 阅读情况分组项(字段名固定) */ export interface ReadGroup { GroupName: string; teaslist: ReadGroupUser[]; } /** 阅读情况用户项(id 为班级ID,读/未读按班级粒度) */ export interface ReadGroupUser { id: string; teaname: string; states: "read" | "unread"; } // ============================ 回执 / 报名 ============================ /** 回执名单项(Signups 接口返回,精简) */ export interface SignupBrief { signupId: number; studentId: number; studentName: string; className: string; /** 家长姓名 */ guardianName: string; /** 联系电话 */ guardianPhone: string; /** 参加人数(含学生本人) */ joinCount: number; status: SignupStatus; statusDesc: string; signedAt: string | null; /** 是否已回执/已报名 */ hasReceipt: boolean; /** 备注(如过敏史、随行人数说明) */ remark: string; } /** 回执名单按班级分组 */ export interface SignupGroup { className: string; students: SignupBrief[]; } /** 某活动的回执/报名结果 */ export interface SignupsResultVo { activityId: number; title: string; category: string; venue: string; startTime: string | null; signupDeadline: string | null; actStatus: ActivityStatus; actStatusDesc: string; receiptMode: ReceiptMode; receiptModeDesc: string; summary: ActivityProgress; groups: SignupGroup[]; } /** 单条回执详情(回执详情弹窗用) */ export interface SignupDetailVo { signupId: number; activityId: number; activityTitle: string; category: string; studentId: number; studentName: string; classId: string; className: string; guardianName: string; guardianPhone: string; joinCount: number; status: SignupStatus; statusDesc: string; signedAt: string | null; read: boolean; readAt: string | null; remark: string; } /** 回执审核/处理入参 */ export interface ReviewRequest { signupId: number; /** confirm 确认参加 / cancel 取消或请假 / waitlist 转待定 */ action: "confirm" | "cancel" | "waitlist"; remark?: string; } // ============================ 统计 ============================ /** 活动统计视图 */ export interface ActivityStatisticsVo { /** 活动总数 */ total: number; /** 已发布(含报名中/已截止/已结束) */ publishedCount: number; /** 我发布的活动数 */ myActivityCount: number; /** 累计回执/报名人次 */ totalSignups: number; /** 平均回执率(%) */ avgSignupRate: number; /** 待处理回执(名额超额或需人工确认) */ pendingReview: number; /** 按主办部门 */ byPublisher: { publisherName: string; count: number }[]; /** 按月份 */ byMonth: { year: number; month: number; count: number }[]; /** 按活动分类分布 */ byCategory: { label: string; key: string; count: number }[]; /** 我发布的活动·回执与已读 */ byActivity: ({ id: number; title: string; category: string; venue: string; actStatus: ActivityStatus; actStatusDesc: string; } & ActivityProgress)[]; } // ============================ 请求入参 ============================ /** 活动发布/编辑入参 */ export interface ActivityRequest { title: string; content?: string; /** 活动分类 */ category?: string; /** 活动地点 */ venue?: string; /** 活动开始时间 yyyy-MM-dd HH:mm:ss */ startTime?: string; /** 活动结束时间 */ endTime?: string; /** 报名截止时间 */ signupDeadline?: string; /** 回执方式 */ receiptMode?: ReceiptMode; /** 名额上限(0 不限) */ quota?: number; /** 是否允许家长随行 */ allowAccompany?: number; /** 活动费用(元) */ cost?: number; /** 主办部门ID */ deptId?: string; deptName?: string; /** 存草稿:true 则不发布 */ draft?: boolean; topmost?: number; /** 接收对象:"all" 或 班级 id 逗号串(receiveType=class) */ receiveList?: string; /** 接收对象类型:class=班级 */ receiveType?: string; /** 附件文件ID列表(逗号分隔串) */ fileIds?: string; /** 定时发送时间 */ timingSendTime?: string; /** 短信发送标记 */ smsFlag?: number; /** 转发/复用的源活动ID */ sourceId?: number; } /** 活动列表查询参数 */ export interface ActivityQuery { pageIndex?: number; pageSize?: number; keyword?: string; /** 列表范围(管理端):"user" 只看自己发布的,不传=全部 */ scope?: string; deptId?: string; /** 活动分类筛选 */ category?: string; /** 流程状态筛选:draft/signup/closed/finished,缺省或 all=全部 */ actStatus?: string; /** 发布人ID */ publisherId?: number; /** 开始时间(yyyy-MM-dd 短日期) */ startTime?: string; /** 结束时间(yyyy-MM-dd 短日期) */ endTime?: string; /** 阅读状态过滤(仅家长端):0 全部 / 1 未读 / 2 已读 */ readType?: number; /** 排序:1 时间倒序 / 2 时间正序 */ orderByTime?: string; } /** 家长端报名入参 */ export interface SignupRequest { serid: number; /** 参加人数(含学生本人) */ joinCount?: number | string; guardianName?: string; guardianPhone?: string; remark?: string; } // ============================ 字典/联系组 ============================ /** 系统字典下拉项 */ export interface DictOption { k: number | string; v: string | null; [key: string]: any; } /** 主办部门管理列表项 */ export interface DeptManageItem { SerID: number; CodeID: string; Name: string; Enable: number; } /** 联系组列表项 */ export interface ContactGroupItem { serid: number; GroupName: string; } /** 联系组分页结果 */ export interface ContactGroupPage { list: ContactGroupItem[]; total: number; } /** 联系组用户项(id=平台用户ID,不保存账号) */ export interface ContactUser { id: number; name: string; } /** 联系组用户分页结果 */ export interface ContactUserPage { list: ContactUser[]; total: number; } /** 组织树节点(基础平台返回) */ export interface SchoolTreeNode { [key: string]: any; } // ============================ 班级 ============================ /** 年级→班级树节点(叶子=班级,id 为数字班级 id,附学生数) */ export interface ClassTreeNode { id: number; name: string; isParent: boolean; studentCount?: number; children?: ClassTreeNode[]; [key: string]: any; } // ============================ 家长端 ============================ /** 家长/学生视角的报名态 */ export interface MySignupInfo { signupId: number; status: SignupStatus; statusDesc: string; joinCount: number; guardianName: string; guardianPhone: string; remark: string; signedAt: string | null; } /** 家长端活动项 */ export interface ParentActivityVo { id: number; title: string; category: string; venue: string; startTime: string | null; endTime: string | null; signupDeadline: string | null; receiptMode: ReceiptMode; receiptModeDesc: string; quota: number; allowAccompany: number; cost: number; content: string; publisherName: string; deptName: string; createTime: string | null; actStatus: ActivityStatus; actStatusDesc: string; /** 无需报名(仅通知) */ viewOnly: boolean; /** 是否还能报名 */ canSignup: boolean; my: MySignupInfo | null; } /** 家长端活动列表(含分桶计数) */ export interface MyActivitiesVo { buckets: { todo: number; signed: number; finished: number; all: number }; list: ParentActivityVo[]; } /** 家长端某活动详情(活动信息 + 我的报名) */ export interface MyActivityVo { activity: { id: number; title: string; category: string; venue: string; content: string; startTime: string | null; endTime: string | null; signupDeadline: string | null; receiptMode: ReceiptMode; receiptModeDesc: string; quota: number; allowAccompany: number; cost: number; publisherName: string; deptName: string; actStatus: ActivityStatus; actStatusDesc: string; }; my: MySignupInfo | null; }