Files
klp-mono/apps/hand-factory/pages/easycode/easycode.vue
2025-11-11 14:26:12 +08:00

839 lines
21 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
<view class="container">
<!-- 分条操作区 -->
<view class="section-card split-section">
<view class="section-title">
<text class="title-icon"></text>
<text class="title-text">分条操作</text>
</view>
<view class="btn-grid">
<button
v-for='item in splitTypes'
:key="item.dictValue"
@click="handleScan(item.dictValue)"
class="type-btn split-btn">
{{ item.dictLabel }}
</button>
</view>
</view>
<!-- 其他操作区 -->
<view class="section-card other-section">
<view class="section-title">
<text class="title-icon">🔧</text>
<text class="title-text">其他操作</text>
</view>
<view class="btn-grid">
<button
v-for='item in otherTypes'
:key="item.dictValue"
@click="handleScan(item.dictValue)"
class="type-btn other-btn">
{{ item.dictLabel }}
</button>
</view>
</view>
<!-- 快捷操作区 -->
<view class="section-card quick-section">
<view class="section-title">
<text class="title-icon"></text>
<text class="title-text">快捷操作</text>
</view>
<view class="btn-grid quick-grid">
<!-- <button class="type-btn move-btn" @click="handleTranfer">移库</button> -->
<button class="type-btn ship-btn" @click="handleShip">发货</button>
</view>
</view>
<uni-popup ref="tranferPopup" type="bottom">
<view style="background-color: white;">
<view class="info-card" v-if="form.coilId">
<view class="card-title">
<text class="title-dot"></text>
<text class="title-text">原钢卷信息</text>
<view class="more-btn" @click.stop="showBomDialog"
v-if="coilDetail.bomItemList && coilDetail.bomItemList.length > 0">
<text class="icon-more"></text>
<text class="more-text">参数</text>
</view>
</view>
<view class="info-grid">
<view class="info-item">
<text class="item-label">入场钢卷号</text>
<text class="item-value">{{ coilDetail.enterCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">当前钢卷号</text>
<text class="item-value">{{ coilDetail.currentCoilNo || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">当前库区</text>
<text class="item-value">{{ coilDetail.actualWarehouseName }}</text>
</view>
</view>
</view>
<view class="form-card" v-if="form.coilId">
<view class="form-item form-item-optional">
<text class="form-label-optional">真实库区</text>
<klp-warehouse-picker v-model="form.actualWarehouseId" :disabled="coilDetail.dataType === 0"
placeholder="请选择目标库区" ware-type="actual" />
</view>
<view class="action-buttons">
<button class="btn btn-secondary" @click="handleReScan">重新扫码</button>
<button v-if="coilDetail.dataType === 1" class="btn btn-primary" @click="handleConfirm" :disabled="loading">
{{ loading ? '提交中...' : '保存' }}
</button>
</view>
</view>
</view>
</uni-popup>
<!-- 退出登录按钮固定在底部 -->
<view class="logout-container">
<button @click='handleLogout' class="logout-btn">
退出登录
</button>
</view>
</view>
</template>
<script>
import {
getDicts
} from '@/api/system/dict/data.js'
import {
getGenerateRecord
} from '@/api/wms/code.js'
import {
getMaterialCoil,
updateMaterialCoilSimple
} from '@/api/wms/coil.js'
import {
addPendingAction
} from '@/api/wms/pendingAction.js'
export default {
data() {
return {
types: [],
loading: false,
coilDetail: {},
form: {}
}
},
computed: {
// 分条操作列表100-199
splitTypes() {
return this.types.filter(item => {
const value = parseInt(item.dictValue);
return value >= 100 && value <= 199;
});
},
// 其他操作列表200-299等
otherTypes() {
return this.types.filter(item => {
const value = parseInt(item.dictValue);
return value < 100 || value > 199;
});
}
},
methods: {
handleLogout() {
this.$modal.confirm('确定注销并退出系统吗?').then(() => {
this.$store.dispatch('LogOut').then(() => {}).finally(() => {
this.$tab.reLaunch('/pages/login')
})
})
},
// 扫码并创建待操作
handleScan(actionType) {
uni.scanCode({
success: async (res) => {
console.log('=== 开始扫码流程 ===');
console.log('扫码结果:', res.result);
console.log('操作类型:', actionType);
uni.showLoading({
title: '处理中...'
});
try {
const qrcodeId = res.result;
// 1. 通过二维码ID获取二维码详情
console.log('1. 获取二维码详情ID:', qrcodeId);
const qrcodeRes = await getGenerateRecord(qrcodeId);
console.log('二维码响应:', qrcodeRes);
if (qrcodeRes.code !== 200) {
throw new Error('未找到二维码记录');
}
// 2. 解析二维码的content获取coil_id
const qrcodeRecord = qrcodeRes.data;
console.log('2. 二维码记录:', qrcodeRecord);
// 检查二维码状态0=失效1=有效)
if (qrcodeRecord.status === 0) {
uni.hideLoading();
uni.showModal({
title: '提示',
content: '该二维码已失效,无法创建待操作任务',
showCancel: false
});
return;
}
const content = JSON.parse(qrcodeRecord.content);
console.log('解析后的内容:', content);
// 优先使用current_coil_id当前有效的钢卷ID如果没有则使用coil_id兼容旧数据
let coilId = content.current_coil_id && content.current_coil_id !== 'null' ? content
.current_coil_id : null;
if (!coilId) {
coilId = content.coil_id && content.coil_id !== 'null' ? content.coil_id : null;
}
console.log('提取钢卷ID - current_coil_id:', content.current_coil_id, 'coil_id:', content.coil_id,
'最终使用:', coilId);
if (!coilId) {
throw new Error('二维码中未包含有效的钢卷ID');
}
// 3. 直接通过钢卷ID获取钢卷详情
console.log('3. 获取钢卷详情钢卷ID:', coilId);
const coilRes = await getMaterialCoil(coilId);
console.log('钢卷详情响应:', coilRes);
if (coilRes.code !== 200) {
throw new Error(coilRes.msg || '查询钢卷信息失败');
}
if (!coilRes.data) {
throw new Error('未找到钢卷信息');
}
const coilData = coilRes.data;
console.log('4. 钢卷数据:', coilData);
// 4. 创建待操作记录
const pendingData = {
coilId: coilData.coilId,
currentCoilNo: coilData.currentCoilNo,
actionType: parseInt(actionType),
actionStatus: 0, // 待处理
sourceType: 'scan', // 扫码来源
scanTime: new Date().toISOString(),
scanDevice: this.getDeviceInfo(),
warehouseId: coilData.warehouseId,
priority: 0, // 默认普通优先级
remark: `移动端扫码创建-${this.getActionTypeName(actionType)}`
};
console.log('5. 创建待操作记录,数据:', pendingData);
const addRes = await addPendingAction(pendingData);
console.log('创建待操作响应:', addRes);
if (addRes.code !== 200) {
throw new Error(addRes.msg || '创建待操作失败');
}
uni.hideLoading();
console.log('=== 扫码流程完成 ===');
uni.navigateTo({
url: '/pages/scansuccess/scansuccess'
})
// uni.showToast({
// title: '创建成功',
// icon: 'success',
// duration: 2000
// });
// // 延迟后返回或跳转
// setTimeout(() => {
// // 可以跳转到待操作列表或返回上一页
// uni.navigateBack();
// }, 2000);
} catch (err) {
console.error('=== 扫码处理失败 ===');
console.error('错误信息:', err);
console.error('错误堆栈:', err.stack);
uni.hideLoading();
uni.showToast({
title: err.message || '处理失败',
icon: 'none',
duration: 3000
});
}
},
fail: (err) => {
console.error('扫码失败:', err);
uni.showToast({
title: '扫码失败,请重试',
icon: 'none'
});
}
});
},
handleShip() {
uni.scanCode({
success: async (res) => {
console.log('=== 开始扫码流程 ===');
console.log('扫码结果:', res.result);
// console.log('操作类型:', actionType);
uni.showLoading({
title: '处理中...'
});
try {
const qrcodeId = res.result;
// 1. 通过二维码ID获取二维码详情
console.log('1. 获取二维码详情ID:', qrcodeId);
const qrcodeRes = await getGenerateRecord(qrcodeId);
console.log('二维码响应:', qrcodeRes);
if (qrcodeRes.code !== 200) {
throw new Error('未找到二维码记录');
}
// 2. 解析二维码的content获取coil_id
const qrcodeRecord = qrcodeRes.data;
console.log('2. 二维码记录:', qrcodeRecord);
// 检查二维码状态0=失效1=有效)
if (qrcodeRecord.status === 0) {
uni.hideLoading();
uni.showModal({
title: '提示',
content: '该二维码已失效,无法创建待操作任务',
showCancel: false
});
return;
}
const content = JSON.parse(qrcodeRecord.content);
console.log('解析后的内容:', content);
// 优先使用current_coil_id当前有效的钢卷ID如果没有则使用coil_id兼容旧数据
let coilId = content.current_coil_id && content.current_coil_id !== 'null' ? content
.current_coil_id : null;
if (!coilId) {
coilId = content.coil_id && content.coil_id !== 'null' ? content.coil_id : null;
}
console.log('提取钢卷ID - current_coil_id:', content.current_coil_id, 'coil_id:', content.coil_id,
'最终使用:', coilId);
if (!coilId) {
throw new Error('二维码中未包含有效的钢卷ID');
}
// 3. 直接通过钢卷ID获取钢卷详情
console.log('3. 获取钢卷详情钢卷ID:', coilId);
const coilRes = await getMaterialCoil(coilId);
console.log('钢卷详情响应:', coilRes);
if (coilRes.code !== 200) {
throw new Error(coilRes.msg || '查询钢卷信息失败');
}
if (!coilRes.data) {
throw new Error('未找到钢卷信息');
}
const coilData = coilRes.data;
if (coilRes.data.status == 1) {
uni.showToast({
title: '钢卷已经发货,无需再次发货'
})
return;
}
uni.showModal({
cancelText: '取消',
confirmText: '确认',
title: '确定要将钢卷号为:' + coilRes.data.currentCoilNo + '发货吗?',
showCancel: true,
success: async () => {
try {
// 1. 更新钢卷状态为已发货
await updateMaterialCoilSimple({
...coilRes.data,
status: 1,
});
// 2. 插入一条已完成的待操作记录
await addPendingAction({
coilId: coilRes.data.coilId,
currentCoilNo: coilRes.data.currentCoilNo,
actionType: 4, // 4=发货
actionStatus: 2, // 2=已完成
scanTime: new Date(),
scanDevice: this.getDeviceInfo(),
priority: 0, // 0=普通
sourceType: 'scan',
warehouseId: coilRes.data.warehouseId,
processTime: new Date(),
completeTime: new Date()
});
uni.showToast({
title: '发货成功',
icon: 'none'
});
} catch (error) {
console.error('发货失败:', error);
uni.showToast({
title: error.message || '发货失败',
icon: 'none'
});
}
},
fail() {
uni.showToast({
title: '已取消发货',
icon: 'none'
})
}
});
uni.hideLoading();
} catch (err) {
console.error('=== 扫码处理失败 ===');
console.error('错误信息:', err);
console.error('错误堆栈:', err.stack);
uni.hideLoading();
uni.showToast({
title: err.message || '处理失败',
icon: 'none',
duration: 3000
});
}
},
fail: (err) => {
console.error('扫码失败:', err);
uni.showToast({
title: '扫码失败,请重试',
icon: 'none'
});
}
});
},
handleTranfer() {
uni.scanCode({
success: async (res) => {
console.log('=== 开始扫码流程 ===');
console.log('扫码结果:', res.result);
// console.log('操作类型:', actionType);
uni.showLoading({
title: '处理中...'
});
try {
const qrcodeId = res.result;
// 1. 通过二维码ID获取二维码详情
console.log('1. 获取二维码详情ID:', qrcodeId);
const qrcodeRes = await getGenerateRecord(qrcodeId);
console.log('二维码响应:', qrcodeRes);
if (qrcodeRes.code !== 200) {
throw new Error('未找到二维码记录');
}
// 2. 解析二维码的content获取coil_id
const qrcodeRecord = qrcodeRes.data;
console.log('2. 二维码记录:', qrcodeRecord);
// 检查二维码状态0=失效1=有效)
if (qrcodeRecord.status === 0) {
uni.hideLoading();
uni.showModal({
title: '提示',
content: '该二维码已失效,无法创建待操作任务',
showCancel: false
});
return;
}
const content = JSON.parse(qrcodeRecord.content);
console.log('解析后的内容:', content);
// 优先使用current_coil_id当前有效的钢卷ID如果没有则使用coil_id兼容旧数据
let coilId = content.current_coil_id && content.current_coil_id !== 'null' ? content
.current_coil_id : null;
if (!coilId) {
coilId = content.coil_id && content.coil_id !== 'null' ? content.coil_id : null;
}
console.log('提取钢卷ID - current_coil_id:', content.current_coil_id, 'coil_id:', content.coil_id,
'最终使用:', coilId);
if (!coilId) {
throw new Error('二维码中未包含有效的钢卷ID');
}
// 3. 直接通过钢卷ID获取钢卷详情
console.log('3. 获取钢卷详情钢卷ID:', coilId);
const coilRes = await getMaterialCoil(coilId);
console.log('钢卷详情响应:', coilRes);
if (coilRes.code !== 200) {
throw new Error(coilRes.msg || '查询钢卷信息失败');
}
if (!coilRes.data) {
throw new Error('未找到钢卷信息');
}
this.coilDetail = coilRes.data;
this.form = coilRes.data;
this.$refs.tranferPopup.open();
uni.hideLoading()
} catch (err) {
console.error('=== 扫码处理失败 ===');
console.error('错误信息:', err);
console.error('错误堆栈:', err.stack);
uni.hideLoading();
uni.showToast({
title: err.message || '处理失败',
icon: 'none',
duration: 3000
});
}
},
fail: (err) => {
console.error('扫码失败:', err);
uni.showToast({
title: '扫码失败,请重试',
icon: 'none'
});
}
});
},
async handleConfirm() {
try {
// 1. 更新钢卷信息(移库)
await updateMaterialCoilSimple(this.form);
// 2. 插入一条已完成的待操作记录
await addPendingAction({
coilId: this.form.coilId,
currentCoilNo: this.form.currentCoilNo,
actionType: 5, // 5=移库
actionStatus: 2, // 2=已完成
scanTime: new Date(),
scanDevice: this.getDeviceInfo(),
priority: 0, // 0=普通
sourceType: 'scan',
warehouseId: this.form.warehouseId,
processTime: new Date(),
completeTime: new Date()
});
uni.showToast({
title: '移库成功',
icon: 'none'
});
this.$refs.tranferPopup.close();
} catch (error) {
console.error('移库失败:', error);
uni.showToast({
title: error.message || '移库失败',
icon: 'none'
});
}
},
// 获取设备信息
getDeviceInfo() {
try {
const systemInfo = uni.getSystemInfoSync();
return `${systemInfo.platform} ${systemInfo.model}`;
} catch (e) {
return 'Unknown Device';
}
},
// 获取操作类型名称
getActionTypeName(actionType) {
const type = this.types.find(t => t.dictValue === String(actionType));
return type ? type.dictLabel : '未知操作';
}
},
mounted() {
getDicts('action_type').then(res => {
this.types = res.data
})
}
}
</script>
<style scoped>
.container {
padding: 15rpx;
min-height: 100vh;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
align-items: center;
padding-bottom: 120rpx;
}
/* 页面标题 */
.page-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
padding: 10rpx 0;
margin-bottom: 15rpx;
text-align: center;
}
/* 分区卡片 */
.section-card {
width: 100%;
background: #fff;
border-radius: 16rpx;
padding: 20rpx;
margin-bottom: 15rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
/* 分区标题 */
.section-title {
display: flex;
align-items: center;
margin-bottom: 12rpx;
padding-bottom: 10rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.title-icon {
font-size: 32rpx;
margin-right: 10rpx;
}
.title-text {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
/* 分条区域特殊样式 */
.split-section {
border-left: 4rpx solid #409eff;
}
.split-section .section-title {
border-bottom-color: #409eff;
}
/* 其他操作区域特殊样式 */
.other-section {
border-left: 4rpx solid #909399;
}
.other-section .section-title {
border-bottom-color: #909399;
}
/* 快捷操作区域特殊样式 */
.quick-section {
border-left: 4rpx solid #67c23a;
}
.quick-section .section-title {
border-bottom-color: #67c23a;
}
/* 按钮网格布局 */
.btn-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15rpx;
}
/* 快捷操作区按钮网格 - 两列 */
.quick-grid {
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
}
.quick-grid .type-btn {
height: 120rpx;
font-size: 28rpx;
}
/* 操作类型按钮样式 - 工业化简洁风格 */
.type-btn {
width: 100%;
height: 110rpx;
white-space: normal;
line-height: 1.4;
padding: 10rpx;
font-size: 26rpx;
font-weight: 600;
border-radius: 10rpx;
border: 2rpx solid transparent;
box-shadow: none;
transition: all 0.2s ease;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
/* 分条按钮样式 - 浅蓝色 */
.split-btn {
background-color: #e3f2fd;
color: #1976d2;
border-color: #1976d2;
}
.split-btn:active {
background-color: #bbdefb;
opacity: 0.9;
}
/* 其他操作按钮样式 - 浅灰色 */
.other-btn {
background-color: #f5f5f5;
color: #606266;
border-color: #909399;
}
.other-btn:active {
background-color: #e0e0e0;
opacity: 0.9;
}
/* 移库按钮 - 黄色 */
.move-btn {
background-color: #fff9e6;
color: #e6a23c;
border-color: #e6a23c;
}
.move-btn:active {
background-color: #fff3cc;
opacity: 0.9;
}
/* 发货按钮 - 绿色 */
.ship-btn {
background-color: #e8f5e9;
color: #67c23a;
border-color: #67c23a;
}
.ship-btn:active {
background-color: #c8e6c9;
opacity: 0.9;
}
/* 退出登录按钮容器 */
.logout-container {
width: 100%;
position: fixed;
bottom: 30rpx;
left: 0;
padding: 0 20rpx;
box-sizing: border-box;
}
/* 退出登录按钮样式 */
.logout-btn {
width: 100%;
height: 80rpx;
line-height: 80rpx;
/* 文字竖直居中 */
font-size: 28rpx;
color: #fff;
background-color: #ff4d4f;
border-radius: 12rpx;
border: none;
box-shadow: 0 2rpx 8rpx rgba(255, 77, 79, 0.15);
transition: all 0.2s ease;
}
.logout-btn:active {
background-color: #f5222d;
transform: scale(0.98);
}
/* 卡片样式 */
.info-card,
.material-card,
.form-card {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
/* 表单项 */
.form-item {
margin-bottom: 30rpx;
&:last-of-type {
margin-bottom: 0;
}
.form-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
&::before {
content: '*';
color: #ff4d4f;
margin-right: 6rpx;
}
}
.form-label-optional {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 15rpx;
font-weight: 500;
}
.form-input {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
transition: all 0.3s;
&:focus {
background: #fff;
border-color: #007aff;
}
&.form-input-disabled {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
}
}
</style>