From 7f095044cb6091b91f9fd1a858d2f05ec8c75a6f Mon Sep 17 00:00:00 2001 From: menxipeng Date: Thu, 20 Nov 2025 23:28:07 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/CompanyPermissionsPage.tsx | 575 +++++++++++++++++- src/components/pages/EquipmentPage.tsx | 331 +++++++--- src/components/pages/MallsPage.tsx | 43 +- src/components/pages/MerchantsPage.tsx | 75 ++- 4 files changed, 887 insertions(+), 137 deletions(-) diff --git a/src/components/pages/CompanyPermissionsPage.tsx b/src/components/pages/CompanyPermissionsPage.tsx index e4aad2c..1317124 100644 --- a/src/components/pages/CompanyPermissionsPage.tsx +++ b/src/components/pages/CompanyPermissionsPage.tsx @@ -14,8 +14,9 @@ import { DialogTrigger, } from "../ui/dialog" import { Label } from "../ui/label" -import { Plus, Search, Download, User, Shield, Building, Store, Wrench, Eye, Edit } from "lucide-react" -import { apiGet, apiPost } from "../../lib/services/api" +import { Plus, Search, Download, User, Shield, Building, Store, Wrench, Eye, Edit, Trash2 } from "lucide-react" +import { apiGet, apiPost, apiPut, apiDelete } from "../../lib/services/api" +import { getUserData } from "../../lib/utils/storage" // 定义角色数据类型 interface Role { @@ -67,6 +68,12 @@ export default function CompanyPermissionsPage() { const [total, setTotal] = useState(0) const [selectedRoleId, setSelectedRoleId] = useState("") const [activeTab, setActiveTab] = useState("all") + const [isViewDialogOpen, setIsViewDialogOpen] = useState(false) + const [isEditDialogOpen, setIsEditDialogOpen] = useState(false) + const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false) + const [selectedUser, setSelectedUser] = useState(null) + const [isSubmitting, setIsSubmitting] = useState(false) + const [currentUserRole, setCurrentUserRole] = useState("") // 获取角色列表 const fetchRoles = async () => { @@ -134,6 +141,20 @@ export default function CompanyPermissionsPage() { } } + // 检查当前用户是否是总部管理员 + useEffect(() => { + const userData = getUserData() + if (userData) { + // 从用户数据中获取角色信息 + const roleName = userData.roleName || userData.roles?.[0]?.roleName || "" + const roleKey = roles.find(r => r.roleName === roleName)?.roleKey || "" + setCurrentUserRole(roleKey) + } + }, [roles]) + + // 判断是否是总部管理员 + const isAdmin = currentUserRole === "admin" + // 初始化数据 useEffect(() => { fetchRoles() @@ -204,6 +225,56 @@ export default function CompanyPermissionsPage() { return acc }, {} as Record) + // 查看用户详情 + const handleViewUser = (user: UserData) => { + setSelectedUser(user) + setIsViewDialogOpen(true) + } + + // 编辑用户 + const handleEditUser = (user: UserData) => { + setSelectedUser(user) + setIsEditDialogOpen(true) + } + + // 删除用户 + const handleDeleteUser = (user: UserData) => { + setSelectedUser(user) + setIsDeleteDialogOpen(true) + } + + // 确认删除用户 + const handleConfirmDelete = async () => { + if (!selectedUser) return + + setIsSubmitting(true) + try { + const result = await apiDelete(`/system/user/${selectedUser.userId}`) + + if (result.code === 200) { + alert('删除用户成功') + setIsDeleteDialogOpen(false) + setSelectedUser(null) + // 刷新数据 + if (roleFilter === "all") { + fetchAllUsers() + } else { + const role = roles.find(r => r.roleKey === roleFilter) + if (role) { + fetchUsersByRole(role.roleId, currentPage) + } + } + } else { + alert(result.msg || '删除用户失败') + } + } catch (error) { + console.error('删除用户失败:', error) + alert('网络错误,请稍后重试') + } finally { + setIsSubmitting(false) + } + } + const UserTable = ({ users }: { users: UserData[] }) => (
@@ -216,19 +287,19 @@ export default function CompanyPermissionsPage() { 联系方式最后登录状态 - 操作 + {isAdmin && 操作} {loading ? ( - +
加载中...
) : users.length === 0 ? ( - +
暂无数据
@@ -270,16 +341,37 @@ export default function CompanyPermissionsPage() { {getStatusBadge(user.status)} - -
- - -
-
+ {isAdmin && ( + +
+ + + +
+
+ )} ) }) @@ -297,21 +389,23 @@ export default function CompanyPermissionsPage() {

公司权限管理

管理公司内部用户账户和权限分配

- - - - - - - 创建新用户 - 填写用户信息并分配相应的角色权限 - - setIsCreateDialogOpen(false)} /> - - + {isAdmin && ( + + + + + + + 创建新用户 + 填写用户信息并分配相应的角色权限 + + setIsCreateDialogOpen(false)} /> + + + )} {/* Stats Cards */} @@ -425,6 +519,133 @@ export default function CompanyPermissionsPage() { + + {/* 查看用户详情对话框 */} + + + + 用户详情 + 查看用户详细信息 + + {selectedUser && ( +
+
+
+ +
{selectedUser.userName}
+
+
+ +
{selectedUser.nickName}
+
+
+ +
{selectedUser.phonenumber || '-'}
+
+
+ +
{getStatusBadge(selectedUser.status)}
+
+
+ +
+ {selectedUser.roles.map((role, idx) => ( + + {role.roleName} + + ))} +
+
+
+ +
+ {selectedUser.provinceName || '总公司'} +
+
+
+ +
{selectedUser.dept?.deptName || '-'}
+
+
+ +
+ {selectedUser.loginDate + ? new Date(selectedUser.loginDate).toLocaleString('zh-CN') + : '-'} +
+
+
+
+ )} +
+ +
+
+
+ + {/* 编辑用户对话框 */} + + + + 编辑用户 + 修改用户信息 + + {selectedUser && ( + { + setIsEditDialogOpen(false) + setSelectedUser(null) + }} + onSuccess={() => { + // 刷新数据 + if (roleFilter === "all") { + fetchAllUsers() + } else { + const role = roles.find(r => r.roleKey === roleFilter) + if (role) { + fetchUsersByRole(role.roleId, currentPage) + } + } + }} + /> + )} + + + + {/* 删除确认对话框 */} + + + + 确认删除用户 + + 您确定要删除用户 {selectedUser?.nickName || selectedUser?.userName} 吗?此操作不可撤销。 + + +
+ + +
+
+
) } @@ -667,3 +888,297 @@ function CreateUserForm({ roles, onClose }: { roles: Role[]; onClose: () => void ) } +function EditUserForm({ + user, + roles, + onClose, + onSuccess +}: { + user: UserData + roles: Role[] + onClose: () => void + onSuccess: () => void +}) { + const [formData, setFormData] = useState({ + username: user.userName || "", + name: user.nickName || "", + phone: user.phonenumber || "", + role: "", + department: user.dept?.deptName || "", + provinces: [] as string[], + password: "", + status: user.status || "0", + }) + const [loading, setLoading] = useState(false) + const [availableProvinces, setAvailableProvinces] = useState([]) + const [provincesLoading, setProvincesLoading] = useState(false) + + // 根据角色获取省份数据 + const fetchProvinces = async (roleKey: string) => { + try { + setProvincesLoading(true) + + const endpoint = roleKey === "common" + ? "/back/region/deProvinces" + : "/back/region/provinces" + + const result = await apiGet(endpoint) + + if (result.code === 200) { + setAvailableProvinces(result.data || []) + } + } catch (error) { + console.error('获取省份数据失败:', error) + } finally { + setProvincesLoading(false) + } + } + + // 初始化表单数据 + useEffect(() => { + const userRole = user.roles[0] + const role = roles.find(r => r.roleName === userRole?.roleName) + if (role) { + setFormData(prev => ({ + ...prev, + role: role.roleKey + })) + // 如果有省份信息,解析省份名称 + if (user.provinceName) { + setFormData(prev => ({ + ...prev, + provinces: [user.provinceName] + })) + } + // 加载省份数据 + if (role.roleKey && role.roleKey !== "admin" && role.roleKey !== "merchant") { + fetchProvinces(role.roleKey) + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user, roles]) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + + if (!formData.role) { + alert('请选择角色') + return + } + + try { + setLoading(true) + + const selectedRole = roles.find(r => r.roleKey === formData.role) + if (!selectedRole) { + alert('选择的角色无效') + return + } + + const selectedProvinceCodes = formData.provinces + .map(provinceName => { + const province = availableProvinces.find(p => p.name === provinceName) + return province ? province.code : null + }) + .filter(code => code !== null) + .join(',') + + const requestData: any = { + userId: user.userId, + userName: formData.username, + nickName: formData.name, + phonenumber: formData.phone, + sex: "0", + status: formData.status, + remark: formData.department || "", + postIds: [], + roleIds: [selectedRole.roleId], + provinceCode: selectedProvinceCodes || "" + } + + // 如果修改了密码,才包含密码字段 + if (formData.password.trim()) { + requestData.password = formData.password + } + + console.log('更新用户请求参数:', requestData) + + const result = await apiPut('/system/user', requestData) + + if (result.code === 200) { + alert('用户更新成功') + onClose() + onSuccess() + } else { + alert(result.msg || '更新用户失败') + } + } catch (error) { + console.error('更新用户失败:', error) + alert('网络错误,请稍后重试') + } finally { + setLoading(false) + } + } + + const handleProvinceToggle = (province: string) => { + setFormData((prev) => ({ + ...prev, + provinces: prev.provinces.includes(province) + ? prev.provinces.filter((p) => p !== province) + : [...prev.provinces, province], + })) + } + + const shouldShowProvinces = formData.role && formData.role !== "admin" && formData.role !== "merchant" + + return ( +
+
+
+ + setFormData({ ...formData, username: e.target.value })} + placeholder="请输入用户名" + required + /> +
+ +
+ + setFormData({ ...formData, name: e.target.value })} + placeholder="请输入真实姓名" + required + /> +
+ +
+ + setFormData({ ...formData, phone: e.target.value })} + placeholder="请输入手机号" + required + /> +
+ +
+ + +
+ +
+ + +
+ + {shouldShowProvinces && ( +
+ +
+
+ {formData.role === "common" ? "经销商可选择多个省份" : "其他角色只能选择一个省份"} +
+ {provincesLoading ? ( +
正在加载省份数据...
+ ) : ( +
+ {availableProvinces.map((province) => ( +
+ { + if (formData.role === "common") { + handleProvinceToggle(province.name) + } else { + setFormData({ ...formData, provinces: [province.name] }) + } + }} + className="rounded border-gray-300" + /> + +
+ ))} +
+ )} + {formData.provinces.length > 0 && ( +
+ {formData.provinces.map((province) => ( + + {province} + + ))} +
+ )} +
+
+ )} + +
+ + setFormData({ ...formData, password: e.target.value })} + placeholder="留空则不修改密码" + /> +
+
+ +
+ + +
+ + ) +} + diff --git a/src/components/pages/EquipmentPage.tsx b/src/components/pages/EquipmentPage.tsx index 9d17d69..21b378d 100644 --- a/src/components/pages/EquipmentPage.tsx +++ b/src/components/pages/EquipmentPage.tsx @@ -75,6 +75,8 @@ export default function EquipmentPage() { const [statusFilter, setStatusFilter] = useState("all") const [isAddEquipmentOpen, setIsAddEquipmentOpen] = useState(false) const [isEditEquipmentOpen, setIsEditEquipmentOpen] = useState(false) + const [isViewEquipmentOpen, setIsViewEquipmentOpen] = useState(false) + const [viewEquipment, setViewEquipment] = useState(null) const [isSubmitting, setIsSubmitting] = useState(false) const [merchants, setMerchants] = useState([]) const [loadingMerchants, setLoadingMerchants] = useState(false) @@ -316,6 +318,16 @@ export default function EquipmentPage() { } } + // 打开查看对话框 + const handleViewEquipment = (equipment: Equipment) => { + setViewEquipment(equipment) + setIsViewEquipmentOpen(true) + // 加载设备类型数据用于显示 + if (Object.keys(equipmentTypes).length === 0) { + fetchEquipmentTypes() + } + } + // 打开编辑对话框 const handleEditEquipment = (equipment: Equipment) => { setEditEquipment({ @@ -891,6 +903,146 @@ export default function EquipmentPage() { + + {/* 查看设备对话框 */} + + + + 设备详情 + 查看设备完整信息 + + {viewEquipment && ( +
+ {/* 设备基本信息 */} +
+
+ +
+ + {viewEquipment.equipmentId} +
+
+
+ +
{viewEquipment.equipmentName}
+
+
+ +
+ {equipmentTypes[viewEquipment.equipmentType] || viewEquipment.equipmentType} +
+
+
+ +
{viewEquipment.equipmentModel || '-'}
+
+
+ +
{getStatusBadge(viewEquipment.status)}
+
+
+ + {/* 商户信息 */} +
+

