diff --git a/.react-doctor/false-positives.md b/.react-doctor/false-positives.md
new file mode 100644
index 0000000..59eef50
--- /dev/null
+++ b/.react-doctor/false-positives.md
@@ -0,0 +1,26 @@
+# React Doctor — 已确认的误报 (false positives)
+
+本文件记录经人工确认的误报。React Doctor 在分诊时会读取此文件并跳过匹配的诊断。
+每条注明:规则、位置、代码形状、为何是误报。
+
+---
+
+## `react-doctor/server-auth-actions`
+
+- **位置**: `components/login/libs/session.ts` — `genAccessToken`
+- **代码形状**: 文件顶部含 `"use server"`,导出的 async 函数本身就是**会话校验 / 凭证建立端点**——读取会话 cookie (`SESSION_COOKIE_NAME`)、查 redis、校验客户端 IP,失败时返回 `ok:false` 重定向到登录页。
+- **为何是误报**: 该函数*就是*鉴权逻辑本身,不存在"调用前的会话"可供校验。规则的 validation prompt 明确把"action 即认证/凭证建立端点(login/signup/OTP/session 校验)"列为典型误报——这里因函数名为 `genAccessToken`(不在规则的 `auth()`/`validateSession()` 等识别名单内)而误触发。给它再加 `auth()` 会构成循环逻辑。
+- **判定**: 跳过此规则在该函数上的诊断。
+
+---
+
+## `react-doctor/exhaustive-deps` — 有意排除的依赖(加了会引 bug)
+
+以下 useEffect 均**有意**保持最小依赖数组,且都已带 `// eslint-disable-next-line react-hooks/exhaustive-deps`(react-doctor 用的是 oxlint 同名规则,故未被该注释覆盖)。逐条确认:补齐缺失依赖会引入真实 bug,故不改逻辑,登记为误报。
+
+- **`app/person/report/components/DailyReportModal.tsx:190`** — 缺 `resetFormState` 等。`resetFormState` 每次渲染重建,加入依赖会导致 effect 每次渲染都执行(反复重置表单)。effect 设计为仅在 `[opened, record, user_name]` 变化时运行。
+- **`app/person/report/components/DailyReportModal.tsx:201` / `:227`** — 缺 `form.setFieldValue`。Mantine form 方法引用稳定;effect 有意仅在对应 `form.values.*` 变化时联动计算字段,补 setter 无意义且违背设计意图。
+- **`app/person/workload/WorkloadMetricsTable.tsx:124`** — 缺 `refresh`。这是 `[]` 挂载时一次性拉取数据的 effect;`refresh` 为每次渲染重建的普通 async 函数,加入依赖会导致每次渲染重复请求。
+- **`components/tree-select/tree.tsx:122`** — 缺 `tree.initialize`。`useTree()` 每次渲染返回新的 controller 对象(文件内注释亦说明此点),依赖它会造成无限重渲染;effect 有意仅在 `[data]` 变化时初始化。
+
+- **判定**: 以上位置跳过 `exhaustive-deps`。如需让 react-doctor 扫描层面也静默,可在各行改用 `// oxlint-disable-next-line react-doctor/exhaustive-deps` 并附理由(本表已记录理由)。
diff --git a/app/person/dashboard/components/Icon.tsx b/app/person/dashboard/components/Icon.tsx
deleted file mode 100644
index f3bf826..0000000
--- a/app/person/dashboard/components/Icon.tsx
+++ /dev/null
@@ -1,282 +0,0 @@
-"use client"
-
-export const DataIcon = () => (
-
-)
-
-export const HourIcon = () => (
-
-)
-
-export const ReviewIcon = () => (
-
-)
diff --git a/app/person/dashboard/components/PersonalTaskTable.tsx b/app/person/dashboard/components/PersonalTaskTable.tsx
index 4d7262a..802bd76 100644
--- a/app/person/dashboard/components/PersonalTaskTable.tsx
+++ b/app/person/dashboard/components/PersonalTaskTable.tsx
@@ -18,13 +18,27 @@ import {
getPersistedPageSizeOptions,
resolvePageSizeWithinOptions,
} from "@/components/setting/pageSize"
-import { Button, Group, Stack, Text, UnstyledButton } from "@mantine/core"
+import {
+ Button,
+ Group,
+ Select,
+ Stack,
+ Text,
+ UnstyledButton,
+} from "@mantine/core"
import { IconRefresh } from "@tabler/icons-react"
import { DataTableColumn } from "mantine-datatable"
import { useCallback, useEffect, useMemo, useState } from "react"
import classes from "../page.module.css"
const DEFAULT_RECORDS_PER_PAGE_OPTIONS = [10, 15, 20, 50]
+const REJECTED_FILTER_OPTIONS = [
+ { value: "all", label: "全部" },
+ { value: "true", label: "是" },
+ { value: "false", label: "否" },
+] as const
+
+type RejectedFilterValue = (typeof REJECTED_FILTER_OPTIONS)[number]["value"]
export default function PersonalTaskTable() {
const user_name = usePermissionStore((s) => s.user_name)
@@ -47,6 +61,8 @@ export default function PersonalTaskTable() {
const [totalItems, setTotalItems] = useState(0)
const [records, setRecords] = useState([])
const [loading, setLoading] = useState(false)
+ const [rejectedFilter, setRejectedFilter] =
+ useState("all")
const totalPages = useMemo(() => {
return Math.max(1, Math.ceil(totalItems / pageSize))
@@ -59,13 +75,15 @@ export default function PersonalTaskTable() {
const res = await getUserTaskList({
page_number: page,
page_size: pageSize,
+ rejected:
+ rejectedFilter === "all" ? undefined : rejectedFilter === "true",
})
setRecords(res?.simple_task_list ?? [])
setTotalItems(res?.total_items ?? 0)
} finally {
setLoading(false)
}
- }, [page, pageSize, user_name])
+ }, [page, pageSize, rejectedFilter, user_name])
useEffect(() => {
load()
@@ -198,7 +216,32 @@ export default function PersonalTaskTable() {
+
+ 共 {totalItems} 条记录
+
+
+
+ 是否返工
+
+
+
+ }
actions={