import { useEffect, useMemo, useRef, useState, type ChangeEvent } from "react"; import { MapPin, Camera, Send, CalendarDays, CheckCircle2, FileText, ListTodo, Filter, RefreshCw, X } from "lucide-react"; import { format } from "date-fns"; import { motion } from "motion/react"; import { getWorkOverview, reverseWorkGeocode, saveWorkCheckIn, saveWorkDailyReport, uploadWorkCheckInPhoto, type CreateWorkCheckInPayload, type CreateWorkDailyReportPayload, type WorkHistoryItem, } from "@/lib/auth"; const historyFilters = ["全部", "日报", "外勤打卡"] as const; const defaultCheckInForm: CreateWorkCheckInPayload = { locationText: "", remark: "", }; const defaultReportForm: CreateWorkDailyReportPayload = { workContent: "", tomorrowPlan: "", sourceType: "manual", }; function getCheckInStatus(status?: string) { if (!status) { return "待打卡"; } return status === "updated" ? "已更新" : "已打卡"; } function getReportStatus(status?: string) { if (!status) { return "待提交"; } return status === "reviewed" || status === "已点评" ? "已点评" : "已提交"; } export default function Work() { const hasAutoRefreshedLocation = useRef(false); const photoInputRef = useRef(null); const [loading, setLoading] = useState(true); const [refreshingLocation, setRefreshingLocation] = useState(false); const [submittingCheckIn, setSubmittingCheckIn] = useState(false); const [submittingReport, setSubmittingReport] = useState(false); const [uploadingPhoto, setUploadingPhoto] = useState(false); const [historyFilter, setHistoryFilter] = useState<(typeof historyFilters)[number]>("全部"); const [locationHint, setLocationHint] = useState(""); const [locationLocked, setLocationLocked] = useState(false); const [pageError, setPageError] = useState(""); const [checkInError, setCheckInError] = useState(""); const [reportError, setReportError] = useState(""); const [checkInSuccess, setCheckInSuccess] = useState(""); const [reportSuccess, setReportSuccess] = useState(""); const [historyData, setHistoryData] = useState([]); const [checkInStatus, setCheckInStatus] = useState(); const [reportStatus, setReportStatus] = useState(); const [checkInPhotoUrls, setCheckInPhotoUrls] = useState([]); const [checkInForm, setCheckInForm] = useState(defaultCheckInForm); const [reportForm, setReportForm] = useState(defaultReportForm); const filteredHistory = useMemo(() => { if (historyFilter === "全部") { return historyData; } return historyData.filter((item) => item.type === historyFilter); }, [historyData, historyFilter]); useEffect(() => { void loadOverview(); }, []); useEffect(() => { if (loading || hasAutoRefreshedLocation.current) { return; } hasAutoRefreshedLocation.current = true; void handleRefreshLocation(); }, [loading]); const handleRefreshLocation = async () => { setCheckInError(""); setRefreshingLocation(true); setLocationLocked(false); if (!window.isSecureContext && location.hostname !== "localhost" && location.hostname !== "127.0.0.1") { setLocationHint("当前是通过 HTTP 地址在手机端访问,浏览器会直接禁止定位。请改用 HTTPS 地址打开,或先手动填写当前位置。"); setRefreshingLocation(false); return; } setLocationHint("正在获取当前位置..."); try { const position = await resolveCurrentPosition(); const latitude = Number(position.coords.latitude.toFixed(6)); const longitude = Number(position.coords.longitude.toFixed(6)); try { const displayName = await reverseWorkGeocode(latitude, longitude); setCheckInForm((prev) => ({ ...prev, locationText: displayName || `定位坐标:${latitude}, ${longitude}`, latitude, longitude, })); setLocationLocked(Boolean(displayName)); setLocationHint(displayName ? "定位已刷新并锁定当前位置,如需变更请点击“刷新定位”。" : "已获取定位坐标,如需更精确地址可再次刷新定位。"); } catch { setCheckInForm((prev) => ({ ...prev, locationText: `定位坐标:${latitude}, ${longitude}`, latitude, longitude, })); setLocationLocked(false); setLocationHint("已获取坐标,但地点名称解析失败,你也可以手动补充。"); } } catch (error) { setLocationLocked(false); setLocationHint(error instanceof Error ? error.message : "定位获取失败,请手动填写当前位置。"); } finally { setRefreshingLocation(false); } }; const handlePickPhoto = () => { photoInputRef.current?.click(); }; const handlePhotoChange = async (event: ChangeEvent) => { const file = event.target.files?.[0]; if (!file) { return; } setCheckInError(""); setCheckInSuccess(""); setUploadingPhoto(true); try { const uploadedUrl = await uploadWorkCheckInPhoto(file); setCheckInPhotoUrls([uploadedUrl]); } catch (error) { setCheckInError(error instanceof Error ? error.message : "现场照片上传失败"); } finally { setUploadingPhoto(false); event.target.value = ""; } }; const handleRemovePhoto = () => { setCheckInPhotoUrls([]); }; const handleCheckInSubmit = async () => { if (submittingCheckIn) { return; } setCheckInError(""); setCheckInSuccess(""); setSubmittingCheckIn(true); try { if (!checkInPhotoUrls.length) { throw new Error("请先拍摄并上传现场照片"); } await saveWorkCheckIn({ locationText: checkInForm.locationText.trim(), remark: checkInForm.remark?.trim() || undefined, longitude: checkInForm.longitude, latitude: checkInForm.latitude, photoUrls: checkInPhotoUrls, }); await loadOverview(); setCheckInForm(defaultCheckInForm); setCheckInPhotoUrls([]); setLocationLocked(false); setCheckInSuccess("打卡已记录,本日可继续新增打卡。"); } catch (error) { setCheckInError(error instanceof Error ? error.message : "打卡提交失败"); } finally { setSubmittingCheckIn(false); } }; const handleReportSubmit = async () => { if (submittingReport) { return; } setReportError(""); setReportSuccess(""); setSubmittingReport(true); try { await saveWorkDailyReport({ workContent: reportForm.workContent.trim(), tomorrowPlan: reportForm.tomorrowPlan.trim(), sourceType: reportForm.sourceType || "manual", }); await loadOverview(); setReportSuccess("日报已保存,今日再次提交会覆盖当天内容。"); } catch (error) { setReportError(error instanceof Error ? error.message : "日报提交失败"); } finally { setSubmittingReport(false); } }; const handleFilterToggle = () => { setHistoryFilter((current) => { const index = historyFilters.indexOf(current); return historyFilters[(index + 1) % historyFilters.length]; }); }; async function loadOverview() { setLoading(true); setPageError(""); try { const data = await getWorkOverview(); setHistoryData(data.history ?? []); setCheckInStatus(data.todayCheckIn?.status); setReportStatus(data.todayReport?.status); setCheckInForm({ locationText: "", remark: "", longitude: undefined, latitude: undefined, }); setCheckInPhotoUrls([]); setLocationLocked(false); setReportForm({ workContent: data.suggestedWorkContent || data.todayReport?.workContent || "", tomorrowPlan: data.todayReport?.tomorrowPlan ?? "", sourceType: data.todayReport?.sourceType ?? "manual", }); } catch (error) { setPageError(error instanceof Error ? error.message : "工作台数据加载失败"); setHistoryData([]); setCheckInStatus(undefined); setReportStatus(undefined); } finally { setLoading(false); } } return (

工作台

今天是 {format(new Date(), "yyyy年MM月dd日 EEEE")}

今日工作

外勤打卡

{loading ? "加载中..." : getCheckInStatus(checkInStatus)}

当前位置