Files
shanxia2.0/web-admin/src/composables/usePlRemoteOptions.ts
T
2026-08-17 09:22:31 +08:00

216 lines
5.8 KiB
TypeScript

import {
carrierApi,
personnelApi,
vehicleApi,
type Carrier,
type Personnel,
type PersonnelQuery,
type Vehicle,
type VehicleDetail,
type VehicleQuery
} from '@/api/pl'
import { pickBxData, pickBxList } from '@/utils/http/bx'
const REMOTE_PAGE_SIZE = 100
type IdItem = { id: string }
function keepSelected<T extends IdItem>(
rows: T[],
selectedId: string | undefined,
currentList: T[]
): T[] {
if (!selectedId) return rows
if (rows.some(item => item.id === selectedId)) return rows
const kept = currentList.find(item => item.id === selectedId)
return kept ? [kept, ...rows] : rows
}
function keepSelectedByPlate(
rows: Vehicle[],
selectedPlate: string | undefined,
currentList: Vehicle[]
): Vehicle[] {
const plate = selectedPlate?.trim()
if (!plate) return rows
if (rows.some(item => item.licensePlate === plate)) return rows
const kept = currentList.find(item => item.licensePlate === plate)
return kept ? [kept, ...rows] : rows
}
/** 车辆下拉:服务端按车牌 q 检索 */
export function usePlRemoteVehicleOptions(options?: {
getSelectedId?: () => string | undefined
getSelectedPlate?: () => string | undefined
/** 默认按 id 保留已选项;选车牌字符串时传 licensePlate */
valueMode?: 'id' | 'licensePlate'
listParams?: Omit<VehicleQuery, 'q' | 'page' | 'pageSize'>
}) {
const list = ref<Vehicle[]>([])
const loading = ref(false)
const loaded = ref(false)
const valueMode = options?.valueMode ?? 'id'
async function search(keyword: string) {
loading.value = true
try {
const res = await vehicleApi.list({
...(options?.listParams || {}),
...(keyword.trim() ? { q: keyword.trim() } : {}),
page: 1,
pageSize: REMOTE_PAGE_SIZE
})
const rows = pickBxList<Vehicle>(res)
list.value =
valueMode === 'licensePlate'
? keepSelectedByPlate(rows, options?.getSelectedPlate?.(), list.value)
: keepSelected(rows, options?.getSelectedId?.(), list.value)
loaded.value = true
} catch (error) {
console.error('加载车辆选项失败', error)
list.value = []
} finally {
loading.value = false
}
}
function onFocus() {
if (!loaded.value) void search('')
}
function reset() {
list.value = []
loaded.value = false
}
async function ensureById(vehicleId: string) {
if (!vehicleId || list.value.some(item => item.id === vehicleId)) return
try {
const res = await vehicleApi.get(vehicleId)
const detail = pickBxData<VehicleDetail>(res)
if (detail?.id) list.value = [detail, ...list.value]
} catch {
// ignore
}
}
return { list, loading, loaded, search, onFocus, reset, ensureById }
}
/** 承运商下拉:服务端按 q 检索 */
export function usePlRemoteCarrierOptions(options?: {
getSelectedId?: () => string | undefined
listParams?: { status?: string; auditStatus?: string }
}) {
const list = ref<Carrier[]>([])
const loading = ref(false)
const loaded = ref(false)
async function search(keyword: string) {
loading.value = true
try {
const res = await carrierApi.list({
...(options?.listParams || {}),
...(keyword.trim() ? { q: keyword.trim() } : {}),
page: 1,
pageSize: REMOTE_PAGE_SIZE
})
list.value = keepSelected(
pickBxList<Carrier>(res),
options?.getSelectedId?.(),
list.value
)
loaded.value = true
} catch (error) {
console.error('加载承运商选项失败', error)
list.value = []
} finally {
loading.value = false
}
}
function onFocus() {
if (!loaded.value) void search('')
}
function reset() {
list.value = []
loaded.value = false
}
async function ensureById(carrierId: string) {
if (!carrierId || list.value.some(item => item.id === carrierId)) return
try {
const res = await carrierApi.get(carrierId)
const detail = pickBxData<Carrier>(res)
if (detail?.id) list.value = [detail, ...list.value]
} catch {
// ignore
}
}
return { list, loading, loaded, search, onFocus, reset, ensureById }
}
/** 人员下拉:服务端按姓名/手机号 q 检索 */
export function usePlRemotePersonnelOptions(options?: {
getSelectedId?: () => string | undefined
listParams?: Omit<PersonnelQuery, 'q' | 'page' | 'pageSize'> | (() => Omit<PersonnelQuery, 'q' | 'page' | 'pageSize'>)
}) {
const list = ref<Personnel[]>([])
const loading = ref(false)
const loaded = ref(false)
async function search(keyword: string) {
loading.value = true
try {
const extra =
typeof options?.listParams === 'function' ? options.listParams() : options?.listParams || {}
const res = await personnelApi.list({
...extra,
...(keyword.trim() ? { q: keyword.trim() } : {}),
page: 1,
pageSize: REMOTE_PAGE_SIZE
})
list.value = keepSelected(
pickBxList<Personnel>(res),
options?.getSelectedId?.(),
list.value
)
loaded.value = true
} catch (error) {
console.error('加载人员选项失败', error)
list.value = []
} finally {
loading.value = false
}
}
function onFocus() {
if (!loaded.value) void search('')
}
function reset() {
list.value = []
loaded.value = false
}
/** 切换归属等过滤条件后需重新拉取 */
function invalidate() {
loaded.value = false
}
async function ensureById(personnelId: string) {
if (!personnelId || list.value.some(item => item.id === personnelId)) return
try {
const res = await personnelApi.get(personnelId)
const detail = pickBxData<Personnel>(res)
if (detail?.id) list.value = [detail, ...list.value]
} catch {
// ignore
}
}
return { list, loading, loaded, search, onFocus, reset, invalidate, ensureById }
}