60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
/**
|
||
* 地区数据模块级单例缓存。
|
||
* 首次调用时 fetch /region.csv 并构建 idMap 和 parentMap,
|
||
* 后续调用直接返回缓存,SPA 生命周期内只加载一次。
|
||
*/
|
||
|
||
interface RegionItem {
|
||
id: number;
|
||
parentId: number;
|
||
level: number;
|
||
name: string;
|
||
}
|
||
|
||
interface RegionCache {
|
||
/** id → RegionItem,用于表格列的 id→name 转换 */
|
||
idMap: Map<number, RegionItem>;
|
||
/** parentId → children[],用于省/市/区下拉联动 O(1) 查找 */
|
||
parentMap: Map<number, RegionItem[]>;
|
||
/** 所有地区平铺数组 */
|
||
list: RegionItem[];
|
||
}
|
||
|
||
let _cache: RegionCache | null = null;
|
||
|
||
function parseCSV(text: string): RegionItem[] {
|
||
const lines = text.split("\n").filter((l) => l.trim());
|
||
const headers = lines[0].split(",").map((h) => h.trim());
|
||
return lines.slice(1).map((line) => {
|
||
const cols = line.split(",").map((c) => c.trim());
|
||
const obj: any = {};
|
||
headers.forEach((h, i) => {
|
||
obj[h] = h === "name" ? cols[i] : Number(cols[i]);
|
||
});
|
||
return obj as RegionItem;
|
||
});
|
||
}
|
||
|
||
export async function useRegionCache(): Promise<RegionCache> {
|
||
if (_cache) return _cache;
|
||
|
||
const res = await fetch("/region.csv");
|
||
if (!res.ok) throw new Error("地区数据加载失败");
|
||
const text = await res.text();
|
||
const list = parseCSV(text);
|
||
|
||
const idMap = new Map<number, RegionItem>();
|
||
const parentMap = new Map<number, RegionItem[]>();
|
||
|
||
for (const item of list) {
|
||
idMap.set(item.id, item);
|
||
if (!parentMap.has(item.parentId)) {
|
||
parentMap.set(item.parentId, []);
|
||
}
|
||
parentMap.get(item.parentId)!.push(item);
|
||
}
|
||
|
||
_cache = { idMap, parentMap, list };
|
||
return _cache;
|
||
}
|