pda-cli/src/pages/storegoods/storeGoodsProcessOutMixin.js
2026-07-29 14:07:21 +08:00

477 lines
14 KiB
JavaScript
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.

/**
* 加工出仓单表单 mixin新增/编辑共用)
*
* 1. 先填表头(加工单位 / 仓库 / 备注)提交 add拿到 id 后可扫码
* 2. 扫码走 updateFpmProcessOutOrderarrange_type: 1 录入 / 3 删除),不扫仓位
* 3. 手机扫码成功展示详情后自动再次调起扫码,形成连续扫
*/
import util from '@/common/util';
import scanMixin from '@/common/scanMixin.js';
import { initTts, speak } from '@/common/tts.js';
import {
AUDIT_STATUS_MAP,
ARRANGE_TYPE,
BUSINESS_UNIT_TYPE_PROCESS,
WAREHOUSE_TYPE_FINISHED,
OUT_ORDER_TYPE_PROCESS,
OUT_ORDER_TYPE_PROCESS_NAME,
normalizeOrder,
mapToSelectOptions,
canScanAtStatus,
isLockedOrderStatus,
getFormStatusActionButtons,
orderToFormFields,
confirmOrderStatusAction,
DRAFT_AUDIT_STATUS,
DRAFT_AUDIT_STATUS_NAME,
getEmptyScanDetail,
buildScanDetailFromScanResponse,
buildScanUpdateParams,
pickDefaultWarehouse,
formatDisplayTime,
} from '@/common/storeGoodsProcessOut';
export default {
mixins: [scanMixin],
data() {
return {
pageMode: 'add',
orderId: 0,
form: this.getEmptyForm(),
headerSaved: false,
selectShow: false,
selectList: [],
selectType: '',
canScan: false,
QRBarCode: '',
BarCodeDelStatus: false,
BillDataMessage: '',
scanDetail: getEmptyScanDetail(),
auditStatus: 0,
processUnitOptions: [],
warehouseOptions: [],
outOrderTypeOptions: [],
dropdownLoading: false,
/** 手机连续扫码开关:成功后自动再调起;取消/失败则关闭 */
phoneContinuousScan: false,
};
},
computed: {
isReadonly() {
return this.pageMode === 'view';
},
isEditable() {
return this.pageMode === 'add' || this.pageMode === 'edit';
},
headerEditable() {
return this.pageMode === 'add' && !this.headerSaved;
},
statusActionButtons() {
return getFormStatusActionButtons(this.headerSaved, this.orderId, this.auditStatus);
},
displayAuditStatus() {
if (this.pageMode === 'add' && !this.headerSaved) return DRAFT_AUDIT_STATUS;
return this.auditStatus;
},
displayAuditStatusName() {
if (this.pageMode === 'add' && !this.headerSaved) return DRAFT_AUDIT_STATUS_NAME;
return AUDIT_STATUS_MAP[this.auditStatus] || '';
},
canScanQr() {
return this.canScan;
},
showQrScanBar() {
return this.canScan;
},
qrDisabledTip() {
if (!this.canScan) return '请先提交保存后再扫码';
return '当前状态不可扫码';
},
},
onShow() {
this.isPageActive = true;
initTts();
if (this.canScan && this.isEditable) {
this.registerOrderScanBroadcast();
}
},
onHide() {
this.isPageActive = false;
this.phoneContinuousScan = false;
this.unregisterScanBroadcast();
},
onUnload() {
this.isPageActive = false;
this.phoneContinuousScan = false;
this.unregisterScanBroadcast();
},
methods: {
handlePhoneScan() {
if (!this.canScan || !this.orderId) {
this.showError('请先提交保存后再扫码');
return;
}
this.phoneContinuousScan = true;
this.openContinuousPhoneScan();
},
openContinuousPhoneScan() {
if (!this.phoneContinuousScan || !this.canScanQr || !this.isPageActive) {
this.phoneContinuousScan = false;
return;
}
this.openPhoneScan({
callback: (scanResult) => {
this.QRBarCode = String(scanResult || '').trim().replace(/[\r\n]/g, '');
this.$nextTick(() => this.handleScan({ fromPhone: true }));
},
fail: () => {
this.phoneContinuousScan = false;
},
});
},
scheduleNextPhoneScan() {
if (!this.phoneContinuousScan || !this.canScanQr || !this.isPageActive) {
this.phoneContinuousScan = false;
return;
}
setTimeout(() => {
this.openContinuousPhoneScan();
}, 400);
},
registerOrderScanBroadcast() {
this.registerScanBroadcast((scanResult) => {
const code = String(scanResult || '').trim().replace(/[\r\n]/g, '');
if (!code) return;
this.QRBarCode = code;
this.$nextTick(() => this.handleScan());
});
},
syncCanScanFromStatus(status) {
const nextCanScan = this.isEditable && canScanAtStatus(status);
if (this.canScan && !nextCanScan) {
this.phoneContinuousScan = false;
this.unregisterScanBroadcast();
}
this.canScan = nextCanScan;
},
loadBaseDropdowns() {
if (this.dropdownLoading) return Promise.resolve();
this.dropdownLoading = true;
return Promise.all([
this.ensureOutOrderTypeOptions().catch((e) => {
console.error('加载出仓类型失败', e);
return [];
}),
this.ensureProcessUnitOptions().catch((e) => {
console.error('加载加工单位失败', e);
return [];
}),
this.ensureWarehouseOptions().catch((e) => {
console.error('加载仓库失败', e);
return [];
}),
]).finally(() => {
this.dropdownLoading = false;
});
},
ensureOutOrderTypeOptions() {
if (this.outOrderTypeOptions.length) return Promise.resolve(this.outOrderTypeOptions);
return this.$u.api.fpmProcessOutOrder.getOutTypeEnum()
.then((res) => {
this.outOrderTypeOptions = mapToSelectOptions(res);
if (this.headerEditable && !this.form.out_order_type) {
this.applyDefaultOutOrderType();
}
return this.outOrderTypeOptions;
});
},
applyDefaultOutOrderType() {
const list = this.outOrderTypeOptions || [];
const preferred = list.find((item) => Number(item.value) === OUT_ORDER_TYPE_PROCESS) || list[0];
if (!preferred) return;
this.form.out_order_type = preferred.value;
this.form.out_order_type_name = preferred.label;
},
ensureProcessUnitOptions() {
if (this.processUnitOptions.length) return Promise.resolve(this.processUnitOptions);
return this.$u.api.businessUnit.list({ unit_type_id: BUSINESS_UNIT_TYPE_PROCESS })
.then((res) => {
this.processUnitOptions = mapToSelectOptions(res);
return this.processUnitOptions;
});
},
ensureWarehouseOptions() {
if (this.warehouseOptions.length) return Promise.resolve(this.warehouseOptions);
return this.$u.api.physicalWarehouse.getDropdownList({ warehouse_type_id: WAREHOUSE_TYPE_FINISHED })
.then((res) => {
this.warehouseOptions = mapToSelectOptions(res);
if (this.headerEditable && !this.form.warehouse_id) {
this.applyDefaultWarehouse();
}
return this.warehouseOptions;
});
},
applyDefaultWarehouse() {
const app = getApp();
const picked = pickDefaultWarehouse(
this.warehouseOptions,
app && app.globalData ? app.globalData.StoreNameID : '',
app && app.globalData ? app.globalData.StoreName : '',
);
if (!picked) return;
this.form.warehouse_id = picked.value;
this.form.warehouse_name = picked.label;
},
getEmptyForm() {
return {
order_no: '',
out_order_type: OUT_ORDER_TYPE_PROCESS,
out_order_type_name: OUT_ORDER_TYPE_PROCESS_NAME,
process_unit_id: '',
process_name: '',
warehouse_id: '',
warehouse_name: '',
remark: '',
item_data: [],
};
},
loadOrder(id, options = {}) {
const { rejectIfLocked = false } = options;
return this.$u.api.fpmProcessOutOrder.detail({ id })
.then((res) => {
const order = normalizeOrder(res);
if (!order) {
this.showError('单据不存在');
return null;
}
if (rejectIfLocked && isLockedOrderStatus(order.audit_status)) {
this.showError('当前状态不可编辑');
setTimeout(() => uni.navigateBack(), 1500);
return null;
}
this.orderId = order.id;
this.auditStatus = order.audit_status;
this.headerSaved = true;
this.form = orderToFormFields(order);
this.syncCanScanFromStatus(order.audit_status);
if (this.canScan) this.registerOrderScanBroadcast();
return order;
})
.catch((e) => {
this.showError(e.message || '加载单据失败');
return null;
});
},
pickerSelectFun(type) {
if (!this.headerEditable) return;
this.selectType = type;
const openPicker = (list) => {
if (!list.length) {
this.showError('暂无可选数据');
return;
}
this.selectList = list;
this.selectShow = true;
};
if (type === '出仓类型') {
this.ensureOutOrderTypeOptions()
.then(openPicker)
.catch((e) => this.showError(e.message || '加载出仓类型失败'));
} else if (type === '加工单位') {
this.ensureProcessUnitOptions()
.then(openPicker)
.catch((e) => this.showError(e.message || '加载加工单位失败'));
} else if (type === '仓库名称') {
this.ensureWarehouseOptions()
.then(openPicker)
.catch((e) => this.showError(e.message || '加载仓库失败'));
}
},
selectConfirmFun(e) {
const item = e[0];
if (this.selectType === '出仓类型') {
this.form.out_order_type = item.value;
this.form.out_order_type_name = item.label;
} else if (this.selectType === '加工单位') {
this.form.process_unit_id = item.value;
this.form.process_name = item.label;
} else if (this.selectType === '仓库名称') {
this.form.warehouse_id = item.value;
this.form.warehouse_name = item.label;
}
},
validateForm() {
if (!this.form.out_order_type) return '请选择出仓类型';
if (!this.form.process_unit_id) return '请选择加工单位';
if (!this.form.warehouse_id) return '请选择仓库名称';
const app = getApp();
const saleSystemId = app && app.globalData ? app.globalData.PlanDepartmentID : '';
if (!saleSystemId) return '缺少营销体系,请重新登录';
return '';
},
buildAddParam() {
const app = getApp();
return {
// OpenAPI: product.AddFpmProcessOutOrderParam
out_order_type: Number(this.form.out_order_type),
process_unit_id: Number(this.form.process_unit_id),
warehouse_id: Number(this.form.warehouse_id),
sale_system_id: Number(app.globalData.PlanDepartmentID),
warehouse_out_time: formatDisplayTime(new Date(), 'YYYY-MM-DD'),
remark: this.form.remark || '',
item_data: [],
};
},
submitSave() {
if (this.headerSaved) {
this.showError('表头已保存,请直接扫码');
return;
}
const err = this.validateForm();
if (err) {
this.showError(err);
return;
}
uni.showLoading({ title: '保存中...' });
this.$u.api.fpmProcessOutOrder.add(this.buildAddParam())
.then((res) => {
this.orderId = (res && res.id) || 0;
if (!this.orderId) {
throw new Error('保存失败未返回单据ID');
}
return this.$u.api.fpmProcessOutOrder.detail({ id: this.orderId });
})
.then((detail) => {
uni.hideLoading();
const order = normalizeOrder(detail);
this.applyOrder(order);
this.headerSaved = true;
this.syncCanScanFromStatus(order.audit_status);
this.showSuccess('保存成功,请开始扫码');
this.registerOrderScanBroadcast();
})
.catch((e) => {
uni.hideLoading();
this.showError(e.message || '保存失败');
});
},
applyOrder(order) {
if (!order) return;
this.auditStatus = order.audit_status;
Object.assign(this.form, orderToFormFields(order));
},
handleScan(options = {}) {
const fromPhone = !!options.fromPhone;
const code = (this.QRBarCode || '').trim();
if (!this.canScan || !this.orderId) {
this.showError('请先提交保存后再扫码');
this.QRBarCode = '';
this.phoneContinuousScan = false;
return;
}
if (!code) {
this.QRBarCode = '';
if (fromPhone) this.scheduleNextPhoneScan();
return;
}
const arrangeType = this.BarCodeDelStatus ? ARRANGE_TYPE.DEL : ARRANGE_TYPE.IN;
this.doScanUpdate(code, arrangeType, { fromPhone });
},
BarCodeDelChange(e) {
this.BarCodeDelStatus = (e.detail.value || []).length > 0;
this.BillDataMessage = this.BarCodeDelStatus ? '删除模式:扫描细码即可删除' : '';
},
getFineCodeScanCode(fineCode) {
if (!fineCode) return '';
return fineCode.qr_code
|| fineCode.scan_code
|| fineCode.digital_code
|| fineCode.bar_code
|| '';
},
onDeleteFineCode(fineCode) {
if (!this.canScan || !this.orderId) {
this.showError('当前状态不可删除');
return;
}
const scanCode = this.getFineCodeScanCode(fineCode);
if (!scanCode) {
this.showError('该细码缺少条码,无法删除');
return;
}
uni.showModal({
title: '提示',
content: `确认删除细码 ${scanCode}`,
success: (res) => {
if (!res.confirm) return;
this.doScanUpdate(scanCode, ARRANGE_TYPE.DEL);
},
});
},
doScanUpdate(scanCode, arrangeType, options = {}) {
const { fromPhone = false } = options;
const isDelete = arrangeType === ARRANGE_TYPE.DEL;
uni.showLoading({ title: isDelete ? '删除中...' : '处理中...' });
return this.$u.api.fpmProcessOutOrder.scanUpdate(buildScanUpdateParams({
id: this.orderId,
scanCode,
arrangeType,
}))
.then((scanRes) => {
this.scanDetail = buildScanDetailFromScanResponse(scanRes);
this.BillDataMessage = isDelete ? '删除成功' : '扫描成功';
this.QRBarCode = '';
if (isDelete) {
speak('已删除');
uni.showToast({ title: '删除成功', icon: 'success' });
} else {
speak('成功');
}
return this.$u.api.fpmProcessOutOrder.detail({ id: this.orderId })
.then((detail) => {
const order = normalizeOrder(detail);
if (order) {
this.form.item_data = order.item_data;
this.auditStatus = order.audit_status;
}
})
.catch(() => null);
})
.then(() => {
uni.hideLoading();
if (fromPhone) this.scheduleNextPhoneScan();
})
.catch((e) => {
uni.hideLoading();
this.phoneContinuousScan = false;
const message = e.message || (isDelete ? '删除失败' : '扫码失败');
this.showError(message);
this.QRBarCode = '';
});
},
handleStatusAction(action) {
confirmOrderStatusAction(this, {
orderId: this.orderId,
action,
onSuccess: () => this.$u.api.fpmProcessOutOrder.detail({ id: this.orderId })
.then((detail) => {
uni.hideLoading();
const order = normalizeOrder(detail);
if (!order) return;
this.applyOrder(order);
this.syncCanScanFromStatus(order.audit_status);
this.showSuccess('操作成功');
}),
});
},
showError(message) {
util.playErrorAudio();
uni.showModal({ title: '提示', content: message, showCancel: false });
},
showSuccess(message) {
util.playSuccessAudio();
uni.showToast({ title: message, icon: 'success' });
},
},
};