216 lines
5.8 KiB
TypeScript
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 }
|
|
}
|