Files
klp-oa/klp-ui/src/views/wms/coil/docorrent.vue
砂糖 97cc86c6c4 feat(钢卷操作): 将操作类型显示从静态文本改为可编辑的下拉选择框
修改操作类型显示方式,从静态文本替换为可编辑的下拉选择框,支持用户直接修改操作类型。同时保留原有字典类型的选项支持,提升用户体验和操作便捷性。
2026-03-28 15:58:23 +08:00

808 lines
27 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="80px">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input v-model="queryParams.currentCoilNo" placeholder="请输入钢卷号" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="操作类型" prop="actionType">
<el-select v-model="queryParams.actionType" placeholder="请选择操作类型" clearable filterable>
<el-option v-for="item in dict.type.action_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<!-- <el-form-item label="只看待操作" prop="actionStatus">
<el-switch @change="switchActionStatus" v-model="queryParams.actionSwitch" />
</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="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-refresh" size="mini" @click="handleRefresh"
:disabled="buttonLoading" v-loading="buttonLoading">刷新</el-button>
</el-col>
<el-col :span="3">
<el-checkbox v-model="rubbish" label="1" @change="getList">查看被删除操作</el-checkbox>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="actionList" @selection-change="handleSelectionChange"
:row-class-name="tableRowClassName">
<el-table-column type="selection" width="55" align="center" />
<!-- <el-table-column label="序号" type="index" width="60" align="center" /> -->
<el-table-column label="钢卷号" align="center" prop="currentCoilNo">
<template slot-scope="scope">
<coil-no :coil-no="scope.row.currentCoilNo"></coil-no>
</template>
</el-table-column>
<el-table-column label="操作类型" align="center" prop="actionType" width="160">
<template slot-scope="scope">
<el-select @change="handleStatusChange(scope.row)" v-model="scope.row.actionType" placeholder="请选择操作类型" clearable filterable>
<el-option label="入库/收货操作" :value="401" />
<el-option label="发货操作" :value="402" />
<el-option label="移库操作" :value="403" />
<el-option label="通过库区编辑钢卷" :value="404" />
<el-option label="钢卷打包" :value="405" />
<el-option v-for="item in dict.type.action_type" :key="item.value" :label="item.label" :value="parseInt(item.value)" />
</el-select>
<!-- <span v-if="scope.row.actionType === 401">入库/收货操作</span>
<span v-else-if="scope.row.actionType === 402">发货操作</span>
<span v-else-if="scope.row.actionType === 403">移库操作</span>
<span v-else-if="scope.row.actionType === 404">通过库区编辑钢卷</span>
<span v-else-if="scope.row.actionType === 405">钢卷打包</span>
<dict-tag v-else :options='dict.type.action_type' :value="scope.row.actionType"></dict-tag> -->
</template>
</el-table-column>
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
<template slot-scope="scope">
<el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态" @change="handleStatusChange(scope.row)">
<el-option label="待处理" :value="0" />
<el-option label="处理中" :value="1" />
<el-option label="已完成" :value="2" />
<el-option label="已取消" :value="3" />
</el-select>
</template>
</el-table-column>
<el-table-column label="优先级" align="center" prop="priority" width="90">
<template slot-scope="scope">
<el-tag v-if="scope.row.priority === 0" type="info" size="mini">普通</el-tag>
<el-tag v-else-if="scope.row.priority === 1" type="warning" size="mini">重要</el-tag>
<el-tag v-else-if="scope.row.priority === 2" type="danger" size="mini">紧急</el-tag>
</template>
</el-table-column>
<el-table-column label="来源" align="center" prop="sourceType" width="80">
<template slot-scope="scope">
<el-tag v-if="scope.row.sourceType === 'scan'" type="success" size="mini">
<i class="el-icon-mobile"></i> 扫码
</el-tag>
<el-tag v-else type="info" size="mini">
<i class="el-icon-edit-outline"></i> 手动
</el-tag>
</template>
</el-table-column>
<el-table-column label="新增时间" align="center" prop="createTime" width="155" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" prop="updateBy" width="100" />
<el-table-column label="创建人" align="center" prop="createByName" width="140">
<template slot-scope="scope">
<el-select @change="handleProcessTimeChange(scope.row)" v-model="scope.row.createBy" placeholder="请选择创建人" filterable>
<el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userName" />
</el-select>
</template>
</el-table-column>
<el-table-column label="完成时间" align="center" prop="completeTime" width="220" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-date-picker @change="handleProcessTimeChange(scope.row)" value-format="yyyy-MM-dd HH:mm:ss"
style="width: 200px" v-model="scope.row.completeTime" type="datetime" placeholder="选择完成时间" />
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width" fixed="right">
<template slot-scope="scope">
<!-- 待处理状态显示操作按钮 -->
<!-- <template v-if="scope.row.actionStatus === 0">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="handleProcess(scope.row)"
v-loading="buttonLoading" :disabled="buttonLoading">操作</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template> -->
<!-- 处理中状态显示继续按钮 -->
<!-- <template v-else-if="scope.row.actionStatus === 1">
<el-button size="mini" type="warning" icon="el-icon-edit" @click="handleProcess(scope.row)"
:disabled="buttonLoading" v-loading="buttonLoading">继续</el-button>
<el-button size="mini" type="info" icon="el-icon-close" @click="handleCancel(scope.row)">取消</el-button>
</template> -->
<!-- 已完成或已取消状态显示删除按钮 -->
<template v-if="scope.row.actionStatus === 2 || scope.row.actionStatus === 3">
<el-button v-if="scope.row.delFlag == 0" size="mini" type="danger" icon="el-icon-delete"
@click="handleDelete(scope.row)">删除</el-button>
<el-button v-if="scope.row.delFlag == 2" size="mini" type="success" icon="el-icon-refresh"
@click="handleRestore(scope.row)">还原</el-button>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="钢卷" prop="coilId">
<coil-selector v-model="form.coilId" :use-trigger="true" @select="handleCoilSelect" />
</el-form-item>
<el-form-item label="操作类型" prop="actionType">
<div class="action-type-cards">
<!-- 分条操作区 -->
<div class="card-section" v-if="splitTypes.length > 0">
<div class="section-title">分条操作</div>
<div class="action-cards-row">
<div v-for="item in splitTypes" :key="item.value" class="action-card split-card"
:class="{ 'active': form.actionType == item.value }" @click="form.actionType = parseInt(item.value)">
<div class="card-icon">
<i :class="getActionIcon(item.value)"></i>
</div>
<div class="card-content">
<div class="card-title">{{ item.label }}</div>
<div class="card-desc">{{ item.remark || '钢卷分条操作' }}</div>
</div>
</div>
</div>
</div>
<!-- 合卷操作区 -->
<div class="card-section" v-if="mergeTypes.length > 0">
<div class="section-title">合卷操作</div>
<div class="action-cards-row">
<div v-for="item in mergeTypes" :key="item.value" class="action-card"
:class="{ 'active': form.actionType == item.value }" @click="form.actionType = parseInt(item.value)">
<div class="card-icon">
<i :class="getActionIcon(item.value)"></i>
</div>
<div class="card-content">
<div class="card-title">{{ item.label }}</div>
<div class="card-desc">{{ item.remark || '钢卷操作' }}</div>
</div>
</div>
</div>
</div>
<!-- 其他操作区 -->
<div class="card-section" v-if="otherTypes.length > 0">
<div class="section-title">其他操作</div>
<div class="action-cards-row">
<div v-for="item in otherTypes" :key="item.value" class="action-card"
:class="{ 'active': form.actionType == item.value }" @click="form.actionType = parseInt(item.value)">
<div class="card-icon">
<i :class="getActionIcon(item.value)"></i>
</div>
<div class="card-content">
<div class="card-title">{{ item.label }}</div>
<div class="card-desc">{{ item.remark || '钢卷操作' }}</div>
</div>
</div>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="优先级" prop="priority">
<el-select v-model="form.priority" placeholder="请选择优先级">
<el-option label="普通" :value="0" />
<el-option label="重要" :value="1" />
<el-option label="紧急" :value="2" />
</el-select>
</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 type="primary" @click="submitForm" :disabled="buttonLoading" v-loading="buttonLoading">
</el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listPendingAction,
getPendingAction,
delPendingAction,
addPendingAction,
updatePendingAction,
startProcess,
cancelAction,
restorePendingAction,
} from '@/api/wms/pendingAction';
import { listUser } from '@/api/system/user';
import CoilSelector from '@/components/CoilSelector';
import CoilNo from '@/components/KLPService/Renderer/CoilNo.vue';
export default {
name: 'CoilActflow',
dicts: ['action_type'],
components: {
CoilSelector,
CoilNo
},
data() {
return {
// 遮罩层
loading: true,
buttonLoading: false,
rubbish: false,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 待操作列表数据
actionList: [],
// 弹出层标题
title: '',
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 20,
currentCoilNo: null,
actionType: null,
actionStatus: null, // 默认查询待处理
priority: null
},
// 表单参数
form: {},
// 表单校验
rules: {
coilId: [
{ required: true, message: '请选择钢卷', trigger: 'blur' }
],
actionType: [
{ required: true, message: '请选择操作类型', trigger: 'change' }
]
},
// 钢卷选择器可见性
coilSelectorVisible: false,
// 用户列表
userList: [],
};
},
computed: {
// 分条操作列表100-199
splitTypes() {
if (!this.dict.type.action_type) return [];
return this.dict.type.action_type.filter(item => {
const value = parseInt(item.value);
return value >= 100 && value <= 199;
});
},
// 合卷操作列表200-299
mergeTypes() {
if (!this.dict.type.action_type) return [];
return this.dict.type.action_type.filter(item => {
const value = parseInt(item.value);
return value >= 200 && value <= 299;
});
},
// 其他操作列表200-299等
otherTypes() {
if (!this.dict.type.action_type) return [];
return this.dict.type.action_type.filter(item => {
const value = parseInt(item.value);
return value < 100 || value > 299;
});
}
},
created() {
this.getList();
// 设置定时刷新(可选,用于移动端扫码后自动刷新)
this.startAutoRefresh();
// 查询用户列表
this.getUserList();
},
beforeDestroy() {
// 清除定时器
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
}
},
methods: {
/** 查询待操作列表 */
getList() {
this.loading = true;
this.buttonLoading = true;
const payload = {
...this.queryParams,
includeDeleted: this.rubbish ? 2 : 0
}
listPendingAction(payload).then(response => {
console.log('response.rows', response.rows);
this.actionList = response.rows;
this.total = response.total;
this.buttonLoading = false;
this.loading = false;
});
},
/** 查询用户列表 */
getUserList() {
listUser({ pageSize: 9999 }).then(response => {
this.userList = response.rows;
});
},
switchActionStatus(value) {
console.log(value)
if (!value) {
this.queryParams.actionStatus = null;
} else {
this.queryParams.actionStatus = '-1';
}
this.getList()
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
actionId: null,
coilId: null,
currentCoilNo: null,
actionType: null,
actionStatus: null,
priority: 0,
sourceType: 'manual',
remark: null
};
this.resetForm('form');
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm('queryForm');
this.handleQuery();
},
handleStatusChange(row) {
// console.log(row)
updatePendingAction(row).then(response => {
this.$message.success('操作状态更新成功');
this.getList();
});
},
/** 还原按钮操作 */
handleRestore(row) {
const actionId = row.actionId;
this.$modal.confirm('是否确认还原该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
restorePendingAction(actionId).then(response => {
this.$message.success('还原成功');
this.getList();
});
});
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.actionId);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = '添加待操作';
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const actionId = row.actionId || this.ids;
getPendingAction(actionId).then(response => {
this.form = response.data;
this.open = true;
this.title = '修改待操作';
});
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (valid) {
this.buttonLoading = true;
if (this.form.actionId != null) {
updatePendingAction(this.form).then(response => {
this.$message.success('修改成功');
this.open = false;
this.getList();
this.buttonLoading = false;
});
} else {
addPendingAction(this.form).then(response => {
this.$message.success('新增成功');
this.open = false;
this.getList();
this.buttonLoading = false;
});
}
}
});
},
/** 完成时间改变时触发 */
handleProcessTimeChange(row) {
console.log('完成时间改变:', row);
updatePendingAction(row).then(response => {
this.$message.success('更新成功');
});
},
/** 删除按钮操作 */
handleDelete(row) {
const actionIds = row.actionId || this.ids;
this.$confirm('是否确认删除该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delPendingAction(actionIds);
}).then(() => {
this.getList();
this.$message.success('删除成功');
}).catch(() => { });
},
/** 处理操作 - 跳转到对应页面 */
handleProcess(row) {
console.log('=== 开始处理操作 ===');
console.log('待操作记录:', row);
console.log('操作类型:', row.actionType);
console.log('钢卷ID:', row.coilId);
this.buttonLoading = true;
this.$forceUpdate();
const actionType = parseInt(row.actionType);
// 特殊处理:发货和移库操作不需要跳转
if (actionType === 4 || actionType === 5 || actionType === 401 || actionType === 402) {
this.$message.info(actionType === 4 ? '发货操作已在移动端完成' : '移库操作已在移动端完成');
this.buttonLoading = false;
return;
}
// 根据操作类型跳转到不同页面
let path = '';
// 分条操作100-199
if (actionType >= 100 && actionType <= 199) {
path = '/wms/split';
}
// 合卷操作200-299
else if (actionType == 200) {
path = '/wms/merge';
}
else if (actionType < 100) {
path = '/wms/typing';
}
// 其他操作类型
else {
this.$message.error('特殊操作请到专门的页面进行处理');
this.buttonLoading = false;
return;
}
if (!path) {
this.$message.error('未知的操作类型: ' + row.actionType);
this.buttonLoading = false;
return;
}
// 更新状态为处理中
console.log('调用startProcessactionId:', row.actionId);
startProcess(row.actionId).then(response => {
console.log('开始处理响应:', response);
if (response.code !== 200) {
this.$message.error(response.msg || '更新状态失败');
return;
}
// 跳转并传递参数
console.log('准备跳转到:', path, '参数:', { coilId: row.coilId, actionId: row.actionId });
this.$router.push({
path: path,
query: {
coilId: row.coilId,
actionId: row.actionId
}
});
this.buttonLoading = false;
}).catch(error => {
console.error('更新状态失败:', error);
this.$message.error('更新状态失败: ' + (error.message || error));
}).finally(() => {
this.buttonLoading = false;
});
},
/** 取消操作 */
handleCancel(row) {
this.$confirm('是否确认取消该操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return cancelAction(row.actionId);
}).then(() => {
this.$message.success('操作已取消');
this.getList();
}).catch(() => { });
},
/** 刷新列表 */
handleRefresh() {
this.getList();
this.$message.success('刷新成功');
},
/** 自动刷新 */
startAutoRefresh() {
// 每30秒自动刷新一次用于移动端扫码后自动更新列表
this.refreshTimer = setInterval(() => {
// 只在查看待处理状态时自动刷新
this.getList();
}, 30000);
},
/** 表格行样式 */
tableRowClassName({ row }) {
if (row.priority === 2) {
return 'urgent-row';
} else if (row.priority === 1) {
return 'important-row';
}
return '';
},
/** 显示钢卷选择器 */
showCoilSelector() {
this.coilSelectorVisible = true;
},
/** 钢卷选择回调 */
handleCoilSelect(coil) {
this.form.coilId = coil.coilId;
this.form.currentCoilNo = coil.currentCoilNo;
},
/** 获取状态文本 */
getStatusText(status) {
const statusMap = {
0: '待处理',
1: '处理中',
2: '已完成',
3: '已取消'
};
return statusMap[status] || '未知';
},
/** 根据操作类型获取图标 */
getActionIcon(actionType) {
const value = parseInt(actionType);
const iconMap = {
1: 'el-icon-connection', // 合卷
2: 'el-icon-s-operation', // 分条
3: 'el-icon-edit', // 更新
4: 'el-icon-truck', // 发货
5: 'el-icon-s-grid', // 移库
101: 'el-icon-scissors', // 纵剪分条
102: 'el-icon-s-operation', // 横切分条
103: 'el-icon-s-unfold' // 开卷分条
};
return iconMap[value] || 'el-icon-s-operation';
}
}
};
</script>
<style scoped lang="scss">
.app-container {
::v-deep .urgent-row {
background: #fef0f0 !important;
}
::v-deep .important-row {
background: #fdf6ec !important;
}
// 优化按钮文字颜色
// 实心按钮:白色文字(在深色背景上清晰可见)
::v-deep .el-button--primary.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--danger.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--warning.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--info.el-button--mini:not(.is-plain) {
color: #fff;
}
::v-deep .el-button--success.el-button--mini:not(.is-plain) {
color: #fff;
}
// plain按钮同色系深色文字在浅色背景上
::v-deep .el-button--primary.el-button--mini.is-plain {
color: #409eff;
}
::v-deep .el-button--danger.el-button--mini.is-plain {
color: #f56c6c;
}
::v-deep .el-button--warning.el-button--mini.is-plain {
color: #e6a23c;
}
}
/* 操作类型卡片样式 */
.action-type-cards {
width: 100%;
.card-section {
margin-bottom: 24px;
&:last-child {
margin-bottom: 0;
}
}
.section-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-left: 8px;
border-left: 3px solid #409eff;
}
// 分条操作区域的特殊样式
.card-section:first-child .section-title {
border-left-color: #e6a23c;
}
.action-cards-row {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 12px;
}
.action-card {
min-width: 0;
padding: 16px;
border: 2px solid #dcdfe6;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s ease;
background: #fff;
display: flex;
align-items: center;
gap: 12px;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.15);
transform: translateY(-2px);
}
&.active {
border-color: #409eff;
background: linear-gradient(135deg, #e3f2fd 0%, #f0f7ff 100%);
box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.3);
.card-icon {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
color: #fff;
}
.card-title {
color: #409eff;
font-weight: 600;
}
}
&.split-card {
&.active {
background: linear-gradient(135deg, #fff3e0 0%, #fff8f0 100%);
border-color: #e6a23c;
.card-icon {
background: linear-gradient(135deg, #e6a23c 0%, #f0ad4e 100%);
}
.card-title {
color: #e6a23c;
}
}
&:hover {
border-color: #e6a23c;
box-shadow: 0 2px 12px 0 rgba(230, 162, 60, 0.15);
}
}
}
.card-icon {
width: 48px;
height: 48px;
border-radius: 8px;
background: #f5f7fa;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: #909399;
transition: all 0.3s ease;
flex-shrink: 0;
}
.card-content {
flex: 1;
}
.card-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 4px;
transition: all 0.3s ease;
}
.card-desc {
font-size: 13px;
color: #909399;
line-height: 1.4;
}
}
</style>