diff --git a/app/person/dashboard/components/PersonalProjectTable.tsx b/app/person/dashboard/components/PersonalProjectTable.tsx
index e821296..37c95cb 100644
--- a/app/person/dashboard/components/PersonalProjectTable.tsx
+++ b/app/person/dashboard/components/PersonalProjectTable.tsx
@@ -2,6 +2,7 @@
import { getPersonProjectDashBoard } from "@/components/label/api/project"
import { Project } from "@/components/label/api/project/typing"
+import { formatWorkTimeHoursMinutes } from "@/components/label/utils/time"
import {
SettingDataTable,
SettingListHeader,
@@ -18,24 +19,10 @@ import { DatePickerInput, type DatesRangeValue } from "@mantine/dates"
import { IconRefresh, IconSearch } from "@tabler/icons-react"
import dayjs from "dayjs"
import "dayjs/locale/zh-cn"
-import duration from "dayjs/plugin/duration"
import { DataTableColumn } from "mantine-datatable"
import { useCallback, useEffect, useMemo, useState } from "react"
import classes from "../page.module.css"
-dayjs.extend(duration)
-
-function formatDurationSeconds(seconds?: number | null) {
- const value = seconds ?? 0
- if (!value) return "-"
- const durationObj = dayjs.duration(value, "seconds")
- const hours = durationObj.hours()
- const minutes = durationObj.minutes()
- if (hours) return `${hours}小时${minutes}分钟`
- if (minutes) return `${minutes}分钟`
- return "-"
-}
-
interface FilterFormRecord {
query_date: DatesRangeValue
}
@@ -201,7 +188,7 @@ export default function PersonalProjectTable() {
render: (record: Project.PersonProjectDashboardResponseItem) => {
return (
- {formatDurationSeconds(record.work_time)}
+ {formatWorkTimeHoursMinutes(record.work_time)}
)
},
diff --git a/app/person/dashboard/page.tsx b/app/person/dashboard/page.tsx
index 1c969c9..ce338ef 100644
--- a/app/person/dashboard/page.tsx
+++ b/app/person/dashboard/page.tsx
@@ -1,6 +1,7 @@
"use client"
import { getCurrentPersonData } from "@/components/label/api/project"
+import { formatWorkTimeHoursMinutes } from "@/components/label/utils/time"
import {
SettingContentPanel,
SettingPage,
@@ -8,14 +9,11 @@ import {
} from "@/components/setting/PageSurface"
import { Stack, Text } from "@mantine/core"
import dayjs from "dayjs"
-import duration from "dayjs/plugin/duration"
import { useEffect, useMemo, useState } from "react"
import PersonalProjectTable from "./components/PersonalProjectTable"
import PersonalTaskTable from "./components/PersonalTaskTable"
import classes from "./page.module.css"
-dayjs.extend(duration)
-
function monthText(month: string) {
const list = [
"一月",
@@ -35,17 +33,6 @@ function monthText(month: string) {
return list[idx] ?? ""
}
-function formatDurationSeconds(seconds?: number | null) {
- const value = seconds ?? 0
- if (!value) return "-"
- const durationObj = dayjs.duration(value, "seconds")
- const hours = durationObj.hours()
- const minutes = durationObj.minutes()
- if (hours) return `${hours}小时${minutes}分钟`
- if (minutes) return `${minutes}分钟`
- return "-"
-}
-
export default function PersonDashboardPage() {
const [data, setData] = useState<{
label_data_size: number
@@ -68,9 +55,9 @@ export default function PersonDashboardPage() {
const dataText = useMemo(() => {
return {
- label: formatDurationSeconds(data?.label_work_time ?? 0),
- review1: formatDurationSeconds(data?.review1_work_time ?? 0),
- review2: formatDurationSeconds(data?.review2_work_time ?? 0),
+ label: formatWorkTimeHoursMinutes(data?.label_work_time ?? 0),
+ review1: formatWorkTimeHoursMinutes(data?.review1_work_time ?? 0),
+ review2: formatWorkTimeHoursMinutes(data?.review2_work_time ?? 0),
}
}, [data])
diff --git a/app/person/report/page.tsx b/app/person/report/page.tsx
index 216be81..2aa95ee 100644
--- a/app/person/report/page.tsx
+++ b/app/person/report/page.tsx
@@ -7,6 +7,7 @@ import {
import { Daily } from "@/components/label/api/daily/typing"
import { getSelfProjectList } from "@/components/label/api/project"
import { useAllUserStore } from "@/components/label/store/auth"
+import { formatWorkTime } from "@/components/label/utils/time"
import {
SettingContentPanel,
SettingCustomPageSizeControl,
@@ -47,7 +48,6 @@ import { VirtualTreeSelect } from "@/components/tree-select/tree"
import { DateInput } from "@mantine/dates"
import dayjs from "dayjs"
import "dayjs/locale/zh-cn"
-import duration from "dayjs/plugin/duration"
import { DataTableColumn, DataTableSortStatus } from "mantine-datatable"
import { useCallback, useEffect, useMemo, useState } from "react"
import DailyReportModal from "./components/DailyReportModal"
@@ -62,7 +62,6 @@ import {
workTypeOpts,
} from "./config"
import classes from "./page.module.css"
-dayjs.extend(duration)
function weekDayText(day: number) {
const list = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
@@ -241,10 +240,6 @@ export default function PersonReportPage() {
return accumulator + (Number.isFinite(value) ? value : 0)
}, 0)
- const getTime = (time: number) => {
- return dayjs.duration(time, "seconds").format("HH:mm:ss")
- }
-
const columns = useMemo(() => {
const cols: DataTableColumn[] = [
{
@@ -335,8 +330,9 @@ export default function PersonReportPage() {
title: "工时",
width: 90,
sortable: true,
- render: (record) => (record.work_time ? getTime(record.work_time) : 0),
- footer: getTime(sum(records.map((r) => r.work_time ?? 0))),
+ render: (record) =>
+ record.work_time ? formatWorkTime(record.work_time) : 0,
+ footer: formatWorkTime(sum(records.map((r) => r.work_time ?? 0))),
},
{ accessor: "rate", title: "额定倍率", width: 90 },
{
diff --git a/app/person/workload/WorkloadMetricsTable.tsx b/app/person/workload/WorkloadMetricsTable.tsx
index 1fa32e3..dc47d9a 100644
--- a/app/person/workload/WorkloadMetricsTable.tsx
+++ b/app/person/workload/WorkloadMetricsTable.tsx
@@ -1,6 +1,7 @@
"use client"
import { TimeFilter } from "@/components/label/api/workload/typing"
+import { formatWorkTime } from "@/components/label/utils/time"
import {
SettingContentPanel,
SettingDataTable,
@@ -23,12 +24,10 @@ import {
} from "@tabler/icons-react"
import dayjs from "dayjs"
import "dayjs/locale/zh-cn"
-import duration from "dayjs/plugin/duration"
import { DataTableColumn, DataTableSortStatus } from "mantine-datatable"
import { useEffect, useMemo, useState } from "react"
import * as XLSX from "xlsx-js-style"
import { DimensionType, GroupedData, MetricColumn } from "./config"
-dayjs.extend(duration)
function emptyGroupedData(): GroupedData {
return {
@@ -157,10 +156,6 @@ export default function WorkloadMetricsTable(props: {
return records
}, [appliedFilters, data])
- const getTime = (time: number) => {
- return dayjs.duration(time, "seconds").format("HH:mm:ss")
- }
-
const baseColumns = useMemo(() => {
const allCols: Record[]> = {
all: [
@@ -253,12 +248,12 @@ export default function WorkloadMetricsTable(props: {
return acc + (Number.isFinite(value) ? value : 0)
}, 0)
if (["work_time"].includes(metric.key)) {
- return [metric.key, getTime(sum ?? 0)]
+ return [metric.key, formatWorkTime(sum)]
} else {
return [metric.key, sum]
}
})
- ) as Record
+ ) as Record
const metricCols = metrics.map((metric) => {
if (["work_time"].includes(metric.key)) {
@@ -268,7 +263,7 @@ export default function WorkloadMetricsTable(props: {
width: 140,
sortable: true,
footer: totalsByKey[metric.key] ?? 0,
- render: (record) => getTime(record[metric.key] ?? 0),
+ render: (record) => formatWorkTime(record[metric.key]),
} as DataTableColumn
} else {
return {
diff --git a/components/label/utils/time.ts b/components/label/utils/time.ts
new file mode 100644
index 0000000..7e6ae14
--- /dev/null
+++ b/components/label/utils/time.ts
@@ -0,0 +1,41 @@
+function normalizeDurationSeconds(value: unknown) {
+ const totalSeconds = Number(value ?? 0)
+ if (!Number.isFinite(totalSeconds) || totalSeconds <= 0) {
+ return 0
+ }
+
+ return Math.floor(totalSeconds)
+}
+
+export function formatWorkTime(value: unknown) {
+ const normalizedSeconds = normalizeDurationSeconds(value)
+ if (!normalizedSeconds) {
+ return "00:00:00"
+ }
+
+ const hours = Math.floor(normalizedSeconds / 3600)
+ const minutes = Math.floor((normalizedSeconds % 3600) / 60)
+ const seconds = normalizedSeconds % 60
+
+ return [hours, minutes, seconds]
+ .map((part) => String(part).padStart(2, "0"))
+ .join(":")
+}
+
+export function formatWorkTimeHoursMinutes(value: unknown) {
+ const normalizedSeconds = normalizeDurationSeconds(value)
+ if (!normalizedSeconds) {
+ return "-"
+ }
+
+ const hours = Math.floor(normalizedSeconds / 3600)
+ const minutes = Math.floor((normalizedSeconds % 3600) / 60)
+
+ if (hours > 0) {
+ return `${hours}小时${minutes}分钟`
+ }
+ if (minutes > 0) {
+ return `${minutes}分钟`
+ }
+ return "-"
+}