|
|
<template> <div class="mod-config"> <!-- 条件查询 --> <el-card :class="['search-card', { 'collapsed': !searchExpanded }]" shadow="hover"> <div slot="header" class="search-header"> <div class="header-left"> <i class="el-icon-search"></i> <span class="header-title">Search</span> </div> <div class="header-right"> <el-button type="text" size="small" @click="toggleSearchExpand" class="collapse-btn"> <span>{{ searchExpanded ? '收起' : '展开' }}</span> <i :class="searchExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i> </el-button> </div> </div>
<el-form :inline="true" label-position="top" :model="searchData" class="search-form" @keyup.enter.native="getDataList">
<template v-if="searchExpanded"> <el-row :gutter="16"> <el-col :span="2"> <el-form-item label="BU"> <el-select v-model="searchData.buNo" placeholder="请选择" clearable style="width: 100%"> <el-option v-for="i in userBuList" :key="i.buNo" :label="i.buDesc" :value="i.buNo"> </el-option> </el-select> </el-form-item> </el-col> <el-col :span="2"> <el-form-item label="变动类型"> <el-select v-model="searchData.documentType" placeholder="请选择" clearable style="width: 100%"> <el-option v-for="item in documentTypeList" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="变动单号"> <el-input v-model="searchData.transactionId" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="标签条码"> <el-input v-model="searchData.rollNo" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="物料编码"> <el-input v-model="searchData.partNo" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="物料名称"> <el-input v-model="searchData.partDesc" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="规格型号"> <el-input v-model="searchData.spec" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="16"> <el-col :span="3"> <el-form-item label="传输状态"> <el-select v-model="searchData.syncedFlag" placeholder="请选择" clearable style="width: 100%"> <el-option label="已传输" value="Y"></el-option> <el-option label="待传输" value="N"></el-option> </el-select> </el-form-item> </el-col> <el-col :span="3"> <el-form-item label="通知单号"> <el-input v-model="searchData.documentNo" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="3"> <el-form-item label="关联单号"> <el-input v-model="searchData.orderNo" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="3"> <el-form-item label="关联单行号"> <el-input v-model="searchData.orderLineNo" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="合约号码"> <el-input v-model="searchData.batchNo" clearable placeholder="请输入"></el-input> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="变动日期"> <el-date-picker v-model="searchData.startDate" type="datetime" value-format="yyyy-MM-dd HH:mm" format="yyyy-MM-dd HH:mm" placeholder="开始日期" style="width: 44%"> </el-date-picker> <span style="margin: 0 8px; color: #DCDFE6;">~</span> <el-date-picker v-model="searchData.endDate" type="datetime" value-format="yyyy-MM-dd HH:mm" format="yyyy-MM-dd HH:mm" placeholder="结束日期" style="width: 44%"> </el-date-picker> </el-form-item> </el-col> </el-row> </template>
<!-- 操作按钮区域 --> <el-row :gutter="16"> <el-col :span="24"> <div class="search-actions"> <div class="action-left"> <el-button type="primary" icon="el-icon-search" :loading="dataListLoading" @click="getDataList"> 查询 </el-button> <el-button icon="el-icon-refresh-left" @click="resetSearch"> 重置 </el-button> </div> <div class="action-right"> <el-button v-if="isAuth('105006:try')" type="warning" icon="el-icon-refresh-right" @click="batchRetryHandle"> 手动重试 </el-button> <el-button icon="el-icon-download" @click="exportData"> 导出 </el-button> </div> </div> </el-col> </el-row> </el-form> </el-card>
<!-- 页签列表 --> <el-tabs v-model="activeTab" @tab-click="handleTabClick"> <el-tab-pane label="变动明细" name="all"></el-tab-pane> <el-tab-pane label="采购入库" name="采购入库"></el-tab-pane> <el-tab-pane label="采购退货" name="采购退货"></el-tab-pane> <el-tab-pane label="生产领料" name="生产领料"></el-tab-pane> <el-tab-pane label="生产退仓" name="生产退仓"></el-tab-pane> <el-tab-pane label="生产入库" name="生产入库"></el-tab-pane> <el-tab-pane label="销售出库" name="销售出库"></el-tab-pane> <el-tab-pane label="销售退货" name="销售退货"></el-tab-pane> <el-tab-pane label="其他入库" name="其他入库"></el-tab-pane> <el-tab-pane label="其他出库" name="其他出库"></el-tab-pane> <el-tab-pane label="移库调拨" name="移库调拨"></el-tab-pane> </el-tabs>
<!-- 展示列表 --> <el-table :height="height" :data="dataList" border v-loading="dataListLoading" @selection-change="selectionChangeHandle" style="width: 100%;"> <el-table-column type="selection" header-align="center" align="center" width="50"> </el-table-column> <el-table-column prop="buNo" label="BU" header-align="center" align="center" width="80"></el-table-column> <el-table-column prop="transactionId" label="变动单号" header-align="center" align="left" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="documentType" label="变动类型" header-align="center" align="center" width="100"></el-table-column> <el-table-column prop="documentNo" label="通知单号" header-align="center" align="left" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="orderNo" label="关联单号" header-align="center" align="left" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="orderLineNo" label="关联单行号" header-align="center" align="center" width="100"></el-table-column> <el-table-column prop="rollNo" label="标签条码" header-align="center" align="left" min-width="180" show-overflow-tooltip></el-table-column> <el-table-column prop="rollQty" label="变动数量" header-align="center" align="right" width="100"></el-table-column> <el-table-column prop="batchNo" label="合约号码" header-align="center" align="left" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="partNo" label="物料编码" header-align="center" align="left" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column prop="partDesc" label="物料名称" header-align="center" align="left" min-width="180" show-overflow-tooltip></el-table-column> <el-table-column prop="spec" label="规格型号" header-align="center" align="left" min-width="120" show-overflow-tooltip></el-table-column> <el-table-column prop="warehouseId" label="仓库编码" header-align="center" align="center" width="100"></el-table-column> <el-table-column prop="warehouseName" label="仓库名称" header-align="center" align="left" min-width="120" show-overflow-tooltip></el-table-column> <el-table-column prop="locationId" label="库位编码" header-align="center" align="center" width="100"></el-table-column> <el-table-column prop="locationName" label="库位名称" header-align="center" align="left" min-width="120" show-overflow-tooltip></el-table-column> <el-table-column prop="syncedFlag" label="传输状态" header-align="center" align="center" width="90"> <template slot-scope="scope"> <el-tag :type="scope.row.syncedFlag === '已传输' ? 'success' : 'warning'" size="small"> {{ scope.row.syncedFlag }} </el-tag> </template> </el-table-column> <el-table-column prop="syncedTime" label="传输时间" header-align="center" align="center" width="160"></el-table-column> <el-table-column prop="syncedErrorMsg" label="传输消息" header-align="center" align="left" min-width="150" show-overflow-tooltip></el-table-column> <el-table-column v-if="showBomItemNo" prop="bomItemNo" label="Bom行号" header-align="center" align="center" width="100"></el-table-column> <el-table-column prop="transactionBy" label="操作员" header-align="center" align="center" width="100"></el-table-column> <el-table-column prop="transactionDate" label="变动日期" header-align="center" align="center" width="160"></el-table-column> </el-table>
<!-- 分页 --> <el-pagination style="margin-top: 10px" @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex" :page-sizes="[20, 50, 100, 200, 500]" :page-size="pageSize" :total="totalPage" layout="total, sizes, prev, pager, next, jumper"> </el-pagination> </div></template>
<script>import { labelTransactionLogList, labelTransactionLogRetry } from '@/api/warehouse/labelTransactionLog.js'import { getSiteAndBuByUserName2 } from '@/api/qc/qc.js'import excel from '@/utils/excel-util.js' // 导入导出工具类
export default { data() { return { height: window.innerHeight - 313, searchExpanded: true, searchData: { buNo: '', documentType: '', rollNo: '', partNo: '', partDesc: '', spec: '', startDate: '', endDate: '', transactionId: '', documentNo: '', orderNo: '', orderLineNo: '', batchNo: '', syncedFlag: '' }, // 变动类型列表(不包含"变动明细")
documentTypeList: [ { label: '采购入库', value: '采购入库' }, { label: '采购退货', value: '采购退货' }, { label: '生产领料', value: '生产领料' }, { label: '生产退仓', value: '生产退仓' }, { label: '生产入库', value: '生产入库' }, { label: '销售出库', value: '销售出库' }, { label: '销售退货', value: '销售退货' }, { label: '其他入库', value: '其他入库' }, { label: '其他出库', value: '其他出库' }, { label: '移库调拨', value: '移库调拨' } ], activeTab: 'all', dataList: [], dataListLoading: false, dataListSelections: [], pageIndex: 1, pageSize: 20, totalPage: 0, userBuList: [], // 导出列配置
exportColumnList: [ { columnProp: 'buNo', columnLabel: 'BU', headerAlign: 'center', align: 'center', columnWidth: 80 }, { columnProp: 'transactionId', columnLabel: '变动单号', headerAlign: 'center', align: 'left', columnWidth: 150 }, { columnProp: 'documentType', columnLabel: '变动类型', headerAlign: 'center', align: 'center', columnWidth: 100 }, { columnProp: 'documentNo', columnLabel: '通知单号', headerAlign: 'center', align: 'left', columnWidth: 150 }, { columnProp: 'orderNo', columnLabel: '关联单号', headerAlign: 'center', align: 'left', columnWidth: 150 }, { columnProp: 'orderLineNo', columnLabel: '关联单行号', headerAlign: 'center', align: 'center', columnWidth: 100 }, { columnProp: 'rollNo', columnLabel: '标签条码', headerAlign: 'center', align: 'left', columnWidth: 180 }, { columnProp: 'rollQty', columnLabel: '变动数量', headerAlign: 'center', align: 'right', columnWidth: 100 }, { columnProp: 'batchNo', columnLabel: '合约号码', headerAlign: 'center', align: 'left', columnWidth: 150 }, { columnProp: 'partNo', columnLabel: '物料编码', headerAlign: 'center', align: 'left', columnWidth: 150 }, { columnProp: 'partDesc', columnLabel: '物料名称', headerAlign: 'center', align: 'left', columnWidth: 180 }, { columnProp: 'spec', columnLabel: '规格型号', headerAlign: 'center', align: 'left', columnWidth: 120 }, { columnProp: 'warehouseId', columnLabel: '仓库编码', headerAlign: 'center', align: 'center', columnWidth: 100 }, { columnProp: 'warehouseName', columnLabel: '仓库名称', headerAlign: 'center', align: 'left', columnWidth: 120 }, { columnProp: 'locationId', columnLabel: '库位编码', headerAlign: 'center', align: 'center', columnWidth: 100 }, { columnProp: 'locationName', columnLabel: '库位名称', headerAlign: 'center', align: 'left', columnWidth: 120 }, { columnProp: 'syncedFlag', columnLabel: '传输状态', headerAlign: 'center', align: 'center', columnWidth: 90 }, { columnProp: 'syncedTime', columnLabel: '传输时间', headerAlign: 'center', align: 'center', columnWidth: 160 }, { columnProp: 'syncedErrorMsg', columnLabel: '传输消息', headerAlign: 'center', align: 'left', columnWidth: 150 }, { columnProp: 'bomItemNo', columnLabel: 'Bom行号', headerAlign: 'center', align: 'center', columnWidth: 100 }, { columnProp: 'transactionBy', columnLabel: '操作员', headerAlign: 'center', align: 'center', columnWidth: 100 }, { columnProp: 'transactionDate', columnLabel: '变动日期', headerAlign: 'center', align: 'center', columnWidth: 160 } ] } }, computed: { // 只有生产领料和生产退仓页签才显示Bom行号列
showBomItemNo() { return this.activeTab === '生产领料' || this.activeTab === '生产退仓' } }, mounted() { this.initBuList() this.initDefaultDate() this.getDataList() this.handleResize(); window.addEventListener('resize', this.handleResize) }, beforeDestroy() { window.removeEventListener('resize', this.handleResize) }, methods: { handleResize() { this.$nextTick(() => { const windowHeight = window.innerHeight; const headerHeight = this.searchExpanded ? 340 : 220; this.height = windowHeight - headerHeight - 85; }); },
// 切换搜索区域展开/收起
toggleSearchExpand() { this.searchExpanded = !this.searchExpanded; this.handleResize(); },
// 初始化BU列表
initBuList() { const tempData = { username: this.$store.state.user.name } getSiteAndBuByUserName2(tempData).then(({ data }) => { if (data.code === 0) { this.userBuList = data.rows || [] } }) },
// 初始化默认日期为今天
initDefaultDate() { const today = this.formatDate(new Date()) this.searchData.startDate = today + ' 00:00' this.searchData.endDate = today + ' 23:59' },
// 格式化日期
formatDate(date) { const year = date.getFullYear() const month = String(date.getMonth() + 1).padStart(2, '0') const day = String(date.getDate()).padStart(2, '0') return `${year}-${month}-${day}` },
// 页签切换
handleTabClick(tab) { this.pageIndex = 1 this.getDataList() },
// 查询列表
getDataList() { this.dataListLoading = true const params = { buNo: this.searchData.buNo, documentType: this.activeTab === 'all' ? this.searchData.documentType : this.activeTab, rollNo: this.searchData.rollNo, partNo: this.searchData.partNo, partDesc: this.searchData.partDesc, spec: this.searchData.spec, startDate: this.searchData.startDate || '', endDate: this.searchData.endDate || '', transactionId: this.searchData.transactionId, documentNo: this.searchData.documentNo, orderNo: this.searchData.orderNo, orderLineNo: this.searchData.orderLineNo, batchNo: this.searchData.batchNo, syncedFlag: this.searchData.syncedFlag, page: this.pageIndex, limit: this.pageSize }
labelTransactionLogList(params).then(({ data }) => { this.dataListLoading = false if (data && data.code === 0) { this.dataList = data.page.list || [] this.totalPage = data.page.totalCount || 0 } else { this.dataList = [] this.totalPage = 0 this.$message.error(data.msg || '查询失败') } }).catch(() => { this.dataListLoading = false this.dataList = [] this.totalPage = 0 }) },
// 重置查询条件
resetSearch() { this.searchData = { buNo: this.userBuList.length > 0 ? this.userBuList[0].buNo : '', documentType: '', rollNo: '', partNo: '', partDesc: '', spec: '', startDate: '', endDate: '', transactionId: '', documentNo: '', orderNo: '', orderLineNo: '', batchNo: '', syncedFlag: '' } this.initDefaultDate() this.activeTab = 'all' this.pageIndex = 1 this.getDataList() },
// 导出数据
exportData() { // 构造导出参数(与查询一致,但不分页)
const exportParams = { buNo: this.searchData.buNo, documentType: this.activeTab === 'all' ? this.searchData.documentType : this.activeTab, rollNo: this.searchData.rollNo, partNo: this.searchData.partNo, partDesc: this.searchData.partDesc, spec: this.searchData.spec, startDate: this.searchData.startDate || '', endDate: this.searchData.endDate || '', transactionId: this.searchData.transactionId, documentNo: this.searchData.documentNo, orderNo: this.searchData.orderNo, orderLineNo: this.searchData.orderLineNo, batchNo: this.searchData.batchNo, syncedFlag: this.searchData.syncedFlag, userName: this.$store.state.user.name, page: 1, limit: 999999 // 使用大数字代替-1,SQL Server的FETCH子句不支持负数
}
// 根据当前页签生成文件名
const tabName = this.activeTab === 'all' ? '全部' : this.activeTab const fileName = `标签变动记录_${tabName}_${this.dayjs().format('YYYYMMDDHHmmss')}.xlsx`
// 使用excel工具类导出
excel.exportTable({ url: '/warehouse/labelTransactionLog/list', // 使用list接口,传limit=999999导出所有数据
columnMapping: this.exportColumnList, // 使用导出列配置
mergeSetting: [], // 需要合并的列
params: exportParams, // 查询参数
fileName: fileName, // 文件名
rowFetcher: res => res.data.page.list, // 数据提取路径
columnFormatter: [], // 列格式化
dropColumns: [] // 不需要剔除的列
}) },
// 每页数量变化
sizeChangeHandle(val) { this.pageSize = val this.pageIndex = 1 this.getDataList() },
// 页码变化
currentChangeHandle(val) { this.pageIndex = val this.getDataList() },
// 多选变化
selectionChangeHandle(val) { this.dataListSelections = val },
// 批量手动重试
batchRetryHandle() { if (this.dataListSelections.length === 0) { this.$message.warning('请选择要重试的记录!') return }
// 校验:只能选择待传输(syncedFlag不为'已传输')且有错误消息的记录
const invalidItems = this.dataListSelections.filter(item => item.syncedFlag === '已传输' // || !item.syncedErrorMsg || item.syncedErrorMsg.trim() === ''
) if (invalidItems.length > 0) { this.$message.warning('只能选择待传输的记录进行手动重试!') return }
const count = this.dataListSelections.length this.$confirm(`确定要手动重试选中的 ${count} 条记录吗?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { const loading = this.$loading({ lock: true, text: `正在重试 ${count} 条记录,请稍候...`, spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' })
// 构造批量重试参数
const retryList = this.dataListSelections.map(item => ({ site: item.site, buNo: item.buNo, transactionId: item.transactionId }))
// 调用批量重试接口
labelTransactionLogRetry({ retryList }).then(({ data }) => { loading.close() if (data && data.code === 0) { const result = data.result || {} const successCount = result.successCount || 0 const failureCount = result.failureCount || 0
let message = `重试完成!成功:${successCount},失败:${failureCount}` if (successCount === count) { this.$message.success(message) } else if (successCount > 0) { this.$message.warning(message) } else { this.$message.error(message) }
// 显示详细结果对话框
if (result.details && result.details.length > 0) { this.showRetryResultDialog(result.details) }
// 刷新列表
this.getDataList() } else { this.$message.error(data.msg || '重试失败') } }).catch(error => { loading.close() this.$message.error('重试失败:' + (error.message || '网络错误')) }) }).catch(() => {}) },
// 显示重试结果详情对话框
showRetryResultDialog(details) { const successList = details.filter(d => d.status === 'success') const failureList = details.filter(d => d.status === 'failure') const errorList = details.filter(d => d.status === 'error')
let messageHtml = '<div style="max-height: 400px; overflow-y: auto;">'
if (successList.length > 0) { messageHtml += '<div style="margin-bottom: 15px;"><strong style="color: #67C23A;">成功 (' + successList.length + '):</strong><ul style="margin: 5px 0; padding-left: 20px;">' successList.forEach(item => { messageHtml += '<li>事务ID:' + item.transactionId + (item.u8CCode ? ' - U8单号:' + item.u8CCode : '') + '</li>' }) messageHtml += '</ul></div>' }
if (failureList.length > 0) { messageHtml += '<div style="margin-bottom: 15px;"><strong style="color: #E6A23C;">失败 (' + failureList.length + '):</strong><ul style="margin: 5px 0; padding-left: 20px;">' failureList.forEach(item => { messageHtml += '<li>事务ID:' + item.transactionId + ':' + (item.message || '未知错误') + '</li>' }) messageHtml += '</ul></div>' }
if (errorList.length > 0) { messageHtml += '<div><strong style="color: #F56C6C;">异常 (' + errorList.length + '):</strong><ul style="margin: 5px 0; padding-left: 20px;">' errorList.forEach(item => { messageHtml += '<li>事务ID:' + item.transactionId + ':' + (item.message || '未知异常') + '</li>' }) messageHtml += '</ul></div>' }
messageHtml += '</div>'
this.$alert(messageHtml, '批量重试结果详情', { confirmButtonText: '确定', dangerouslyUseHTMLString: true }) } }}</script>
<style scoped>.mod-config { padding: 0px;}
/* 搜索卡片样式 */.search-card { margin-bottom: 12px; border-radius: 8px; overflow: hidden; transition: all 0.3s ease;}
.search-card:hover { box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);}
.search-card /deep/ .el-card__header { padding: 5px 20px; background: linear-gradient(135deg, #9ac3d0 20%, #b6c7dd 80%); border-bottom: none;}
.search-header { display: flex; justify-content: space-between; align-items: center;}
.header-left { display: flex; align-items: center; color: #fff;}
.header-left i { font-size: 16px; margin-right: 8px;}
.header-title { font-size: 14px; font-weight: 600;}
.header-right { display: flex; align-items: center;}
.collapse-btn { color: #fff !important; font-size: 12px; padding: 4px 8px;}
.collapse-btn:hover { background: rgba(255, 255, 255, 0.1); border-radius: 4px;}
.collapse-btn i { margin-left: 4px;}
/* 搜索表单样式 */.search-form { padding: 6px 0; min-height: 0;}
/* 卡片主体样式 */.search-card /deep/ .el-card__body { padding: 10px; transition: all 0.3s ease;}
/* 收起时的样式 */.search-card.collapsed /deep/ .el-card__body { padding: 10px 20px;}
.search-form /deep/ .el-form-item { margin-bottom: 12px;}
.search-form /deep/ .el-form-item__label { font-weight: 500; color: #606266; padding-bottom: 4px;}
.search-form /deep/ .el-input__inner,.search-form /deep/ .el-textarea__inner { border-radius: 6px; border: 1px solid #DCDFE6; transition: all 0.3s ease;}
.search-form /deep/ .el-input__inner:focus,.search-form /deep/ .el-textarea__inner:focus { border-color: #9ac3d0; box-shadow: 0 0 0 2px rgba(154, 195, 208, 0.1);}
.search-form /deep/ .el-select { width: 100%;}
.search-form /deep/ .el-date-editor.el-input,.search-form /deep/ .el-date-editor--daterange.el-input__inner { width: 100%;}
.search-form /deep/ .el-date-editor--daterange { width: 100% !important;}
.search-form /deep/ .el-range-input { width: 42%;}
.search-form /deep/ .el-range-separator { width: 16%; padding: 0;}
/* 操作按钮区域 */.search-actions { display: flex; justify-content: space-between; align-items: center; padding: 8px 0 2px 0;}
/* 展开时显示上边框 */.search-card:not(.collapsed) .search-actions { border-top: 1px solid #f0f0f0; margin-top: 6px;}
/* 收起时不显示上边框和上边距 */.search-card.collapsed .search-actions { border-top: none; margin-top: 0; padding-top: 0;}
.action-left,.action-right { display: flex; gap: 8px;}
.search-actions .el-button { border-radius: 4px; padding: 5px 10px; font-size: 12px; font-weight: 500; transition: all 0.3s ease;}
/* 页签样式 *//deep/ .el-tabs__header { margin-bottom: 10px;}
/deep/ .el-tabs__nav-wrap::after { height: 1px;}
/deep/ .el-tabs__item { padding: 0 15px; height: 36px; line-height: 36px;}
/deep/ .el-tabs__item.is-active { color: #17B3A3;}
/deep/ .el-tabs__active-bar { background-color: #17B3A3;}
/* 分页样式 *//deep/ .el-pagination { margin-top: 10px; padding: 0;}</style>
|