feat: 优化手动进仓扫码流程并升至1.1.22

This commit is contained in:
2026-11-08 22:38:49 +08:00
parent 5b6690b4d8
commit 4d3f767e16
7 changed files with 216 additions and 139 deletions
+13 -9
View File
@@ -46,12 +46,12 @@ export const FABRIC_INFO_FIELDS = [
/** 细码表格列(不含操作列) */
export const FINE_CODE_TABLE_COLUMNS = [
{ label: '序号', key: 'seq', width: 70 },
{ label: '卷号', key: 'roll_no', width: 90 },
{ label: '匹数', key: 'roll', width: 90 },
{ label: '数量(重量)', key: 'weight', width: 120 },
{ label: '条码', key: 'bar_code', width: 260 },
{ label: '仓位', key: 'position', width: 110 },
{ label: '序号', key: 'seq', width: 90 },
{ label: '卷号', key: 'roll_no', width: 110 },
{ label: '匹数', key: 'roll', width: 100 },
{ label: '数量(重量)', key: 'weight', width: 160 },
{ label: '条码', key: 'bar_code', width: 280 },
{ label: '仓位', key: 'position', width: 140 },
];
/** 审核状态变更操作配置(apiKey 对应 gfmOtherDeliveryOrder 下的方法名) */
@@ -490,7 +490,8 @@ export function orderToFormFields(order) {
export function getFineCodeTableColumns(readonly) {
const cols = [...FINE_CODE_TABLE_COLUMNS];
if (!readonly) cols.push({ label: '操作', key: 'action', width: 90 });
// 操作列放前面,避免 PDA 小屏横向滚动后才看到删除
if (!readonly) cols.splice(1, 0, { label: '操作', key: 'action', width: 160 });
return cols;
}
@@ -516,7 +517,7 @@ export function getFineCodeTableWidth(columns) {
* @param {Vue} vm 页面实例,需有 $u.api 与 showError
* @param {{ orderId: number, action: string, onSuccess?: Function }} options
*/
export function confirmOrderStatusAction(vm, { orderId, action, onSuccess }) {
export function confirmOrderStatusAction(vm, { orderId, action, onSuccess, onCancel }) {
const cfg = STATUS_ACTION_CONFIG[action];
if (!cfg || !orderId) return;
const api = vm.$u.api.gfmOtherDeliveryOrder;
@@ -526,7 +527,10 @@ export function confirmOrderStatusAction(vm, { orderId, action, onSuccess }) {
title: '提示',
content: cfg.msg,
success: (res) => {
if (!res.confirm) return;
if (!res.confirm) {
if (typeof onCancel === 'function') onCancel();
return;
}
uni.showLoading({ title: '处理中...' });
requestFn(buildStatusParam(orderId, cfg.status))
.then(() => {
+15 -11
View File
@@ -10,14 +10,12 @@
@input="$emit('input', $event.detail.value)"
@confirm="$emit('scan')"
/>
<u-icon
v-if="showPhoneScan"
class="fabric-out-phoneScanIcon"
name="scan"
size="80"
color="#2979ff"
@click="$emit('phone-scan')"
/>
<view
class="fabric-out-toolbarIcon"
@click.stop="$emit('phone-scan')"
>
<u-icon name="scan" size="44" color="#595959" />
</view>
<checkbox-group @change="$emit('delete-mode-change', $event)">
<label class="fabric-out-delCheck">
<checkbox :checked="deleteMode" />删除
@@ -37,7 +35,6 @@ export default {
deleteMode: { type: Boolean, default: false },
message: { type: String, default: '' },
disabledTip: { type: String, default: '当前状态不可扫码' },
showPhoneScan: { type: Boolean, default: false },
},
};
</script>
@@ -45,9 +42,16 @@ export default {
<style scoped lang="scss">
@import '@/pages/storefabric/storeFabricBusinessOutPage.scss';
.fabric-out-phoneScanIcon {
.fabric-out-toolbarIcon {
display: flex;
align-items: center;
justify-content: center;
width: 72rpx;
height: 72rpx;
margin-left: 8rpx;
padding: 10rpx 16rpx;
border-radius: 8rpx;
border: 1rpx solid #d9d9d9;
background: #f7f7f7;
flex-shrink: 0;
}
</style>
+40 -12
View File
@@ -21,11 +21,17 @@
:class="{ actionCell: col.key === 'action' && !readonly }"
:style="cellStyle(col)"
@click="onCellTap(col.key, rowIndex)"
>{{ row[col.key] }}</view>
>
<text
v-if="col.key === 'action' && !readonly"
class="deleteBtn"
>{{ row[col.key] }}</text>
<template v-else>{{ row[col.key] }}</template>
</view>
</view>
</view>
</scroll-view>
<view v-if="!readonly && list.length" class="tableTip">点击「操作」列删除,将调用扫码删除接口</view>
<view v-if="!readonly && list.length" class="tableTip">点击「删除」将调用扫码删除接口</view>
</view>
</u-popup>
</template>
@@ -81,9 +87,11 @@ export default {
};
</script>
<style scoped>
<style scoped lang="scss">
@import '@/common/pda-typography.scss';
.popupWrap {
padding: 24rpx 16rpx 30rpx;
padding: 28rpx 16rpx 32rpx;
max-height: 80vh;
box-sizing: border-box;
display: flex;
@@ -91,18 +99,18 @@ export default {
overflow: hidden;
}
.popupTitle {
font-size: 32rpx;
font-size: $pda-font-popup-title;
font-weight: bold;
text-align: center;
margin-bottom: 20rpx;
margin-bottom: 24rpx;
color: #333;
flex-shrink: 0;
}
.emptyTip {
text-align: center;
color: #999;
padding: 40rpx 0;
font-size: 28rpx;
padding: 48rpx 0;
font-size: $pda-font-popup-sub;
}
.tableScroll {
width: 100%;
@@ -118,6 +126,7 @@ export default {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: stretch;
border-bottom: 1rpx solid #e1e1e1;
}
.tableRow:last-child {
@@ -131,8 +140,12 @@ export default {
}
.tableCell {
flex-shrink: 0;
padding: 12rpx 8rpx;
font-size: 22rpx;
display: flex;
align-items: center;
justify-content: center;
min-height: $pda-row-min-height;
padding: 16rpx 10rpx;
font-size: $pda-font-popup-item;
color: #333;
text-align: center;
border-right: 1rpx solid #e1e1e1;
@@ -146,13 +159,28 @@ export default {
.headCell {
font-weight: bold;
color: #3e3e3e;
min-height: 80rpx;
}
.actionCell {
padding: 12rpx 8rpx;
}
.deleteBtn {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 120rpx;
min-height: 72rpx;
padding: 0 20rpx;
border-radius: 8rpx;
background: #fff1f0;
border: 1rpx solid #ffa39e;
color: #f5222d;
font-size: $pda-font-action;
line-height: 1.2;
}
.tableTip {
margin-top: 16rpx;
font-size: 22rpx;
margin-top: 20rpx;
font-size: $pda-font-popup-sub;
color: #999;
text-align: center;
flex-shrink: 0;
+2 -2
View File
@@ -2,8 +2,8 @@
"name" : "浩拓织厂",
"appid" : "__UNI__F79F300",
"description" : "周尚-浩拓织厂",
"versionName" : "1.1.21",
"versionCode" : 121,
"versionName" : "1.1.22",
"versionCode" : 122,
"transformPx" : false,
"app-plus" : {
"optimization" : {
@@ -48,7 +48,6 @@
:delete-mode="BarCodeDelStatus"
:message="BillDataMessage"
disabled-tip="请先提交保存后再扫码"
:show-phone-scan="usePhoneScanFallback"
@input="QRBarCode = $event"
@scan="handleScan"
@phone-scan="handlePhoneScan"
@@ -41,7 +41,6 @@
:value="QRBarCode"
:delete-mode="BarCodeDelStatus"
:message="BillDataMessage"
:show-phone-scan="usePhoneScanFallback"
@input="QRBarCode = $event"
@scan="handleScan"
@phone-scan="handlePhoneScan"
+146 -103
View File
@@ -9,39 +9,15 @@
</template>
</common-navbar>
<view class="manual-in__scan">
<input
class="manual-in__scan-input"
type="text"
confirm-type="done"
:focus="scanFocus"
v-model="scanCode"
placeholder="请点击扫描/输入布票编码"
placeholder-class="manual-in__placeholder"
@confirm="onScanConfirm"
/>
</view>
<view class="manual-in__panel">
<view class="manual-in__row">
<text class="manual-in__label">布票编码</text>
<text class="manual-in__value">{{ detail.fabric_piece_code || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">生产单号</text>
<text class="manual-in__value">{{ detail.production_order_no || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">机台</text>
<text class="manual-in__value">{{ detail.machine_number || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">布种名称</text>
<text class="manual-in__value">{{ detail.grey_fabric_name || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">坯布编号</text>
<text class="manual-in__value">{{ detail.grey_fabric_code || '-' }}</text>
<view class="manual-in__row manual-in__row--input" @click="openInspectorPicker">
<text class="manual-in__label">查布工</text>
<view class="manual-in__right">
<text :class="detail.inspector_name ? 'manual-in__field-text' : 'manual-in__placeholder'">
{{ detail.inspector_name || '请选择查布工' }}
</text>
<text class="manual-in__action" @click.stop="clearInspector">取消</text>
</view>
</view>
<view class="manual-in__row manual-in__row--input">
<text class="manual-in__label">重量</text>
@@ -66,15 +42,6 @@
<text class="manual-in__action" @click.stop="clearLevel">取消</text>
</view>
</view>
<view class="manual-in__row manual-in__row--input" @click="openInspectorPicker">
<text class="manual-in__label">查布工</text>
<view class="manual-in__right">
<text :class="detail.inspector_name ? 'manual-in__field-text' : 'manual-in__placeholder'">
{{ detail.inspector_name || '请选择查布工' }}
</text>
<text class="manual-in__action" @click.stop="clearInspector">取消</text>
</view>
</view>
<view class="manual-in__row manual-in__row--input">
<text class="manual-in__label">存放仓位</text>
<view class="manual-in__right">
@@ -88,22 +55,62 @@
<text class="manual-in__action" @click="editWarehouseBin">修改</text>
</view>
</view>
</view>
<view class="manual-in__scan">
<input
class="manual-in__scan-input"
type="text"
confirm-type="done"
:confirm-hold="true"
:focus="scanFocus"
v-model="scanCode"
placeholder="先选查布工并填写信息,再扫描布票编码"
placeholder-class="manual-in__placeholder"
@confirm="onScanConfirm"
/>
<view
v-if="scanCode"
class="manual-in__scan-icon"
@click.stop="clearScanCode"
>
<u-icon name="close-circle-fill" size="44" color="#bfbfbf" />
</view>
<view
class="manual-in__scan-icon"
@click.stop="handlePhoneScan"
>
<u-icon name="scan" size="44" color="#595959" />
</view>
</view>
<view class="manual-in__panel">
<view class="manual-in__row">
<text class="manual-in__label">布票编码</text>
<text class="manual-in__value">{{ detail.fabric_piece_code || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">生产单号</text>
<text class="manual-in__value">{{ detail.production_order_no || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">机台</text>
<text class="manual-in__value">{{ detail.machine_number || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">布种名称</text>
<text class="manual-in__value">{{ detail.grey_fabric_name || '-' }}</text>
</view>
<view class="manual-in__row">
<text class="manual-in__label">坯布编号</text>
<text class="manual-in__value">{{ detail.grey_fabric_code || '-' }}</text>
</view>
<view class="manual-in__row" v-if="detail.volume_number != null && detail.volume_number !== ''">
<text class="manual-in__label">卷号</text>
<text class="manual-in__value">{{ detail.volume_number }}</text>
</view>
</view>
<view class="manual-in__footer">
<u-button
type="primary"
shape="circle"
:loading="submitting"
:disabled="submitting || loadingDetail"
@click="submitInWarehouse"
>确定进仓</u-button>
</view>
<SearchSelectPopup
:show.sync="levelPickerShow"
title="选择等级"
@@ -217,12 +224,19 @@ export default {
this.loadInspectorOptions();
},
onShow() {
this.scanFocus = false;
this.$nextTick(() => {
this.scanFocus = true;
});
this.refocusScanInput(50);
},
onUnload() {
clearTimeout(this._scanFocusTimer);
},
methods: {
refocusScanInput(delay = 120) {
clearTimeout(this._scanFocusTimer);
this.scanFocus = false;
this._scanFocusTimer = setTimeout(() => {
this.scanFocus = true;
}, delay);
},
navToSetting() {
uni.navigateTo({ url: '/pages/sys/user/scan-settings' });
},
@@ -330,6 +344,22 @@ export default {
if (!code) return;
this.fetchScanDetail(code);
},
clearScanCode() {
this.scanCode = '';
this.refocusScanInput();
},
handlePhoneScan() {
const err = this.validateBeforeScan();
if (err) {
this.$u.toast(err);
return;
}
this.openPhoneScan({
callback: (scanResult) => {
this.handleScanCode(scanResult);
},
});
},
onScanConfirm() {
const code = String(this.scanCode || '').trim();
if (!code) {
@@ -338,33 +368,60 @@ export default {
}
this.fetchScanDetail(code);
},
validateBeforeScan() {
const inspectorName = String(this.detail.inspector_name || '').trim();
if (!inspectorName && (this.detail.inspector_id == null || this.detail.inspector_id === '')) {
return '请先选择查布工';
}
if (toWeightInt(this.weightKg) == null) {
return '请先输入有效重量';
}
return '';
},
async fetchScanDetail(code) {
if (this.loadingDetail) return;
if (this.loadingDetail || this.submitting) return;
const err = this.validateBeforeScan();
if (err) {
this.$u.toast(err);
return;
}
this.loadingDetail = true;
this.scanCode = code;
let detailOk = false;
try {
const res = await this.$u.api.productionScheduleOrder.getScanFineCodeDetail({
fabric_piece_code: code,
});
this.applyScanDetail(res, code);
detailOk = true;
} catch (error) {
console.log('扫码获取细码失败', error);
const kept = this.keepFormFields();
this.detail = {
...emptyDetail(),
fabric_piece_code: code,
inspector_id: this.detail.inspector_id,
inspector_name: this.detail.inspector_name,
...kept,
};
this.weightKg = '';
this.scanCode = '';
this.refocusScanInput(200);
} finally {
this.loadingDetail = false;
}
if (detailOk) {
await this.submitInWarehouse();
}
},
keepFormFields() {
return {
grey_fabric_level_id: normalizeLevelIds(this.detail.grey_fabric_level_id),
grey_fabric_level_name: this.detail.grey_fabric_level_name || '',
inspector_id: this.detail.inspector_id,
inspector_name: this.detail.inspector_name || '',
};
},
applyScanDetail(res, fallbackCode) {
const data = res || {};
const levelIds = normalizeLevelIds(data.grey_fabric_level_id);
const hasIncomingInspector = data.inspector_id != null && data.inspector_id !== ''
|| String(data.inspector_name || '').trim();
const kept = this.keepFormFields();
this.detail = {
...emptyDetail(),
fabric_piece_code: data.fabric_piece_code || fallbackCode || '',
@@ -372,21 +429,11 @@ export default {
machine_number: data.machine_number || '',
grey_fabric_name: data.grey_fabric_name || '',
grey_fabric_code: data.grey_fabric_code || '',
inspection_weight: formatDisplayWeightKg(data.inspection_weight) ? data.inspection_weight : null,
grey_fabric_level_id: levelIds,
grey_fabric_level_name: Array.isArray(data.grey_fabric_level_name)
? data.grey_fabric_level_name.filter(Boolean).join('、')
: (data.grey_fabric_level_name || ''),
inspector_id: hasIncomingInspector && data.inspector_id != null && data.inspector_id !== ''
? data.inspector_id
: this.detail.inspector_id,
inspector_name: hasIncomingInspector
? (data.inspector_name || this.detail.inspector_name || '')
: (this.detail.inspector_name || ''),
inspection_weight: toWeightInt(this.weightKg),
volume_number: data.volume_number != null && data.volume_number !== '' ? data.volume_number : null,
...kept,
};
this.weightKg = formatDisplayWeightKg(data.inspection_weight);
this.scanCode = this.detail.fabric_piece_code;
util.playSpeak('扫码成功');
},
async submitInWarehouse() {
const fabricPieceCode = String(this.detail.fabric_piece_code || this.scanCode || '').trim();
@@ -440,26 +487,21 @@ export default {
this.resetForNextScan();
} catch (error) {
console.log('手动进仓失败', error);
this.scanCode = '';
this.refocusScanInput(200);
} finally {
this.submitting = false;
}
},
resetForNextScan() {
const inspectorId = this.detail.inspector_id;
const inspectorName = this.detail.inspector_name;
const kept = this.keepFormFields();
this.scanCode = '';
this.detail = {
...emptyDetail(),
inspector_id: inspectorId,
inspector_name: inspectorName,
...kept,
};
this.weightKg = '';
this.$nextTick(() => {
this.scanFocus = false;
this.$nextTick(() => {
this.scanFocus = true;
});
});
// toast 会抢焦点,稍后再聚焦,方便连续扫码
this.refocusScanInput(600);
},
},
};
@@ -471,7 +513,7 @@ export default {
.manual-in {
min-height: 100vh;
background: #f5f6f8;
padding-bottom: 180rpx;
padding-bottom: 40rpx;
box-sizing: border-box;
}
@@ -487,14 +529,31 @@ export default {
margin: 16rpx 0;
padding: 0 28rpx;
background: #fff;
display: flex;
align-items: center;
gap: 12rpx;
}
.manual-in__scan-input {
flex: 1;
min-width: 0;
height: $pda-scan-input-height;
font-size: $pda-font-body;
color: #202328;
}
.manual-in__scan-icon {
display: flex;
align-items: center;
justify-content: center;
width: 72rpx;
height: 72rpx;
flex-shrink: 0;
border-radius: 8rpx;
border: 1rpx solid #d9d9d9;
background: #f7f7f7;
}
.manual-in__placeholder {
color: #b0b4bb;
font-size: $pda-font-placeholder;
@@ -569,20 +628,4 @@ export default {
color: #2f78e6;
flex-shrink: 0;
}
.manual-in__footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 24rpx 40rpx calc(24rpx + env(safe-area-inset-bottom));
background: #fff;
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.04);
}
::v-deep .manual-in__footer .u-btn {
height: $pda-button-height !important;
line-height: $pda-button-height !important;
font-size: $pda-font-button !important;
}
</style>