You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

533 lines
36 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 考勤打卡
> 模块编码attendance
> 端侧Web + 小程序(双端)
> 关联文档01-模块划分 §3.5 / 02-功能清单-物业公司 §5 / 03-业务流转逻辑-物业公司 §5 / 05-接口规范 §9.2 / 06-项目技术要求 §4.4
> 强制规范遵循 `07-前端界面开发规范.md`
## 功能概览
| 项目 | 说明 |
|------|------|
| 菜单名称 | 考勤打卡 |
| 子菜单 | 打卡点管理、打卡规则、考勤记录、异常审核、数据补录 |
| 功能编号 | PR-A-01 ~ PR-A-05 |
| 权限编码前缀 | attendance:point:* / attendance:rule:* / attendance:record:* / attendance:appeal:* / attendance:supplement:* |
---
## 页面1打卡点管理页
**页面编号**PR-A-01-P01
**端侧归属**Web专属
**页面路径**/attendance/points
### 界面布局
```
┌──────────────────────────────────────────────────────────────────┐
│ [面包屑] 考勤打卡 > 打卡点管理 │
├──────────────────────────────────────────────────────────────────┤
│ [查询条件区] │
│ 打卡点名称[____] 所属班组[▼] 状态[▼] [查询] [重置] │
├──────────────────────────────────────────────────────────────────┤
│ [操作栏] [新增打卡点] │
├──────────────────────────────────────────────────────────────────┤
│ [列表区] │
│ 序号| 打卡点名称 | 所属班组 | 蓝牙Beacon | Beacon状态 | 操作 │
│ 1 | 1号楼大厅 | 水电班 | B-001 | 在线 | 编辑 删除 │
│ 2 | 2号楼入口 | 巡检班 | B-002 | 离线 | 编辑 删除 │
├──────────────────────────────────────────────────────────────────┤
│ [分页] 共8条 │
└──────────────────────────────────────────────────────────────────┘
```
### 表单字段(新增/编辑弹窗)
| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 |
|--------|----------|------|--------|----------|----------|
| 打卡点名称 | 文本输入 | 是 | — | 自填 | 最大30字 |
| 所属班组 | 下拉单选 | 是 | — | 班组列表 | — |
| 位置描述 | 文本输入 | 是 | — | 自填 | 最大100字 |
| 蓝牙Beacon | 下拉单选 | 是 | — | 蓝牙设备管理 | — |
| 适用角色 | 下拉多选 | 是 | 全部 | 固定选项 | 全部/主管/员工 |
### 操作按钮
| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 |
|------|----------|------|----------|------|
| 新增打卡点 | attendance:point:create | 操作栏 | 始终 | — |
| 编辑 | attendance:point:update | 行操作 | 始终 | — |
| 删除 | attendance:point:delete | 行操作 | 无人员关联 | 二次确认 |
### API端点
| 页面操作 | API路径 | 方法 | 说明 |
|----------|---------|------|------|
| 列表查询 | /api/v1/attendance-points | GET | — |
| 新增 | /api/v1/attendance-points | POST | — |
| 编辑 | /api/v1/attendance-points/{id} | PUT | — |
### 交互流程要求
1. **页面加载流程**:进入页面 → 请求打卡点列表API → 渲染表格数据 → 默认无选中状态
2. **查询/筛选交互流程**:填写筛选条件(打卡点名称/所属班组/状态)→ 点击"查询" → 调用列表API并刷新表格 → 点击"重置"清空条件并重新加载
3. **表单填写与提交流程**:点击"新增打卡点" → 弹出新增弹窗 → 填写表单字段 → 点击确定 → 前端校验通过 → 调用新增API → 成功后关闭弹窗并刷新列表
4. **弹窗/抽屉交互流程**:新增/编辑弹窗居中展示宽度480px点击遮罩层或右上角关闭按钮可关闭未保存变更时提示确认
5. **行内操作流程**:点击"编辑" → 弹出编辑弹窗(预填数据)→ 修改后提交 → 刷新当前行;点击"删除" → 弹出二次确认弹窗"确定删除该打卡点?" → 确认后调用删除API → 刷新列表
6. **异常与错误处理**API请求失败显示ElMessage.error提示删除有关联人员的打卡点时提示"该打卡点下存在关联人员,无法删除"
7. **联动/级联交互**选择所属班组后蓝牙Beacon下拉选项可按班组过滤Beacon状态根据设备管理模块实时数据展示在线/离线
8. **权限控制交互表现**:无`attendance:point:create`权限时隐藏"新增打卡点"按钮;无`attendance:point:update`权限时隐藏行内"编辑"按钮;无`attendance:point:delete`权限时隐藏行内"删除"按钮
9. **H1 防重复请求(强制)**"查询""新增打卡点"按钮点击后立即disabled并显示loading态行内"编辑""删除"操作时整行添加半透明遮罩禁用重复点击;翻页/切换筛选条件时自动abort前一个未完成请求再发新请求列表查询与下拉选项加载等并行请求互不阻塞
10. **H2 超时配置(强制)**列表查询GET请求设置15s超时新增/编辑POST请求设置30s超时任何请求耗时>3s时在页面顶部展示全局ElLoading("数据加载中...")直到响应返回
11. **H3 操作确认(强制)**"删除打卡点"操作弹出ElMessageBox.confirm二次确认type="error",提示文案"确定删除该打卡点?删除后将不可恢复"
12. **H6 批量限制(建议)**当前页面暂无批量操作若后续扩展批量删除功能单次批量删除上限50条记录超出时提示"单次最多选择50条记录进行操作"
13. **H8 反馈规范(建议)**:新增/编辑成功后ElMessage.success显示2秒后自动消失同时silent方式刷新列表不显示loading遮罩失败提示ElMessage.error需用户手动关闭网络异常时显示"网络连接异常,请检查网络后重试"并提供重试按钮
### 组件规范
| 元素 | 组件 | 配置参数 |
|------|------|----------|
| 打卡点名称输入框 | ElInput | maxlength=30, showWordLimit=true, placeholder="请输入打卡点名称" |
| 所属班组下拉 | ElSelect | filterable=true, clearable=true, placeholder="请选择所属班组" |
| 位置描述输入框 | ElInput | maxlength=100, showWordLimit=true, type="textarea", :rows=2 |
| 蓝牙Beacon下拉 | ElSelect | filterable=true, clearable=true, placeholder="请选择蓝牙Beacon" |
| 适用角色多选 | ElSelect | multiple=true, collapseTags=true, placeholder="请选择适用角色" |
| 状态下拉 | ElSelect | clearable=true, :options=[{label:"在线",value:"online"},{label:"离线",value:"offline"}] |
| 查询按钮 | ElButton | type="primary", icon="Search" |
| 重置按钮 | ElButton | icon="Refresh" |
| 新增打卡点按钮 | ElButton | type="primary", icon="Plus" |
| 列表表格 | ElTable | stripe=true, border=true, :data=tableData |
| 分页 | ElPagination | layout="total, sizes, prev, pager, next", :page-sizes=[10,20,50] |
| 新增/编辑弹窗 | ElDialog | width="480px", :close-on-click-modal=false, :destroy-on-close=true |
| 删除确认弹窗 | ElMessageBox | type="warning", confirmButtonText="确定", cancelButtonText="取消" |
### 校验规则
| 字段 | 规则 | 错误提示 |
|------|------|----------|
| 打卡点名称 | required, maxLength=30 | 请输入打卡点名称打卡点名称不能超过30个字符 |
| 所属班组 | required | 请选择所属班组 |
| 位置描述 | required, maxLength=100 | 请输入位置描述位置描述不能超过100个字符 |
| 蓝牙Beacon | required | 请选择蓝牙Beacon设备 |
| 适用角色 | required | 请选择适用角色 |
### 响应式布局
| 断点 | 布局调整 |
|------|----------|
| ≥1280px桌面端 | 查询条件区水平排列表格完整展示所有列弹窗宽度480px |
| 1024-1279pxPad横屏 | 查询条件区换行排列(名称独占一行,班组+状态一行表格隐藏位置描述列弹窗宽度420px |
| 768-1023pxPad竖屏 | 查询条件区垂直堆叠表格仅显示打卡点名称、所属班组、操作列弹窗宽度90vw |
---
## 页面2打卡规则页
**页面编号**PR-A-02-P01
**端侧归属**Web专属
**页面路径**/attendance/rules
### 界面布局
```
┌──────────────────────────────────────────────────────────────────┐
│ [面包屑] 考勤打卡 > 打卡规则 │
├──────────────────────────────────────────────────────────────────┤
│ [按班组显示规则卡片] │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 水电维修班 │ │
│ │ 上班时间08:00 上班打卡窗口07:30~08:30 │ │
│ │ 下班时间17:00 下班打卡窗口16:30~17:30 │ │
│ │ 迟到规则:>08:00 迟到 >08:30 严重迟到 │ │
│ │ 早退规则:<17:00 早退 <16:30 严重早退 │ │
│ │ [编辑] │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ 巡检一班 │ │
│ │ ... [编辑] │ │
│ └──────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
### 表单字段(编辑弹窗)
| 字段名 | 控件类型 | 必填 | 默认值 | 数据来源 | 校验规则 |
|--------|----------|------|--------|----------|----------|
| 上班时间 | 时间选择 | 是 | 08:00 | 自填 | — |
| 上班打卡窗口(起) | 时间选择 | 是 | 上班前30分 | 自填 | — |
| 上班打卡窗口(止) | 时间选择 | 是 | 上班后30分 | 自填 | — |
| 下班时间 | 时间选择 | 是 | 17:00 | 自填 | — |
| 下班打卡窗口(起) | 时间选择 | 是 | 下班前30分 | 自填 | — |
| 下班打卡窗口(止) | 时间选择 | 是 | 下班后30分 | 自填 | — |
| 迟到阈值(分钟) | 数字输入 | 是 | 0 | 自填 | ≥0 |
| 严重迟到阈值(分钟) | 数字输入 | 是 | 30 | 自填 | >迟到阈值 |
| 早退阈值(分钟) | 数字输入 | 是 | 0 | 自填 | ≥0 |
| 严重早退阈值(分钟) | 数字输入 | 是 | 30 | 自填 | >早退阈值 |
### 操作按钮
| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 |
|------|----------|------|----------|------|
| 编辑 | attendance:rule:update | 卡片操作 | 始终 | — |
### API端点
| 页面操作 | API路径 | 方法 | 说明 |
|----------|---------|------|------|
| 规则查询 | /api/v1/attendance-rules | GET | 按班组查询 |
| 保存 | /api/v1/attendance-rules | POST | — |
### 交互流程要求
1. **页面加载流程**:进入页面 → 请求规则列表API按班组分组→ 渲染规则卡片列表 → 默认展示全部班组卡片
2. **查询/筛选交互流程**:本页无独立筛选条件,数据按班组以卡片形式展示,所有班组规则一次加载
3. **表单填写与提交流程**:点击卡片"编辑"按钮 → 弹出编辑弹窗(预填当前规则数据)→ 修改时间与阈值 → 点击确定 → 前端校验通过 → 调用保存API → 成功后关闭弹窗并刷新对应卡片数据
4. **弹窗/抽屉交互流程**编辑弹窗居中展示宽度520px弹窗内时间选择器联动显示打卡窗口点击遮罩层或关闭按钮可退出未保存时提示确认
5. **行内操作流程**:无行内操作,仅在卡片上提供"编辑"按钮
6. **异常与错误处理**:严重迟到阈值≤迟到阈值时提示"严重迟到阈值必须大于迟到阈值";严重早退阈值≤早退阈值时提示"严重早退阈值必须大于早退阈值";打卡窗口起止时间逻辑冲突时提示错误
7. **联动/级联交互**修改上班时间时自动调整上班打卡窗口默认值上班前30分~上班后30分修改下班时间同理自动调整下班打卡窗口
8. **权限控制交互表现**:无`attendance:rule:update`权限时隐藏卡片"编辑"按钮,卡片仅展示只读信息
9. **H1 防重复请求(强制)**:卡片"编辑"按钮点击后立即disabled并显示loading态编辑弹窗提交按钮点击后disabled防重复提交
10. **H2 超时配置(强制)**规则查询GET请求设置15s超时保存POST请求设置30s超时请求耗时>3s时展示全局ElLoading
11. **H4 脏数据检测(强制)**打开编辑弹窗时对当前规则数据进行deepClone快照弹窗内监听表单变更计算isDirty状态点击弹窗关闭按钮或遮罩层且isDirty为true时弹出ElMessageBox.confirm提示"修改尚未保存,确定要关闭吗?"路由离开前通过beforeRouteLeave守卫拦截未保存的变更
12. **H8 反馈规范(建议)**保存成功后ElMessage.success("规则保存成功")显示2秒后自动消失并silent刷新对应卡片数据失败提示需手动关闭网络异常提供重试
### 组件规范
| 元素 | 组件 | 配置参数 |
|------|------|----------|
| 上班时间选择 | ElTimePicker | format="HH:mm", placeholder="请选择上班时间" |
| 上班打卡窗口(起) | ElTimePicker | format="HH:mm", placeholder="上班打卡开始时间" |
| 上班打卡窗口(止) | ElTimePicker | format="HH:mm", placeholder="上班打卡结束时间" |
| 下班时间选择 | ElTimePicker | format="HH:mm", placeholder="请选择下班时间" |
| 下班打卡窗口(起) | ElTimePicker | format="HH:mm", placeholder="下班打卡开始时间" |
| 下班打卡窗口(止) | ElTimePicker | format="HH:mm", placeholder="下班打卡结束时间" |
| 迟到阈值 | ElInputNumber | :min=0, :max=180, :step=5, controls-position="right" |
| 严重迟到阈值 | ElInputNumber | :min=1, :max=180, :step=5, controls-position="right" |
| 早退阈值 | ElInputNumber | :min=0, :max=180, :step=5, controls-position="right" |
| 严重早退阈值 | ElInputNumber | :min=1, :max=180, :step=5, controls-position="right" |
| 规则卡片 | ElCard | shadow="hover", :body-style="{ padding: '20px' }" |
| 编辑按钮 | ElButton | type="primary", link=true, icon="Edit" |
| 编辑弹窗 | ElDialog | width="520px", :close-on-click-modal=false, :destroy-on-close=true |
### 校验规则
| 字段 | 规则 | 错误提示 |
|------|------|----------|
| 上班时间 | required | 请选择上班时间 |
| 上班打卡窗口(起) | required, 必须早于上班时间 | 请选择上班打卡开始时间;上班打卡开始时间必须早于上班时间 |
| 上班打卡窗口(止) | required, 必须晚于上班时间 | 请选择上班打卡结束时间;上班打卡结束时间必须晚于上班时间 |
| 下班时间 | required | 请选择下班时间 |
| 下班打卡窗口(起) | required, 必须早于下班时间 | 请选择下班打卡开始时间;下班打卡开始时间必须早于下班时间 |
| 下班打卡窗口(止) | required, 必须晚于下班时间 | 请选择下班打卡结束时间;下班打卡结束时间必须晚于下班时间 |
| 迟到阈值(分钟) | required, ≥0 | 请输入迟到阈值;迟到阈值不能为负数 |
| 严重迟到阈值(分钟) | required, >迟到阈值 | 请输入严重迟到阈值;严重迟到阈值必须大于迟到阈值 |
| 早退阈值(分钟) | required, ≥0 | 请输入早退阈值;早退阈值不能为负数 |
| 严重早退阈值(分钟) | required, >早退阈值 | 请输入严重早退阈值;严重早退阈值必须大于早退阈值 |
### 响应式布局
| 断点 | 布局调整 |
|------|----------|
| ≥1280px桌面端 | 规则卡片双列排列卡片内信息水平展示弹窗宽度520px |
| 1024-1279pxPad横屏 | 规则卡片单列排列卡片内信息水平展示弹窗宽度480px |
| 768-1023pxPad竖屏 | 规则卡片单列排列卡片内信息垂直堆叠标签与值分行显示弹窗宽度90vw |
---
## 页面3考勤记录页
**页面编号**PR-A-03-P01
**端侧归属**Web专属
**页面路径**/attendance/records
### 查询条件
| 字段名 | 控件类型 | 必填 | 默认值 | 说明 |
|--------|----------|------|--------|------|
| 日期 | 日期选择 | 否 | 今天 | — |
| 班组 | 下拉单选 | 否 | 全部 | — |
| 人员 | 文本输入 | 否 | — | 模糊匹配 |
| 打卡状态 | 下拉单选 | 否 | 全部 | 正常/迟到/早退/缺卡/补录 |
### 列表字段
| 序号 | 字段名 | 列宽 | 支持排序 | 说明 |
|------|--------|------|----------|------|
| 1 | 姓名 | 80px | 否 | — |
| 2 | 班组 | 100px | 否 | — |
| 3 | 上班打卡时间 | 120px | 是 | — |
| 4 | 上班打卡方式 | 90px | 否 | 蓝牙/手动/补录 |
| 5 | 上班状态 | 80px | 否 | 正常/迟到/严重迟到 |
| 6 | 下班打卡时间 | 120px | 是 | — |
| 7 | 下班打卡方式 | 90px | 否 | — |
| 8 | 下班状态 | 80px | 否 | 正常/早退/严重早退 |
| 9 | 补录标记 | 70px | 否 | 补录显示"补录"标签 |
| 10 | 操作 | 80px | — | 查看详情 |
### 操作按钮
| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 |
|------|----------|------|----------|------|
| 查看详情 | attendance:record:view | 行操作 | 始终 | — |
### API端点
| 页面操作 | API路径 | 方法 | 说明 |
|----------|---------|------|------|
| 记录查询 | /api/v1/attendance-records | GET | 分页查询 |
### 交互流程要求
1. **页面加载流程**:进入页面 → 默认日期为今天 → 请求考勤记录API → 渲染表格数据
2. **查询/筛选交互流程**:选择日期/班组/人员/打卡状态 → 点击"查询" → 调用API刷新表格 → 点击"重置"恢复默认条件(今天/全部/全部/全部)并重新加载
3. **表单填写与提交流程**:本页无表单提交操作
4. **弹窗/抽屉交互流程**:点击"查看详情" → 弹出详情弹窗展示完整打卡信息打卡时间、方式、状态、打卡点、蓝牙设备信息等宽度500px
5. **行内操作流程**:点击"查看详情" → 调用详情API → 弹窗展示完整考勤记录详情
6. **异常与错误处理**API请求失败显示ElMessage.error提示列表数据为空时展示ElEmpty空状态补录标记列显示ElTag标签"补录"
7. **联动/级联交互**:选择班组后人员筛选可按班组过滤;上班/下班状态字段根据状态值显示不同颜色Tag正常-绿/迟到-橙/严重迟到-红/早退-橙/严重早退-红)
8. **权限控制交互表现**:无`attendance:record:view`权限时隐藏"查看详情"按钮;主管仅看到本班组数据,员工仅看本人数据(后端数据权限控制)
9. **H1 防重复请求(强制-轻量)**"查询"按钮点击后disabled+loading态行内"查看详情"按钮点击后整行半透明遮罩防重复分页切换时abort前一次未完成请求本页以查看为主采用轻量级防重复策略
10. **H2 超时配置(强制)**记录查询GET请求设置15s超时请求耗时>3s时在表格区域展示ElLoading局部加载动画
11. **H8 反馈规范(建议)**详情弹窗加载完成后正常展示无需额外成功反馈API请求失败时ElMessage.error提示需手动关闭网络异常时显示重试按钮
### 组件规范
| 元素 | 组件 | 配置参数 |
|------|------|----------|
| 日期选择 | ElDatePicker | type="date", value-format="YYYY-MM-DD", placeholder="选择日期" |
| 班组下拉 | ElSelect | filterable=true, clearable=true, placeholder="请选择班组" |
| 人员输入框 | ElInput | placeholder="请输入人员姓名", clearable=true |
| 打卡状态下拉 | ElSelect | clearable=true, :options=[正常,迟到,早退,缺卡,补录] |
| 查询按钮 | ElButton | type="primary", icon="Search" |
| 重置按钮 | ElButton | icon="Refresh" |
| 列表表格 | ElTable | stripe=true, border=true, :data=tableData, :default-sort={prop:"上班打卡时间",order:"ascending"} |
| 上班状态列 | ElTag | :type=状态映射(正常→success/迟到→warning/严重迟到→danger) |
| 下班状态列 | ElTag | :type=状态映射(正常→success/早退→warning/严重早退→danger) |
| 补录标记列 | ElTag | type="info", v-if="is_supplement" |
| 分页 | ElPagination | layout="total, sizes, prev, pager, next", :page-sizes=[10,20,50] |
| 详情弹窗 | ElDialog | width="500px", :close-on-click-modal=true, :destroy-on-close=true |
### 校验规则
| 字段 | 规则 | 错误提示 |
|------|------|----------|
| 日期 | 非必填,格式校验 | 日期格式不正确 |
| 人员 | 最大20字 | 人员姓名不能超过20个字符 |
| 打卡状态 | 枚举值校验 | 请选择有效的打卡状态 |
### 响应式布局
| 断点 | 布局调整 |
|------|----------|
| ≥1280px桌面端 | 查询条件区水平排列表格完整展示所有10列分页右对齐 |
| 1024-1279pxPad横屏 | 查询条件区换行排列表格隐藏上班打卡方式、下班打卡方式列保留8列 |
| 768-1023pxPad竖屏 | 查询条件区垂直堆叠,表格仅显示姓名、班组、上班状态、下班状态、操作列,分页居中 |
---
## 页面4异常审核页
**页面编号**PR-A-04-P01
**端侧归属**Web专属
**页面路径**/attendance/appeals
### 查询条件
| 字段名 | 控件类型 | 必填 | 默认值 | 说明 |
|--------|----------|------|--------|------|
| 审核状态 | 下拉单选 | 否 | 全部 | 待审核/已通过/已驳回 |
| 申诉人 | 文本输入 | 否 | — | 模糊匹配 |
| 日期范围 | 日期范围 | 否 | — | — |
### 列表字段
| 序号 | 字段名 | 列宽 | 支持排序 | 说明 |
|------|--------|------|----------|------|
| 1 | 申诉人 | 80px | 否 | — |
| 2 | 班组 | 100px | 否 | — |
| 3 | 申诉日期 | 100px | 是 | — |
| 4 | 异常类型 | 100px | 否 | 蓝牙故障/手机异常/系统异常/忘记打卡/其他 |
| 5 | 申诉说明 | 200px | 否 | — |
| 6 | 审核状态 | 90px | 是 | 待审核(黄)/已通过(绿)/已驳回(红) |
| 7 | 操作 | 100px | — | 审核/查看 |
### 操作按钮
| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 |
|------|----------|------|----------|------|
| 审核 | attendance:appeal:approve | 行操作 | 审核状态=待审核 | 通过/驳回弹窗 |
### 通知触发
| 触发操作 | 通知对象 | 通知方式 | 消息模板 | 文档来源 |
|----------|----------|----------|----------|----------|
| 审核通过 | 申诉人 | 小程序推送 | 申诉通过,系统自动补录打卡 | 03-物业公司 §5 / 03-小程序端 §5.1 |
| 审核驳回 | 申诉人 | 小程序推送 | 申诉未通过 | 03-物业公司 §5 |
### 蓝牙双模式差异
| 元素 | 策略=REQUIRED | 策略=OPTIONAL |
|------|---------------|---------------|
| 打卡方式 | 仅蓝牙打卡 | 蓝牙/手动双按钮 |
| 蓝牙失败 | 提交异常申诉 | 可直接手动打卡(check_method=MANUAL) |
| 异常申诉 | 必须审核 | 无需申诉(手动打卡) |
| 打卡记录标记 | check_method=BLUETOOTH | check_method=MANUAL |
### API端点
| 页面操作 | API路径 | 方法 | 说明 |
|----------|---------|------|------|
| 申诉列表 | /api/v1/attendance-appeals | GET | — |
| 审核 | /api/v1/attendance-appeals/{id}/approve | POST | 通过后自动补录打卡 |
### 交互流程要求
1. **页面加载流程**:进入页面 → 调用申诉列表API GET /api/v1/attendance-appeals → 渲染异常审核表格默认按申诉日期倒序排列每页20条同时加载审核状态下拉选项
2. **查询/筛选交互流程**:选择审核状态/输入申诉人/选择日期范围 → 点击[查询] → 携带筛选参数重新请求第1页 → 点击[重置]清空条件并重新加载
3. **表单填写与提交流程**:本页无新增表单,申诉数据由小程序端提交
4. **弹窗/抽屉交互流程**:点击[审核](审核状态=待审核时显示)→ 弹出审核弹窗,选择"通过"或"驳回",驳回时必填驳回原因 → 确认后调用审核API → 审核通过后系统自动补录打卡记录 → 成功后关闭弹窗并刷新列表
5. **行内操作流程**:点击[审核] → 弹窗选择通过/驳回 → 提交 → 刷新该行审核状态;点击[查看](如有)→ 弹窗展示申诉详情
6. **异常与错误处理**:审核已审核过的记录提示"该申诉已审核";审核通过后自动补录打卡失败时提示"自动补录失败,请手动处理"API请求失败显示ElMessage.error列表无数据时显示ElEmpty
7. **联动/级联交互**:审核状态筛选影响列表展示;蓝牙双模式下,策略=REQUIRED时异常申诉必须审核策略=OPTIONAL时无需申诉手动打卡
8. **权限控制交互表现**:无 attendance:appeal:approve 权限时[审核]按钮隐藏;主管仅审核本班组人员的申诉
9. **H1 防重复请求(强制)**"查询"按钮点击后disabled+loading态行内[审核]按钮点击后整行禁用+半透明遮罩分页切换时abort前一次未完成请求
10. **H2 超时配置(强制)**申诉列表GET请求设置15s超时审核POST请求设置30s超时请求耗时>3s时展示全局ElLoading
11. **H3 操作确认(强制)**:审核操作(通过/驳回为不可逆操作提交前弹出ElMessageBox.confirm二次确认通过操作type="info"提示"确定通过该申诉?通过后将自动补录打卡记录"驳回操作type="warning"提示"确定驳回该申诉?"
12. **H6 批量限制(建议)**当前页面暂无批量操作若后续扩展批量审核功能单次批量审核上限100条记录超出时提示"单次最多选择100条进行批量审核"
13. **H8 反馈规范(建议)**审核成功后ElMessage.success显示2秒后自动消失silent刷新列表状态失败提示需手动关闭网络异常提供重试按钮
### 组件规范
| 元素 | 组件 | 配置参数 |
|------|------|----------|
| 审核状态筛选 | el-select | clearable, placeholder="全部状态" |
| 申诉人输入 | el-input | clearable, maxlength=20, placeholder="请输入申诉人" |
| 日期范围 | el-date-picker | type="daterange", value-format="YYYY-MM-DD", range-separator="至" |
| 列表 | el-table | stripe, border, :data="tableData" |
| 分页 | el-pagination | layout="total, sizes, prev, pager, next", :page-sizes="[10,20,50]" |
| 审核状态标签 | el-tag | 待审核=warning / 已通过=success / 已驳回=danger |
| 异常类型标签 | el-tag | type="info", size="small" |
| 审核按钮 | el-button | type="primary", link, v-if="row.auditStatus==='pending'" |
| 审核弹窗 | el-dialog | title="审核异常申诉", width="500px", :close-on-click-modal="false" |
| 审核结果 | el-radio-group | v-model="auditForm.result" |
| 驳回原因 | el-input | type="textarea", :rows="3", maxlength=200, show-word-limit, v-if="auditForm.result==='reject'" |
| 蓝牙双模式差异展示 | el-descriptions | :column="2", border, title="蓝牙策略差异" |
### 校验规则
| 字段 | 规则 | 错误提示 |
|------|------|----------|
| 审核结果 | 必选 | "请选择审核结果" |
| 驳回原因 | 驳回时必填maxlength=200 | "请填写驳回原因" |
| 日期范围 | 结束日期≥开始日期 | "结束日期不能早于开始日期" |
### 响应式布局
| 断点 | 布局调整 |
|------|----------|
| ≥1280px桌面端 | 查询条件区水平排列表格完整展示全部7列弹窗宽度500px |
| 1024-1279pxPad横屏 | 查询条件区换行排列,表格隐藏"申诉说明"列弹窗宽度460px |
| 768-1023pxPad竖屏 | 查询条件区垂直堆叠表格仅显示申诉人、异常类型、审核状态、操作列弹窗宽度90vw |
---
## 页面5数据补录页
**页面编号**PR-A-05-P01
**端侧归属**Web专属
**页面路径**/attendance/supplement
### 补录数据标记规范
| 标记项 | 说明 |
|--------|------|
| is_supplement | true |
| supplement_reason | 蓝牙故障/系统异常/其他 |
| supplement_audit_status | 待审核/通过/驳回 |
| 自动补录 | 异常申诉审核通过后系统自动补录打卡记录 |
### 操作按钮
| 按钮 | 权限编码 | 位置 | 显示条件 | 说明 |
|------|----------|------|----------|------|
| 审核 | attendance:supplement:approve | 行操作 | 审核状态=待审核 | — |
### API端点
| 页面操作 | API路径 | 方法 | 说明 |
|----------|---------|------|------|
| 补录列表 | /api/v1/attendance-records/supplements | GET | — |
| 审核 | /api/v1/attendance-records/supplements/{id}/approve | POST | — |
### 交互流程要求
1. **页面加载流程**:进入页面 → 调用补录列表API GET /api/v1/attendance-records/supplements → 渲染补录数据表格默认按补录时间倒序排列每页20条
2. **查询/筛选交互流程**:选择审核状态/输入补录人/选择日期范围 → 点击[查询] → 重新加载数据 → 点击[重置]清空条件
3. **表单填写与提交流程**:本页无新增表单,补录数据来源:①小程序端蓝牙失败后手动补录 ②异常申诉审核通过后系统自动补录
4. **弹窗/抽屉交互流程**:点击[审核](审核状态=待审核时显示)→ 弹出审核弹窗,选择"通过"或"驳回",驳回时必填驳回原因 → 确认后调用审核API → 成功后关闭弹窗并刷新列表
5. **行内操作流程**:点击[审核] → 弹窗选择通过/驳回 → 提交 → 刷新该行审核状态;自动补录的记录(异常申诉审核通过)标记为"自动补录",无需二次审核
6. **异常与错误处理**:审核已审核过的记录提示"该记录已审核"API请求失败显示ElMessage.error列表无数据时显示ElEmpty
7. **联动/级联交互**:审核状态筛选影响列表展示;补录原因枚举来源于系统配置;自动补录记录与手动补录记录通过标签区分
8. **权限控制交互表现**:无 attendance:supplement:approve 权限时[审核]按钮隐藏
9. **H1 防重复请求(强制)**"查询"按钮点击后disabled+loading态行内[审核]按钮点击后整行禁用+半透明遮罩分页切换时abort前一次未完成请求
10. **H2 超时配置(强制)**补录列表GET请求设置15s超时审核POST请求设置30s超时请求耗时>3s时展示全局ElLoading
11. **H3 操作确认(强制)**:审核操作(通过/驳回为不可逆操作提交前弹出ElMessageBox.confirm二次确认通过type="info"提示"确定通过该补录记录?"驳回type="warning"提示"确定驳回该补录记录?"
12. **H6 批量限制(建议)**当前页面暂无批量操作若后续扩展批量审核功能单次批量审核上限100条记录
13. **H8 反馈规范(建议)**审核成功ElMessage.success 2秒自动消失+silent刷新列表失败手动关闭网络异常提供重试
### 组件规范
| 元素 | 组件 | 配置参数 |
|------|------|----------|
| 审核状态筛选 | el-select | clearable, placeholder="全部状态" |
| 补录人输入 | el-input | clearable, maxlength=20, placeholder="请输入补录人" |
| 日期范围 | el-date-picker | type="daterange", value-format="YYYY-MM-DD", range-separator="至" |
| 列表 | el-table | stripe, border, :data="tableData" |
| 分页 | el-pagination | layout="total, sizes, prev, pager, next", :page-sizes="[10,20,50]" |
| 审核状态标签 | el-tag | 待审核=warning / 已通过=success / 已驳回=danger |
| 补录类型标签 | el-tag | 自动补录=primary / 手动补录=warning, size="small" |
| 审核按钮 | el-button | type="primary", link, v-if="row.auditStatus==='pending'" |
| 审核弹窗 | el-dialog | title="审核补录", width="500px", :close-on-click-modal="false" |
| 审核结果 | el-radio-group | v-model="auditForm.result" |
| 驳回原因 | el-input | type="textarea", :rows="3", maxlength=200, show-word-limit, v-if="auditForm.result==='reject'" |
### 校验规则
| 字段 | 规则 | 错误提示 |
|------|------|----------|
| 审核结果 | 必选 | "请选择审核结果" |
| 驳回原因 | 驳回时必填maxlength=200 | "请填写驳回原因" |
| 日期范围 | 结束日期≥开始日期 | "结束日期不能早于开始日期" |
### 响应式布局
| 断点 | 布局调整 |
|------|----------|
| ≥1280px桌面端 | 查询条件区水平排列表格完整展示全部列弹窗宽度500px |
| 1024-1279pxPad横屏 | 查询条件区换行排列表格隐藏次要列弹窗宽度460px |
| 768-1023pxPad竖屏 | 查询条件区垂直堆叠表格仅显示关键列弹窗宽度90vw |
---
## 需求追溯
| 功能点编号 | 功能名称 | 文档来源 | 后续服务 | 关联功能 |
|------------|----------|----------|----------|----------|
| PR-A-01 | 打卡点管理 | 02-物业公司 §5 / 03-物业公司 §5 | 打卡点→蓝牙绑定→小程序打卡 | 组织架构(打卡点分配) / 系统配置(蓝牙设备) |
| PR-A-02 | 打卡规则 | 02-物业公司 §5 / 03-物业公司 §5 | 规则→迟到早退判定 | — |
| PR-A-03 | 考勤记录 | 02-物业公司 §5 | — | 统计报表→考勤统计 |
| PR-A-04 | 异常审核 | 02-物业公司 §5 / 03-物业公司 §5 | 审核→自动补录打卡 | 小程序端异常申诉(MP-AT-04) |
| PR-A-05 | 数据补录 | 02-物业公司 §5 | 补录→审核 | 操作日志→补录日志 |
## 业务规则
1. **蓝牙强制打卡**:策略=REQUIRED时必须在指定打卡点连接蓝牙后才可打卡来源01 §9 / 06 §4.4
2. **蓝牙双模式**:策略=OPTIONAL时允许手动打卡(check_method=MANUAL)来源06 §4.4
3. **异常申诉流程**蓝牙失败→提交异常申诉→主管审核→通过后系统自动补录打卡记录来源03-物业公司 §5 / 03-小程序端 §5.1
4. **打卡窗口**:上班/下班各设打卡时间窗口窗口外打卡标记异常来源02-物业公司 PR-A-02
5. **迟到/早退规则**可自定义迟到、严重迟到、早退、严重早退的分钟阈值来源02-物业公司 PR-A-02
6. **数据权限**主管仅看本班组数据员工仅看本人数据来源01 §1.3
7. **打卡判定**不判断距离只要成功连接蓝牙设备即可打卡来源06 §5.4