Files
klp-mono/apps/hand-factory/components/panels/code/typing.vue

1344 lines
33 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="typing-container">
<!-- 扫码按钮 -->
<view class="scan-section" v-if="!form.coilId">
<view class="scan-btn-wrapper" @click="handleScan">
<view class="scan-icon">
<text class="icon-camera">📷</text>
</view>
<text class="scan-tip">点击扫描二维码</text>
</view>
</view>
<!-- 钢卷基本信息 -->
<view class="info-card" v-if="form.coilId">
<view class="card-title">
<text class="title-dot"></text>
<text class="title-text">钢卷信息</text>
<view class="status-badge" :class="'status-' + coilDetail.dataType" v-if="coilDetail.dataType !== undefined">
{{ coilDetail.dataType === 1 ? '当前数据' : '历史数据' }}
</view>
<view class="more-btn" @click.stop="showBomDialog" v-if="bomItemList && 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">{{ currentWarehouseName || '未分配' }}</text>
</view>
<view class="info-item" v-if="materialDetail">
<text class="item-label">原材料</text>
<text class="item-value">{{ materialDetail.rawMaterialName || '-' }}</text>
</view>
<view class="info-item" v-if="materialDetail">
<text class="item-label">规格</text>
<text class="item-value">{{ materialDetail.specification || '-' }}</text>
</view>
</view>
</view>
<!-- 历史数据提示 -->
<view class="warning-card" v-if="form.coilId && coilDetail.dataType === 0">
<view class="warning-icon"></view>
<view class="warning-content">
<text class="warning-title">历史数据</text>
<text class="warning-desc">此为历史记录仅供查看不允许进行修改操作</text>
</view>
</view>
<!-- 表单区域 -->
<view class="form-card" v-if="form.coilId" @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="form.currentCoilNo"
placeholder="请输入当前钢卷号"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view>
<!-- 班组 -->
<view class="form-item">
<text class="form-label">班组</text>
<input
v-model="form.team"
placeholder="请输入班组名称"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view>
<!-- 库区选择 - 滚筒选择器 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">目标库区</text>
<view
class="picker-input"
@click="coilDetail.dataType !== 0 && showWarehousePicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !currentWarehouseName }">
{{ currentWarehouseName || '请选择目标库区' }}
</text>
<text class="picker-arrow" v-if="coilDetail.dataType !== 0"></text>
</view>
</view>
<!-- 产品选择仅当选择了成品库区时显示 -->
<view class="form-item form-item-optional" v-if="form.itemType === 'product'">
<text class="form-label-optional">选择产品</text>
<view
class="picker-input"
@click="coilDetail.dataType !== 0 && showProductPicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedProductName }">
{{ selectedProductName || '请选择产品' }}
</text>
<text class="picker-arrow" v-if="coilDetail.dataType !== 0"></text>
</view>
</view>
<!-- 原材料选择仅当选择了原材料库区时显示 -->
<view class="form-item form-item-optional" v-if="form.itemType === 'raw_material'">
<text class="form-label-optional">选择原材料</text>
<view
class="picker-input"
@click="coilDetail.dataType !== 0 && showRawMaterialPicker()"
:class="{ 'picker-input-disabled': coilDetail.dataType === 0 }"
>
<text class="picker-text" :class="{ 'picker-placeholder': !selectedRawMaterialName }">
{{ selectedRawMaterialName || '请选择原材料' }}
</text>
<text class="picker-arrow" v-if="coilDetail.dataType !== 0"></text>
</view>
</view>
<!-- 毛重 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">毛重 ()</text>
<input
v-model="form.grossWeight"
type="digit"
placeholder="请输入毛重(选填)"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</view>
<!-- 净重 -->
<view class="form-item form-item-optional">
<text class="form-label-optional">净重 ()</text>
<input
v-model="form.netWeight"
type="digit"
placeholder="请输入净重(选填)"
class="form-input"
:disabled="coilDetail.dataType === 0"
:class="{ 'form-input-disabled': coilDetail.dataType === 0 }"
/>
</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
v-if="coilDetail.dataType === 1"
class="btn btn-primary"
@click="handleConfirm"
:disabled="loading"
>
{{ loading ? '提交中...' : '保存' }}
</button>
</view>
</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="form.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 scroll-y class="popup-body">
<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="form.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 scroll-y class="popup-body">
<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="form.itemId === material.rawMaterialId"></text>
</view>
<view class="empty-tip" v-if="!filteredRawMaterialsInPicker || filteredRawMaterialsInPicker.length === 0">
<text>未找到匹配的原材料</text>
</view>
</scroll-view>
</view>
</uni-popup>
<!-- BOM弹窗 -->
<uni-popup ref="bomPopup" type="bottom">
<view class="bom-popup">
<view class="popup-header">
<text class="popup-title">BOM 清单</text>
<text class="popup-close" @click="closeBomDialog"></text>
</view>
<scroll-view class="popup-body" scroll-y>
<view class="bom-item" v-for="(item, index) in bomItemList" :key="index">
<view class="bom-index">{{ index + 1 }}</view>
<view class="bom-content">
<view class="bom-row">
<text class="bom-label">{{ item.attrKey }}:</text>
<text class="bom-value">{{ item.attrValue }}</text>
</view>
<view class="bom-row" v-if="item.remark">
<text class="bom-label">备注:</text>
<text class="bom-value">{{ item.remark }}</text>
</view>
</view>
</view>
<view class="empty-tip" v-if="!bomItemList || bomItemList.length === 0">
<text>暂无参数数据</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 { getRawMaterial, listRawMaterial } from '@/api/wms/rawMaterial.js'
import { listProduct } from '@/api/wms/product.js'
export default {
data() {
return {
form: {
coilId: undefined,
itemType: '',
itemId: undefined,
team: '',
currentCoilNo: '',
warehouseId: undefined,
warehouseName: '',
grossWeight: '',
netWeight: ''
},
coilDetail: {},
materialDetail: null,
bomItemList: [],
warehouses: [],
filteredWarehouses: [],
warehouseKeyword: '',
showWarehouseList: false,
currentWarehouseName: '',
warehouseSearchKeyword: '',
filteredWarehousesInPicker: [],
products: [], // 产品列表
productSearchKeyword: '',
filteredProductsInPicker: [],
selectedProductName: '', // 已选择的产品名称
rawMaterials: [], // 原材料列表
rawMaterialSearchKeyword: '',
filteredRawMaterialsInPicker: [],
selectedRawMaterialName: '', // 已选择的原材料名称
loading: false,
qrcodeStatus: 1 // 二维码状态0=历史码1=当前有效码
}
},
computed: {
// 获取当前操作者昵称
operatorName() {
return this.$store.state.user.nickName || this.$store.state.user.name || '未知'
}
},
onLoad() {
this.loadWarehouses();
this.loadProducts();
this.loadRawMaterials();
},
mounted() {
this.loadWarehouses();
this.loadProducts();
this.loadRawMaterials();
},
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() {
console.log('过滤产品,关键词:', this.productSearchKeyword);
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.form.itemId = product.productId;
this.form.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() {
console.log('过滤原材料,关键词:', this.rawMaterialSearchKeyword);
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.form.itemId = material.rawMaterialId;
this.form.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(item => {
const name = (item.warehouseName || '').toLowerCase();
return name.includes(keyword);
});
}
console.log('过滤后库区数量:', this.filteredWarehouses.length);
this.showWarehouseList = true;
},
// 选择库区
selectWarehouse(warehouse) {
this.form.warehouseId = warehouse.warehouseId;
this.form.warehouseName = warehouse.warehouseName;
this.warehouseKeyword = warehouse.warehouseName;
// 关闭搜索结果列表
this.$nextTick(() => {
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.form.warehouseId = warehouse.warehouseId;
this.form.warehouseName = warehouse.warehouseName;
this.currentWarehouseName = warehouse.warehouseName;
this.closeWarehousePicker();
// 根据库区ID判断类型999为成品库其他为原材料库
if (warehouse.warehouseId === 999) {
// 成品库,显示产品选择器
this.form.itemType = 'product';
this.showProductPicker();
} else {
// 其他库区,显示原材料选择器
this.form.itemType = 'raw_material';
this.showRawMaterialPicker();
}
},
// 扫码
handleScan() {
uni.scanCode({
success: async (res) => {
console.log('扫码结果:', res.result);
try {
// 扫码结果是二维码ID (recordId)
const qrcodeId = res.result;
// 1. 通过二维码ID获取二维码详情
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;
// 保存二维码状态0=历史码1=当前有效码)
this.qrcodeStatus = qrcodeRecord.status || 1;
if (!enterCoilNo) {
throw new Error('二维码中未包含有效的入场钢卷号');
}
// 3. 如果是历史码,提示用户
if (this.qrcodeStatus === 0) {
uni.showToast({
title: '历史二维码,仅供查看',
icon: 'none',
duration: 2000
});
}
// 4. 通过入场钢卷号查询钢卷追溯信息
const traceRes = await getMaterialCoilTrace(enterCoilNo, currentCoilNo);
if (traceRes.code !== 200 || !traceRes.data || !traceRes.data.records || traceRes.data.records.length === 0) {
throw new Error('未找到钢卷信息');
}
// 5. 根据二维码内容匹配对应的钢卷数据
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('未找到对应的钢卷数据');
}
// 保存钢卷详情
this.coilDetail = coilData;
// 填充表单数据
this.form.coilId = coilData.coilId;
this.form.currentCoilNo = coilData.currentCoilNo || '';
this.form.team = coilData.team || '';
this.form.itemType = coilData.itemType || '';
this.form.itemId = coilData.itemId;
this.form.warehouseId = coilData.warehouseId;
this.form.grossWeight = coilData.grossWeight || '';
this.form.netWeight = coilData.netWeight || '';
// 设置当前库区名称(用于显示)
if (coilData.warehouse && coilData.warehouse.warehouseName) {
this.currentWarehouseName = coilData.warehouse.warehouseName;
}
// 保存原材料详情
if (coilData.rawMaterial) {
this.materialDetail = coilData.rawMaterial;
}
// 保存BOM项目列表
if (coilData.bomItemList) {
this.bomItemList = coilData.bomItemList;
}
console.log('钢卷详情:', coilData);
uni.showToast({
title: '扫码成功',
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'
});
}
});
},
// 显示BOM弹窗
showBomDialog() {
this.$refs.bomPopup.open();
},
// 关闭BOM弹窗
closeBomDialog() {
this.$refs.bomPopup.close();
},
// 关闭库区搜索列表
closeWarehouseList() {
this.showWarehouseList = false;
},
// 重新扫码
handleReset() {
uni.showModal({
title: '确认重新扫码',
content: '是否要清空当前数据并重新扫码?',
success: (res) => {
if (res.confirm) {
this.form = {
coilId: undefined,
itemType: '',
itemId: undefined,
team: '',
currentCoilNo: '',
warehouseId: undefined,
warehouseName: '',
grossWeight: '',
netWeight: ''
};
this.coilDetail = {};
this.materialDetail = null;
this.bomItemList = [];
this.warehouseKeyword = '';
this.currentWarehouseName = '';
this.selectedProductName = '';
this.filteredWarehouses = this.warehouses;
this.qrcodeStatus = 1; // 重置二维码状态
}
}
});
},
// 提交
handleConfirm() {
// 历史数据不允许修改
if (this.coilDetail.dataType === 0) {
uni.showToast({ title: '历史数据不允许修改', icon: 'none' });
return;
}
// 验证必填项
if (!this.form.currentCoilNo) {
uni.showToast({ title: '请输入当前钢卷号', icon: 'none' });
return;
}
if (!this.form.team) {
uni.showToast({ title: '请输入班组', icon: 'none' });
return;
}
this.loading = true;
const submitData = {
coilId: this.form.coilId,
enterCoilNo: this.coilDetail.enterCoilNo, // 添加入场钢卷号
supplierCoilNo: this.coilDetail.supplierCoilNo, // 保留厂家原料卷号
currentCoilNo: this.form.currentCoilNo,
itemType: this.form.itemType,
itemId: this.form.itemId,
team: this.form.team,
warehouseId: this.form.warehouseId,
grossWeight: this.form.grossWeight ? Number(this.form.grossWeight) : null,
netWeight: this.form.netWeight ? Number(this.form.netWeight) : null
};
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">
.typing-container {
padding-bottom: 30rpx;
}
/* 扫码区域 */
.scan-section {
padding: 80rpx 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: 30rpx;
.scan-icon {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
background: linear-gradient(135deg, #007aff 0%, #0051d5 100%);
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 24rpx rgba(0, 122, 255, 0.3);
&:active {
transform: scale(0.95);
}
}
.icon-camera {
font-size: 70rpx;
}
.scan-tip {
font-size: 28rpx;
color: #666;
}
}
}
/* 卡片样式 */
.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);
}
/* 警告卡片 */
.warning-card {
background: #fff2f0;
border: 2rpx solid #ffccc7;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
display: flex;
align-items: center;
gap: 20rpx;
.warning-icon {
font-size: 48rpx;
flex-shrink: 0;
}
.warning-content {
flex: 1;
.warning-title {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #cf1322;
margin-bottom: 8rpx;
}
.warning-desc {
display: block;
font-size: 24rpx;
color: #a8071a;
line-height: 1.4;
}
}
}
.card-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 25rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f0f0f0;
.title-dot {
width: 8rpx;
height: 28rpx;
background: #007aff;
border-radius: 4rpx;
margin-right: 12rpx;
}
.title-text {
flex: 1;
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.status-badge {
font-size: 22rpx;
padding: 4rpx 12rpx;
border-radius: 12rpx;
margin-right: 10rpx;
&.status-1 {
background: #d1f2eb;
color: #0c6957;
}
&.status-0 {
background: #f8d7da;
color: #721c24;
}
}
.more-btn {
display: flex;
align-items: center;
gap: 8rpx;
padding: 8rpx 16rpx;
background: #f0f7ff;
border-radius: 20rpx;
border: 1rpx solid #007aff;
.icon-more {
font-size: 24rpx;
color: #007aff;
}
.more-text {
font-size: 24rpx;
color: #007aff;
}
}
}
/* 信息网格 */
.info-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
.info-item {
flex: 1;
min-width: 45%;
background: #f8f9fa;
padding: 20rpx;
border-radius: 12rpx;
.item-label {
display: block;
font-size: 24rpx;
color: #999;
margin-bottom: 10rpx;
}
.item-value {
display: block;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
}
/* 详情网格 */
.detail-grid {
.detail-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 0;
border-bottom: 1rpx solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.detail-label {
font-size: 28rpx;
color: #666;
}
.detail-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
}
}
/* 表单项 */
.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;
}
}
}
/* 选择器输入框 */
.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: #007aff;
}
&.picker-input-disabled {
background: #f5f5f5;
color: #999;
cursor: not-allowed;
}
.picker-text {
flex: 1;
font-size: 28rpx;
color: #333;
&.picker-placeholder {
color: #999;
}
}
.picker-arrow {
font-size: 24rpx;
color: #999;
margin-left: 10rpx;
}
}
/* 库区选择弹窗 */
.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: #007aff;
}
}
}
.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: #f0f7ff;
}
.warehouse-name {
flex: 1;
font-size: 28rpx;
color: #333;
}
.warehouse-check {
font-size: 32rpx;
color: #007aff;
font-weight: bold;
}
}
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
}
}
/* 操作者信息 */
.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: #007aff;
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, #007aff 0%, #0051d5 100%);
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(0, 122, 255, 0.3);
}
}
/* BOM弹窗 */
.bom-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-body {
padding: 30rpx;
max-height: 500rpx;
.bom-item {
display: flex;
gap: 20rpx;
padding: 24rpx;
background: #f8f9fa;
border-radius: 12rpx;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
.bom-index {
width: 60rpx;
height: 60rpx;
background: #007aff;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
font-weight: bold;
flex-shrink: 0;
}
.bom-content {
flex: 1;
.bom-row {
display: flex;
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
.bom-label {
font-size: 26rpx;
color: #666;
min-width: 120rpx;
}
.bom-value {
font-size: 26rpx;
color: #333;
font-weight: 500;
}
}
}
}
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
}
}
</style>