import { Button, Image, Input, Text, Textarea, View } from "@tarojs/components"; import Taro from "@tarojs/taro"; import { useMemo, useState } from "react"; import { REPAIR_DESCRIPTION_LIMIT, REPAIR_DEVICE_TYPE_LABELS, REPAIR_DRAFT_STORAGE_KEY, type RepairAttachment, type RepairDeviceOption, type RepairDeviceType, type RepairSubmissionSnapshot, appendRepairAttachments, buildDeviceMap, clampDescription, normalizeChosenFiles, validateRepairForm } from "./repair-utils"; import "./index.scss"; const repairDevices: RepairDeviceOption[] = [ { id: "A9876456546", type: "monitor", label: "A9876456546", params: "3AW1 / 654616313" }, { id: "A3648201488", type: "monitor", label: "A3648201488", params: "5BZ2 / 882730114" }, { id: "C7842037781", type: "camera", label: "C7842037781", params: "AI-CAM / 220184900" }, { id: "C7842037782", type: "camera", label: "C7842037782", params: "AI-CAM / 220184901" } ]; const groupedDevices = buildDeviceMap(repairDevices); const deviceTypeOrder: RepairDeviceType[] = ["monitor", "camera"]; function delay(ms: number) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } function formatAttachmentSize(size?: number) { if (!size) { return ""; } if (size >= 1024 * 1024) { return `${(size / 1024 / 1024).toFixed(1)}MB`; } return `${Math.max(size / 1024, 0.1).toFixed(1)}KB`; } function createTicketNo() { return `BX${Date.now().toString().slice(-8)}`; } export default function RepairPage() { const [deviceType, setDeviceType] = useState("monitor"); const [selectedDeviceId, setSelectedDeviceId] = useState(groupedDevices.monitor[0]?.id || ""); const [description, setDescription] = useState(""); const [attachments, setAttachments] = useState([]); const [contactName, setContactName] = useState("张小龙"); const [phone, setPhone] = useState("13689569989"); const [submitting, setSubmitting] = useState(false); const currentDevices = groupedDevices[deviceType]; const selectedDevice = currentDevices.find((item) => item.id === selectedDeviceId) || currentDevices[0] || repairDevices[0]; const imageCount = attachments.filter((item) => item.kind === "image").length; const videoCount = attachments.filter((item) => item.kind === "video").length; const uploadHint = useMemo(() => { if (deviceType === "camera") { return "点击上传AI摄像头故障照片或视频"; } return "点击上传体征设备故障照片或视频"; }, [deviceType]); const showToast = (title: string) => { Taro.showToast({ title, icon: "none" }); }; const handleTypeChange = (nextType: RepairDeviceType) => { if (nextType === deviceType) { return; } const nextDevices = groupedDevices[nextType]; setDeviceType(nextType); setSelectedDeviceId(nextDevices[0]?.id || ""); }; const handleSelectDevice = async () => { if (!currentDevices.length) { showToast("当前暂无可选设备"); return; } try { const result = await Taro.showActionSheet({ itemList: currentDevices.map((item) => item.label) }); const nextDevice = currentDevices[result.tapIndex]; if (nextDevice) { setSelectedDeviceId(nextDevice.id); } } catch (error) { const message = error instanceof Error ? error.message : ""; if (!message.includes("cancel")) { showToast("设备选择失败"); } } }; const handleChooseMedia = async () => { try { const result = await Taro.chooseMedia({ count: 9, mediaType: ["image", "video"], sourceType: ["album", "camera"] }); const chosen = normalizeChosenFiles((result.tempFiles || []) as never[]); if (!chosen.length) { return; } const merged = appendRepairAttachments(attachments, chosen); setAttachments(merged.attachments); if (merged.errorMessage) { showToast(merged.errorMessage); } } catch (error) { const message = error instanceof Error ? error.message : ""; if (message.includes("cancel")) { return; } showToast("上传失败,请重试"); } }; const handlePreviewAttachment = (attachment: RepairAttachment) => { if (attachment.kind === "image") { Taro.previewImage({ current: attachment.path, urls: attachments.filter((item) => item.kind === "image").map((item) => item.path) }); return; } const previewMedia = (Taro as unknown as { previewMedia?: (options: { current?: number; sources: Array<{ url: string; type: "image" | "video"; poster?: string }>; }) => Promise; }).previewMedia; if (typeof previewMedia === "function") { void previewMedia({ current: 0, sources: [ { url: attachment.path, type: "video", poster: attachment.thumbPath } ] }); return; } showToast("当前环境暂不支持视频预览"); }; const handleDeleteAttachment = (attachmentId: string, event: { stopPropagation?: () => void }) => { event.stopPropagation?.(); setAttachments((prev) => prev.filter((item) => item.id !== attachmentId)); }; const handleSubmit = async () => { const errorMessage = validateRepairForm({ selectedDeviceId, description, contactName, phone }); if (errorMessage) { showToast(errorMessage); return; } if (!selectedDevice) { showToast("请选择设备"); return; } const payload: RepairSubmissionSnapshot = { ticketNo: createTicketNo(), deviceType, deviceTypeLabel: REPAIR_DEVICE_TYPE_LABELS[deviceType], deviceId: selectedDevice.id, deviceParams: selectedDevice.params, description: description.trim(), attachments, contactName: contactName.trim(), phone: phone.trim(), createdAt: new Date().toLocaleString("zh-CN", { hour12: false }), statusLabel: "已提交,待审核" }; setSubmitting(true); try { await delay(800); Taro.setStorageSync(REPAIR_DRAFT_STORAGE_KEY, payload); await Taro.showToast({ title: "提交成功", icon: "success" }); await Taro.navigateTo({ url: "/pages/repair-detail/index" }); } catch { showToast("提交失败,请稍后重试"); } finally { setSubmitting(false); } }; return ( showToast("历史记录功能待开放")}> 历史记录 {deviceTypeOrder.map((item) => ( handleTypeChange(item)} > {REPAIR_DEVICE_TYPE_LABELS[item]} ))} 设备ID {selectedDevice?.label || "请选择设备"} 设备参数 {selectedDevice?.params || "--"}