优化地图编辑中的字段管理

This commit is contained in:
18086616529
2026-06-26 09:23:16 +08:00
parent e7bd326ea2
commit ce66da772e
10 changed files with 598 additions and 139 deletions
@@ -2,8 +2,8 @@ import { computed, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { fetchQuickEntryKeys, saveQuickEntryKeys } from '@/api/dashboardQuickEntries'
import {
defaultQuickKeys, getQuickEntryCatalog, MAX_QUICK_ENTRIES,
normalizeQuickKeys, resolveQuickEntry, type QuickEntryDef
defaultQuickKeys, finalizeQuickKeys, getQuickEntryCatalog, isMandatoryQuickKey,
MAX_QUICK_ENTRIES, normalizeQuickKeys, resolveQuickEntry, type QuickEntryDef
} from '@/config/quickEntries'
import { useAuthStore } from '@/stores/auth'
import type { Scope } from '@/types/auth'
@@ -20,8 +20,10 @@ export function useDashboardQuickEntries() {
/** 空列表仅在「尚未自定义」(usingDefaults) 时回退系统默认;用户主动清空则保持为空 */
function effectiveKeys(): string[] {
if (keys.value.length > 0) return keys.value
return usingDefaults.value ? defaultQuickKeys(scope.value as Scope) : []
const base = keys.value.length > 0
? keys.value
: (usingDefaults.value ? defaultQuickKeys(scope.value as Scope) : [])
return finalizeQuickKeys(base, scope.value as Scope)
}
function filterByPermission(list: string[]): string[] {
@@ -63,8 +65,8 @@ export function useDashboardQuickEntries() {
const dto = await fetchQuickEntryKeys(userId.value, scope.value)
const loaded = normalizeQuickKeys(dto.keys)
keys.value = loaded.length > 0
? loaded
: (dto.usingDefaults ? defaultQuickKeys(scope.value as Scope) : [])
? finalizeQuickKeys(loaded, scope.value as Scope)
: (dto.usingDefaults ? defaultQuickKeys(scope.value as Scope) : finalizeQuickKeys([], scope.value as Scope))
usingDefaults.value = dto.usingDefaults
} catch (e) {
keys.value = defaultQuickKeys(scope.value as Scope)
@@ -76,13 +78,14 @@ export function useDashboardQuickEntries() {
}
async function persist(nextKeys: string[]) {
const finalized = finalizeQuickKeys(nextKeys, scope.value as Scope)
if (!userId.value) {
keys.value = nextKeys
keys.value = finalized
return
}
try {
const dto = await saveQuickEntryKeys(userId.value, scope.value, normalizeQuickKeys(nextKeys))
keys.value = normalizeQuickKeys(dto.keys)
const dto = await saveQuickEntryKeys(userId.value, scope.value, finalized)
keys.value = finalizeQuickKeys(normalizeQuickKeys(dto.keys), scope.value as Scope)
usingDefaults.value = dto.usingDefaults
} catch (e) {
ElMessage.error(`保存快捷入口失败:${e instanceof Error ? e.message : String(e)}`)
@@ -105,6 +108,10 @@ export function useDashboardQuickEntries() {
}
async function removeKey(key: string) {
if (isMandatoryQuickKey(key, scope.value as Scope)) {
ElMessage.warning('该快捷入口为系统默认项,不可移除')
return
}
const base = [...effectiveKeys()]
await persist(base.filter((k) => k !== key))
ElMessage.success('已移除快捷入口')
@@ -140,6 +147,7 @@ export function useDashboardQuickEntries() {
addKey,
removeKey,
swapKeys,
openPicker
openPicker,
isMandatoryQuickKey: (key: string) => isMandatoryQuickKey(key, scope.value as Scope)
}
}
@@ -0,0 +1,98 @@
import { computed, ref, watch, type Ref } from 'vue'
import { listSimpleFields } from '@/api/simpleField'
import type { SimpleFieldCategory, SimpleFieldRecord } from '@/types/simpleField'
export function fieldCategoryForMapKind(kind: 'site' | 'track' | 'car' | null): SimpleFieldCategory | null {
if (kind === 'site') return 'siteFields'
if (kind === 'track') return 'trackFields'
if (kind === 'car') return 'carFields'
return null
}
/** 按 key 去重(同 key 多条车型定义时保留第一条)。 */
function dedupeByKey(rows: SimpleFieldRecord[]): SimpleFieldRecord[] {
const seen = new Set<string>()
const out: SimpleFieldRecord[] = []
for (const row of rows) {
if (seen.has(row.key)) continue
seen.add(row.key)
out.push(row)
}
return out
}
function normalizeCarTypeToken(v: string | null | undefined): string {
return (v ?? '').trim().replace(/^UI/i, '')
}
function shortCarType(v: string): string {
const s = v.trim()
const i = s.lastIndexOf('.')
return i >= 0 ? s.slice(i + 1) : s
}
function filterRowsByCarType(rows: SimpleFieldRecord[], current: string | null | undefined): SimpleFieldRecord[] {
const token = shortCarType(normalizeCarTypeToken(current)).toLowerCase()
if (!token) return []
return rows.filter((r) => shortCarType(r.carType).toLowerCase() === token)
}
export function useSimpleFieldCatalog(
kind: Ref<'site' | 'track' | 'car' | null>,
carType?: Ref<string | null | undefined>
) {
const loading = ref(false)
const records = ref<SimpleFieldRecord[]>([])
const fieldType = computed(() => fieldCategoryForMapKind(kind.value))
const byKey = computed(() => {
const map = new Map<string, SimpleFieldRecord>()
for (const row of records.value) map.set(row.key, row)
return map
})
async function reload() {
const ft = fieldType.value
if (!ft) {
records.value = []
return
}
loading.value = true
try {
// 车辆:为兼容 shortName / assembly.shortName 等不同 car_type 存储格式,先拉 carFields 再前端匹配当前车型。
if (ft === 'carFields') {
const all = await listSimpleFields(ft)
records.value = dedupeByKey(filterRowsByCarType(all, carType?.value))
} else {
const rows = await listSimpleFields(ft)
records.value = dedupeByKey(rows)
}
} catch {
records.value = []
} finally {
loading.value = false
}
}
watch(fieldType, () => { void reload() }, { immediate: true })
function labelForKey(key: string): string {
const row = byKey.value.get(key)
return row?.chinese?.trim() || row?.english?.trim() || '—'
}
function defaultValueForKey(key: string): string {
return byKey.value.get(key)?.value ?? ''
}
return {
loading,
records,
fieldType,
byKey,
reload,
labelForKey,
defaultValueForKey
}
}