【操盘手】 设备选择优化

This commit is contained in:
wong
2025-05-29 17:45:36 +08:00
parent 75d009b722
commit 91817b6a9b

View File

@@ -9,6 +9,8 @@ import { Avatar } from "@/components/ui/avatar"
import { Search } from "lucide-react"
import { Input } from "@/components/ui/input"
import { api } from "@/lib/api"
import { DeviceSelectionDialog } from "@/app/components/device-selection-dialog"
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"
interface Device {
id: string
@@ -30,66 +32,140 @@ interface TargetSettingsStepProps {
initialData?: any
}
export default function TargetSettingsStep({ onNext, onBack, initialData = {} }: TargetSettingsStepProps) {
export default function TargetSettingsStep({ onNext, onBack, initialData = {}, setDevices }: TargetSettingsStepProps & { setDevices: (ids: string[]) => void }) {
const [deviceList, setDeviceList] = useState<any[]>([])
const [selectedDeviceIds, setSelectedDeviceIds] = useState<string[]>(initialData.devices || [])
const [selectedDeviceIds, setSelectedDeviceIds] = useState<string[]>([])
const [search, setSearch] = useState("")
const [loading, setLoading] = useState(false)
const [deviceDialogOpen, setDeviceDialogOpen] = useState(false)
const [statusFilter, setStatusFilter] = useState("all")
// 每次弹窗打开时,同步主表单的 devices转为字符串数组
useEffect(() => {
if (deviceDialogOpen) {
const ids = Array.isArray(initialData.devices) ? initialData.devices.map(String) : [];
setSelectedDeviceIds(ids);
}
}, [deviceDialogOpen, initialData.devices])
useEffect(() => {
setLoading(true)
api.get('/v1/devices?page=1&limit=100').then(res => {
api.get('/v1/devices?page=1&limit=100').then((res: any) => {
setDeviceList(res.data?.list || [])
}).finally(() => setLoading(false))
}, [])
const filteredDevices = deviceList.filter(device =>
(device.memo || device.nickname || "").toLowerCase().includes(search.toLowerCase())
)
const toggleDevice = (id: string) => {
setSelectedDeviceIds(prev =>
prev.includes(id) ? prev.filter(did => did !== id) : [...prev, id]
)
}
const filteredDevices = deviceList.filter(device => {
const matchesSearch =
search === "" ||
(device.memo || device.nickname || "").toLowerCase().includes(search.toLowerCase()) ||
(device.imei || "").toLowerCase().includes(search.toLowerCase()) ||
(device.wechatId || "").toLowerCase().includes(search.toLowerCase())
const matchesStatus = statusFilter === "all" || (statusFilter === "online" ? device.alive === 1 : device.alive !== 1)
return matchesSearch && matchesStatus
})
const handleSubmit = () => {
onNext({
devices: selectedDeviceIds,
})
onNext({ devices: Array.isArray(initialData.devices) ? initialData.devices : [] })
}
// 弹窗内确认选择
const handleDialogConfirm = () => {
if (typeof setDevices === 'function') {
setDevices(selectedDeviceIds)
}
setDeviceDialogOpen(false)
}
return (
<div className="bg-white rounded-lg p-6 shadow-sm">
<h2 className="text-xl font-bold mb-6"></h2>
<div className="mb-4">
<Input placeholder="搜索设备" value={search} onChange={e => setSearch(e.target.value)} />
<div className="relative w-full">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<Input
placeholder="选择设备"
value={Array.isArray(initialData.devices) && initialData.devices.length > 0 ? `已选择${initialData.devices.length}个设备` : ''}
readOnly
className="pl-10 cursor-pointer"
onClick={() => setDeviceDialogOpen(true)}
/>
</div>
</div>
<div className="space-y-3 mt-4 max-h-80 overflow-y-auto">
{loading ? <div className="text-center text-gray-400 py-8">...</div> :
filteredDevices.map(device => (
<div key={device.id} className="flex items-center border rounded-lg px-4 py-2 mb-2 justify-between">
<div className="flex items-center gap-3">
<span className={`w-8 h-8 flex items-center justify-center rounded-full ${device.alive === 1 ? "bg-green-100 text-green-600" : "bg-gray-100 text-gray-400"}`}></span>
<div>
<div className="font-medium">{device.memo }</div>
<div className="text-xs text-gray-400">IMEI:{device.imei}</div>
<div className="text-xs text-gray-400">:{device.wechatId || "--"}{device.nickname || "--"}</div>
<div className={`text-xs ${device.alive === 1 ? "text-green-600" : "text-gray-400"}`}>{device.alive === 1 ? "在线" : "离线"}</div>
</div>
</div>
<Checkbox
checked={selectedDeviceIds.includes(device.id)}
onCheckedChange={() => toggleDevice(device.id)}
/>
</div>
))
}
{Array.isArray(initialData.devices) && initialData.devices.length === 0 ? (
<div className="text-gray-400"></div>
) : (
<div className="text-base text-gray-500">{Array.isArray(initialData.devices) ? initialData.devices.length : 0} </div>
)}
</div>
<div className="mt-8 flex justify-between">
<Button variant="outline" onClick={onBack}> </Button>
<Button onClick={handleSubmit} disabled={selectedDeviceIds.length === 0}> </Button>
</div>
{/* 设备选择弹窗 */}
<Dialog open={deviceDialogOpen} onOpenChange={setDeviceDialogOpen}>
<DialogContent className="max-w-xl w-full p-0">
<DialogTitle className="text-lg font-bold text-center mb-4"></DialogTitle>
<div className="p-6 pt-0">
<div className="flex items-center gap-2 mb-4">
<Input
placeholder="搜索设备IMEI/备注/微信号"
value={search}
onChange={e => setSearch(e.target.value)}
className="flex-1"
/>
<select
className="border rounded px-2 py-1 text-sm"
value={statusFilter}
onChange={e => setStatusFilter(e.target.value)}
>
<option value="all"></option>
<option value="online">线</option>
<option value="offline">线</option>
</select>
</div>
<div className="max-h-72 overflow-y-auto divide-y">
{loading ? (
<div className="text-center text-gray-400 py-8">...</div>
) : filteredDevices.length === 0 ? (
<div className="text-center text-gray-400 py-8"></div>
) : (
filteredDevices.map(device => (
<label
key={device.id}
className="flex items-center px-2 py-3 cursor-pointer hover:bg-gray-50"
>
<input
type="checkbox"
className="mr-3 accent-blue-500"
checked={selectedDeviceIds.includes(String(device.id))}
onChange={() => {
setSelectedDeviceIds(prev =>
prev.includes(String(device.id))
? prev.filter(id => id !== String(device.id))
: [...prev, String(device.id)]
)
}}
/>
<div className="flex-1">
<div className="font-medium text-base">{device.memo || device.nickname || device.name}</div>
<div className="text-xs text-gray-500">IMEI: {device.imei}</div>
<div className="text-xs text-gray-500">: {device.wechatId || '--'}{device.nickname || '--'}</div>
</div>
<span className={`ml-2 text-xs ${device.alive === 1 ? 'text-green-600' : 'text-gray-400'}`}>{device.alive === 1 ? '在线' : '离线'}</span>
</label>
))
)}
</div>
<div className="flex justify-end mt-6">
<Button className="w-full" onClick={handleDialogConfirm}>
</Button>
</div>
</div>
</DialogContent>
</Dialog>
</div>
)
}