fix:荧光线人家交互页面优化

This commit is contained in:
17630416519 2026-01-05 17:34:52 +08:00
parent 2733cb9aac
commit 9438e78e90
4 changed files with 626 additions and 226 deletions

View File

@ -3,8 +3,8 @@ import request from '@/utils/request'
export function getProcessInfoTree(data) {
return request({
url: 'mes/WorkOrder/queryWorkOrderToDay',
method: 'get',
params: data
method: 'post',
data: data
})
}
@ -39,4 +39,22 @@ export function getLineName() {
url: 'MasterDataManagement/Plant/PlantProductlinebody/getAllLine',
method: 'get'
})
}
//不良原因下拉
export function getReason() {
return request({
url: 'mes/QualityDefectReason/getQualityDefectReason',
method: 'post'
})
}
//主表列表
export function getProcessInfoList(data) {
return request({
url: 'mes/WorkOrder/createWorkOrderBySacnCode',
method: 'post',
data: data
})
}

View File

@ -357,7 +357,6 @@ function handleQuery() {
checkDate: theSameDayTime.value
}
checkFirstInspection(params).then(res => {
console.log(res, 'res的值');
if (res.code == 400) {
ElMessage.error(res.msg);
return

View File

@ -1,20 +1,47 @@
<template>
<div class="work-order-page">
<el-row :gutter="20">
<el-row :gutter="20" class="main-row">
<el-col :span="5">
<div class="order-list">
<h3>今日工单列表</h3>
<ul>
<li v-for="(order, index) in orders" style="position: relative;"
@click="onHandleOrderClick(order)" :key="index" :class="{ active: order.active }">
<span>{{ order.workOrderCode }}</span>
<div style="color: #666;font-size: 12px;">
<span>{{ order.lineName }}</span>
<span style="margin-left: 20px;">数量:{{ order.totalQty }}</span>
<div class="select-line">
<el-select
style="width: 100%;"
filterable
clearable
@change="handleSelectLineNameLeft"
v-model="lineNameLeft"
placeholder="请选择产线"
size="default"
>
<el-option
v-for="item in productionLine"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<h3 class="order-list-title">今日工单列表</h3>
<ul class="order-list-container">
<li
v-for="(order, index) in orders"
style="position: relative;"
@click="onHandleOrderClick(order)"
:key="index"
:class="{ active: order.active }"
class="order-item"
>
<div class="order-code">{{ order.workOrderCode }}</div>
<div class="order-details">
<span class="line-name">{{ order.lineName }}</span>
<span class="order-quantity">数量: {{ order.totalQty }}</span>
</div>
<span style="position: absolute; right: 5%; top:35%"
:class="getOrderStatusClass(order.orderStatus)">{{
getOrderStatusText(order.orderStatus) }}</span>
<span
class="order-status"
:class="getOrderStatusClass(order.orderStatus)"
>
{{ getOrderStatusText(order.orderStatus) }}
</span>
</li>
</ul>
</div>
@ -22,89 +49,171 @@
<el-col :span="15">
<div class="main-content">
<h2>工单号: {{ currentOrder.workOrderCode }}</h2>
<div class="product-info">
<div class="info-item">
<span>产线编号:</span>
<span>{{ currentOrder.lineCode }}</span>
<div class="content-header">
<h2 class="work-order-title">工单号: {{ currentOrder.workOrderCode }}</h2>
<div class="order-status-badge" :class="getOrderStatusClass(currentOrder.orderStatus)">
{{ getOrderStatusText(currentOrder.orderStatus) }}
</div>
<div class="info-item">
<span>产线名称:</span>
<span>{{ currentOrder.lineName }}</span>
</div>
<div class="info-section">
<div class="info-grid">
<div class="info-card">
<div class="info-label">产线编号</div>
<div class="info-value">{{ currentOrder.lineCode }}</div>
</div>
<div class="info-card">
<div class="info-label">产线名称</div>
<div class="info-value">{{ currentOrder.lineName }}</div>
</div>
<div class="info-card">
<div class="info-label">工艺路线编码</div>
<div class="info-value">{{ currentOrder.processCode }}</div>
</div>
<div class="info-card">
<div class="info-label">工艺路线名称</div>
<div class="info-value">{{ currentOrder.processName }}</div>
</div>
</div>
<div class="info-item">
<span>工艺路线编码:</span>
<span>{{ currentOrder.processCode }}</span>
</div>
<div class="info-item">
<span>工艺路线名称:</span>
<span>{{ currentOrder.processName }}</span>
<div class="info-grid">
<div class="info-card">
<div class="info-label">工单日期</div>
<div class="info-value">{{ currentOrder.orderDate }}</div>
</div>
<div class="info-card">
<div class="info-label">零件编码</div>
<div class="info-value">{{ currentOrder.materialCode }}</div>
</div>
<div class="info-card">
<div class="info-label">工单状态</div>
<div class="info-value status-value" :class="getOrderStatusClass(currentOrder.orderStatus)">
{{ getOrderStatusText(currentOrder.orderStatus) }}
</div>
</div>
<div class="info-card">
<div class="info-label">零件名称</div>
<div class="info-value">{{ currentOrder.materialName }}</div>
</div>
</div>
</div>
<div class="order-data">
<div class="data-item">
<span>工单日期:</span>
<span>{{ currentOrder.orderDate }}</span>
</div>
<div class="data-item">
<span>零件编码:</span>
<span>{{ currentOrder.materialCode }}</span>
</div>
<div class="data-item">
<span>工单状态:</span>
<span :class="getOrderStatusClass(currentOrder.orderStatus)">{{
getOrderStatusText(currentOrder.orderStatus)
}}</span>
</div>
<div class="data-item">
<span>零件名称:</span>
<span>{{ currentOrder.materialName }}</span>
</div>
</div>
<div class="remark">
<p>{{ currentOrder.remark }}</p>
<div class="remark-section">
<div class="remark-label">备注信息</div>
<div class="remark-content">{{ currentOrder.remark || '暂无备注' }}</div>
</div>
<div class="input-section">
<div class="input-group">
<label>合格数</label>
<input v-model.number="currentOrder.okQty" type="number" />
</div>
<div class="input-group">
<label>不合格数</label>
<input min="0" v-model.number="currentOrder.ngQty" type="number" />
</div>
<div class="input-group">
<label>不良原因</label>
<textarea min="0" v-model="currentOrder.defectReason" placeholder="请输入不良原因"></textarea>
<h3 class="section-title">质量检验</h3>
<div class="input-grid">
<div class="input-group">
<label class="input-label">合格数</label>
<el-input
v-model.number="currentOrder.okQty"
type="number"
:min="0"
placeholder="请输入合格数量"
class="input-field"
/>
</div>
<div class="input-group">
<label class="input-label">不合格数</label>
<el-input
v-model.number="currentOrder.ngQty"
type="number"
:min="0"
placeholder="请输入不合格数量"
class="input-field"
/>
</div>
<div class="input-group">
<label class="input-label">不良原因</label>
<el-select
v-model="currentOrder.defectReason"
placeholder="请选择不良原因"
class="input-field"
>
<el-option
v-for="item in defectReason"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</div>
<div class="button-group">
<el-button @click="save">保存</el-button>
<el-button type="primary" @click="completeOrder">工单完工</el-button>
<el-button
type="success"
@click="save"
:disabled="!currentOrder.workOrderCode"
class="action-btn"
>
<el-icon><DocumentChecked /></el-icon>
保存成品检验
</el-button>
<el-button
type="primary"
@click="completeOrder"
:disabled="!currentOrder.workOrderCode || currentOrder.orderStatus === '2'"
class="action-btn"
>
<el-icon><Finished /></el-icon>
工单完工
</el-button>
<el-button
type="warning"
@click="handleClick"
:disabled="!currentOrder.workOrderCode"
class="action-btn"
>
<el-icon><Lightning /></el-icon>
首检
</el-button>
</div>
</div>
</el-col>
<el-col :span="4">
<div class="scan-area">
<h3>标签扫描</h3>
<el-form label-width="70px">
<el-form-item label="选择产线">
<el-select filterable clearable @change="handleSelectLineName" v-model="lineName"
placeholder="请选择产线">
<el-option v-for="item in productionLine" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="扫码结果">
<el-input @keyup.enter="handleQuery" placeholder="请扫描或输入"
v-model="tagNumber"></el-input>
</el-form-item>
</el-form>
<h3 class="scan-title">标签扫描</h3>
<el-form label-width="80px" class="scan-form">
<el-form-item label="选择产线">
<el-select
filterable
clearable
@change="handleSelectLineName"
v-model="lineName"
placeholder="请选择产线"
size="default"
class="scan-input"
>
<el-option
v-for="item in productionLine"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="扫码结果">
<el-input
@keyup.enter="handleQuery"
placeholder="请扫描或输入"
v-model="tagNumber"
class="scan-input"
>
<template #suffix>
<el-icon @click="handleQuery"><Search /></el-icon>
</template>
</el-input>
</el-form-item>
</el-form>
<div class="scan-instruction">
<p>提示扫描或输入标签编号进行操作</p>
</div>
</div>
</el-col>
</el-row>
@ -112,15 +221,25 @@
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { getProcessInfoTree, updateProcessInfo, updateProcessInfoList, checkFirstInspection, getLineName } from '@/api/humanComputerInteraction/index.js';
import { ref, computed } from 'vue';
import { getProcessInfoTree, updateProcessInfo, updateProcessInfoList, checkFirstInspection, getLineName, getReason, getProcessInfoList } from '@/api/humanComputerInteraction/index.js';
import { ElMessage } from 'element-plus';
const productionLine = ref([])
const tagNumber = ref('');
import useUserStore from '@/store/modules/user'
import { DocumentChecked, Finished, Lightning, Search } from '@element-plus/icons-vue'
import { dayjs } from 'element-plus';
const orders = ref([
]);
const lineName = ref('');
const userStore = useUserStore()
const userId = userStore.userId
const userName = userStore.userName
const productionLine = ref([])
const loading = ref(false)
const tagNumber = ref('');
const orders = ref([]);
const lineName = ref('');
const lineNameLeft = ref('')
const total = ref(0)
//
const currentOrder = ref({
workOrderCode: '',//
@ -131,8 +250,8 @@ const currentOrder = ref({
orderDate: '',//
materialCode: '',//
materialName: '',//
okQty: '',//
ngQty: '',//
okQty: 0,//
ngQty: 0,//
defectReason: '',//
totalQty: '',//
orderStatus: '',//
@ -141,13 +260,17 @@ const currentOrder = ref({
});
const getLeftTreeList = () => {
getProcessInfoTree().then(res => {
let params = {
lineCode: ''
}
getProcessInfoTree(params).then(res => {
if (res.code == 200) {
orders.value = res.data
}
})
}
getLeftTreeList()
const getLineNameData = () => {
getLineName().then(res => {
if (res.code == 200) {
@ -161,23 +284,46 @@ const getLineNameData = () => {
})
}
getLineNameData()
const getOrderStatusClass = (status) => {
const statusClassMap = {
'0': 'pending',
'1': 'processing',
'2': 'completed'
'0': 'status-pending',
'1': 'status-processing',
'2': 'status-completed'
};
return statusClassMap[status] || '';
return statusClassMap[status] || 'status-unknown';
};
const selectedItemValue = ref('')
const handleSelectLineName = (val) => {
const selectedItem = productionLine.value.find(item => item.value === val);
if (selectedItem) {
selectedItemValue.value = selectedItem.label;
}
};
const handleSelectLineNameLeft = (val) => {
let params = {
lineCode: val
}
getProcessInfoTree(params).then(res => {
if (res.code == 200) {
orders.value = res.data
}
})
}
const getOrderStatusText = (status) => {
const statusMap = {
'0': '待执行',
'1': '执行中',
'2': '已完成'
};
return statusMap[status] || '';
return statusMap[status] || '未知';
};
const isWhiteText = ref(false)
const defectReasonData = ref([])
const onHandleOrderClick = (val) => {
isWhiteText.value = true
orders.value.forEach(order => {
@ -187,6 +333,11 @@ const onHandleOrderClick = (val) => {
currentOrder.value = {
...val
}
getReason().then(res => {
if (res.code == 200) {
defectReasonData.value = res.data.result
}
})
}
const handleQuery = () => {
@ -194,22 +345,52 @@ const handleQuery = () => {
ElMessage.error('请选择产线名称');
return;
}
let params={
lineCode:lineName.value,
checkDate:dayjs(new Date()).format('YYYY-MM-DD'),
let params = {
lineCode: lineName.value,
checkDate: dayjs(new Date()).format('YYYY-MM-DD'),
}
checkFirstInspection(params).then(res => {
checkFirstInspection(params).then(res => {
if (res.code == 400) {
ElMessage.error(res.msg);
return
}
if(res && res.code == 200){
ElMessage.error(res.msg);
return
}
if (res && res.code == 200) {
ElMessage.success('请求成功!');
let data = {
FlowCardNo: tagNumber.value,
LineCode: lineName.value,
LineName: selectedItemValue.value,
ProcessCode: '',
ProcessName: '',
MaterialCode: "MAT-2025-ASM-002",
MaterialName: "智能手机整机套件",
TotalQty: 300,
BatchNumber: "BATCH-20251121-002",
UserId: userId,
UserName: userName
};
getProcessInfoList(data).then(res => {
loading.value = false;
if (res && res.code == 200) {
getLeftTreeList()
} else {
total.value = 0;
}
}).catch(err => {
loading.value = false;
console.error('获取工艺信息列表失败:', err);
total.value = 0;
});
}
})
}
//
const save = () => {
if (!currentOrder.value.workOrderCode) {
ElMessage.warning('请先选择一个工单');
return;
}
updateProcessInfo(currentOrder.value).then(res => {
if (res.code == 200) {
ElMessage.success('保存成功')
@ -217,18 +398,31 @@ const save = () => {
})
};
const handleClick = () => {
if (!currentOrder.value.workOrderCode) {
ElMessage.warning('请先选择一个工单');
return;
}
ElMessage.info('首检功能正在开发中');
};
const completeOrder = () => {
if (!currentOrder.value.workOrderCode) {
ElMessage.warning('请先选择一个工单');
return;
}
if (currentOrder.value.orderStatus == '2') {
ElMessage.warning('工单已完工,请勿重复操作')
return;
}
let data = {
...currentOrder.value,
orderStatus: currentOrder.value.orderStatus = '2'
orderStatus: '2'
}
updateProcessInfoList(data).then(res => {
if (res.code == 200) {
ElMessage.success('状态修改完成')
getLeftTreeList()
}
})
};
@ -236,174 +430,363 @@ const completeOrder = () => {
<style scoped>
.work-order-page {
padding: 20px;
padding: 10px;
height: 100%;
background-color: #f5f5f5;
background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
/* min-height: 100vh; */
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.top-bar {
.main-row {
margin: 0 !important;
}
/* 左侧工单列表样式 */
.order-list {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
height: calc(88vh - 40px);
display: flex;
flex-direction: column;
}
.select-line {
margin-bottom: 16px;
}
.order-list-title {
margin: 0 0 16px 0;
color: white;
background: linear-gradient(135deg, #409EFF 0%, #0066CC 100%);
padding: 12px;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
text-align: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.order-list-container {
list-style: none;
padding: 0;
margin: 0;
flex: 1;
overflow-y: auto;
}
.order-item {
padding: 12px;
border-bottom: 1px solid #eee;
cursor: pointer;
border-radius: 8px;
margin-bottom: 8px;
transition: all 0.3s ease;
position: relative;
background: #fafafa;
}
.order-item:hover {
background-color: #e3f2fd;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.order-item.active {
background: linear-gradient(135deg, #409EFF 0%, #0066CC 100%);
color: white !important;
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
}
.order-code {
font-weight: 600;
font-size: 14px;
margin-bottom: 4px;
color: #333;
}
.order-item.active .order-code {
color: white;
}
.order-details {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #666;
margin-top: 5px;
}
.order-item.active .order-details {
color: rgba(255, 255, 255, 0.8);
}
.order-status {
position: absolute;
right: 8px;
top: 35%;
transform: translateY(-50%);
padding: 4px 8px;
border-radius: 12px;
font-size: 11px;
font-weight: 500;
}
/* 主内容区域样式 */
.main-content {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
height: calc(88vh - 40px);
display: flex;
flex-direction: column;
overflow-y: auto;
}
.content-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
font-size: 14px;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 1px solid #eee;
}
.time {
.work-order-title {
margin: 0;
color: #333;
font-size: 20px;
font-weight: 600;
}
.order-status-badge {
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
color: white;
background-color: #ccc;
}
.status-pending {
background-color: #F56C6C;
}
.status-processing {
background-color: #409EFF;
}
.status-completed {
background-color: #67C23A;
}
.info-section {
margin-bottom: 24px;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
margin-bottom: 16px;
}
.info-card {
background: #f8f9fa;
border-radius: 8px;
padding: 16px;
border-left: 4px solid #409EFF;
transition: transform 0.2s ease;
}
.info-card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.info-label {
font-size: 12px;
color: #666;
margin-bottom: 4px;
}
.pending {
color: #999999;
.info-value {
font-size: 14px;
font-weight: 500;
color: #333;
}
.processing {
.status-value.status-pending {
color: #F56C6C;
}
.status-value.status-processing {
color: #409EFF;
}
.completed {
color: #4caf50;
.status-value.status-completed {
color: #67C23A;
}
.order-list {
background: white;
.remark-section {
background: #f8f9fa;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 24px;
}
.order-list h3 {
margin-top: 0;
color: white;
background-color: #409EFF;
padding: 8px;
border-radius: 4px;
.remark-label {
font-size: 14px;
}
.order-list ul {
list-style: none;
padding: 0;
margin: 10px 0;
}
.order-list li {
padding: 8px;
border-bottom: 1px solid #eee;
cursor: pointer;
}
.order-list li:hover {
background-color: #f0f0f0;
}
.order-list li.active {
background-color: #f0f0f0;
color: #000 !important;
}
.order-list .status {
float: right;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
}
.white-text {
color: white;
}
.main-content {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.main-content h2 {
margin-top: 0;
font-weight: 600;
color: #333;
font-size: 18px;
}
.info-item,
.data-item {
display: flex;
margin-bottom: 8px;
}
.info-item span:first-child,
.data-item span:first-child {
width: 100px;
font-weight: bold;
.remark-content {
padding: 12px;
background: white;
border-radius: 6px;
border: 1px solid #eee;
color: #666;
}
.info-item span:last-child,
.data-item span:last-child {
flex: 1;
}
.normal {
color: #4caf50;
}
.remark {
margin: 20px 0;
padding: 10px;
background-color: #f9f9f9;
border-radius: 4px;
font-size: 12px;
line-height: 1.5;
min-height: 40px;
}
.input-section {
margin: 20px 0;
margin-bottom: 24px;
}
.section-title {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #333;
padding-bottom: 8px;
border-bottom: 2px solid #409EFF;
}
.input-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
}
.input-group {
margin-bottom: 16px;
}
.input-group label {
.input-label {
display: block;
margin-bottom: 8px;
font-weight: bold;
font-weight: 500;
color: #333;
font-size: 14px;
}
.input-group input,
.input-group textarea {
.input-field {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.button-group {
display: flex;
gap: 16px;
margin-top: 20px;
flex-wrap: wrap;
}
.action-btn {
flex: 1;
min-width: 120px;
height: 44px;
border-radius: 8px;
font-weight: 500;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 右侧扫描区域样式 */
.scan-area {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
text-align: center;
border-radius: 12px;
padding: 24px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
height: calc(88vh - 40px);
display: flex;
flex-direction: column;
}
.scan-area h3 {
margin-top: 0;
.scan-title {
margin: 0 0 20px 0;
color: #333;
font-size: 18px;
font-weight: 600;
text-align: center;
padding-bottom: 12px;
border-bottom: 2px solid #409EFF;
}
.scan-box {
.scan-form {
flex: 1;
}
.scan-input {
width: 100%;
height: 100px;
background-color: #409EFF;
margin-top: 16px;
border-radius: 4px;
}
.scan-instruction {
margin-top: auto;
padding: 16px;
background: #f8f9fa;
border-radius: 8px;
border: 1px dashed #ccc;
}
.scan-instruction p {
margin: 0;
text-align: center;
color: #666;
font-size: 13px;
}
/* 响应式设计 */
@media (max-width: 1400px) {
.info-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 1200px) {
.input-grid {
grid-template-columns: 1fr;
}
}
/* 滚动条样式 */
.order-list-container::-webkit-scrollbar {
width: 6px;
}
.order-list-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.order-list-container::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 10px;
}
.order-list-container::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* 动画效果 */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.order-item {
animation: fadeIn 0.3s ease-out;
}
</style>

View File

@ -127,7 +127,7 @@ import {
listProcessOperationTransition,
addProcessOperationTransition, delProcessOperationTransition,
updateProcessOperationTransition, getProcessOperationTransition,
getProcessOperationTransitionSelect
// getProcessOperationTransitionSelect
}
from '@/api/masterDataManagement/process/processoperationtransition.js'
import useUserStore from '@/store/modules/user'
@ -176,17 +176,17 @@ function getList() {
loading.value = false
}
})
getProcessOperationTransitionSelect().then(res => {
console.log(res,'下拉的值');
if(res.code == 200){
options.value.transitionTypeOptions=res.data.map(item=>{
return {
dictValue: item.transitionCode,
dictLabel: item.transtionName
}
})
}
})
// getProcessOperationTransitionSelect().then(res => {
// console.log(res,'');
// if(res.code == 200){
// options.value.transitionTypeOptions=res.data.map(item=>{
// return {
// dictValue: item.transitionCode,
// dictLabel: item.transtionName
// }
// })
// }
// })
}
//