feat: 更新出仓扫码页并升至1.1.18

This commit is contained in:
2026-11-02 14:24:06 +08:00
parent 61bb43f759
commit 804e1a8f2b
7 changed files with 283 additions and 167 deletions
+45 -1
View File
@@ -125,7 +125,8 @@ export function getFineCodeDisplayWeight(fineCode) {
*/
export function normalizeOrder(order) {
if (!order) return null;
const itemData = groupItemData((order.item_data || []).map((item) => normalizeItem(item)));
const normalizedItems = (order.item_data || []).map((item) => normalizeItem(item));
const itemData = groupItemData(normalizedItems);
return {
id: order.id,
order_no: order.order_no || '',
@@ -149,10 +150,52 @@ export function normalizeOrder(order) {
total_roll: formatRoll(order.total_roll),
total_weight: formatWeightKg(order.total_weight),
item_data: itemData,
summary_rows: buildSummaryRows(normalizedItems),
_raw: order,
};
}
/** 扫码区下方汇总表列(与出仓明细表一致,可横向滑动) */
export const SUMMARY_TABLE_COLUMNS = [
{ label: '坯布编号', key: 'grey_fabric_code', width: 200 },
{ label: '坯布名称', key: 'grey_fabric_name', width: 240 },
{ label: '纱批', key: 'yarn_batch', width: 180 },
{ label: '机台号', key: 'machine_number', width: 160 },
{ label: '条数', key: 'roll', width: 140 },
{ label: '重量', key: 'weight', width: 160 },
];
/** 汇总行归类:坯布编号 + 名称 + 纱批 + 机台号 */
export function getSummaryGroupKey(item) {
return [
item.grey_fabric_code || '',
item.grey_fabric_name || '',
item.yarn_batch || '',
item.machine_number || '',
].join('|');
}
/** 按坯布、纱批、机台号汇总条数和重量,供扫码区表格展示 */
export function buildSummaryRows(items) {
const grouped = new Map();
(items || []).forEach((item) => {
const groupKey = getSummaryGroupKey(item);
const existing = grouped.get(groupKey);
if (!existing) {
grouped.set(groupKey, {
...item,
group_key: groupKey,
fine_codes: [...(item.fine_codes || [])],
});
return;
}
existing.fine_codes.push(...(item.fine_codes || []));
existing.roll = Number((Number(existing.roll || 0) + Number(item.roll || 0)).toFixed(2));
existing.weight = Number((Number(existing.weight || 0) + Number(item.weight || 0)).toFixed(2));
});
return Array.from(grouped.values());
}
/** 扫码详情区汇总维度(勾选后随扫码请求把对应 lock 字段传给后端) */
export const SCAN_GROUP_OPTIONS = [
{ key: 'produce_order_no', label: '合同' },
@@ -441,6 +484,7 @@ export function orderToFormFields(order) {
delivery_time: order.delivery_time,
remark: order.remark,
item_data: order.item_data,
summary_rows: order.summary_rows || [],
};
}
@@ -0,0 +1,73 @@
<template>
<view class="fabric-out-summary">
<scroll-view scroll-x class="fabric-out-summaryScroll">
<wyb-table
:headers="headers"
:contents="contents"
:width="tableWidth"
height="auto"
:font-size="[36, 36]"
:min-height="[100, 100]"
:padding="[16, 12]"
:first-line-fixed="false"
empty-string=""
@onCellClick="$emit('cell-click', $event)"
/>
</scroll-view>
<view v-if="!contents.length" class="fabric-out-summaryEmpty">暂无数据~~</view>
</view>
</template>
<script>
import wybTable from '@/components/wyb-table/wyb-table.vue';
import { SUMMARY_TABLE_COLUMNS } from '@/common/storeFabricBusinessOut';
export default {
components: { wybTable },
props: {
rows: { type: Array, default: () => [] },
},
computed: {
headers() {
return SUMMARY_TABLE_COLUMNS;
},
tableWidth() {
const total = this.headers.reduce((sum, col) => sum + (col.width || 160), 0);
return `${total}rpx`;
},
contents() {
return (this.rows || []).map((row) => ({
...row,
grey_fabric_code: row.grey_fabric_code || '',
grey_fabric_name: row.grey_fabric_name || '',
yarn_batch: row.yarn_batch || '',
machine_number: row.machine_number || '',
roll: row.roll != null && row.roll !== '' ? String(row.roll) : '0',
weight: row.weight != null && row.weight !== '' ? String(row.weight) : '0',
}));
},
},
};
</script>
<style scoped lang="scss">
.fabric-out-summary {
background: #fff;
margin-top: 16rpx;
}
.fabric-out-summaryScroll {
width: 100%;
}
.fabric-out-summary ::v-deep .wyb-table-scroll-view {
height: auto !important;
overflow-x: auto;
overflow-y: visible;
}
.fabric-out-summaryEmpty {
text-align: center;
color: #999;
font-size: 36rpx;
line-height: 100rpx;
background: #fff;
}
</style>
+2 -2
View File
@@ -2,8 +2,8 @@
"name" : "浩拓织厂",
"appid" : "__UNI__F79F300",
"description" : "周尚-浩拓织厂",
"versionName" : "1.1.17",
"versionCode" : 117,
"versionName" : "1.1.18",
"versionCode" : 118,
"transformPx" : false,
"app-plus" : {
"optimization" : {
@@ -1,79 +1,48 @@
<template>
<view class="fabric-out-page">
<view v-if="showHeaderToggle" class="fabric-out-headerBar" @click="toggleHeader">
<view class="fabric-out-headerBarMain">
<text class="fabric-out-headerBarTitle">单据信息</text>
<text v-if="form.order_no" class="fabric-out-headerBarSub">{{ form.order_no }}</text>
</view>
<view class="fabric-out-headerBarAction">
<text>{{ headerExpanded ? '收起' : '展开' }}</text>
<u-icon class="fabric-out-headerBarIcon" :name="headerExpanded ? 'arrow-up' : 'arrow-down'" size="32" color="#2979ff"></u-icon>
</view>
</view>
<view v-show="headerExpanded">
<OrderStatusBar class="fabric-out-mt32" :status="displayAuditStatus" :name="displayAuditStatusName" />
<view class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">出仓单号</text>
<u-input disabled placeholder="保存后自动生成" v-model="form.order_no" />
</view>
<view class="flex-white-plr26 ptb20 bdb_f5">
<text class="mr26">出仓类型</text>
<view>{{ getBillTypeName() }}</view>
</view>
<view @click="pickerSelectFun('接收单位')" class="flex-white-plr26 ptb20 bdb_f5">
<text class="mr26">接收单位<text class="redXingh">*</text></text>
<view :class="form.business_unit_name ? '' : 'cBlack'">
{{ form.business_unit_name || '请选择' }}
<u-icon v-if="headerEditable" class="ml26" name="arrow-right" size="40" color="#888888"></u-icon>
</view>
</view>
<view class="flex-white-plr26 ptb20 bdb_f5">
<text class="mr26">{{ dateLabel }}<text class="redXingh">*</text></text>
<picker mode="date" :value="form.delivery_time" :disabled="!headerEditable" @change="bindDateChange">
<view>{{ form.delivery_time }}</view>
</picker>
</view>
<view class="flex-white-plr26-column ptb20 mt32">
<view style="margin-bottom: 8rpx;"><text>单据备注</text></view>
<u-input v-model="form.remark" :disabled="!headerEditable" type="textarea" :border="true" :height="100" :auto-height="true" />
</view>
</view>
<FabricOutDetailList
:list="form.item_data"
@fabric-info="openFabricInfo"
@fine-code="openFineCode"
>
<view v-if="showScanSection">
<FabricOutScanBar
slot="before-list"
:can-scan="canScan"
:value="QRBarCode"
:delete-mode="BarCodeDelStatus"
@@ -85,42 +54,29 @@
@phone-scan="handlePhoneScan"
@delete-mode-change="BarCodeDelChange"
/>
<FabricOutScanDetail
slot="before-list"
:detail="scanDetail"
:group-keys="scanGroupKeys"
@group-change="scanGroupKeys = $event"
/>
</FabricOutDetailList>
<FabricOutSummaryTable
:rows="form.summary_rows"
@cell-click="onSummaryCellClick"
/>
</view>
<FabricOutFooter
v-if="!headerSaved"
:buttons="[{ label: '提交保存', action: 'save' }]"
single
@action="submitSave"
/>
<FabricOutFooter
v-else
:buttons="statusActionButtons"
@action="handleStatusAction"
/>
<search-select-popup
:show.sync="selectShow"
title="选择接收单位"
@@ -128,88 +84,46 @@
:list="selectList"
@confirm="selectConfirmFun"
/>
<FabricInfoPopup :show.sync="fabricInfoShow" :data="currentFabricInfo" />
<FineCodePopup :show.sync="fineCodeShow" :list="currentFineCodes" :readonly="false" @delete="onDeleteFineCode" />
</view>
</template>
<script>
import formMixin from './storeFabricBusinessOutMixin.js';
import FabricInfoPopup from '@/components/storefabric/FabricInfoPopup.vue';
import FineCodePopup from '@/components/storefabric/FineCodePopup.vue';
import OrderStatusBar from '@/components/storefabric/OrderStatusBar.vue';
import FabricOutDetailList from '@/components/storefabric/FabricOutDetailList.vue';
import FabricOutScanBar from '@/components/storefabric/FabricOutScanBar.vue';
import FabricOutScanDetail from '@/components/storefabric/FabricOutScanDetail.vue';
import FabricOutSummaryTable from '@/components/storefabric/FabricOutSummaryTable.vue';
import FabricOutFooter from '@/components/storefabric/FabricOutFooter.vue';
import SearchSelectPopup from '@/components/storefabric/SearchSelectPopup.vue';
export default {
components: {
FabricInfoPopup,
FineCodePopup,
OrderStatusBar,
FabricOutDetailList,
FabricOutScanBar,
FabricOutScanDetail,
FabricOutSummaryTable,
FabricOutFooter,
SearchSelectPopup,
},
mixins: [formMixin],
onLoad() {
uni.setNavigationBarTitle({ title: '新增坯布出仓单' });
this.pageMode = 'add';
this.loadBaseDropdowns();
},
};
</script>
<style lang="scss">
@import '@/pages/storefabric/storeFabricBusinessOutPage.scss';
page {
background-color: #F8F8F8;
padding-bottom: 260rpx;
}
</style>
@@ -1,7 +1,18 @@
<template>
<view class="fabric-out-page">
<OrderStatusBar class="fabric-out-mt32" :status="displayAuditStatus" :name="displayAuditStatusName" />
<view v-if="showHeaderToggle" class="fabric-out-headerBar" @click="toggleHeader">
<view class="fabric-out-headerBarMain">
<text class="fabric-out-headerBarTitle">单据信息</text>
<text v-if="form.order_no" class="fabric-out-headerBarSub">{{ form.order_no }}</text>
</view>
<view class="fabric-out-headerBarAction">
<text>{{ headerExpanded ? '收起' : '展开' }}</text>
<u-icon class="fabric-out-headerBarIcon" :name="headerExpanded ? 'arrow-up' : 'arrow-down'" size="32" color="#2979ff"></u-icon>
</view>
</view>
<view v-show="headerExpanded">
<OrderStatusBar class="fabric-out-mt32" :status="displayAuditStatus" :name="displayAuditStatusName" />
<view class="flex-white-plr26 ptb10 bdb_f5">
<text class="mr26">出仓单号</text>
<text>{{ form.order_no }}</text>
@@ -22,14 +33,10 @@
<text class="mr26">单据备注</text>
<text>{{ form.remark || '-' }}</text>
</view>
</view>
<FabricOutDetailList
:list="form.item_data"
@fabric-info="openFabricInfo"
@fine-code="openFineCode"
>
<view v-if="showScanSection">
<FabricOutScanBar
slot="before-list"
:can-scan="canScan"
:value="QRBarCode"
:delete-mode="BarCodeDelStatus"
@@ -41,12 +48,15 @@
@delete-mode-change="BarCodeDelChange"
/>
<FabricOutScanDetail
slot="before-list"
:detail="scanDetail"
:group-keys="scanGroupKeys"
@group-change="scanGroupKeys = $event"
/>
</FabricOutDetailList>
<FabricOutSummaryTable
:rows="form.summary_rows"
@cell-click="onSummaryCellClick"
/>
</view>
<FabricOutFooter :buttons="statusActionButtons" @action="handleStatusAction" />
@@ -67,9 +77,9 @@ import formMixin from './storeFabricBusinessOutMixin.js';
import FabricInfoPopup from '@/components/storefabric/FabricInfoPopup.vue';
import FineCodePopup from '@/components/storefabric/FineCodePopup.vue';
import OrderStatusBar from '@/components/storefabric/OrderStatusBar.vue';
import FabricOutDetailList from '@/components/storefabric/FabricOutDetailList.vue';
import FabricOutScanBar from '@/components/storefabric/FabricOutScanBar.vue';
import FabricOutScanDetail from '@/components/storefabric/FabricOutScanDetail.vue';
import FabricOutSummaryTable from '@/components/storefabric/FabricOutSummaryTable.vue';
import FabricOutFooter from '@/components/storefabric/FabricOutFooter.vue';
import SearchSelectPopup from '@/components/storefabric/SearchSelectPopup.vue';
@@ -78,16 +88,23 @@ export default {
FabricInfoPopup,
FineCodePopup,
OrderStatusBar,
FabricOutDetailList,
FabricOutScanBar,
FabricOutScanDetail,
FabricOutSummaryTable,
FabricOutFooter,
SearchSelectPopup,
},
mixins: [formMixin],
data() {
return {
pageMode: 'edit',
headerExpanded: false,
};
},
onLoad(e) {
uni.setNavigationBarTitle({ title: '编辑坯布出仓单' });
this.pageMode = 'edit';
this.headerExpanded = false;
if (e.id) {
this.loadOrder(Number(e.id), { rejectIfLocked: true });
}
@@ -4,9 +4,9 @@
* 业务说明:
* 1. 后端当前仅提供「坯布其他出货单」一种类型的接口,故出仓类型固定为 other,
* 表头保留接收单位(business_unit) / 出货日期 / 备注 等字段。
* 2. 用户先填写表头并「提交保存」(addGfmOtherDeliveryOrder),拿到出仓单 id 后即可扫码;
* 2. 用户先填写表头并「提交保存」(addGfmOtherDeliveryOrder),拿到出仓单 id 后才显示扫码区和汇总表;
* 扫码新增/删除细码走 updateGfmOtherDeliveryOrder;勾选锁定维度时附带 *_lock 字段,操作后用返回的最新详情刷新。
* 3. 后端没有「修改表头」接口,保存成功或编辑进入后表头变为只读,仅可扫码维护细码。
* 3. 后端没有「修改表头」接口,保存成功或编辑进入后表头变为只读,并默认收起,仅可扫码维护细码。
*/
import util from '@/common/util';
import scanMixin from '@/common/scanMixin.js';
@@ -42,6 +42,8 @@ export default {
orderId: 0,
form: this.getEmptyForm(),
headerSaved: false,
// 新增未保存时展开表头;保存后及编辑进入时收起
headerExpanded: true,
selectShow: false,
selectList: [],
selectType: '',
@@ -75,6 +77,14 @@ export default {
headerEditable() {
return this.pageMode === 'add' && !this.headerSaved;
},
/** 已保存或编辑页才提供收起/展开 */
showHeaderToggle() {
return this.pageMode === 'edit' || this.headerSaved;
},
/** 未保存只填表头;保存后才出现扫码区与汇总表 */
showScanSection() {
return this.headerSaved;
},
dateLabel() {
return '出货日期';
},
@@ -151,8 +161,13 @@ export default {
delivery_time: this.$u.timeFormat(new Date(), 'yyyy-mm-dd'),
remark: '',
item_data: [],
summary_rows: [],
};
},
toggleHeader() {
if (!this.showHeaderToggle) return;
this.headerExpanded = !this.headerExpanded;
},
loadOrder(id, options = {}) {
const { rejectIfLocked = false } = options;
return this.$u.api.gfmOtherDeliveryOrder.detail({ id })
@@ -242,6 +257,7 @@ export default {
const order = normalizeOrder(detail);
this.applyOrder(order);
this.headerSaved = true;
this.headerExpanded = false;
this.syncCanScanFromStatus(order.audit_status);
this.showSuccess('保存成功,可以扫码', '提交成功');
this.registerOrderScanBroadcast();
@@ -325,11 +341,13 @@ export default {
uni.hideLoading();
const order = normalizeOrder(detail);
this.form.item_data = order.item_data;
this.form.summary_rows = order.summary_rows || [];
this.auditStatus = order.audit_status;
this.applyScanDetail(scanCode, order, scanType);
if (refreshFineCodes) {
const row = order.item_data.find((i) => (i.group_key || String(i.id)) === this.currentGroupKey);
this.currentFineCodes = row ? [...row.fine_codes] : [];
const rows = order.summary_rows || [];
const row = rows.find((i) => i.group_key === this.currentGroupKey);
this.currentFineCodes = row ? [...(row.fine_codes || [])] : [];
}
this.BillDataMessage = scanType === 2 ? '删除成功' : '扫码出仓成功';
this.QRBarCode = '';
@@ -351,6 +369,15 @@ export default {
this.currentFineCodes = [...(row.fine_codes || [])];
this.fineCodeShow = true;
},
onSummaryCellClick(event) {
const row = event && event.lineData;
if (!row) return;
if (event.key === 'grey_fabric_code' || event.key === 'grey_fabric_name') {
this.openFabricInfo(row);
return;
}
this.openFineCode(row);
},
onDeleteFineCode(fineCode) {
if (this.isReadonly || !this.canScan) return;
const scanCode = getFineCodeScanCode(fineCode);
@@ -6,6 +6,47 @@
.fabric-out-mt32 {
margin-top: 32rpx;
}
.fabric-out-headerBar {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 100rpx;
padding: 16rpx 26rpx;
background: #fff;
border-bottom: 1rpx solid #f5f5f5;
box-sizing: border-box;
}
.fabric-out-headerBarMain {
display: flex;
align-items: center;
min-width: 0;
flex: 1;
}
.fabric-out-headerBarTitle {
font-size: 40rpx;
font-weight: bold;
color: #333;
flex-shrink: 0;
}
.fabric-out-headerBarSub {
margin-left: 16rpx;
font-size: 36rpx;
color: #666;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.fabric-out-headerBarAction {
display: flex;
align-items: center;
flex-shrink: 0;
margin-left: 16rpx;
font-size: 36rpx;
color: #2979ff;
}
.fabric-out-headerBarIcon {
margin-left: 8rpx;
}
.fabric-out-page .flex-white-plr26,
.fabric-out-page .flex-white-plr26-column,
.fabric-out-page .flex-white-plr26 text,