Files
klp-oa/klp-ui/src/views/wms/post/InvCount/execute.vue
砂糖 39eaab139e feat: 新增盘库管理全流程功能模块
1.  新增批量新增盘库差异记录API
2.  新增盘库Excel对比工具函数
3.  新增盘库申请页面与库区明细组件
4.  优化流程图页面,新增流程图下载功能
5.  重构盘库主页面流程状态与操作逻辑
6.  新增多组件拆分与页面模块化改造
2026-06-26 15:41:21 +08:00

144 lines
9.0 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="app-container count-container">
<DragResizePanel :initialSize="280" :minSize="280" :maxSize="600">
<template #panelA>
<div class="left-panel">
<div class="panel-header">
<div class="header-title">
<i class="el-icon-s-data"></i>
<span>差异处理</span>
<el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" title="刷新列表" />
</div>
</div>
<div class="search-row">
<el-input v-model="queryParams.planCode" placeholder="搜索计划编号..." clearable prefix-icon="el-icon-search" size="small" @keyup.enter.native="handleQuery" @clear="handleQuery" />
</div>
<div v-loading="loading" class="list-body">
<div v-for="item in dataList" :key="item.planId" class="list-item"
:class="{ active: currentRow && currentRow.planId === item.planId }" @click="handleRowClick(item)">
<div class="item-main"><span class="item-title">{{ item.planCode }}</span><span class="item-sub">{{ item.planName }}</span></div>
<div class="item-meta"><el-tag type="danger" size="mini">差异处理中</el-tag></div>
</div>
<div v-if="dataList.length === 0 && !loading" class="list-empty"><i class="el-icon-folder-opened"></i><span>暂无差异处理中的计划</span></div>
</div>
<div class="list-footer"><pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /></div>
</div>
</template>
<template #panelB>
<div class="right-panel">
<div v-if="!currentRow" class="empty-tip"><i class="el-icon-info"></i><span>请在左侧列表中选择一条盘库计划</span></div>
<div v-else v-loading="detailLoading" class="detail-content">
<div class="doc-header">
<div class="doc-header-top">
<div class="doc-title-group"><div class="doc-title">{{ currentRow.planCode }}</div><div class="doc-subtitle">Discrepancy Processing</div></div>
<div class="doc-header-right"><el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail">刷新</el-button></div>
</div>
<div class="doc-status-row"><span class="doc-status-label">Status / 状态</span><el-tag type="danger" size="small">差异处理中</el-tag></div>
</div>
<div class="detail-meta">
<span><i class="el-icon-document"></i>{{ currentRow.planName }}</span>
<span v-if="currentRow.countUserName"><i class="el-icon-user-solid"></i>{{ currentRow.countUserName }}</span>
</div>
<CountFlowSection :planStatus="3" />
<el-divider />
<WarehouseDetailPanel ref="whPanel"
:planId="currentRow.planId"
:planStatus="3"
@process-disc="handleProcessDisc"
/>
<div class="section-gap" />
<div class="section-title">备注 <span class="en-sub">· Remarks</span></div>
<div class="remark-content">{{ currentRow.remark || '无' }}</div>
</div>
</div>
</template>
</DragResizePanel>
</div>
</template>
<script>
import { listCountPlan, getCountPlan, updateCountPlan } from "@/api/flow/countPlan";
import { updateCountDiscrepancy } from "@/api/flow/countDiscrepancy";
import DragResizePanel from "@/components/DragResizePanel/index.vue";
import CountFlowSection from "./components/CountFlowSection.vue";
import WarehouseDetailPanel from "./components/WarehouseDetailPanel.vue";
import { parseTime } from '@/utils/klp'
export default {
name: "InvCountExecute",
components: { DragResizePanel, CountFlowSection, WarehouseDetailPanel },
data() {
return {
loading: false, detailLoading: false, total: 0,
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 3 },
dataList: [], currentRow: null
};
},
created() { this.getList(); },
methods: {
parseTime,
getList() { var self = this; this.loading = true; listCountPlan(this.queryParams).then(function(r) { self.dataList = r.rows; self.total = r.total; }).finally(function() { self.loading = false; }); },
handleQuery() { this.queryParams.pageNum = 1; this.getList(); },
handleRowClick(row) { this.currentRow = row; this.detailLoading = true; getCountPlan(row.planId).then(function(r) { self.currentRow = r.data; }).finally(function() { self.detailLoading = false; }); },
handleRefreshDetail() { if (this.currentRow) { var self = this; this.detailLoading = true; getCountPlan(this.currentRow.planId).then(function(r) { self.currentRow = r.data; }).finally(function() { self.detailLoading = false; }); } },
handleProcessDisc({ row, relId }) {
var self = this;
this.$modal.confirm('确认将该差异项标记为已处理?', '处理确认', { confirmButtonText: '确认处理', cancelButtonText: '取消', type: 'warning' }).then(function() {
var now = new Date();
var pad = function(n) { return n < 10 ? '0' + n : '' + n; };
return updateCountDiscrepancy({
discrepancyId: row.discrepancyId,
processResult: row._processResult || '',
processStatus: 2,
processTime: now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate()) + ' ' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds())
});
}).then(function() {
self.$modal.msgSuccess('已处理');
self.$refs.whPanel.refreshOneDisc(relId);
}).catch(function(err) { if (err !== 'cancel') self.$modal.msgError('处理失败'); });
}
}
};
</script>
<style scoped>
.count-container { height: calc(100vh - 84px); }
.left-panel { display: flex; flex-direction: column; height: 100%; background: #f5f7fa; border-right: 1px solid #e4e7ed; }
.panel-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px 8px; background: #f5f7fa; }
.header-title { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 600; color: #303133; }
.header-title i { color: #409eff; font-size: 16px; }
.search-row { display: flex; align-items: center; gap: 6px; padding: 0 14px 10px; background: #f5f7fa; }
.list-body { flex: 1; overflow-y: auto; padding: 0 6px; }
.list-item { display: flex; align-items: center; padding: 10px 12px; margin-bottom: 2px; cursor: pointer; border-radius: 6px; transition: all 0.15s; }
.list-item:hover { background: #ebeef5; }
.list-item.active { background: #d9ecff; }
.list-item.active .item-title { color: #409eff; font-weight: 600; }
.item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.item-title { font-size: 13px; font-weight: 500; color: #303133; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.item-sub { font-size: 12px; color: #909399; }
.item-meta { flex-shrink: 0; margin: 0 8px; }
.list-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 60px 0; color: #c0c4cc; font-size: 13px; gap: 8px; }
.list-empty i { font-size: 32px; }
.list-footer { border-top: 1px solid #e4e7ed; padding: 2px 8px 0; background: #f5f7fa; }
.right-panel { height: 100%; overflow-y: auto; padding: 12px 16px; background: #faf8f5; }
.detail-content { margin: 0 auto; background: #fff; padding: 28px 32px 36px; box-shadow: 0 1px 4px rgba(0,0,0,0.06), 0 2px 12px rgba(0,0,0,0.04); min-height: 100%; }
.empty-tip { display: flex; align-items: center; justify-content: center; height: 100%; color: #909399; font-size: 14px; gap: 8px; }
.doc-header { margin-bottom: 18px; padding-bottom: 14px; border-bottom: 2px solid #1a3c6e; }
.doc-header-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.doc-title-group { flex: 1; min-width: 0; }
.doc-title { font-size: 24px; font-weight: 700; color: #1a1a1a; line-height: 1.3; letter-spacing: 0.5px; }
.doc-subtitle { font-size: 12px; color: #8c8c8c; font-style: italic; letter-spacing: 0.8px; margin-top: 2px; }
.doc-header-right { flex-shrink: 0; }
.doc-status-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.doc-status-label { font-size: 11px; color: #8c8c8c; letter-spacing: 0.3px; }
.detail-meta { display: flex; flex-wrap: wrap; gap: 16px; font-size: 12px; color: #909399; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid #e0dcd6; }
.detail-meta span { display: inline-flex; align-items: center; gap: 4px; }
.detail-meta i { font-size: 13px; }
.section-title { font-size: 15px; font-weight: 700; color: #1a1a1a; margin: 22px 0 12px; padding: 0 0 10px; border-bottom: 1px solid #d4d0c8; display: flex; align-items: center; gap: 10px; }
.section-title .en-sub { font-size: 11px; font-weight: 400; color: #8c8c8c; letter-spacing: 0.5px; font-style: italic; }
.remark-content { padding: 12px 16px; background: #faf8f5; border: 1px solid #e8e4de; border-radius: 2px; font-size: 13px; line-height: 1.8; color: #1a1a1a; }
.section-gap { height: 16px; }
</style>