Files
klp-mono/apps/hand-factory/components/panels/code/merge.vue
砂糖 9fcbad1f8e fix: 修复登录跳转路径和版本号更新
refactor: 移除调试日志和冗余代码
style: 格式化代码和修复条件判断逻辑
feat: 重新启用401错误处理并优化表单重置逻辑
2025-11-04 14:27:20 +08:00

1223 lines
30 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>
<view class="merge-container">
<!-- 扫码提示 -->
<view class="scan-section">
<view class="scan-btn-wrapper" @click="handleScan">
<view class="scan-icon">
<text class="icon-camera">📷</text>
</view>
<text class="scan-tip">扫描要合卷的钢卷</text>
<text class="scan-hint">已扫描 {{ scannedCoils.length }} 个钢卷</text>
</view>
</view>
<!-- 已扫描的钢卷列表 -->
<view class="coil-list" v-if="scannedCoils.length > 0">
<view class="card-title">
<text class="title-dot"></text>
<text class="title-text">待合卷列表</text>
</view>
<view class="coil-item" v-for="(coil, index) in scannedCoils" :key="index">
<view class="coil-content">
<view class="coil-index">{{ index + 1 }}</view>
<view class="coil-info">
<view class="coil-row">
<text class="coil-label">入场钢卷号</text>
<text class="coil-value">{{ coil.enterCoilNo }}</text>
</view>
<view class="coil-row">
<text class="coil-label">当前钢卷号</text>
<text class="coil-value">{{ coil.currentCoilNo }}</text>
</view>
<view class="coil-row" v-if="coil.warehouse">
<text class="coil-label">库区</text>
<text class="coil-value">{{ coil.warehouse.warehouseName }}</text>
</view>
</view>
</view>
<view class="coil-remove" @click="removeCoil(index)">
<text></text>
</view>
</view>
</view>
<!-- 合卷配置 -->
<view class="form-card" v-if="scannedCoils.length >= 2" @click="closeWarehouseList">
<view class="card-title">
<text class="title-dot"></text>
<text class="title-text">合卷配置</text>
</view>
<!-- 新钢卷号 -->
<view class="form-item">
<text class="form-label">新钢卷号</text>
<input
v-model="mergedCoilNo"
placeholder="请输入合卷后的新钢卷号"
class="form-input"
/>
</view>
<!-- 班组 -->
<view class="form-item">
<text class="form-label">班组</text>
<input
v-model="team"
placeholder="请输入班组名称"
class="form-input"
/>
</view>
<!-- 目标库区 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">目标库位</text>
<view
class="picker-input"
@click="showWarehousePicker()"
>
<text class="picker-text" :class="{ 'picker-placeholder': !warehouseName }">
{{ warehouseName || '请选择目标库位' }}
</text>
<text class="picker-arrow"></text>
</view>
</view>
<!-- 实际库区 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">实际库区</text>
<klp-warehouse-picker v-model="actualWarehouseId" placeholder="请选择目标库区"
ware-type="actual" />
</view>
<!-- 物品类型选择 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">物品类型</text>
<view
class="picker-input"
@click="showItemTypePicker()"
>
<text class="picker-text" :class="{ 'picker-placeholder': !itemType }">
{{ itemType === 'product' ? '成品' : itemType === 'raw_material' ? '原料' : '请选择物品类型' }}
</text>
<text class="picker-arrow"></text>
</view>
</view>
<!-- 产品选择仅当选择了成品类型时显示 -->
<view class="form-item form-item-optional" v-if="itemType === 'product'">
<text class="form-label-optional">选择产品</text>
<view
class="picker-input"
@click="showProductPicker()"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedProductName }">
{{ selectedProductName || '请选择产品' }}
</text>
<text class="picker-arrow"></text>
</view>
</view>
<!-- 原材料选择仅当选择了原料类型时显示 -->
<view class="form-item form-item-optional" v-if="itemType === 'raw_material'">
<text class="form-label-optional">选择原材料</text>
<view
class="picker-input"
@click="showRawMaterialPicker()"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedRawMaterialName }">
{{ selectedRawMaterialName || '请选择原材料' }}
</text>
<text class="picker-arrow"></text>
</view>
</view>
<!-- 毛重 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">毛重 ()</text>
<input
v-model="grossWeight"
type="digit"
placeholder="请输入毛重(选填)"
class="form-input"
/>
</view>
<!-- 净重 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">净重 ()</text>
<input
v-model="netWeight"
type="digit"
placeholder="请输入净重(选填)"
class="form-input"
/>
</view>
<!-- 操作者信息 -->
<view class="operator-info">
<text class="operator-label">操作人</text>
<text class="operator-name">{{ operatorName }}</text>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<button class="btn btn-secondary" @click="handleReset">清空重新扫</button>
<button class="btn btn-primary" @click="handleConfirm" :disabled="loading">
{{ loading ? '提交中...' : '确认合卷' }}
</button>
</view>
</view>
<!-- 提示信息 -->
<view class="tip-card" v-if="scannedCoils.length === 1">
<text class="tip-text">至少需要扫描 2 个钢卷才能进行合卷操作</text>
</view>
<!-- 库区选择弹窗 -->
<uni-popup ref="warehousePopup" type="bottom">
<view class="warehouse-popup">
<view class="popup-header">
<text class="popup-title">选择库区</text>
<text class="popup-close" @click="closeWarehousePicker"></text>
</view>
<view class="popup-search">
<input
v-model="warehouseSearchKeyword"
@input="filterWarehousesInPicker"
placeholder="搜索库区名称"
class="search-input"
/>
</view>
<scroll-view class="popup-body" scroll-y>
<view
class="warehouse-item"
v-for="warehouse in filteredWarehousesInPicker"
:key="warehouse.warehouseId"
@click="selectWarehouseFromPicker(warehouse)"
>
<text class="warehouse-name">{{ warehouse.warehouseName }}</text>
<text class="warehouse-check" v-if="warehouseId === warehouse.warehouseId"></text>
</view>
<view class="empty-tip" v-if="!filteredWarehousesInPicker || filteredWarehousesInPicker.length === 0">
<text>未找到匹配的库区</text>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 产品选择弹窗 -->
<uni-popup ref="productPopup" type="bottom">
<view class="warehouse-popup">
<view class="popup-header">
<text class="popup-title">选择产品</text>
<text class="popup-close" @click="closeProductPicker"></text>
</view>
<view class="popup-search">
<input
v-model="productSearchKeyword"
@input="filterProductsInPicker"
placeholder="搜索产品名称"
class="search-input"
/>
</view>
<scroll-view class="popup-body" scroll-y>
<view
class="warehouse-item"
v-for="product in filteredProductsInPicker"
:key="product.productId"
@click="selectProductFromPicker(product)"
>
<text class="warehouse-name">{{ product.productName }}</text>
<text class="warehouse-check" v-if="itemId === product.productId"></text>
</view>
<view class="empty-tip" v-if="!filteredProductsInPicker || filteredProductsInPicker.length === 0">
<text>未找到匹配的产品</text>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 原材料选择弹窗 -->
<uni-popup ref="rawMaterialPopup" type="bottom">
<view class="warehouse-popup">
<view class="popup-header">
<text class="popup-title">选择原材料</text>
<text class="popup-close" @click="closeRawMaterialPicker"></text>
</view>
<view class="popup-search">
<input
v-model="rawMaterialSearchKeyword"
@input="filterRawMaterialsInPicker"
placeholder="搜索原材料名称"
class="search-input"
/>
</view>
<scroll-view class="popup-body" scroll-y>
<view
class="warehouse-item"
v-for="material in filteredRawMaterialsInPicker"
:key="material.rawMaterialId"
@click="selectRawMaterialFromPicker(material)"
>
<text class="warehouse-name">{{ material.rawMaterialName }}</text>
<text class="warehouse-check" v-if="itemId === material.rawMaterialId"></text>
</view>
<view class="empty-tip" v-if="!filteredRawMaterialsInPicker || filteredRawMaterialsInPicker.length === 0">
<text>未找到匹配的原材料</text>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- 物品类型选择弹窗 -->
<uni-popup ref="itemTypePopup" type="bottom">
<view class="warehouse-popup">
<view class="popup-header">
<text class="popup-title">选择物品类型</text>
<text class="popup-close" @click="closeItemTypePicker"></text>
</view>
<scroll-view class="popup-body" scroll-y>
<view class="warehouse-item" @click="selectItemType('product')">
<text class="warehouse-name">成品</text>
<text class="warehouse-check" v-if="itemType === 'product'"></text>
</view>
<view class="warehouse-item" @click="selectItemType('raw_material')">
<text class="warehouse-name">原料</text>
<text class="warehouse-check" v-if="itemType === 'raw_material'"></text>
</view>
</scroll-view>
</view>
</uni-popup>
</view>
</template>
<script>
import { getGenerateRecord } from '@/api/wms/code.js'
import { updateMaterialCoil, getMaterialCoil, getMaterialCoilTrace } from '@/api/wms/coil.js'
import { listWarehouse } from '@/api/wms/warehouse.js'
import { listProduct } from '@/api/wms/product.js'
import { listRawMaterial } from '@/api/wms/rawMaterial.js'
export default {
data() {
return {
scannedCoils: [],
mergedCoilNo: '',
team: '',
warehouseId: undefined,
actualWarehouseId: undefined,
warehouseName: '',
warehouseKeyword: '',
warehouses: [],
filteredWarehouses: [],
showWarehouseList: false,
warehouseSearchKeyword: '',
filteredWarehousesInPicker: [],
products: [], // 产品列表
productSearchKeyword: '',
filteredProductsInPicker: [],
rawMaterials: [], // 原材料列表
rawMaterialSearchKeyword: '',
filteredRawMaterialsInPicker: [],
itemType: '', // 合卷后的物品类型
itemId: undefined, // 合卷后的物品ID
selectedProductName: '', // 已选择的产品名称
selectedRawMaterialName: '', // 已选择的原材料名称
grossWeight: '',
netWeight: '',
loading: false
}
},
onLoad() {
this.loadWarehouses();
this.loadProducts();
this.loadRawMaterials();
},
mounted() {
this.loadWarehouses();
this.loadProducts();
this.loadRawMaterials();
},
computed: {
operatorName() {
return this.$store.state.user.nickName || this.$store.state.user.name || '未知'
}
},
methods: {
// 加载库区列表
async loadWarehouses() {
console.log('合卷页面开始加载库区...');
try {
const res = await listWarehouse({ pageNum: 1, pageSize: 1000 });
console.log("合卷页面库区返回值", res);
if (res.code === 200) {
this.warehouses = res.data || [];
this.filteredWarehouses = [...this.warehouses];
console.log('合卷页面库区加载成功,数量:', this.warehouses.length);
} else {
console.error('合卷页面库区加载失败:', res.msg);
}
} catch (err) {
console.error('合卷页面加载库区异常:', err);
}
},
// 加载产品列表
async loadProducts() {
console.log('开始加载产品列表...');
try {
const res = await listProduct({ pageNum: 1, pageSize: 1000 });
console.log("产品返回值", res);
if (res.code === 200) {
this.products = res.rows || res.data || [];
this.filteredProductsInPicker = this.products;
console.log('产品加载成功,数量:', this.products.length);
} else {
console.error('产品加载失败:', res.msg);
}
} catch (err) {
console.error('加载产品异常:', err);
}
},
// 加载原材料列表
async loadRawMaterials() {
console.log('开始加载原材料列表...');
try {
const res = await listRawMaterial({ pageNum: 1, pageSize: 1000 });
console.log("原材料返回值", res);
if (res.code === 200) {
this.rawMaterials = res.rows || res.data || [];
this.filteredRawMaterialsInPicker = this.rawMaterials;
console.log('原材料加载成功,数量:', this.rawMaterials.length);
} else {
console.error('原材料加载失败:', res.msg);
}
} catch (err) {
console.error('加载原材料异常:', err);
}
},
// 显示产品选择器
showProductPicker() {
this.productSearchKeyword = '';
this.filteredProductsInPicker = [...this.products];
this.$refs.productPopup.open();
},
// 关闭产品选择器
closeProductPicker() {
this.$refs.productPopup.close();
},
// 过滤产品(在选择器中)
filterProductsInPicker() {
const keyword = this.productSearchKeyword.trim().toLowerCase();
if (!keyword) {
this.filteredProductsInPicker = [...this.products];
} else {
this.filteredProductsInPicker = this.products.filter(product => {
const name = (product.productName || '').toLowerCase();
return name.includes(keyword);
});
}
},
// 从选择器中选择产品
selectProductFromPicker(product) {
this.itemId = product.productId;
this.itemType = 'product';
this.selectedProductName = product.productName;
uni.showToast({
title: `已选择产品:${product.productName}`,
icon: 'success'
});
this.closeProductPicker();
},
// 显示原材料选择器
showRawMaterialPicker() {
this.rawMaterialSearchKeyword = '';
this.filteredRawMaterialsInPicker = [...this.rawMaterials];
this.$refs.rawMaterialPopup.open();
},
// 关闭原材料选择器
closeRawMaterialPicker() {
this.$refs.rawMaterialPopup.close();
},
// 过滤原材料(在选择器中)
filterRawMaterialsInPicker() {
const keyword = this.rawMaterialSearchKeyword.trim().toLowerCase();
if (!keyword) {
this.filteredRawMaterialsInPicker = [...this.rawMaterials];
} else {
this.filteredRawMaterialsInPicker = this.rawMaterials.filter(material => {
const name = (material.rawMaterialName || '').toLowerCase();
return name.includes(keyword);
});
}
},
// 从选择器中选择原材料
selectRawMaterialFromPicker(material) {
this.itemId = material.rawMaterialId;
this.itemType = 'raw_material';
this.selectedRawMaterialName = material.rawMaterialName;
uni.showToast({
title: `已选择原材料:${material.rawMaterialName}`,
icon: 'success'
});
this.closeRawMaterialPicker();
},
// 过滤库区
filterWarehouses() {
console.log('合卷页面过滤库区,关键词:', this.warehouseKeyword);
console.log('合卷页面当前库区列表:', this.warehouses);
const keyword = this.warehouseKeyword.trim().toLowerCase();
if (!keyword) {
this.filteredWarehouses = this.warehouses;
} else {
this.filteredWarehouses = this.warehouses.filter(warehouse => {
const name = (warehouse.warehouseName || '').toLowerCase();
return name.includes(keyword);
});
}
console.log('合卷页面过滤后库区数量:', this.filteredWarehouses.length);
this.showWarehouseList = true;
},
// 选择库区
selectWarehouse(warehouse) {
this.warehouseId = warehouse.warehouseId;
this.warehouseName = warehouse.warehouseName;
this.warehouseKeyword = warehouse.warehouseName;
this.showWarehouseList = false;
},
// 关闭库区搜索列表
closeWarehouseList() {
this.showWarehouseList = false;
},
// 显示库区选择器
showWarehousePicker() {
this.warehouseSearchKeyword = '';
this.filteredWarehousesInPicker = [...this.warehouses];
this.$refs.warehousePopup.open();
},
// 关闭库区选择器
closeWarehousePicker() {
this.$refs.warehousePopup.close();
},
// 在选择器中过滤库区
filterWarehousesInPicker() {
const keyword = this.warehouseSearchKeyword.trim().toLowerCase();
if (!keyword) {
this.filteredWarehousesInPicker = [...this.warehouses];
} else {
this.filteredWarehousesInPicker = this.warehouses.filter(warehouse => {
const name = (warehouse.warehouseName || '').toLowerCase();
return name.includes(keyword);
});
}
},
// 从选择器中选择库区
async selectWarehouseFromPicker(warehouse) {
this.warehouseId = warehouse.warehouseId;
this.warehouseName = warehouse.warehouseName;
this.warehouseKeyword = warehouse.warehouseName;
this.closeWarehousePicker();
},
// 显示物品类型选择器
showItemTypePicker() {
this.$refs.itemTypePopup.open();
},
// 关闭物品类型选择器
closeItemTypePicker() {
this.$refs.itemTypePopup.close();
},
// 选择物品类型
selectItemType(type) {
// 设置物品类型
this.itemType = type;
// 清空之前选择的物品
this.itemId = undefined;
this.selectedProductName = '';
this.selectedRawMaterialName = '';
this.closeItemTypePicker();
// 根据类型自动弹出对应的选择器
if (type === 'product') {
this.showProductPicker();
} else if (type === 'raw_material') {
this.showRawMaterialPicker();
}
},
// 扫码
handleScan() {
uni.scanCode({
success: async (res) => {
console.log('扫码结果:', res.result);
try {
const qrcodeId = res.result;
// 1. 获取二维码详情
const qrcodeRes = await getGenerateRecord(qrcodeId);
if (qrcodeRes.code !== 200) {
throw new Error('未找到二维码记录');
}
// 2. 解析content获取enter_coil_no、current_coil_no和coil_id
const qrcodeRecord = qrcodeRes.data;
const content = JSON.parse(qrcodeRecord.content);
const enterCoilNo = content.enter_coil_no;
const currentCoilNo = content.current_coil_no;
const coilId = content.coil_id && content.coil_id !== 'null' ? content.coil_id : null;
if (!enterCoilNo) {
throw new Error('二维码中未包含有效的入场钢卷号');
}
// 3. 通过追溯接口获取钢卷信息
const traceRes = await getMaterialCoilTrace(enterCoilNo, currentCoilNo);
if (traceRes.code !== 200 || !traceRes.data || !traceRes.data.records || traceRes.data.records.length === 0) {
throw new Error('未找到钢卷信息');
}
// 4. 根据二维码内容匹配对应的钢卷数据
let coilData = null;
const records = traceRes.data.records;
// 优先使用coil_id精确匹配
if (coilId) {
coilData = records.find(record => String(record.coilId) === String(coilId));
}
// 如果没找到使用currentCoilNo匹配
if (!coilData && currentCoilNo) {
coilData = records.find(record => record.currentCoilNo === currentCoilNo);
}
// 如果还是没找到,取第一条记录
if (!coilData && records.length > 0) {
coilData = records[0];
}
if (!coilData) {
throw new Error('未找到对应的钢卷数据');
}
// 5. 检查是否为历史数据
if (coilData.dataType === 0) {
uni.showModal({
title: '历史数据',
content: '此为历史记录,不允许进行合卷操作',
showCancel: false
});
return;
}
// 6. 检查是否已扫描过
const exists = this.scannedCoils.some(coil => coil.coilId === coilData.coilId);
if (exists) {
uni.showToast({
title: '该钢卷已扫描',
icon: 'none'
});
return;
}
this.scannedCoils.push(coilData);
console.log('钢卷详情:', coilData);
uni.showToast({
title: `${this.scannedCoils.length} 个钢卷扫描成功`,
icon: 'success'
});
} catch (err) {
console.error('扫码处理失败:', err);
uni.showToast({
title: err.message || '扫码信息解析失败',
icon: 'none',
duration: 2000
});
}
},
fail: (err) => {
console.error('扫码失败:', err);
uni.showToast({
title: '扫码失败,请重试',
icon: 'none'
});
}
});
},
// 移除钢卷
removeCoil(index) {
uni.showModal({
title: '确认移除',
content: '是否要移除此钢卷?',
success: (res) => {
if (res.confirm) {
this.scannedCoils.splice(index, 1);
}
}
});
},
// 重置
handleReset() {
uni.showModal({
title: '确认重置',
content: '是否要清空所有已扫描的钢卷?',
success: (res) => {
if (res.confirm) {
this.scannedCoils = [];
this.mergedCoilNo = '';
this.team = '';
this.warehouseId = undefined;
this.actualWarehouseId = undefined;
this.warehouseName = '';
this.warehouseKeyword = '';
this.itemType = '';
this.itemId = undefined;
this.selectedProductName = '';
this.selectedRawMaterialName = '';
this.grossWeight = '';
this.netWeight = '';
this.showWarehouseList = false;
}
}
});
},
// 提交合卷
handleConfirm() {
// 检查是否包含历史数据
const hasHistoryData = this.scannedCoils.some(coil => coil.dataType === 0);
if (hasHistoryData) {
uni.showModal({
title: '包含历史数据',
content: '列表中包含历史记录,不允许进行合卷操作,请移除后重试',
showCancel: false
});
return;
}
// 验证
if (this.scannedCoils.length < 2) {
uni.showToast({
title: '至少需要2个钢卷',
icon: 'none'
});
return;
}
if (!this.mergedCoilNo) {
uni.showToast({
title: '请输入新钢卷号',
icon: 'none'
});
return;
}
if (!this.team) {
uni.showToast({
title: '请输入班组名称',
icon: 'none'
});
return;
}
this.loading = true;
// 构建提交数据
// 根据后端逻辑bo是合卷后的新钢卷bo.newCoils是参与合卷的原始钢卷
const submitData = {
coilId: null, // 合卷时coilId为null
enterCoilNo: this.scannedCoils[0].enterCoilNo, // 使用第一个钢卷的入场号
supplierCoilNo: this.scannedCoils[0].supplierCoilNo, // 保留厂家原料卷号
currentCoilNo: this.mergedCoilNo,
team: this.team,
hasMergeSplit: 2, // 2表示合卷
itemType: this.itemType || this.scannedCoils[0].itemType, // 优先使用选择的itemType
itemId: this.itemId || this.scannedCoils[0].itemId, // 优先使用选择的itemId
warehouseId: this.warehouseId || this.scannedCoils[0].warehouseId, // 使用选择的库区或第一个钢卷的库区
actualWarehouseId: this.actualWarehouseId || this.scannedCoils[0].actualWarehouseId,
grossWeight: this.grossWeight ? Number(this.grossWeight) : null,
netWeight: this.netWeight ? Number(this.netWeight) : null,
newCoils: this.scannedCoils.map(coil => ({
coilId: coil.coilId,
currentCoilNo: coil.currentCoilNo
}))
};
updateMaterialCoil(submitData).then(res => {
if (res.code === 200) {
uni.showToast({
title: '合卷成功',
icon: 'success'
});
setTimeout(() => {
this.handleReset();
}, 1500);
} else {
uni.showToast({
title: res.msg || '合卷失败',
icon: 'none'
});
}
}).catch(err => {
console.error('提交失败:', err);
uni.showToast({
title: '合卷失败,请重试',
icon: 'none'
});
}).finally(() => {
this.loading = false;
});
}
}
}
</script>
<style scoped lang="scss">
.merge-container {
padding-bottom: 30rpx;
}
/* 扫码区域 */
.scan-section {
padding: 60rpx 40rpx;
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.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;
}
.scan-tip {
font-size: 28rpx;
color: #666;
}
.scan-hint {
font-size: 24rpx;
color: #34c759;
font-weight: 500;
}
}
}
/* 钢卷列表 */
.coil-list {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
}
.card-title {
display: flex;
align-items: center;
margin-bottom: 25rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
.title-dot {
width: 8rpx;
height: 28rpx;
background: #34c759;
border-radius: 4rpx;
margin-right: 12rpx;
}
.title-text {
flex: 1;
font-size: 32rpx;
font-weight: 600;
color: #333;
}
}
.coil-item {
display: flex;
align-items: center;
background: #f8f9fa;
border-radius: 12rpx;
padding: 24rpx;
margin-bottom: 20rpx;
position: relative;
&:last-child {
margin-bottom: 0;
}
.coil-content {
display: flex;
flex: 1;
gap: 20rpx;
.coil-index {
width: 60rpx;
height: 60rpx;
background: #34c759;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
font-weight: bold;
flex-shrink: 0;
&.index-history {
background: #999;
}
}
.coil-info {
flex: 1;
.coil-row {
display: flex;
align-items: center;
margin-bottom: 8rpx;
&:last-child {
margin-bottom: 0;
}
.coil-label {
font-size: 24rpx;
color: #666;
min-width: 150rpx;
}
.coil-value {
font-size: 24rpx;
color: #333;
font-weight: 500;
}
.history-tag {
font-size: 20rpx;
padding: 2rpx 10rpx;
background: #f8d7da;
color: #721c24;
border-radius: 8rpx;
margin-left: 10rpx;
}
}
}
}
.coil-remove {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
color: #ff4d4f;
font-size: 32rpx;
margin-left: 10rpx;
&:active {
opacity: 0.6;
}
}
}
/* 表单卡片 */
.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;
.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: #34c759;
}
}
.picker-input {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 12rpx;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
transition: all 0.3s;
&:active {
background: #fff;
border-color: #34c759;
}
.picker-text {
flex: 1;
font-size: 28rpx;
color: #333;
&.picker-placeholder {
color: #999;
}
}
.picker-arrow {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
}
}
/* 操作者信息 */
.operator-info {
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0;
margin-top: 20rpx;
.operator-label {
font-size: 26rpx;
color: #999;
}
.operator-name {
font-size: 26rpx;
color: #34c759;
font-weight: 500;
}
}
/* 操作按钮 */
.action-buttons {
display: flex;
gap: 20rpx;
margin-top: 30rpx;
.btn {
flex: 1;
height: 88rpx;
border-radius: 12rpx;
font-size: 30rpx;
font-weight: 500;
border: none;
transition: all 0.2s;
&:active {
transform: scale(0.98);
}
&[disabled] {
opacity: 0.6;
}
}
.btn-secondary {
background: #f5f5f5;
color: #666;
}
.btn-primary {
background: linear-gradient(135deg, #34c759 0%, #30b350 100%);
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(52, 199, 89, 0.3);
}
}
/* 提示卡片 */
.tip-card {
background: #fff3cd;
border-radius: 12rpx;
padding: 30rpx;
text-align: center;
.tip-text {
font-size: 26rpx;
color: #856404;
}
}
/* 库区选择弹窗 */
.warehouse-popup {
background: #fff;
border-radius: 24rpx 24rpx 0 0;
max-height: 70vh;
.popup-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.popup-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
}
.popup-close {
font-size: 40rpx;
color: #999;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.popup-search {
padding: 20rpx 30rpx;
border-bottom: 1rpx solid #f0f0f0;
.search-input {
width: 100%;
height: 80rpx;
padding: 0 20rpx;
background: #f8f9fa;
border: 2rpx solid #e8e8e8;
border-radius: 10rpx;
font-size: 28rpx;
color: #333;
box-sizing: border-box;
&:focus {
background: #fff;
border-color: #34c759;
}
}
}
.popup-body {
max-height: 400rpx;
.warehouse-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
&:active {
background: #e8f5e8;
}
.warehouse-name {
flex: 1;
font-size: 28rpx;
color: #333;
}
.warehouse-check {
font-size: 32rpx;
color: #34c759;
font-weight: bold;
}
}
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
}
}
</style>