feat: 新增合同、订单明细导出功能,补充业务员字段展示

1.  新增crm订单主、订单明细的导出接口,支持业务精简字段导出
2.  为订单明细VO新增业务员字段,关联查询订单表填充数据
3.  在订单列表页新增业务员表格列展示
4.  为合同编辑页、订单明细页添加导出按钮并实现导出逻辑
5.  新增导出专用的VO类,处理日期格式化和状态转文本
This commit is contained in:
王文昊
2026-07-06 17:19:49 +08:00
parent e42eac9115
commit 93bb094566
12 changed files with 418 additions and 7 deletions

View File

@@ -64,3 +64,13 @@ export function listTodayOrder(query) {
params: query
})
}
// 导出正式订单主列表(业务精简字段)
export function exportOrder(query) {
return request({
url: '/crm/order/exportDetail',
method: 'post',
data: query,
responseType: 'blob'
})
}

View File

@@ -42,3 +42,13 @@ export function delOrderItem(itemId) {
method: 'delete'
})
}
// 导出正式订单明细列表(业务精简字段)
export function exportOrderItem(query) {
return request({
url: '/crm/orderItem/exportDetail',
method: 'post',
data: query,
responseType: 'blob'
})
}

View File

@@ -66,6 +66,7 @@
/>
<el-button type="primary" size="small" icon="el-icon-search" @click="handleQuery">筛选</el-button>
<el-button size="small" icon="el-icon-refresh" @click="resetQuery">重置</el-button>
<el-button size="small" icon="el-icon-download" @click="handleExport">导出</el-button>
<span v-if="total > 0" class="result-count"> {{ total }} 条记录</span>
</div>
@@ -130,6 +131,14 @@
</div>
</template>
</el-table-column>
<!-- 业务员 -->
<el-table-column label="业务员" width="110">
<template slot-scope="scope">
<el-select v-model="scope.row.salesman" size="small" style="width: 100%" @change="saveRow(scope.row)">
<el-option v-for="item in dict.type.wip_pack_saleman" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<!-- 签订日期 -->
<el-table-column label="签订日期" prop="signTime" width="100">
<template slot-scope="scope">
@@ -421,8 +430,10 @@
</template>
<script>
import { listOrder, updateOrder } from '@/api/crm/order'
import { listOrder, updateOrder, exportOrder } from '@/api/crm/order'
import { listCustomer } from '@/api/crm/customer'
import { blobValidate } from "@/utils/klp";
import { saveAs } from 'file-saver'
const STATUS_MAP = {
'0': { label: '草稿', type: 'info' },
@@ -433,6 +444,7 @@ const STATUS_MAP = {
export default {
name: 'ContractDetailEdit',
dicts: ['wip_pack_saleman'],
data() {
return {
loading: false,
@@ -628,7 +640,38 @@ export default {
}
this.customerDialogVisible = false
this.saveRow(row)
}
},
// 导出合同明细(按当前筛选条件)
handleExport() {
const params = {}
if (this.contractQuery.contractCode) params.contractCode = this.contractQuery.contractCode
if (this.contractQuery.supplier) params.supplier = this.contractQuery.supplier
if (this.contractQuery.customer) params.customer = this.contractQuery.customer
if (this.contractQuery.status !== undefined && this.contractQuery.status !== null) params.status = this.contractQuery.status
if (this.contractQuery.signDateStart) params.signDateStart = this.contractQuery.signDateStart
if (this.contractQuery.signDateEnd) params.signDateEnd = this.contractQuery.signDateEnd
if (this.contractQuery.deliveryDateStart) params.deliveryDateStart = this.contractQuery.deliveryDateStart
if (this.contractQuery.deliveryDateEnd) params.deliveryDateEnd = this.contractQuery.deliveryDateEnd
if (this.contractQuery.signLocation) params.signLocation = this.contractQuery.signLocation
exportOrder(params).then((res) => {
this.handleExportBlob(res, '合同编辑详情.xlsx')
}).catch(() => {})
},
// 处理blob文件导出
async handleExportBlob(res, fileName) {
const isBlob = blobValidate(res);
if (isBlob) {
saveAs(res, fileName);
this.$message.success('导出成功!');
} else {
const resText = await res.text();
const rspObj = JSON.parse(resText);
const errMsg = rspObj.msg || '导出失败';
this.$message.error(errMsg);
}
},
}
}
</script>

View File

@@ -21,6 +21,7 @@
<div class="toolbar">
<el-button type="danger" size="small" icon="el-icon-delete" :disabled="!selection.length" @click="handleBatchDelete">批量删除</el-button>
<el-button type="primary" size="small" icon="el-icon-download" @click="handleExport">导出</el-button>
<span class="toolbar-tip">合同列为只读明细列失焦自动保存需有修改权限</span>
</div>
@@ -50,6 +51,9 @@
<el-table-column label="供方" min-width="120" show-overflow-tooltip>
<template slot-scope="{ row }">{{ (row.orderInfo && row.orderInfo.supplier) || '-' }}</template>
</el-table-column>
<el-table-column label="业务员" min-width="80" show-overflow-tooltip>
<template slot-scope="{ row }">{{ (row.orderInfo && row.orderInfo.salesman) || row.salesman || '-' }}</template>
</el-table-column>
<el-table-column label="签订时间" width="110">
<template slot-scope="{ row }">{{ row.orderInfo && row.orderInfo.signTime ? parseTime(row.orderInfo.signTime, '{y}-{m}-{d}') : '-' }}</template>
</el-table-column>
@@ -201,7 +205,9 @@
</template>
<script>
import { listOrderItem, updateOrderItem, delOrderItem } from '@/api/crm/orderItem'
import { listOrderItem, updateOrderItem, delOrderItem, exportOrderItem } from '@/api/crm/orderItem'
import { blobValidate } from "@/utils/klp";
import { saveAs } from 'file-saver'
const ITEM_PAYLOAD_KEYS = [
'itemId',
@@ -354,7 +360,36 @@ export default {
console.error('批量删除失败:', err)
}
})
}
},
// 导出订单明细(按当前筛选条件)
handleExport() {
const params = {}
if (this.queryParams.contractCode) params.contractCode = this.queryParams.contractCode
if (this.queryParams.customer) params.customer = this.queryParams.customer
if (this.queryParams.material) params.material = this.queryParams.material
if (this.queryParams.orderId) {
const n = Number(this.queryParams.orderId)
params.orderId = Number.isNaN(n) ? this.queryParams.orderId : n
}
exportOrderItem(params).then((res) => {
this.handleExportBlob(res, '正式订单明细.xlsx')
}).catch(() => {})
},
// 处理blob文件导出
async handleExportBlob(res, fileName) {
const isBlob = blobValidate(res);
if (isBlob) {
saveAs(res, fileName);
this.$modal.msgSuccess('导出成功!');
} else {
const resText = await res.text();
const rspObj = JSON.parse(resText);
const errMsg = rspObj.msg || '导出失败';
this.$modal.msgError(errMsg);
}
},
}
}
</script>

