fix: 所有筛选统一为select下拉,修复iOS不支持datalist
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- 客户名称、业务负责人、车型名称、车牌号码全部从input+datalist 改为select下拉,iOS Safari完全兼容 - 弹窗快速搜索也改为select - 所有过滤逻辑统一为精确匹配(select值) - 样式统一:所有筛选控件使用相同的select样式 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
63
src/App.tsx
63
src/App.tsx
@@ -294,7 +294,7 @@ export default function App() {
|
||||
const mc = !inventoryFilters.city || s.city === inventoryFilters.city;
|
||||
const mb = !inventoryFilters.brand || s.brand === inventoryFilters.brand;
|
||||
const mbt = !inventoryFilters.batch || s.batch === inventoryFilters.batch;
|
||||
const mm = !inventoryFilters.model || s.model.toLowerCase().includes(inventoryFilters.model.toLowerCase());
|
||||
const mm = !inventoryFilters.model || s.model === inventoryFilters.model;
|
||||
return mr && mc && mb && mbt && mm;
|
||||
}), [inventoryData, inventoryFilters]);
|
||||
|
||||
@@ -336,10 +336,10 @@ export default function App() {
|
||||
|
||||
// Derived data for customer section
|
||||
const filteredCustomerStats = useMemo(() => customerData.filter((s) => {
|
||||
const mc = !customerFilters.customer || s.customer.toLowerCase().includes(customerFilters.customer.toLowerCase());
|
||||
const mc = !customerFilters.customer || s.customer === customerFilters.customer;
|
||||
const mb = !customerFilters.brand || s.brand === customerFilters.brand;
|
||||
const md = !customerFilters.department || s.department === customerFilters.department;
|
||||
const mm = !customerFilters.manager || s.manager.toLowerCase().includes(customerFilters.manager.toLowerCase());
|
||||
const mm = !customerFilters.manager || s.manager === customerFilters.manager;
|
||||
const mr = !customerFilters.region || s.region === customerFilters.region;
|
||||
return mc && mb && md && mm && mr;
|
||||
}), [customerData, customerFilters]);
|
||||
@@ -360,7 +360,7 @@ export default function App() {
|
||||
|
||||
// Filtered modal vehicles based on modal filters
|
||||
const filteredModalVehicles = useMemo(() => modalVehicles.filter((v) => {
|
||||
const mp = !modalFilters.plateNumber || (v.plateNumber || v.vin || '').toLowerCase().includes(modalFilters.plateNumber.toLowerCase());
|
||||
const mp = !modalFilters.plateNumber || (v.plateNumber || v.vin) === modalFilters.plateNumber;
|
||||
const mm = !modalFilters.model || v.model === modalFilters.model;
|
||||
const mb = !modalFilters.brand || v.brandLabel === modalFilters.brand;
|
||||
const ml = !modalFilters.location || v.location === modalFilters.location;
|
||||
@@ -368,7 +368,7 @@ export default function App() {
|
||||
}), [modalVehicles, modalFilters]);
|
||||
|
||||
const filteredModalWeeklyDetail = useMemo(() => modalWeeklyDetail.filter((v) => {
|
||||
const mp = !modalFilters.plateNumber || v.plate_number.toLowerCase().includes(modalFilters.plateNumber.toLowerCase());
|
||||
const mp = !modalFilters.plateNumber || v.plate_number === modalFilters.plateNumber;
|
||||
return mp;
|
||||
}), [modalWeeklyDetail, modalFilters.plateNumber]);
|
||||
|
||||
@@ -983,11 +983,10 @@ export default function App() {
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-[10px] text-slate-400 block mb-1">车型名称</label>
|
||||
<div className="relative">
|
||||
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-slate-400" />
|
||||
<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" />
|
||||
<datalist id="dl-inv-model">{uniqueInventoryModels.map(m => <option key={m} value={m} />)}</datalist>
|
||||
</div>
|
||||
<select value={inventoryFilters.model} onChange={(e) => setInventoryFilters({...inventoryFilters, model: 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">
|
||||
<option value="">全部车型</option>
|
||||
{uniqueInventoryModels.map(m => <option key={m} value={m}>{m}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -1873,11 +1872,10 @@ export default function App() {
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider">客户名称</label>
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" size={14} />
|
||||
<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 }))} />
|
||||
<datalist id="dl-region-customer">{uniqueCustomerNames.map(c => <option key={c} value={c} />)}</datalist>
|
||||
</div>
|
||||
<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.customer} onChange={(e) => setRegionFilters(prev => ({ ...prev, customer: e.target.value }))}>
|
||||
<option value="">所有客户</option>
|
||||
{uniqueCustomerNames.map(c => <option key={c} value={c}>{c}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
@@ -2182,20 +2180,18 @@ export default function App() {
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider">客户名称</label>
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" size={12} />
|
||||
<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 }))} />
|
||||
<datalist id="dl-cust-customer">{uniqueCustomerNames.map(c => <option key={c} value={c} />)}</datalist>
|
||||
</div>
|
||||
<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.customer} onChange={(e) => setCustomerFilters(prev => ({ ...prev, customer: e.target.value }))}>
|
||||
<option value="">所有客户</option>
|
||||
{uniqueCustomerNames.map(c => <option key={c} value={c}>{c}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider">业务负责人</label>
|
||||
<div className="relative">
|
||||
<Search className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" size={12} />
|
||||
<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 }))} />
|
||||
<datalist id="dl-cust-manager">{uniqueCustomerManagers.map(m => <option key={m} value={m} />)}</datalist>
|
||||
</div>
|
||||
<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.manager} onChange={(e) => setCustomerFilters(prev => ({ ...prev, manager: e.target.value }))}>
|
||||
<option value="">所有负责人</option>
|
||||
{uniqueCustomerManagers.map(m => <option key={m} value={m}>{m}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
@@ -2469,9 +2465,11 @@ export default function App() {
|
||||
<div className="flex items-center gap-3">
|
||||
{/* Quick Search always visible when collapsed */}
|
||||
{!isModalFilterExpanded && (
|
||||
<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" />
|
||||
<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" />
|
||||
<div className="w-40 sm:w-64" onClick={(e) => e.stopPropagation()}>
|
||||
<select value={modalFilters.plateNumber} onChange={(e) => setModalFilters({...modalFilters, plateNumber: e.target.value})} className="w-full text-[11px] px-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 cursor-pointer">
|
||||
<option value="">快速搜索车牌...</option>
|
||||
{uniqueModalPlates.map(p => <option key={p} value={p}>{p}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
<motion.div
|
||||
@@ -2494,11 +2492,10 @@ export default function App() {
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3 py-3 border-t border-gray-100 mt-1">
|
||||
<div className="space-y-1">
|
||||
<label className="block text-[10px] text-gray-500 font-medium">车牌号码</label>
|
||||
<div className="relative">
|
||||
<Search size={12} className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400" />
|
||||
<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" />
|
||||
<datalist id="dl-modal-plate">{uniqueModalPlates.map(p => <option key={p} value={p} />)}</datalist>
|
||||
</div>
|
||||
<select value={modalFilters.plateNumber} onChange={(e) => setModalFilters({...modalFilters, plateNumber: 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">
|
||||
<option value="">全部车牌</option>
|
||||
{uniqueModalPlates.map(p => <option key={p} value={p}>{p}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<label className="block text-[10px] text-gray-500 font-medium">车型型号</label>
|
||||
|
||||
Reference in New Issue
Block a user