修复 1
This commit is contained in:
@@ -527,7 +527,7 @@ function CreateUserForm({ roles, onClose }: { roles: Role[]; onClose: () => void
|
||||
}))
|
||||
}
|
||||
|
||||
const shouldShowProvinces = formData.role && formData.role !== "admin"
|
||||
const shouldShowProvinces = formData.role && formData.role !== "admin" && formData.role !== "merchant"
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
|
@@ -94,6 +94,7 @@ export default function MallsPage() {
|
||||
const [provinces, setProvinces] = useState<Province[]>([])
|
||||
const [mallUsers, setMallUsers] = useState<MallUser[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [userRole, setUserRole] = useState<string>("")
|
||||
const [newMall, setNewMall] = useState({
|
||||
name: "",
|
||||
address: "",
|
||||
@@ -102,6 +103,18 @@ export default function MallsPage() {
|
||||
description: "",
|
||||
})
|
||||
|
||||
// 获取用户角色
|
||||
const fetchUserRole = async () => {
|
||||
try {
|
||||
const response = await apiGet('/back/getUserRole')
|
||||
if (response.code === 200) {
|
||||
setUserRole(response.data || "")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户角色失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取商场列表
|
||||
const fetchMalls = async () => {
|
||||
try {
|
||||
@@ -160,6 +173,7 @@ export default function MallsPage() {
|
||||
|
||||
// 页面加载时获取数据
|
||||
useEffect(() => {
|
||||
fetchUserRole()
|
||||
fetchProvinces()
|
||||
fetchMalls()
|
||||
}, [])
|
||||
@@ -250,108 +264,110 @@ export default function MallsPage() {
|
||||
<h1 className="text-2xl font-bold text-gray-900">商场管理</h1>
|
||||
<p className="text-gray-600">管理商场信息、查看商户和设备分布</p>
|
||||
</div>
|
||||
<Dialog open={isAddDialogOpen} onOpenChange={setIsAddDialogOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
添加商场
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>添加新商场</DialogTitle>
|
||||
<DialogDescription>填写商场基本信息,选择对应省份和商场账号</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="name">商场名称</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={newMall.name}
|
||||
onChange={(e) => setNewMall({ ...newMall, name: e.target.value })}
|
||||
placeholder="请输入商场名称"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="address">商场地址</Label>
|
||||
<Input
|
||||
id="address"
|
||||
value={newMall.address}
|
||||
onChange={(e) => setNewMall({ ...newMall, address: e.target.value })}
|
||||
placeholder="请输入详细地址"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="province">选择省份</Label>
|
||||
<Select
|
||||
value={newMall.provinceCode}
|
||||
onValueChange={(value) => setNewMall({ ...newMall, provinceCode: value })}
|
||||
disabled={loading}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择省份" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{provinces.map((province) => (
|
||||
<SelectItem key={province.code} value={province.code}>
|
||||
{province.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="mallUser">选择商场</Label>
|
||||
<Select
|
||||
value={newMall.mallUserId}
|
||||
onValueChange={(value) => setNewMall({ ...newMall, mallUserId: value })}
|
||||
disabled={loading || !newMall.provinceCode}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={
|
||||
!newMall.provinceCode
|
||||
? "请先选择省份"
|
||||
: mallUsers.length === 0
|
||||
? "该省份暂无可选商场"
|
||||
: "请选择商场"
|
||||
} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{mallUsers.map((mallUser) => (
|
||||
<SelectItem key={mallUser.userId} value={mallUser.userId}>
|
||||
<div className="flex flex-col items-start">
|
||||
<span>{mallUser.userName}</span>
|
||||
<span className="text-xs text-gray-500">{mallUser.phonenumber}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="description">备注说明</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
value={newMall.description}
|
||||
onChange={(e) => setNewMall({ ...newMall, description: e.target.value })}
|
||||
placeholder="请输入备注信息(可选)"
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setIsAddDialogOpen(false)}>
|
||||
取消
|
||||
{userRole !== "mall" && (
|
||||
<Dialog open={isAddDialogOpen} onOpenChange={setIsAddDialogOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
添加商场
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAddMall}
|
||||
disabled={!newMall.name || !newMall.address || !newMall.provinceCode || !newMall.mallUserId || loading}
|
||||
>
|
||||
{loading ? "加载中..." : "确认添加"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>添加新商场</DialogTitle>
|
||||
<DialogDescription>填写商场基本信息,选择对应省份和商场账号</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="name">商场名称</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={newMall.name}
|
||||
onChange={(e) => setNewMall({ ...newMall, name: e.target.value })}
|
||||
placeholder="请输入商场名称"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="address">商场地址</Label>
|
||||
<Input
|
||||
id="address"
|
||||
value={newMall.address}
|
||||
onChange={(e) => setNewMall({ ...newMall, address: e.target.value })}
|
||||
placeholder="请输入详细地址"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="province">选择省份</Label>
|
||||
<Select
|
||||
value={newMall.provinceCode}
|
||||
onValueChange={(value) => setNewMall({ ...newMall, provinceCode: value })}
|
||||
disabled={loading}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="请选择省份" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{provinces.map((province) => (
|
||||
<SelectItem key={province.code} value={province.code}>
|
||||
{province.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="mallUser">选择商场</Label>
|
||||
<Select
|
||||
value={newMall.mallUserId}
|
||||
onValueChange={(value) => setNewMall({ ...newMall, mallUserId: value })}
|
||||
disabled={loading || !newMall.provinceCode}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={
|
||||
!newMall.provinceCode
|
||||
? "请先选择省份"
|
||||
: mallUsers.length === 0
|
||||
? "该省份暂无可选商场"
|
||||
: "请选择商场"
|
||||
} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{mallUsers.map((mallUser) => (
|
||||
<SelectItem key={mallUser.userId} value={mallUser.userId}>
|
||||
<div className="flex flex-col items-start">
|
||||
<span>{mallUser.userName}</span>
|
||||
<span className="text-xs text-gray-500">{mallUser.phonenumber}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="description">备注说明</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
value={newMall.description}
|
||||
onChange={(e) => setNewMall({ ...newMall, description: e.target.value })}
|
||||
placeholder="请输入备注信息(可选)"
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setIsAddDialogOpen(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAddMall}
|
||||
disabled={!newMall.name || !newMall.address || !newMall.provinceCode || !newMall.mallUserId || loading}
|
||||
>
|
||||
{loading ? "加载中..." : "确认添加"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 统计卡片 */}
|
||||
@@ -451,26 +467,28 @@ export default function MallsPage() {
|
||||
</div>
|
||||
</div>
|
||||
{getStatusBadge(mall.status)}
|
||||
<div className="flex space-x-1">
|
||||
<div
|
||||
className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-9 px-3 cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// 处理编辑逻辑
|
||||
}}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
{userRole !== "mall" && (
|
||||
<div className="flex space-x-1">
|
||||
<div
|
||||
className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-9 px-3 cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// 处理编辑逻辑
|
||||
}}
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</div>
|
||||
<div
|
||||
className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-9 px-3 cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// 处理删除逻辑
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-9 px-3 cursor-pointer"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// 处理删除逻辑
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{expandedMalls.includes(mall.id) && (
|
||||
|
@@ -63,6 +63,7 @@ export default function MerchantsPage() {
|
||||
const [isAddMerchantOpen, setIsAddMerchantOpen] = useState(false)
|
||||
const [isAddEquipmentOpen, setIsAddEquipmentOpen] = useState(false)
|
||||
const [selectedMerchant, setSelectedMerchant] = useState<any>(null)
|
||||
const [isEquipmentDialogOpen, setIsEquipmentDialogOpen] = useState(false)
|
||||
const [malls, setMalls] = useState<any[]>([])
|
||||
const [loadingMalls, setLoadingMalls] = useState(false)
|
||||
const [totalMerchants, setTotalMerchants] = useState<TotalMerchant[]>([])
|
||||
@@ -74,6 +75,7 @@ export default function MerchantsPage() {
|
||||
const [total, setTotal] = useState(0)
|
||||
const [merchantEquipments, setMerchantEquipments] = useState<{[key: string]: any[]}>({})
|
||||
const [loadingMerchantEquipments, setLoadingMerchantEquipments] = useState<{[key: string]: boolean}>({})
|
||||
const [userRole, setUserRole] = useState<string>("")
|
||||
|
||||
const [newMerchant, setNewMerchant] = useState({
|
||||
name: "",
|
||||
@@ -90,6 +92,18 @@ export default function MerchantsPage() {
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
|
||||
// 获取用户角色
|
||||
const fetchUserRole = async () => {
|
||||
try {
|
||||
const response = await apiGet('/back/getUserRole')
|
||||
if (response.code === 200) {
|
||||
setUserRole(response.data || "")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户角色失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理省份变化
|
||||
const handleProvinceChange = (province: string) => {
|
||||
setNewMerchant({
|
||||
@@ -166,20 +180,20 @@ export default function MerchantsPage() {
|
||||
}
|
||||
|
||||
// 获取商户设备列表
|
||||
const fetchMerchantEquipments = async (merchantsId: string) => {
|
||||
setLoadingMerchantEquipments(prev => ({ ...prev, [merchantsId]: true }))
|
||||
const fetchMerchantEquipments = async (merchantId: string) => {
|
||||
setLoadingMerchantEquipments(prev => ({ ...prev, [merchantId]: true }))
|
||||
try {
|
||||
const response = await apiGet(`/back/equipment/list?pageNum=1&pageSize=10&merchantsId=${merchantsId}`)
|
||||
const response = await apiGet(`/back/equipment/list?pageNum=1&pageSize=10&merchantId=${merchantId}`)
|
||||
if (response.code === 200) {
|
||||
setMerchantEquipments(prev => ({ ...prev, [merchantsId]: response.rows || [] }))
|
||||
setMerchantEquipments(prev => ({ ...prev, [merchantId]: response.rows || [] }))
|
||||
return response.rows || []
|
||||
}
|
||||
return []
|
||||
} catch (error) {
|
||||
console.error(`获取商户${merchantsId}设备列表失败:`, error)
|
||||
console.error(`获取商户${merchantId}设备列表失败:`, error)
|
||||
return []
|
||||
} finally {
|
||||
setLoadingMerchantEquipments(prev => ({ ...prev, [merchantsId]: false }))
|
||||
setLoadingMerchantEquipments(prev => ({ ...prev, [merchantId]: false }))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +232,7 @@ export default function MerchantsPage() {
|
||||
|
||||
// 组件加载时获取数据
|
||||
useEffect(() => {
|
||||
fetchUserRole()
|
||||
fetchMerchants()
|
||||
}, [])
|
||||
|
||||
@@ -347,6 +362,14 @@ export default function MerchantsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
// 打开设备对话框
|
||||
const handleViewEquipment = (merchant: any) => {
|
||||
setSelectedMerchant(merchant)
|
||||
setIsEquipmentDialogOpen(true)
|
||||
const merchantId = merchant.merchantsId || merchant.id
|
||||
fetchMerchantEquipments(merchantId)
|
||||
}
|
||||
|
||||
const filteredMerchants = merchants.filter((merchant) => {
|
||||
const matchesSearch =
|
||||
merchant.merchantName?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
@@ -365,118 +388,6 @@ export default function MerchantsPage() {
|
||||
return matchesSearch && matchesStatus
|
||||
})
|
||||
|
||||
const EquipmentDialog = ({ merchant }: { merchant: any }) => {
|
||||
const merchantsId = merchant.merchantsId || merchant.id
|
||||
const equipments = merchantEquipments[merchantsId] || []
|
||||
const isLoading = loadingMerchantEquipments[merchantsId] || false
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
if (open && !merchantEquipments[merchantsId]) {
|
||||
fetchMerchantEquipments(merchantsId)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog onOpenChange={handleOpenChange}>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline" size="sm">
|
||||
<Eye className="h-4 w-4 mr-1" />
|
||||
查看设备({merchant.equipmentCount})
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="!w-[1400px] !max-w-[1400px] max-h-[800px] overflow-hidden flex flex-col">
|
||||
<DialogHeader className="flex-shrink-0">
|
||||
<DialogTitle>{merchant.merchantName} - 设备详情</DialogTitle>
|
||||
<DialogDescription>查看该商户的所有设备信息和状态</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex-1 overflow-y-auto space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="text-center">
|
||||
<p className="text-2xl font-bold text-green-600">{merchant.normalCount}</p>
|
||||
<p className="text-sm text-gray-600">正常设备</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="text-center">
|
||||
<p className="text-2xl font-bold text-yellow-600">{merchant.expiringCount}</p>
|
||||
<p className="text-sm text-gray-600">即将到期</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="text-center">
|
||||
<p className="text-2xl font-bold text-red-600">{merchant.expiredCount}</p>
|
||||
<p className="text-sm text-gray-600">已过期</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border overflow-hidden">
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="min-w-[120px]">设备编号</TableHead>
|
||||
<TableHead className="min-w-[150px]">设备名称</TableHead>
|
||||
<TableHead className="min-w-[120px]">类型</TableHead>
|
||||
<TableHead className="min-w-[120px]">安装日期</TableHead>
|
||||
<TableHead className="min-w-[150px]">安装位置</TableHead>
|
||||
<TableHead className="min-w-[100px]">状态</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{isLoading ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className="text-center py-4">
|
||||
加载中...
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : equipments.length > 0 ? (
|
||||
equipments.map((equipment: any) => (
|
||||
<TableRow key={equipment.id}>
|
||||
<TableCell className="font-medium truncate max-w-[120px]" title={equipment.equipmentId}>
|
||||
{equipment.equipmentId}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[150px]" title={equipment.equipmentName}>
|
||||
{equipment.equipmentName}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[120px]" title={equipment.equipmentType}>
|
||||
{equipment.equipmentType}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[120px]" title={equipment.installationDate}>
|
||||
{equipment.installationDate}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[150px]" title={equipment.installationLocation}>
|
||||
{equipment.installationLocation}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{getStatusBadge(equipment.status)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className="text-center py-4">
|
||||
暂无设备数据
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex justify-between items-center">
|
||||
@@ -484,10 +395,12 @@ export default function MerchantsPage() {
|
||||
<h1 className="text-3xl font-bold text-gray-900">商户管理</h1>
|
||||
<p className="text-gray-600">管理所有商户信息及其设备状态</p>
|
||||
</div>
|
||||
<Button onClick={() => setIsAddMerchantOpen(true)}>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
添加商户
|
||||
</Button>
|
||||
{userRole !== "merchant" && (
|
||||
<Button onClick={() => setIsAddMerchantOpen(true)}>
|
||||
<Plus className="h-4 w-4 mr-2" />
|
||||
添加商户
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
@@ -664,10 +577,15 @@ export default function MerchantsPage() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex space-x-2">
|
||||
<EquipmentDialog merchant={merchant} />
|
||||
<Button variant="outline" size="sm">
|
||||
编辑
|
||||
<Button variant="outline" size="sm" onClick={() => handleViewEquipment(merchant)}>
|
||||
<Eye className="h-4 w-4 mr-1" />
|
||||
查看设备({merchant.equipmentCount})
|
||||
</Button>
|
||||
{userRole !== "merchant" && (
|
||||
<Button variant="outline" size="sm">
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -943,6 +861,99 @@ export default function MerchantsPage() {
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* 设备详情对话框 */}
|
||||
<Dialog open={isEquipmentDialogOpen} onOpenChange={setIsEquipmentDialogOpen}>
|
||||
<DialogContent className="!w-[1400px] !max-w-[1400px] max-h-[800px] overflow-hidden flex flex-col">
|
||||
<DialogHeader className="flex-shrink-0">
|
||||
<DialogTitle>{selectedMerchant?.merchantName} - 设备详情</DialogTitle>
|
||||
<DialogDescription>查看该商户的所有设备信息和状态</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex-1 overflow-y-auto space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="text-center">
|
||||
<p className="text-2xl font-bold text-green-600">{selectedMerchant?.normalCount || 0}</p>
|
||||
<p className="text-sm text-gray-600">正常设备</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="text-center">
|
||||
<p className="text-2xl font-bold text-yellow-600">{selectedMerchant?.expiringCount || 0}</p>
|
||||
<p className="text-sm text-gray-600">即将到期</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-4">
|
||||
<div className="text-center">
|
||||
<p className="text-2xl font-bold text-red-600">{selectedMerchant?.expiredCount || 0}</p>
|
||||
<p className="text-sm text-gray-600">已过期</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border overflow-hidden">
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="min-w-[120px]">设备编号</TableHead>
|
||||
<TableHead className="min-w-[150px]">设备名称</TableHead>
|
||||
<TableHead className="min-w-[120px]">类型</TableHead>
|
||||
<TableHead className="min-w-[120px]">安装日期</TableHead>
|
||||
<TableHead className="min-w-[150px]">安装位置</TableHead>
|
||||
<TableHead className="min-w-[100px]">状态</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{loadingMerchantEquipments[selectedMerchant?.merchantsId || selectedMerchant?.id] ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className="text-center py-4">
|
||||
加载中...
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (merchantEquipments[selectedMerchant?.merchantsId || selectedMerchant?.id] || []).length > 0 ? (
|
||||
(merchantEquipments[selectedMerchant?.merchantsId || selectedMerchant?.id] || []).map((equipment: any) => (
|
||||
<TableRow key={equipment.id}>
|
||||
<TableCell className="font-medium truncate max-w-[120px]" title={equipment.equipmentId}>
|
||||
{equipment.equipmentId}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[150px]" title={equipment.equipmentName}>
|
||||
{equipment.equipmentName}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[120px]" title={equipment.equipmentType}>
|
||||
{equipment.equipmentType}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[120px]" title={equipment.installationDate}>
|
||||
{equipment.installationDate}
|
||||
</TableCell>
|
||||
<TableCell className="truncate max-w-[150px]" title={equipment.installationLocation}>
|
||||
{equipment.installationLocation}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{getStatusBadge(equipment.status)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className="text-center py-4">
|
||||
暂无设备数据
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user