Files
tms-erp-web/src/views/business/components/voucher-execution-detail.vue
T
gxwebsoft 6de87ed4e2 style(contract): 优化合同管理页面表单样式与布局
- 调整合同管理备注输入框行数和最大长度
- 细化合同变更页面表单项间距和对齐方式
- 统一弹窗表单项的底部间距样式,改为注释禁用
- 调整 port-terminal 和 region 组件的表单项底部间距
- 修改 vite 配置中 API 请求代理地址
- 优化凭证执行详情搜索表单列宽布局
- 在运单管理页面更新型号字段为非必填,调整变更记录内容格式化显示
- 引入并使用 formatRouteChangeContent 工具函数
- 统一明细按钮显示逻辑,草稿状态也显示详情按钮
- 新增路由变更相关工具函数与样式支持
2026-10-14 12:44:56 +08:00

275 lines
8.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="voucher-folder-page voucher-folder-page--embedded">
<section class="voucher-folder-page__search">
<el-form :model="query" label-position="right">
<div class="voucher-folder-page__search-grid">
<el-form-item label="车牌号">
<el-input v-model="query.plateNo" clearable placeholder="请输入" />
</el-form-item>
<el-form-item label="是否关联运单">
<el-select v-model="query.matched" clearable placeholder="全部">
<el-option label="是" :value="1" />
<el-option label="否" :value="0" />
</el-select>
</el-form-item>
<div class="voucher-folder-page__search-actions">
<el-button type="primary" @click="search">查询</el-button>
<el-button @click="reset">重置</el-button>
</div>
</div>
</el-form>
</section>
<section class="voucher-folder-page__table-wrap">
<div class="voucher-folder-page__title">{{ batchTitle }}</div>
<el-table v-loading="loading" :data="pageRows" border class="voucher-folder-page__table">
<el-table-column type="index" label="序号" width="70" :index="rowIndex" />
<el-table-column prop="voucherNo" label="执行凭证号" min-width="220">
<template #default="{ row }">
<el-link type="primary" @click="openViewer(row)">{{ row.voucherNo }}</el-link>
</template>
</el-table-column>
<el-table-column prop="plateNo" label="车牌号" min-width="150" />
<el-table-column prop="folderName" label="文件夹名称" min-width="160" />
<el-table-column prop="matched" label="是否关联运单" width="130">
<template #default="{ row }">{{ row.matched === 1 ? '是' : '否' }}</template>
</el-table-column>
<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="120" fixed="right">
<template #default="{ row }">
<div class="voucher-folder-page__actions">
<el-link type="primary" @click="openViewer(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="filteredRows.length"
:page-sizes="[10, 20, 50]"
layout="total, prev, pager, next, sizes"
@size-change="page.current = 1"
/>
</div>
</section>
<el-dialog v-model="viewerVisible" title="执行凭证详情" width="960px" destroy-on-close>
<div v-loading="viewerLoading" class="voucher-folder-page__viewer">
<div class="voucher-folder-page__viewer-info">
<span>执行凭证号:{{ viewer.voucherNo || '-' }}</span>
<span>文件夹名称:{{ viewer.folderName || '-' }}</span>
<span>是否关联运单:{{ viewer.matched === 1 ? '是' : '否' }}</span>
<span>
配载单号:
<el-link v-if="viewer.loadingNo" type="primary" @click="goToLoading(viewer.loadingNo)">
{{ viewer.loadingNo }}
</el-link>
<template v-else>-</template>
</span>
</div>
<div v-if="viewerFiles.length" class="voucher-folder-page__images">
<el-image
v-for="(file, index) in viewerFiles"
:key="file.id || file.url || index"
:src="file.url"
:preview-src-list="viewerFiles.map(item => item.url).filter(Boolean)"
:initial-index="index"
fit="cover"
/>
</div>
<el-empty v-else description="暂无凭证文件" />
</div>
</el-dialog>
</div>
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage } from 'element-plus';
import { getVoucherFolderDetail, getVoucherFolders } from '@/api/business/process-config';
const props = defineProps({
waybillId: {
type: [String, Number],
default: '',
},
});
const router = useRouter();
const loading = ref(false);
const rows = ref([]);
const page = reactive({ current: 1, size: 10 });
const query = reactive({ plateNo: '', matched: undefined });
const appliedQuery = reactive({ plateNo: '', matched: undefined });
const viewerVisible = ref(false);
const viewerLoading = ref(false);
const viewer = ref({});
const viewerFiles = ref([]);
const batchTitle = computed(() => {
const batchNos = [...new Set(rows.value.map(item => item.voucherBatchNo).filter(Boolean))];
return batchNos.length === 1 ? batchNos[0] : '执行凭证详情';
});
const filteredRows = computed(() => {
const plateNo = String(appliedQuery.plateNo || '').trim();
return rows.value.filter(item => {
const plateMatched = !plateNo || String(item.plateNo || '').includes(plateNo);
const relatedMatched =
appliedQuery.matched === undefined || appliedQuery.matched === null || appliedQuery.matched === ''
? true
: item.matched === appliedQuery.matched;
return plateMatched && relatedMatched;
});
});
const pageRows = computed(() => {
const start = (page.current - 1) * page.size;
return filteredRows.value.slice(start, start + page.size);
});
const rowIndex = index => (page.current - 1) * page.size + index + 1;
const load = async () => {
if (!props.waybillId) {
rows.value = [];
return;
}
loading.value = true;
try {
const res = await getVoucherFolders(props.waybillId);
rows.value = res.data?.data || [];
} catch (error) {
rows.value = [];
ElMessage.error(error.message || '获取执行凭证失败');
} finally {
loading.value = false;
}
};
const search = () => {
appliedQuery.plateNo = query.plateNo;
appliedQuery.matched = query.matched;
page.current = 1;
};
const reset = () => {
query.plateNo = '';
query.matched = undefined;
search();
};
const openViewer = async row => {
viewerVisible.value = true;
viewerLoading.value = true;
viewer.value = row;
viewerFiles.value = [];
try {
const res = await getVoucherFolderDetail(row.voucherId, row.plateNo);
viewer.value = res.data?.data || row;
viewerFiles.value = viewer.value.files || [];
} catch (error) {
ElMessage.error(error.message || '获取凭证详情失败');
} finally {
viewerLoading.value = false;
}
};
const goToLoading = loadingNo => {
router.push({ path: '/business/loading-manage', query: { loadingNo } });
};
watch(
() => props.waybillId,
() => {
page.current = 1;
load();
},
{ immediate: true }
);
</script>
<style scoped lang="scss">
.voucher-folder-page {
&__search {
padding: 12px 12px 4px;
margin-bottom: 8px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
&__search-grid {
display: grid;
grid-template-columns: 220px 220px 1fr;
gap: 8px 24px;
}
&__search-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
&__table-wrap {
padding: 12px;
background: #fff;
}
&__title {
padding-bottom: 12px;
color: #303133;
font-size: 16px;
font-weight: 600;
}
&__actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
&__pagination {
display: flex;
justify-content: flex-end;
padding-top: 12px;
}
&__viewer {
min-height: 360px;
}
&__viewer-info {
display: flex;
flex-wrap: wrap;
gap: 28px;
padding-bottom: 20px;
color: #303133;
}
&__images {
display: grid;
grid-template-columns: repeat(5, 140px);
gap: 20px;
}
&__images :deep(.el-image) {
width: 140px;
height: 100px;
border: 6px solid #cfcfcf;
cursor: zoom-in;
}
:deep(.el-table) {
--el-table-border-color: #eff1f7;
}
:deep(.el-table__body tr:nth-child(even) > td) {
background: #fafafa;
}
:deep(.el-form-item) {
margin-bottom: 8px;
}
:deep(.el-form-item__label) {
white-space: nowrap;
}
:deep(.el-input),
:deep(.el-select) {
width: 100%;
}
}
@media (max-width: 900px) {
.voucher-folder-page__search-grid {
grid-template-columns: 1fr 1fr;
}
.voucher-folder-page__search-actions {
grid-column: 1 / -1;
}
}
</style>