View File

@@ -52,6 +52,7 @@
/>
<el-button type="primary" size="small" icon="el-icon-search" @click="handleQuery">筛选</el-button>
<el-button size="small" icon="el-icon-refresh" @click="resetQuery">重置</el-button>
<el-button size="small" icon="el-icon-download" @click="handleExport">导出</el-button>
<span class="sort-hint">已按合同签订日期默认当月结果按交货日期倒序排列</span>
</div>
@@ -96,6 +97,11 @@
<span class="contract-info" :title="row.customer">{{ row.customer }}</span>
</template>
</el-table-column>
<el-table-column label="业务员" width="80">
<template slot-scope="{ row }">
<span class="contract-info">{{ row._order && row._order.salesman ? row._order.salesman : '-' }}</span>
</template>
</el-table-column>
<el-table-column label="签订日期" prop="signTime" width="100">
<template slot-scope="{ row }">
<span class="contract-info contract-date">{{ formatDate(row.signTime) }}</span>
@@ -270,8 +276,10 @@
</template>
<script>
import { listOrder, updateOrder } from '@/api/crm/order'
import { listOrder, updateOrder, exportOrder } from '@/api/crm/order'
import { parseProductContent, stringifyProductContent, calculateProductFields, recalculateTotals } from '@/utils/productContent'
import { blobValidate } from "@/utils/klp";
import { saveAs } from 'file-saver'
export default {
name: 'OrderItemList',
@@ -555,6 +563,34 @@ export default {
this.getList()
},
// 导出订单明细(按当前筛选条件)
handleExport() {
const params = {}
if (this.queryParams.contractCode) params.contractCode = this.queryParams.contractCode
if (this.queryParams.customer) params.customer = this.queryParams.customer
if (this.queryParams.signDateStart) params.signDateStart = this.queryParams.signDateStart
if (this.queryParams.signDateEnd) params.signDateEnd = this.queryParams.signDateEnd
if (this.queryParams.deliveryDateStart) params.deliveryDateStart = this.queryParams.deliveryDateStart
if (this.queryParams.deliveryDateEnd) params.deliveryDateEnd = this.queryParams.deliveryDateEnd
exportOrder(params).then((res) => {
this.handleExportBlob(res, '订单明细列表.xlsx')
}).catch(() => {})
},
// 处理blob文件导出
async handleExportBlob(res, fileName) {
const isBlob = blobValidate(res);
if (isBlob) {
saveAs(res, fileName);
this.$message.success('导出成功!');
} else {
const resText = await res.text();
const rspObj = JSON.parse(resText);
const errMsg = rspObj.msg || '导出失败';
this.$message.error(errMsg);
}
},
groupRowClassName({ row, rowIndex }) {
if (row.productIndex === 0) {
return 'group-row-a'