商户信息

+
+
+ +
{viewEquipment.merchantName}
+
+
+ +
{viewEquipment.mallName || '-'}
+
+
+ +
+ + {viewEquipment.installationLocation || '-'} +
+
+
+
+ + {/* 检测信息 */} +
+

检测信息

+
+
+ +
+ + {viewEquipment.installationDate || '-'} +
+
+
+ +
+ + + {viewEquipment.nextInspectionDate || '-'} + +
+
+
+
+ + {/* 其他信息 */} +
+

其他信息

+
+
+ +
{viewEquipment.createdBy || '-'}
+
+
+ +
{viewEquipment.createdAt || '-'}
+
+ {viewEquipment.updatedBy && ( +
+ +
{viewEquipment.updatedBy}
+
+ )} +
+ +
{viewEquipment.updatedAt || '-'}
+
+ {viewEquipment.remarks && ( +
+ +
+ {viewEquipment.remarks} +
+
+ )} +
+
+
+ )} +
+ + {viewEquipment && ( + + )} +
+
+
@@ -956,44 +1108,44 @@ export default function EquipmentPage() { {/* 筛选区域 */} -
-
+
+
- + setEquipmentIdSearch(e.target.value)} - className="pl-10" + className="pl-10 h-9 sm:h-10 text-sm" />
-
-
- + setEquipmentNameSearch(e.target.value)} - className="pl-10" + className="pl-10 h-9 sm:h-10 text-sm" />
- - +
+ + +
{/* Desktop Table View */} @@ -1080,13 +1232,24 @@ export default function EquipmentPage() {
- +
+ + +
) @@ -1097,70 +1260,94 @@ export default function EquipmentPage() {
{/* Mobile Card View */} -
+
{loadingEquipmentList ? ( -
加载中...
+
加载中...
) : filteredEquipment.length === 0 ? ( -
暂无数据
+
暂无数据
) : ( filteredEquipment.map((item) => { const equipmentTypeDisplay = equipmentTypes[item.equipmentType] || item.equipmentType return ( - - -
+ + + {/* 设备基本信息 */} +
-
+
- {item.equipmentId} - {getStatusBadge(item.status)} + {item.equipmentId} +
{getStatusBadge(item.status)}
-
{item.equipmentName}
-
类型: {equipmentTypeDisplay}
-
型号: {item.equipmentModel}
+
{item.equipmentName}
+
类型: {equipmentTypeDisplay}
+ {item.equipmentModel && ( +
型号: {item.equipmentModel}
+ )} +
+
+ +
-
-
-
-
商户信息
-
{item.merchantName}
-
{item.mallName}
-
- - {item.installationLocation} -
+ {/* 详细信息 */} +
+ {/* 商户信息 */} +
+
商户信息
+
{item.merchantName}
+ {item.mallName && ( +
{item.mallName}
+ )} + {item.installationLocation && ( +
+ + {item.installationLocation} +
+ )}
-
-
检测信息
+ {/* 检测信息 */} +
+
检测信息
{item.installationDate && ( -
- - 上次检测: {item.installationDate} +
+ + 安装日期: {item.installationDate}
)} {item.nextInspectionDate && ( -
- - 下次检测: {item.nextInspectionDate} +
+ + + 下次检测: {item.nextInspectionDate} +
)} -
安装: {item.installationDate}
-
-
负责经销商
-
{item.createdBy}
-
+ {/* 负责经销商 */} + {item.createdBy && ( +
+
负责经销商
+
{item.createdBy}
+
+ )}
diff --git a/src/components/pages/MallsPage.tsx b/src/components/pages/MallsPage.tsx index 8ca794e..f838b5a 100644 --- a/src/components/pages/MallsPage.tsx +++ b/src/components/pages/MallsPage.tsx @@ -1189,37 +1189,42 @@ export default function MallsPage() { {/* Mobile Card View */}
{loadingEquipments ? ( -
加载中...
+
加载中...
) : merchantEquipments.length > 0 ? ( merchantEquipments.map((equipment: any) => ( - - -
+ + + {/* 设备基本信息 */} +
-
{equipment.equipmentName}
-
编号: {equipment.equipmentId}
+
{equipment.equipmentName}
+
编号: {equipment.equipmentId}
- {getEquipmentStatusBadge(equipment.status)} +
{getEquipmentStatusBadge(equipment.status)}
-
-
- 类型: - {equipment.equipmentType} + + {/* 详细信息 - 竖着显示 */} +
+
+
类型
+
{equipment.equipmentType || '-'}
-
- 安装日期: - {equipment.installationDate} -
-
- 安装位置: - {equipment.installationLocation} +
+
安装日期
+
{equipment.installationDate || '-'}
+ {equipment.installationLocation && ( +
+
安装位置
+
{equipment.installationLocation}
+
+ )}
)) ) : ( -
暂无设备数据
+
暂无设备数据
)}
diff --git a/src/components/pages/MerchantsPage.tsx b/src/components/pages/MerchantsPage.tsx index 60eabac..1c7dfb2 100644 --- a/src/components/pages/MerchantsPage.tsx +++ b/src/components/pages/MerchantsPage.tsx @@ -1182,40 +1182,41 @@ export default function MerchantsPage() { {/* 设备详情对话框 */} - - - {selectedMerchant?.merchantName} - 设备详情 - 查看该商户的所有设备信息和状态 + + + {selectedMerchant?.merchantName} - 设备详情 + 查看该商户的所有设备信息和状态 -
-
+
+
- +
-

{selectedMerchant?.normalCount || 0}

-

正常设备

+

{selectedMerchant?.normalCount || 0}

+

正常设备

- +
-

{selectedMerchant?.expiringCount || 0}

-

即将到期

+

{selectedMerchant?.expiringCount || 0}

+

即将到期

- +
-

{selectedMerchant?.expiredCount || 0}

-

已过期

+

{selectedMerchant?.expiredCount || 0}

+

已过期

-
+ {/* Desktop Table View */} +
@@ -1269,6 +1270,48 @@ export default function MerchantsPage() {
+ + {/* Mobile Card View */} +
+ {loadingMerchantEquipments[selectedMerchant?.merchantsId || selectedMerchant?.id] ? ( +
加载中...
+ ) : (merchantEquipments[selectedMerchant?.merchantsId || selectedMerchant?.id] || []).length > 0 ? ( + (merchantEquipments[selectedMerchant?.merchantsId || selectedMerchant?.id] || []).map((equipment: any) => ( + + + {/* 设备基本信息 */} +
+
+
{equipment.equipmentName}
+
编号: {equipment.equipmentId}
+
+
{getStatusBadge(equipment.status)}
+
+ + {/* 详细信息 - 竖着显示 */} +
+
+
类型
+
{equipment.equipmentType || '-'}
+
+
+
安装日期
+
{equipment.installationDate || '-'}
+
+ {equipment.installationLocation && ( +
+
安装位置
+
{equipment.installationLocation}
+
+ )} +
+
+
+ )) + ) : ( +
暂无设备数据
+ )} +