Files
klp-oa/klp-ui/src/views/wms/delivery/plan/index.vue
砂糖 e900aec86b feat(销售权限): 实现钢卷销售权限分配功能
新增销售权限管理模块,包含以下功能:
1. 在用户模块添加id字段用于权限控制
2. 重构CoilSelector组件支持销售视角权限过滤
3. 新增销售权限分配页面,支持钢卷分配与移除
4. 优化表格样式和交互体验

组件现在支持根据用户权限动态显示和过滤钢卷数据,管理员可在新页面为销售分配钢卷权限
2025-12-18 11:51:14 +08:00

633 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="计划名称" prop="planName">
<el-input v-model="queryParams.planName" placeholder="请输入发货计划名称" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="计划日期" prop="planDate">
<el-date-picker clearable v-model="queryParams.planDate" type="date" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择计划日期">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-row :gutter="10">
<!-- 左侧发货计划列表 - 新增left-col类 -->
<el-col :span="4" class="left-col">
<!-- 卡片容器 - 新增left-card-container类 -->
<el-row :gutter="10" v-loading="loading" class="left-card-container">
<el-col :span="24" v-for="(row, index) in deliveryPlanList" :key="row.planId">
<el-card shadow="hover" class="delivery-plan-card" @click.native="handleCardClick(row)">
<div class="card-header">
<div class="card-title">{{ row.planName }}</div>
</div>
<div class="card-content">
<div class="content-item">
<span>{{ parseTime(row.planDate, '{y}-{m}-{d}') }}</span>
</div>
<div class="content-item">
<span>{{ row.createBy }}({{ parseTime(row.updateTime, '{y}-{m}-{d}') }})</span>
</div>
<div class="content-item">
<span class="label">备注</span>
<span>{{ row.remark || '-' }}</span>
</div>
</div>
<div class="card-actions">
<el-button size="mini" type="text" icon="el-icon-edit" @click.stop="handleUpdate(row)">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click.stop="handleDelete(row)">删除</el-button>
</div>
</el-card>
</el-col>
</el-row>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList" class="pagination-container" />
</el-col>
<!-- 右侧钢卷列表 - 新增right-col类 -->
<el-col :span="20" v-loading="rightLoading" class="right-col">
<!-- 选中的钢卷表格为空时的提示 -->
<div v-if="!currentPlan.planId" class="empty-tip">
<el-empty description="请先选择发货计划" />
</div>
<div v-else>
<div>
<plan-order :plan-id="currentPlan.planId"></plan-order>
</div>
<div>
<el-descriptions title="配卷">
</el-descriptions>
<coil-selector ref="coilSelector" placeholder="请选择钢卷添加至计划" @change="handleCoilChange"
:filters="coilFilters" :coil-column="coilColumn" dialog-width="1200px" :sales-restricted="true"></coil-selector>
<div v-if="selectedCoilList.length > 0 && currentPlan.planId">
<el-table :data="selectedCoilList" border highlight-current-row style="width: 100%" max-height="400px">
<!-- <el-table-column type="index" width="50" align="center" label="序号" /> -->
<!-- { label: '质量状态', prop: 'qualityStatus' },
{ label: '打包状态', prop: 'packingStatus' },
// 对应edgeType
{ label: '切边要求', prop: 'edgeRequirement' },
// 对应packaging
{ label: '包装要求', prop: 'packagingRequirement' }, -->
<el-table-column label="卷号" align="center" prop="coilDetail.currentCoilNo"
:show-overflow-tooltip="true" />
<el-table-column label="质量状态" align="center" prop="coilDetail.qualityStatus" />
<!-- <el-table-column label="打包状态" align="center" prop="coilDetail.packingStatus" /> -->
<el-table-column label="切边要求" align="center" prop="coilDetail.edgeRequirement" />
<el-table-column label="包装要求" align="center" prop="coilDetail.packagingRequirement" />
<el-table-column label="存储位置" align="center" prop="coilDetail.actualWarehouseName" width="120"
:show-overflow-tooltip="true" />
<el-table-column label="物料" align="center" prop="coilDetail.itemName" width="100" />
<el-table-column label="规格" align="center" prop="coilDetail.specification" width="100" />
<el-table-column label="材质" align="center" prop="coilDetail.material" />
<!-- <el-table-column label="厂家" align="center" prop="coilDetail.manufacturer" /> -->
<!-- <el-table-column label="重量(t)" align="center" prop="coilDetail.netWeight" width="100" /> -->
<el-table-column label="库区" align="center" prop="coilDetail.warehouseName" width="120"
:show-overflow-tooltip="true" />
<el-table-column label="操作时间" align="center" prop="createTime" :show-overflow-tooltip="true"><template
slot-scope="scope">
{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}
</template></el-table-column>
<el-table-column label="操作人" align="center" prop="createBy" width="80" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button type="danger" size="small" @click.stop="handleDeleteCoil(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div v-else class="empty-tip">
<el-empty description="暂无数据" />
</div>
</div>
</div>
</el-col>
</el-row>
<!-- 添加或修改发货计划对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="发货计划名称" prop="planName">
<el-input v-model="form.planName" placeholder="请输入发货计划名称" />
</el-form-item>
<el-form-item label="计划日期" prop="planDate">
<el-date-picker clearable v-model="form.planDate" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择计划日期">
</el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listDeliveryPlan, getDeliveryPlan, delDeliveryPlan, addDeliveryPlan, updateDeliveryPlan } from "@/api/wms/deliveryPlan";
import { listCoilOperation } from "@/api/wms/coil";
import { addDeliveryPlanCoilOperate } from "@/api/wms/deliveryPlanCoilOperate";
import coilSelector from "@/components/CoilSelector";
import PlanOrder from "../components/planOrder.vue";
export default {
name: "DeliveryPlan",
components: {
coilSelector,
PlanOrder,
},
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 发货计划表格数据
deliveryPlanList: [],
rightLoading: false,
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
planName: undefined,
planDate: undefined,
planType: 0,
},
// 表单参数
form: {
planName: '',
planDate: '',
orderId: '',
remark: '',
},
// 表单校验
rules: {},
// 选中的钢卷列表
selectedCoilList: [],
currentPlan: {},
// 防抖定时器
debounceTimer: null,
coilFilters: {
status: 0,
materialType: '成品',
selectType: 'product'
},
coilColumn: [
{
label: '卷号',
align: 'center',
prop: 'currentCoilNo',
showOverflowTooltip: true
},
{ label: '质量状态', prop: 'qualityStatus' },
{ label: '打包状态', prop: 'packingStatus' },
// 对应edgeType
{ label: '切边要求', prop: 'edgeRequirement' },
// 对应packaging
{ label: '包装要求', prop: 'packagingRequirement' },
{
label: '存储位置',
align: 'center',
prop: 'actualWarehouseName',
width: '120',
showOverflowTooltip: true
},
{
label: '物料',
align: 'center',
prop: 'itemName',
width: '100'
},
{
label: '规格',
align: 'center',
prop: 'specification',
width: '100'
},
{
label: '材质',
align: 'center',
prop: 'material',
width: '100'
},
{
label: '厂家',
align: 'center',
prop: 'manufacturer',
width: '100'
},
{
label: '重量(t)',
align: 'center',
prop: 'netWeight',
width: '100'
},
{
label: '库区',
align: 'center',
prop: 'warehouseName',
width: '120',
showOverflowTooltip: true
},
]
};
},
created() {
this.getList();
},
methods: {
/** 查询发货计划列表 */
getList() {
this.loading = true;
listDeliveryPlan(this.queryParams).then(response => {
this.deliveryPlanList = response.rows.map(item => ({
...item,
selected: false
}));
this.total = response.total;
this.loading = false;
// 重置选择状态
this.ids = [];
this.single = true;
this.multiple = true;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
async handleApprove(row) {
// 二次确认
await this.$confirm('确定审批通过该发货计划吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
this.loading = true;
this.buttonLoading = true;
const auditTime = this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}');
await updateDeliveryPlan({
planId: row.planId,
auditStatus: 1,
auditBy: this.$store.getters.name,
auditTime: auditTime,
})
this.loading = false;
this.buttonLoading = false;
// 如何当前选中的计划是被审批的计划,需要同步修改数据
if (row.planId == this.currentPlan.planId) {
this.currentPlan.auditStatus = 1;
}
this.$message({
message: '审批成功',
type: 'success'
});
this.getList();
},
getCoilList() {
if (!this.currentPlan.planId) {
this.selectedCoilList = [];
return;
}
this.rightLoading = true;
console.log(this.currentPlan)
listCoilOperation({ coilIds: this.currentPlan.coil, planId: this.currentPlan.planId }).then(response => {
this.selectedCoilList = response.data || [];
this.rightLoading = false;
});
},
handleCardClick(row) {
// 防抖处理,防止频繁点击
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(() => {
this.currentPlan = row;
this.getCoilList();
}, 300); // 300ms防抖时间
},
handleCoilChange(coilId) {
const ids = this.selectedCoilList.map(item => item.coilDetail.coilId);
if (coilId) {
// 检查是否已存在
if (!ids.includes(coilId)) {
ids.push(coilId);
const idsStr = ids.join(',');
this.currentPlan.coil = idsStr;
// 从后端查询详细信息
this.rightLoading = true;
updateDeliveryPlan({
planId: this.currentPlan.planId,
coil: ids.join(',')
}).then(_ => {
this.getList();
this.getCoilList();
addDeliveryPlanCoilOperate({
planId: this.currentPlan.planId,
coilId: coilId,
operateType: '插入',
})
})
} else {
this.$message({
message: '钢卷已存在',
type: 'warning'
});
}
}
},
// 处理删除选中钢卷
async handleDeleteCoil(row) {
await this.$modal.confirm('确定删除选中的钢卷吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
// 从选中的钢卷列表中删除选中的行
this.selectedCoilList = this.selectedCoilList.filter(item => item !== row);
// 更新发货计划
this.rightLoading = true;
await updateDeliveryPlan({
planId: this.currentPlan.planId,
coil: this.selectedCoilList.map(item => item.coilDetail.coilId).join(',')
})
this.rightLoading = false;
this.$message({
message: '删除成功',
type: 'success'
});
addDeliveryPlanCoilOperate({
planId: this.currentPlan.planId,
coilId: row.coilId,
operateType: '删除',
})
this.getList();
},
// 表单重置
reset() {
this.form = {
planId: undefined,
planName: undefined,
planDate: undefined,
planType: 0,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined,
orderId: undefined,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 卡片选择处理
handleCardSelectionChange(row) {
// 重新计算选中的ID数组
this.ids = this.deliveryPlanList.filter(item => item.selected).map(item => item.planId);
this.single = this.ids.length !== 1;
this.multiple = !this.ids.length;
},
/** 新增按钮操作 */
handleAdd() {
// this.reset();
// 默认选中今天的日期和时间, 格式化未yyyy-MM-dd HH:mm:ss
this.form.planDate = new Date().toLocaleString().replace('T', ' ').replace().replace(/\//g, '-')
// 发货计划名称格式为年-月-日命名
this.form.planName = new Date().toLocaleDateString().replace(/\//g, '-') + '发货计划'
// 计划类型为发货计划
this.form.planType = 0
this.open = true;
this.title = "添加发货计划";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const planId = row.planId || this.ids
getDeliveryPlan(planId).then(response => {
this.loading = false;
this.form = response.data;
this.open = true;
this.title = "修改发货计划";
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.planId != null) {
updateDeliveryPlan(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
} else {
addDeliveryPlan(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const planIds = row.planId || this.ids;
this.$modal.confirm('是否确认删除发货计划编号为"' + planIds + '"的数据项?').then(() => {
this.loading = true;
return delDeliveryPlan(planIds);
}).then(() => {
this.loading = false;
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 导出按钮操作 */
handleExport() {
this.download('wms/deliveryPlan/export', {
...this.queryParams
}, `deliveryPlan_${new Date().getTime()}.xlsx`)
}
}
};
</script>
<style scoped>
/* 左侧列容器样式 */
.left-col {
height: calc(100vh - 180px);
/* 自适应高度,减去顶部栏高度 */
box-sizing: border-box;
padding-right: 8px;
}
/* 左侧卡片容器 - 独立滚动 */
.left-card-container {
height: calc(100% - 50px);
/* 减去分页高度 */
overflow-y: auto;
padding-right: 5px;
/* 避免滚动条遮挡内容 */
}
/* 左侧滚动条美化 */
.left-card-container::-webkit-scrollbar {
width: 6px;
}
.left-card-container::-webkit-scrollbar-thumb {
background-color: #e6e6e6;
border-radius: 3px;
}
.left-card-container::-webkit-scrollbar-track {
background-color: #f5f5f5;
}
/* 右侧列容器样式 - 独立滚动 */
.right-col {
height: calc(100vh - 180px);
/* 和左侧等高 */
overflow-y: auto;
box-sizing: border-box;
padding-left: 8px;
}
/* 右侧滚动条美化 */
.right-col::-webkit-scrollbar {
width: 6px;
}
.right-col::-webkit-scrollbar-thumb {
background-color: #e6e6e6;
border-radius: 3px;
}
.right-col::-webkit-scrollbar-track {
background-color: #f5f5f5;
}
/* 发货计划卡片样式 - 更紧凑 */
.delivery-plan-card {
margin-bottom: 8px;
/* 减少卡片间距 */
height: 100%;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
/* 减少间距 */
}
.card-title {
font-size: 14px;
/* 减小标题字体 */
font-weight: 600;
color: #333;
}
.card-content {
margin-bottom: 6px;
/* 减少间距 */
}
.content-item {
margin-bottom: 4px;
/* 减少内容项间距 */
display: flex;
gap: 6px;
/* 减小间距 */
align-items: center;
font-size: 12px;
/* 减小字体 */
color: #606266;
}
.label {
width: 50px;
/* 减小标签宽度 */
font-weight: 500;
color: #606266;
margin-right: 4px;
}
.card-actions {
display: flex;
justify-content: center;
gap: 5px;
font-size: 12px;
}
/* 空状态提示 */
.empty-tip {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
/* 分页容器 */
.pagination-container {
margin-top: 10px;
text-align: right;
}
</style>