Files
klp-mono/apps/hand-factory/pages/easycode/easycode.vue
砂糖 983bb0a172 feat(钢卷管理): 添加撤回发货功能并更新版本号至1.3.20
- 在钢卷管理页面新增撤回发货按钮及相关处理逻辑
- 添加撤回发货API接口cancelExportCoil
- 重构发货操作弹窗,支持发货和撤回发货两种操作
- 更新应用版本号至1.3.20,涉及config.js、manifest.json等文件
2026-01-11 19:05:44 +08:00

1284 lines
32 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 ship-btn" @click="handleShip">发货</button>
<button class="type-btn cancelship-btn" @click="handleCancelShip">撤回发货</button>
<button class="type-btn move-btn" @click="handleTranfer">移库</button>
<button class="type-btn see-btn" @click="handleSee">查看存储钢卷</button>
<button class="type-btn packing-btn" @click="handlePack">打包</button>
</view>
</view>
<uni-popup ref="tranferPopup" type="bottom">
<view style="background-color: white; padding: 20rpx;">
<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>
<!-- 未选择目标库区显示扫码按钮 -->
<view v-if="!targetWarehouse" class="scan-btn-wrapper" @click="handleScanWarehouseCode">
<view class="scan-icon">
<text class="icon-camera">📷</text>
</view>
<text class="scan-tip">扫描库区码</text>
<text class="scan-hint">请扫描目标库区的二维码</text>
</view>
<!-- 已选择目标库区回显信息 + 重新扫码按钮 -->
<view v-else class="selected-warehouse">
<view class="warehouse-info">
<text class="warehouse-label">已选中</text>
<text class="warehouse-value">{{ targetWarehouse.actualWarehouseName }}</text>
</view>
<button class="re-scan-btn" @click="handleReScan">重新选择</button>
</view>
</view>
<view class="action-buttons">
<button class="btn btn-secondary" @click="handleClosePopup">取消</button>
<!-- 已选择目标库区才启用提交按钮 -->
<button class="btn btn-primary" @click="handleConfirm" :disabled="loading || !targetWarehouse">
{{ loading ? '提交中...' : '确认移库' }}
</button>
</view>
</view>
</view>
</uni-popup>
<!-- <klp-scaner></klp-scaner> -->
<qs-scanlistener ref='pda'></qs-scanlistener>
<uni-popup ref="shipPopup" type="bottom">
<view style="background-color: white; padding: 20rpx;">
<view class="info-card" v-if="coilDetail.coilId">
<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.netWeight || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">厂家</text>
<text class="item-value">{{ coilDetail.product && coilDetail.product.manufacturer || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">材质</text>
<text class="item-value">{{ coilDetail.product && coilDetail.product.material || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">规格</text>
<text class="item-value">{{ coilDetail.product && coilDetail.product.specification || '-' }}</text>
</view>
<view class="info-item">
<text class="item-label">品名</text>
<text class="item-value">{{ coilDetail.product && coilDetail.product.productName || '-' }}</text>
</view>
</view>
</view>
<button
v-if="currentAction == 'withdrawShip'"
:disabled="buttonLoading"
:loading="buttonLoading"
@click="handleCancelShipSubmit">
撤回发货
</button>
<button
v-if="currentAction == 'ship'"
:disabled="buttonLoading"
:loading="buttonLoading"
@click="handleShipSubmit">
发货
</button>
</view>
</uni-popup>
</view>
</template>
<script>
import {
getDicts
} from '@/api/system/dict/data.js'
import {
getGenerateRecord
} from '@/api/wms/code.js'
import {
getMaterialCoil,
updateMaterialCoilSimple,
listMaterialCoil,
updateMaterialCoil,
exportCoil,
cancelExportCoil
} from '@/api/wms/coil.js'
import {
addPendingAction
} from '@/api/wms/pendingAction.js'
import {
getActualWarehouse
} from '@/api/wms/actualWarehouse.js'
export default {
data() {
return {
types: [],
loading: false,
coilDetail: {},
form: {},
targetWarehouse: null, // 存储选中的目标库区信息
bomDialogShow: false, // BOM参数弹窗控制原有功能补充
mode: 'pda', // pda或camera
currentAction: '',
buttonLoading: false,
}
},
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')
})
})
},
async handleCancelShip() {
// 撤回发货
this.currentAction = 'withdrawShip';
const content = await this.getQRCodeContent()
let coilId = content.current_coil_id && content.current_coil_id !== 'null' ? content
.current_coil_id : null;
if (!coilId) {
uni.showToast({
title: '二维码异常',
icon: 'none'
})
return;
}
const coilRes = await getMaterialCoil(coilId);
if (coilRes.data.status == 0) {
uni.showToast({
title: '钢卷还未发货',
icon: 'error'
})
return;
}
this.coilDetail = coilRes.data;
this.$refs.shipPopup.open('bottom');
},
async handleCancelShipSubmit() {
if (!this.coilDetail.coilId) {
uni.showToast({
title: '钢卷标识缺失',
icon: 'none'
})
}
const res = await cancelExportCoil(this.coilDetail.coilId)
console.log(res)
if (res.code != 200) {
uni.showToast({
icon: 'error',
title: res.message || '撤回失败请重试'
})
return;
}
uni.showToast({
icon: 'success',
title: this.coilDetail.currentCoilNo + '发货已撤回'
})
this.$refs.shipPopup.close()
},
scan(mode = 'camera') {
return new Promise((resolve, reject) => {
if (mode == 'camera') {
uni.scanCode({
success(res) {
console.log('扫码成功')
resolve(res.result)
},
fail() {
reject()
}
})
} else if (mode == 'pda') {
this.$refs.pda.open().then(code => {
resolve(code);
}).catch(() => {
reject()
})
}
})
},
async handlePack() {
const content = await this.getQRCodeContent()
let coilId = content.current_coil_id && content.current_coil_id !== 'null' ? content
.current_coil_id : null;
if (!coilId) {
uni.showToast({
title: '二维码异常',
icon: 'none'
})
return;
}
uni.navigateTo({
url: '/pages/easycode/packing?coilId=' + coilId
})
},
async handleSee() {
const actualWarehouseId = await this.scan()
// 查询真实库区在此处的钢卷
const res = await listMaterialCoil({
actualWarehouseId,
dataType: 1
})
if (res.total == 0) {
uni.showToast({
title: '该库区未发现钢卷',
icon: 'none'
});
return;
}
if (res.rows.length == 1) {
const coilId = res.rows[0].coilId;
uni.navigateTo({
url: '/pages/easycode/editby?coilId=' + coilId
})
} else {
uni.showToast({
title: '数据异常',
icon: 'none'
})
}
},
// 扫码并创建待操作(原有方法不变)
async handleScan(actionType) {
const content = await this.getQRCodeContent()
// 优先使用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'
})
},
// 通用扫码获取二维码内容(原有方法不变)
async getQRCodeContent() {
return new Promise((resolve, reject) => {
this.scan().then(async res => {
uni.showLoading({
title: '处理中...'
});
try {
const qrcodeId = res;
// 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;
}
uni.hideLoading();
const content = JSON.parse(qrcodeRecord.content);
console.log('解析后的内容:', content);
resolve(content)
} catch (err) {
console.error('=== 扫码处理失败 ===');
console.error('错误信息:', err);
console.error('错误堆栈:', err.stack);
uni.hideLoading();
uni.showToast({
title: err.message || '处理失败',
icon: 'none',
duration: 3000
});
reject()
}
}).catch(() => {
reject()
})
})
},
// 发货操作(原有方法不变)
async handleShip() {
const content = await this.getQRCodeContent();
// 优先使用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;
}
this.$refs.shipPopup.open('bottom');
this.currentAction = 'ship';
this.coilDetail = coilRes.data
// uni.showModal({
// cancelText: '取消',
// confirmText: '确认',
// title: '确定要将钢卷号为:' + coilRes.data.currentCoilNo + '发货吗?',
// showCancel: true,
// success: async (res) => {
// console.log(res)
// if (res.cancel) {
// uni.showToast({
// title: '已取消发货',
// icon: 'none'
// })
// return;
// }
// try {
// // 判断钢卷的质量状态必须是A+, AA-, B+其中之一
// if (!['A+', 'A', 'A-', 'B+'].includes(coilRes.data.qualityStatus)) {
// uni.showToast({
// title: '只能发货B+以上品质的钢卷',
// icon: 'none'
// });
// return;
// }
// // 1. 更新钢卷状态为已发货
// await exportCoil(coilRes.data.coilId);
// // 2. 插入一条已完成的待操作记录
// await addPendingAction({
// coilId: coilRes.data.coilId,
// currentCoilNo: coilRes.data.currentCoilNo,
// actionType: 402, // 402=发货
// actionStatus: 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();
},
async handleShipSubmit() {
try {
// 判断钢卷的质量状态必须是A+, AA-, B+其中之一
if (!['A+', 'A', 'A-', 'B+'].includes(this.coilDetail.qualityStatus)) {
uni.showToast({
title: '只能发货B+以上品质的钢卷',
icon: 'none'
});
return;
}
// 1. 更新钢卷状态为已发货
const res = await exportCoil(this.coilDetail.coilId);
// 2. 插入一条已完成的待操作记录
await addPendingAction({
coilId: this.coilDetail.coilId,
currentCoilNo: this.coilDetail.currentCoilNo,
actionType: 402, // 402=发货
actionStatus: 2, // 直接标记为完成状态
scanTime: new Date(),
scanDevice: this.getDeviceInfo(),
priority: 0, // 0=普通
sourceType: 'scan',
warehouseId: this.coilDetail.warehouseId,
processTime: new Date(),
completeTime: new Date()
});
if (res.code != 200) {
uni.showToast({
icon: 'error',
title: res.message || '发货失败请重试'
})
return;
}
uni.showToast({
title: '发货成功',
icon: 'success'
});
this.$refs.shipPopup.close()
} catch (error) {
console.error('发货失败:', error);
uni.showToast({
title: error?.message || '发货失败',
icon: 'none'
});
}
},
// 移库操作:第一步 - 扫描钢卷,打开移库弹窗(原有方法优化)
async handleTranfer() {
try {
const content = await this.getQRCodeContent()
// 优先使用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.targetWarehouse = null;
this.coilDetail = coilRes.data;
this.form = {
...coilRes.data
};
// 打开移库弹窗
this.$refs.tranferPopup.open();
uni.hideLoading()
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error?.message || '打开移库失败',
icon: 'none',
duration: 2000
});
}
},
// 移库操作:第二步 - 扫描目标库区码(核心补充)
async handleScanWarehouseCode() {
try {
uni.showLoading({
title: '扫码中...'
});
// 扫描库区二维码
const scanRes = await this.scan()
uni.hideLoading();
const warehouseQrCode = scanRes;
if (!warehouseQrCode) {
throw new Error('未识别到库区信息');
}
// 解析库区二维码假设二维码内容是库区ID若为JSON格式需调整解析逻辑
const targetWarehouseId = warehouseQrCode;
console.log('扫描到的目标库区ID', targetWarehouseId);
// 调用接口获取库区详情关键通过库区ID查询名称等信息
uni.showLoading({
title: '验证库区...'
});
const warehouseRes = await getActualWarehouse(targetWarehouseId);
uni.hideLoading();
if (warehouseRes.code !== 200 || !warehouseRes.data) {
throw new Error('获取库区信息失败,请确认库区码有效');
}
const targetWarehouse = warehouseRes.data;
// 校验:目标库区不能与原库区相同
if (targetWarehouse.actualWarehouseId === this.coilDetail.actualWarehouseId) {
throw new Error('目标库区不能与当前库区相同');
}
// 存储目标库区信息(用于回显和提交)
this.targetWarehouse = targetWarehouse;
// 更新表单中的目标库区ID提交时需要
this.form.actualWarehouseId = targetWarehouse.actualWarehouseId;
this.form.actualWarehouseName = targetWarehouse.actualWarehouseName;
uni.showToast({
title: `已选中库区:${targetWarehouse.actualWarehouseName}`,
icon: 'none',
duration: 1500
});
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error?.message || '扫描库区失败',
icon: 'none',
duration: 2500
});
}
},
// 移库操作:重新扫描目标库区
handleReScan() {
this.targetWarehouse = null;
this.form.warehouseId = this.coilDetail.warehouseId; // 重置为原库区ID
this.form.actualWarehouseName = this.coilDetail.actualWarehouseName;
},
// 移库操作:关闭弹窗
handleClosePopup() {
this.$refs.tranferPopup.close();
// 重置状态
this.targetWarehouse = null;
this.form = {};
this.coilDetail = {};
},
// 移库操作:第三步 - 确认移库(核心补充)
async handleConfirm() {
try {
// 再次校验:防止异常场景
if (!this.targetWarehouse || !this.form.warehouseId) {
uni.showToast({
title: '请先选择目标库区',
icon: 'none'
});
return;
}
if (this.targetWarehouse.actualWarehouseId === this.coilDetail.warehouseId) {
uni.showToast({
title: '目标库区不能与当前库区相同',
icon: 'none'
});
return;
}
this.loading = true;
uni.showLoading({
title: '移库中...'
});
// 1. 核心:更新钢卷的库区信息
const updateRes = await updateMaterialCoilSimple(this.form);
if (updateRes.code !== 200) {
throw new Error(updateRes.msg || '更新钢卷库区失败');
}
// 2. 创建移库操作记录(标记为已完成)
const pendingData = {
coilId: this.form.coilId,
currentCoilNo: this.form.currentCoilNo,
actionType: 403, // 403=移库需与字典表action_type的移库编码一致
actionStatus: 2, // 2=已完成
scanTime: new Date().toISOString(),
scanDevice: this.getDeviceInfo(),
priority: 0, // 普通优先级
sourceType: 'scan', // 扫码来源
processTime: new Date().toISOString(),
completeTime: new Date().toISOString(),
remark: `移库操作:${this.coilDetail.actualWarehouseName}${this.form.actualWarehouseName}`
};
const addRes = await addPendingAction(pendingData);
if (addRes.code !== 200) {
throw new Error(addRes.msg || '创建移库记录失败');
}
// 操作成功
uni.hideLoading();
uni.showToast({
title: '移库成功',
icon: 'success',
duration: 1500
});
// 关闭弹窗并重置状态
setTimeout(() => {
this.handleClosePopup();
}, 1500);
} catch (error) {
this.loading = false;
uni.hideLoading();
console.error('移库失败详情:', error);
uni.showToast({
title: error?.message || '移库失败,请重试',
icon: 'none',
duration: 3000
});
} finally {
this.loading = false;
}
},
// 显示BOM参数弹窗原有功能补充实现
showBomDialog() {
this.bomDialogShow = true;
// 可扩展BOM参数弹窗内容此处省略弹窗组件实现
},
// 获取设备信息(原有方法不变)
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;
}
.see-btn {
background-color: #6fd2ff;
color: #0777ff;
border-color: #0777ff;
}
.packing-btn {
background-color: #f2e9ff;
/* 浅紫底色,与黄色#fff9e6、蓝色#6fd2ff等浅底色亮度/饱和度匹配 */
color: #722ed1;
/* 深紫文字色,延续「同色系饱和色」的文字/边框逻辑 */
border-color: #722ed1;
}
.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;
}
}
}
/* 扫码按钮样式 */
.scan-btn-wrapper {
display: flex;
flex-direction: column;
align-items: center;
gap: 20rpx;
.scan-icon {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
background: linear-gradient(135deg, #34c759 0%, #30b350 100%);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(52, 199, 89, 0.3);
&:active {
transform: scale(0.95);
}
}
.icon-camera {
font-size: 70rpx;
color: #fff;
}
.scan-tip {
font-size: 28rpx;
color: #666;
}
.scan-hint {
font-size: 24rpx;
color: #999;
}
}
/* 已选中库区样式 */
.selected-warehouse {
display: flex;
flex-direction: column;
align-items: center;
gap: 15rpx;
padding: 20rpx;
background-color: #f0f9ff;
border-radius: 12rpx;
width: 100%;
box-sizing: border-box;
}
.warehouse-info {
display: flex;
align-items: center;
gap: 10rpx;
font-size: 28rpx;
}
.warehouse-label {
color: #666;
}
.warehouse-value {
color: #1976d2;
font-weight: 600;
}
.re-scan-btn {
padding: 10rpx 30rpx;
font-size: 24rpx;
color: #409eff;
background-color: transparent;
border: 2rpx solid #409eff;
border-radius: 8rpx;
}
/* 操作按钮组样式 */
.action-buttons {
display: flex;
gap: 20rpx;
margin-top: 40rpx;
}
.btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
font-size: 28rpx;
border-radius: 12rpx;
border: none;
}
.btn-secondary {
background-color: #f5f5f5;
color: #666;
}
.btn-primary {
background-color: #409eff;
color: #fff;
}
.btn:disabled {
opacity: 0.6;
}
/* 信息网格样式 */
.info-grid {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-top: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10rpx 0;
border-bottom: 2rpx solid #f5f5f5;
}
.item-label {
font-size: 26rpx;
color: #666;
width: 30%;
}
.item-value {
font-size: 26rpx;
color: #333;
width: 70%;
text-align: right;
word-break: break-all;
}
/* 卡片标题样式 */
.card-title {
display: flex;
align-items: center;
justify-content: space-between;
}
.title-dot {
display: inline-block;
width: 12rpx;
height: 12rpx;
background-color: #409eff;
border-radius: 50%;
margin-right: 10rpx;
}
.more-btn {
display: flex;
align-items: center;
gap: 5rpx;
color: #409eff;
font-size: 24rpx;
}
.icon-more {
font-size: 26rpx;
}
</style>