feat: 业务负责人下拉按部门分组显示
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- 部门Tab和客户Tab的业务负责人下拉用optgroup按部门分组 - 顺序:部门名称作为组标题,组内显示该部门的负责人列表 - 部门排序与部门Tab一致(业务一部→二部→...→公务车) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
22
src/App.tsx
22
src/App.tsx
@@ -407,6 +407,7 @@ export default function App() {
|
||||
|
||||
// Derived data for dept section
|
||||
const allManagersList = useMemo(() => deptData.flatMap((d) => d.managers.map((m) => m.manager)).filter((v, i, a) => a.indexOf(v) === i).sort(), [deptData]);
|
||||
const managersGroupedByDept = useMemo(() => deptData.map((d) => ({ department: d.department, managers: d.managers.map((m) => m.manager) })), [deptData]);
|
||||
const managerStats = useMemo(() => deptData
|
||||
.flatMap((d) => d.managers)
|
||||
.filter((m) => selectedManager === 'All' || m.manager === selectedManager)
|
||||
@@ -427,6 +428,15 @@ export default function App() {
|
||||
const uniqueCities = useMemo(() => Array.from(new Set(customerData.map((s) => s.city).filter(Boolean))), [customerData]);
|
||||
const uniqueCustomerNames = useMemo(() => Array.from(new Set(customerData.map((s) => s.customer).filter(Boolean))), [customerData]);
|
||||
const uniqueCustomerManagers = useMemo(() => Array.from(new Set(customerData.map((s) => s.manager).filter(Boolean))), [customerData]);
|
||||
const customerManagersGroupedByDept = useMemo(() => {
|
||||
const deptMap = new Map<string, Set<string>>();
|
||||
for (const s of customerData) {
|
||||
if (!s.manager || !s.department) continue;
|
||||
if (!deptMap.has(s.department)) deptMap.set(s.department, new Set());
|
||||
deptMap.get(s.department)!.add(s.manager);
|
||||
}
|
||||
return Array.from(deptMap.entries()).map(([dept, mgrs]) => ({ department: dept, managers: Array.from(mgrs) }));
|
||||
}, [customerData]);
|
||||
const uniqueInventoryModels = useMemo(() => Array.from(new Set(inventoryData.map((s) => s.model).filter(Boolean))), [inventoryData]);
|
||||
const uniqueModalPlates = useMemo(() => Array.from(new Set(modalVehicles.map(v => v.plateNumber || v.vin).filter(Boolean))), [modalVehicles]);
|
||||
const uniqueModalModels = useMemo(() => Array.from(new Set(modalVehicles.map(v => v.model).filter(Boolean))), [modalVehicles]);
|
||||
@@ -1422,8 +1432,10 @@ export default function App() {
|
||||
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"
|
||||
>
|
||||
<option value="All">所有业务负责人</option>
|
||||
{allManagersList.map(m => (
|
||||
<option key={m} value={m}>{m}</option>
|
||||
{managersGroupedByDept.map(g => (
|
||||
<optgroup key={g.department} label={g.department}>
|
||||
{g.managers.map(m => <option key={m} value={m}>{m}</option>)}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
<ChevronDown className="absolute right-2.5 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none" size={14} />
|
||||
@@ -2270,7 +2282,11 @@ export default function App() {
|
||||
<label className="text-[10px] font-bold text-gray-400 uppercase tracking-wider">业务负责人</label>
|
||||
<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>)}
|
||||
{customerManagersGroupedByDept.map(g => (
|
||||
<optgroup key={g.department} label={g.department}>
|
||||
{g.managers.map(m => <option key={m} value={m}>{m}</option>)}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user