shangc
This commit is contained in:
@@ -16,7 +16,7 @@ import {
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog"
|
||||
import { Plus, Download, MapPin, Calendar, Shield, ChevronLeft, ChevronRight, Minus, Plus as PlusIcon, Search } from "lucide-react"
|
||||
import { apiGet, apiPost, apiPut } from "../../lib/services/api"
|
||||
import { apiGet, apiPost, apiPut, apiExportFile } from "../../lib/services/api"
|
||||
|
||||
// 商户数据类型(根据新接口返回格式定义)
|
||||
interface ProvinceMerchant {
|
||||
@@ -98,6 +98,7 @@ export default function EquipmentPage() {
|
||||
const [loadingStats, setLoadingStats] = useState(false)
|
||||
const [merchantSearchForAdd, setMerchantSearchForAdd] = useState("")
|
||||
const [merchantSearchForEdit, setMerchantSearchForEdit] = useState("")
|
||||
const [isExporting, setIsExporting] = useState(false)
|
||||
|
||||
// 获取设备统计数据
|
||||
const fetchEquipmentStats = async () => {
|
||||
@@ -534,6 +535,29 @@ export default function EquipmentPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// 导出设备数据
|
||||
const handleExportEquipment = async () => {
|
||||
setIsExporting(true)
|
||||
try {
|
||||
// 构建导出参数(包含当前搜索条件)
|
||||
const exportParams = {
|
||||
equipmentId: equipmentIdSearch.trim() || undefined,
|
||||
equipmentName: equipmentNameSearch.trim() || undefined,
|
||||
status: statusFilter !== "all" ? statusFilter : undefined,
|
||||
}
|
||||
|
||||
// 调用导出接口
|
||||
await apiExportFile('/back/equipment/export', exportParams, `设备列表_${new Date().toISOString().split('T')[0]}.xlsx`)
|
||||
|
||||
console.log('导出设备数据成功')
|
||||
} catch (error) {
|
||||
console.error('导出设备数据失败:', error)
|
||||
alert('导出失败:' + (error instanceof Error ? error.message : '未知错误'))
|
||||
} finally {
|
||||
setIsExporting(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 直接使用从API返回的数据,不再进行前端过滤
|
||||
const filteredEquipment = equipmentList
|
||||
|
||||
@@ -1228,9 +1252,14 @@ export default function EquipmentPage() {
|
||||
<SelectItem value="3">已到期</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" className="w-full sm:w-auto h-9 sm:h-10 text-sm">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full sm:w-auto h-9 sm:h-10 text-sm"
|
||||
onClick={handleExportEquipment}
|
||||
disabled={isExporting}
|
||||
>
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
导出
|
||||
{isExporting ? "导出中..." : "导出"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
DialogTitle,
|
||||
} from "../ui/dialog"
|
||||
import { Plus, Search, Filter, Download, Store, Eye, Building2, MapPin, ChevronLeft, ChevronRight, Edit } from "lucide-react"
|
||||
import { apiGet, apiPost, apiPut } from "../../lib/services/api"
|
||||
import { apiGet, apiPost, apiPut, apiExportFile } from "../../lib/services/api"
|
||||
|
||||
// 总商户数据类型
|
||||
interface TotalMerchant {
|
||||
@@ -87,6 +87,7 @@ export default function MerchantsPage() {
|
||||
countExpire: 0
|
||||
})
|
||||
const [loadingUserEquipmentCount, setLoadingUserEquipmentCount] = useState(false)
|
||||
const [isExporting, setIsExporting] = useState(false)
|
||||
|
||||
const [newMerchant, setNewMerchant] = useState({
|
||||
name: "",
|
||||
@@ -571,6 +572,30 @@ export default function MerchantsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// 导出商户数据
|
||||
const handleExportMerchants = async () => {
|
||||
setIsExporting(true)
|
||||
try {
|
||||
// 构建导出参数(包含当前搜索条件)
|
||||
const exportParams = {
|
||||
merchantName: merchantNameSearch.trim() || undefined,
|
||||
contactPerson: contactPersonSearch.trim() || undefined,
|
||||
contactPhone: contactPhoneSearch.trim() || undefined,
|
||||
equipmentStatus: statusFilter !== "all" ? statusFilter : undefined,
|
||||
}
|
||||
|
||||
// 调用导出接口
|
||||
await apiExportFile('/back/merchants/export', exportParams, `商户列表_${new Date().toISOString().split('T')[0]}.xlsx`)
|
||||
|
||||
console.log('导出商户数据成功')
|
||||
} catch (error) {
|
||||
console.error('导出商户数据失败:', error)
|
||||
alert('导出失败:' + (error instanceof Error ? error.message : '未知错误'))
|
||||
} finally {
|
||||
setIsExporting(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 提交编辑
|
||||
const handleUpdateMerchant = async () => {
|
||||
if (!editMerchant.name || !editMerchant.contact || !editMerchant.phone) {
|
||||
@@ -740,9 +765,13 @@ export default function MerchantsPage() {
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
<Button variant="outline">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleExportMerchants}
|
||||
disabled={isExporting}
|
||||
>
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
导出
|
||||
{isExporting ? '导出中...' : '导出'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card";
|
||||
import { Button } from "../ui/button";
|
||||
import { Input } from "../ui/input";
|
||||
@@ -47,6 +48,7 @@ interface ArchivedWorkOrder {
|
||||
}
|
||||
|
||||
export default function WorkOrderArchivePage() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [archivedOrders, setArchivedOrders] = useState<ArchivedWorkOrder[]>([]);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [statusFilter, setStatusFilter] = useState("all");
|
||||
@@ -81,14 +83,15 @@ export default function WorkOrderArchivePage() {
|
||||
};
|
||||
|
||||
// 获取归档工单列表
|
||||
const fetchArchivedOrders = async (pageNum = 1, pageSize = 10) => {
|
||||
const fetchArchivedOrders = async (pageNum = 1, pageSize = 10, searchValue?: string) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
let url = `/back/workOrderArchive/list?pageNum=${pageNum}&pageSize=${pageSize}`;
|
||||
|
||||
// 添加工单编号搜索参数
|
||||
if (searchTerm.trim()) {
|
||||
url += `&workOrderNumber=${encodeURIComponent(searchTerm.trim())}`;
|
||||
// 添加工单编号搜索参数,优先使用传入的搜索值,否则使用 state 中的 searchTerm
|
||||
const searchValueToUse = searchValue !== undefined ? searchValue : searchTerm;
|
||||
if (searchValueToUse.trim()) {
|
||||
url += `&workOrderNumber=${encodeURIComponent(searchValueToUse.trim())}`;
|
||||
}
|
||||
|
||||
// 添加合格/不合格筛选参数
|
||||
@@ -112,9 +115,25 @@ export default function WorkOrderArchivePage() {
|
||||
}
|
||||
};
|
||||
|
||||
// 从 URL 参数中读取工单号并设置搜索词
|
||||
useEffect(() => {
|
||||
const workOrderNumber = searchParams.get('workOrderNumber');
|
||||
if (workOrderNumber) {
|
||||
setSearchTerm(workOrderNumber);
|
||||
// 立即搜索,不等待防抖
|
||||
fetchArchivedOrders(1, 10, workOrderNumber);
|
||||
// 清除 URL 参数,避免刷新时重复搜索
|
||||
setSearchParams({}, { replace: true });
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchParams]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchArchiveCount();
|
||||
fetchArchivedOrders(1, 10);
|
||||
// 只有在没有 URL 参数时才执行初始加载(避免与上面的 useEffect 重复)
|
||||
if (!searchParams.get('workOrderNumber')) {
|
||||
fetchArchivedOrders(1, 10);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 监听搜索词和筛选条件变化,重新请求数据
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from "react"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
|
||||
import { Button } from "../ui/button"
|
||||
import { Input } from "../ui/input"
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
ChevronRight,
|
||||
Wrench,
|
||||
Edit,
|
||||
FileText,
|
||||
} from "lucide-react"
|
||||
import { apiGet, apiPost, apiPut } from "../../lib/services/api"
|
||||
|
||||
@@ -153,6 +155,7 @@ interface WorkOrder {
|
||||
}
|
||||
|
||||
export default function WorkOrdersPage() {
|
||||
const navigate = useNavigate()
|
||||
const [searchTerm, setSearchTerm] = useState("")
|
||||
const [statusFilter, setStatusFilter] = useState("all")
|
||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false)
|
||||
@@ -502,16 +505,30 @@ export default function WorkOrdersPage() {
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setEditingWorkOrder(item)
|
||||
setIsEditDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setEditingWorkOrder(item)
|
||||
setIsEditDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
{item.status === "7" && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigate(`/admin/workorder-archive?workOrderNumber=${encodeURIComponent(item.workOrderNumber)}`)
|
||||
}}
|
||||
title="查看归档"
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
@@ -540,16 +557,30 @@ export default function WorkOrdersPage() {
|
||||
<div className="text-sm font-medium text-gray-900">{item.equipmentName}</div>
|
||||
<div className="text-xs text-gray-500">设备: {item.equipmentId}</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setEditingWorkOrder(item)
|
||||
setIsEditDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setEditingWorkOrder(item)
|
||||
setIsEditDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
{item.status === "7" && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
navigate(`/admin/workorder-archive?workOrderNumber=${encodeURIComponent(item.workOrderNumber)}`)
|
||||
}}
|
||||
title="查看归档"
|
||||
>
|
||||
<FileText className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-3 space-y-2">
|
||||
|
||||
Reference in New Issue
Block a user