fix: 恢复弹窗条件表格、筛选改为下拉+搜索混合、删除月列
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

- 恢复弹窗条件判断:customer源用13列详情表格(删除月列),
  其他源用简洁表格(车牌/品牌/车型/所在地)
- 保留w-max和whitespace-nowrap修复移动端水平滚动
- 筛选控件:枚举值少的用select下拉(区域/城市/品牌/部门/
  车型/批次/业务员),名称类用input+datalist支持模糊搜索
  (客户名称/业务负责人/车牌/库存车型)
- 客户详情表格删除"月"列(原显示contractNo,无实际意义)
- 恢复模糊匹配:车牌搜索和客户/负责人筛选用includes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-03-28 19:49:40 +08:00
parent 93a6c7df1c
commit 3e3546f6ac

View File

@@ -356,10 +356,10 @@ export default function App() {
// Filtered modal vehicles based on modal filters // Filtered modal vehicles based on modal filters
const filteredModalVehicles = modalVehicles.filter((v) => { const filteredModalVehicles = modalVehicles.filter((v) => {
const mp = !modalFilters.plateNumber || v.plateNumber.toLowerCase().includes(modalFilters.plateNumber.toLowerCase()) || v.vin.toLowerCase().includes(modalFilters.plateNumber.toLowerCase()); const mp = !modalFilters.plateNumber || (v.plateNumber || v.vin || '').toLowerCase().includes(modalFilters.plateNumber.toLowerCase());
const mm = !modalFilters.model || v.model.toLowerCase().includes(modalFilters.model.toLowerCase()); const mm = !modalFilters.model || v.model === modalFilters.model;
const mb = !modalFilters.brand || (v.brandLabel || '').toLowerCase().includes(modalFilters.brand.toLowerCase()); const mb = !modalFilters.brand || v.brandLabel === modalFilters.brand;
const ml = !modalFilters.location || v.location.toLowerCase().includes(modalFilters.location.toLowerCase()); const ml = !modalFilters.location || v.location === modalFilters.location;
return mp && mm && mb && ml; return mp && mm && mb && ml;
}); });
@@ -936,75 +936,38 @@ export default function App() {
<div className="space-y-3 text-left"> <div className="space-y-3 text-left">
<div> <div>
<label className="text-[10px] text-slate-400 block mb-1"></label> <label className="text-[10px] text-slate-400 block mb-1"></label>
<input <select value={inventoryFilters.region} onChange={(e) => setInventoryFilters({...inventoryFilters, region: e.target.value})} className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
list="dl-inv-region" <option value=""></option>
type="text" {uniqueInventoryRegions.map(r => <option key={r} value={r}>{r}</option>)}
placeholder="搜索或选择..." </select>
value={inventoryFilters.region}
onChange={(e) => setInventoryFilters({...inventoryFilters, region: e.target.value})}
className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-inv-region">
{uniqueInventoryRegions.map(r => <option key={r} value={r} />)}
</datalist>
</div> </div>
<div> <div>
<label className="text-[10px] text-slate-400 block mb-1"></label> <label className="text-[10px] text-slate-400 block mb-1"></label>
<input <select value={inventoryFilters.city} onChange={(e) => setInventoryFilters({...inventoryFilters, city: e.target.value})} className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
list="dl-inv-city" <option value=""></option>
type="text" {uniqueInventoryCities.map(c => <option key={c} value={c}>{c}</option>)}
placeholder="搜索或选择..." </select>
value={inventoryFilters.city}
onChange={(e) => setInventoryFilters({...inventoryFilters, city: e.target.value})}
className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-inv-city">
{uniqueInventoryCities.map(c => <option key={c} value={c} />)}
</datalist>
</div> </div>
<div> <div>
<label className="text-[10px] text-slate-400 block mb-1"></label> <label className="text-[10px] text-slate-400 block mb-1"></label>
<input <select value={inventoryFilters.brand} onChange={(e) => setInventoryFilters({...inventoryFilters, brand: e.target.value})} className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
list="dl-inv-brand" <option value=""></option>
type="text" {uniqueInventoryBrands.map(b => <option key={b} value={b}>{b}</option>)}
placeholder="搜索或选择..." </select>
value={inventoryFilters.brand}
onChange={(e) => setInventoryFilters({...inventoryFilters, brand: e.target.value})}
className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-inv-brand">
{uniqueInventoryBrands.map(b => <option key={b} value={b} />)}
</datalist>
</div> </div>
<div> <div>
<label className="text-[10px] text-slate-400 block mb-1"></label> <label className="text-[10px] text-slate-400 block mb-1"></label>
<input <select value={inventoryFilters.batch} onChange={(e) => setInventoryFilters({...inventoryFilters, batch: e.target.value})} className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
list="dl-inv-batch" <option value=""></option>
type="text" {uniqueInventoryBatches.map(b => <option key={b} value={b}>{b}</option>)}
placeholder="搜索或选择..." </select>
value={inventoryFilters.batch}
onChange={(e) => setInventoryFilters({...inventoryFilters, batch: e.target.value})}
className="w-full text-xs bg-white border border-slate-200 rounded-lg px-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-inv-batch">
{uniqueInventoryBatches.map(b => <option key={b} value={b} />)}
</datalist>
</div> </div>
<div> <div>
<label className="text-[10px] text-slate-400 block mb-1"></label> <label className="text-[10px] text-slate-400 block mb-1"></label>
<div className="relative"> <div className="relative">
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-slate-400" /> <Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-slate-400" />
<input <input type="text" list="dl-inv-model" placeholder="搜索车型..." value={inventoryFilters.model} onChange={(e) => setInventoryFilters({...inventoryFilters, model: e.target.value})} className="w-full text-xs bg-white border border-slate-200 rounded-lg pl-7 pr-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm" />
list="dl-inv-model" <datalist id="dl-inv-model">{uniqueInventoryModels.map(m => <option key={m} value={m} />)}</datalist>
type="text"
placeholder="搜索车型..."
value={inventoryFilters.model}
onChange={(e) => setInventoryFilters({...inventoryFilters, model: e.target.value})}
className="w-full text-xs bg-white border border-slate-200 rounded-lg pl-7 pr-2 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-inv-model">
{uniqueInventoryModels.map(m => <option key={m} value={m} />)}
</datalist>
</div> </div>
</div> </div>
</div> </div>
@@ -1353,21 +1316,18 @@ export default function App() {
<div className="flex-1 max-w-[240px]"> <div className="flex-1 max-w-[240px]">
{deptViewMode === 'manager' && ( {deptViewMode === 'manager' && (
<div className="relative"> <div className="relative">
<Filter className="absolute left-2.5 top-1/2 -translate-y-1/2 text-gray-400" size={14} /> <Filter className="absolute left-2.5 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none" size={14} />
<input <select
list="dl-dept-manager" value={selectedManager}
type="text" onChange={(e) => setSelectedManager(e.target.value)}
placeholder="搜索或选择..." className="w-full pl-9 pr-8 py-1.5 bg-white border border-gray-200 rounded-lg text-xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm appearance-none cursor-pointer font-bold text-gray-700"
value={selectedManager === 'All' ? '' : selectedManager} >
onChange={(e) => setSelectedManager(e.target.value || 'All')} <option value="All"></option>
className="w-full pl-9 pr-8 py-1.5 bg-white border border-gray-200 rounded-lg text-xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm font-bold text-gray-700"
/>
<datalist id="dl-dept-manager">
<option value="All"></option>
{allManagersList.map(m => ( {allManagersList.map(m => (
<option key={m} value={m} /> <option key={m} value={m}>{m}</option>
))} ))}
</datalist> </select>
<ChevronDown className="absolute right-2.5 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none" size={14} />
</div> </div>
)} )}
</div> </div>
@@ -1923,48 +1883,25 @@ export default function App() {
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<div className="relative"> <div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" size={14} /> <Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" size={14} />
<input <input type="text" list="dl-region-customer" placeholder="搜索客户名称..." className="w-full bg-white border border-gray-200 rounded-lg py-2 pl-9 pr-3 text-xs focus:ring-2 focus:ring-slate-500/20 focus:border-slate-500 outline-none transition-all shadow-sm" value={regionFilters.customer} onChange={(e) => setRegionFilters(prev => ({ ...prev, customer: e.target.value }))} />
list="dl-region-customer" <datalist id="dl-region-customer">{uniqueCustomerNames.map(c => <option key={c} value={c} />)}</datalist>
type="text"
placeholder="搜索客户名称..."
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 pl-9 pr-3 text-xs focus:ring-2 focus:ring-slate-500/20 focus:border-slate-500 outline-none transition-all"
value={regionFilters.customer}
onChange={(e) => setRegionFilters(prev => ({ ...prev, customer: e.target.value }))}
/>
<datalist id="dl-region-customer">
{uniqueCustomerNames.map(c => <option key={c} value={c} />)}
</datalist>
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<input <select className="w-full bg-white border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-slate-500/20 focus:border-slate-500 outline-none transition-all cursor-pointer shadow-sm" value={regionFilters.region} onChange={(e) => setRegionFilters(prev => ({ ...prev, region: e.target.value }))}>
list="dl-region-region" <option value=""></option>
type="text" {uniqueRegions.map(r => <option key={r} value={r}>{r}</option>)}
placeholder="搜索或选择..." </select>
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-slate-500/20 focus:border-slate-500 outline-none transition-all"
value={regionFilters.region}
onChange={(e) => setRegionFilters(prev => ({ ...prev, region: e.target.value }))}
/>
<datalist id="dl-region-region">
{uniqueRegions.map(r => <option key={r} value={r} />)}
</datalist>
</div> </div>
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<input <select className="w-full bg-white border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-slate-500/20 focus:border-slate-500 outline-none transition-all cursor-pointer shadow-sm" value={regionFilters.city} onChange={(e) => setRegionFilters(prev => ({ ...prev, city: e.target.value }))}>
list="dl-region-city" <option value=""></option>
type="text" {uniqueCities.map(c => <option key={c} value={c}>{c}</option>)}
placeholder="搜索或选择..." </select>
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-slate-500/20 focus:border-slate-500 outline-none transition-all"
value={regionFilters.city}
onChange={(e) => setRegionFilters(prev => ({ ...prev, city: e.target.value }))}
/>
<datalist id="dl-region-city">
{uniqueCities.map(c => <option key={c} value={c} />)}
</datalist>
</div> </div>
</div> </div>
</div> </div>
@@ -2267,17 +2204,8 @@ export default function App() {
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<div className="relative"> <div className="relative">
<Search className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" size={12} /> <Search className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" size={12} />
<input <input type="text" list="dl-cust-customer" placeholder="搜索客户..." className="w-full bg-white border border-gray-200 rounded-lg py-2 pl-8 pr-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all shadow-sm" value={customerFilters.customer} onChange={(e) => setCustomerFilters(prev => ({ ...prev, customer: e.target.value }))} />
list="dl-cust-customer" <datalist id="dl-cust-customer">{uniqueCustomerNames.map(c => <option key={c} value={c} />)}</datalist>
type="text"
placeholder="搜索客户..."
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 pl-8 pr-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all"
value={customerFilters.customer}
onChange={(e) => setCustomerFilters(prev => ({ ...prev, customer: e.target.value }))}
/>
<datalist id="dl-cust-customer">
{uniqueCustomerNames.map(c => <option key={c} value={c} />)}
</datalist>
</div> </div>
</div> </div>
@@ -2285,62 +2213,32 @@ export default function App() {
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<div className="relative"> <div className="relative">
<Search className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" size={12} /> <Search className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" size={12} />
<input <input type="text" list="dl-cust-manager" placeholder="搜索负责人..." className="w-full bg-white border border-gray-200 rounded-lg py-2 pl-8 pr-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all shadow-sm" value={customerFilters.manager} onChange={(e) => setCustomerFilters(prev => ({ ...prev, manager: e.target.value }))} />
list="dl-cust-manager" <datalist id="dl-cust-manager">{uniqueCustomerManagers.map(m => <option key={m} value={m} />)}</datalist>
type="text"
placeholder="搜索负责人..."
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 pl-8 pr-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all"
value={customerFilters.manager}
onChange={(e) => setCustomerFilters(prev => ({ ...prev, manager: e.target.value }))}
/>
<datalist id="dl-cust-manager">
{uniqueCustomerManagers.map(m => <option key={m} value={m} />)}
</datalist>
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<input <select className="w-full bg-white border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all cursor-pointer shadow-sm" value={customerFilters.brand} onChange={(e) => setCustomerFilters(prev => ({ ...prev, brand: e.target.value }))}>
list="dl-cust-brand" <option value=""></option>
type="text" {uniqueBrands.map(b => <option key={b} value={b}>{b}</option>)}
placeholder="搜索或选择..." </select>
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all"
value={customerFilters.brand}
onChange={(e) => setCustomerFilters(prev => ({ ...prev, brand: e.target.value }))}
/>
<datalist id="dl-cust-brand">
{uniqueBrands.map(b => <option key={b} value={b} />)}
</datalist>
</div> </div>
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<input <select className="w-full bg-white border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all cursor-pointer shadow-sm" value={customerFilters.department} onChange={(e) => setCustomerFilters(prev => ({ ...prev, department: e.target.value }))}>
list="dl-cust-dept" <option value=""></option>
type="text" {uniqueDepts.map(d => <option key={d} value={d}>{d}</option>)}
placeholder="搜索或选择..." </select>
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all"
value={customerFilters.department}
onChange={(e) => setCustomerFilters(prev => ({ ...prev, department: e.target.value }))}
/>
<datalist id="dl-cust-dept">
{uniqueDepts.map(d => <option key={d} value={d} />)}
</datalist>
</div> </div>
<div className="space-y-1.5"> <div className="space-y-1.5">
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label> <label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider"></label>
<input <select className="w-full bg-white border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all cursor-pointer shadow-sm" value={customerFilters.region} onChange={(e) => setCustomerFilters(prev => ({ ...prev, region: e.target.value }))}>
list="dl-cust-region" <option value=""></option>
type="text" {uniqueRegions.map(r => <option key={r} value={r}>{r}</option>)}
placeholder="搜索或选择..." </select>
className="w-full bg-gray-50 border border-gray-200 rounded-lg py-2 px-2 text-xs focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-500 outline-none transition-all"
value={customerFilters.region}
onChange={(e) => setCustomerFilters(prev => ({ ...prev, region: e.target.value }))}
/>
<datalist id="dl-cust-region">
{uniqueRegions.map(r => <option key={r} value={r} />)}
</datalist>
</div> </div>
</div> </div>
</div> </div>
@@ -2551,7 +2449,7 @@ export default function App() {
<motion.div <motion.div
initial={{ scale: 0.9, opacity: 0, y: 20 }} initial={{ scale: 0.9, opacity: 0, y: 20 }}
animate={{ scale: 1, opacity: 1, y: 0 }} animate={{ scale: 1, opacity: 1, y: 0 }}
className="bg-white rounded-xl shadow-2xl w-full max-w-[95vw] lg:max-w-6xl overflow-hidden flex flex-col max-h-[85vh] sm:max-h-[90vh] min-h-[40vh]" className={`bg-white rounded-xl shadow-2xl w-full max-w-[95vw] ${showPlateNumbers.source === 'customer' ? 'lg:max-w-6xl' : 'lg:max-w-4xl'} overflow-hidden flex flex-col max-h-[85vh] sm:max-h-[90vh] min-h-[40vh]`}
> >
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-slate-800 text-white shrink-0"> <div className="p-4 border-b border-gray-100 flex justify-between items-center bg-slate-800 text-white shrink-0">
<div> <div>
@@ -2593,13 +2491,7 @@ export default function App() {
{!isModalFilterExpanded && ( {!isModalFilterExpanded && (
<div className="relative w-40 sm:w-64" onClick={(e) => e.stopPropagation()}> <div className="relative w-40 sm:w-64" onClick={(e) => e.stopPropagation()}>
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" /> <Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" />
<input <input type="text" value={modalFilters.plateNumber} onChange={(e) => setModalFilters({...modalFilters, plateNumber: e.target.value})} placeholder="快速搜索车牌..." className="w-full text-[11px] pl-7 pr-2 py-1 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm" />
type="text"
value={modalFilters.plateNumber}
onChange={(e) => setModalFilters({...modalFilters, plateNumber: e.target.value})}
placeholder="快速搜索车牌..."
className="w-full text-[11px] pl-7 pr-2 py-1 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
</div> </div>
)} )}
<motion.div <motion.div
@@ -2624,69 +2516,30 @@ export default function App() {
<label className="block text-[10px] text-gray-500 font-medium"></label> <label className="block text-[10px] text-gray-500 font-medium"></label>
<div className="relative"> <div className="relative">
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" /> <Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" />
<input <input type="text" list="dl-modal-plate" placeholder="搜索车牌..." value={modalFilters.plateNumber} onChange={(e) => setModalFilters({...modalFilters, plateNumber: e.target.value})} className="w-full text-[11px] pl-7 pr-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm" />
list="dl-modal-plate" <datalist id="dl-modal-plate">{uniqueModalPlates.map(p => <option key={p} value={p} />)}</datalist>
type="text"
value={modalFilters.plateNumber}
onChange={(e) => setModalFilters({...modalFilters, plateNumber: e.target.value})}
placeholder="搜索车牌..."
className="w-full text-[11px] pl-7 pr-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-modal-plate">
{uniqueModalPlates.map(p => <option key={p} value={p} />)}
</datalist>
</div> </div>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<label className="block text-[10px] text-gray-500 font-medium"></label> <label className="block text-[10px] text-gray-500 font-medium"></label>
<div className="relative"> <select value={modalFilters.model} onChange={(e) => setModalFilters({...modalFilters, model: e.target.value})} className="w-full text-[11px] px-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" /> <option value=""></option>
<input {uniqueModalModels.map(m => <option key={m} value={m}>{m}</option>)}
list="dl-modal-model" </select>
type="text"
value={modalFilters.model}
onChange={(e) => setModalFilters({...modalFilters, model: e.target.value})}
placeholder="搜索车型..."
className="w-full text-[11px] pl-7 pr-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-modal-model">
{uniqueModalModels.map(m => <option key={m} value={m} />)}
</datalist>
</div>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<label className="block text-[10px] text-gray-500 font-medium"></label> <label className="block text-[10px] text-gray-500 font-medium"></label>
<div className="relative"> <select value={modalFilters.brand} onChange={(e) => setModalFilters({...modalFilters, brand: e.target.value})} className="w-full text-[11px] px-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" /> <option value=""></option>
<input {uniqueModalBrands.map(b => <option key={b} value={b}>{b}</option>)}
list="dl-modal-brand" </select>
type="text"
value={modalFilters.brand}
onChange={(e) => setModalFilters({...modalFilters, brand: e.target.value})}
placeholder="搜索品牌..."
className="w-full text-[11px] pl-7 pr-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-modal-brand">
{uniqueModalBrands.map(b => <option key={b} value={b} />)}
</datalist>
</div>
</div> </div>
<div className="space-y-1"> <div className="space-y-1">
<label className="block text-[10px] text-gray-500 font-medium"></label> <label className="block text-[10px] text-gray-500 font-medium"></label>
<div className="relative"> <select value={modalFilters.location} onChange={(e) => setModalFilters({...modalFilters, location: e.target.value})} className="w-full text-[11px] px-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm cursor-pointer">
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" /> <option value=""></option>
<input {uniqueModalLocations.map(l => <option key={l} value={l}>{l}</option>)}
list="dl-modal-location" </select>
type="text"
value={modalFilters.location}
onChange={(e) => setModalFilters({...modalFilters, location: e.target.value})}
placeholder="搜索所在地..."
className="w-full text-[11px] pl-7 pr-2 py-1.5 bg-white border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all shadow-sm"
/>
<datalist id="dl-modal-location">
{uniqueModalLocations.map(l => <option key={l} value={l} />)}
</datalist>
</div>
</div> </div>
</div> </div>
<div className="flex justify-end pb-2"> <div className="flex justify-end pb-2">
@@ -2733,7 +2586,8 @@ export default function App() {
<table className="min-w-full w-max text-left border-collapse"> <table className="min-w-full w-max text-left border-collapse">
<thead className="sticky top-0 z-20 shadow-sm"> <thead className="sticky top-0 z-20 shadow-sm">
<tr className="bg-slate-700 text-white text-[10px] uppercase tracking-wider whitespace-nowrap"> <tr className="bg-slate-700 text-white text-[10px] uppercase tracking-wider whitespace-nowrap">
<th className="p-2 font-semibold border-r border-slate-600 sticky left-0 top-0 bg-slate-700 z-30 w-10 text-center"></th> {showPlateNumbers.source === 'customer' ? (
<>
<th className="p-2 font-semibold border-r border-slate-600 w-24"></th> <th className="p-2 font-semibold border-r border-slate-600 w-24"></th>
<th className="p-2 font-semibold border-r border-slate-600 w-24"></th> <th className="p-2 font-semibold border-r border-slate-600 w-24"></th>
<th className="p-2 font-semibold border-r border-slate-600 w-16"></th> <th className="p-2 font-semibold border-r border-slate-600 w-16"></th>
@@ -2747,12 +2601,25 @@ export default function App() {
<th className="p-2 font-semibold border-r border-slate-600 w-24"></th> <th className="p-2 font-semibold border-r border-slate-600 w-24"></th>
<th className="p-2 font-semibold border-r border-slate-600 w-20 text-center"></th> <th className="p-2 font-semibold border-r border-slate-600 w-20 text-center"></th>
<th className="p-2 font-semibold w-48"></th> <th className="p-2 font-semibold w-48"></th>
</>
) : (
<>
<th className="p-2 font-semibold border-r border-slate-600 text-center"></th>
{showPlateNumbers.source !== 'asset' && showPlateNumbers.category !== 'Inventory' && (
<th className="p-2 font-semibold border-r border-slate-600 text-center"></th>
)}
<th className="p-2 font-semibold border-r border-slate-600 text-center"></th>
<th className="p-2 font-semibold border-r border-slate-600 text-center"></th>
<th className="p-2 font-semibold text-center"></th>
</>
)}
</tr> </tr>
</thead> </thead>
<tbody className="text-[11px]"> <tbody className="text-[11px]">
{filteredModalVehicles.map((v, idx) => ( {filteredModalVehicles.map((v, idx) => (
<tr key={v.id} className={`border-b border-gray-100 hover:bg-blue-50/50 transition-colors whitespace-nowrap ${idx % 2 === 0 ? 'bg-white' : 'bg-gray-50/30'}`}> <tr key={v.id} className={`border-b border-gray-100 hover:bg-blue-50/50 transition-colors whitespace-nowrap ${idx % 2 === 0 ? 'bg-white' : 'bg-gray-50/30'}`}>
<td className="p-2 border-r border-gray-100 text-center sticky left-0 bg-inherit z-10 font-bold text-gray-400">{v.contractNo || '—'}</td> {showPlateNumbers.source === 'customer' ? (
<>
<td className="p-2 border-r border-gray-100 text-gray-600">{v.departmentName || '—'}</td> <td className="p-2 border-r border-gray-100 text-gray-600">{v.departmentName || '—'}</td>
<td className="p-2 border-r border-gray-100 font-medium text-gray-700">{v.customerManager || '—'}</td> <td className="p-2 border-r border-gray-100 font-medium text-gray-700">{v.customerManager || '—'}</td>
<td className="p-2 border-r border-gray-100 text-gray-600">{v.brandLabel || '—'}</td> <td className="p-2 border-r border-gray-100 text-gray-600">{v.brandLabel || '—'}</td>
@@ -2773,11 +2640,23 @@ export default function App() {
<td className="p-2 border-r border-gray-100 text-gray-600">{v.location}</td> <td className="p-2 border-r border-gray-100 text-gray-600">{v.location}</td>
<td className="p-2 border-r border-gray-100 text-center font-bold text-orange-600">{'—'}</td> <td className="p-2 border-r border-gray-100 text-center font-bold text-orange-600">{'—'}</td>
<td className="p-2 text-gray-500 text-[10px]">{v.orgName || '—'}</td> <td className="p-2 text-gray-500 text-[10px]">{v.orgName || '—'}</td>
</>
) : (
<>
<td className={`p-2 border-r border-gray-100 font-mono font-bold text-center ${v.plateNumber ? 'text-blue-700' : 'text-orange-500'}`}>{v.plateNumber || v.vin || '—'}</td>
{showPlateNumbers.source !== 'asset' && showPlateNumbers.category !== 'Inventory' && (
<td className="p-2 border-r border-gray-100 font-bold text-gray-800 text-center">{v.customerName || '—'}</td>
)}
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{v.brandLabel || '—'}</td>
<td className="p-2 border-r border-gray-100 text-gray-600 text-center">{v.type}</td>
<td className="p-2 text-gray-600 text-center">{v.location}</td>
</>
)}
</tr> </tr>
))} ))}
{filteredModalVehicles.length === 0 && ( {filteredModalVehicles.length === 0 && (
<tr> <tr>
<td colSpan={14} className="p-8 text-center text-gray-400 italic"> <td colSpan={showPlateNumbers.source === 'customer' ? 13 : ((showPlateNumbers.source === 'asset' || showPlateNumbers.category === 'Inventory') ? 4 : 5)} className="p-8 text-center text-gray-400 italic">
</td> </td>
</tr> </tr>