shebi xiufu
This commit is contained in:
@@ -16,7 +16,7 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "../ui/dialog"
|
} from "../ui/dialog"
|
||||||
import { Plus, Filter, Download, MapPin, Calendar, Shield, ChevronLeft, ChevronRight } from "lucide-react"
|
import { Plus, Filter, Download, MapPin, Calendar, Shield, ChevronLeft, ChevronRight } from "lucide-react"
|
||||||
import { apiGet, apiPost } from "../../lib/services/api"
|
import { apiGet, apiPost, apiPut } from "../../lib/services/api"
|
||||||
|
|
||||||
// 商户数据类型(根据新接口返回格式定义)
|
// 商户数据类型(根据新接口返回格式定义)
|
||||||
interface ProvinceMerchant {
|
interface ProvinceMerchant {
|
||||||
@@ -70,6 +70,7 @@ export default function EquipmentPage() {
|
|||||||
const [searchTerm, setSearchTerm] = useState("")
|
const [searchTerm, setSearchTerm] = useState("")
|
||||||
const [statusFilter, setStatusFilter] = useState("all")
|
const [statusFilter, setStatusFilter] = useState("all")
|
||||||
const [isAddEquipmentOpen, setIsAddEquipmentOpen] = useState(false)
|
const [isAddEquipmentOpen, setIsAddEquipmentOpen] = useState(false)
|
||||||
|
const [isEditEquipmentOpen, setIsEditEquipmentOpen] = useState(false)
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||||
const [merchants, setMerchants] = useState<ProvinceMerchant[]>([])
|
const [merchants, setMerchants] = useState<ProvinceMerchant[]>([])
|
||||||
const [loadingMerchants, setLoadingMerchants] = useState(false)
|
const [loadingMerchants, setLoadingMerchants] = useState(false)
|
||||||
@@ -179,6 +180,84 @@ export default function EquipmentPage() {
|
|||||||
notes: "",
|
notes: "",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [editEquipment, setEditEquipment] = useState({
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
type: "",
|
||||||
|
model: "",
|
||||||
|
merchantId: "",
|
||||||
|
location: "",
|
||||||
|
installDate: "",
|
||||||
|
status: "normal",
|
||||||
|
notes: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
// 打开编辑对话框
|
||||||
|
const handleEditEquipment = (equipment: Equipment) => {
|
||||||
|
setEditEquipment({
|
||||||
|
id: equipment.id,
|
||||||
|
name: equipment.equipmentName || "",
|
||||||
|
type: equipment.equipmentType || "",
|
||||||
|
model: equipment.equipmentModel || "",
|
||||||
|
merchantId: equipment.merchantId || "",
|
||||||
|
location: equipment.installationLocation || "",
|
||||||
|
installDate: equipment.installationDate || "",
|
||||||
|
status: equipment.status === "1" ? "normal" : equipment.status === "2" ? "expiring" : "expired",
|
||||||
|
notes: equipment.remarks || "",
|
||||||
|
})
|
||||||
|
setIsEditEquipmentOpen(true)
|
||||||
|
// 加载商户和设备类型数据
|
||||||
|
if (merchants.length === 0) {
|
||||||
|
fetchMerchants()
|
||||||
|
}
|
||||||
|
if (Object.keys(equipmentTypes).length === 0) {
|
||||||
|
fetchEquipmentTypes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交编辑
|
||||||
|
const handleUpdateEquipment = async () => {
|
||||||
|
if (!editEquipment.name || !editEquipment.type || !editEquipment.merchantId) {
|
||||||
|
alert('请填写必填信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsSubmitting(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const equipmentData = {
|
||||||
|
id: editEquipment.id,
|
||||||
|
equipmentName: editEquipment.name,
|
||||||
|
equipmentType: editEquipment.type,
|
||||||
|
equipmentModel: editEquipment.model,
|
||||||
|
merchantId: editEquipment.merchantId,
|
||||||
|
installationLocation: editEquipment.location,
|
||||||
|
installationDate: editEquipment.installDate,
|
||||||
|
status: editEquipment.status === 'normal' ? 1 : editEquipment.status === 'expiring' ? 2 : 3,
|
||||||
|
remarks: editEquipment.notes,
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("编辑设备:", equipmentData)
|
||||||
|
|
||||||
|
const result = await apiPut('/back/equipment/', equipmentData)
|
||||||
|
|
||||||
|
if (result.code === 200) {
|
||||||
|
console.log('编辑设备成功:', result)
|
||||||
|
alert('编辑设备成功!')
|
||||||
|
setIsEditEquipmentOpen(false)
|
||||||
|
fetchEquipmentList(pagination.pageNum, pagination.pageSize)
|
||||||
|
} else {
|
||||||
|
console.error('编辑设备失败:', result)
|
||||||
|
alert('编辑设备失败:' + (result.msg || '未知错误'))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('编辑设备请求失败:', error)
|
||||||
|
alert('网络错误,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleAddEquipment = async () => {
|
const handleAddEquipment = async () => {
|
||||||
if (!newEquipment.name || !newEquipment.type || !newEquipment.merchantId) {
|
if (!newEquipment.name || !newEquipment.type || !newEquipment.merchantId) {
|
||||||
alert('请填写必填信息')
|
alert('请填写必填信息')
|
||||||
@@ -273,7 +352,17 @@ export default function EquipmentPage() {
|
|||||||
item.equipmentName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
item.equipmentName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
merchantInfo.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
merchantInfo.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
merchantInfo.mall.toLowerCase().includes(searchTerm.toLowerCase())
|
merchantInfo.mall.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
const matchesStatus = statusFilter === "all" || item.status === statusFilter
|
|
||||||
|
// 修正状态筛选逻辑
|
||||||
|
let matchesStatus = true
|
||||||
|
if (statusFilter === "1" || statusFilter === "normal") {
|
||||||
|
matchesStatus = item.status === "1"
|
||||||
|
} else if (statusFilter === "2" || statusFilter === "expiring") {
|
||||||
|
matchesStatus = item.status === "2"
|
||||||
|
} else if (statusFilter === "3" || statusFilter === "expired") {
|
||||||
|
matchesStatus = item.status === "3"
|
||||||
|
}
|
||||||
|
|
||||||
return matchesSearch && matchesStatus
|
return matchesSearch && matchesStatus
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -285,10 +374,18 @@ export default function EquipmentPage() {
|
|||||||
<p className="text-gray-600">管理所有消防设备的档案和状态</p>
|
<p className="text-gray-600">管理所有消防设备的档案和状态</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Button variant="outline">
|
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||||
<Filter className="h-4 w-4 mr-2" />
|
<SelectTrigger className="w-40">
|
||||||
全部状态
|
<Filter className="h-4 w-4 mr-2" />
|
||||||
</Button>
|
<SelectValue placeholder="筛选状态" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="all">全部状态</SelectItem>
|
||||||
|
<SelectItem value="1">正常</SelectItem>
|
||||||
|
<SelectItem value="2">即将到期</SelectItem>
|
||||||
|
<SelectItem value="3">已到期</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
<Button variant="outline">
|
<Button variant="outline">
|
||||||
<Download className="h-4 w-4 mr-2" />
|
<Download className="h-4 w-4 mr-2" />
|
||||||
导出数据
|
导出数据
|
||||||
@@ -441,6 +538,133 @@ export default function EquipmentPage() {
|
|||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
{/* 编辑设备对话框 */}
|
||||||
|
<Dialog open={isEditEquipmentOpen} onOpenChange={setIsEditEquipmentOpen}>
|
||||||
|
<DialogContent className="max-w-2xl">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>编辑设备</DialogTitle>
|
||||||
|
<DialogDescription>修改设备基本信息和安装详情</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-equipmentName">设备名称</Label>
|
||||||
|
<Input
|
||||||
|
id="edit-equipmentName"
|
||||||
|
value={editEquipment.name}
|
||||||
|
onChange={(e) => setEditEquipment({ ...editEquipment, name: e.target.value })}
|
||||||
|
placeholder="请输入设备名称"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-equipmentType">设备类型</Label>
|
||||||
|
<Select
|
||||||
|
value={editEquipment.type}
|
||||||
|
onValueChange={(value) => setEditEquipment({ ...editEquipment, type: value })}
|
||||||
|
disabled={loadingEquipmentTypes}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder={loadingEquipmentTypes ? "加载中..." : "选择设备类型"} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{Object.entries(equipmentTypes).map(([key, value]) => (
|
||||||
|
<SelectItem key={key} value={key}>
|
||||||
|
{value}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-model">设备型号</Label>
|
||||||
|
<Input
|
||||||
|
id="edit-model"
|
||||||
|
value={editEquipment.model}
|
||||||
|
onChange={(e) => setEditEquipment({ ...editEquipment, model: e.target.value })}
|
||||||
|
placeholder="请输入设备型号"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-merchant">所属商户</Label>
|
||||||
|
<Select
|
||||||
|
value={editEquipment.merchantId}
|
||||||
|
onValueChange={(value) => setEditEquipment({ ...editEquipment, merchantId: value })}
|
||||||
|
disabled={loadingMerchants}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder={loadingMerchants ? "加载中..." : "选择商户"} />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{merchants.map((merchant) => (
|
||||||
|
<SelectItem key={merchant.id} value={merchant.merchantsId || merchant.id}>
|
||||||
|
{merchant.merchantName}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-location">安装位置</Label>
|
||||||
|
<Input
|
||||||
|
id="edit-location"
|
||||||
|
value={editEquipment.location}
|
||||||
|
onChange={(e) => setEditEquipment({ ...editEquipment, location: e.target.value })}
|
||||||
|
placeholder="请输入安装位置"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-installDate">安装日期</Label>
|
||||||
|
<Input
|
||||||
|
id="edit-installDate"
|
||||||
|
type="date"
|
||||||
|
value={editEquipment.installDate}
|
||||||
|
onChange={(e) => setEditEquipment({ ...editEquipment, installDate: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="edit-status">设备状态</Label>
|
||||||
|
<Select
|
||||||
|
value={editEquipment.status}
|
||||||
|
onValueChange={(value) => setEditEquipment({ ...editEquipment, status: value })}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="选择设备状态" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="normal">正常</SelectItem>
|
||||||
|
<SelectItem value="expiring">即将到期</SelectItem>
|
||||||
|
<SelectItem value="expired">已到期</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-2 space-y-2">
|
||||||
|
<Label htmlFor="edit-notes">备注</Label>
|
||||||
|
<Textarea
|
||||||
|
id="edit-notes"
|
||||||
|
value={editEquipment.notes}
|
||||||
|
onChange={(e) => setEditEquipment({ ...editEquipment, notes: e.target.value })}
|
||||||
|
placeholder="请输入备注信息"
|
||||||
|
rows={3}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end space-x-2 mt-6">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setIsEditEquipmentOpen(false)}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={handleUpdateEquipment}
|
||||||
|
disabled={!editEquipment.name || !editEquipment.type || !editEquipment.merchantId || isSubmitting}
|
||||||
|
>
|
||||||
|
{isSubmitting ? "更新中..." : "更新设备"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -454,6 +678,38 @@ export default function EquipmentPage() {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
|
{/* 筛选区域 */}
|
||||||
|
<div className="flex flex-col sm:flex-row gap-4 mb-6">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="relative">
|
||||||
|
<MapPin className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
|
||||||
|
<Input
|
||||||
|
placeholder="搜索设备名称、商户或商场..."
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
className="pl-10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||||
|
<SelectTrigger className="w-full sm:w-40">
|
||||||
|
<SelectValue placeholder="筛选状态" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="all">全部状态</SelectItem>
|
||||||
|
<SelectItem value="1">正常</SelectItem>
|
||||||
|
<SelectItem value="2">即将到期</SelectItem>
|
||||||
|
<SelectItem value="3">已到期</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Button variant="outline">
|
||||||
|
<Download className="h-4 w-4 mr-2" />
|
||||||
|
导出
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="rounded-md border">
|
<div className="rounded-md border">
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
@@ -526,9 +782,13 @@ export default function EquipmentPage() {
|
|||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="flex items-center justify-center">
|
<div className="flex items-center justify-center space-x-2">
|
||||||
<Button variant="ghost" size="sm">
|
<Button
|
||||||
<span className="text-lg">⋯</span>
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => handleEditEquipment(item)}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
Reference in New Issue
Block a user