更新时间
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
@@ -6,134 +6,79 @@ import { Badge } from "../ui/badge";
|
|||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog";
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog";
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||||
import { Search, Eye, Download, FileText, CheckCircle, User, Building } from "lucide-react";
|
import { Search, Eye, Download, FileText, CheckCircle, User, Building, ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
import { apiGet } from "../../lib/services/api";
|
||||||
|
|
||||||
interface ArchivedWorkOrder {
|
interface ArchivedWorkOrder {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
workOrderNumber: string;
|
||||||
merchant: string;
|
workOrderType: string;
|
||||||
equipment: string;
|
merchantName: string;
|
||||||
worker: string;
|
equipmentName: string;
|
||||||
dealer: string;
|
workerName: string;
|
||||||
completedDate: string;
|
priority: string;
|
||||||
archiveDate: string;
|
completedDate: string | null;
|
||||||
status: "completed";
|
createdDate: string;
|
||||||
priority: "high" | "medium" | "low";
|
status: string;
|
||||||
signatures: {
|
createdAt: string;
|
||||||
worker: {
|
updatedAt: string;
|
||||||
name: string;
|
merchantAddress: string;
|
||||||
signature: string;
|
responsiblePerson: string;
|
||||||
timestamp: string;
|
responsibleVirtualPhone: string;
|
||||||
photos: string[];
|
workerVirtualPhone: string;
|
||||||
};
|
frontImg: string;
|
||||||
merchant: {
|
openImg: string;
|
||||||
name: string;
|
ropeReImg: string;
|
||||||
signature: string;
|
hostReImg: string;
|
||||||
timestamp: string;
|
otherImg: string;
|
||||||
};
|
repairImg: string;
|
||||||
dealerAdmin: {
|
repairVideo: string;
|
||||||
name: string;
|
needRepair: boolean;
|
||||||
signature: string;
|
equNormal: boolean;
|
||||||
timestamp: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
workDetails: {
|
|
||||||
description: string;
|
|
||||||
beforePhotos: string[];
|
|
||||||
afterPhotos: string[];
|
|
||||||
materials: string[];
|
|
||||||
notes: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function WorkOrderArchivePage() {
|
export default function WorkOrderArchivePage() {
|
||||||
const [archivedOrders, setArchivedOrders] = useState<ArchivedWorkOrder[]>([
|
const [archivedOrders, setArchivedOrders] = useState<ArchivedWorkOrder[]>([]);
|
||||||
{
|
|
||||||
id: "WO-2024-001",
|
|
||||||
title: "干粉灭火器年检",
|
|
||||||
merchant: "星巴克咖啡店",
|
|
||||||
equipment: "干粉灭火器-001",
|
|
||||||
worker: "张师傅",
|
|
||||||
dealer: "华东经销商",
|
|
||||||
completedDate: "2024-01-15",
|
|
||||||
archiveDate: "2024-01-16",
|
|
||||||
status: "completed",
|
|
||||||
priority: "medium",
|
|
||||||
signatures: {
|
|
||||||
worker: {
|
|
||||||
name: "张师傅",
|
|
||||||
signature: "/placeholder.svg?height=100&width=200",
|
|
||||||
timestamp: "2024-01-15 14:30:00",
|
|
||||||
photos: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
|
|
||||||
},
|
|
||||||
merchant: {
|
|
||||||
name: "李经理",
|
|
||||||
signature: "/placeholder.svg?height=100&width=200",
|
|
||||||
timestamp: "2024-01-15 15:00:00",
|
|
||||||
},
|
|
||||||
dealerAdmin: {
|
|
||||||
name: "王主管",
|
|
||||||
signature: "/placeholder.svg?height=100&width=200",
|
|
||||||
timestamp: "2024-01-15 16:00:00",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
workDetails: {
|
|
||||||
description: "对干粉灭火器进行年度检测,检查压力表、安全销、喷嘴等部件",
|
|
||||||
beforePhotos: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
|
|
||||||
afterPhotos: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
|
|
||||||
materials: ["压力表", "安全销", "检测标签"],
|
|
||||||
notes: "设备状态良好,已更换压力表,贴上检测合格标签",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "WO-2024-002",
|
|
||||||
title: "烟感器故障维修",
|
|
||||||
merchant: "麦当劳餐厅",
|
|
||||||
equipment: "烟感器-025",
|
|
||||||
worker: "李师傅",
|
|
||||||
dealer: "华南经销商",
|
|
||||||
completedDate: "2024-01-12",
|
|
||||||
archiveDate: "2024-01-13",
|
|
||||||
status: "completed",
|
|
||||||
priority: "high",
|
|
||||||
signatures: {
|
|
||||||
worker: {
|
|
||||||
name: "李师傅",
|
|
||||||
signature: "/placeholder.svg?height=100&width=200",
|
|
||||||
timestamp: "2024-01-12 11:45:00",
|
|
||||||
photos: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
|
|
||||||
},
|
|
||||||
merchant: {
|
|
||||||
name: "陈店长",
|
|
||||||
signature: "/placeholder.svg?height=100&width=200",
|
|
||||||
timestamp: "2024-01-12 12:15:00",
|
|
||||||
},
|
|
||||||
dealerAdmin: {
|
|
||||||
name: "赵经理",
|
|
||||||
signature: "/placeholder.svg?height=100&width=200",
|
|
||||||
timestamp: "2024-01-12 13:00:00",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
workDetails: {
|
|
||||||
description: "烟感器报警异常,需要更换传感器模块",
|
|
||||||
beforePhotos: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
|
|
||||||
afterPhotos: ["/placeholder.svg?height=300&width=400", "/placeholder.svg?height=300&width=400"],
|
|
||||||
materials: ["传感器模块", "电池", "固定螺丝"],
|
|
||||||
notes: "已更换传感器模块,测试正常,设备恢复正常工作",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const [statusFilter, setStatusFilter] = useState("all");
|
const [statusFilter, setStatusFilter] = useState("all");
|
||||||
const [selectedOrder, setSelectedOrder] = useState<ArchivedWorkOrder | null>(null);
|
const [selectedOrder, setSelectedOrder] = useState<ArchivedWorkOrder | null>(null);
|
||||||
const [isDetailDialogOpen, setIsDetailDialogOpen] = useState(false);
|
const [isDetailDialogOpen, setIsDetailDialogOpen] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [pagination, setPagination] = useState({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取归档工单列表
|
||||||
|
const fetchArchivedOrders = async (pageNum = 1, pageSize = 10) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const response = await apiGet(`/client/work/list?queryStaus=6&pageNum=${pageNum}&pageSize=${pageSize}`);
|
||||||
|
if (response.code === 200) {
|
||||||
|
setArchivedOrders(response.data || []);
|
||||||
|
setPagination({
|
||||||
|
pageNum,
|
||||||
|
pageSize,
|
||||||
|
total: parseInt(response.total) || 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取归档工单列表失败:', error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchArchivedOrders();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filteredOrders = archivedOrders.filter((order) => {
|
const filteredOrders = archivedOrders.filter((order) => {
|
||||||
const matchesSearch =
|
const matchesSearch =
|
||||||
order.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
order.workOrderType.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
order.merchant.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
order.merchantName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
order.id.toLowerCase().includes(searchTerm.toLowerCase());
|
order.workOrderNumber.toLowerCase().includes(searchTerm.toLowerCase());
|
||||||
const matchesStatus = statusFilter === "all" || order.status === statusFilter;
|
const matchesStatus = statusFilter === "all" || order.status === statusFilter;
|
||||||
return matchesSearch && matchesStatus;
|
return matchesSearch && matchesStatus;
|
||||||
});
|
});
|
||||||
@@ -145,11 +90,11 @@ export default function WorkOrderArchivePage() {
|
|||||||
|
|
||||||
const getPriorityColor = (priority: string) => {
|
const getPriorityColor = (priority: string) => {
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
case "high":
|
case "1":
|
||||||
return "bg-red-100 text-red-800";
|
return "bg-red-100 text-red-800";
|
||||||
case "medium":
|
case "2":
|
||||||
return "bg-yellow-100 text-yellow-800";
|
return "bg-yellow-100 text-yellow-800";
|
||||||
case "low":
|
case "3":
|
||||||
return "bg-green-100 text-green-800";
|
return "bg-green-100 text-green-800";
|
||||||
default:
|
default:
|
||||||
return "bg-gray-100 text-gray-800";
|
return "bg-gray-100 text-gray-800";
|
||||||
@@ -158,11 +103,11 @@ export default function WorkOrderArchivePage() {
|
|||||||
|
|
||||||
const getPriorityText = (priority: string) => {
|
const getPriorityText = (priority: string) => {
|
||||||
switch (priority) {
|
switch (priority) {
|
||||||
case "high":
|
case "1":
|
||||||
return "高";
|
return "高";
|
||||||
case "medium":
|
case "2":
|
||||||
return "中";
|
return "中";
|
||||||
case "low":
|
case "3":
|
||||||
return "低";
|
return "低";
|
||||||
default:
|
default:
|
||||||
return "未知";
|
return "未知";
|
||||||
@@ -190,7 +135,7 @@ export default function WorkOrderArchivePage() {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-600">归档总数</p>
|
<p className="text-sm font-medium text-gray-600">归档总数</p>
|
||||||
<p className="text-3xl font-bold">1,248</p>
|
<p className="text-3xl font-bold">{pagination.total}</p>
|
||||||
</div>
|
</div>
|
||||||
<FileText className="h-8 w-8 text-blue-500" />
|
<FileText className="h-8 w-8 text-blue-500" />
|
||||||
</div>
|
</div>
|
||||||
@@ -201,8 +146,8 @@ export default function WorkOrderArchivePage() {
|
|||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-600">本月归档</p>
|
<p className="text-sm font-medium text-gray-600">当前页</p>
|
||||||
<p className="text-3xl font-bold">156</p>
|
<p className="text-3xl font-bold">{archivedOrders.length}</p>
|
||||||
</div>
|
</div>
|
||||||
<CheckCircle className="h-8 w-8 text-green-500" />
|
<CheckCircle className="h-8 w-8 text-green-500" />
|
||||||
</div>
|
</div>
|
||||||
@@ -213,8 +158,8 @@ export default function WorkOrderArchivePage() {
|
|||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-600">完整签字</p>
|
<p className="text-sm font-medium text-gray-600">页码</p>
|
||||||
<p className="text-3xl font-bold">98.5%</p>
|
<p className="text-3xl font-bold">{pagination.pageNum}/{Math.ceil(pagination.total / pagination.pageSize)}</p>
|
||||||
</div>
|
</div>
|
||||||
<User className="h-8 w-8 text-purple-500" />
|
<User className="h-8 w-8 text-purple-500" />
|
||||||
</div>
|
</div>
|
||||||
@@ -225,8 +170,8 @@ export default function WorkOrderArchivePage() {
|
|||||||
<CardContent className="p-6">
|
<CardContent className="p-6">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-gray-600">存储容量</p>
|
<p className="text-sm font-medium text-gray-600">每页数量</p>
|
||||||
<p className="text-3xl font-bold">2.4GB</p>
|
<p className="text-3xl font-bold">{pagination.pageSize}</p>
|
||||||
</div>
|
</div>
|
||||||
<Building className="h-8 w-8 text-orange-500" />
|
<Building className="h-8 w-8 text-orange-500" />
|
||||||
</div>
|
</div>
|
||||||
@@ -279,37 +224,78 @@ export default function WorkOrderArchivePage() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{filteredOrders.map((order) => (
|
{loading ? (
|
||||||
<TableRow key={order.id}>
|
<TableRow>
|
||||||
<TableCell className="font-medium">{order.id}</TableCell>
|
<TableCell colSpan={9} className="text-center py-8">
|
||||||
<TableCell>{order.title}</TableCell>
|
<div className="text-gray-500">加载中...</div>
|
||||||
<TableCell>{order.merchant}</TableCell>
|
|
||||||
<TableCell>{order.equipment}</TableCell>
|
|
||||||
<TableCell>{order.worker}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<Badge className={getPriorityColor(order.priority)}>{getPriorityText(order.priority)}</Badge>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>{order.completedDate}</TableCell>
|
|
||||||
<TableCell>{order.archiveDate}</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
<Button variant="outline" size="sm" onClick={() => openDetailDialog(order)}>
|
|
||||||
<Eye className="h-4 w-4 mr-1" />
|
|
||||||
查看详情
|
|
||||||
</Button>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
) : filteredOrders.length === 0 ? (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={9} className="text-center py-8">
|
||||||
|
<div className="text-gray-500">暂无数据</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : (
|
||||||
|
filteredOrders.map((order) => (
|
||||||
|
<TableRow key={order.id}>
|
||||||
|
<TableCell className="font-medium">{order.workOrderNumber}</TableCell>
|
||||||
|
<TableCell>{order.workOrderType}</TableCell>
|
||||||
|
<TableCell>{order.merchantName}</TableCell>
|
||||||
|
<TableCell>{order.equipmentName}</TableCell>
|
||||||
|
<TableCell>{order.workerName}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge className={getPriorityColor(order.priority)}>{getPriorityText(order.priority)}</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{order.updatedAt}</TableCell>
|
||||||
|
<TableCell>{order.updatedAt}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button variant="outline" size="sm" onClick={() => openDetailDialog(order)}>
|
||||||
|
<Eye className="h-4 w-4 mr-1" />
|
||||||
|
查看详情
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
|
{/* Pagination */}
|
||||||
|
<div className="flex items-center justify-between mt-4">
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
共 {pagination.total} 条记录,当前第 {pagination.pageNum} 页,共 {Math.ceil(pagination.total / pagination.pageSize)} 页
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => fetchArchivedOrders(pagination.pageNum - 1, pagination.pageSize)}
|
||||||
|
disabled={pagination.pageNum === 1 || loading}
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-4 w-4" />
|
||||||
|
上一页
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => fetchArchivedOrders(pagination.pageNum + 1, pagination.pageSize)}
|
||||||
|
disabled={pagination.pageNum >= Math.ceil(pagination.total / pagination.pageSize) || loading}
|
||||||
|
>
|
||||||
|
下一页
|
||||||
|
<ChevronRight className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Detail Dialog */}
|
{/* Detail Dialog */}
|
||||||
<Dialog open={isDetailDialogOpen} onOpenChange={setIsDetailDialogOpen}>
|
<Dialog open={isDetailDialogOpen} onOpenChange={setIsDetailDialogOpen}>
|
||||||
<DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
|
<DialogContent className="max-w-7xl sm:max-w-7xl max-h-[90vh] overflow-y-auto w-[95vw]">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>工单归档详情 - {selectedOrder?.id}</DialogTitle>
|
<DialogTitle>工单归档详情 - {selectedOrder?.workOrderNumber}</DialogTitle>
|
||||||
<DialogDescription>查看完整的工单执行记录和签字确认</DialogDescription>
|
<DialogDescription>查看完整的工单执行记录</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
{selectedOrder && (
|
{selectedOrder && (
|
||||||
@@ -322,49 +308,40 @@ export default function WorkOrderArchivePage() {
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600">工单标题</p>
|
<p className="text-sm text-gray-600">工单编号</p>
|
||||||
<p className="font-medium">{selectedOrder.title}</p>
|
<p className="font-medium">{selectedOrder.workOrderNumber}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600">工单类型</p>
|
||||||
|
<p className="font-medium">{selectedOrder.workOrderType}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600">商户名称</p>
|
<p className="text-sm text-gray-600">商户名称</p>
|
||||||
<p className="font-medium">{selectedOrder.merchant}</p>
|
<p className="font-medium">{selectedOrder.merchantName}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600">设备信息</p>
|
<p className="text-sm text-gray-600">设备信息</p>
|
||||||
<p className="font-medium">{selectedOrder.equipment}</p>
|
<p className="font-medium">{selectedOrder.equipmentName}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600">经销商</p>
|
<p className="text-sm text-gray-600">维修工人</p>
|
||||||
<p className="font-medium">{selectedOrder.dealer}</p>
|
<p className="font-medium">{selectedOrder.workerName}</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
{/* Work Details */}
|
|
||||||
<Card>
|
|
||||||
<CardHeader>
|
|
||||||
<CardTitle className="text-lg">作业详情</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent>
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<p className="text-sm text-gray-600">作业描述</p>
|
|
||||||
<p className="font-medium">{selectedOrder.workDetails.description}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600">使用材料</p>
|
<p className="text-sm text-gray-600">优先级</p>
|
||||||
<div className="flex flex-wrap gap-2 mt-1">
|
<Badge className={getPriorityColor(selectedOrder.priority)}>{getPriorityText(selectedOrder.priority)}</Badge>
|
||||||
{selectedOrder.workDetails.materials.map((material, index) => (
|
|
||||||
<Badge key={index} variant="outline">
|
|
||||||
{material}
|
|
||||||
</Badge>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-gray-600">作业备注</p>
|
<p className="text-sm text-gray-600">负责人</p>
|
||||||
<p className="font-medium">{selectedOrder.workDetails.notes}</p>
|
<p className="font-medium">{selectedOrder.responsiblePerson}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600">联系电话</p>
|
||||||
|
<p className="font-medium">{selectedOrder.responsibleVirtualPhone}</p>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2">
|
||||||
|
<p className="text-sm text-gray-600">地址</p>
|
||||||
|
<p className="font-medium">{selectedOrder.merchantAddress}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -376,90 +353,127 @@ export default function WorkOrderArchivePage() {
|
|||||||
<CardTitle className="text-lg">作业照片</CardTitle>
|
<CardTitle className="text-lg">作业照片</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-2 gap-6">
|
<div className="space-y-4">
|
||||||
<div>
|
{selectedOrder.frontImg && (
|
||||||
<p className="text-sm text-gray-600 mb-2">作业前照片</p>
|
<div>
|
||||||
<div className="grid grid-cols-2 gap-2">
|
<p className="text-sm text-gray-600 mb-2">正面照</p>
|
||||||
{selectedOrder.workDetails.beforePhotos.map((photo, index) => (
|
<div className="grid grid-cols-4 gap-2">
|
||||||
<img
|
{selectedOrder.frontImg.split(',').filter(url => url.trim()).map((photo, index) => (
|
||||||
key={index}
|
<img
|
||||||
src={photo || "/placeholder.svg"}
|
key={index}
|
||||||
alt={`作业前照片 ${index + 1}`}
|
src={photo || "/placeholder.svg"}
|
||||||
className="w-full h-32 object-cover rounded border"
|
alt={`正面照 ${index + 1}`}
|
||||||
/>
|
className="w-full h-32 object-cover rounded border"
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
<div>
|
{selectedOrder.openImg && (
|
||||||
<p className="text-sm text-gray-600 mb-2">作业后照片</p>
|
<div>
|
||||||
<div className="grid grid-cols-2 gap-2">
|
<p className="text-sm text-gray-600 mb-2">开箱照</p>
|
||||||
{selectedOrder.workDetails.afterPhotos.map((photo, index) => (
|
<div className="grid grid-cols-4 gap-2">
|
||||||
<img
|
{selectedOrder.openImg.split(',').filter(url => url.trim()).map((photo, index) => (
|
||||||
key={index}
|
<img
|
||||||
src={photo || "/placeholder.svg"}
|
key={index}
|
||||||
alt={`作业后照片 ${index + 1}`}
|
src={photo || "/placeholder.svg"}
|
||||||
className="w-full h-32 object-cover rounded border"
|
alt={`开箱照 ${index + 1}`}
|
||||||
/>
|
className="w-full h-32 object-cover rounded border"
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
|
{selectedOrder.ropeReImg && (
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600 mb-2">绳索恢复照</p>
|
||||||
|
<div className="grid grid-cols-4 gap-2">
|
||||||
|
{selectedOrder.ropeReImg.split(',').filter(url => url.trim()).map((photo, index) => (
|
||||||
|
<img
|
||||||
|
key={index}
|
||||||
|
src={photo || "/placeholder.svg"}
|
||||||
|
alt={`绳索恢复 ${index + 1}`}
|
||||||
|
className="w-full h-32 object-cover rounded border"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{selectedOrder.hostReImg && (
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600 mb-2">主机恢复照</p>
|
||||||
|
<div className="grid grid-cols-4 gap-2">
|
||||||
|
{selectedOrder.hostReImg.split(',').filter(url => url.trim()).map((photo, index) => (
|
||||||
|
<img
|
||||||
|
key={index}
|
||||||
|
src={photo || "/placeholder.svg"}
|
||||||
|
alt={`主机恢复 ${index + 1}`}
|
||||||
|
className="w-full h-32 object-cover rounded border"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{selectedOrder.otherImg && (
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600 mb-2">其他照片</p>
|
||||||
|
<div className="grid grid-cols-4 gap-2">
|
||||||
|
{selectedOrder.otherImg.split(',').filter(url => url.trim()).map((photo, index) => (
|
||||||
|
<img
|
||||||
|
key={index}
|
||||||
|
src={photo || "/placeholder.svg"}
|
||||||
|
alt={`其他照片 ${index + 1}`}
|
||||||
|
className="w-full h-32 object-cover rounded border"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{selectedOrder.repairImg && (
|
||||||
|
<div>
|
||||||
|
<p className="text-sm text-gray-600 mb-2">维修照片</p>
|
||||||
|
<div className="grid grid-cols-4 gap-2">
|
||||||
|
{selectedOrder.repairImg.split(',').filter(url => url.trim()).map((photo, index) => (
|
||||||
|
<img
|
||||||
|
key={index}
|
||||||
|
src={photo || "/placeholder.svg"}
|
||||||
|
alt={`维修照片 ${index + 1}`}
|
||||||
|
className="w-full h-32 object-cover rounded border"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Signatures */}
|
{/* Status Info */}
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="text-lg">签字确认</CardTitle>
|
<CardTitle className="text-lg">状态信息</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
{/* Worker Signature */}
|
<div>
|
||||||
<div className="space-y-3">
|
<p className="text-sm text-gray-600">是否需要维修</p>
|
||||||
<h4 className="font-medium text-green-700">维修工人确认</h4>
|
<Badge variant={selectedOrder.needRepair ? "destructive" : "outline"}>
|
||||||
<div className="border rounded p-3">
|
{selectedOrder.needRepair ? "需要维修" : "无需维修"}
|
||||||
<p className="text-sm text-gray-600">签字人:{selectedOrder.signatures.worker.name}</p>
|
</Badge>
|
||||||
<p className="text-sm text-gray-600">时间:{selectedOrder.signatures.worker.timestamp}</p>
|
|
||||||
<div className="mt-2">
|
|
||||||
<img
|
|
||||||
src={selectedOrder.signatures.worker.signature || "/placeholder.svg"}
|
|
||||||
alt="工人签字"
|
|
||||||
className="w-full h-16 object-contain border rounded"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
{/* Merchant Signature */}
|
<p className="text-sm text-gray-600">设备是否正常</p>
|
||||||
<div className="space-y-3">
|
<Badge variant={selectedOrder.equNormal ? "default" : "destructive"}>
|
||||||
<h4 className="font-medium text-blue-700">商户负责人验收</h4>
|
{selectedOrder.equNormal ? "正常" : "异常"}
|
||||||
<div className="border rounded p-3">
|
</Badge>
|
||||||
<p className="text-sm text-gray-600">签字人:{selectedOrder.signatures.merchant.name}</p>
|
|
||||||
<p className="text-sm text-gray-600">时间:{selectedOrder.signatures.merchant.timestamp}</p>
|
|
||||||
<div className="mt-2">
|
|
||||||
<img
|
|
||||||
src={selectedOrder.signatures.merchant.signature || "/placeholder.svg"}
|
|
||||||
alt="商户签字"
|
|
||||||
className="w-full h-16 object-contain border rounded"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
{/* Dealer Admin Signature */}
|
<p className="text-sm text-gray-600">创建时间</p>
|
||||||
<div className="space-y-3">
|
<p className="font-medium">{selectedOrder.createdAt}</p>
|
||||||
<h4 className="font-medium text-purple-700">经销商管理员确认</h4>
|
</div>
|
||||||
<div className="border rounded p-3">
|
<div>
|
||||||
<p className="text-sm text-gray-600">签字人:{selectedOrder.signatures.dealerAdmin.name}</p>
|
<p className="text-sm text-gray-600">更新时间</p>
|
||||||
<p className="text-sm text-gray-600">时间:{selectedOrder.signatures.dealerAdmin.timestamp}</p>
|
<p className="font-medium">{selectedOrder.updatedAt}</p>
|
||||||
<div className="mt-2">
|
|
||||||
<img
|
|
||||||
src={selectedOrder.signatures.dealerAdmin.signature || "/placeholder.svg"}
|
|
||||||
alt="经销商管理员签字"
|
|
||||||
className="w-full h-16 object-contain border rounded"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
Reference in New Issue
Block a user