Files
shanxia2.0/web-admin/src/api/pl/quota-cert.ts
T

458 lines
14 KiB
TypeScript

import request, { pickBxData } from '@/utils/http/bx'
export type CertType = 'purchase' | 'transport'
export interface PurchaseReference {
id?: string
referenceType: 'purchase_permit' | 'purchase_filing' | 'export_permit' | 'unknown'
referenceNo: string
purchaseCertId?: string | null
remark?: string | null
orderNum?: number | null
}
export interface CertBody {
certNo: string
issueDate?: string | null
productNameOnCert: string
totalQty: string | number
quantityUnit: string
validFrom?: string | null
validTo?: string | null
validUseText: string
entryMode: 'manual' | 'image_parse'
attachmentUrls?: string | null
status?: 'draft' | 'suspended' | 'void'
remark?: string | null
orderNum?: number | null
buyerName?: string | null
buyerAddress?: string | null
buyerLegalRepresentative?: string | null
buyerPhone?: string | null
sellerName?: string | null
sellerAddress?: string | null
sellerLegalRepresentative?: string | null
sellerPhone?: string | null
purchasePurpose?: string | null
shipperName?: string | null
shipperAddress?: string | null
shipperLegalRepresentative?: string | null
shipperPhone?: string | null
packagingText?: string | null
carrierName?: string | null
carrierAddressPhone?: string | null
transportMode?: string | null
vehicleNumbersJson?: string[]
routeText?: string | null
consigneeName?: string | null
applicantName?: string | null
contractBindings?: CertificateContractBinding[]
purchaseRefs?: PurchaseReference[]
}
export interface QuotaCert extends Omit<CertBody, 'status'> {
id: string
status: 'draft' | 'active' | 'suspended' | 'void'
bindingsEditable?: boolean
referencesEditable?: boolean
revision: number
reservedQty: string | number
usedQty: string | number
availableQty: string | number
verifiedTime?: string | null
openingConfirmed: boolean
usagePolicy: 'once' | 'multiple' | 'needs_confirmation'
createTime?: string
}
export interface ScopeProduct {
id?: string
contractProductId: string
scopeStatus?: 'active' | 'inactive'
remark?: string | null
orderNum?: number | null
}
export interface CertBinding {
id?: string
certType: CertType
certId: string
linkStatus?: 'active' | 'inactive'
products: ScopeProduct[]
scopeRevision?: number
remark?: string | null
orderNum?: number | null
}
export interface ContractOption {
id: string
contractNo: string
contractName: string
contractType?: string
}
export interface ContractProduct {
id: string
productId: string
productName: string
model?: string
unit?: string
quantity?: string | number
}
export interface LegalDocument {
id: string
planNo: string
archiveStatus: string
transportStatus: string
products: {
id: string
productId: string
productName: string
model?: string
legalUseCertUrl: string | null
documentStatus: 'uploaded' | 'pending'
contexts?: {
stopType: string
stopProductId: string
partyName?: string
address?: string
contractId?: string
contractNo?: string
contractProductId?: string
}[]
}[]
}
const base = '/transport/quota-certs'
export const quotaCertApi = {
list: (kind: CertType, params: { keyword?: string; status?: string } = {}) =>
request.get(`${base}/${kind}`, { params }).then(pickBxData<QuotaCert[]>),
get: (kind: CertType, id: string) =>
request.get(`${base}/${kind}/${id}`).then(pickBxData<QuotaCert>),
save: (kind: CertType, body: CertBody, id?: string) =>
(id ? request.put(`${base}/${kind}/${id}`, body) : request.post(`${base}/${kind}`, body)).then(
pickBxData<QuotaCert>
),
remove: (kind: CertType, id: string) => request.delete(`${base}/${kind}/${id}`),
confirm: (
kind: CertType,
id: string,
body: {
operationId: string
usedQty: string
singleUseConsumed: boolean
reason: string
sourceNote?: string
evidenceUrls?: string
}
) => request.post(`${base}/${kind}/${id}/confirm`, body).then(pickBxData<QuotaCert>),
verify: (kind: CertType, id: string, body: { operationId: string; reason: string }) =>
request.post(`${base}/${kind}/${id}/verify`, body).then(pickBxData<QuotaCert>),
recognize: (kind: CertType, attachmentUrl: string) =>
request.post(`${base}/${kind}/recognize`, { attachmentUrl }, { timeout: 90000 }).then(
pickBxData<{
candidates: Partial<CertBody>
invalidFields: Record<string, string>
requiresConfirmation: boolean
}>
),
contracts: (keyword = '') =>
request.get(`${base}/contracts`, { params: { keyword } }).then(pickBxData<ContractOption[]>),
products: (id: string) =>
request.get(`${base}/contracts/${id}/products`).then(pickBxData<ContractProduct[]>),
bindings: (id: string) =>
request.get(`${base}/contracts/${id}/bindings`).then(pickBxData<CertBinding[]>),
saveBindings: (id: string, bindings: CertBinding[]) =>
request.put(`${base}/contracts/${id}/bindings`, { bindings }).then(pickBxData<CertBinding[]>),
certificateContracts: (kind: CertType, id: string) =>
request.get(`${base}/${kind}/${id}/contracts`).then(pickBxData<ContractOption[]>)
}
const legalBase = '/transport/legal-use-documents'
export interface StopLegalDocumentItem {
stopType: 'load' | 'delivery'
stopId: string
stopOrder: number
stopProductId: string
productId: string
productName: string
model?: string
unit?: string
contractId?: string | null
contractNo?: string | null
contractProductId?: string | null
partyName?: string | null
address?: string | null
legalUseCertUrl: string
documentStatus: 'pending' | 'uploaded'
uploadedBy?: string | null
uploadedTime?: string | null
}
export interface StopLegalDocument {
id: string
planNo: string
planDate?: string
licensePlate?: string
transportStatus: string
archiveStatus: string
requiredCount: number
uploadedCount: number
documentStatus: 'pending' | 'uploaded' | 'not_required'
items: StopLegalDocumentItem[]
legacyProducts: {
id: string
productId: string
productName: string
model?: string
legalUseCertUrl?: string | null
}[]
}
export const legalDocumentApi = {
listStops: (params: {
keyword?: string
planNo?: string
status?: 'pending' | 'uploaded'
contractId?: string
page?: number
pageSize?: number
}) =>
request
.get(`${legalBase}/stops`, { params })
.then(
pickBxData<{ list: StopLegalDocument[]; total: number; page: number; pageSize: number }>
),
getStops: (id: string, contractId?: string) =>
request
.get(`${legalBase}/stops/${id}`, { params: { contractId } })
.then(pickBxData<StopLegalDocument>),
saveStops: (
id: string,
items: Pick<StopLegalDocumentItem, 'stopType' | 'stopProductId' | 'legalUseCertUrl'>[],
contractId?: string
) =>
request
.patch(`${legalBase}/stops/${id}`, { items }, { params: { contractId } })
.then(pickBxData<StopLegalDocument>),
list: (params: { keyword?: string; status?: string }) =>
request.get(legalBase, { params }).then(pickBxData<LegalDocument[]>),
get: (id: string) => request.get(`${legalBase}/${id}`).then(pickBxData<LegalDocument>),
save: (id: string, products: { id: string; legalUseCertUrl?: string | null }[]) =>
request.patch(`${legalBase}/${id}`, { products }).then(pickBxData<LegalDocument>)
}
export type MeasurementVersion = 'per_stop_v2' | 'legacy_single_side'
export interface QuotaSourceOption {
sourceStopId?: string
stopOrder?: number
contractNo?: string | null
bindingsReadable?: boolean
certificates?: { certType: CertType; certId: string; certNo: string; quantityUnit: string }[]
isToxic?: boolean
isExplosive?: boolean
sourceStopType: 'load' | 'delivery'
sourceStopProductId: string
planProductId: string
productName: string
model?: string
quantity: string | number
unit: string
contractId: string
contractProductId: string
partyName?: string
}
export interface QuotaSourcePair {
sourceStopType: 'load' | 'delivery'
sourceStopProductId: string
relatedStopProductIds: string[]
}
export interface ManualQuotaQuantity {
permitKind: CertType
sourceId: string
permitId: string
sourceQuantity: string | number
permitQuantity: string | number
note: string
}
export interface QuotaCondition {
certType: CertType
certId: string
certRevision: number
sourceFingerprint: string
partiesConfirmed: boolean
routeConfirmed: boolean
note: string
}
export interface QuotaConfiguration {
measurementVersion?: MeasurementVersion
sourceMapping?: QuotaSourcePair[] | null
purchaseCertIds: string[]
transportCertIds: string[]
manualAllocations: ManualQuotaQuantity[]
conditions: QuotaCondition[]
}
export interface PlanQuota {
measurementVersion?: MeasurementVersion
stopProducts?: QuotaSourceOption[]
planId: string
planNo: string
licensePlate?: string
canSaveConfiguration?: boolean
configuration: Partial<QuotaConfiguration>
sourceOptions: QuotaSourceOption[]
usages: Record<string, any>[]
}
export interface QuotaContext {
sourceFingerprint: string
sources: {
source_stop_type: string
source_stop_product_id: string
quantity: string
unit: string
snapshot: { stops: Record<string, any>[]; vehicle?: string; trailer?: string }
}[]
}
export interface QuotaPreview extends Partial<QuotaContext> {
status: string
reasons?: string[]
diagnostics?: {
certType: CertType
sourceIds: string[]
unit: string
demand: string
availableUpperBound: string | null
gapLowerBound: string | null
reason: string
}[]
purchaseAllocations?: Record<string, any>[]
transportAllocations?: Record<string, any>[]
}
export const planQuotaApi = {
get: (id: string) => request.get(`${base}/plans/${id}/usage`).then(pickBxData<PlanQuota>),
context: (id: string, body: QuotaConfiguration & QuotaPreviewVehicle) =>
request.post(`${base}/plans/${id}/context`, body).then(pickBxData<QuotaContext>),
preview: (id: string, body: QuotaConfiguration & QuotaPreviewVehicle) =>
request.post(`${base}/plans/${id}/preview`, body).then(pickBxData<QuotaPreview>),
save: (id: string, body: QuotaConfiguration) =>
request.put(`${base}/plans/${id}/configuration`, body).then(pickBxData<QuotaConfiguration>)
}
export interface QuotaPreviewVehicle {
targetLicensePlate?: string
targetTrailerNo?: string | null
}
export interface CertTotalAdjustment {
operationId: string
totalQty: string
reason: string
sourceNote: string
evidenceUrls: string
}
export const quotaAdjustmentApi = {
logs: (kind: CertType, id: string) =>
request.get(`${base}/${kind}/${id}/logs`).then(pickBxData<Record<string, any>[]>),
total: (kind: CertType, id: string, body: CertTotalAdjustment) =>
request.post(`${base}/${kind}/${id}/total-adjust`, body)
}
export type QuotaQuantity = string | number
export interface CertificateContractBinding {
editLocked?: boolean
id?: string
contractId: string
linkStatus?: 'active' | 'inactive'
products: ScopeProduct[]
scopeRevision?: number
remark?: string | null
orderNum?: number | null
}
export interface StatisticsPage<T> {
list: T[]
total: number
page: number
pageSize: number
}
export interface ContractStatisticsSummary extends ContractOption {
certCount: number
}
export interface CertificateStatisticsSummary {
id: string
certId: string
certType: CertType
certNo: string
productNameOnCert: string
quantityUnit: string
totalQty: QuotaQuantity
reservedQty: QuotaQuantity
usedQty: QuotaQuantity
availableQty: QuotaQuantity
status: string
validFrom: string | null
validTo: string | null
}
export interface StatisticsProduct {
id: string
contractProductId: string
productId: string
productName: string
model: string | null
unit: string | null
bindingId: string | null
scopeId: string | null
scopeStatus: string | null
linkStatus: string | null
reservedQty: QuotaQuantity
usedQty: QuotaQuantity
}
export interface StatisticsBinding {
bindingId: string | null
linkStatus: string | null
scopeRevision: number | null
contractReservedQty: QuotaQuantity
contractUsedQty: QuotaQuantity
products: StatisticsProduct[]
}
export interface ContractStatistics extends ContractOption {
certificates: (CertificateStatisticsSummary & StatisticsBinding & { productNames: string[] })[]
}
export interface StatisticsUsageItem {
partyName?: string | null
address?: string | null
id: string
usageId: string
certType: CertType
certId: string
planId: string
planNo: string
stopType: string
stopId: string
stopProductId: string
planProductId: string
contractId: string
contractProductId: string
productName: string
quantityUnit: string
reservedQty: QuotaQuantity
usedQty: QuotaQuantity
itemStatus: string
}
export interface CertificateStatistics extends CertificateStatisticsSummary {
contracts: (ContractOption & StatisticsBinding)[]
usageItems: StatisticsUsageItem[]
openingUsedQty: QuotaQuantity
unattributedUsedQty: QuotaQuantity
}
export interface StatisticsQuery {
contractNo?: string
certNo?: string
keyword?: string
page?: number
pageSize?: number
certType?: CertType
}
export const quotaStatisticsApi = {
contracts: (params: StatisticsQuery) =>
request
.get(`${base}/statistics/contracts`, { params })
.then(pickBxData<StatisticsPage<ContractStatisticsSummary>>),
certificates: (params: StatisticsQuery) =>
request
.get(`${base}/statistics/certificates`, { params })
.then(pickBxData<StatisticsPage<CertificateStatisticsSummary>>),
contract: (id: string) =>
request.get(`${base}/contracts/${id}/statistics`).then(pickBxData<ContractStatistics>),
certificate: (kind: CertType, id: string) =>
request.get(`${base}/${kind}/${id}/statistics`).then(pickBxData<CertificateStatistics>)
}