"use client" import { addDailyWorkData, editDailyWorkData, } from "@/components/label/api/daily" import { Daily } from "@/components/label/api/daily/typing" import { useAllUserStore, usePermissionStore, } from "@/components/label/store/auth" import { Button, Group, Modal, NumberInput, Paper, Select, SimpleGrid, Stack, Text, TextInput, } from "@mantine/core" import { useForm } from "@mantine/form" import { notifications } from "@mantine/notifications" import { useEffect, useMemo } from "react" import classes from "./DailyReportModal.module.css" import { accountTypeOpts, actualTypeOpts, objTypeOpts, performanceOpts, setTypeOpts, workTypeOpts, } from "../config" function normalizeTimeValue(value?: string | null) { if (!value) return "" return value.length >= 5 ? value.slice(0, 5) : value } function toTimeWithSeconds(value?: string) { if (!value) return undefined return value.length === 5 ? `${value}:00` : value } type LeaderTreeNode = { title?: string value?: string | number children?: LeaderTreeNode[] } function flattenLeaderTree( nodes: LeaderTreeNode[], prefixTitle: string[] = [] ): Array<{ label: string; value: string }> { const result: Array<{ label: string; value: string }> = [] nodes.forEach((node) => { const title = node.title ?? "" const nextPrefix = title ? [...prefixTitle, title] : prefixTitle const children = node.children ?? [] const hasChildren = children.length > 0 const valueRaw = node.value if (hasChildren) { result.push(...flattenLeaderTree(children, nextPrefix)) return } if (valueRaw === undefined || valueRaw === null) return if (typeof valueRaw === "string" && valueRaw.includes("-")) return result.push({ label: nextPrefix.join(" / "), value: String(valueRaw), }) }) return result } function HourRightSection() { return ( 小时(H) ) } export default function DailyReportModal(props: { opened: boolean record: Daily.DailyWorkList | null projectOptions: Array<{ label: string; value: string }> onCloseAction: (refresh?: boolean) => void }) { const { opened, record, onCloseAction, projectOptions } = props const user_id = usePermissionStore((s) => s.user_id) const user_name = usePermissionStore((s) => s.user_name) const treeData = useAllUserStore((s) => s.treeData) const leaderOptions = useMemo(() => { return flattenLeaderTree(treeData ?? []) }, [treeData]) const form = useForm({ initialValues: { user_name: user_name ?? "", date: "", start_time: "", end_time: "", set_type: "", actual_type: "", project_id: "", leader_uid: "", work_type: "", accounting_type: "", performance_accounting: "", obj_type: "", work_time: undefined as number | undefined, rate: undefined as number | undefined, standard_size: undefined as number | undefined, completed_size: undefined as number | undefined, residual_size: undefined as number | undefined, residual_work_time: undefined as number | undefined, residual_pm: "", remarks: "", }, validate: { date: (v) => (v ? null : "请输入日期"), // set_type: (v) => (v ? null : "请选择规定类型"), actual_type: (v) => (v ? null : "请选择出勤类型"), }, validateInputOnChange: true, validateInputOnBlur: true, clearInputErrorOnChange: true, }) useEffect(() => { if (!opened) return if (!record) { form.setValues({ user_name: user_name ?? "", date: new Date().toISOString().slice(0, 10), start_time: "", end_time: "", set_type: "", actual_type: "", project_id: "", leader_uid: "", work_type: "", accounting_type: "", performance_accounting: "", obj_type: "", work_time: undefined, rate: undefined, standard_size: undefined, completed_size: undefined, residual_size: undefined, residual_work_time: undefined, residual_pm: "", remarks: "", }) form.resetDirty() return } form.setValues({ user_name: user_name ?? "", date: record.date ?? "", start_time: normalizeTimeValue(record.start_time), end_time: normalizeTimeValue(record.end_time), set_type: record.set_type ?? "", actual_type: record.actual_type ?? "", project_id: record.project_id === undefined || record.project_id === null ? "" : String(record.project_id), leader_uid: record.leader_uid === undefined || record.leader_uid === null ? "" : String(record.leader_uid), work_type: record.work_type ?? "", accounting_type: record.accounting_type ?? "", performance_accounting: record.performance_accounting === true ? "true" : record.performance_accounting === false ? "false" : "", obj_type: record.obj_type === undefined || record.obj_type === null ? "" : String(record.obj_type), work_time: record.work_time ?? undefined, rate: record.rate ?? undefined, standard_size: record.standard_size ?? undefined, completed_size: record.completed_size ?? undefined, residual_size: record.residual_size ?? undefined, residual_work_time: record.residual_work_time ?? undefined, residual_pm: record.residual_pm === true ? "正" : record.residual_pm === false ? "负" : "", remarks: record.remarks ?? "", }) form.resetDirty() // eslint-disable-next-line react-hooks/exhaustive-deps }, [opened, record, user_name]) useEffect(() => { const workTime = form.values.work_time const rate = form.values.rate if (workTime !== undefined && rate !== undefined) { form.setFieldValue("standard_size", Number((workTime * rate).toFixed(1))) } else { form.setFieldValue("standard_size", undefined) } // eslint-disable-next-line react-hooks/exhaustive-deps }, [form.values.work_time, form.values.rate]) useEffect(() => { const standardSize = form.values.standard_size const completedSize = form.values.completed_size const workTime = form.values.work_time if ( standardSize !== undefined && completedSize !== undefined && workTime !== undefined && standardSize !== 0 ) { const residualSize = completedSize - standardSize const residualWorkTime = Number( ((residualSize / standardSize) * workTime).toFixed(1) ) form.setFieldValue("residual_size", Number(residualSize.toFixed(1))) form.setFieldValue("residual_work_time", residualWorkTime) form.setFieldValue("residual_pm", residualSize >= 0 ? "正" : "负") } else { form.setFieldValue("residual_size", undefined) form.setFieldValue("residual_work_time", undefined) form.setFieldValue("residual_pm", "") } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ form.values.standard_size, form.values.completed_size, form.values.work_time, ]) const handleSubmit = form.onSubmit(async (values) => { const uid = typeof user_id === "number" ? user_id : Number(user_id ?? 0) if (!uid) { notifications.show({ color: "red", title: "提交失败", message: "未获取到用户信息", }) return } const params: Daily.CreateProps = { uid, date: values.date, start_time: toTimeWithSeconds(values.start_time), end_time: toTimeWithSeconds(values.end_time), set_type: values.set_type, actual_type: values.actual_type, project_id: values.project_id ? Number(values.project_id) : undefined, leader_uid: values.leader_uid ? Number(values.leader_uid) : undefined, work_type: values.work_type || undefined, accounting_type: values.accounting_type || undefined, performance_accounting: values.performance_accounting === "true" ? true : values.performance_accounting === "false" ? false : undefined, obj_type: values.obj_type ? Number(values.obj_type) : undefined, work_time: values.work_time, rate: values.rate, standard_size: values.standard_size, completed_size: values.completed_size, residual_size: values.residual_size, residual_work_time: values.residual_work_time, residual_pm: values.residual_pm === "正" ? true : values.residual_pm === "负" ? false : undefined, remarks: values.remarks || undefined, } try { if (record?.id) { await editDailyWorkData(params, record.id) notifications.show({ color: "green", title: "操作成功", message: "已更新日报", }) } else { await addDailyWorkData(params) notifications.show({ color: "green", title: "操作成功", message: "已提交日报", }) } onCloseAction(true) form.reset() } catch (e) { notifications.show({ color: "red", title: "操作失败", message: e instanceof Error ? e.message : "请求失败", }) } }) return ( { form.reset() onCloseAction() }} title={record ? "编辑日报" : "填写日报"} size={840} centered classNames={{ content: classes.modalContent, header: classes.modalHeader, title: classes.modalTitle, body: classes.modalBody, }} overlayProps={{ backgroundOpacity: 0.22 }} transitionProps={{ transition: "fade", duration: 100, timingFunction: "ease", }} closeOnClickOutside={false}>
} rightSectionWidth={78} {...form.getInputProps("work_time")} />
} rightSectionWidth={78} /> ) }