| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- import type { CertRow } from '@/api/pl'
- export const PL_PERSONNEL_CERT_MISSING_SUFFIX = '(证书缺失)'
- export const PL_PERSONNEL_DRIVER_REQUIRED_CERT_NAMES = [
- '身份证',
- '驾驶证',
- '驾驶员从业资格证'
- ] as const
- export const PL_PERSONNEL_ESCORT_REQUIRED_CERT_NAMES = [
- '身份证',
- '押运员从业资格证'
- ] as const
- export const PL_PERSONNEL_BOTH_REQUIRED_CERT_NAMES = [
- '身份证',
- '驾驶证',
- '驾驶员从业资格证',
- '押运员从业资格证'
- ] as const
- export type PersonnelCertRole = 'driver' | 'escort'
- export type PersonnelType = 'driver' | 'escort' | 'both'
- export const PL_PERSONNEL_TYPE_OPTIONS = [
- { value: 'driver', label: '驾驶员' },
- { value: 'escort', label: '押运员' },
- { value: 'both', label: '驾驶员兼押运员' }
- ] as const
- export type PersonnelAffiliation = 'self' | 'carrier'
- export const PL_PERSONNEL_AFFILIATION_OPTIONS = [
- { value: 'self', label: '山峡' },
- { value: 'carrier', label: '非山峡' }
- ] as const
- export function getPersonnelAffiliationLabel(affiliation?: string | null): string {
- const found = PL_PERSONNEL_AFFILIATION_OPTIONS.find(item => item.value === affiliation)
- return found?.label || affiliation || '—'
- }
- export function getPersonnelAffiliationTagType(
- affiliation?: string | null
- ): 'success' | 'warning' | 'info' {
- if (affiliation === 'self') return 'success'
- if (affiliation === 'carrier') return 'warning'
- return 'info'
- }
- export function validatePersonnelAffiliationVehicleCompat(
- personnelAffiliation: string | undefined,
- vehicleType: string | undefined,
- onError: (message: string) => void
- ): boolean {
- if (!personnelAffiliation || !vehicleType) return true
- if (personnelAffiliation === vehicleType) return true
- const vehicleLabel = vehicleType === 'self' ? '山峡' : '非山峡'
- onError(`${vehicleLabel}车辆仅可关联${vehicleLabel}人员`)
- return false
- }
- export function getPersonnelTypeLabel(type?: string | null): string {
- const found = PL_PERSONNEL_TYPE_OPTIONS.find(item => item.value === type)
- return found?.label || type || '—'
- }
- export function getPersonnelTypeTagType(type?: string | null): 'success' | 'warning' | 'primary' | 'info' {
- if (type === 'driver') return 'primary'
- if (type === 'escort') return 'warning'
- if (type === 'both') return 'success'
- return 'info'
- }
- export function getRequiredPersonnelCertNamesByType(
- personnelType?: string | null
- ): readonly string[] {
- if (personnelType === 'escort') {
- return PL_PERSONNEL_ESCORT_REQUIRED_CERT_NAMES
- }
- if (personnelType === 'driver') {
- return PL_PERSONNEL_DRIVER_REQUIRED_CERT_NAMES
- }
- return PL_PERSONNEL_BOTH_REQUIRED_CERT_NAMES
- }
- /** 车辆关联人员:从人员主数据类型映射为关联角色(司机/押运员) */
- export function mapPersonnelTypeToVehicleRole(
- personnelType?: string | null
- ): 'driver' | 'escort' | undefined {
- if (personnelType === 'driver') return 'driver'
- if (personnelType === 'escort') return 'escort'
- if (personnelType === 'both') return 'driver'
- return undefined
- }
- export function validatePersonnelTypeRoleCompat(
- personnelType: string | undefined,
- role: string | undefined,
- onError: (message: string) => void
- ): boolean {
- if (!personnelType || !role) return true
- if (personnelType === 'driver' && role === 'escort') {
- onError('驾驶员类型人员不可关联为押运员')
- return false
- }
- if (personnelType === 'escort' && role === 'driver') {
- onError('押运员类型人员不可关联为驾驶员')
- return false
- }
- return true
- }
- export function isPersonnelCertStrictComplete(
- cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls'> | undefined,
- requiredName: string
- ): boolean {
- if (!cert?.certName?.trim()) return false
- if (!matchRequiredCertName(cert.certName, requiredName)) return false
- if (!cert.expireDate) return false
- // 证书附件非必填
- return true
- }
- export function matchRequiredCertName(
- actualName: string | undefined,
- requiredName: string
- ): boolean {
- const name = actualName?.trim() || ''
- if (!name) return false
- if (requiredName === '押运员从业资格证') {
- return name === '押运员从业资格证' || name === '押运员证'
- }
- return name === requiredName
- }
- export function isPersonnelCertUploaded(cert?: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls'>) {
- return Boolean(cert?.certName?.trim() && cert?.expireDate)
- }
- export function getRequiredPersonnelCertNames(role: PersonnelCertRole): readonly string[] {
- return role === 'driver'
- ? PL_PERSONNEL_DRIVER_REQUIRED_CERT_NAMES
- : PL_PERSONNEL_ESCORT_REQUIRED_CERT_NAMES
- }
- export function getMissingPersonnelCertNames(
- role: PersonnelCertRole,
- certList: CertRow[] = []
- ): string[] {
- return getRequiredPersonnelCertNames(role).filter(requiredName => {
- const matched = certList.find(cert => matchRequiredCertName(cert.certName, requiredName))
- return !isPersonnelCertUploaded(matched)
- })
- }
- export function hasPersonnelCertMissing(
- role: PersonnelCertRole,
- certList: CertRow[] = []
- ): boolean {
- return getMissingPersonnelCertNames(role, certList).length > 0
- }
- /** 人员主数据页:按人员类型检查必备证书 */
- export function hasPersonnelMasterCertMissing(
- certList: CertRow[] = [],
- personnelType?: string | null
- ): boolean {
- const required = getRequiredPersonnelCertNamesByType(personnelType || 'both')
- return required.some(requiredName => {
- const matched = certList.find(cert => matchRequiredCertName(cert.certName, requiredName))
- return !isPersonnelCertStrictComplete(matched, requiredName)
- })
- }
- export function getPersonnelCertMissingSuffix(
- certList: CertRow[] = [],
- role?: PersonnelCertRole,
- personnelType?: string | null
- ): string {
- if (personnelType) {
- return hasPersonnelMasterCertMissing(certList, personnelType)
- ? PL_PERSONNEL_CERT_MISSING_SUFFIX
- : ''
- }
- if (role) {
- return hasPersonnelCertMissing(role, certList) ? PL_PERSONNEL_CERT_MISSING_SUFFIX : ''
- }
- return hasPersonnelMasterCertMissing(certList) ? PL_PERSONNEL_CERT_MISSING_SUFFIX : ''
- }
- export const PL_PERSONNEL_CERT_SHORT_LABELS: Record<string, string> = {
- 身份证: '身',
- 驾驶证: '驾',
- 驾驶员从业资格证: '业',
- 押运员从业资格证: '押'
- }
- export type PersonnelCertBadgeStatus = 'missing' | 'valid' | 'expiring' | 'expired'
- export interface PersonnelCertBadgeItem {
- requiredName: string
- shortLabel: string
- status: PersonnelCertBadgeStatus
- title: string
- }
- function getPersonnelCertMissingFieldLabels(
- cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls'> | undefined,
- requiredName: string
- ): string[] {
- if (!cert || !matchRequiredCertName(cert.certName, requiredName)) {
- return ['有效期']
- }
- const missing: string[] = []
- if (!cert.expireDate) missing.push('有效期')
- // 证书附件非必填
- return missing
- }
- function formatPersonnelCertBadgeTooltip(
- requiredName: string,
- status: PersonnelCertBadgeStatus,
- cert?: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls' | 'remindDays'>
- ): string {
- if (status === 'missing') {
- if (!cert || !matchRequiredCertName(cert.certName, requiredName)) {
- return `${requiredName}:缺失(未登记该证书)`
- }
- const missing = getPersonnelCertMissingFieldLabels(cert, requiredName)
- return `${requiredName}:缺失(缺少${missing.join('、')})`
- }
- const expireDate = cert?.expireDate || '—'
- const expDate = new Date(expireDate)
- const today = new Date()
- today.setHours(0, 0, 0, 0)
- expDate.setHours(0, 0, 0, 0)
- const diffDays = Math.ceil((expDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
- const certNo = cert?.certNo?.trim()
- const certNoText = certNo ? `,证号 ${certNo}` : ''
- if (status === 'expired') {
- return `${requiredName}:已过期,有效期 ${expireDate},已过期 ${Math.abs(diffDays)} 天${certNoText}`
- }
- if (status === 'expiring') {
- return `${requiredName}:临期,有效期 ${expireDate},剩余 ${diffDays} 天${certNoText}`
- }
- return `${requiredName}:正常,有效期 ${expireDate}${certNoText}`
- }
- export function getPersonnelCertBadgeStatus(
- cert: Pick<CertRow, 'certName' | 'certNo' | 'expireDate' | 'attachmentUrls' | 'remindDays'> | undefined,
- requiredName: string
- ): PersonnelCertBadgeStatus {
- if (!isPersonnelCertStrictComplete(cert, requiredName)) {
- return 'missing'
- }
- const expireDate = cert?.expireDate
- if (!expireDate) return 'missing'
- const remindDays = cert?.remindDays ?? 30
- const expDate = new Date(expireDate)
- const today = new Date()
- today.setHours(0, 0, 0, 0)
- expDate.setHours(0, 0, 0, 0)
- const diffDays = Math.ceil((expDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24))
- if (diffDays <= 0) return 'expired'
- if (diffDays <= remindDays) return 'expiring'
- return 'valid'
- }
- export function getPersonnelRequiredCertBadges(
- personnelType: string | null | undefined,
- certList: CertRow[] = []
- ): PersonnelCertBadgeItem[] {
- return getRequiredPersonnelCertNamesByType(personnelType).map(requiredName => {
- const matched = certList.find(cert => matchRequiredCertName(cert.certName, requiredName))
- const status = getPersonnelCertBadgeStatus(matched, requiredName)
- const shortLabel = PL_PERSONNEL_CERT_SHORT_LABELS[requiredName] || requiredName.slice(0, 1)
- return {
- requiredName,
- shortLabel,
- status,
- title: formatPersonnelCertBadgeTooltip(requiredName, status, matched)
- }
- })
- }
|