q q q
This commit is contained in:
@@ -745,7 +745,7 @@ export default function EquipmentPage() {
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Shield className="h-4 w-4 text-blue-600" />
|
||||
<span className="font-medium text-blue-600">{item.equipmentId}</span>
|
||||
<span className="font-medium text-blue-600">{item.equId}</span>
|
||||
</div>
|
||||
<div className="text-sm font-medium">{item.equipmentName}</div>
|
||||
<div className="text-xs text-gray-500">类型: {equipmentTypeDisplay}</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react"
|
||||
import { useState, useEffect } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
|
||||
import { Button } from "../ui/button"
|
||||
import { Input } from "../ui/input"
|
||||
@@ -16,121 +16,165 @@ import {
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog"
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table"
|
||||
import { Plus, Edit, Trash2, Phone } from "lucide-react"
|
||||
|
||||
interface ValueAddedService {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
status: "active" | "inactive"
|
||||
assignedDealers: string[]
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
interface Dealer {
|
||||
id: string
|
||||
name: string
|
||||
phone: string
|
||||
region: string
|
||||
}
|
||||
import { Plus, Edit, Trash2, Phone, ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { getServiceList, createService, updateService, deleteService } from "@/lib/services/service"
|
||||
import { ValueAddedService } from "@/lib/types/service"
|
||||
import { getUserByRoleKey } from "@/lib/services/user"
|
||||
import type { User } from "@/lib/types/user"
|
||||
|
||||
export default function ValueAddedServicesPage() {
|
||||
const [services, setServices] = useState<ValueAddedService[]>([
|
||||
{
|
||||
id: "1",
|
||||
title: "消防设备年检服务",
|
||||
description: "提供专业的消防设备年度检测服务,确保设备符合安全标准",
|
||||
status: "active",
|
||||
assignedDealers: ["dealer1", "dealer2"],
|
||||
createdAt: "2024-01-15",
|
||||
updatedAt: "2024-01-15",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
title: "紧急维修服务",
|
||||
description: "24小时紧急维修服务,快速响应设备故障",
|
||||
status: "active",
|
||||
assignedDealers: ["dealer1", "dealer3"],
|
||||
createdAt: "2024-01-10",
|
||||
updatedAt: "2024-01-20",
|
||||
},
|
||||
])
|
||||
|
||||
const [dealers] = useState<Dealer[]>([
|
||||
{ id: "dealer1", name: "华东经销商", phone: "138****1234", region: "华东区" },
|
||||
{ id: "dealer2", name: "华南经销商", phone: "139****5678", region: "华南区" },
|
||||
{ id: "dealer3", name: "华北经销商", phone: "137****9012", region: "华北区" },
|
||||
])
|
||||
|
||||
const [services, setServices] = useState<ValueAddedService[]>([])
|
||||
const [adminUsers, setAdminUsers] = useState<User[]>([])
|
||||
const [commonUsers, setCommonUsers] = useState<User[]>([])
|
||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false)
|
||||
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false)
|
||||
const [selectedService, setSelectedService] = useState<ValueAddedService | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [pageNum, setPageNum] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(10)
|
||||
const [total, setTotal] = useState(0)
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
title: "",
|
||||
serviceTitle: "",
|
||||
description: "",
|
||||
status: "active" as "active" | "inactive",
|
||||
assignedDealers: [] as string[],
|
||||
status: "1",
|
||||
assignedAdmin: "",
|
||||
assignedCommon: "",
|
||||
})
|
||||
|
||||
const handleCreateService = () => {
|
||||
const newService: ValueAddedService = {
|
||||
id: Date.now().toString(),
|
||||
title: formData.title,
|
||||
description: formData.description,
|
||||
status: formData.status,
|
||||
assignedDealers: formData.assignedDealers,
|
||||
createdAt: new Date().toISOString().split("T")[0],
|
||||
updatedAt: new Date().toISOString().split("T")[0],
|
||||
useEffect(() => {
|
||||
loadServices()
|
||||
loadUsers()
|
||||
}, [pageNum, pageSize])
|
||||
|
||||
const loadServices = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await getServiceList({ pageNum, pageSize })
|
||||
if (response.code === 200) {
|
||||
setServices(response.rows)
|
||||
setTotal(response.total)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载服务列表失败:", error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
setServices([...services, newService])
|
||||
}
|
||||
|
||||
const loadUsers = async () => {
|
||||
try {
|
||||
const [adminResponse, commonResponse] = await Promise.all([
|
||||
getUserByRoleKey("admin"),
|
||||
getUserByRoleKey("common"),
|
||||
])
|
||||
|
||||
if (adminResponse.code === 200 && adminResponse.data) {
|
||||
setAdminUsers(adminResponse.data)
|
||||
}
|
||||
|
||||
if (commonResponse.code === 200 && commonResponse.data) {
|
||||
setCommonUsers(commonResponse.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载用户列表失败:", error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreateService = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await createService(formData)
|
||||
if (response.code === 200) {
|
||||
setIsCreateDialogOpen(false)
|
||||
resetForm()
|
||||
loadServices()
|
||||
} else {
|
||||
alert(response.msg || "创建失败")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("创建服务失败:", error)
|
||||
alert("创建服务失败")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleEditService = () => {
|
||||
const handleEditService = async () => {
|
||||
if (!selectedService) return
|
||||
|
||||
const updatedServices = services.map((service) =>
|
||||
service.id === selectedService.id
|
||||
? {
|
||||
...service,
|
||||
title: formData.title,
|
||||
description: formData.description,
|
||||
status: formData.status,
|
||||
assignedDealers: formData.assignedDealers,
|
||||
updatedAt: new Date().toISOString().split("T")[0],
|
||||
}
|
||||
: service,
|
||||
)
|
||||
setServices(updatedServices)
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await updateService({
|
||||
id: selectedService.id,
|
||||
...formData,
|
||||
})
|
||||
if (response.code === 200) {
|
||||
setIsEditDialogOpen(false)
|
||||
resetForm()
|
||||
loadServices()
|
||||
} else {
|
||||
alert(response.msg || "更新失败")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新服务失败:", error)
|
||||
alert("更新服务失败")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteService = (id: string) => {
|
||||
setServices(services.filter((service) => service.id !== id))
|
||||
const handleDeleteService = async (id: string) => {
|
||||
if (!confirm("确定要删除该服务吗?")) return
|
||||
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await deleteService(id)
|
||||
if (response.code === 200) {
|
||||
loadServices()
|
||||
} else {
|
||||
alert(response.msg || "删除失败")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除服务失败:", error)
|
||||
alert("删除服务失败")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const toggleServiceStatus = (id: string) => {
|
||||
const updatedServices = services.map((service) =>
|
||||
service.id === id
|
||||
? {
|
||||
...service,
|
||||
status: service.status === "active" ? ("inactive" as const) : ("active" as const),
|
||||
updatedAt: new Date().toISOString().split("T")[0],
|
||||
}
|
||||
: service,
|
||||
)
|
||||
setServices(updatedServices)
|
||||
const toggleServiceStatus = async (service: ValueAddedService) => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const newStatus = service.status === "1" ? "0" : "1"
|
||||
const response = await updateService({
|
||||
id: service.id,
|
||||
serviceTitle: service.serviceTitle,
|
||||
description: service.description,
|
||||
status: newStatus,
|
||||
assignedAdmin: service.assignedAdmin || "",
|
||||
assignedCommon: service.assignedCommon || "",
|
||||
})
|
||||
if (response.code === 200) {
|
||||
loadServices()
|
||||
} else {
|
||||
alert(response.msg || "更新状态失败")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新状态失败:", error)
|
||||
alert("更新状态失败")
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData({
|
||||
title: "",
|
||||
serviceTitle: "",
|
||||
description: "",
|
||||
status: "active",
|
||||
assignedDealers: [],
|
||||
status: "1",
|
||||
assignedAdmin: "",
|
||||
assignedCommon: "",
|
||||
})
|
||||
setSelectedService(null)
|
||||
}
|
||||
@@ -138,16 +182,37 @@ export default function ValueAddedServicesPage() {
|
||||
const openEditDialog = (service: ValueAddedService) => {
|
||||
setSelectedService(service)
|
||||
setFormData({
|
||||
title: service.title,
|
||||
serviceTitle: service.serviceTitle,
|
||||
description: service.description,
|
||||
status: service.status,
|
||||
assignedDealers: service.assignedDealers,
|
||||
assignedAdmin: service.assignedAdmin || "",
|
||||
assignedCommon: service.assignedCommon || "",
|
||||
})
|
||||
setIsEditDialogOpen(true)
|
||||
}
|
||||
|
||||
const getDealerName = (dealerId: string) => {
|
||||
return dealers.find((dealer) => dealer.id === dealerId)?.name || "未知经销商"
|
||||
const getUserName = (userId: string, userList: User[]) => {
|
||||
const user = userList.find((u) => u.userId === userId)
|
||||
return user ? (user.nickName || user.userName) : "未知用户"
|
||||
}
|
||||
|
||||
const getUsersByIds = (ids: string) => {
|
||||
if (!ids) return []
|
||||
return ids.split(",").filter(Boolean)
|
||||
}
|
||||
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
|
||||
const handlePrevPage = () => {
|
||||
if (pageNum > 1) {
|
||||
setPageNum(pageNum - 1)
|
||||
}
|
||||
}
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (pageNum < totalPages) {
|
||||
setPageNum(pageNum + 1)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -175,8 +240,8 @@ export default function ValueAddedServicesPage() {
|
||||
<Label htmlFor="title">服务标题</Label>
|
||||
<Input
|
||||
id="title"
|
||||
value={formData.title}
|
||||
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
|
||||
value={formData.serviceTitle}
|
||||
onChange={(e) => setFormData({ ...formData, serviceTitle: e.target.value })}
|
||||
placeholder="请输入服务标题"
|
||||
/>
|
||||
</div>
|
||||
@@ -190,49 +255,96 @@ export default function ValueAddedServicesPage() {
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>分配总公司用户</Label>
|
||||
<div className="grid grid-cols-1 gap-2 mt-2 max-h-48 overflow-y-auto border rounded p-2">
|
||||
{adminUsers.map((user) => {
|
||||
const assignedIds = formData.assignedAdmin.split(",").filter(Boolean)
|
||||
const userId = user.userId
|
||||
return (
|
||||
<div key={userId} className="flex items-center space-x-2 p-2 border rounded">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`admin-${userId}`}
|
||||
checked={assignedIds.includes(userId)}
|
||||
onChange={(e) => {
|
||||
const ids = formData.assignedAdmin.split(",").filter(Boolean)
|
||||
if (e.target.checked) {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedAdmin: [...ids, userId].join(","),
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedAdmin: ids.filter((id) => id !== userId).join(","),
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={`admin-${userId}`} className="flex-1 cursor-pointer">
|
||||
<div className="flex justify-between">
|
||||
<span className="font-medium">{user.nickName || user.userName}</span>
|
||||
<span className="text-sm text-gray-500 flex items-center">
|
||||
<Phone className="h-3 w-3 mr-1" />
|
||||
{user.phonenumber}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>分配经销商</Label>
|
||||
<div className="grid grid-cols-1 gap-2 mt-2">
|
||||
{dealers.map((dealer) => (
|
||||
<div key={dealer.id} className="flex items-center space-x-2 p-2 border rounded">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={dealer.id}
|
||||
checked={formData.assignedDealers.includes(dealer.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedDealers: [...formData.assignedDealers, dealer.id],
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedDealers: formData.assignedDealers.filter((id) => id !== dealer.id),
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={dealer.id} className="flex-1 cursor-pointer">
|
||||
<div className="grid grid-cols-1 gap-2 mt-2 max-h-48 overflow-y-auto border rounded p-2">
|
||||
{commonUsers.map((user) => {
|
||||
const assignedIds = formData.assignedCommon.split(",").filter(Boolean)
|
||||
const userId = user.userId
|
||||
return (
|
||||
<div key={userId} className="flex items-center space-x-2 p-2 border rounded">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`common-${userId}`}
|
||||
checked={assignedIds.includes(userId)}
|
||||
onChange={(e) => {
|
||||
const ids = formData.assignedCommon.split(",").filter(Boolean)
|
||||
if (e.target.checked) {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedCommon: [...ids, userId].join(","),
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedCommon: ids.filter((id) => id !== userId).join(","),
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={`common-${userId}`} className="flex-1 cursor-pointer">
|
||||
<div className="flex justify-between">
|
||||
<span className="font-medium">{dealer.name}</span>
|
||||
<span className="text-sm text-gray-500">{dealer.region}</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 flex items-center">
|
||||
<span className="font-medium">{user.nickName || user.userName}</span>
|
||||
<span className="text-sm text-gray-500 flex items-center">
|
||||
<Phone className="h-3 w-3 mr-1" />
|
||||
{dealer.phone}
|
||||
{user.phonenumber}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setIsCreateDialogOpen(false)}>
|
||||
<Button variant="outline" onClick={() => setIsCreateDialogOpen(false)} disabled={loading}>
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={handleCreateService}>创建服务</Button>
|
||||
<Button onClick={handleCreateService} disabled={loading}>
|
||||
{loading ? "创建中..." : "创建服务"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
@@ -251,56 +363,125 @@ export default function ValueAddedServicesPage() {
|
||||
<TableHead>服务标题</TableHead>
|
||||
<TableHead>描述</TableHead>
|
||||
<TableHead>状态</TableHead>
|
||||
<TableHead>分配经销商</TableHead>
|
||||
<TableHead>总公司</TableHead>
|
||||
<TableHead>经销商</TableHead>
|
||||
<TableHead>创建时间</TableHead>
|
||||
<TableHead>操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{services.map((service) => (
|
||||
{loading ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={7} className="text-center py-8">
|
||||
加载中...
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : services.length === 0 ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={7} className="text-center py-8 text-gray-500">
|
||||
暂无数据
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
services.map((service) => (
|
||||
<TableRow key={service.id}>
|
||||
<TableCell className="font-medium">{service.title}</TableCell>
|
||||
<TableCell className="font-medium">{service.serviceTitle}</TableCell>
|
||||
<TableCell className="max-w-xs truncate">{service.description}</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
checked={service.status === "active"}
|
||||
onCheckedChange={() => toggleServiceStatus(service.id)}
|
||||
checked={service.status === "1"}
|
||||
onCheckedChange={() => toggleServiceStatus(service)}
|
||||
disabled={loading}
|
||||
/>
|
||||
<Badge variant={service.status === "active" ? "default" : "secondary"}>
|
||||
{service.status === "active" ? "上架" : "下架"}
|
||||
<Badge variant={service.status === "1" ? "default" : "secondary"}>
|
||||
{service.status === "1" ? "上架" : "下架"}
|
||||
</Badge>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{service.assignedDealers.slice(0, 2).map((dealerId) => (
|
||||
<Badge key={dealerId} variant="outline" className="text-xs">
|
||||
{getDealerName(dealerId)}
|
||||
</Badge>
|
||||
))}
|
||||
{service.assignedDealers.length > 2 && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
+{service.assignedDealers.length - 2}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>{service.createdAt}</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{getUsersByIds(service.assignedAdmin || "").length > 0 ? (
|
||||
<>
|
||||
{getUsersByIds(service.assignedAdmin).slice(0, 2).map((userId) => (
|
||||
<Badge key={userId} variant="outline" className="text-xs">
|
||||
{getUserName(userId, adminUsers)}
|
||||
</Badge>
|
||||
))}
|
||||
{getUsersByIds(service.assignedAdmin).length > 2 && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
+{getUsersByIds(service.assignedAdmin).length - 2}
|
||||
</Badge>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span className="text-xs text-gray-400">-</span>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{getUsersByIds(service.assignedCommon || "").length > 0 ? (
|
||||
<>
|
||||
{getUsersByIds(service.assignedCommon).slice(0, 2).map((userId) => (
|
||||
<Badge key={userId} variant="outline" className="text-xs">
|
||||
{getUserName(userId, commonUsers)}
|
||||
</Badge>
|
||||
))}
|
||||
{getUsersByIds(service.assignedCommon).length > 2 && (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
+{getUsersByIds(service.assignedCommon).length - 2}
|
||||
</Badge>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span className="text-xs text-gray-400">-</span>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>{service.createdTime || "-"}</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex space-x-2">
|
||||
<Button variant="outline" size="sm" onClick={() => openEditDialog(service)}>
|
||||
<Button variant="outline" size="sm" onClick={() => openEditDialog(service)} disabled={loading}>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" onClick={() => handleDeleteService(service.id)}>
|
||||
<Button variant="outline" size="sm" onClick={() => handleDeleteService(service.id)} disabled={loading}>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
{/* Pagination */}
|
||||
<div className="flex items-center justify-between mt-4">
|
||||
<div className="text-sm text-gray-600">
|
||||
共 {total} 条记录,第 {pageNum} / {totalPages || 1} 页
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handlePrevPage}
|
||||
disabled={pageNum === 1 || loading}
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4 mr-1" />
|
||||
上一页
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleNextPage}
|
||||
disabled={pageNum >= totalPages || loading}
|
||||
>
|
||||
下一页
|
||||
<ChevronRight className="h-4 w-4 ml-1" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -316,8 +497,8 @@ export default function ValueAddedServicesPage() {
|
||||
<Label htmlFor="edit-title">服务标题</Label>
|
||||
<Input
|
||||
id="edit-title"
|
||||
value={formData.title}
|
||||
onChange={(e) => setFormData({ ...formData, title: e.target.value })}
|
||||
value={formData.serviceTitle}
|
||||
onChange={(e) => setFormData({ ...formData, serviceTitle: e.target.value })}
|
||||
placeholder="请输入服务标题"
|
||||
/>
|
||||
</div>
|
||||
@@ -331,49 +512,96 @@ export default function ValueAddedServicesPage() {
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>分配总公司用户</Label>
|
||||
<div className="grid grid-cols-1 gap-2 mt-2 max-h-48 overflow-y-auto border rounded p-2">
|
||||
{adminUsers.map((user) => {
|
||||
const assignedIds = formData.assignedAdmin.split(",").filter(Boolean)
|
||||
const userId = user.userId
|
||||
return (
|
||||
<div key={userId} className="flex items-center space-x-2 p-2 border rounded">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`edit-admin-${userId}`}
|
||||
checked={assignedIds.includes(userId)}
|
||||
onChange={(e) => {
|
||||
const ids = formData.assignedAdmin.split(",").filter(Boolean)
|
||||
if (e.target.checked) {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedAdmin: [...ids, userId].join(","),
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedAdmin: ids.filter((id) => id !== userId).join(","),
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={`edit-admin-${userId}`} className="flex-1 cursor-pointer">
|
||||
<div className="flex justify-between">
|
||||
<span className="font-medium">{user.nickName || user.userName}</span>
|
||||
<span className="text-sm text-gray-500 flex items-center">
|
||||
<Phone className="h-3 w-3 mr-1" />
|
||||
{user.phonenumber}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>分配经销商</Label>
|
||||
<div className="grid grid-cols-1 gap-2 mt-2">
|
||||
{dealers.map((dealer) => (
|
||||
<div key={dealer.id} className="flex items-center space-x-2 p-2 border rounded">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`edit-${dealer.id}`}
|
||||
checked={formData.assignedDealers.includes(dealer.id)}
|
||||
onChange={(e) => {
|
||||
if (e.target.checked) {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedDealers: [...formData.assignedDealers, dealer.id],
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedDealers: formData.assignedDealers.filter((id) => id !== dealer.id),
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={`edit-${dealer.id}`} className="flex-1 cursor-pointer">
|
||||
<div className="grid grid-cols-1 gap-2 mt-2 max-h-48 overflow-y-auto border rounded p-2">
|
||||
{commonUsers.map((user) => {
|
||||
const assignedIds = formData.assignedCommon.split(",").filter(Boolean)
|
||||
const userId = user.userId
|
||||
return (
|
||||
<div key={userId} className="flex items-center space-x-2 p-2 border rounded">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`edit-common-${userId}`}
|
||||
checked={assignedIds.includes(userId)}
|
||||
onChange={(e) => {
|
||||
const ids = formData.assignedCommon.split(",").filter(Boolean)
|
||||
if (e.target.checked) {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedCommon: [...ids, userId].join(","),
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
...formData,
|
||||
assignedCommon: ids.filter((id) => id !== userId).join(","),
|
||||
})
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={`edit-common-${userId}`} className="flex-1 cursor-pointer">
|
||||
<div className="flex justify-between">
|
||||
<span className="font-medium">{dealer.name}</span>
|
||||
<span className="text-sm text-gray-500">{dealer.region}</span>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500 flex items-center">
|
||||
<span className="font-medium">{user.nickName || user.userName}</span>
|
||||
<span className="text-sm text-gray-500 flex items-center">
|
||||
<Phone className="h-3 w-3 mr-1" />
|
||||
{dealer.phone}
|
||||
{user.phonenumber}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setIsEditDialogOpen(false)}>
|
||||
<Button variant="outline" onClick={() => setIsEditDialogOpen(false)} disabled={loading}>
|
||||
取消
|
||||
</Button>
|
||||
<Button onClick={handleEditService}>保存修改</Button>
|
||||
<Button onClick={handleEditService} disabled={loading}>
|
||||
{loading ? "保存中..." : "保存修改"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
49
src/lib/services/service.ts
Normal file
49
src/lib/services/service.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
ServiceListParams,
|
||||
ServiceListResponse,
|
||||
ServiceCreateParams,
|
||||
ServiceUpdateParams,
|
||||
ServiceResponse
|
||||
} from '@/lib/types/service'
|
||||
import { apiGet, apiPost, apiPut, apiDelete } from './api'
|
||||
|
||||
export async function getServiceList(params: ServiceListParams): Promise<ServiceListResponse> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams({
|
||||
pageSize: params.pageSize.toString(),
|
||||
pageNum: params.pageNum.toString(),
|
||||
})
|
||||
return await apiGet<ServiceListResponse>(`/back/services/list?${queryParams}`)
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch services:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function createService(data: ServiceCreateParams): Promise<ServiceResponse> {
|
||||
try {
|
||||
return await apiPost<ServiceResponse>('/back/services/', data)
|
||||
} catch (error) {
|
||||
console.error('Failed to create service:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateService(data: ServiceUpdateParams): Promise<ServiceResponse> {
|
||||
try {
|
||||
return await apiPut<ServiceResponse>('/back/services/', data)
|
||||
} catch (error) {
|
||||
console.error('Failed to update service:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteService(id: string): Promise<ServiceResponse> {
|
||||
try {
|
||||
return await apiDelete<ServiceResponse>(`/back/services/${id}`)
|
||||
} catch (error) {
|
||||
console.error('Failed to delete service:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
12
src/lib/services/user.ts
Normal file
12
src/lib/services/user.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { UserByRoleResponse } from '@/lib/types/user'
|
||||
import { apiGet } from './api'
|
||||
|
||||
export async function getUserByRoleKey(roleKey: string): Promise<UserByRoleResponse> {
|
||||
try {
|
||||
return await apiGet<UserByRoleResponse>(`/back/user/getUserByRoleKey?roleKey=${roleKey}`)
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch users with role ${roleKey}:`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
45
src/lib/types/service.ts
Normal file
45
src/lib/types/service.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export interface ValueAddedService {
|
||||
id: string
|
||||
serviceTitle: string
|
||||
description: string
|
||||
status: string
|
||||
assignedAdmin: string
|
||||
assignedCommon: string
|
||||
createTime?: string
|
||||
updateTime?: string
|
||||
}
|
||||
|
||||
export interface ServiceListParams {
|
||||
pageSize: number
|
||||
pageNum: number
|
||||
}
|
||||
|
||||
export interface ServiceListResponse {
|
||||
code: number
|
||||
msg: string
|
||||
rows: ValueAddedService[]
|
||||
total: number
|
||||
}
|
||||
|
||||
export interface ServiceCreateParams {
|
||||
serviceTitle: string
|
||||
description: string
|
||||
status: string
|
||||
assignedAdmin: string
|
||||
assignedCommon: string
|
||||
}
|
||||
|
||||
export interface ServiceUpdateParams {
|
||||
id: string
|
||||
serviceTitle: string
|
||||
description: string
|
||||
status: string
|
||||
assignedAdmin: string
|
||||
assignedCommon: string
|
||||
}
|
||||
|
||||
export interface ServiceResponse {
|
||||
code: number
|
||||
msg: string
|
||||
data?: any
|
||||
}
|
||||
44
src/lib/types/user.ts
Normal file
44
src/lib/types/user.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
export interface User {
|
||||
createBy: string
|
||||
createTime: string
|
||||
updateBy: string | null
|
||||
updateTime: string | null
|
||||
remark: string | null
|
||||
userId: string
|
||||
deptId: string | null
|
||||
userName: string
|
||||
nickName: string
|
||||
email: string
|
||||
phonenumber: string
|
||||
sex: string
|
||||
avatar: string
|
||||
password: string
|
||||
status: string
|
||||
delFlag: string
|
||||
loginIp: string
|
||||
loginDate: string
|
||||
pwdUpdateDate: string | null
|
||||
dept: any
|
||||
roles: any[]
|
||||
roleIds: any
|
||||
postIds: any
|
||||
roleId: string | null
|
||||
roleName: string | null
|
||||
provinceCode: string
|
||||
parentId: string | null
|
||||
type: string | null
|
||||
mallId: string | null
|
||||
businessLicense: string | null
|
||||
businessType: string | null
|
||||
address: string | null
|
||||
provinceAddress: string | null
|
||||
shopAddress: string | null
|
||||
admin: boolean
|
||||
}
|
||||
|
||||
export interface UserByRoleResponse {
|
||||
msg: string
|
||||
code: number
|
||||
data: User[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user