diff --git a/src/api/business/waybill-manage.js b/src/api/business/waybill-manage.js index 6b1645c..d9ba828 100644 --- a/src/api/business/waybill-manage.js +++ b/src/api/business/waybill-manage.js @@ -7,6 +7,7 @@ const api = createCrudApi(baseUrl); export const getList = api.getList; export const getDetail = api.getDetail; export const submit = api.submit; +export const saveDraft = data => request({ url: `${baseUrl}/save-draft`, method: 'post', data }); export const remove = api.remove; export const copy = api.copy; export const cancel = api.cancel; diff --git a/src/api/payment/billLedger.js b/src/api/payment/billLedger.js index 706c051..d268f2b 100644 --- a/src/api/payment/billLedger.js +++ b/src/api/payment/billLedger.js @@ -12,6 +12,12 @@ export const getAvailableOptions = (keyword, deptId, selectedId) => method: 'get', params: { keyword, deptId, selectedId }, }); +export const getAvailablePage = (current, size, keyword, deptId, selectedId) => + request({ + url: `${baseUrl}/available-page`, + method: 'get', + params: { current, size, keyword, deptId, selectedId }, + }); export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data }); export const remove = id => request({ url: `${baseUrl}/remove`, method: 'post', params: { id } }); diff --git a/src/api/payment/paymentApplication.js b/src/api/payment/paymentApplication.js index bc772d0..c51a9de 100644 --- a/src/api/payment/paymentApplication.js +++ b/src/api/payment/paymentApplication.js @@ -24,11 +24,6 @@ export const paymentTypeOptions = [ { label: '进度预付', value: 'progress_advance' }, { label: '结算付款', value: 'settlement_payment' }, ]; -export const paymentMethodOptions = [ - { label: '银行转账', value: 'bank_transfer' }, - { label: '银行承兑汇票', value: 'bank_draft' }, - { label: '商业承兑汇票', value: 'commercial_draft' }, -]; export const approvalStatusOptions = [ { label: '草稿', value: 'draft' }, { label: '审批中', value: 'reviewing' }, diff --git a/src/api/settlement/preSettlement.js b/src/api/settlement/preSettlement.js index 2b96d13..bb61417 100644 --- a/src/api/settlement/preSettlement.js +++ b/src/api/settlement/preSettlement.js @@ -10,6 +10,18 @@ export const getDetail = id => request({ url: `${baseUrl}/detail`, method: 'get' export const getContractOptions = keyword => request({ url: `${baseUrl}/contract-options`, method: 'get', params: { keyword } }); +export const getContractList = (current, size, params) => + request({ + url: '/blade-transport/contract-manage/list', + method: 'get', + params: { + current, + size, + approvalStatuses: 'approved,change_approved', + ...params, + }, + }); + export const getFeeOptions = () => request({ url: `${baseUrl}/fee-options`, method: 'get' }); export const getCandidateDetails = (current, size, params) => diff --git a/src/option/business/transport-plan.js b/src/option/business/transport-plan.js index 0b65b82..ec940fb 100644 --- a/src/option/business/transport-plan.js +++ b/src/option/business/transport-plan.js @@ -1,7 +1,6 @@ import { auditColumns, createCrudOption, - dataSourceOptions, phoneRule, planStatusOptions, selectRule, @@ -9,6 +8,12 @@ import { withSearchPlaceholders, } from './common'; +const transportPlanDataSourceOptions = [ + { label: '批量导入', value: '批量导入' }, + { label: '手工创建', value: '手工创建' }, + { label: '外部系统', value: '外部系统' }, +]; + const listDicFormatter = res => { const data = res?.data || res; if (Array.isArray(data)) return data; @@ -61,7 +66,17 @@ const getSecondCargoTypeName = item => '货物'; const formatGoodsInfo = row => { - const rows = parseGoodsRows(row.goodsJson); + const rows = [ + row.goodsJson, + row.goodsList, + row.goodsRows, + row.cargoList, + row.cargoRows, + row.goods, + ] + .map(source => parseGoodsRows(source)) + .filter(source => source.length) + .sort((left, right) => right.length - left.length)[0] || []; if (!rows.length) return row.goodsInfo || ''; const groups = rows.reduce((result, item = {}) => { @@ -78,11 +93,22 @@ const formatGoodsInfo = row => { item.goodsQuantity, item.quantityUnit, item.goodsQuantityUnit, + item.cargoUnit, item.unit, ].some(Boolean); if (!hasGoodsInfo) return result; - const unit = item.quantityUnit || item.goodsQuantityUnit || item.unit || ''; + const unit = String( + item.quantityUnit || + item.goodsQuantityUnit || + item.cargoUnit || + item.unit || + row.quantityUnit || + row.goodsQuantityUnit || + row.cargoUnit || + row.unit || + '' + ).trim(); if (!result[unit]) { result[unit] = { typeName: getSecondCargoTypeName(item), @@ -388,7 +414,7 @@ export const option = { type: 'select', search: true, searchOrder: 1, - dicData: dataSourceOptions, + dicData: transportPlanDataSourceOptions, minWidth: 120, addDisplay: false, editDisplay: false, diff --git a/src/option/business/waybill-manage.js b/src/option/business/waybill-manage.js index 352c40f..4ddf551 100644 --- a/src/option/business/waybill-manage.js +++ b/src/option/business/waybill-manage.js @@ -207,6 +207,26 @@ const getFirstValue = (row, props) => { const getGoodsRows = row => parseJsonArray(row.goodsList || row.goodsRows || row.goodsJson); +const getDetailedGoodsRows = row => { + const goodsRows = [ + row.goodsJson, + row.goodsList, + row.goodsRows, + row.cargoList, + row.cargoRows, + row.goods, + ] + .map(source => { + if (source === undefined || source === null || source === '') return []; + if (Array.isArray(source)) return source; + if (typeof source === 'object') return [source]; + return parseJsonArray(source); + }) + .filter(source => source.length) + .sort((left, right) => right.length - left.length); + return goodsRows[0] || []; +}; + const getBillingRows = row => { const freightRows = parseJsonArray(row.freightList || row.freightRows || row.freightJson); if (freightRows.length) return freightRows; @@ -218,9 +238,25 @@ const getBillingRows = row => { const joinText = list => list.filter(item => !isEmpty(item)).join('/'); const formatGoodsInfo = row => { + const goodsRows = [ + row.goodsJson, + row.goodsList, + row.goodsRows, + row.cargoList, + row.cargoRows, + row.goods, + ] + .map(source => { + if (source === undefined || source === null || source === '') return []; + if (Array.isArray(source)) return source; + if (typeof source === 'object') return [source]; + return parseJsonArray(source); + }) + .filter(source => source.length) + .sort((left, right) => right.length - left.length)[0] || []; const text = getFirstValue(row, ['goodsInfo', 'cargoInfo']); - if (text) return text; - return getGoodsRows(row) + if (!goodsRows.length) return text || ''; + return goodsRows .map(item => { const name = getFirstValue(item, ['cargoName', 'goodsName', 'name']); const type = getFirstValue(item, ['cargoType', 'goodsType', 'typeName']); @@ -228,12 +264,13 @@ const formatGoodsInfo = row => { normalizeNumericDisplayValue( getFirstValue(item, ['quantity', 'cargoQuantity', 'goodsQuantity']) ), - getFirstValue(item, ['quantityUnit', 'cargoUnit', 'unit']), + getFirstValue(item, ['quantityUnit', 'goodsQuantityUnit', 'cargoUnit', 'unit']) || + getFirstValue(row, ['quantityUnit', 'goodsQuantityUnit', 'cargoUnit', 'unit']), ]); return joinText([name, type, quantity]); }) .filter(Boolean) - .join('; '); + .join('; ') || text || ''; }; const formatGoodsField = (row, props) => { @@ -246,6 +283,28 @@ const formatGoodsField = (row, props) => { const formatUnitPrice = row => { const value = normalizeNumericDisplayValue(getFirstValue(row, ['unitPrice', 'price'])); const unit = getFirstValue(row, ['priceUnit', 'billingUnit', 'unit']); + + const goodsRows = getDetailedGoodsRows(row); + if (goodsRows.length > 1) { + const billingRows = getBillingRows(row); + const goodsPrices = goodsRows + .map((item, index) => { + const itemPrice = normalizeNumericDisplayValue( + getFirstValue(item, ['unitPrice', 'price']) + ); + if (!isEmpty(itemPrice)) return itemPrice; + return normalizeNumericDisplayValue( + getFirstValue(billingRows[index] || {}, ['unitPrice', 'price']) + ); + }) + .filter(itemPrice => !isEmpty(itemPrice)); + const priceKeys = goodsPrices.map(itemPrice => { + const numericPrice = Number(itemPrice); + return Number.isFinite(numericPrice) ? String(numericPrice) : String(itemPrice).trim(); + }); + if (new Set(priceKeys).size > 1) return '-'; + } + if (!isEmpty(value)) return unit ? `${value}(${unit})` : value; const billing = getBillingRows(row).find( item => !isEmpty(normalizeNumericDisplayValue(item.unitPrice)) diff --git a/src/option/payment/invoiceApplication.js b/src/option/payment/invoiceApplication.js index 5c4a708..a2cef3c 100644 --- a/src/option/payment/invoiceApplication.js +++ b/src/option/payment/invoiceApplication.js @@ -21,8 +21,8 @@ export const invoiceApplicationDetailColumns = [ { prop: 'vehicleNo', label: '车号', minWidth: 120 }, { prop: 'departureAddress', label: '发货地址', minWidth: 180 }, { prop: 'arrivalAddress', label: '到货地址', minWidth: 180 }, - { prop: 'actualDepartureTime', label: '实际发货时间', minWidth: 170 }, - { prop: 'actualCompletionTime', label: '实际完成时间', minWidth: 170 }, + { prop: 'actualDepartureTime', label: '实际发货时间', minWidth: 170, dateTime: true }, + { prop: 'actualCompletionTime', label: '实际完成时间', minWidth: 170, dateTime: true }, { prop: 'transportType', label: '运输类型', minWidth: 120 }, { prop: 'cargoName', label: '货物名称', minWidth: 140 }, { prop: 'cargoType', label: '货物类型', minWidth: 130 }, diff --git a/src/option/settlement/receivable-payable-detail.js b/src/option/settlement/receivable-payable-detail.js index dd91680..745ca2e 100644 --- a/src/option/settlement/receivable-payable-detail.js +++ b/src/option/settlement/receivable-payable-detail.js @@ -138,4 +138,11 @@ export const generatePreviewColumns = [ { label: '货物名称', prop: 'cargoName', minWidth: 140 }, { label: '货物类型', prop: 'cargoType', minWidth: 140 }, { label: '规格', prop: 'specification', minWidth: 140 }, + { label: '型号', prop: 'model', minWidth: 120 }, + { label: '计费要素', prop: 'billingFactor', minWidth: 130 }, + { label: '计费类型', prop: 'billingType', minWidth: 130 }, + { label: '运输量', prop: 'transportQuantityText', minWidth: 120 }, + { label: '运费计算单位', prop: 'priceUnit', minWidth: 130 }, + { label: '运输单价', prop: 'unitPrice', minWidth: 120 }, + { label: '里程(KM)', prop: 'mileage', minWidth: 120 }, ]; diff --git a/src/views/base/fee-item.vue b/src/views/base/fee-item.vue index de2b752..fd56038 100644 --- a/src/views/base/fee-item.vue +++ b/src/views/base/fee-item.vue @@ -35,7 +35,6 @@ v-model="form.feeCategory" class="fee-item-form-control" clearable - :disabled="dialogType !== 'add'" filterable placeholder="请选择费用类型" @change="handleFeeCategoryChange" @@ -43,7 +42,7 @@ @@ -54,7 +53,6 @@ :maxlength="feeItemCodeMaxlength" class="fee-item-form-control" clearable - :disabled="dialogType !== 'add'" placeholder="请输入费用项代码" @change="handleFeeItemCodeChange" > @@ -339,31 +337,63 @@ export default { values.englishName = this.getFeeItemCodeSuffix(values.englishName, values.feeCategory); return values; }, + validateUnique(row) { + const rowId = String(row.id || ''); + const hasDuplicate = (params, prop) => { + if (!row[prop]) { + return Promise.resolve(false); + } + return getList(1, 100, params).then(res => { + const records = res.data.data.records || []; + return records.some( + item => + String(item[prop] || '').trim() === String(row[prop]).trim() && + String(item.id || '') !== rowId + ); + }); + }; + return Promise.all([ + hasDuplicate({ name: row.name }, 'name'), + hasDuplicate({ englishName: row.englishName }, 'englishName'), + ]).then(([nameExists, codeExists]) => { + if (nameExists) { + return Promise.reject(new Error('该费用项已存在')); + } + if (codeExists) { + return Promise.reject(new Error('该费用项代码已存在')); + } + return Promise.resolve(); + }); + }, + handleSubmitError(error, loading) { + const uniqueMessages = ['该费用项已存在', '该费用项代码已存在']; + if (uniqueMessages.includes(error.message)) { + this.$message.warning(error.message); + } + window.console.log(error); + loading(); + }, rowSave(row, done, loading) { - submit(this.normalizeRow(row)).then( - () => { + const submitRow = this.normalizeRow(row); + this.validateUnique(submitRow) + .then(() => submit(submitRow)) + .then(() => { this.onLoad(this.page); this.$message({ type: 'success', message: '操作成功!' }); done(); - }, - error => { - window.console.log(error); - loading(); - } - ); + }) + .catch(error => this.handleSubmitError(error, loading)); }, rowUpdate(row, index, done, loading) { - submit(this.normalizeRow(row)).then( - () => { + const submitRow = this.normalizeRow(row); + this.validateUnique(submitRow) + .then(() => submit(submitRow)) + .then(() => { this.onLoad(this.page); this.$message({ type: 'success', message: '操作成功!' }); done(); - }, - error => { - window.console.log(error); - loading(); - } - ); + }) + .catch(error => this.handleSubmitError(error, loading)); }, rowDel(row) { this.$confirm('确定将选择数据删除?', { diff --git a/src/views/base/port-terminal.vue b/src/views/base/port-terminal.vue index 79589de..94ed862 100644 --- a/src/views/base/port-terminal.vue +++ b/src/views/base/port-terminal.vue @@ -110,7 +110,9 @@ maxlength="24" placeholder="请输入码头标识" @input="handleTerminalCodeChange" - /> + > + + -