1、调整导入运单
2、调整对账
This commit is contained in:
@@ -13,11 +13,14 @@ export const getDetail = (id, waybillId) =>
|
||||
...(waybillId === undefined ? {} : { waybillId }),
|
||||
},
|
||||
});
|
||||
export const getVoucherImages = waybillId =>
|
||||
export const getVoucherImages = (waybillId, params = {}) =>
|
||||
request({
|
||||
url: '/blade-transport/process-config/voucher-images',
|
||||
method: 'get',
|
||||
params: { waybillId },
|
||||
params: {
|
||||
waybillId,
|
||||
...params,
|
||||
},
|
||||
});
|
||||
export const submit = api.submit;
|
||||
export const remove = api.remove;
|
||||
|
||||
@@ -26,6 +26,8 @@ export const replaceFolderByObject = (voucherId, plateNo, fileInfo) =>
|
||||
export const removeFolder = (voucherId, plateNo) =>
|
||||
request({ url: `${baseUrl}/folder-remove`, method: 'post', params: { voucherId, plateNo } });
|
||||
export const submit = data => request({ url: `${baseUrl}/submit`, method: 'post', data });
|
||||
export const changeWaybillBatch = data =>
|
||||
request({ url: `${baseUrl}/change-waybill-batch`, method: 'post', data });
|
||||
export const createUploadDraft = data =>
|
||||
request({ url: `${baseUrl}/upload-draft`, method: 'post', data });
|
||||
export const completeUploadFile = data =>
|
||||
|
||||
@@ -1949,18 +1949,61 @@
|
||||
label="批量补录"
|
||||
name="batchSupplement"
|
||||
>
|
||||
<div
|
||||
v-if="waybillVoucherFolderView"
|
||||
class="waybill-manage-page__voucher-folder-toolbar"
|
||||
>
|
||||
<el-button text type="primary" @click="backToWaybillVoucherFolders">
|
||||
返回文件夹
|
||||
</el-button>
|
||||
<span>{{ waybillVoucherFolderName(waybillVoucherFolder) }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-loading="waybillVoucherImagesLoading"
|
||||
class="waybill-manage-page__voucher-image-grid"
|
||||
>
|
||||
<div
|
||||
v-for="(image, index) in waybillVoucherImages"
|
||||
:key="image.id || image.objectKey || index"
|
||||
class="waybill-manage-page__voucher-image-item"
|
||||
:title="image.imageName"
|
||||
@click="previewWaybillVoucherImage(index)"
|
||||
:key="
|
||||
image.id ||
|
||||
image.objectKey ||
|
||||
(isWaybillVoucherFolder(image)
|
||||
? `${image.voucherId || 'folder'}-${image.folderName || image.name || index}`
|
||||
: index)
|
||||
"
|
||||
:class="[
|
||||
'waybill-manage-page__voucher-image-item',
|
||||
{
|
||||
'waybill-manage-page__voucher-image-item--folder':
|
||||
isWaybillVoucherFolder(image),
|
||||
},
|
||||
]"
|
||||
:title="
|
||||
isWaybillVoucherFolder(image)
|
||||
? waybillVoucherFolderName(image)
|
||||
: image.imageName || image.name
|
||||
"
|
||||
@click="
|
||||
isWaybillVoucherFolder(image)
|
||||
? openWaybillVoucherFolder(image)
|
||||
: previewWaybillVoucherImage(index)
|
||||
"
|
||||
>
|
||||
<el-image :src="image.url" fit="cover" lazy />
|
||||
<el-image
|
||||
:src="
|
||||
isWaybillVoucherFolder(image)
|
||||
? image.icon || '/img/文件夹.png'
|
||||
: image.url
|
||||
"
|
||||
:fit="isWaybillVoucherFolder(image) ? 'contain' : 'cover'"
|
||||
lazy
|
||||
/>
|
||||
<div
|
||||
v-if="isWaybillVoucherFolder(image)"
|
||||
class="waybill-manage-page__voucher-folder-name"
|
||||
>
|
||||
{{ waybillVoucherFolderName(image) }}
|
||||
</div>
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!waybillVoucherImagesLoading && !waybillVoucherImages.length"
|
||||
@@ -3039,6 +3082,9 @@ export default {
|
||||
waybillProcessDetailTab: 'punch',
|
||||
waybillHasRelatedVoucher: false,
|
||||
waybillVoucherImages: [],
|
||||
waybillVoucherFolders: [],
|
||||
waybillVoucherFolder: null,
|
||||
waybillVoucherFolderView: false,
|
||||
waybillVoucherImagesLoading: false,
|
||||
waybillVoucherImagesLoaded: false,
|
||||
waybillRouteChangeBox: false,
|
||||
@@ -4118,6 +4164,9 @@ export default {
|
||||
this.waybillProcessDetailTab = 'punch';
|
||||
this.waybillHasRelatedVoucher = false;
|
||||
this.waybillVoucherImages = [];
|
||||
this.waybillVoucherFolders = [];
|
||||
this.waybillVoucherFolder = null;
|
||||
this.waybillVoucherFolderView = false;
|
||||
this.waybillVoucherImagesLoaded = false;
|
||||
const request =
|
||||
typeof this.api.getDetail === 'function'
|
||||
@@ -4222,6 +4271,11 @@ export default {
|
||||
getProcessConfigVoucherImages(this.detailRow.id)
|
||||
.then(res => {
|
||||
this.waybillVoucherImages = extractRecords(res);
|
||||
this.waybillVoucherFolders = this.waybillVoucherImages.filter(item =>
|
||||
this.isWaybillVoucherFolder(item)
|
||||
);
|
||||
this.waybillVoucherFolder = null;
|
||||
this.waybillVoucherFolderView = false;
|
||||
if (this.waybillVoucherImages.length) this.waybillHasRelatedVoucher = true;
|
||||
this.waybillVoucherImagesLoaded = true;
|
||||
})
|
||||
@@ -4229,11 +4283,49 @@ export default {
|
||||
this.waybillVoucherImagesLoading = false;
|
||||
});
|
||||
},
|
||||
isWaybillVoucherFolder(item) {
|
||||
return Boolean(item && (item.isFolder === true || item.type === 'folder'));
|
||||
},
|
||||
waybillVoucherFolderName(folder) {
|
||||
return folder?.folderName || folder?.name || folder?.plateNo || '凭证文件夹';
|
||||
},
|
||||
openWaybillVoucherFolder(folder) {
|
||||
if (!this.detailRow.id || !this.isWaybillVoucherFolder(folder)) return;
|
||||
if (!folder.voucherId || !folder.folderName) {
|
||||
this.$message.warning('凭证文件夹信息不完整');
|
||||
return;
|
||||
}
|
||||
this.waybillVoucherImagesLoading = true;
|
||||
getProcessConfigVoucherImages(this.detailRow.id, {
|
||||
voucherId: folder.voucherId,
|
||||
folderName: folder.folderName,
|
||||
})
|
||||
.then(res => {
|
||||
this.waybillVoucherFolder = folder;
|
||||
this.waybillVoucherImages = extractRecords(res).filter(
|
||||
item => !this.isWaybillVoucherFolder(item)
|
||||
);
|
||||
this.waybillVoucherFolderView = true;
|
||||
})
|
||||
.finally(() => {
|
||||
this.waybillVoucherImagesLoading = false;
|
||||
});
|
||||
},
|
||||
backToWaybillVoucherFolders() {
|
||||
this.waybillVoucherImages = [...this.waybillVoucherFolders];
|
||||
this.waybillVoucherFolder = null;
|
||||
this.waybillVoucherFolderView = false;
|
||||
},
|
||||
previewWaybillVoucherImage(index) {
|
||||
this.attachmentImagePreviewUrls = this.waybillVoucherImages
|
||||
const imageRows = this.waybillVoucherImages.filter(
|
||||
image => !this.isWaybillVoucherFolder(image)
|
||||
);
|
||||
const currentImage = this.waybillVoucherImages[index];
|
||||
const imageIndex = imageRows.findIndex(image => image === currentImage);
|
||||
this.attachmentImagePreviewUrls = imageRows
|
||||
.map(image => image.url)
|
||||
.filter(Boolean);
|
||||
this.attachmentImagePreviewIndex = index;
|
||||
this.attachmentImagePreviewIndex = imageIndex >= 0 ? imageIndex : 0;
|
||||
this.attachmentImagePreviewVisible = this.attachmentImagePreviewUrls.length > 0;
|
||||
},
|
||||
buildWaybillRouteNodes(rows = []) {
|
||||
@@ -8984,6 +9076,7 @@ export default {
|
||||
}
|
||||
|
||||
&__voucher-image-item {
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
@@ -8995,6 +9088,42 @@ export default {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&--folder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
|
||||
.el-image {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__voucher-folder-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 32px;
|
||||
margin-bottom: 8px;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&__voucher-folder-name {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__route-change-dialog {
|
||||
|
||||
@@ -1389,7 +1389,7 @@ export default {
|
||||
this.page.total = result.total || 0;
|
||||
this.data = result.records || [];
|
||||
this.selectionClear();
|
||||
this.refreshFundRiskStats({ ...params, ...this.query, allDept: this.allDept });
|
||||
// this.refreshFundRiskStats({ ...params, ...this.query, allDept: this.allDept });
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<el-table-column prop="processStatus" label="处理状态" width="130" />
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="180" />
|
||||
<el-table-column prop="updateTime" label="更新时间" min-width="180" />
|
||||
<el-table-column label="操作" width="220" fixed="right"><template #default="{ row }"><div class="voucher-folder-page__actions"><el-link v-if="row.matched !== 1" type="primary" @click="openReplace(row)">单个上传</el-link><el-link type="primary" @click="openViewer(row)">查看</el-link><el-link type="danger" @click="removeFolder(row)">删除</el-link></div></template></el-table-column>
|
||||
<el-table-column label="操作" width="220" fixed="right"><template #default="{ row }"><div class="voucher-folder-page__actions"><el-link v-if="isSuperAdmin && row.matched !== 1" type="primary" @click="openReplace(row)">单个上传</el-link><el-link type="primary" @click="openViewer(row)">查看</el-link><el-link type="danger" @click="removeFolder(row)">删除</el-link></div></template></el-table-column>
|
||||
</el-table>
|
||||
<div class="voucher-folder-page__pagination"><el-pagination v-model:current-page="page.current" v-model:page-size="page.size" :total="page.total" :page-sizes="[10, 20, 50]" layout="total, prev, pager, next, sizes" @current-change="load" @size-change="load" /></div>
|
||||
</section>
|
||||
@@ -39,15 +39,23 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import md5 from 'js-md5';
|
||||
import * as api from '@/api/business/voucher-manage';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const store = useStore();
|
||||
const voucherId = route.query.id;
|
||||
const isSuperAdmin = computed(() => {
|
||||
const authority = store.getters.userInfo?.authority;
|
||||
return Array.isArray(authority)
|
||||
? authority.includes('admin')
|
||||
: String(authority || '').includes('admin');
|
||||
});
|
||||
const loading = ref(false), rows = ref([]), voucher = ref({ voucherBatchNo: route.query.batchNo || '' });
|
||||
const page = reactive({ current: 1, size: 10, total: 0 });
|
||||
const query = reactive({ plateNo: '', matched: undefined });
|
||||
|
||||
@@ -90,9 +90,9 @@
|
||||
width="100"
|
||||
/><el-table-column
|
||||
prop="relatedWaybillCount"
|
||||
label="已关联运单"
|
||||
width="115"
|
||||
/><el-table-column prop="unRelatedWaybillCount" label="未关联运单" width="115" />
|
||||
label="凭证已关联数量"
|
||||
width="125"
|
||||
/><el-table-column prop="unRelatedWaybillCount" label="凭证未关联数量" width="125" />
|
||||
<el-table-column prop="createTime" label="创建时间" min-width="170" />
|
||||
<el-table-column
|
||||
prop="auditStatus"
|
||||
@@ -100,7 +100,16 @@
|
||||
width="120"
|
||||
fixed="right"
|
||||
align="center"
|
||||
/><el-table-column label="操作" width="320" fixed="right" align="left"
|
||||
><template #default="{ row }"
|
||||
><span class="voucher-manage-page__audit-status"
|
||||
><span>{{ row.auditStatus }}</span
|
||||
><el-tooltip
|
||||
v-if="row.auditStatus === '审核驳回' && hasRejectReason(row)"
|
||||
:content="row.rejectReason"
|
||||
placement="top"
|
||||
><el-icon class="voucher-manage-page__audit-reject-icon"><WarnTriangleFilled /></el-icon
|
||||
></el-tooltip></span></template
|
||||
></el-table-column><el-table-column label="操作" width="320" fixed="right" align="center"
|
||||
><template #default="{ row }"
|
||||
><div class="voucher-manage-page__actions">
|
||||
<el-link
|
||||
@@ -128,12 +137,12 @@
|
||||
><el-link
|
||||
v-if="row.auditStatus === '审核驳回'"
|
||||
type="primary"
|
||||
@click="openUpload(row, 'changeBatch')"
|
||||
@click="openBatchDialog(row)"
|
||||
>更换运单批次</el-link
|
||||
><el-link
|
||||
v-if="row.processStatus !== '处理完成' || row.auditStatus === '待审核'"
|
||||
v-if="(row.processStatus !== '处理完成' || row.auditStatus === '待审核') && row.auditStatus !== '审核驳回'"
|
||||
type="primary"
|
||||
@click="openUpload(row)"
|
||||
@click="openBatchDialog(row)"
|
||||
>更换运单批次</el-link
|
||||
><el-link
|
||||
v-if="row.processStatus === '上传中' || row.auditStatus === '审核驳回'"
|
||||
@@ -328,7 +337,11 @@
|
||||
placeholder="请输入" /></el-form-item></el-col
|
||||
><el-col :span="12"
|
||||
><el-form-item label="运单数"
|
||||
><el-input-number v-model="batchQuery.waybillCount" :min="0" /></el-form-item></el-col
|
||||
><el-input
|
||||
v-model="batchQuery.waybillCount"
|
||||
clearable
|
||||
placeholder="请输入"
|
||||
@input="handleWaybillCountInput" /></el-form-item></el-col
|
||||
></el-row>
|
||||
<div class="voucher-manage-page__search-actions">
|
||||
<el-button type="primary" @click="loadBatches">查询</el-button
|
||||
@@ -373,7 +386,7 @@
|
||||
</div>
|
||||
<template #footer
|
||||
><el-button @click="batchVisible = false">取消</el-button
|
||||
><el-button type="primary" @click="confirmBatches">确认</el-button></template
|
||||
><el-button type="primary" :loading="batchSaving" @click="confirmBatches">确认</el-button></template
|
||||
>
|
||||
</el-dialog>
|
||||
|
||||
@@ -484,6 +497,7 @@ import { useRouter } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
import md5 from 'js-md5';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { WarnTriangleFilled } from '@element-plus/icons-vue';
|
||||
import { getList as getProjectList } from '@/api/business/project-apply';
|
||||
import * as api from '@/api/business/voucher-manage';
|
||||
import SectionCard from '@/components/section-card/main.vue';
|
||||
@@ -499,6 +513,12 @@ const hasPermission = code => {
|
||||
if (isAdmin.value) return true;
|
||||
return permission.value?.[code] === true;
|
||||
};
|
||||
const hasRejectReason = row => {
|
||||
const reason = row?.rejectReason;
|
||||
return typeof reason === 'string'
|
||||
? reason.trim().length > 0
|
||||
: reason !== undefined && reason !== null;
|
||||
};
|
||||
|
||||
// 判断当前用户是否为承运商(顶级组织是否为"外部组织")
|
||||
const isCarrier = ref(false);
|
||||
@@ -521,6 +541,9 @@ const loading = ref(false),
|
||||
detailRow = ref({}),
|
||||
uploadVisible = ref(false),
|
||||
batchVisible = ref(false),
|
||||
batchDialogMode = ref('upload'),
|
||||
batchTarget = ref(),
|
||||
batchSaving = ref(false),
|
||||
progressVisible = ref(false),
|
||||
uploadFormRef = ref(),
|
||||
uploading = ref(false),
|
||||
@@ -862,9 +885,16 @@ watch(uploadVisible, visible => {
|
||||
// 兜底处理:右上角、遮罩、Esc 直接修改 v-model 时仍必须停止上传。
|
||||
if (!visible && !closingUploadDialog.value) void stopCurrentUpload(editing.fileTaskId);
|
||||
});
|
||||
const openBatchDialog = async () => {
|
||||
const openBatchDialog = async row => {
|
||||
batchDialogMode.value = row ? 'change' : 'upload';
|
||||
batchTarget.value = row;
|
||||
batchSelection.value = [];
|
||||
batchVisible.value = true;
|
||||
await loadBatches();
|
||||
if (row?.waybillBatchNo) {
|
||||
const currentBatch = batchRows.value.find(item => item.batchNo === row.waybillBatchNo);
|
||||
if (currentBatch) batchSelection.value = [currentBatch];
|
||||
}
|
||||
};
|
||||
const loadBatches = async () => {
|
||||
const res = await api.getWaybillBatches(batchPage.current, batchPage.size, {
|
||||
@@ -878,13 +908,56 @@ const loadBatches = async () => {
|
||||
batchRows.value = data.records || [];
|
||||
batchPage.total = data.total || 0;
|
||||
};
|
||||
const handleWaybillCountInput = value => {
|
||||
// 只允许输入正整数
|
||||
const filtered = value.replace(/[^\d]/g, '');
|
||||
if (filtered !== value) {
|
||||
batchQuery.waybillCount = filtered;
|
||||
}
|
||||
// 移除前导零
|
||||
if (filtered.length > 1 && filtered.startsWith('0')) {
|
||||
batchQuery.waybillCount = filtered.replace(/^0+/, '');
|
||||
}
|
||||
};
|
||||
const resetBatchQuery = () => {
|
||||
Object.assign(batchQuery, { batchNo: '', createUser: '', waybillCount: undefined });
|
||||
batchCreateRange.value = [];
|
||||
batchPage.current = 1;
|
||||
loadBatches();
|
||||
};
|
||||
const selectBatch = row => {
|
||||
const updateWaybillBatch = async (target, selected) => {
|
||||
if (!target?.id) {
|
||||
ElMessage.error('缺少凭证批次信息');
|
||||
return false;
|
||||
}
|
||||
if (!selected?.batchNo) {
|
||||
ElMessage.warning('请选择运单批次');
|
||||
return false;
|
||||
}
|
||||
batchSaving.value = true;
|
||||
try {
|
||||
await api.changeWaybillBatch({
|
||||
voucherId: target.id,
|
||||
waybillImportBatchIds: [selected.id],
|
||||
});
|
||||
target.waybillBatchNo = selected.batchNo;
|
||||
batchVisible.value = false;
|
||||
ElMessage.success('运单批次更换成功,已提交重新匹配任务');
|
||||
await load();
|
||||
return true;
|
||||
} catch (error) {
|
||||
ElMessage.error(error.message || '运单批次更换失败');
|
||||
return false;
|
||||
} finally {
|
||||
batchSaving.value = false;
|
||||
}
|
||||
};
|
||||
const selectBatch = async row => {
|
||||
if (batchDialogMode.value === 'change') {
|
||||
batchSelection.value = [row];
|
||||
await updateWaybillBatch(batchTarget.value, row);
|
||||
return;
|
||||
}
|
||||
const batches = new Map();
|
||||
selectedBatches.value.forEach(item => {
|
||||
if (!batches.has(item.batchNo)) batches.set(item.batchNo, item);
|
||||
@@ -894,7 +967,12 @@ const selectBatch = row => {
|
||||
editing.waybillImportBatchIds = selectedBatches.value.map(item => item.id);
|
||||
batchVisible.value = false;
|
||||
};
|
||||
const confirmBatches = () => {
|
||||
const confirmBatches = async () => {
|
||||
if (batchDialogMode.value === 'change') {
|
||||
const selected = batchSelection.value[0];
|
||||
await updateWaybillBatch(batchTarget.value, selected);
|
||||
return;
|
||||
}
|
||||
const batches = new Map();
|
||||
batchSelection.value.forEach(item => {
|
||||
if (!batches.has(item.batchNo)) batches.set(item.batchNo, item);
|
||||
@@ -1240,9 +1318,19 @@ load();
|
||||
padding: 0;
|
||||
min-height: auto;
|
||||
}
|
||||
&__audit-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
&__audit-reject-icon {
|
||||
margin-left: 4px;
|
||||
color: #f56c6c;
|
||||
cursor: help;
|
||||
}
|
||||
&__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 2px 12px;
|
||||
}
|
||||
&__pagination {
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
:precision="2"
|
||||
disabled
|
||||
/>
|
||||
<span v-else-if="field.prop === 'reconciliationMode'">
|
||||
{{ reconciliationModeLabel }}
|
||||
</span>
|
||||
<span v-else>{{ displayValue(form[field.prop]) }}</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -1084,6 +1087,7 @@ export default {
|
||||
const params = {
|
||||
settlementType: this.settlementType,
|
||||
keyword: this.formalDialog.query.keyword,
|
||||
approvalStatus: 'draft',
|
||||
};
|
||||
const data = this.unwrapData(
|
||||
await api.getFormalOptions(
|
||||
@@ -1098,7 +1102,7 @@ export default {
|
||||
const fallback = await formalSettlementApi.getList(
|
||||
this.formalDialog.page.current,
|
||||
this.formalDialog.page.size,
|
||||
{ ...params, approvalStatus: 'approved' }
|
||||
params
|
||||
);
|
||||
const fallbackData = this.unwrapData(fallback);
|
||||
rows = fallbackData.records || [];
|
||||
|
||||
Reference in New Issue
Block a user