提交
This commit is contained in:
1 parent
d84f4b944c
commit
7c838cfb2d
249 files changed
+50600
-18556
No files matched your search
@@ -0,0 +1,55 @@
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
export type DateShortcutType = 'all' | 'today' | 'tomorrow' | 'yesterday' | 'week'
|
||||
|
||||
function formatYmd(date: Date): string {
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表工具栏计划日期快捷筛选(全部 / 昨日 / 今日 / 明日 / 本周)
|
||||
*/
|
||||
export function useListDateShortcut(dateRange: Ref<string[]>, onSearch: () => void) {
|
||||
const activeDateShortcut = ref<DateShortcutType>('all')
|
||||
|
||||
function handleDateShortcut(type: DateShortcutType) {
|
||||
activeDateShortcut.value = type
|
||||
const today = new Date()
|
||||
|
||||
if (type === 'all') {
|
||||
dateRange.value = []
|
||||
} else if (type === 'today') {
|
||||
const d = formatYmd(today)
|
||||
dateRange.value = [d, d]
|
||||
} else if (type === 'tomorrow') {
|
||||
const t = new Date(today)
|
||||
t.setDate(t.getDate() + 1)
|
||||
const d = formatYmd(t)
|
||||
dateRange.value = [d, d]
|
||||
} else if (type === 'yesterday') {
|
||||
const y = new Date(today)
|
||||
y.setDate(y.getDate() - 1)
|
||||
const d = formatYmd(y)
|
||||
dateRange.value = [d, d]
|
||||
} else if (type === 'week') {
|
||||
const start = new Date(today)
|
||||
const day = start.getDay() || 7
|
||||
start.setDate(start.getDate() - day + 1)
|
||||
const end = new Date(start)
|
||||
end.setDate(start.getDate() + 6)
|
||||
dateRange.value = [formatYmd(start), formatYmd(end)]
|
||||
}
|
||||
|
||||
onSearch()
|
||||
}
|
||||
|
||||
function resetDateShortcut() {
|
||||
activeDateShortcut.value = 'all'
|
||||
dateRange.value = []
|
||||
}
|
||||
|
||||
return { activeDateShortcut, handleDateShortcut, resetDateShortcut }
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
export interface ListColumnDef {
|
||||
prop: string
|
||||
label: string
|
||||
/** 默认是否显示;未指定时为 true */
|
||||
defaultVisible?: boolean
|
||||
/** 为 true 时不可取消勾选(如固定展示列) */
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export interface UsePersistedListColumnsOptions {
|
||||
/** 默认可见列 prop 列表;未指定时取 defaultVisible !== false 的列 */
|
||||
defaultVisibleProps?: string[]
|
||||
}
|
||||
|
||||
function resolveDefaultVisibleProps(
|
||||
columns: ListColumnDef[],
|
||||
options?: UsePersistedListColumnsOptions
|
||||
): string[] {
|
||||
if (options?.defaultVisibleProps?.length) {
|
||||
return [...options.defaultVisibleProps]
|
||||
}
|
||||
return columns.filter((col) => col.defaultVisible !== false).map((col) => col.prop)
|
||||
}
|
||||
|
||||
function loadVisibleColumns(
|
||||
storageKey: string,
|
||||
columns: ListColumnDef[],
|
||||
defaultVisibleProps: string[]
|
||||
): string[] {
|
||||
const allowed = new Set(columns.map((col) => col.prop))
|
||||
if (typeof localStorage === 'undefined') {
|
||||
return defaultVisibleProps.filter((prop) => allowed.has(prop))
|
||||
}
|
||||
const saved = localStorage.getItem(storageKey)
|
||||
if (!saved) {
|
||||
return defaultVisibleProps.filter((prop) => allowed.has(prop))
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(saved)
|
||||
if (!Array.isArray(parsed)) {
|
||||
return defaultVisibleProps.filter((prop) => allowed.has(prop))
|
||||
}
|
||||
return parsed.filter((prop): prop is string => typeof prop === 'string' && allowed.has(prop))
|
||||
} catch {
|
||||
return defaultVisibleProps.filter((prop) => allowed.has(prop))
|
||||
}
|
||||
}
|
||||
|
||||
function persistVisibleColumns(storageKey: string, visibleColumns: string[]) {
|
||||
if (typeof localStorage === 'undefined') return
|
||||
try {
|
||||
localStorage.setItem(storageKey, JSON.stringify(visibleColumns))
|
||||
} catch {
|
||||
// ignore quota / private mode errors
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表可选列显隐 + localStorage 持久化。
|
||||
* 勾选变化会自动写入 storageKey 对应键。
|
||||
*/
|
||||
export function usePersistedListColumns(
|
||||
storageKey: string,
|
||||
columns: ListColumnDef[],
|
||||
options?: UsePersistedListColumnsOptions
|
||||
) {
|
||||
const columnDefs = columns
|
||||
const defaultVisibleProps = resolveDefaultVisibleProps(columns, options)
|
||||
const visibleColumns = ref<string[]>(
|
||||
loadVisibleColumns(storageKey, columns, defaultVisibleProps)
|
||||
)
|
||||
|
||||
watch(
|
||||
visibleColumns,
|
||||
(value) => {
|
||||
persistVisibleColumns(storageKey, value)
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const toggleableColumns = computed(() => columnDefs.filter((col) => !col.disabled))
|
||||
|
||||
const checkAll = computed({
|
||||
get() {
|
||||
const toggleable = toggleableColumns.value
|
||||
if (!toggleable.length) return false
|
||||
return toggleable.every((col) => visibleColumns.value.includes(col.prop))
|
||||
},
|
||||
set(checked: boolean) {
|
||||
visibleColumns.value = checked
|
||||
? toggleableColumns.value.map((col) => col.prop)
|
||||
: columnDefs.filter((col) => col.disabled).map((col) => col.prop)
|
||||
}
|
||||
})
|
||||
|
||||
const isIndeterminate = computed(() => {
|
||||
const toggleable = toggleableColumns.value
|
||||
if (!toggleable.length) return false
|
||||
const checkedCount = toggleable.filter((col) =>
|
||||
visibleColumns.value.includes(col.prop)
|
||||
).length
|
||||
return checkedCount > 0 && checkedCount < toggleable.length
|
||||
})
|
||||
|
||||
const isColumnVisible = (prop: string) => visibleColumns.value.includes(prop)
|
||||
|
||||
const setColumnVisible = (prop: string, visible: boolean) => {
|
||||
const target = columnDefs.find((col) => col.prop === prop)
|
||||
if (!target || target.disabled) return
|
||||
const next = new Set(visibleColumns.value)
|
||||
if (visible) {
|
||||
next.add(prop)
|
||||
} else {
|
||||
next.delete(prop)
|
||||
}
|
||||
visibleColumns.value = columnDefs
|
||||
.filter((col) => col.disabled || next.has(col.prop))
|
||||
.map((col) => col.prop)
|
||||
}
|
||||
|
||||
const resetToDefault = () => {
|
||||
visibleColumns.value = [...defaultVisibleProps]
|
||||
}
|
||||
|
||||
return {
|
||||
columnDefs,
|
||||
visibleColumns,
|
||||
checkAll,
|
||||
isIndeterminate,
|
||||
isColumnVisible,
|
||||
setColumnVisible,
|
||||
resetToDefault
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from '@/api/pl'
|
||||
import type { PlanFormProductRow } from '@/composables/usePlContractToPlan'
|
||||
import { loadVehicleViewBundle, type VehicleViewBundle } from '@/composables/usePlVehicleViewDetail'
|
||||
import { snapshotToVehicleViewBundle } from '@/utils/pl-transport-resource-snapshot'
|
||||
import { enrichPlanProductsHazardFromCrm } from '@/composables/usePlToxicProductCertCheck'
|
||||
import { pickBxData } from '@/utils/http/bx'
|
||||
|
||||
@@ -235,7 +236,9 @@ export function usePlPlanViewDetail() {
|
||||
)
|
||||
}
|
||||
|
||||
if (data?.vehicleId) {
|
||||
if (data?.resourceSnapshot) {
|
||||
vehicleBundle.value = snapshotToVehicleViewBundle(data.resourceSnapshot)
|
||||
} else if (data?.vehicleId) {
|
||||
detailTasks.push(
|
||||
loadVehicleViewBundle(data.vehicleId)
|
||||
.then((bundle) => {
|
||||
|
||||
@@ -108,5 +108,5 @@ export function buildMissingHazardCertMessage(products: PlanProduct[]) {
|
||||
const missing = findMissingHazardCerts(products)
|
||||
if (!missing.length) return ''
|
||||
const names = missing.map(p => `「${p.productName}」`).join('、')
|
||||
return `以下产品须上传购买证和运输证:${names}`
|
||||
return `以下产品须上传购买证和合法使用证明:${names}`
|
||||
}
|
||||
Reference in new issue
Block a user