feat(wms盘库): 完成多项功能升级与体验优化

1. 新增仓库选择组件多选支持,适配批量库区操作
2. 售后单新增自动生成编号与当前日期填充
3. 盘点计划新增流程审批操作按钮,支持驳回与审批通过
4. 优化库区绑定页面,支持编辑删除已绑定库区
5. 替换人员选择为可搜索下拉框,支持多选参与人
6. 新增驳回审批弹窗,提供快捷驳回理由
7. 优化表单提交逻辑,适配多库区数据格式
This commit is contained in:
2026-06-27 14:38:33 +08:00
parent 88d2d864b2
commit 3d5c0a7281
7 changed files with 217 additions and 73 deletions

View File

@@ -28,9 +28,13 @@
subtitle="Application"
emptyText="请在左侧列表中选择一条盘库计划"
@submit-approval="handleSubmitApproval"
@approve="handlePlanApprove"
@reject="handleReject"
@edit-plan="handleUpdate"
@delete-plan="handleDelete"
@bind-warehouse="handleAddWarehouse"
@edit-warehouse="handleEditWarehouse"
@delete-warehouse="handleDeleteWarehouse"
/>
</div>
</template>
@@ -41,29 +45,43 @@
<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-select v-model="planForm.countUserName" filterable allow-create default-first-option placeholder="请输入盘点人" style="width:100%"><el-option v-for="e in employeeList" :key="e" :label="e" :value="e" /></el-select></el-form-item>
<el-form-item label="负责人"><el-select v-model="planForm.principalUserName" filterable allow-create default-first-option placeholder="请输入负责人" style="width:100%"><el-option v-for="e in employeeList" :key="e" :label="e" :value="e" /></el-select></el-form-item>
<el-form-item label="参与人"><el-select v-model="participantNamesArr" multiple filterable allow-create default-first-option placeholder="请输入参与人员" style="width:100%"><el-option v-for="e in employeeList" :key="e" :label="e" :value="e" /></el-select></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>
<el-dialog title="绑定库区" :visible.sync="whDialogOpen" width="550px" append-to-body>
<el-form :model="whForm" label-width="120px">
<el-form-item label="逻辑库区"><WarehouseSelect ref="wsRef" v-model="whForm.warehouseId" @change="onWhChange" /></el-form-item>
<el-form-item label="实际库区"><ActualWarehouseL1L2Select ref="awsRef" v-model="whForm.actualWarehouseId" @change="onAwhChange" /></el-form-item>
<el-dialog :title="whDialogTitle" :visible.sync="whDialogOpen" width="550px" append-to-body>
<el-form :model="whForm" label-width="120px" :key="'wh-form-' + whDialogMode + '-' + (editingRelId || 0)">
<el-form-item label="逻辑库区"><WarehouseSelect ref="wsRef" v-model="whForm.warehouseIds" multiple @change="onWhChange" /></el-form-item>
<el-form-item label="实际库区"><ActualWarehouseL1L2Select ref="awsRef" v-model="whForm.actualWarehouseIds" multiple @change="onAwhChange" /></el-form-item>
<el-form-item label="出入库起始"><el-date-picker v-model="whForm.ioStartTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%" /></el-form-item>
<el-form-item label="出入库截止"><el-date-picker v-model="whForm.ioEndTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" style="width:100%" /></el-form-item>
</el-form>
<div slot="footer"><el-button :loading="whBtnLoading" type="primary" @click="submitWh">确定</el-button><el-button @click="whDialogOpen = false">取消</el-button></div>
</el-dialog>
<!-- 驳回审批对话框 -->
<el-dialog title="驳回审批" :visible.sync="rejectDialogVisible" width="520px" append-to-body>
<div class="reject-quick-reasons">
<span class="reject-quick-label">快捷理由</span>
<el-tag v-for="(r, i) in rejectQuickReasons" :key="i" class="reject-tag" size="small" @click="rejectReason = r">{{ r }}</el-tag>
</div>
<el-input v-model="rejectReason" type="textarea" :rows="4" placeholder="请输入驳回原因" style="margin-top:10px;" />
<div slot="footer" class="dialog-footer">
<el-button type="danger" @click="confirmReject" :disabled="!rejectReason.trim()">确认驳回</el-button>
<el-button @click="rejectDialogVisible = false">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listCountPlan, addCountPlan, updateCountPlan, delCountPlan } from "@/api/flow/countPlan";
import { addCountPlanWarehouse } from "@/api/flow/countPlanWarehouse";
import { addCountPlanWarehouse, updateCountPlanWarehouse, delCountPlanWarehouse } from "@/api/flow/countPlanWarehouse";
import { listEmployeeInfo } from "@/api/wms/employeeInfo";
import DragResizePanel from "@/components/DragResizePanel/index.vue";
import PlanDetailPanel from "./components/PlanDetailPanel.vue";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect/index.vue";
@@ -77,25 +95,32 @@ export default {
return {
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 }
planDialogOpen: false, planDialogTitle: '', planForm: {}, employeeList: [], participantNamesArr: [],
whDialogOpen: false, whDialogTitle: '绑定库区', whDialogMode: 'add', editingRelId: null, whForm: { warehouseIds: [], actualWarehouseIds: [], warehouseName: '', actualWarehouseName: '', ioStartTime: undefined, ioEndTime: undefined },
rejectDialogVisible: false, rejectReason: '', rejectQuickReasons: ['盘点计划信息不完整,请补充后重新提交', '库区绑定有误,请核实库区信息', '盘点时间安排不合理,请调整', '盘点人员安排需调整', '缺少必要的备注说明']
};
},
created() { this.getList(); },
created() { this.getList(); this.loadEmployees(); },
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; },
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; }); },
loadEmployees() { var self = this; listEmployeeInfo({ pageNum: 1, pageSize: 9999 }).then(function(r) { self.employeeList = (r.rows || []).map(function(e) { return e.name || ''; }).filter(Boolean); }); },
handleAdd() { this.planForm = { planName: new Date().toLocaleDateString().replace(/\//g, '-') + '盘库计划' }; this.participantNamesArr = []; this.planDialogTitle = '新增盘库计划'; this.planDialogOpen = true; },
handleUpdate(row) { this.planForm = Object.assign({}, row); this.participantNamesArr = row.participantNames ? row.participantNames.split(',') : []; this.planDialogTitle = '修改'; this.planDialogOpen = true; },
submitPlan() { var self = this; this.btnLoading = true; this.planForm.planCode = this.planForm.planName; this.planForm.participantNames = this.participantNamesArr.join(','); 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.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.detailPanel.refresh(); }).finally(function() { self.whBtnLoading = false; }); }
handlePlanApprove() { var self = this; this.$modal.confirm('确认通过审批?通过后进入盘库执行阶段。').then(function() { return updateCountPlan({ planId: self.currentRow.planId, planStatus: 2 }); }).then(function() { self.$modal.msgSuccess('审批通过'); self.getList(); self.currentRow = null; }); },
handleReject() { this.rejectReason = ''; this.rejectDialogVisible = true; },
confirmReject() { var self = this; var targetStatus = self.currentRow.planStatus === 3 ? 2 : 0; var rejectMsg = targetStatus === 2 ? '驳回至盘库执行' : '驳回至草稿'; updateCountPlan({ planId: self.currentRow.planId, planStatus: targetStatus, remark: self.rejectReason }).then(function() { self.$modal.msgSuccess('已' + rejectMsg); self.rejectDialogVisible = false; self.currentRow = null; self.getList(); }); },
handleAddWarehouse() { this.whDialogMode = 'add'; this.editingRelId = null; this.whDialogTitle = '绑定库区'; this.whForm = { warehouseIds: [], actualWarehouseIds: [], warehouseName: '', actualWarehouseName: '', ioStartTime: undefined, ioEndTime: undefined }; this.whDialogOpen = true; },
handleEditWarehouse(wh) { console.log('[apply] wh:', JSON.parse(JSON.stringify(wh))); this.whDialogMode = 'edit'; this.editingRelId = wh.relId; this.whDialogTitle = '编辑库区'; var ids = wh.warehouseIds ? String(wh.warehouseIds).split(',') : []; var aids = wh.actualWarehouseIds ? String(wh.actualWarehouseIds).split(',') : []; console.log('[apply] parsed ids:', ids, 'aids:', aids); this.whForm = { warehouseIds: ids, actualWarehouseIds: aids, warehouseName: wh.warehouseName || '', actualWarehouseName: wh.actualWarehouseName || '', ioStartTime: wh.ioStartTime || undefined, ioEndTime: wh.ioEndTime || undefined }; console.log('[apply] whForm.warehouseIds:', this.whForm.warehouseIds, 'actualWarehouseIds:', this.whForm.actualWarehouseIds); this.whDialogOpen = true; },
handleDeleteWarehouse(wh) { var self = this; this.$modal.confirm('确认删除库区"' + (wh.warehouseName || wh.actualWarehouseName || '') + '"').then(function() { return delCountPlanWarehouse(wh.relId); }).then(function() { self.$modal.msgSuccess('已删除'); self.$refs.detailPanel.refresh(); }).catch(function() {}); },
onWhChange(val) { if (val && val.length && this.$refs.wsRef) { var o = this.$refs.wsRef.warehouseOptions; var names = val.map(function(id) { var f = o.find(function(x) { return x.warehouseId == id; }); return f ? f.warehouseName : ''; }).filter(Boolean); this.whForm.warehouseName = names.join(','); } else this.whForm.warehouseName = ''; },
onAwhChange(val) { if (val && val.length && this.$refs.awsRef) { var o = this.$refs.awsRef.options; var names = val.map(function(id) { var f = o.find(function(x) { return x.actualWarehouseId == id; }); return f ? f.actualWarehouseName : ''; }).filter(Boolean); this.whForm.actualWarehouseName = names.join(','); } else this.whForm.actualWarehouseName = ''; },
submitWh() { var self = this; if ((!this.whForm.warehouseIds || this.whForm.warehouseIds.length === 0) && (!this.whForm.actualWarehouseIds || this.whForm.actualWarehouseIds.length === 0)) { this.$modal.msgWarning('请至少选择一个库区'); return; } this.whBtnLoading = true; var data = { planId: this.currentRow.planId, warehouseIds: (this.whForm.warehouseIds && this.whForm.warehouseIds.length) ? this.whForm.warehouseIds.join(',') : undefined, actualWarehouseIds: (this.whForm.actualWarehouseIds && this.whForm.actualWarehouseIds.length) ? this.whForm.actualWarehouseIds.join(',') : undefined, warehouseName: this.whForm.warehouseName || undefined, actualWarehouseName: this.whForm.actualWarehouseName || undefined, ioStartTime: this.whForm.ioStartTime, ioEndTime: this.whForm.ioEndTime }; if (this.whDialogMode === 'edit') { data.relId = this.editingRelId; } var api = this.whDialogMode === 'edit' ? updateCountPlanWarehouse : addCountPlanWarehouse; api(data).then(function() { self.$modal.msgSuccess(self.whDialogMode === 'edit' ? '修改成功' : '绑定成功'); self.whDialogOpen = false; self.$refs.detailPanel.refresh(); }).finally(function() { self.whBtnLoading = false; }); }
}
};
</script>
@@ -137,4 +162,8 @@ export default {
.section-title .en-sub { font-size: 11px; font-weight: 400; color: #8c8c8c; 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; }
.reject-quick-reasons { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.reject-quick-label { font-size: 13px; color: #606266; flex-shrink: 0; }
.reject-tag { cursor: pointer; user-select: none; }
.reject-tag:hover { opacity: 0.8; }
</style>