refactor(盘库流程): 重构盘库流程页面与组件,完善排产明细功能
1. 重构盘库流程的步骤与状态映射,调整流程节点顺序与名称 2. 拆分通用盘库详情组件PlanDetailPanel,复用各流程页面 3. 新增计划审批、盘库执行页面,完善差异审批页面 4. 为排产单明细添加增删改查API与前端操作功能 5. 为排产日期添加格式化注解,完善参数接收格式
This commit is contained in:
@@ -7,14 +7,14 @@
|
||||
<div class="header-title"><i class="el-icon-s-check"></i><span>盘库申请</span><el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" title="刷新列表" /></div>
|
||||
<el-select v-model="queryParams.planStatus" size="mini" @change="handleQuery" class="header-filter">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="待审批" :value="1" />
|
||||
<el-option label="计划待审批" :value="1" />
|
||||
</el-select>
|
||||
</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" /><el-button type="primary" size="small" @click="handleAdd"><i class="el-icon-plus"></i></el-button></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 v-if="item.planStatus === 0" type="info" size="mini">草稿</el-tag><el-tag v-else size="mini">待审批</el-tag></div>
|
||||
<div class="item-meta"><el-tag v-if="item.planStatus === 0" type="info" size="mini">草稿</el-tag><el-tag v-else 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>
|
||||
@@ -23,54 +23,28 @@
|
||||
</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">Application</div></div>
|
||||
<div class="doc-header-right">
|
||||
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail">刷新</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(currentRow)">编辑</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(currentRow)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="doc-status-row"><span class="doc-status-label">Status:</span><el-tag v-if="currentRow.planStatus === 0" type="info" size="small">草稿</el-tag><el-tag v-else size="small">待审批</el-tag></div>
|
||||
</div>
|
||||
<div class="detail-meta">
|
||||
<span><i class="el-icon-document"></i>{{ currentRow.planName }}</span>
|
||||
<span v-if="currentRow.countDate"><i class="el-icon-date"></i>{{ parseTime(currentRow.countDate, '{y}-{m}-{d}') }}</span>
|
||||
<span v-if="currentRow.countUserName"><i class="el-icon-user-solid"></i>{{ currentRow.countUserName }}</span>
|
||||
</div>
|
||||
<CountFlowSection :planStatus="currentRow.planStatus" />
|
||||
<el-divider />
|
||||
|
||||
<div class="section-title">库区盘点明细 <span class="en-sub">· Warehouses</span>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="primary" plain icon="el-icon-plus" @click="handleAddWarehouse">绑定库区</el-button>
|
||||
</div>
|
||||
|
||||
<WarehouseDetailPanel ref="whPanel"
|
||||
:planId="currentRow.planId"
|
||||
:planStatus="currentRow.planStatus"
|
||||
@submit-approval="handleSubmitApproval"
|
||||
/>
|
||||
|
||||
<div class="section-gap" />
|
||||
<div class="section-title">备注 <span class="en-sub">· Remarks</span></div>
|
||||
<div class="remark-content">{{ currentRow.remark || '无' }}</div>
|
||||
</div>
|
||||
<PlanDetailPanel ref="detailPanel"
|
||||
:planId="currentRow ? currentRow.planId : null"
|
||||
subtitle="Application"
|
||||
emptyText="请在左侧列表中选择一条盘库计划"
|
||||
@submit-approval="handleSubmitApproval"
|
||||
@edit-plan="handleUpdate"
|
||||
@delete-plan="handleDelete"
|
||||
@bind-warehouse="handleAddWarehouse"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
|
||||
<el-dialog :title="planDialogTitle" :visible.sync="planDialogOpen" width="650px" append-to-body>
|
||||
<el-form ref="planForm" :model="planForm" label-width="100px">
|
||||
<el-form-item label="计划名称" prop="planName"><el-input v-model="planForm.planName" /></el-form-item>
|
||||
<el-form-item label="盘库日期" prop="countDate"><el-date-picker v-model="planForm.countDate" type="date" value-format="yyyy-MM-dd" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="截止时间" prop="deadlineTime"><el-date-picker v-model="planForm.deadlineTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="盘点人"><el-input v-model="planForm.countUserName" /></el-form-item>
|
||||
<el-form-item label="负责人"><el-input v-model="planForm.principalUserName" /></el-form-item>
|
||||
<el-form-item label="参与人"><el-input v-model="planForm.participantNames" /></el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="planForm.remark" type="textarea" :rows="3" /></el-form-item>
|
||||
<el-form-item label="计划名称" prop="planName"><el-input v-model="planForm.planName" placeholder="请输入计划名称" /></el-form-item>
|
||||
<el-form-item label="盘库日期" prop="countDate"><el-date-picker v-model="planForm.countDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择盘库日期" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="截止时间" prop="deadlineTime"><el-date-picker v-model="planForm.deadlineTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择截止时间" style="width:100%" /></el-form-item>
|
||||
<el-form-item label="盘点人"><el-input v-model="planForm.countUserName" placeholder="请输入盘点人" /></el-form-item>
|
||||
<el-form-item label="负责人"><el-input v-model="planForm.principalUserName" placeholder="请输入负责人" /></el-form-item>
|
||||
<el-form-item label="参与人"><el-input v-model="planForm.participantNames" placeholder="请输入参与人员" /></el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="planForm.remark" type="textarea" :rows="3" placeholder="请输入备注" /></el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer"><el-button :loading="btnLoading" type="primary" @click="submitPlan">确定</el-button><el-button @click="planDialogOpen = false">取消</el-button></div>
|
||||
</el-dialog>
|
||||
@@ -88,21 +62,20 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCountPlan, getCountPlan, addCountPlan, updateCountPlan, delCountPlan } from "@/api/flow/countPlan";
|
||||
import { listCountPlan, addCountPlan, updateCountPlan, delCountPlan } from "@/api/flow/countPlan";
|
||||
import { addCountPlanWarehouse } from "@/api/flow/countPlanWarehouse";
|
||||
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||
import CountFlowSection from "./components/CountFlowSection.vue";
|
||||
import WarehouseDetailPanel from "./components/WarehouseDetailPanel.vue";
|
||||
import PlanDetailPanel from "./components/PlanDetailPanel.vue";
|
||||
import WarehouseSelect from "@/components/KLPService/WarehouseSelect/index.vue";
|
||||
import ActualWarehouseL1L2Select from "@/components/KLPService/ActualWarehouseL1L2Select/index.vue";
|
||||
import { parseTime } from '@/utils/klp'
|
||||
|
||||
export default {
|
||||
name: "InvCountApply",
|
||||
components: { DragResizePanel, CountFlowSection, WarehouseDetailPanel, WarehouseSelect, ActualWarehouseL1L2Select },
|
||||
components: { DragResizePanel, PlanDetailPanel, WarehouseSelect, ActualWarehouseL1L2Select },
|
||||
data() {
|
||||
return {
|
||||
loading: false, detailLoading: false, btnLoading: false, whBtnLoading: false, submitLoading: false, total: 0, dataList: [], currentRow: null,
|
||||
loading: false, btnLoading: false, whBtnLoading: false, submitLoading: false, total: 0, dataList: [], currentRow: null,
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 0 },
|
||||
planDialogOpen: false, planDialogTitle: '', planForm: {},
|
||||
whDialogOpen: false, whForm: { warehouseId: undefined, actualWarehouseId: undefined, warehouseName: '', actualWarehouseName: '', ioStartTime: undefined, ioEndTime: undefined }
|
||||
@@ -113,18 +86,16 @@ export default {
|
||||
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.loadDetail(row.planId); },
|
||||
loadDetail(planId) { var self = this; this.detailLoading = true; getCountPlan(planId).then(function(r) { self.currentRow = r.data; }).finally(function() { self.detailLoading = false; }); },
|
||||
handleRefreshDetail() { if (this.currentRow) this.loadDetail(this.currentRow.planId); },
|
||||
handleAdd() { this.planForm = {}; this.planDialogTitle = '新增盘库计划'; this.planDialogOpen = true; },
|
||||
handleUpdate(row) { var self = this; getCountPlan(row.planId).then(function(r) { self.planForm = r.data; self.planDialogTitle = '修改'; self.planDialogOpen = true; }); },
|
||||
submitPlan() { var self = this; this.btnLoading = true; var api = this.planForm.planId ? updateCountPlan : addCountPlan; api(this.planForm).then(function() { self.$modal.msgSuccess('成功'); self.planDialogOpen = false; self.getList(); }).finally(function() { self.btnLoading = false; }); },
|
||||
handleRowClick(row) { this.currentRow = row; },
|
||||
handleAdd() { this.planForm = { planName: new Date().toLocaleDateString().replace(/\//g, '-') + '盘库计划' }; this.planDialogTitle = '新增盘库计划'; this.planDialogOpen = true; },
|
||||
handleUpdate(row) { this.planForm = Object.assign({}, row); this.planDialogTitle = '修改'; this.planDialogOpen = true; },
|
||||
submitPlan() { var self = this; this.btnLoading = true; this.planForm.planCode = this.planForm.planName; var api = this.planForm.planId ? updateCountPlan : addCountPlan; api(this.planForm).then(function() { self.$modal.msgSuccess('成功'); self.planDialogOpen = false; self.getList(); }).finally(function() { self.btnLoading = false; }); },
|
||||
handleDelete(row) { var self = this; this.$modal.confirm('确认删除?').then(function() { return delCountPlan(row.planId); }).then(function() { self.$modal.msgSuccess('已删除'); self.currentRow = null; self.getList(); }).catch(function() {}); },
|
||||
handleSubmitApproval() { var self = this; this.$modal.confirm('确认提交审批?').then(function() { self.submitLoading = true; return updateCountPlan({ planId: self.currentRow.planId, planStatus: 1 }); }).then(function() { self.$modal.msgSuccess('已提交'); self.loadDetail(self.currentRow.planId); self.getList(); }).finally(function() { self.submitLoading = false; }); },
|
||||
handleSubmitApproval() { var self = this; this.$modal.confirm('确认提交审批?').then(function() { self.submitLoading = true; return updateCountPlan({ planId: self.currentRow.planId, planStatus: 1 }); }).then(function() { self.$modal.msgSuccess('已提交'); self.getList(); self.currentRow = null; }).finally(function() { self.submitLoading = false; }); },
|
||||
handleAddWarehouse() { this.whForm = { warehouseId: undefined, actualWarehouseId: undefined, warehouseName: '', actualWarehouseName: '', ioStartTime: undefined, ioEndTime: undefined }; this.whDialogOpen = true; },
|
||||
onWhChange(val) { if (val && this.$refs.wsRef) { var o = this.$refs.wsRef.warehouseOptions; var f = o.find(function(x) { return x.warehouseId === val; }); this.whForm.warehouseName = f ? f.warehouseName : ''; } else this.whForm.warehouseName = ''; },
|
||||
onAwhChange(val) { if (val && this.$refs.awsRef) { var o = this.$refs.awsRef.options; var f = o.find(function(x) { return x.actualWarehouseId === val; }); this.whForm.actualWarehouseName = f ? f.actualWarehouseName : ''; } else this.whForm.actualWarehouseName = ''; },
|
||||
submitWh() { var self = this; if (!this.whForm.warehouseId && !this.whForm.actualWarehouseId) { this.$modal.msgWarning('请至少选择一个库区'); return; } this.whBtnLoading = true; addCountPlanWarehouse({ planId: this.currentRow.planId, warehouseId: this.whForm.warehouseId || undefined, actualWarehouseId: this.whForm.actualWarehouseId || undefined, warehouseName: this.whForm.warehouseName || undefined, actualWarehouseName: this.whForm.actualWarehouseName || undefined, ioStartTime: this.whForm.ioStartTime, ioEndTime: this.whForm.ioEndTime }).then(function() { self.$modal.msgSuccess('绑定成功'); self.whDialogOpen = false; self.$refs.whPanel.refreshAll(); }).finally(function() { self.whBtnLoading = false; }); }
|
||||
submitWh() { var self = this; if (!this.whForm.warehouseId && !this.whForm.actualWarehouseId) { this.$modal.msgWarning('请至少选择一个库区'); return; } this.whBtnLoading = true; addCountPlanWarehouse({ planId: this.currentRow.planId, warehouseId: this.whForm.warehouseId || undefined, actualWarehouseId: this.whForm.actualWarehouseId || undefined, warehouseName: this.whForm.warehouseName || undefined, actualWarehouseName: this.whForm.actualWarehouseName || undefined, ioStartTime: this.whForm.ioStartTime, ioEndTime: this.whForm.ioEndTime }).then(function() { self.$modal.msgSuccess('绑定成功'); self.whDialogOpen = false; self.$refs.detailPanel.refresh(); }).finally(function() { self.whBtnLoading = false; }); }
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -4,98 +4,48 @@
|
||||
<template #panelA>
|
||||
<div class="left-panel">
|
||||
<div class="panel-header">
|
||||
<div class="header-title"><i class="el-icon-s-check"></i><span>盘库审批</span><el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" style="margin-left:4px;" title="刷新列表" /></div>
|
||||
<div class="header-title"><i class="el-icon-s-check"></i><span>差异审批</span><el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" style="margin-left:4px;" 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 size="mini">待审批</el-tag></div>
|
||||
<div class="item-meta"><el-tag 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 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">Approval</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 size="small">待审批</el-tag></div>
|
||||
</div>
|
||||
<div class="detail-meta">
|
||||
<span><i class="el-icon-document"></i>{{ currentRow.planName }}</span>
|
||||
<span v-if="currentRow.countDate"><i class="el-icon-date"></i>{{ parseTime(currentRow.countDate, '{y}-{m}-{d}') }}</span>
|
||||
<span v-if="currentRow.countUserName"><i class="el-icon-user-solid"></i>{{ currentRow.countUserName }}</span>
|
||||
</div>
|
||||
<CountFlowSection :planStatus="1" />
|
||||
<el-divider />
|
||||
|
||||
<WarehouseDetailPanel ref="whPanel"
|
||||
:planId="currentRow.planId"
|
||||
:planStatus="1"
|
||||
@approve="handleApprove"
|
||||
@reject="handleReject"
|
||||
@mark-disc="handleMarkDisc"
|
||||
@preview="handlePreview"
|
||||
/>
|
||||
|
||||
<div class="section-gap" />
|
||||
<div class="section-title">备注 <span class="en-sub">· Remarks</span></div>
|
||||
<div class="remark-content">{{ currentRow.remark || '无' }}</div>
|
||||
</div>
|
||||
<PlanDetailPanel ref="detailPanel"
|
||||
:planId="currentRow ? currentRow.planId : null"
|
||||
subtitle="Discrepancy Approval"
|
||||
emptyText="请在左侧列表中选择一条盘库计划进行差异审批"
|
||||
@diff-approve="handleApprove"
|
||||
@reject="handleReject"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
|
||||
<el-dialog title="标记差异项" :visible.sync="markDialogVisible" width="500px" append-to-body>
|
||||
<el-form :model="markForm" label-width="100px">
|
||||
<el-form-item label="差异类型">
|
||||
<el-tag v-if="markForm.discrepancyType === 1" type="success">盘盈</el-tag>
|
||||
<el-tag v-else-if="markForm.discrepancyType === 2" type="danger">盘亏</el-tag>
|
||||
<el-tag v-else-if="markForm.discrepancyType === 3" type="warning">不符</el-tag>
|
||||
<el-tag v-else>偏差</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="钢卷号">{{ markForm.enterCoilNo }}</el-form-item>
|
||||
<el-form-item label="差异详情">{{ markForm.discrepancyDetail }}</el-form-item>
|
||||
<el-form-item label="须处理"><el-switch v-model="markForm.needResolve" active-text="是" inactive-text="否" /></el-form-item>
|
||||
<el-form-item label="审批意见"><el-input v-model="markForm.approveRemark" type="textarea" :rows="3" placeholder="审批意见" /></el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer"><el-button type="primary" @click="submitMark">确定</el-button><el-button @click="markDialogVisible = false">取消</el-button></div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="文件预览" :visible.sync="previewOpen" width="80%" top="5vh" append-to-body :before-close="function(){previewOpen=false;previewUrl='';}">
|
||||
<div style="height:75vh;"><vue-office-excel v-if="previewUrl" :src="previewUrl" @render-error="function(){ $modal.msgError('预览失败'); }" /><span v-else>加载中...</span></div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCountPlan, getCountPlan, updateCountPlan } from "@/api/flow/countPlan";
|
||||
import { updateCountDiscrepancy } from "@/api/flow/countDiscrepancy";
|
||||
import { listCountPlan, updateCountPlan } from "@/api/flow/countPlan";
|
||||
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||
import CountFlowSection from "./components/CountFlowSection.vue";
|
||||
import WarehouseDetailPanel from "./components/WarehouseDetailPanel.vue";
|
||||
import VueOfficeExcel from '@vue-office/excel';
|
||||
import '@vue-office/excel/lib/index.css';
|
||||
import { listByIds } from '@/api/system/oss';
|
||||
import PlanDetailPanel from "./components/PlanDetailPanel.vue";
|
||||
import { parseTime } from '@/utils/klp'
|
||||
|
||||
export default {
|
||||
name: "InvCountApproval",
|
||||
components: { DragResizePanel, CountFlowSection, WarehouseDetailPanel, VueOfficeExcel },
|
||||
name: "InvCountDiffApproval",
|
||||
components: { DragResizePanel, PlanDetailPanel },
|
||||
data() {
|
||||
return {
|
||||
loading: false, detailLoading: false, total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 1 },
|
||||
loading: false, total: 0,
|
||||
dataList: [], currentRow: null,
|
||||
markDialogVisible: false, markForm: { discrepancyId: null, discrepancyType: null, enterCoilNo: '', discrepancyDetail: '', needResolve: false, approveRemark: '' },
|
||||
previewOpen: false, previewUrl: ''
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 3 }
|
||||
};
|
||||
},
|
||||
created() { this.getList(); },
|
||||
@@ -103,36 +53,18 @@ export default {
|
||||
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.loadDetail(row.planId); },
|
||||
loadDetail(planId) { var self = this; this.detailLoading = true; getCountPlan(planId).then(function(r) { self.currentRow = r.data; }).finally(function() { self.detailLoading = false; }); },
|
||||
handleRefreshDetail() { if (this.currentRow) this.loadDetail(this.currentRow.planId); },
|
||||
handleRowClick(row) { this.currentRow = row; },
|
||||
handleApprove() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认通过"' + this.currentRow.planCode + '"的审批?').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 3 });
|
||||
}).then(function() { self.$modal.msgSuccess("审批通过"); self.currentRow = null; self.getList(); });
|
||||
this.$modal.confirm('确认通过"' + this.currentRow.planCode + '"的差异审批?通过后进入差异处理阶段。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 4 });
|
||||
}).then(function() { self.$modal.msgSuccess("审批通过,已进入差异处理"); self.currentRow = null; self.getList(); });
|
||||
},
|
||||
handleReject() {
|
||||
var self = this;
|
||||
this.$prompt('请输入驳回原因', '驳回审批', { inputType: 'textarea', inputValidator: function(v) { return v ? true : '驳回原因不能为空'; } }).then(function({ value }) {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 0, remark: value });
|
||||
}).then(function() { self.$modal.msgSuccess("已驳回"); self.currentRow = null; self.getList(); });
|
||||
},
|
||||
handleMarkDisc(row) {
|
||||
this.markForm = { discrepancyId: row.discrepancyId, discrepancyType: row.discrepancyType, enterCoilNo: row.enterCoilNo, discrepancyDetail: row.discrepancyDetail, needResolve: row.processStatus === 1, approveRemark: row.remark || '' };
|
||||
this.markDialogVisible = true;
|
||||
},
|
||||
submitMark() {
|
||||
var self = this;
|
||||
updateCountDiscrepancy({ discrepancyId: this.markForm.discrepancyId, processStatus: this.markForm.needResolve ? 1 : 0, remark: this.markForm.approveRemark }).then(function() {
|
||||
self.$modal.msgSuccess('标记已保存'); self.markDialogVisible = false;
|
||||
var wh = self.$refs.whPanel.getActiveWarehouse();
|
||||
if (wh) self.$refs.whPanel.refreshOneDisc(wh.relId);
|
||||
}).catch(function() { self.$modal.msgError('保存失败'); });
|
||||
},
|
||||
handlePreview(ossId, label) {
|
||||
var self = this; this.previewUrl = ''; this.previewOpen = true;
|
||||
listByIds(ossId).then(function(r) { var list = r.data || r.rows || []; if (list.length > 0) self.previewUrl = list[0].url; else { self.$modal.msgError('未找到'); self.previewOpen = false; } }).catch(function() { self.$modal.msgError('失败'); self.previewOpen = false; });
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 2, remark: value });
|
||||
}).then(function() { self.$modal.msgSuccess("已驳回至盘库执行"); self.currentRow = null; self.getList(); });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -158,21 +90,5 @@ export default {
|
||||
.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>
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
</div>
|
||||
<el-steps :active="activeStep" align-center class="flow-steps">
|
||||
<el-step title="创建计划" icon="el-icon-document" />
|
||||
<el-step title="快照与对比" icon="el-icon-camera" />
|
||||
<el-step title="提交审批" icon="el-icon-s-promotion" />
|
||||
<el-step title="处理差异" icon="el-icon-warning" />
|
||||
<el-step title="计划审批" icon="el-icon-s-promotion" />
|
||||
<el-step title="盘库执行" icon="el-icon-camera" />
|
||||
<el-step title="差异审批" icon="el-icon-s-check" />
|
||||
<el-step title="差异处理" icon="el-icon-warning" />
|
||||
<el-step title="完成归档" icon="el-icon-circle-check" />
|
||||
</el-steps>
|
||||
<div class="current-status">
|
||||
@@ -34,28 +35,28 @@ export default {
|
||||
computed: {
|
||||
/**
|
||||
* el-steps active 从 0 开始。
|
||||
* 步骤:0=创建计划, 1=快照与对比, 2=提交审批, 3=处理差异, 4=完成归档
|
||||
* status 0=草稿 -> active=0 (创建计划)
|
||||
* status 1=待审批 -> active=2 (提交审批)
|
||||
* status 2=执行中 -> active=3 (处理差异)
|
||||
* status 3=差异处理 -> active=3 (处理差异)
|
||||
* status 4=已归档 -> active=5 (全部finish)
|
||||
* 步骤:0=创建计划, 1=计划审批, 2=盘库执行, 3=差异审批, 4=差异处理, 5=完成归档
|
||||
* status 0=草稿 -> active=0
|
||||
* status 1=计划待审批 -> active=1
|
||||
* status 2=盘库执行中 -> active=2
|
||||
* status 3=差异审批中 -> active=3
|
||||
* status 4=差异处理中 -> active=4
|
||||
* status 5=已归档 -> active=6 (全部finish)
|
||||
*/
|
||||
activeStep() {
|
||||
if (this.planStatus == null) return -1;
|
||||
const v = Number(this.planStatus);
|
||||
if (v >= 4) return 5;
|
||||
if (v === 1) return 2;
|
||||
if (v === 2 || v === 3) return 3;
|
||||
if (v >= 5) return 6;
|
||||
return v;
|
||||
},
|
||||
flowStatusText() {
|
||||
const map = {
|
||||
0: '草稿',
|
||||
1: '待审批',
|
||||
2: '执行中',
|
||||
3: '差异处理中',
|
||||
4: '已归档'
|
||||
1: '计划待审批',
|
||||
2: '盘库执行中',
|
||||
3: '差异审批中',
|
||||
4: '差异处理中',
|
||||
5: '已归档'
|
||||
};
|
||||
return map[this.planStatus] || '未知';
|
||||
},
|
||||
@@ -64,8 +65,9 @@ export default {
|
||||
0: 'info',
|
||||
1: '',
|
||||
2: 'warning',
|
||||
3: 'danger',
|
||||
4: 'success'
|
||||
3: '',
|
||||
4: 'danger',
|
||||
5: 'success'
|
||||
};
|
||||
return map[this.planStatus] || '';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div v-if="!currentRow" class="empty-tip"><i class="el-icon-info"></i><span>{{ emptyText }}</span></div>
|
||||
<div v-else v-loading="loading" 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">{{ subtitle }}</div>
|
||||
</div>
|
||||
<div class="doc-header-right">
|
||||
<el-button size="mini" type="text" icon="el-icon-refresh" @click="refresh">刷新</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="text" icon="el-icon-edit" @click="$emit('edit-plan', currentRow)">编辑</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="text" icon="el-icon-delete" @click="$emit('delete-plan', currentRow)">删除</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 4" size="mini" type="success" icon="el-icon-circle-check" @click="$emit('archive')">归档封存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="doc-status-row">
|
||||
<span class="doc-status-label">Status:</span>
|
||||
<el-tag v-if="currentRow.planStatus === 0" type="info" size="small">草稿</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 1" size="small">计划待审批</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 2" type="warning" size="small">盘库执行中</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 3" size="small">差异审批中</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 4" type="danger" size="small">差异处理中</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 5" type="success" size="small">已归档</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-meta">
|
||||
<span><i class="el-icon-document"></i>{{ currentRow.planName }}</span>
|
||||
<span v-if="currentRow.countDate"><i class="el-icon-date"></i>{{ formatTime(currentRow.countDate, '{y}-{m}-{d}') }}</span>
|
||||
<span v-if="currentRow.countUserName"><i class="el-icon-user-solid"></i>{{ currentRow.countUserName }}</span>
|
||||
<span v-if="currentRow.principalUserName"><i class="el-icon-s-custom"></i>{{ currentRow.principalUserName }}</span>
|
||||
</div>
|
||||
|
||||
<CountFlowSection :planStatus="currentRow.planStatus" />
|
||||
|
||||
<el-divider />
|
||||
|
||||
<!-- 流程操作按钮 -->
|
||||
<div v-if="currentRow.planStatus === 0" class="section-title">
|
||||
<span>流程操作 <span class="en-sub">· Actions</span></span>
|
||||
</div>
|
||||
<div class="flow-actions" v-if="currentRow.planStatus === 0">
|
||||
<el-button type="primary" size="small" icon="el-icon-s-promotion" @click="$emit('submit-approval')">提交审批</el-button>
|
||||
</div>
|
||||
|
||||
<el-divider v-if="currentRow.planStatus === 0" />
|
||||
|
||||
<div class="section-title">库区盘点明细 <span class="en-sub">· Warehouses</span>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="primary" plain icon="el-icon-plus" style="margin-left:8px;" @click="$emit('bind-warehouse')">绑定库区</el-button>
|
||||
</div>
|
||||
|
||||
<WarehouseDetailPanel ref="whPanel"
|
||||
:planId="currentRow.planId"
|
||||
:planStatus="currentRow.planStatus"
|
||||
@approve="$emit('approve')"
|
||||
@diff-approve="$emit('diff-approve')"
|
||||
@reject="$emit('reject')"
|
||||
@archive="$emit('archive')"
|
||||
@process-disc="$emit('process-disc', $event)"
|
||||
@submit-disc-approval="$emit('submit-disc-approval')"
|
||||
/>
|
||||
|
||||
<div class="section-gap" />
|
||||
<div class="section-title">备注 <span class="en-sub">· Remarks</span></div>
|
||||
<div class="remark-content">{{ currentRow.remark || '无' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCountPlan } from "@/api/flow/countPlan";
|
||||
import CountFlowSection from "./CountFlowSection.vue";
|
||||
import WarehouseDetailPanel from "./WarehouseDetailPanel.vue";
|
||||
import { parseTime } from '@/utils/klp';
|
||||
|
||||
export default {
|
||||
name: 'PlanDetailPanel',
|
||||
components: { CountFlowSection, WarehouseDetailPanel },
|
||||
props: {
|
||||
planId: { type: [Number, String], default: null },
|
||||
emptyText: { type: String, default: '请在左侧列表中选择一条盘库计划' },
|
||||
subtitle: { type: String, default: 'Inventory Count Plan' }
|
||||
},
|
||||
data() {
|
||||
return { loading: false, currentRow: null };
|
||||
},
|
||||
watch: {
|
||||
planId: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (!val) { this.currentRow = null; return; }
|
||||
this.loadDetail(val);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatTime(val, fmt) { if (!val) return ''; return parseTime(val, fmt); },
|
||||
loadDetail(planId) {
|
||||
this.loading = true; var self = this;
|
||||
getCountPlan(planId).then(function(r) { self.currentRow = r.data; self.$emit('loaded', r.data); }).finally(function() { self.loading = false; });
|
||||
},
|
||||
refresh() { if (this.currentRow) this.loadDetail(this.currentRow.planId); if (this.$refs.whPanel) this.$refs.whPanel.refreshAll(); }
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.empty-tip { display: flex; align-items: center; justify-content: center; height: 100%; color: #909399; font-size: 14px; gap: 8px; }
|
||||
.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%; }
|
||||
.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; letter-spacing: 0.3px; }
|
||||
.section-title:first-child { margin-top: 0; }
|
||||
.section-title .en-sub { font-size: 11px; font-weight: 400; color: #8c8c8c; letter-spacing: 0.5px; font-style: italic; }
|
||||
.flow-actions { display: flex; gap: 10px; flex-wrap: wrap; }
|
||||
.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>
|
||||
@@ -13,8 +13,8 @@
|
||||
<div class="doc-tabs-content">
|
||||
<div v-for="(wh, idx) in warehouseList" :key="wh.relId" v-show="activeIdx === idx">
|
||||
|
||||
<!-- ====== 草稿 (0):操作台 ====== -->
|
||||
<template v-if="planStatus === 0">
|
||||
<!-- ====== 盘库执行中 (2):操作台 ====== -->
|
||||
<template v-if="planStatus === 2">
|
||||
<div class="console-section">
|
||||
<div class="console-steps">
|
||||
<div class="console-step" :class="{ done: wh.snapshotCoilLogic }">
|
||||
@@ -73,12 +73,34 @@
|
||||
</div>
|
||||
|
||||
<div style="text-align:right;margin-bottom:8px;">
|
||||
<el-button type="primary" size="small" icon="el-icon-s-promotion" @click="$emit('submit-approval')">提交审批</el-button>
|
||||
<el-button type="primary" size="small" icon="el-icon-s-promotion" @click="$emit('submit-disc-approval')">提交差异审批</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ====== 概览卡片(状态 0/1/4) ====== -->
|
||||
<div v-if="planStatus !== 3" class="wh-overview">
|
||||
<!-- ====== 草稿 (0) / 计划待审批 (1):库区清单 ====== -->
|
||||
<template v-if="planStatus === 0 || planStatus === 1">
|
||||
<div class="wh-detail-list">
|
||||
<div class="wh-detail-row">
|
||||
<span class="wh-detail-label">逻辑库区</span>
|
||||
<span class="wh-detail-value">{{ wh.warehouseName || '-' }}</span>
|
||||
</div>
|
||||
<div class="wh-detail-row">
|
||||
<span class="wh-detail-label">实际库区</span>
|
||||
<span class="wh-detail-value">{{ wh.actualWarehouseName || '-' }}</span>
|
||||
</div>
|
||||
<div class="wh-detail-row">
|
||||
<span class="wh-detail-label">出入库查询起始</span>
|
||||
<span class="wh-detail-value">{{ wh.ioStartTime ? formatTime(wh.ioStartTime) : '-' }}</span>
|
||||
</div>
|
||||
<div class="wh-detail-row">
|
||||
<span class="wh-detail-label">出入库查询截止</span>
|
||||
<span class="wh-detail-value">{{ wh.ioEndTime ? formatTime(wh.ioEndTime) : '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ====== 概览卡片(状态 2/3/4/5) ====== -->
|
||||
<div v-if="planStatus >= 2" class="wh-overview">
|
||||
<div class="wh-box">
|
||||
<div class="wh-box-title">盘点范围</div>
|
||||
<div class="wh-box-body">
|
||||
@@ -108,19 +130,28 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== 待审批操作 ===== -->
|
||||
<!-- ===== 计划待审批 (1) 操作 ===== -->
|
||||
<div v-if="planStatus === 1" style="text-align:right;margin-bottom:8px;">
|
||||
<el-button size="small" type="danger" icon="el-icon-close" @click="$emit('reject')">驳回</el-button>
|
||||
<el-button size="small" type="primary" icon="el-icon-check" @click="$emit('approve')">审批通过</el-button>
|
||||
</div>
|
||||
|
||||
<!-- ===== 差异审批中 (3) 操作 ===== -->
|
||||
<div v-if="planStatus === 3" style="text-align:right;margin-bottom:8px;">
|
||||
<el-button size="small" type="danger" icon="el-icon-close" @click="$emit('reject')">驳回</el-button>
|
||||
<el-button size="small" type="primary" icon="el-icon-check" @click="$emit('diff-approve')">审批通过</el-button>
|
||||
</div>
|
||||
|
||||
<!-- ===== 差异处理中 (4) 操作 ===== -->
|
||||
<div v-if="planStatus === 4" style="text-align:right;margin-bottom:8px;">
|
||||
<el-button size="small" type="success" icon="el-icon-circle-check" @click="$emit('archive')">归档封存</el-button>
|
||||
</div>
|
||||
|
||||
<!-- ====== 差异明细表格 ====== -->
|
||||
<!-- ====== 差异明细表格(状态 2+) ====== -->
|
||||
<template v-if="planStatus >= 2">
|
||||
<div class="section-title">差异明细</div>
|
||||
|
||||
<template v-if="planStatus === 0">
|
||||
<template v-if="planStatus === 2">
|
||||
<div style="display:flex;justify-content:flex-end;margin-bottom:4px;">
|
||||
<el-button size="mini" type="danger" plain icon="el-icon-delete" :disabled="discSelected.length === 0" @click="batchDelDisc(wh)">批量删除</el-button>
|
||||
</div>
|
||||
@@ -167,21 +198,31 @@
|
||||
<el-table-column label="处理建议" align="center" min-width="100">
|
||||
<template slot-scope="ds">{{ ds.row.processSuggestion || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="需处理" align="center" width="80">
|
||||
<template slot-scope="ds">
|
||||
<el-tag v-if="ds.row.processStatus === 1" type="warning" size="mini">是</el-tag>
|
||||
<el-tag v-else type="info" size="mini">否</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="80">
|
||||
<template slot-scope="ds">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="$emit('mark-disc', ds.row)">标记</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<template v-else-if="planStatus === 3">
|
||||
<el-table v-loading="discLoadingMap[wh.relId]" :data="discMap[wh.relId] || []" border size="small" style="width:100%" height="300">
|
||||
<el-table-column label="类型" align="center" width="80">
|
||||
<template slot-scope="ds">
|
||||
<el-tag v-if="ds.row.discrepancyType === 1" type="success" size="mini">盘盈</el-tag>
|
||||
<el-tag v-else-if="ds.row.discrepancyType === 2" type="danger" size="mini">盘亏</el-tag>
|
||||
<el-tag v-else-if="ds.row.discrepancyType === 3" type="warning" size="mini">不符</el-tag>
|
||||
<el-tag v-else size="mini">偏差</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="钢卷号" align="center" prop="enterCoilNo" width="140" />
|
||||
<el-table-column label="差异详情" align="center" prop="discrepancyDetail" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="原因分析" align="center" min-width="100">
|
||||
<template slot-scope="ds">{{ ds.row.reasonAnalysis || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="处理建议" align="center" min-width="100">
|
||||
<template slot-scope="ds">{{ ds.row.processSuggestion || '-' }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<template v-else-if="planStatus === 4">
|
||||
<el-table v-loading="discLoadingMap[wh.relId]" :data="discMap[wh.relId] || []" border size="small" style="width:100%" height="300">
|
||||
<el-table-column label="类型" align="center" width="80">
|
||||
<template slot-scope="ds">
|
||||
@@ -219,7 +260,7 @@
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<template v-else-if="planStatus === 4">
|
||||
<template v-else-if="planStatus === 5">
|
||||
<el-table v-loading="discLoadingMap[wh.relId]" :data="discMap[wh.relId] || []" border size="small" style="width:100%" height="300">
|
||||
<el-table-column label="类型" align="center" width="80">
|
||||
<template slot-scope="ds">
|
||||
@@ -257,6 +298,7 @@
|
||||
<div v-else style="text-align:right;padding:4px 0;">
|
||||
<el-pagination background layout="prev, pager, next, total" :total="discTotalMap[wh.relId] || 0" :page-size="discPageSize" :current-page="discPageMap[wh.relId] || 1" @current-change="function(p) { loadDisc(wh.relId, p); }" small />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -402,8 +444,11 @@ export default {
|
||||
listCountDiscrepancy({ relId, pageNum: pageNum, pageSize: this.discPageSize }).then(function(r) {
|
||||
self.$set(self.discMap, relId, (r.rows || []).map(function(item) {
|
||||
if (item._processResult === undefined) item._processResult = item.processResult || '';
|
||||
if (item._needResolve === undefined) item._needResolve = item.processStatus === 1;
|
||||
if (item._approveRemark === undefined) item._approveRemark = item.remark || '';
|
||||
return item;
|
||||
}));
|
||||
self.$set(self.discTotalMap, relId, r.total || 0);
|
||||
}).finally(function() { self.$set(self.discLoadingMap, relId, false); });
|
||||
},
|
||||
loadAllDisc() { var self = this; this.warehouseList.forEach(function(wh) { self.loadDisc(wh.relId); }); },
|
||||
@@ -507,6 +552,10 @@ export default {
|
||||
if (!row || !row.discrepancyId) return;
|
||||
updateCountDiscrepancy({ discrepancyId: row.discrepancyId, reasonAnalysis: row.reasonAnalysis, processSuggestion: row.processSuggestion }).catch(function() {});
|
||||
},
|
||||
saveDiscMark(row) {
|
||||
if (!row || !row.discrepancyId) return;
|
||||
updateCountDiscrepancy({ discrepancyId: row.discrepancyId, processStatus: row._needResolve ? 1 : 0, remark: row._approveRemark }).catch(function() {});
|
||||
},
|
||||
|
||||
// ===== 对比 =====
|
||||
async doCompare(wh) {
|
||||
@@ -568,6 +617,11 @@ export default {
|
||||
<style scoped>
|
||||
.wh-panel { }
|
||||
.wh-empty { padding: 16px 0; color: #909399; font-size: 13px; }
|
||||
.wh-detail-list { margin: 8px 0 16px; border: 1px solid #e8e4de; border-radius: 2px; overflow: hidden; }
|
||||
.wh-detail-row { display: flex; padding: 8px 14px; font-size: 13px; border-bottom: 1px solid #f0ece6; }
|
||||
.wh-detail-row:last-child { border-bottom: none; }
|
||||
.wh-detail-label { width: 120px; flex-shrink: 0; color: #606266; font-weight: 500; }
|
||||
.wh-detail-value { color: #303133; }
|
||||
.doc-tabs-header { display: flex; border-bottom: 1px solid #d4d0c8; margin-bottom: 12px; }
|
||||
.doc-tab-item { padding: 8px 16px; cursor: pointer; color: #8c8c8c; font-size: 13px; font-weight: 500; border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color 0.2s, border-color 0.2s; display: flex; align-items: center; gap: 6px; user-select: none; }
|
||||
.doc-tab-item:hover { color: #1a3c6e; }
|
||||
|
||||
87
klp-ui/src/views/wms/post/InvCount/countExecute.vue
Normal file
87
klp-ui/src/views/wms/post/InvCount/countExecute.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<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" style="margin-left:4px;" 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="warning" 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">
|
||||
<PlanDetailPanel ref="detailPanel"
|
||||
:planId="currentRow ? currentRow.planId : null"
|
||||
subtitle="Count Execution"
|
||||
emptyText="请在左侧列表中选择一条盘库计划进行执行操作"
|
||||
@submit-disc-approval="handleSubmitDiscApproval"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCountPlan, updateCountPlan } from "@/api/flow/countPlan";
|
||||
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||
import PlanDetailPanel from "./components/PlanDetailPanel.vue";
|
||||
import { parseTime } from '@/utils/klp'
|
||||
|
||||
export default {
|
||||
name: "InvCountCountExecute",
|
||||
components: { DragResizePanel, PlanDetailPanel },
|
||||
data() {
|
||||
return {
|
||||
loading: false, total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 2 },
|
||||
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; },
|
||||
handleSubmitDiscApproval() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认提交"' + this.currentRow.planCode + '"的差异审批?提交后将进入差异审批阶段。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 3 });
|
||||
}).then(function() { self.$modal.msgSuccess("已提交差异审批"); self.currentRow = null; self.getList(); });
|
||||
}
|
||||
}
|
||||
};
|
||||
</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; }
|
||||
.empty-tip { display: flex; align-items: center; justify-content: center; height: 100%; color: #909399; font-size: 14px; gap: 8px; }
|
||||
</style>
|
||||
@@ -26,32 +26,12 @@
|
||||
</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>
|
||||
<PlanDetailPanel ref="detailPanel"
|
||||
:planId="currentRow ? currentRow.planId : null"
|
||||
subtitle="Discrepancy Processing"
|
||||
@process-disc="handleProcessDisc"
|
||||
@archive="handleArchive"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
@@ -59,20 +39,19 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCountPlan, getCountPlan, updateCountPlan } from "@/api/flow/countPlan";
|
||||
import { listCountPlan, 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 PlanDetailPanel from "./components/PlanDetailPanel.vue";
|
||||
import { parseTime } from '@/utils/klp'
|
||||
|
||||
export default {
|
||||
name: "InvCountExecute",
|
||||
components: { DragResizePanel, CountFlowSection, WarehouseDetailPanel },
|
||||
components: { DragResizePanel, PlanDetailPanel },
|
||||
data() {
|
||||
return {
|
||||
loading: false, detailLoading: false, total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 3 },
|
||||
loading: false, total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 4 },
|
||||
dataList: [], currentRow: null
|
||||
};
|
||||
},
|
||||
@@ -81,8 +60,8 @@ export default {
|
||||
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; }); } },
|
||||
handleRowClick(row) { this.currentRow = row; },
|
||||
handleRefreshDetail() { if (this.currentRow) this.currentRow = Object.assign({}, this.currentRow); },
|
||||
handleProcessDisc({ row, relId }) {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认将该差异项标记为已处理?', '处理确认', { confirmButtonText: '确认处理', cancelButtonText: '取消', type: 'warning' }).then(function() {
|
||||
@@ -91,13 +70,19 @@ export default {
|
||||
return updateCountDiscrepancy({
|
||||
discrepancyId: row.discrepancyId,
|
||||
processResult: row._processResult || '',
|
||||
processStatus: 2,
|
||||
processStatus: 2, processUserId: self.$store.getters.id, processUserName: self.$store.getters.nickName,
|
||||
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);
|
||||
self.$refs.detailPanel.$refs.whPanel.refreshOneDisc(relId);
|
||||
}).catch(function(err) { if (err !== 'cancel') self.$modal.msgError('处理失败'); });
|
||||
},
|
||||
handleArchive() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认将盘库计划归档封存?').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 5 });
|
||||
}).then(function() { self.$modal.msgSuccess("已归档"); self.currentRow = null; self.getList(); });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
</div>
|
||||
<el-select v-model="queryParams.planStatus" placeholder="全部状态" clearable size="mini" @change="handleQuery" class="header-filter">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="待审批" :value="1" />
|
||||
<el-option label="差异处理中" :value="2" />
|
||||
<el-option label="差异处理中" :value="3" />
|
||||
<el-option label="已归档" :value="4" />
|
||||
<el-option label="计划待审批" :value="1" />
|
||||
<el-option label="盘库执行" :value="2" />
|
||||
<el-option label="差异待审批" :value="3" />
|
||||
<el-option label="差异处理" :value="4" />
|
||||
<el-option label="已归档" :value="5" />
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
@@ -35,10 +36,11 @@
|
||||
</div>
|
||||
<div class="item-meta">
|
||||
<el-tag v-if="item.planStatus === 0" type="info" size="mini">草稿</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 1" size="mini">待审批</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 2" type="warning" size="mini">差异处理中</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 3" type="danger" size="mini">差异处理中</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 4" type="success" size="mini">已归档</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 1" size="mini">计划待审批</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 2" type="warning" size="mini">盘库执行中</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 3" size="mini">差异审批中</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 4" type="danger" size="mini">差异处理中</el-tag>
|
||||
<el-tag v-else-if="item.planStatus === 5" type="success" size="mini">已归档</el-tag>
|
||||
</div>
|
||||
<div class="item-actions">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(item)"></el-button>
|
||||
@@ -60,87 +62,21 @@
|
||||
|
||||
<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">Inventory Count Plan</div>
|
||||
</div>
|
||||
<div class="doc-header-right">
|
||||
<el-button size="mini" type="text" icon="el-icon-refresh" @click="handleRefreshDetail" title="刷新详情">刷新</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(currentRow)" v-if="currentRow.planStatus === 0">编辑</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(currentRow)" v-if="currentRow.planStatus === 0">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="doc-status-row">
|
||||
<span class="doc-status-label">Status / 状态:</span>
|
||||
<el-tag v-if="currentRow.planStatus === 0" type="info" size="small">草稿</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 1" size="small">待审批</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 2" type="warning" size="small">差异处理中</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 3" type="danger" size="small">差异处理中</el-tag>
|
||||
<el-tag v-else-if="currentRow.planStatus === 4" type="success" size="small">已归档</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-meta">
|
||||
<span><i class="el-icon-document"></i>{{ currentRow.planName }}</span>
|
||||
<span v-if="currentRow.countDate"><i class="el-icon-date"></i>盘库日期: {{ parseTime(currentRow.countDate, '{y}-{m}-{d}') }}</span>
|
||||
<span v-if="currentRow.deadlineTime"><i class="el-icon-time"></i>截止: {{ parseTime(currentRow.deadlineTime, '{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
<span v-if="currentRow.countUserName"><i class="el-icon-user-solid"></i>盘点人: {{ currentRow.countUserName }}</span>
|
||||
<span v-if="currentRow.principalUserName"><i class="el-icon-s-custom"></i>负责人: {{ currentRow.principalUserName }}</span>
|
||||
<span v-if="currentRow.participantNames"><i class="el-icon-user"></i>参与人: {{ currentRow.participantNames }}</span>
|
||||
</div>
|
||||
|
||||
<CountFlowSection :planStatus="currentRow.planStatus" />
|
||||
|
||||
<el-divider />
|
||||
|
||||
<div class="section-title">
|
||||
<span>流程操作 <span class="en-sub">· Workflow Actions</span></span>
|
||||
</div>
|
||||
<div class="flow-actions">
|
||||
<el-button v-if="currentRow.planStatus === 0" type="primary" size="small" icon="el-icon-s-promotion" @click="handleSubmitApproval">提交审批</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 1" type="primary" size="small" icon="el-icon-s-promotion" @click="handleStartCount">审批通过,开始盘库</el-button>
|
||||
<el-button v-if="currentRow.planStatus === 3" type="success" size="small" icon="el-icon-circle-check" @click="handleArchive">归档封存</el-button>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<div class="section-title">
|
||||
库区盘点明细 <span class="en-sub">· Warehouse Count Details</span>
|
||||
<el-button v-if="currentRow.planStatus === 0" size="mini" type="primary" plain icon="el-icon-plus" style="margin-left: 8px;" @click="handleAddWarehouse">绑定库区</el-button>
|
||||
</div>
|
||||
|
||||
<WarehouseDetailPanel ref="whPanel"
|
||||
:planId="currentRow.planId"
|
||||
:planStatus="currentRow.planStatus"
|
||||
@submit-approval="handleSubmitApproval"
|
||||
@approve="handleStartCount"
|
||||
@archive="handleArchive"
|
||||
@process-disc="handleProcessFromPanel"
|
||||
/>
|
||||
|
||||
|
||||
<!-- Excel 快照预览弹窗 -->
|
||||
<el-dialog title="快照预览" :visible.sync="previewDialogVisible" width="80%" top="5vh" append-to-body
|
||||
:before-close="function() { previewDialogVisible = false; previewUrl = ''; }">
|
||||
<div slot="title">{{ previewTitle }}</div>
|
||||
<div style="height:75vh;">
|
||||
<vue-office-excel v-if="previewUrl" :src="previewUrl" @render-error="handleExcelError" />
|
||||
<span v-else style="color:#909399;">加载中...</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<div class="section-gap" />
|
||||
|
||||
<div class="section-title">备注 <span class="en-sub">· Remarks</span></div>
|
||||
<div class="remark-content">{{ currentRow.remark || '无' }}</div>
|
||||
</div>
|
||||
<PlanDetailPanel ref="detailPanel"
|
||||
:planId="currentRow ? currentRow.planId : null"
|
||||
subtitle="Inventory Count Plan"
|
||||
emptyText="请在左侧列表中选择一条盘库计划查看详情"
|
||||
@submit-approval="handleSubmitApproval"
|
||||
@approve="handlePlanApprove"
|
||||
@diff-approve="handleDiffApprove"
|
||||
@archive="handleArchive"
|
||||
@edit-plan="handleUpdate"
|
||||
@delete-plan="handleDelete"
|
||||
@bind-warehouse="handleAddWarehouse"
|
||||
@reject="handleReject"
|
||||
@process-disc="handleProcessFromPanel"
|
||||
@submit-disc-approval="handleSubmitDiscApproval"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
@@ -275,13 +211,13 @@
|
||||
|
||||
<script>
|
||||
import { listCountPlan, getCountPlan, addCountPlan, updateCountPlan, delCountPlan } from "@/api/flow/countPlan";
|
||||
import { listCountPlanWarehouse, addCountPlanWarehouse, delCountPlanWarehouse, updateCountPlanWarehouse } from "@/api/flow/countPlanWarehouse";
|
||||
import { listCountDiscrepancy, updateCountDiscrepancy } from "@/api/flow/countDiscrepancy";
|
||||
import { addCountPlanWarehouse, delCountPlanWarehouse, updateCountPlanWarehouse } from "@/api/flow/countPlanWarehouse";
|
||||
import { updateCountDiscrepancy } from "@/api/flow/countDiscrepancy";
|
||||
import { exportCoilWithAll } from "@/api/wms/coil";
|
||||
import { uploadFile } from "@/api/system/oss";
|
||||
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||
import CountFlowSection from "./components/CountFlowSection.vue";
|
||||
import WarehouseDetailPanel from "./components/WarehouseDetailPanel.vue";
|
||||
import PlanDetailPanel from "./components/PlanDetailPanel.vue";
|
||||
import WarehouseSelect from "@/components/KLPService/WarehouseSelect/index.vue";
|
||||
import ActualWarehouseL1L2Select from "@/components/KLPService/ActualWarehouseL1L2Select/index.vue";
|
||||
import { parseTime } from '@/utils/klp'
|
||||
@@ -357,7 +293,7 @@ const SNAPSHOT_COL_MAP = {
|
||||
|
||||
export default {
|
||||
name: "CountPlan",
|
||||
components: { DragResizePanel, WarehouseSelect, ActualWarehouseL1L2Select, CountFlowSection, VueOfficeExcel, WarehouseDetailPanel },
|
||||
components: { DragResizePanel, WarehouseSelect, ActualWarehouseL1L2Select, CountFlowSection, VueOfficeExcel, PlanDetailPanel },
|
||||
data() {
|
||||
return {
|
||||
buttonLoading: false,
|
||||
@@ -444,51 +380,32 @@ export default {
|
||||
},
|
||||
handleRowClick(row) {
|
||||
this.currentRow = row;
|
||||
this.loadDetail(row.planId);
|
||||
},
|
||||
loadDetail(planId) {
|
||||
this.detailLoading = true;
|
||||
var self = this;
|
||||
getCountPlan(planId).then(function(response) {
|
||||
self.currentRow = response.data;
|
||||
self.loadWarehouseList(planId);
|
||||
}).finally(function() { self.detailLoading = false; });
|
||||
},
|
||||
loadWarehouseList(planId) {
|
||||
this.warehouseLoading = true;
|
||||
var self = this;
|
||||
listCountPlanWarehouse({ planId: planId, pageNum: 1, pageSize: 999 }).then(function(r) {
|
||||
self.warehouseList = r.rows || [];
|
||||
}).finally(function() { self.warehouseLoading = false; });
|
||||
},
|
||||
handleViewDiscrepancy(row) {
|
||||
var relId = row.relId;
|
||||
if (this.discrepancyMap[relId]) {
|
||||
return;
|
||||
}
|
||||
this.$set(this.discrepancyLoadingMap, relId, true);
|
||||
var self = this;
|
||||
listCountDiscrepancy({ relId: relId, pageNum: 1, pageSize: 999 }).then(function(r) {
|
||||
self.$set(self.discrepancyMap, relId, r.rows || []);
|
||||
}).finally(function() {
|
||||
self.$set(self.discrepancyLoadingMap, relId, false);
|
||||
});
|
||||
},
|
||||
handleRefreshDetail() {
|
||||
if (this.currentRow && this.currentRow.planId) {
|
||||
this.loadDetail(this.currentRow.planId);
|
||||
this.$refs.detailPanel.refresh();
|
||||
}
|
||||
},
|
||||
handleSubmitApproval() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认提交盘库计划"' + this.currentRow.planCode + '"进行审批?').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 1 });
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess("提交审批成功");
|
||||
self.$refs.detailPanel.refresh();
|
||||
self.getList();
|
||||
}).catch(function() { });
|
||||
},
|
||||
// 处理阶段差异处理(来自组件事件)
|
||||
handleProcessFromPanel({ 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.$message.success('已处理'); self.$refs.whPanel.refreshOneDisc(relId); }).catch(function(err) { if (err !== 'cancel') self.$message.error('处理失败'); });
|
||||
return updateCountDiscrepancy({ discrepancyId: row.discrepancyId, processResult: row._processResult || '', processStatus: 2, processUserId: self.$store.getters.id, processUserName: self.$store.getters.nickName, processTime: now.getFullYear() + '-' + pad(now.getMonth()+1) + '-' + pad(now.getDate()) + ' ' + pad(now.getHours()) + ':' + pad(now.getMinutes()) + ':' + pad(now.getSeconds()) });
|
||||
}).then(function() { self.$message.success('已处理'); self.$refs.detailPanel.$refs.whPanel.refreshOneDisc(relId); }).catch(function(err) { if (err !== 'cancel') self.$message.error('处理失败'); });
|
||||
},
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.form = { planName: new Date().toLocaleDateString().replace(/\//g, '-') + '盘库计划' };
|
||||
this.open = true;
|
||||
this.title = "新增盘库计划";
|
||||
},
|
||||
@@ -536,7 +453,7 @@ export default {
|
||||
self.open = false;
|
||||
self.getList();
|
||||
if (self.currentRow && self.currentRow.planId === self.form.planId) {
|
||||
self.loadDetail(self.currentRow.planId);
|
||||
self.$refs.detailPanel.refresh();
|
||||
}
|
||||
}).finally(function() { self.buttonLoading = false; });
|
||||
} else {
|
||||
@@ -565,30 +482,44 @@ export default {
|
||||
self.$modal.msgSuccess("删除成功");
|
||||
}).catch(function() { }).finally(function() { self.loading = false; });
|
||||
},
|
||||
handleSubmitApproval() {
|
||||
handlePlanApprove() {
|
||||
var self = this;
|
||||
if (this.warehouseList.length === 0) {
|
||||
this.$modal.msgWarning("请先绑定库区");
|
||||
return;
|
||||
}
|
||||
this.$modal.confirm('确认提交盘库计划"' + this.currentRow.planCode + '"进行审批?').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 1 });
|
||||
this.$modal.confirm('确认通过"' + this.currentRow.planCode + '"的计划审批?通过后进入盘库执行阶段。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 2 });
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess("提交审批成功");
|
||||
self.loadDetail(self.currentRow.planId);
|
||||
self.$modal.msgSuccess("审批通过,已进入盘库执行");
|
||||
self.$refs.detailPanel.refresh();
|
||||
self.getList();
|
||||
}).catch(function() { });
|
||||
},
|
||||
handleStartCount() {
|
||||
handleDiffApprove() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认开始执行盘库计划"' + this.currentRow.planCode + '"?系统将自动保存当前时间节点的库存快照并统计系统总重量和总数量。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 3 });
|
||||
this.$modal.confirm('确认通过"' + this.currentRow.planCode + '"的差异审批?通过后进入差异处理阶段。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 4 });
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess("盘库已开始执行,系统已生成库存快照");
|
||||
self.loadDetail(self.currentRow.planId);
|
||||
self.$modal.msgSuccess("差异审批通过,已进入差异处理");
|
||||
self.$refs.detailPanel.refresh();
|
||||
self.getList();
|
||||
}).catch(function() { });
|
||||
},
|
||||
handleSubmitDiscApproval() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认提交"' + this.currentRow.planCode + '"的差异审批?').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 3 });
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess("已提交差异审批");
|
||||
self.$refs.detailPanel.refresh();
|
||||
self.getList();
|
||||
}).catch(function() { });
|
||||
},
|
||||
handleReject() {
|
||||
var self = this;
|
||||
var targetStatus = self.currentRow.planStatus === 3 ? 2 : 0;
|
||||
var rejectMsg = targetStatus === 2 ? '驳回至盘库执行' : '驳回至草稿';
|
||||
this.$prompt('请输入驳回原因', '驳回审批', { inputType: 'textarea', inputValidator: function(v) { return v ? true : '驳回原因不能为空'; } }).then(function({ value }) {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: targetStatus, remark: value });
|
||||
}).then(function() { self.$modal.msgSuccess("已" + rejectMsg); self.currentRow = null; self.getList(); });
|
||||
},
|
||||
// 打开导入实盘Excel对话框
|
||||
handleUploadExcel(wh) {
|
||||
this.importWarehouse = wh;
|
||||
@@ -859,10 +790,10 @@ export default {
|
||||
handleArchive() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认将盘库计划"' + this.currentRow.planCode + '"归档封存?归档后数据将不可修改。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 4 });
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 5 });
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess("盘库计划已归档");
|
||||
self.loadDetail(self.currentRow.planId);
|
||||
self.$refs.detailPanel.refresh();
|
||||
self.getList();
|
||||
}).catch(function() { });
|
||||
},
|
||||
@@ -875,7 +806,7 @@ export default {
|
||||
return self.generateWarehouseSnapshot(wh);
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess('库区"' + label + '"快照已生成');
|
||||
self.loadWarehouseList(self.currentRow.planId);
|
||||
self.$refs.detailPanel.refresh();
|
||||
}).catch(function(err) {
|
||||
if (err !== 'cancel') {
|
||||
self.$modal.msgError(err.message || '快照生成失败');
|
||||
@@ -892,7 +823,7 @@ export default {
|
||||
return self.createSnapshot();
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess('全部库区快照已生成');
|
||||
self.loadWarehouseList(self.currentRow.planId);
|
||||
self.$refs.detailPanel.refresh();
|
||||
}).catch(function(err) {
|
||||
if (err !== 'cancel') {
|
||||
self.$modal.msgError(err.message || '快照生成失败');
|
||||
@@ -1050,7 +981,7 @@ export default {
|
||||
addCountPlanWarehouse(data).then(function() {
|
||||
self.$modal.msgSuccess("绑定库区成功");
|
||||
self.warehouseDialogVisible = false;
|
||||
self.loadWarehouseList(self.currentRow.planId);
|
||||
self.$refs.detailPanel.refresh();
|
||||
}).finally(function() { self.whButtonLoading = false; });
|
||||
},
|
||||
// 选择逻辑库区时记录名称
|
||||
@@ -1079,7 +1010,7 @@ export default {
|
||||
return delCountPlanWarehouse(row.relId);
|
||||
}).then(function() {
|
||||
self.$modal.msgSuccess("移除成功");
|
||||
self.loadWarehouseList(self.currentRow.planId);
|
||||
self.$refs.detailPanel.refresh();
|
||||
}).catch(function() { });
|
||||
},
|
||||
handleEditDiscrepancy(row) {
|
||||
@@ -1464,108 +1395,6 @@ export default {
|
||||
}
|
||||
/* ===== 自定义 Tab — 完全原生 DOM ===== */
|
||||
|
||||
/* 主Tab:仓库切换 */
|
||||
.doc-tabs {
|
||||
font-family: 'Microsoft YaHei', '微软雅黑', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
.doc-tabs-header {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
border-bottom: 1px solid #d4d0c8;
|
||||
margin-bottom: 14px;
|
||||
gap: 0;
|
||||
}
|
||||
.doc-tab-item {
|
||||
position: relative;
|
||||
padding: 8px 18px;
|
||||
cursor: pointer;
|
||||
color: #8c8c8c;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.3px;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
transition: color 0.2s, border-color 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
user-select: none;
|
||||
}
|
||||
.doc-tab-item:hover {
|
||||
color: #1a3c6e;
|
||||
}
|
||||
.doc-tab-item.active {
|
||||
color: #1a3c6e;
|
||||
font-weight: 600;
|
||||
border-bottom-color: #1a3c6e;
|
||||
}
|
||||
.doc-tab-label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.doc-tab-badge {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
font-weight: 400;
|
||||
}
|
||||
.doc-tab-item.active .doc-tab-badge {
|
||||
color: #1a3c6e;
|
||||
}
|
||||
.doc-tabs-empty {
|
||||
padding: 8px 0;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
.doc-tabs-content {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
/* 子Tab:概览 / 快照 / 差异明细 */
|
||||
.doc-sub-tabs {
|
||||
font-family: 'Microsoft YaHei', '微软雅黑', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
.doc-sub-tabs-header {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
border-bottom: 1px solid #e0dcd6;
|
||||
margin-bottom: 0;
|
||||
gap: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
.doc-sub-tab-item {
|
||||
position: relative;
|
||||
padding: 5px 18px;
|
||||
cursor: pointer;
|
||||
color: #8c8c8c;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.3px;
|
||||
background: #f7f5f0;
|
||||
border: 1px solid #e0dcd6;
|
||||
border-bottom: 1px solid #e0dcd6;
|
||||
margin-bottom: -1px;
|
||||
margin-right: -1px;
|
||||
transition: color 0.2s, background 0.2s, border-bottom-color 0.2s;
|
||||
user-select: none;
|
||||
}
|
||||
.doc-sub-tab-item:first-child {
|
||||
border-radius: 2px 0 0 0;
|
||||
}
|
||||
.doc-sub-tab-item:last-child {
|
||||
border-radius: 0 2px 0 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.doc-sub-tab-item:hover {
|
||||
color: #1a3c6e;
|
||||
}
|
||||
.doc-sub-tab-item.active {
|
||||
color: #1a3c6e;
|
||||
font-weight: 600;
|
||||
background: #ffffff;
|
||||
border-bottom-color: #ffffff;
|
||||
}
|
||||
.doc-sub-tabs-content {
|
||||
padding: 14px 0 0;
|
||||
}
|
||||
|
||||
/* 概览/快照中 el-descriptions 与文档风格统一 */
|
||||
.right-panel .el-descriptions {
|
||||
|
||||
94
klp-ui/src/views/wms/post/InvCount/planApproval.vue
Normal file
94
klp-ui/src/views/wms/post/InvCount/planApproval.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<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-check"></i><span>计划审批</span><el-button size="mini" type="text" icon="el-icon-refresh" @click="getList" style="margin-left:4px;" 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 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">
|
||||
<PlanDetailPanel ref="detailPanel"
|
||||
:planId="currentRow ? currentRow.planId : null"
|
||||
subtitle="Plan Approval"
|
||||
emptyText="请在左侧列表中选择一条盘库计划进行审批"
|
||||
@approve="handleApprove"
|
||||
@reject="handleReject"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</DragResizePanel>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCountPlan, updateCountPlan } from "@/api/flow/countPlan";
|
||||
import DragResizePanel from "@/components/DragResizePanel/index.vue";
|
||||
import PlanDetailPanel from "./components/PlanDetailPanel.vue";
|
||||
import { parseTime } from '@/utils/klp'
|
||||
|
||||
export default {
|
||||
name: "InvCountPlanApproval",
|
||||
components: { DragResizePanel, PlanDetailPanel },
|
||||
data() {
|
||||
return {
|
||||
loading: false, total: 0,
|
||||
dataList: [], currentRow: null,
|
||||
queryParams: { pageNum: 1, pageSize: 10, planCode: undefined, planStatus: 1 }
|
||||
};
|
||||
},
|
||||
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; },
|
||||
handleApprove() {
|
||||
var self = this;
|
||||
this.$modal.confirm('确认通过"' + this.currentRow.planCode + '"的计划审批?通过后进入盘库执行阶段。').then(function() {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 2 });
|
||||
}).then(function() { self.$modal.msgSuccess("审批通过,已进入盘库执行"); self.currentRow = null; self.getList(); });
|
||||
},
|
||||
handleReject() {
|
||||
var self = this;
|
||||
this.$prompt('请输入驳回原因', '驳回审批', { inputType: 'textarea', inputValidator: function(v) { return v ? true : '驳回原因不能为空'; } }).then(function({ value }) {
|
||||
return updateCountPlan({ planId: self.currentRow.planId, planStatus: 0, remark: value });
|
||||
}).then(function() { self.$modal.msgSuccess("已驳回至草稿"); self.currentRow = null; self.getList(); });
|
||||
}
|
||||
}
|
||||
};
|
||||
</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; }
|
||||
.empty-tip { display: flex; align-items: center; justify-content: center; height: 100%; color: #909399; font-size: 14px; gap: 8px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user