feat: add state, data loading, and helpers for 3 new modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
230
src/App.tsx
230
src/App.tsx
@@ -10,10 +10,13 @@ import {
|
|||||||
ChevronRight,
|
ChevronRight,
|
||||||
Info,
|
Info,
|
||||||
Loader2,
|
Loader2,
|
||||||
|
Search,
|
||||||
|
Filter,
|
||||||
|
ArrowRightLeft,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { motion, AnimatePresence } from 'motion/react';
|
import { motion, AnimatePresence } from 'motion/react';
|
||||||
import type { SummaryData, TypeSummary, VehicleListItem } from './types';
|
import type { SummaryData, TypeSummary, VehicleListItem, DeptGroup, RegionGroup, CustomerStats } from './types';
|
||||||
import { fetchSummary, fetchByType, fetchVehicleList, fetchWeeklyDetail } from './api';
|
import { fetchSummary, fetchByType, fetchVehicleList, fetchWeeklyDetail, fetchDeptStats, fetchRegionStats, fetchCustomerStats } from './api';
|
||||||
import type { WeeklyDetailItem } from './api';
|
import type { WeeklyDetailItem } from './api';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
@@ -24,7 +27,12 @@ export default function App() {
|
|||||||
batch: string;
|
batch: string;
|
||||||
model: string;
|
model: string;
|
||||||
location: string;
|
location: string;
|
||||||
category?: 'Inventory' | 'Pending' | 'Delivered' | 'Returned' | 'Replaced';
|
category?: 'Inventory' | 'Pending' | 'Delivered' | 'Returned' | 'Replaced' | 'Operating';
|
||||||
|
vehicleType?: string;
|
||||||
|
manager?: string;
|
||||||
|
customer?: string;
|
||||||
|
isColdChain?: boolean;
|
||||||
|
isTrailer?: boolean;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
// Data state
|
// Data state
|
||||||
@@ -37,16 +45,43 @@ export default function App() {
|
|||||||
const [lastUpdate, setLastUpdate] = useState<string>('');
|
const [lastUpdate, setLastUpdate] = useState<string>('');
|
||||||
const [modalLoading, setModalLoading] = useState(false);
|
const [modalLoading, setModalLoading] = useState(false);
|
||||||
|
|
||||||
|
// Dept/Region/Customer data
|
||||||
|
const [deptData, setDeptData] = useState<DeptGroup[]>([]);
|
||||||
|
const [regionData, setRegionData] = useState<RegionGroup[]>([]);
|
||||||
|
const [customerData, setCustomerData] = useState<CustomerStats[]>([]);
|
||||||
|
|
||||||
|
// Dept section state
|
||||||
|
const [deptViewMode, setDeptViewMode] = useState<'department' | 'manager'>('department');
|
||||||
|
const [expandedDepts, setExpandedDepts] = useState<Set<string>>(new Set());
|
||||||
|
const [expandedManagerDetails, setExpandedManagerDetails] = useState<Set<string>>(new Set());
|
||||||
|
const [selectedManager, setSelectedManager] = useState<string>('All');
|
||||||
|
|
||||||
|
// Region section state
|
||||||
|
const [expandedRegions, setExpandedRegions] = useState<Set<string>>(new Set());
|
||||||
|
const [regionFilters, setRegionFilters] = useState({ region: '', city: '', customer: '' });
|
||||||
|
const [isRegionFilterOpen, setIsRegionFilterOpen] = useState(false);
|
||||||
|
|
||||||
|
// Customer section state
|
||||||
|
const [expandedCustomers, setExpandedCustomers] = useState<Set<string>>(new Set());
|
||||||
|
const [customerFilters, setCustomerFilters] = useState({ customer: '', brand: '', department: '', manager: '', region: '' });
|
||||||
|
const [isCustomerFilterOpen, setIsCustomerFilterOpen] = useState(false);
|
||||||
|
|
||||||
const loadData = useCallback(async () => {
|
const loadData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
const [s, byType] = await Promise.all([
|
const [s, byType, dept, region, cust] = await Promise.all([
|
||||||
fetchSummary(),
|
fetchSummary(),
|
||||||
fetchByType(),
|
fetchByType(),
|
||||||
|
fetchDeptStats(),
|
||||||
|
fetchRegionStats(),
|
||||||
|
fetchCustomerStats(),
|
||||||
]);
|
]);
|
||||||
setSummary(s);
|
setSummary(s);
|
||||||
setProcessedData(byType);
|
setProcessedData(byType);
|
||||||
|
setDeptData(dept);
|
||||||
|
setRegionData(region);
|
||||||
|
setCustomerData(cust);
|
||||||
setLastUpdate(new Date().toLocaleString('zh-CN'));
|
setLastUpdate(new Date().toLocaleString('zh-CN'));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setError(e instanceof Error ? e.message : '数据加载失败');
|
setError(e instanceof Error ? e.message : '数据加载失败');
|
||||||
@@ -85,10 +120,16 @@ export default function App() {
|
|||||||
// Normal vehicle list
|
// Normal vehicle list
|
||||||
setModalWeeklyDetail([]);
|
setModalWeeklyDetail([]);
|
||||||
const params: Record<string, string> = {};
|
const params: Record<string, string> = {};
|
||||||
|
if (showPlateNumbers.vehicleType) params.vehicleType = showPlateNumbers.vehicleType;
|
||||||
if (showPlateNumbers.batch !== 'All') params.batch = showPlateNumbers.batch;
|
if (showPlateNumbers.batch !== 'All') params.batch = showPlateNumbers.batch;
|
||||||
if (showPlateNumbers.model !== 'All') params.model = showPlateNumbers.model;
|
if (showPlateNumbers.model !== 'All') params.model = showPlateNumbers.model;
|
||||||
if (showPlateNumbers.location !== 'All') params.location = showPlateNumbers.location;
|
if (showPlateNumbers.location !== 'All') params.location = showPlateNumbers.location;
|
||||||
if (cat === 'Inventory') params.status = 'Inventory';
|
if (cat === 'Inventory') params.status = 'Inventory';
|
||||||
|
if (cat === 'Operating') params.category = 'Operating';
|
||||||
|
if (showPlateNumbers.manager) params.manager = showPlateNumbers.manager;
|
||||||
|
if (showPlateNumbers.customer) params.customer = showPlateNumbers.customer;
|
||||||
|
if (showPlateNumbers.isColdChain !== undefined) params.isColdChain = String(showPlateNumbers.isColdChain);
|
||||||
|
if (showPlateNumbers.isTrailer !== undefined) params.isTrailer = String(showPlateNumbers.isTrailer);
|
||||||
fetchVehicleList(params)
|
fetchVehicleList(params)
|
||||||
.then(setModalVehicles)
|
.then(setModalVehicles)
|
||||||
.catch(() => setModalVehicles([]))
|
.catch(() => setModalVehicles([]))
|
||||||
@@ -119,7 +160,57 @@ export default function App() {
|
|||||||
setExpandedModels(newSet);
|
setExpandedModels(newSet);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleDept = (dept: string) => {
|
||||||
|
const newSet = new Set(expandedDepts);
|
||||||
|
if (newSet.has(dept)) newSet.delete(dept);
|
||||||
|
else newSet.add(dept);
|
||||||
|
setExpandedDepts(newSet);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleManagerDetails = (manager: string) => {
|
||||||
|
const newSet = new Set(expandedManagerDetails);
|
||||||
|
if (newSet.has(manager)) newSet.delete(manager);
|
||||||
|
else newSet.add(manager);
|
||||||
|
setExpandedManagerDetails(newSet);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleRegion = (region: string) => {
|
||||||
|
const newSet = new Set(expandedRegions);
|
||||||
|
if (newSet.has(region)) newSet.delete(region);
|
||||||
|
else newSet.add(region);
|
||||||
|
setExpandedRegions(newSet);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleCustomer = (customer: string) => {
|
||||||
|
const newSet = new Set(expandedCustomers);
|
||||||
|
if (newSet.has(customer)) newSet.delete(customer);
|
||||||
|
else newSet.add(customer);
|
||||||
|
setExpandedCustomers(newSet);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Derived data for dept section
|
||||||
|
const allManagersList = deptData.flatMap((d) => d.managers.map((m) => m.manager)).filter((v, i, a) => a.indexOf(v) === i).sort();
|
||||||
|
const managerStats = deptData
|
||||||
|
.flatMap((d) => d.managers)
|
||||||
|
.filter((m) => selectedManager === 'All' || m.manager === selectedManager)
|
||||||
|
.sort((a, b) => b.total - a.total);
|
||||||
|
|
||||||
|
// Derived data for customer section
|
||||||
|
const filteredCustomerStats = customerData.filter((s) => {
|
||||||
|
const mc = !customerFilters.customer || s.customer.toLowerCase().includes(customerFilters.customer.toLowerCase());
|
||||||
|
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 mr = !customerFilters.region || s.region === customerFilters.region;
|
||||||
|
return mc && mb && md && mm && mr;
|
||||||
|
});
|
||||||
|
const uniqueBrands = Array.from(new Set(customerData.map((s) => s.brand).filter(Boolean)));
|
||||||
|
const uniqueDepts = Array.from(new Set(customerData.map((s) => s.department).filter(Boolean)));
|
||||||
|
const uniqueRegions = Array.from(new Set(customerData.map((s) => s.region)));
|
||||||
|
const uniqueCities = Array.from(new Set(customerData.map((s) => s.city).filter(Boolean)));
|
||||||
|
|
||||||
|
// Derived data for region section
|
||||||
|
const filteredRegionData = regionData.filter((r) => !regionFilters.region || r.region === regionFilters.region);
|
||||||
|
|
||||||
if (loading && !summary) {
|
if (loading && !summary) {
|
||||||
return (
|
return (
|
||||||
@@ -346,17 +437,61 @@ export default function App() {
|
|||||||
<tr className="bg-yellow-50/50 text-xs font-bold border-b border-gray-200">
|
<tr className="bg-yellow-50/50 text-xs font-bold border-b border-gray-200">
|
||||||
<td className="p-3 border-r border-gray-100 text-gray-700">总计</td>
|
<td className="p-3 border-r border-gray-100 text-gray-700">总计</td>
|
||||||
<td className="p-3 border-r border-gray-100"></td>
|
<td className="p-3 border-r border-gray-100"></td>
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-gray-800">{processedData.reduce((s, t) => s + t.totalAssets, 0)}</td>
|
<td className="p-3 text-center border-r border-gray-100">
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-blue-700">{processedData.reduce((s, t) => s + t.totalInventory, 0)}</td>
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All' })} className="text-gray-800 hover:text-blue-600 hover:underline font-bold">
|
||||||
|
{processedData.reduce((s, t) => s + t.totalAssets, 0)}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td className="p-3 text-center border-r border-gray-100">
|
||||||
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Inventory' })} className="text-blue-700 hover:underline font-bold">
|
||||||
|
{processedData.reduce((s, t) => s + t.totalInventory, 0)}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
{['嘉兴', '广东', '北京', '新疆', '其他'].map((reg) => {
|
{['嘉兴', '广东', '北京', '新疆', '其他'].map((reg) => {
|
||||||
const val = processedData.reduce((s, t) => s + (t.inventoryRegions?.[reg] || 0), 0);
|
const val = processedData.reduce((s, t) => s + (t.inventoryRegions?.[reg] || 0), 0);
|
||||||
return <td key={reg} className="p-3 text-center border-r border-gray-100 text-blue-700">{val || ''}</td>;
|
return (
|
||||||
|
<td key={reg} className="p-3 text-center border-r border-gray-100">
|
||||||
|
{val > 0 ? (
|
||||||
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: reg, category: 'Inventory' })} className="text-blue-700 hover:underline font-bold">
|
||||||
|
{val}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-gray-700">{processedData.reduce((s, t) => s + t.pending, 0) || ''}</td>
|
<td className="p-3 text-center border-r border-gray-100">
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-green-700 bg-green-50/10">{processedData.reduce((s, t) => s + t.totalOperating, 0)}</td>
|
{processedData.reduce((s, t) => s + t.pending, 0) > 0 ? (
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-blue-700 bg-blue-50/5">{processedData.reduce((s, t) => s + t.weeklyDelivered, 0) || ''}</td>
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending' })} className="text-gray-700 hover:text-blue-600 hover:underline font-bold">
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-orange-700 bg-orange-50/5">{processedData.reduce((s, t) => s + t.weeklyReturned, 0) || ''}</td>
|
{processedData.reduce((s, t) => s + t.pending, 0)}
|
||||||
<td className="p-3 text-center text-purple-700 bg-purple-50/5">{processedData.reduce((s, t) => s + t.weeklyReplaced, 0) || ''}</td>
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
<td className="p-3 text-center border-r border-gray-100 bg-green-50/10">
|
||||||
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating' })} className="text-green-700 hover:underline font-bold">
|
||||||
|
{processedData.reduce((s, t) => s + t.totalOperating, 0)}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td className="p-3 text-center border-r border-gray-100 bg-blue-50/5">
|
||||||
|
{processedData.reduce((s, t) => s + t.weeklyDelivered, 0) > 0 ? (
|
||||||
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Delivered' })} className="text-blue-700 hover:underline font-bold">
|
||||||
|
{processedData.reduce((s, t) => s + t.weeklyDelivered, 0)}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
<td className="p-3 text-center border-r border-gray-100 bg-orange-50/5">
|
||||||
|
{processedData.reduce((s, t) => s + t.weeklyReturned, 0) > 0 ? (
|
||||||
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Returned' })} className="text-orange-700 hover:underline font-bold">
|
||||||
|
{processedData.reduce((s, t) => s + t.weeklyReturned, 0)}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
<td className="p-3 text-center bg-purple-50/5">
|
||||||
|
{processedData.reduce((s, t) => s + t.weeklyReplaced, 0) > 0 ? (
|
||||||
|
<button onClick={() => setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Replaced' })} className="text-purple-700 hover:underline font-bold">
|
||||||
|
{processedData.reduce((s, t) => s + t.weeklyReplaced, 0)}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="text-xs">
|
<tbody className="text-xs">
|
||||||
@@ -389,18 +524,58 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td className={`p-3 border-r border-gray-100 text-[11px] ${theme === 'vibrant' ? 'text-white/70' : 'text-gray-400'} italic`}>小计</td>
|
<td className={`p-3 border-r border-gray-100 text-[11px] ${theme === 'vibrant' ? 'text-white/70' : 'text-gray-400'} italic`}>小计</td>
|
||||||
<td className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white' : 'text-gray-700'}`}>{typeGroup.totalAssets}</td>
|
<td className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white' : ''}`}>
|
||||||
<td className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white' : 'text-blue-600'}`}>{typeGroup.totalInventory}</td>
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white' : 'text-gray-700 hover:text-blue-600'}`}>
|
||||||
|
{typeGroup.totalAssets}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white' : ''}`}>
|
||||||
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Inventory', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white' : 'text-blue-600'}`}>
|
||||||
|
{typeGroup.totalInventory}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
{['嘉兴', '广东', '北京', '新疆', '其他'].map((reg) => (
|
{['嘉兴', '广东', '北京', '新疆', '其他'].map((reg) => (
|
||||||
<td key={reg} className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white/80' : 'text-blue-600'}`}>
|
<td key={reg} className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white/80' : ''}`}>
|
||||||
{(typeGroup.inventoryRegions?.[reg] || 0) > 0 ? typeGroup.inventoryRegions[reg] : ''}
|
{(typeGroup.inventoryRegions?.[reg] || 0) > 0 ? (
|
||||||
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: reg, category: 'Inventory', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white/80' : 'text-blue-600'}`}>
|
||||||
|
{typeGroup.inventoryRegions[reg]}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
<td className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white' : 'text-gray-600'}`}>{typeGroup.pending || ''}</td>
|
<td className={`p-3 text-center border-r border-gray-100 font-bold ${theme === 'vibrant' ? 'text-white' : ''}`}>
|
||||||
<td className={`p-3 text-center border-r border-gray-100 font-bold bg-green-50/10 ${theme === 'vibrant' ? 'text-white' : 'text-green-600'}`}>{typeGroup.totalOperating}</td>
|
{typeGroup.pending > 0 ? (
|
||||||
<td className={`p-3 text-center border-r border-gray-100 font-bold bg-blue-50/5 ${theme === 'vibrant' ? 'text-white/80' : 'text-blue-600'}`}>{typeGroup.weeklyDelivered || ''}</td>
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Pending', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white' : 'text-gray-600 hover:text-blue-600'}`}>
|
||||||
<td className={`p-3 text-center border-r border-gray-100 font-bold bg-orange-50/5 ${theme === 'vibrant' ? 'text-white/80' : 'text-orange-600'}`}>{typeGroup.weeklyReturned || ''}</td>
|
{typeGroup.pending}
|
||||||
<td className={`p-3 text-center font-bold bg-purple-50/5 ${theme === 'vibrant' ? 'text-white/80' : 'text-purple-600'}`}>{typeGroup.weeklyReplaced || ''}</td>
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
<td className={`p-3 text-center border-r border-gray-100 font-bold bg-green-50/10 ${theme === 'vibrant' ? 'text-white' : ''}`}>
|
||||||
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Operating', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white' : 'text-green-600'}`}>
|
||||||
|
{typeGroup.totalOperating}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td className={`p-3 text-center border-r border-gray-100 font-bold bg-blue-50/5 ${theme === 'vibrant' ? 'text-white/80' : ''}`}>
|
||||||
|
{typeGroup.weeklyDelivered > 0 ? (
|
||||||
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Delivered', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white/80' : 'text-blue-600'}`}>
|
||||||
|
{typeGroup.weeklyDelivered}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
<td className={`p-3 text-center border-r border-gray-100 font-bold bg-orange-50/5 ${theme === 'vibrant' ? 'text-white/80' : ''}`}>
|
||||||
|
{typeGroup.weeklyReturned > 0 ? (
|
||||||
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Returned', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white/80' : 'text-orange-600'}`}>
|
||||||
|
{typeGroup.weeklyReturned}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
|
<td className={`p-3 text-center font-bold bg-purple-50/5 ${theme === 'vibrant' ? 'text-white/80' : ''}`}>
|
||||||
|
{typeGroup.weeklyReplaced > 0 ? (
|
||||||
|
<button onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', category: 'Replaced', vehicleType: typeGroup.type }); }} className={`hover:underline font-bold ${theme === 'vibrant' ? 'text-white/80' : 'text-purple-600'}`}>
|
||||||
|
{typeGroup.weeklyReplaced}
|
||||||
|
</button>
|
||||||
|
) : ''}
|
||||||
|
</td>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
@@ -470,8 +645,11 @@ export default function App() {
|
|||||||
''
|
''
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-green-600 font-bold bg-green-50/10">
|
<td className="p-3 text-center border-r border-gray-100 font-bold bg-green-50/10">
|
||||||
{model.operating}
|
<button
|
||||||
|
onClick={(e) => { e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: model.model, location: 'All', category: 'Operating' }); }}
|
||||||
|
className="text-green-600 hover:underline font-bold"
|
||||||
|
>{model.operating}</button>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center border-r border-gray-100 text-blue-600 bg-blue-50/5">
|
<td className="p-3 text-center border-r border-gray-100 text-blue-600 bg-blue-50/5">
|
||||||
{model.weeklyDelivered > 0 ? (
|
{model.weeklyDelivered > 0 ? (
|
||||||
@@ -694,14 +872,16 @@ export default function App() {
|
|||||||
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-blue-600 text-white">
|
<div className="p-4 border-b border-gray-100 flex justify-between items-center bg-blue-600 text-white">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-bold text-sm">
|
<h3 className="font-bold text-sm">
|
||||||
{showPlateNumbers.batch === 'All' ? '全量' : showPlateNumbers.batch} - 车牌明细
|
{showPlateNumbers.vehicleType || (showPlateNumbers.model !== 'All' ? showPlateNumbers.model : '全量')} - 车牌明细
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-[10px] opacity-80">
|
<p className="text-[10px] opacity-80">
|
||||||
{showPlateNumbers.model === 'All' ? '全量型号' : showPlateNumbers.model} |{' '}
|
{showPlateNumbers.vehicleType ? (showPlateNumbers.model === 'All' ? '全量型号' : showPlateNumbers.model) : (showPlateNumbers.batch === 'All' ? '' : showPlateNumbers.batch)} |{' '}
|
||||||
{!showPlateNumbers.category
|
{!showPlateNumbers.category
|
||||||
? '全部车辆'
|
? '全部车辆'
|
||||||
: showPlateNumbers.category === 'Inventory'
|
: showPlateNumbers.category === 'Inventory'
|
||||||
? (showPlateNumbers.location === 'All' ? '库存' : `${showPlateNumbers.location}库存`)
|
? (showPlateNumbers.location === 'All' ? '库存' : `${showPlateNumbers.location}库存`)
|
||||||
|
: showPlateNumbers.category === 'Operating'
|
||||||
|
? '在运营'
|
||||||
: showPlateNumbers.category === 'Pending'
|
: showPlateNumbers.category === 'Pending'
|
||||||
? '待交车'
|
? '待交车'
|
||||||
: showPlateNumbers.category === 'Delivered'
|
: showPlateNumbers.category === 'Delivered'
|
||||||
|
|||||||
Reference in New Issue
Block a user