工单类型
This commit is contained in:
@@ -32,7 +32,6 @@ interface UserData {
|
||||
userId: string
|
||||
userName: string
|
||||
nickName: string
|
||||
email: string
|
||||
phonenumber: string
|
||||
status: string
|
||||
loginDate: string
|
||||
@@ -189,7 +188,6 @@ export default function CompanyPermissionsPage() {
|
||||
const matchesSearch =
|
||||
user.nickName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
user.userName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
user.email.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
(user.dept?.deptName || "").toLowerCase().includes(searchTerm.toLowerCase())
|
||||
|
||||
const matchesStatus = statusFilter === "all" ||
|
||||
@@ -264,10 +262,7 @@ export default function CompanyPermissionsPage() {
|
||||
</TableCell>
|
||||
<TableCell>{user.dept?.deptName || '-'}</TableCell>
|
||||
<TableCell>
|
||||
<div>
|
||||
<div className="text-sm">{user.email || '-'}</div>
|
||||
<div className="text-sm text-gray-500">{user.phonenumber || '-'}</div>
|
||||
</div>
|
||||
<div className="text-sm">{user.phonenumber || '-'}</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="text-sm">
|
||||
@@ -354,7 +349,7 @@ export default function CompanyPermissionsPage() {
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
|
||||
<Input
|
||||
placeholder="搜索用户名、姓名、邮箱或部门..."
|
||||
placeholder="搜索用户名、姓名或部门..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="pl-10"
|
||||
@@ -438,7 +433,6 @@ function CreateUserForm({ roles, onClose }: { roles: Role[]; onClose: () => void
|
||||
const [formData, setFormData] = useState({
|
||||
username: "",
|
||||
name: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
role: "",
|
||||
department: "",
|
||||
@@ -500,7 +494,6 @@ function CreateUserForm({ roles, onClose }: { roles: Role[]; onClose: () => void
|
||||
nickName: formData.name,
|
||||
password: formData.password,
|
||||
phonenumber: formData.phone,
|
||||
email: formData.email,
|
||||
sex: "0",
|
||||
status: "0",
|
||||
remark: formData.department || "",
|
||||
@@ -564,18 +557,6 @@ function CreateUserForm({ roles, onClose }: { roles: Role[]; onClose: () => void
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email">邮箱</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
value={formData.email}
|
||||
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
|
||||
placeholder="请输入邮箱地址"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="phone">手机号</Label>
|
||||
<Input
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../ui/dialog"
|
||||
import { Plus, Filter, Download, MapPin, Calendar, Shield, ChevronLeft, ChevronRight } from "lucide-react"
|
||||
import { Plus, Filter, Download, MapPin, Calendar, Shield, ChevronLeft, ChevronRight, Minus, Plus as PlusIcon } from "lucide-react"
|
||||
import { apiGet, apiPost, apiPut } from "../../lib/services/api"
|
||||
|
||||
// 商户数据类型(根据新接口返回格式定义)
|
||||
@@ -60,6 +60,7 @@ interface Equipment {
|
||||
mallName: string
|
||||
installationLocation: string
|
||||
installationDate: string
|
||||
nextInspectionDate: string
|
||||
status: string
|
||||
remarks: string
|
||||
createdBy: string
|
||||
@@ -201,6 +202,7 @@ export default function EquipmentPage() {
|
||||
merchantId: "",
|
||||
location: "",
|
||||
installDate: "",
|
||||
nextInspectionDate: "",
|
||||
status: "normal",
|
||||
notes: "",
|
||||
})
|
||||
@@ -213,10 +215,71 @@ export default function EquipmentPage() {
|
||||
merchantId: "",
|
||||
location: "",
|
||||
installDate: "",
|
||||
nextInspectionDate: "",
|
||||
status: "normal",
|
||||
notes: "",
|
||||
})
|
||||
|
||||
// 调整下一次检测日期(添加设备)
|
||||
const adjustNextInspectionDate = (years: number) => {
|
||||
if (!newEquipment.nextInspectionDate) {
|
||||
// 如果没有下次检测日期,使用安装日期或当前日期作为基准
|
||||
const baseDate = newEquipment.installDate ? new Date(newEquipment.installDate) : new Date()
|
||||
baseDate.setFullYear(baseDate.getFullYear() + years)
|
||||
const newDateStr = baseDate.toISOString().split('T')[0]
|
||||
|
||||
// 检查是否小于安装日期
|
||||
if (newEquipment.installDate && newDateStr < newEquipment.installDate) {
|
||||
alert('下一次检测时间不能小于安装日期')
|
||||
return
|
||||
}
|
||||
|
||||
setNewEquipment({ ...newEquipment, nextInspectionDate: newDateStr })
|
||||
} else {
|
||||
const currentDate = new Date(newEquipment.nextInspectionDate)
|
||||
currentDate.setFullYear(currentDate.getFullYear() + years)
|
||||
const newDateStr = currentDate.toISOString().split('T')[0]
|
||||
|
||||
// 检查是否小于安装日期
|
||||
if (newEquipment.installDate && newDateStr < newEquipment.installDate) {
|
||||
alert('下一次检测时间不能小于安装日期')
|
||||
return
|
||||
}
|
||||
|
||||
setNewEquipment({ ...newEquipment, nextInspectionDate: newDateStr })
|
||||
}
|
||||
}
|
||||
|
||||
// 调整下一次检测日期(编辑设备)
|
||||
const adjustEditNextInspectionDate = (years: number) => {
|
||||
if (!editEquipment.nextInspectionDate) {
|
||||
// 如果没有下次检测日期,使用安装日期或当前日期作为基准
|
||||
const baseDate = editEquipment.installDate ? new Date(editEquipment.installDate) : new Date()
|
||||
baseDate.setFullYear(baseDate.getFullYear() + years)
|
||||
const newDateStr = baseDate.toISOString().split('T')[0]
|
||||
|
||||
// 检查是否小于安装日期
|
||||
if (editEquipment.installDate && newDateStr < editEquipment.installDate) {
|
||||
alert('下一次检测时间不能小于安装日期')
|
||||
return
|
||||
}
|
||||
|
||||
setEditEquipment({ ...editEquipment, nextInspectionDate: newDateStr })
|
||||
} else {
|
||||
const currentDate = new Date(editEquipment.nextInspectionDate)
|
||||
currentDate.setFullYear(currentDate.getFullYear() + years)
|
||||
const newDateStr = currentDate.toISOString().split('T')[0]
|
||||
|
||||
// 检查是否小于安装日期
|
||||
if (editEquipment.installDate && newDateStr < editEquipment.installDate) {
|
||||
alert('下一次检测时间不能小于安装日期')
|
||||
return
|
||||
}
|
||||
|
||||
setEditEquipment({ ...editEquipment, nextInspectionDate: newDateStr })
|
||||
}
|
||||
}
|
||||
|
||||
// 打开编辑对话框
|
||||
const handleEditEquipment = (equipment: Equipment) => {
|
||||
setEditEquipment({
|
||||
@@ -227,6 +290,7 @@ export default function EquipmentPage() {
|
||||
merchantId: equipment.merchantId || "",
|
||||
location: equipment.installationLocation || "",
|
||||
installDate: equipment.installationDate || "",
|
||||
nextInspectionDate: equipment.nextInspectionDate || "",
|
||||
status: equipment.status === "1" ? "normal" : equipment.status === "2" ? "expiring" : "expired",
|
||||
notes: equipment.remarks || "",
|
||||
})
|
||||
@@ -247,6 +311,16 @@ export default function EquipmentPage() {
|
||||
return
|
||||
}
|
||||
|
||||
// 验证下一次检测时间不能小于安装日期
|
||||
if (editEquipment.nextInspectionDate && editEquipment.installDate) {
|
||||
const nextDate = new Date(editEquipment.nextInspectionDate)
|
||||
const installDate = new Date(editEquipment.installDate)
|
||||
if (nextDate < installDate) {
|
||||
alert('下一次检测时间不能小于安装日期')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setIsSubmitting(true)
|
||||
|
||||
try {
|
||||
@@ -258,6 +332,7 @@ export default function EquipmentPage() {
|
||||
merchantId: editEquipment.merchantId,
|
||||
installationLocation: editEquipment.location,
|
||||
installationDate: editEquipment.installDate,
|
||||
nextInspectionDate: editEquipment.nextInspectionDate,
|
||||
status: editEquipment.status === 'normal' ? 1 : editEquipment.status === 'expiring' ? 2 : 3,
|
||||
remarks: editEquipment.notes,
|
||||
}
|
||||
@@ -289,6 +364,16 @@ export default function EquipmentPage() {
|
||||
return
|
||||
}
|
||||
|
||||
// 验证下一次检测时间不能小于安装日期
|
||||
if (newEquipment.nextInspectionDate && newEquipment.installDate) {
|
||||
const nextDate = new Date(newEquipment.nextInspectionDate)
|
||||
const installDate = new Date(newEquipment.installDate)
|
||||
if (nextDate < installDate) {
|
||||
alert('下一次检测时间不能小于安装日期')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setIsSubmitting(true)
|
||||
|
||||
try {
|
||||
@@ -300,6 +385,7 @@ export default function EquipmentPage() {
|
||||
merchantId: newEquipment.merchantId,
|
||||
installationLocation: newEquipment.location,
|
||||
installationDate: newEquipment.installDate,
|
||||
nextInspectionDate: newEquipment.nextInspectionDate,
|
||||
status: newEquipment.status === 'normal' ? 1 : newEquipment.status === 'expiring' ? 2 : 3,
|
||||
remarks: newEquipment.notes,
|
||||
createdBy: "admin" // 可以从用户上下文获取
|
||||
@@ -322,6 +408,7 @@ export default function EquipmentPage() {
|
||||
merchantId: "",
|
||||
location: "",
|
||||
installDate: "",
|
||||
nextInspectionDate: "",
|
||||
status: "normal",
|
||||
notes: "",
|
||||
})
|
||||
@@ -421,12 +508,12 @@ export default function EquipmentPage() {
|
||||
添加设备
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>添加新设备</DialogTitle>
|
||||
<DialogDescription>填写设备基本信息和安装详情</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-2 gap-x-6 gap-y-5 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="equipmentName">设备名称</Label>
|
||||
<Input
|
||||
@@ -515,9 +602,53 @@ export default function EquipmentPage() {
|
||||
id="installDate"
|
||||
type="date"
|
||||
value={newEquipment.installDate}
|
||||
onChange={(e) => setNewEquipment({ ...newEquipment, installDate: e.target.value })}
|
||||
onChange={(e) => {
|
||||
const installDate = e.target.value
|
||||
setNewEquipment({ ...newEquipment, installDate })
|
||||
|
||||
// 自动填充下一次检测时间(安装日期+1年)
|
||||
if (installDate && !newEquipment.nextInspectionDate) {
|
||||
const nextDate = new Date(installDate)
|
||||
nextDate.setFullYear(nextDate.getFullYear() + 1)
|
||||
const nextDateStr = nextDate.toISOString().split('T')[0]
|
||||
setNewEquipment(prev => ({ ...prev, nextInspectionDate: nextDateStr }))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 space-y-2">
|
||||
<Label htmlFor="nextInspectionDate">下一次检测时间</Label>
|
||||
<div className="flex gap-2 max-w-md">
|
||||
<Input
|
||||
id="nextInspectionDate"
|
||||
type="date"
|
||||
value={newEquipment.nextInspectionDate}
|
||||
min={newEquipment.installDate || undefined}
|
||||
onChange={(e) => setNewEquipment({ ...newEquipment, nextInspectionDate: e.target.value })}
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => adjustNextInspectionDate(-1)}
|
||||
title="上一年"
|
||||
className="px-3"
|
||||
>
|
||||
<Minus className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => adjustNextInspectionDate(1)}
|
||||
title="下一年"
|
||||
className="px-3"
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="status">设备状态</Label>
|
||||
<Select
|
||||
@@ -565,12 +696,12 @@ export default function EquipmentPage() {
|
||||
|
||||
{/* 编辑设备对话框 */}
|
||||
<Dialog open={isEditEquipmentOpen} onOpenChange={setIsEditEquipmentOpen}>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>编辑设备</DialogTitle>
|
||||
<DialogDescription>修改设备基本信息和安装详情</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-2 gap-x-6 gap-y-5 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="edit-equipmentName">设备名称</Label>
|
||||
<Input
|
||||
@@ -642,9 +773,53 @@ export default function EquipmentPage() {
|
||||
id="edit-installDate"
|
||||
type="date"
|
||||
value={editEquipment.installDate}
|
||||
onChange={(e) => setEditEquipment({ ...editEquipment, installDate: e.target.value })}
|
||||
onChange={(e) => {
|
||||
const installDate = e.target.value
|
||||
setEditEquipment({ ...editEquipment, installDate })
|
||||
|
||||
// 自动填充下一次检测时间(安装日期+1年)
|
||||
if (installDate && !editEquipment.nextInspectionDate) {
|
||||
const nextDate = new Date(installDate)
|
||||
nextDate.setFullYear(nextDate.getFullYear() + 1)
|
||||
const nextDateStr = nextDate.toISOString().split('T')[0]
|
||||
setEditEquipment(prev => ({ ...prev, nextInspectionDate: nextDateStr }))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-2 space-y-2">
|
||||
<Label htmlFor="edit-nextInspectionDate">下一次检测时间</Label>
|
||||
<div className="flex gap-2 max-w-md">
|
||||
<Input
|
||||
id="edit-nextInspectionDate"
|
||||
type="date"
|
||||
value={editEquipment.nextInspectionDate}
|
||||
min={editEquipment.installDate || undefined}
|
||||
onChange={(e) => setEditEquipment({ ...editEquipment, nextInspectionDate: e.target.value })}
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => adjustEditNextInspectionDate(-1)}
|
||||
title="上一年"
|
||||
className="px-3"
|
||||
>
|
||||
<Minus className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => adjustEditNextInspectionDate(1)}
|
||||
title="下一年"
|
||||
className="px-3"
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="edit-status">设备状态</Label>
|
||||
<Select
|
||||
@@ -842,9 +1017,21 @@ export default function EquipmentPage() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="space-y-1">
|
||||
{item.installationDate && (
|
||||
<div className="flex items-center text-sm">
|
||||
<Calendar className="h-3 w-3 mr-1 text-blue-600" />
|
||||
<span className="text-blue-600">创建: {item.createdAt}</span>
|
||||
<Calendar className="h-3 w-3 mr-1 text-orange-600" />
|
||||
<span className="text-orange-600">上次检测: {item.installationDate}</span>
|
||||
</div>
|
||||
)}
|
||||
{item.nextInspectionDate && (
|
||||
<div className="flex items-center text-sm">
|
||||
<Calendar className="h-3 w-3 mr-1 text-green-600" />
|
||||
<span className="text-green-600">下次检测: {item.nextInspectionDate}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center text-xs text-gray-500">
|
||||
<Calendar className="h-3 w-3 mr-1" />
|
||||
创建: {item.createdAt}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">更新: {item.updatedAt}</div>
|
||||
</div>
|
||||
|
||||
@@ -574,7 +574,7 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
merchantId: "",
|
||||
equipmentId: "",
|
||||
type: "",
|
||||
assignee: "",
|
||||
assignee: [] as string[], // 改为数组支持多选
|
||||
description: "",
|
||||
})
|
||||
|
||||
@@ -586,6 +586,7 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
const [loadingEquipment, setLoadingEquipment] = useState(false)
|
||||
const [loadingWorkers, setLoadingWorkers] = useState(false)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [isWorkerSelectOpen, setIsWorkerSelectOpen] = useState(false)
|
||||
|
||||
// 获取商户列表
|
||||
const fetchMerchants = async () => {
|
||||
@@ -637,6 +638,23 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
}
|
||||
}
|
||||
|
||||
// 点击外部关闭下拉框
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (isWorkerSelectOpen) {
|
||||
const target = event.target as HTMLElement
|
||||
if (!target.closest('.worker-select-container')) {
|
||||
setIsWorkerSelectOpen(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside)
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside)
|
||||
}
|
||||
}, [isWorkerSelectOpen])
|
||||
|
||||
const handleMerchantChange = (merchantId: string) => {
|
||||
console.log('选择商户,ID:', merchantId)
|
||||
setSelectedMerchant(merchantId)
|
||||
@@ -686,9 +704,34 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
return ["故障检测", "故障维修", "设备安装", "预防性维护", "设备改造", "设备拆除", "更换药剂"]
|
||||
}
|
||||
|
||||
// 切换工人选择
|
||||
const toggleWorkerSelection = (workerId: string) => {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
assignee: prev.assignee.includes(workerId)
|
||||
? prev.assignee.filter(id => id !== workerId)
|
||||
: [...prev.assignee, workerId]
|
||||
}))
|
||||
}
|
||||
|
||||
// 获取选中工人的显示文本
|
||||
const getSelectedWorkersText = () => {
|
||||
if (formData.assignee.length === 0) return "选择维修工人"
|
||||
if (formData.assignee.length === 1) {
|
||||
const worker = workers.find(w => w.id === formData.assignee[0])
|
||||
return worker ? worker.name : "1位工人"
|
||||
}
|
||||
return `已选择 ${formData.assignee.length} 位工人`
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (formData.assignee.length === 0) {
|
||||
alert('请至少选择一位工人')
|
||||
return
|
||||
}
|
||||
|
||||
setSubmitting(true)
|
||||
|
||||
try {
|
||||
@@ -696,22 +739,31 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
const selectedMerchantObj = merchants.find(m => m.id === selectedMerchant)
|
||||
// 找到选中的设备信息
|
||||
const selectedEquipmentObj = availableEquipment.find(e => e.equipmentId === formData.equipmentId)
|
||||
// 找到选中的工人信息
|
||||
const selectedWorkerObj = workers.find(w => w.id === formData.assignee)
|
||||
// 找到所有选中的工人信息
|
||||
const selectedWorkers = workers.filter(w => formData.assignee.includes(w.id))
|
||||
|
||||
if (!selectedMerchantObj || !selectedEquipmentObj || !selectedWorkerObj) {
|
||||
if (!selectedMerchantObj || !selectedEquipmentObj || selectedWorkers.length === 0) {
|
||||
alert('无法获取完整的商户、设备或工人信息')
|
||||
return
|
||||
}
|
||||
|
||||
// 拼接工人ID(使用逗号分隔)
|
||||
const workersIds = selectedWorkers.map(w => w.workersId || "").join(",")
|
||||
// 拼接工人名称(使用逗号分隔)
|
||||
const workerNames = selectedWorkers.map(w => w.name).join(",")
|
||||
// 拼接工人电话(使用逗号分隔)
|
||||
const workerPhones = selectedWorkers.map(w => w.phone).join(",")
|
||||
// 使用第一个工人的经销商ID
|
||||
const distributorUserId = selectedWorkers[0].distributorUserId || ""
|
||||
|
||||
// 生成工单编号
|
||||
const workOrderNumber = `WO${new Date().getFullYear()}${(new Date().getMonth() + 1).toString().padStart(2, '0')}${new Date().getDate().toString().padStart(2, '0')}${Date.now().toString().slice(-4)}`
|
||||
|
||||
// 构建API请求数据
|
||||
const requestData = {
|
||||
merchantUserId: selectedMerchantObj.merchantsId || "",
|
||||
distributorUserId: selectedWorkerObj.distributorUserId || "",
|
||||
workersId: selectedWorkerObj.workersId || "",
|
||||
distributorUserId: distributorUserId,
|
||||
workersId: workersIds, // 拼接的工人ID
|
||||
workOrderNumber: workOrderNumber,
|
||||
workOrderType: formData.type,
|
||||
workOrderSubtype: "", // 暂时为空
|
||||
@@ -724,13 +776,15 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
merchantDistrict: selectedMerchantObj.district || "",
|
||||
responsiblePerson: selectedMerchantObj.contactPerson,
|
||||
responsibleVirtualPhone: selectedMerchantObj.contactPhone,
|
||||
workerVirtualPhone: selectedWorkerObj.phone,
|
||||
workerName: selectedWorkerObj.name,
|
||||
workerVirtualPhone: workerPhones, // 拼接的工人电话
|
||||
workerName: workerNames, // 拼接的工人名称
|
||||
createdDate: new Date().toISOString().split('T')[0],
|
||||
completedDate: ""
|
||||
}
|
||||
|
||||
console.log('创建工单请求数据:', requestData)
|
||||
console.log('选中的工人数量:', selectedWorkers.length)
|
||||
console.log('工人ID拼接结果:', workersIds)
|
||||
|
||||
const response = await apiPost('/back/orders', requestData)
|
||||
|
||||
@@ -834,27 +888,58 @@ function CreateWorkOrderForm({ onClose }: { onClose: () => void }) {
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="assignee">分配工人</Label>
|
||||
<Select
|
||||
value={formData.assignee}
|
||||
onValueChange={(value) => setFormData({ ...formData, assignee: value })}
|
||||
onOpenChange={(open) => {
|
||||
if (open && workers.length === 0 && !loadingWorkers) {
|
||||
<Label htmlFor="assignee">分配工人(可多选)</Label>
|
||||
<div className="relative worker-select-container">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
className="w-full justify-between"
|
||||
onClick={() => {
|
||||
setIsWorkerSelectOpen(!isWorkerSelectOpen)
|
||||
if (!isWorkerSelectOpen && workers.length === 0 && !loadingWorkers) {
|
||||
fetchWorkers()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={loadingWorkers ? "加载中..." : "选择维修工人"} />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="max-h-[300px] overflow-y-auto">
|
||||
<span className="truncate">{loadingWorkers ? "加载中..." : getSelectedWorkersText()}</span>
|
||||
<ChevronRight className={`h-4 w-4 ml-2 transition-transform ${isWorkerSelectOpen ? 'rotate-90' : ''}`} />
|
||||
</Button>
|
||||
{isWorkerSelectOpen && (
|
||||
<div className="absolute z-50 w-full mt-1 bg-white border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{workers.length === 0 ? (
|
||||
<div className="p-4 text-center text-gray-500">暂无工人数据</div>
|
||||
) : (
|
||||
<div className="p-2">
|
||||
{workers.map((worker) => (
|
||||
<SelectItem key={worker.id} value={worker.id}>
|
||||
<div
|
||||
key={worker.id}
|
||||
className="flex items-center space-x-2 p-2 hover:bg-gray-100 rounded cursor-pointer"
|
||||
onClick={() => toggleWorkerSelection(worker.id)}
|
||||
>
|
||||
<div className={`w-4 h-4 border rounded flex items-center justify-center ${
|
||||
formData.assignee.includes(worker.id) ? 'bg-blue-600 border-blue-600' : 'border-gray-300'
|
||||
}`}>
|
||||
{formData.assignee.includes(worker.id) && (
|
||||
<svg className="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
<span className="text-sm flex-1">
|
||||
{worker.name} - {worker.province} ({worker.phone})
|
||||
</SelectItem>
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{formData.assignee.length > 0 && (
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
已选择: {workers.filter(w => formData.assignee.includes(w.id)).map(w => w.name).join(", ")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user