# TBOSS OA 模块 — 全页面元素操作事件与跳转关系说明 > 基于 `2026-05-30-tboss-oa-design.md` 和 `2026-05-30-tboss-oa-database.md`,覆盖 27 个页面的所有可交互元素及其操作逻辑。 --- ## 页面跳转关系总图 ``` / (Appshell) ├─ /messages ────────────────────────────────────────────────────────────── │ └─ (点击消息卡片) → /announcement/detail/:id │ → /expense-apply/detail/:id │ → /expense/detail/:id │ → /overtime/detail/:id │ → /vehicle/detail/:id │ ├─ /home ────────────────────────────────────────────────────────────────── │ ├─ (轮播图) → 绑定的公告/活动链接 或 全屏预览 │ ├─ (金刚区-发起) → /expense-apply/apply /expense/apply │ │ → /vehicle/apply /overtime/apply │ ├─ (金刚区-记录) → /expense-apply/list /expense/list │ │ → /outing-log/list /announcement/list │ ├─ (看板-已提) → /expense-apply/list │ ├─ (看板-报销) → /report/expense-detail │ └─ (看板-待处理) → /messages │ └─ /profile ─────────────────────────────────────────────────────────────── ├─ 审批历史 → (子页面) → (点击单据) → /expense-apply/detail/:id │ → /expense/detail/:id │ → /overtime/detail/:id │ → /vehicle/detail/:id ├─ 我的报表 → (子页面) → /report/.. (5 Tab) └─ 关于 → (子页面) 表单页 (apply) ────(存为草稿/提交)──→ 列表页 (list) ──(点击卡片)──→ 详情页 (detail/:id) ↑ │ │ └───────(左滑编辑/draft编辑)─────────┘ (rejected→重新编辑)──┘ /admin/permissions (仅管理员) /announcement/create (仅管理员) ``` --- ## 页面 1:Appshell 底部导航外壳页 (`/`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 消息 Tab | 点击 | 路由 → `/messages`,图标变 `#00ABF3` | — | | 消息 Tab 角标 `TDBadge` | 数据绑定 | 未读消息数;进入时拉取,之后 30s 轮询或 Push 刷新 | `GET /api/messages/unread-count` | | 工作台 Tab | 点击 | 路由 → `/home`,图标变 `#00ABF3` | — | | 我的 Tab | 点击 | 路由 → `/profile`,图标变 `#00ABF3` | — | | 当前激活 Tab | 重复点击 | 若对应页面含列表 → ScrollToTop;否则无行为 | — | --- ## 页面 2:消息通知聚合页 (`/messages`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 导航栏标题 | — | "消息通知" | — | | 导航栏"全部已读" | 点击 | 仅未读消息>0 时显示;调用接口,所有红点淡出,按钮消失 | `POST /api/messages/read-all` | | 消息卡片(公告类) | 点击 | 路由 → `/announcement/detail/:id` | `BizType='announcement'` | | 消息卡片(审批待办) | 点击 | 按 `BizType` 路由 → 对应详情页,底部直接展示审批操作栏 | `BizType` 决定路由 | | 消息卡片(审批结果) | 点击 | 按 `BizType` 路由 → 对应详情页 | `BizType` 决定路由 | | 已读消息卡片 | — | 透明度 0.6,无红点,不可左滑 | `IsRead=1` | | 未读消息卡片-左滑 | 手势 | 滑出 `[标记已读]`(蓝色) + `[删除]`(红色) | — | | `[标记已读]` | 点击 | 异步标记;成功→红点淡出+透明度↓0.6;失败→Toast 红色"操作失败,请重试" | `PUT /api/messages/:id/read` | | `[删除]` | 点击 | `TDDialog`:"确认删除?删除后不可恢复。"→ 确定→卡片收起动画+软删除(IsDeleted=1) | `PUT /api/messages/:id/delete` | | 列表区域 | 下拉 | `RefreshIndicator`,重置 `page=1` | `GET /api/messages?page=1` | | 列表区域 | 上拉触底 | `page++`,底部菊花+"加载中...",静默追加 | `GET /api/messages?page=N` | | 空列表 | — | `TDEmpty` + 铃铛占位图:"暂无消息通知" | — | --- ## 页面 3:工作台 (`/home`) ### 员工版 | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 导航栏标题 | — | "TBOSS 工作台" | — | | `TDRotation` 轮播图 | 自动 | 每 3s 切换,循环 | `SysBanner` (IsActive=1, IsDeleted=0, ORDER BY SortOrder) | | 轮播图 | 点击 | 有 `LinkUrl`→跳转;无→全屏预览(双指缩放) | `SysBanner.LinkUrl` | | 金刚区-事前申请 | 点击 | 路由 → `/expense-apply/apply` | — | | 金刚区-费用报销 | 点击 | 路由 → `/expense/apply` | — | | 金刚区-用车申请 | 点击 | 路由 → `/vehicle/apply` | — | | 金刚区-加班申请 | 点击 | 路由 → `/overtime/apply` | — | | 金刚区-申请记录 | 点击 | 路由 → `/expense-apply/list`(默认"全部"Chip) | — | | 金刚区-报销记录 | 点击 | 路由 → `/expense/list`(默认"全部"Chip) | — | | 金刚区-外勤日志 | 点击 | 路由 → `/outing-log/list` | — | | 金刚区-公司公告 | 点击 | 路由 → `/announcement/list` | — | | 快捷看板-已提单据总数 | 点击 | 路由 → `/expense-apply/list`(默认"全部") | 后端预计算(缓存5min) | | 快捷看板-本月累计报销 | 点击 | 路由 → `/report/expense-detail` | 后端预计算(缓存5min) | | 快捷看板-待处理总数 | 点击 | 路由 → `/messages`(筛选 `approval_notice`) | 后端预计算(缓存5min) | | 页面整体 | 下拉 | 强制穿透缓存刷新轮播图+看板数据 | — | ### 经理版增量 | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 待审批卡片区 `TDBadge` | — | 红色数字展示待办件数 | `COUNT(ApprovalRecord WHERE ApproverId=当前用户 AND Action='pending' AND IsValid=1)` | | 待审批卡片区 | 点击 | 路由 → `/messages`(筛选 `approval_notice`) | — | ### 财务版增量 | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 财务看盘卡片 | — | 只读展示:已支付流水/待付款总额/异常退回数 | 全公司聚合查询 | --- ## 页面 3.1:我的个人中心页 (`/profile`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 头像 `TDAvatar` | 点击 | 唤起相册/相机 → 裁剪(1:1,≤2MB,JPG/PNG) → 上传 → 全局刷新 | `PUT /api/user/avatar` → `SysUser.AvatarUrl` | | 个人信息卡片 | — | 展示真实姓名、部门、岗位 | `SysUser.RealName`, `DeptName`, `Position` | | 我的审批历史 | 点击 | 路由 → 审批历史子页面 | — | | 我的报表 | 点击 | 路由 → 报表聚合子页面(5 Tab) | — | | 关于 TBOSS OA | 点击 | 路由 → 关于子页面 | — | | 关于-用户协议 | 点击 | `url_launcher` → 宿主 WebView | 远程 HTML | | 关于-隐私政策 | 点击 | `url_launcher` → 宿主 WebView | 远程 HTML | ### 子页面:我的审批历史 | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 导航栏标题 | — | "我的审批历史" | — | | 单据卡片-编号 | 点击 | 按单据类型跳转详情页 | `ApprovalRecord.BizId` + `BizType` | | 列表区域 | 下拉 | 刷新 `page=1` | `ApplicantId` 反查 4 张业务主表 JOIN `ApprovalRecord` | | 列表区域 | 上拉触底 | `page++` | 同上 | | 空列表 | — | `TDEmpty`:"暂无审批记录" | — | ### 子页面:我的报表聚合页 | 元素 | 事件 | 行为 | |------|------|------| | `TDTabBar`(5 Tab) | 切换 | 下方渲染对应页面 21~25 的个人报表视图 | --- ## 页面 4:事前申请表单页 (`/expense-apply/apply`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 申请人姓名 | — | 只读 | `SysUser.RealName` | | 所属部门 | — | 只读 | `SysUser.DeptId → SysDepartment.DeptName` | | 申请日期 | — | 只读,`DateTime.now()`,YYYY-MM-DD | — | | 紧急程度 `TDRadioGroup` | 选择 | 普通/紧急/特急,默认"普通" | `ExpenseApplication.Urgency` | | 费用类型 `TDPicker` | 选择 | 差旅费/招待费/日常采购/活动经费;联动过滤预算科目候选 | `ExpenseApplication.ExpenseType` | | 费用事由 `TDTextarea` | 输入 | 限制 200 字 | `ExpenseApplication.Purpose` | | 关联项目 `TDPicker` | 级联选择 | 一级:`SysProject.Name` → 二级:`SysBudgetSubject.Name`(通过 `SysProjectBudget` 过滤) | `ExpenseApplication.ProjectId` | | 预算科目 `TDPicker` | 选择 | 选完项目+科目后异步加载可用余额 | `ExpenseApplication.BudgetSubjectId` | | 预算余额展示 | — | 只读"¥XXXX.xx" | `SysProjectBudget.AvailableAmount`(ProjectId+SubjectId) | | 预估金额 `TDInput` | 输入 | 纯数字键盘;汇总所有明细行,超预算→金额变红+警告文本 | `ExpenseAppDetail.EstimatedAmount` | | [+ 添加费用明细] | 点击 | 展开新明细卡片,页面滚动聚焦 | — | | 明细卡片 ✕ | 点击 | 气泡"确认删除"→ 折叠消失 | — | | 附件上传 [+] | 点击 | 唤起相册/相机/文件;≤10MB(图)/≤20MB(PDF);超限 Toast | `ExpenseApplicationAttachment` | | 附件缩略图 | 点击 | 黑底全屏预览,双指缩放(0.5x~3x),左右滑动,右上角关闭 | — | | 附件缩略图 ⊖ | 点击 | 气泡"删除该附件?"→ 缩小消失+删除服务器文件 | — | | PDF 附件 | 点击 | 原生 PDF 查看器打开 | — | | [重置] | 点击 | 仅编辑草稿时可见;确认弹窗→清空至初始状态 | — | | [存为草稿] | 点击 | Loading → `PUT /expense-apply/draft` → Toast 绿色 → 跳转列表(激活"草稿"Chip);失败→Toast 红色 | `ExpenseApplication` (Status='draft') | | [提交审批] | 点击 | 校验→ScrollTo 报错字段(300ms)+边框红闪+`TDMessage`;通过→Loading→`POST /expense-apply/submit`→Toast→跳转列表 | `ExpenseApplication` (Status='pending') | | 返回按钮(有未保存修改) | 点击 | `TDDialog`:"是否退出?"→ 继续编辑/放弃并退出 | — | --- ## 页面 5:费用报销表单页 (`/expense/apply`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | [一键导入] 快捷链 | 点击 | 半屏抽屉:`approved` 且未被引用的申请列表;空→`TDEmpty`;选一条覆盖回填 | `Expense.SourceApplicationId` 排除已引用 | | 报销事由 | 输入 | 可由导入回填或手工填写 | `Expense.Purpose` | | 关联项目 | 选择 | 草稿可空 | `Expense.ProjectId` | | 预算科目 | 选择 | 草稿可空 | `Expense.BudgetSubjectId` | | 关联成本中心 `TDPicker` | 选择 | 可空,选项来自 `SysCostCenter` | `Expense.CostCenterId` | | 报销总金额 | — | 只读,明细累加上浮动画 | `Expense.TotalAmount` | | 开户行 `TDInput` | 输入+联想 | `/api/banks` 下拉联想,可自由输入 | `Expense.BankName` | | 开户人户名 | 输入 | 默认当前用户姓名,可修改 | `Expense.AccountName` | | 银行账号 `TDInput` | 输入 | 前端校验 16-19 位;提交时后端再校验;首次提交后回写默认账户 | `Expense.BankAccount` → `SysUser.DefaultBankAccount` | | 发生日期 | 点击 | `TDDatePicker`(年月日,无时分) | `ExpenseDetail.ExpenseDate` | | 费用类别 `TDPicker` | 选择 | 选项来自 `SysCostCategory`(叶子节点) | `ExpenseDetail.ExpenseType` | | 发票金额 `TDInput` | 输入 | 纯数字键盘 | `ExpenseDetail.TotalAmount` | | [+ 添加费用明细] | 点击 | 平滑展开新明细卡片 | — | | 明细行 ✕ | 点击 | 气泡确认→折叠消失 | — | | 发票上传 [+] | 点击 | 相册/相机,≤10MB;满 9 隐藏 | `ExpenseAttachment` | | 发票缩略图 | 点击 | 黑底全屏预览 | — | | [存为草稿] | 点击 | 复用页面 4 逻辑 | — | | [提交审批] | 点击 | 复用页面 4 逻辑 | — | | 返回按钮(有未保存修改) | 点击 | 复用页面 4 逻辑 | — | --- ## 页面 6:事前申请列表页 (`/expense-apply/list`) ## 页面 7:费用报销列表页 (`/expense/list`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 导航栏标题 | — | "申请记录" / "报销记录" | — | | `TDChip`(全部/草稿/审批中/已通过/已拒绝/已撤回) | 点击 | 高亮 `#00ABF3`,列表淡入淡出刷新;无数据→`TDEmpty`(文案随 Chip 变化) | `ExpenseApplication.Status` / `Expense.Status` | | 列表区域 | 下拉 | 刷新,`page=1` | — | | 列表区域 | 上拉触底 | `page++`,追加卡片 | — | | 卡片空白区 | 点击 | 路由 → 详情页 | `/expense-apply/detail/:id` 或 `/expense/detail/:id` | | 卡片左滑-`[编辑]` | 点击 | 仅 draft/rejected;路由 → 表单编辑态 | `/expense-apply/apply?id=xxx` 或 `/expense/apply?id=xxx` | | 卡片左滑-`[删除]` | 点击 | 仅 draft/rejected;`TDDialog`"确认删除?不可恢复。"→ 卡片收起+软删除 | — | | 卡片左滑(其他状态) | — | 无反应 | — | | `StatusTag` | — | 仅展示(灰-草稿/橙-审批中/绿-已通过/红-已拒绝/灰-已撤回) | — | ### 经理版增量 | 元素 | 事件 | 行为 | |------|------|------| | 访问范围标签 `[我的发起]` | 点击 | 与员工版逻辑相同 | | 访问范围标签 `[下属审批]` | 点击 | 列表清空+骨架屏→加载部门下属单据 | | 下属卡片左滑-`[一键同意]` | 点击 | 仅 `pending` 状态;绿色按钮,无需进入详情页即审批通过 | ### 财务版增量(仅页面 7) | 元素 | 事件 | 行为 | |------|------|------| | `[待付款]` Chip | 点击 | 筛选 `Status='approved' AND PaymentStatus='unpaid'` | | 卡片左滑-`[线下已付款]` | 点击 | 标记 `PaymentStatus='paid'` | --- ## 页面 8:事前申请详情页 (`/expense-apply/detail/:id`) ## 页面 9:费用报销详情页 (`/expense/detail/:id`) ### 员工版 | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 状态横幅 | — | 图标+状态中文+当前审批人姓名 | `Status` + `CurrentApproverId → SysUser.RealName` | | 提交时间 | — | 只读"YYYY-MM-DD HH:mm" | `CreateTime` | | 费用明细表"展开全部" | 点击 | >5行时显示;平滑展开 | `ExpenseAppDetail` / `ExpenseDetail` | | 附件缩略图 | 点击 | 黑底全屏预览,双指缩放,左右滑动 | `ExpenseApplicationAttachment` / `ExpenseAttachment` | | 时间线节点 | 点击 | 当前用户待审批→弹出审批操作;否则→展开详情(审批人/时间/意见) | `ApprovalRecord` (IsValid=1 ORDER BY ApprovalLevel) | | 审批人姓名/头像 | 点击 | `TDDialog` 展示基本信息卡片(姓名+部门+岗位) | `ApproverId → SysUser` | | [编辑](draft) | 点击 | 路由 → 表单编辑态 | — | | [提交审批](draft) | 点击 | 校验→提交;失败→`TDDialog`"去编辑"引导 | — | | [撤回申请](pending) | 点击 | `TDDialog`"确认撤回?"→ 确定→Status='withdrawn'→页面刷新 | — | | [重新编辑并发起](rejected) | 点击 | 路由 → 表单编辑态;提交后更新原记录+旧审批链 IsValid=0 | `ApprovalRecord.IsValid` | ### 经理版底部操作栏(仅 pending 状态且当前审批人=该经理时展示) | 元素 | 事件 | 行为 | 接口 | |------|------|------|------| | [拒绝] | 点击 | `TDDialog` 输入理由(≥5字解锁确定按钮)→ `POST` | `/api/{bizType}/approve` (action=reject) | | [转交] | 点击 | MethodChannel 唤起通讯录单选 → `POST` | `/api/{bizType}/approve` (action=transfer) | | [同意] | 点击 | Loading → `POST` → 节点变绿 → 流转 | `/api/{bizType}/approve` (action=approve) | ### 管理员版底部操作栏 | 元素 | 事件 | 行为 | |------|------|------| | [强制终止] | 点击 | `TDDialog` 确认 → Status='withdrawn' + 写入终止原因 | | [查看审批链] | 点击 | 展开完整 `ApprovalRecord` 历史(含 IsValid=0 的失效记录) | ### 财务版增量(仅页面 9) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 合规复选框 ×3 | 勾选 | 全部勾选→解锁 [确认打款] 按钮 | `Expense.IsInvoiceVerified/IsTaxIdMatched/IsCategoryCompliant` | | [退回修改] | 点击 | 选择退回节点(员工/经理)→状态倒流 | — | | [确认已线下打款并归档] | 点击 | 解锁后可用;滑出凭证表单(电汇流水号+记账凭证号必填)→提交→`Paid` | `Expense.BankTransferNo` + `VoucherNo` | | [下一笔待付款] | 点击 | 归档后替换显示;跳转下一条 `approved+unpaid`;无→"已无待付款单据" | — | --- ## 页面 10:加班申请表单页 (`/overtime/apply`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 加班类型 `TDPicker` | 选择 | 工作日/休息日/节假日,默认"工作日";节假日标注费率 | `Overtime.OtType` | | 补偿方式 `TDRadio` | 选择 | 转调休/结算加班费/混合,默认"转调休" | `Overtime.CompensationType` | | 混合模式 `TDSlider` | 拖动 | 10%~90%,步长 10%;右侧实时比例文案 | `Overtime.CompLeaveRatio` | | 开始时间 | 点击 | `TDDatePicker` 年月日时分 | `Overtime.StartTime` | | 结束时间 | 点击 | `TDDatePicker`;确认后自动计算净工时(扣除 12:00-13:00/18:00-18:30) | `Overtime.EndTime` → `NetOtHours` | | 净工时卡片 | — | 只读大字;≤0→变红+提交按钮置灰 | `Overtime.NetOtHours` | | 开始>结束校验 | — | 边框变红+提示+提交按钮置灰 | — | | 加班原因 `TDTextarea` | 输入 | 大文本 | `Overtime.Reason` | | [存为草稿]/[提交审批] | 点击 | 复用页面 4 逻辑 | — | | 返回按钮(有未保存修改) | 点击 | 复用页面 4 逻辑 | — | --- ## 页面 11:加班申请列表页 (`/overtime/list`) | 元素 | 事件 | 行为 | |------|------|------| | `TDChip`(全部/草稿/审批中/已通过/已拒绝/已撤回) | 点击 | 同列表页标准逻辑 | | 补偿方式展示 | — | `overtime_pay`→结算加班费 / `comp_leave`→转调休 / `mixed`→"X%调休+Y%结算" | | 其余交互 | — | 同页面 6/7 标准列表逻辑 | ## 页面 12:加班申请详情页 (`/overtime/detail/:id`) 同页面 8/9 详情节构,员工端仅 `[撤回]`。 --- ## 页面 13:用车申请表单页 (`/vehicle/apply`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 车牌号 `TDPicker` | 选择 | 全公司车池(空闲+使用中);冲突车辆标红"冲突";无可用→`TDEmpty` | `SysVehicle` (IsDeleted=0) | | 车牌号+出车/还车时间 | 失焦 | 异步排期冲突检测;冲突→红色文本+建议文字+锁死提交按钮 | `Vehicle` (Status IN pending,approved) | | 用车事由 | 输入 | 文本 | `Vehicle.Reason` | | 预计始发地 | 定位/输入 | 原生定位匹配 | `Vehicle.Origin` | | 预计目的地+地图图标 | 输入/点图标 | MethodChannel 唤醒地图选点→回填地址+经纬度 | `Vehicle.Destination` + `DestLongitude/Latitude` | | 预计出车时间 | 点击 | `TDDatePicker` 年月日时分 | `Vehicle.StartTime` | | 预计还车时间 | 点击 | `TDDatePicker` 年月日时分 | `Vehicle.EndTime` | | 还车>出车校验 | — | 否则红色提示+提交按钮置灰 | — | | 同行总人数 | 输入 | 纯数字,0→1 | `Vehicle.PassengerCount` | | 随行同行人 [+] | 点击 | MethodChannel 唤醒通讯录多选→胶囊标签展示;取消→无变化 | `VehiclePassenger` | | 胶囊标签 x | 点击 | 剔除该人员 | — | | [存为草稿]/[提交审批] | 点击 | 复用页面 4 逻辑 | — | --- ## 页面 14:用车申请列表页 (`/vehicle/list`) | 元素 | 事件 | 行为 | |------|------|------| | `TDChip`(全部/草稿/审批中/已通过/已拒绝/已撤回/已还车) | 点击 | 同列表页标准逻辑 | | 卡片左滑-`[编辑]`/`[删除]` | 点击 | 仅 draft/rejected | | 卡片左滑-`[确认还车]` | 点击 | 仅 approved;拉起半屏核销抽屉(复用页面 15) | | 卡片左滑(已还车) | — | 无操作 | --- ## 页面 15:用车申请详情页 (`/vehicle/detail/:id`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 微缩静态地图 | 点击 | MethodChannel 唤醒原生地图导航 | `OriginLongitude/Latitude`, `DestLongitude/Latitude` | | [确认还车并登记](approved) | 点击 | 滑出核销抽屉 | — | | 核销-实还时间 | 点击 | `TDDatePicker` 年月日时分 | `Vehicle.ActualReturnTime` | | 核销-出车前里程 | 输入 | 纯数字键盘 | `Vehicle.StartOdometer` | | 核销-还车后里程 | 输入 | 纯数字,前端校验≥出车前里程 | `Vehicle.EndOdometer` | | 核销-费用备注 | 输入 | 路桥费/停车费 | `Vehicle.ActualCost` + `CostRemark` | | 确认提交还车 | 点击 | `TDDialog` 确认→Status='returned'→页面刷新(底部显示归档时间+核销信息) | — | | 已还车底部栏 | — | 灰色只读"已还车归档于 YYYY-MM-DD HH:mm" | `UpdateTime` | --- ## 页面 16:业务员外出日志创建页 (`/outing-log/create`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | GPS 定位区 | 页面初始化 | 强制请求高精度 GPS → ReadOnly 展示地址;精度>100m→黄色警告 | MethodChannel → `OutingLog.CheckInLongitude/Latitude/Address` | | GPS 定位区(失败) | — | `TDEmpty`"无法获取当前位置";提交按钮置灰 | — | | 客户名称 `TDInput` | 输入 | 自动联想 `SysCustomer.CustomerName`;无匹配→自由文本(后端自动创建) | `OutingLog.CustomerName` (草稿: CustomerId=NULL) | | 今日工作总结 `TDTextarea` | 输入 | 大文本 | `OutingLog.VisitSummary` | | 后续推进计划 | 输入 | 大文本 | `OutingLog.NextPlan` | | 现场拍照区域 | 点击 | 跳过相册,直接唤醒相机;水印=服务器授时+GPS;满 4 隐藏 | `OutingLogAttachment` | | 相机权限被拒 | — | `TDDialog` + "前往设置"按钮 | — | | [存为草稿] | 点击 | 复用页面 4 逻辑;GPS、CustomerId 可为空 | — | | [提交] | 点击 | 校验 GPS+照片≥1;无→置灰+红色提示 | — | | 返回按钮(有未保存修改) | 点击 | 复用页面 4 逻辑 | — | --- ## 页面 17:外出日志列表页 (`/outing-log/list`) | 元素 | 事件 | 行为 | |------|------|------| | `TDChip`(全部/本月) | 点击 | 切换刷新 | | 卡片"新点评" `TDBadge` | — | 橙色标记,数据来源:`OutingLogComment.CreateTime > COALESCE(LastViewedTime, '1900-01-01')` 且评论者非员工本人 | | 卡片左滑-`[编辑]`/`[删除]` | 点击 | 仅 draft;`[删除]`需确认弹窗 | | 卡片左滑(completed) | — | 无操作 | | 其余交互 | — | 同标准列表逻辑 | ## 页面 18:外出日志详情页 (`/outing-log/detail/:id`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 微缩地图 | 点击 | 唤醒原生地图导航 | `CheckInLongitude/Latitude` | | 照片墙缩略图 | 点击 | 全屏预览 | `OutingLogAttachment` | | 主管点评区(员工端) | — | 只读浏览,不可回复 | `OutingLogComment` (ORDER BY CreateTime ASC) | | 页面进入 | — | 无感 `PUT /api/outing-log/:id/view`,更新 `LastViewedTime`,列表"新点评"红点消失 | `OutingLog.LastViewedTime = NOW()` | ### 经理版增量 | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | `TDRate` 星级 | 点选 | 1-5 星 | `OutingLogComment.RatingStars` | | 点评文本框 | 输入 | 批示文字 | `OutingLogComment.CommentText` | | 发送按钮 | 点击 | 气泡追加+动画,写入 `OutingLogComment`,同步更新 `OutingLog.UpdateTime` | — | --- ## 页面 19:公司公告列表页 (`/announcement/list`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 导航栏标题 | — | "公司公告" | — | | `TDChip` 类型筛选 | 点击 | 全部/通知公告/人事与制度/放假与活动/我的草稿(仅管理员) | `Announcement.Type` + `Status` | | 公告卡片 | 点击 | 路由 → `/announcement/detail/:id` | — | | 列表排序 | — | 置顶→未过期(PublishTime DESC)→已过期(PublishTime DESC) | `IsTop`, `PublishTime`, `ExpiryDate` | | 已过期卡片 | — | 整体置灰+标题末尾"已过期" | `ExpiryDate < NOW` | | 未读红点 | — | 红点淡出(返回列表后) | `AnnouncementReadLog.IsRead=0` | | 列表区域 | 下拉/上拉 | 刷新/加载更多 | — | | 搜索 | — | 不支持 | — | --- ## 页面 20:公司公告详情页 (`/announcement/detail/:id`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | 公告正文 | — | HTML/Markdown 渲染 | `Announcement.Content` | | 已过期横幅 | — | 红色"该公告已于 YYYY-MM-DD HH:mm 过期" | `Announcement.ExpiryDate` | | 附件图标 | 点击 | 原生浏览器/下载管理器打开;失败→Toast | `AnnouncementAttachment` | | 附件列表为空 | — | 整个"附件下载"区块隐藏 | — | | 页面停留 ≥2s | — | 无感发送已读请求;<2s 返回不发 | `POST /api/announcements/:id/read` → `IsRead=1` | ### 管理员版增量 | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | [已读 N 人] Chip | 点击 | 展开已读员工列表(头像+部门) | `AnnouncementReadLog` (IsRead=1) | | [未读 N 人] Chip | 点击 | 展开未读员工列表(头像+部门) | `AnnouncementReadLog` (IsRead=0) | | [一键 DING] | 点击 | 震动反馈→封装 UserIds→MethodChannel 强推 Push/短信 | `AnnouncementReadLog.IsUrged=1`, `LastUrgeTime` | --- ## 页面 21~25:个人五大明细报表页 (`/report/..`) | 元素 | 事件 | 行为 | |------|------|------| | `TDDropdownMenu`(本月/本季/本年) | 选择 | 数值卡片+图表 300ms 渐变刷新;不支持自定义日期 | | 数值卡片 | — | 只读;空→0/¥0.00 | | `fl_chart` 数据点 | 长按 | tooltip(日期+数值) | | `fl_chart` 图表 | 水平滑动 | 查看历史数据 | | 员工版数据导出 | — | 不支持 | | 图表为空 | — | `TDEmpty`:"所选时间范围内暂无数据" | ### 经理版增量 | 元素 | 事件 | 行为 | |------|------|------| | 柱状图柱体 | 点击 | 下方列表联动过滤→该员工本月单据流水 | | 流水条目 | 点击 | 穿透跳转对应单据详情页 | ### 财务版增量(仅页面 22) | 元素 | 事件 | 行为 | |------|------|------| | 部门树/项目组筛选器 | 级联选择 | 多维组合筛选 | | [数据流水一键导出] | 点击 | Loading→后端生成 Excel→MethodChannel 唤起原生分享面板 | --- ## 页面 26:系统公告发布表单页 (`/announcement/create`) | 元素 | 事件 | 行为 | 数据来源 | |------|------|------|-------------| | 公告标题 `TDInput` | 输入 | 文本 | `Announcement.Title` | | 公告分类下拉 | 选择 | notice/policy/activity | `Announcement.Type` | | 富文本编辑域 | 操作 | 加粗/斜体/下划线/有序列表/无序列表/插入图片/插入链接/字号(H1-H3+正文) | `Announcement.Content` | | 附件上传 [+] | 点击 | ≤5 个,PDF/图片/Word/Excel,≤20MB | `AnnouncementAttachment` | | 置顶 `TDSwitch` | 切换 | 默认关闭 | `Announcement.IsTop` | | 有效期 `TDDatePicker` | 选择 | 非必填,不填永不过期 | `Announcement.ExpiryDate` | | 接收范围选择器 | 点击 | 右侧滑出部门树多选(Checkbox);底部统计"已选 N 部门,覆盖 M 员工";默认全员 | `AnnouncementTarget` | | [预览](导航栏右侧) | 点击 | `TDDialog` 全屏模拟详情页 | — | | [存为草稿] | 点击 | 保存→跳转公告列表(草稿仅创建者+管理员可见) | `Announcement.Status='draft'` | | [发布] | 点击 | 确认弹窗"确认向 M 名员工发布?"→写入+异步 Job 初始化 `AnnouncementReadLog`→Toast | `Announcement.Status='published'` | | 返回按钮(有未保存修改) | 点击 | 复用页面 4 逻辑 | — | --- ## 页面 27:全局用户权限配置页 (`/admin/permissions`) | 元素 | 事件 | 行为 | 数据来源/接口 | |------|------|------|-------------| | `TDSearchBar` | 输入 | 300ms 防抖模糊搜索→骨架屏→结果刷新;无结果→`TDEmpty` | `SysUser.UserName` + `RealName` | | 员工列表 | 下拉/上拉 | 刷新/每页 20 条加载更多 | 默认按部门+姓名排序 | | 员工卡片 | 点击 | 右侧滑出 `TDDrawer` 权限编辑抽屉 | — | | 角色复选框 ×4 `TDCheckboxGroup` | 勾选 | 普通员工/审批人(经理)/财务人员/系统管理员 | `SysUserRole` | | 启用/禁用 `TDSwitch` | 切换 | 映射 `IsActive`;经理有待审批时警告确认;取消→回弹 | `SysUser.IsActive` | | [确认保存权限修改] | 点击 | Loading→`PUT /api/admin/assign-role`→Toast+写入审计日志;失败→Toast 红色 | `SysRoleChangeLog` | | 【变更记录】折叠区 | 展开 | `TDTimeline` 展示最近 20 条变更记录 | `SysRoleChangeLog` (CREATE TIME DESC LIMIT 20) | | 抽屉关闭(有未保存修改) | — | 确认弹窗"是否放弃?" | — | | 自保护 | — | 管理员无法取消自己的 admin 角色→Toast | — | | 最后管理员保护 | — | 移除最后 admin 时后端拒绝 | — | --- ## 全局交互规范速查 | 场景 | 行为 | |------|------| | 所有列表页下拉 | 刷新 `page=1` | | 所有列表页上拉触底 | `page++` 追加 | | 所有表单页返回(有未保存修改) | `TDDialog` 确认 | | 所有表单提交/存草稿 | Loading 态 + 成功/失败 Toast | | 所有附件缩略图点击 | 黑底全屏预览,双指缩放,左右滑动 | | 所有 PDF 附件点击 | 原生 PDF 查看器 | | 并发编辑冲突 | 错误码 `CONCURRENCY_CONFLICT`→`TDDialog`→返回列表刷新 | | 并发审批冲突 | 错误码 `APPROVAL_CONFLICT`→详情页自动刷新+Toast | | 401 未授权 | 静默触发宿主登录流程 | | 横竖屏 | 仅支持竖屏 | | Deep Link | `tboss://oa/{path}` → GoRouter 路由 |