|
|
@@ -5,58 +5,260 @@
|
|
|
</template>
|
|
|
<up-form class="p-rtv bg-#fff" labelPosition="top" :model="form" :rules="rules" labelWidth="auto" ref="upFormRef">
|
|
|
<view class="pd-24 bg-#fff mb-10">
|
|
|
- <view class="h-1" id="inputStorageIdpppp"></view>
|
|
|
- <up-form-item borderBottom label="选择包装对象" prop="inputStorageId" required>
|
|
|
+ <view class="h-1" id="detailListpppp"></view>
|
|
|
+ <up-form-item borderBottom label="销售批次" prop="detailList" required>
|
|
|
<view class="flex1">
|
|
|
- <up-button v-if="!form.inputStorageId" @click="selectStorage" type="primary" plain>
|
|
|
+ <template v-for="(item, index) in form.detailList" :key="index">
|
|
|
+ <view class="bg-#FBFDFB border-#A9D7B4 b-radius mb-10 p-rtv">
|
|
|
+ <view class="border-bottom-#A9D7B4">
|
|
|
+ <ProductItem :item="selectedStorageMap[item]" :showDate="false" :hideExtraInfo="true"></ProductItem>
|
|
|
+ </view>
|
|
|
+ <view class="pd-24">
|
|
|
+ <!-- 嘻嘻嘻 -->
|
|
|
+ <view class="d-flex j-sb mb-10">
|
|
|
+ <view class="f-s-28 c-#333 f-w-500">本次销售量:</view>
|
|
|
+ <view>
|
|
|
+ <up-checkbox @change="changeRowChecked($event, item)" shape="circle" :customStyle="{ marginBottom: '8px' }" label="全部销售" name="agree" usedAlone v-model:checked="selectedStorageFormMap[item].aloneChecked"> </up-checkbox>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-if="+selectedStorageMap[item]?.restAmount" class="d-flex">
|
|
|
+ <view class="flex1 ov-hd f-s-28 c-#666">包装规格:{{ selectedStorageMap[item].specn }}</view>
|
|
|
+ <view class="d-flex f-s-28 c-#666">
|
|
|
+ <view>销售量:</view>
|
|
|
+ <view class="d-flex a-c border-bottom-#E6E6E6 flex1 ov-hd">
|
|
|
+ <up-input class="w-180" maxlength="10" inputAlign="center" v-model="selectedStorageFormMap[item].proCount" @change="changeRowInput(item)" placeholder="请输入" border="none"></up-input>
|
|
|
+ <view class="c-#666 ml-5">{{ selectedStorageMap[item].unit }}</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-if="+selectedStorageMap[item]?.restRestAmount" class="d-flex">
|
|
|
+ <view class="flex1 ov-hd f-s-28 c-#666">包装规格:{{ selectedStorageMap[item].restSpecn }}</view>
|
|
|
+ <view class="d-flex f-s-28 c-#666">
|
|
|
+ <view>销售量:</view>
|
|
|
+ <view class="d-flex a-c border-bottom-#E6E6E6 flex1 ov-hd">
|
|
|
+ <up-input class="w-180" maxlength="10" inputAlign="center" v-model="selectedStorageFormMap[item].restFlag" @change="changeRowInput(item)" placeholder="请输入" border="none"></up-input>
|
|
|
+ <view class="c-#666 ml-5">{{ selectedStorageMap[item].unit }}</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="close-icon pd-16" @click="deleteStorage(item, index)">
|
|
|
+ <up-icon color="#F81242" name="close" size="32rpx"></up-icon>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ <up-button @click="selectStorage" type="primary" plain>
|
|
|
<image class="w-36 h-36 mr-10" src="https://yujin-szyy.oss-cn-chengdu.aliyuncs.com/szyy/images-plt/common/select_push_icon.png" mode="widthFix" />
|
|
|
- <span>请选择您要包装的对象</span>
|
|
|
+ <span>请选择要销售的成品批次</span>
|
|
|
</up-button>
|
|
|
</view>
|
|
|
</up-form-item>
|
|
|
- <view class="h-1" id="storageUseAmountpppp"></view>
|
|
|
- <up-form-item borderBottom label="本次包装用量" prop="storageUseAmount" required>
|
|
|
- <up-input v-model="form.storageUseAmount" placeholder="请输入本次包装用量" border="none" clearable></up-input>
|
|
|
+ <!-- 出库日期 -->
|
|
|
+ <view class="h-1" id="outstoreDatepppp"></view>
|
|
|
+ <ut-datetime-picker v-model="form.outstoreDate" :maxDate="new Date()" mode="date">
|
|
|
+ <up-form-item borderBottom label="出库日期" required prop="outstoreDate">
|
|
|
+ <up-input v-model="form.outstoreDate" readonly placeholder="请选择出库日期" border="none" clearable></up-input>
|
|
|
+ <template #right>
|
|
|
+ <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
|
|
|
+ </template>
|
|
|
+ </up-form-item>
|
|
|
+ </ut-datetime-picker>
|
|
|
+ <!-- 入库批号 -->
|
|
|
+ <view class="h-1" id="orderNopppp"></view>
|
|
|
+ <up-form-item borderBottom label="销售订单号" required prop="orderNo">
|
|
|
+ <up-input v-model="form.orderNo" placeholder="请输入销售订单号" border="none" clearable></up-input>
|
|
|
<template #right>
|
|
|
- <span class="f-s-30 f-w-5 c-#333">{{ form?.storageUseUnit || 'kg' }}</span>
|
|
|
+ <up-button @click="generateBatchCode" type="primary" :customStyle="formItemBtnStyle">系统生成</up-button>
|
|
|
</template>
|
|
|
</up-form-item>
|
|
|
+ <up-form-item borderBottom label="购货单位" prop="customerId" required>
|
|
|
+ <view class="flex1">
|
|
|
+ <ContactUnitInput v-model="form.customerId" v-model:info="form.customerInfo" :params="{ cpyType: '3' }" title="选择购货单位" placeholder="请选择购货单位信息"></ContactUnitInput>
|
|
|
+ </view>
|
|
|
+ </up-form-item>
|
|
|
+ <!-- 随货同行单号 -->
|
|
|
+ <view class="h-1" id="shdNopppp"></view>
|
|
|
+ <up-form-item borderBottom label="随货同行单号" prop="shdNo">
|
|
|
+ <up-input v-model="form.shdNo" placeholder="请输入随货同行单号" border="none" clearable></up-input>
|
|
|
+ </up-form-item>
|
|
|
+ <!-- 随货同行单 -->
|
|
|
+ <up-form-item label="随货同行单" prop="shdImg" borderBottom>
|
|
|
+ <ut-upload v-model="form.shdImg" :max-count="9"></ut-upload>
|
|
|
+ </up-form-item>
|
|
|
+ <!-- 放行单 -->
|
|
|
+ <up-form-item label="放行单" prop="fxdImg" borderBottom>
|
|
|
+ <ut-upload v-model="form.fxdImg" :max-count="9"></ut-upload>
|
|
|
+ </up-form-item>
|
|
|
+ <!-- 放行人默认登录人 -->
|
|
|
+ <up-form-item label="放行人" prop="fxrName" borderBottom>
|
|
|
+ <up-input v-model="form.fxrName" placeholder="请输入放行人姓名" border="none" clearable></up-input>
|
|
|
+ </up-form-item>
|
|
|
+ <!-- 运输方式字典选择 -->
|
|
|
+ <ut-action-sheet v-model="form.transportMode" :tabs="transportation_mode" mode="custom" title="请选择运输方式">
|
|
|
+ <up-form-item borderBottom label="运输方式" prop="transportMode">
|
|
|
+ <view v-if="form.transportMode" class="f-s-30 c-333 f-w-5 flex1">{{ selectDictLabel(transportation_mode, form.transportMode) }}</view>
|
|
|
+ <view v-else class="f-s-30 c-ccc f-w-4 flex1">请选择运输方式</view>
|
|
|
+ <template #right>
|
|
|
+ <up-icon size="22rpx" color="#37A954" name="arrow-down-fill"></up-icon>
|
|
|
+ </template>
|
|
|
+ </up-form-item>
|
|
|
+ </ut-action-sheet>
|
|
|
+ <up-form-item borderBottom label="备注" prop="remark">
|
|
|
+ <up-textarea v-model="form.remark" placeholder="请输入备注" autoHeight></up-textarea>
|
|
|
+ </up-form-item>
|
|
|
</view>
|
|
|
</up-form>
|
|
|
+ <view class="pd2-40-24">
|
|
|
+ <up-button type="primary" @click="submit">确认登记</up-button>
|
|
|
+ </view>
|
|
|
</z-paging>
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
import { useClientRequest } from '@/utils/request';
|
|
|
import { formItemBtnStyle } from '@/assets/styles/uview-plus';
|
|
|
import NP from 'number-precision';
|
|
|
+import { useInfoStore } from '@/store';
|
|
|
+import { parseTime } from '@/utils/ruoyi';
|
|
|
+import ProductItem from '@/plant/models/warehouseCard/product-item.vue';
|
|
|
+import ContactUnitInput from '@/models/contact-unit-input/contact-unit-input.vue';
|
|
|
+interface SelectedStorageItem {
|
|
|
+ id: string | number;
|
|
|
+ [key: string]: any;
|
|
|
+}
|
|
|
+
|
|
|
+const infoStore = useInfoStore();
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
-const { pt_pack_ref_type, pt_pack_spec_unit, pt_expire_date_unit } = toRefs<any>(proxy?.useDict('pt_pack_ref_type', 'pt_pack_spec_unit', 'pt_expire_date_unit'));
|
|
|
+const { transportation_mode } = toRefs<any>(proxy?.useDict('transportation_mode'));
|
|
|
const upFormRef = ref();
|
|
|
const paging = ref();
|
|
|
const form = ref({
|
|
|
-
|
|
|
+ detailList: [] as string[],
|
|
|
+ outstoreDate: parseTime(new Date(), '{y}-{m}-{d}'),
|
|
|
+ orderNo: '',
|
|
|
+ shdNo: '',
|
|
|
+ shdImg: '',
|
|
|
+ fxdImg: '',
|
|
|
+ fxrName: infoStore.userInfo?.name,
|
|
|
+ transportMode: '',
|
|
|
});
|
|
|
+const selectedStorageMap = ref<Record<string, SelectedStorageItem>>({});
|
|
|
+const selectedStorageFormMap = ref<Record<string, any>>({});
|
|
|
+const callbackName = 'selectSalesStorageBatch';
|
|
|
+const selectingStorage = ref(false);
|
|
|
+const handleSelectStorage = (data: SelectedStorageItem[] = []) => {
|
|
|
+ const nextStorageMap = { ...selectedStorageMap.value };
|
|
|
+ const nextDetailList = [...form.value.detailList];
|
|
|
+ data.forEach((item) => {
|
|
|
+ if (!item?.id && item?.id !== 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const itemId = String(item.id);
|
|
|
+ if (!nextDetailList.includes(itemId)) {
|
|
|
+ nextDetailList.push(itemId);
|
|
|
+ nextStorageMap[itemId] = item;
|
|
|
+ selectedStorageFormMap.value[itemId] = {
|
|
|
+ storageId: item.id,
|
|
|
+ proCount: '',
|
|
|
+ restFlag: '',
|
|
|
+ // 是否全部销售
|
|
|
+ aloneChecked: false,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ form.value.detailList = nextDetailList;
|
|
|
+ selectedStorageMap.value = nextStorageMap;
|
|
|
+ selectingStorage.value = false;
|
|
|
+ uni.$off(callbackName);
|
|
|
+};
|
|
|
|
|
|
const rules = reactive<Record<string, any>>({
|
|
|
-
|
|
|
+ detailList: [
|
|
|
+ { type: 'array', required: true, message: '请选择销售批次' },
|
|
|
+ {
|
|
|
+ validator: (rule: any, value: string[], callback: any) => {
|
|
|
+ if (!value || value.length === 0) {
|
|
|
+ callback(new Error('请选择销售批次'));
|
|
|
+ } else {
|
|
|
+ for (const itemId of value) {
|
|
|
+ const storageItem = selectedStorageMap.value[String(itemId)];
|
|
|
+ const formItem = selectedStorageFormMap.value[String(itemId)];
|
|
|
+ if (!storageItem || !formItem) {
|
|
|
+ callback(new Error('请选择销售批次'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const restAmount = Number(storageItem.restAmount || 0);
|
|
|
+ const proCount = Number(formItem.proCount || 0);
|
|
|
+ const restFlag = Number(formItem.restFlag || 0);
|
|
|
+ if (formItem.aloneChecked) {
|
|
|
+ if (restAmount > 0 && proCount !== restAmount) {
|
|
|
+ callback(new Error('请勾选全部销售或输入正确的销售量'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (restAmount === 0 && restFlag !== 0) {
|
|
|
+ callback(new Error('请勾选全部销售或输入正确的销售量'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ((proCount && proCount <= 0) || (restFlag && restFlag <= 0)) {
|
|
|
+ callback(new Error('请输入正确的销售量'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (proCount > restAmount) {
|
|
|
+ callback(new Error('销售量不能大于剩余量'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (restFlag > storageItem.restRestAmount) {
|
|
|
+ callback(new Error('销售量不能大于剩余量'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ outstoreDate: [{ required: true, message: '请选择出库日期' }],
|
|
|
+ orderNo: [{ required: true, message: '请输入销售订单号' }],
|
|
|
});
|
|
|
-
|
|
|
const submit = () => {
|
|
|
- uni.$u.debounce(async () => {
|
|
|
- try {
|
|
|
- await upFormRef.value?.validate();
|
|
|
- } catch (error: any) {
|
|
|
- const firstErrorField = error && error[0].field + 'pppp';
|
|
|
- paging.value?.scrollIntoViewById(firstErrorField, 30, true);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
-
|
|
|
- } catch (e) {
|
|
|
- console.error('销售登记失败:', e);
|
|
|
- }
|
|
|
- }, 500, true);
|
|
|
+ uni.$u.debounce(
|
|
|
+ async () => {
|
|
|
+ try {
|
|
|
+ await upFormRef.value?.validate();
|
|
|
+ } catch (error: any) {
|
|
|
+ const firstErrorField = error && error[0].field + 'pppp';
|
|
|
+ paging.value?.scrollIntoViewById(firstErrorField, 30, true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const submitData = {
|
|
|
+ ...form.value,
|
|
|
+ detailList: form.value.detailList.map((item) => ({
|
|
|
+ storageId: selectedStorageFormMap.value[String(item)].storageId,
|
|
|
+ proCount: selectedStorageFormMap.value[String(item)].proCount,
|
|
|
+ restFlag: selectedStorageFormMap.value[String(item)].restFlag || undefined,
|
|
|
+ })),
|
|
|
+ };
|
|
|
+ await useClientRequest.post('/plt-api/app/saleOrder/add', submitData);
|
|
|
+ uni.showToast({
|
|
|
+ title: '销售登记成功',
|
|
|
+ icon: 'success',
|
|
|
+ });
|
|
|
+ uni.$emit('refreshStorageRoomList');
|
|
|
+ await new Promise((resolve) => setTimeout(resolve, 500));
|
|
|
+ uni.$u.route({
|
|
|
+ type: 'redirect',
|
|
|
+ url: '/plant/storage/finished-product/sales-registration/index',
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.error('销售登记失败:', e);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ 500,
|
|
|
+ true,
|
|
|
+ );
|
|
|
};
|
|
|
// 点击随机生成服务端生成唯一的批号
|
|
|
const generateBatchCode = async () => {
|
|
|
@@ -64,28 +266,83 @@ const generateBatchCode = async () => {
|
|
|
title: '生成中...',
|
|
|
});
|
|
|
const res = await useClientRequest.post('/plt-api/app/plantationTask/getBatchCode', {
|
|
|
- plType: 'Z',
|
|
|
- linkType: 'I',
|
|
|
+ plType: '',
|
|
|
+ linkType: '1',
|
|
|
});
|
|
|
if (res && res.code === 200) {
|
|
|
uni.hideLoading();
|
|
|
- form.value.packSn = res.data;
|
|
|
+ form.value.orderNo = res.data;
|
|
|
uni.showToast({
|
|
|
- title: '批号生成成功',
|
|
|
+ title: '销售订单号生成成功',
|
|
|
icon: 'success',
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
// 去选择包装对象页选择包装对象,选择后返回并赋值
|
|
|
const selectStorage = () => {
|
|
|
- uni.$on('selectStorageObject', (data: any) => {
|
|
|
-
|
|
|
+ selectingStorage.value = true;
|
|
|
+ uni.$off(callbackName);
|
|
|
+ uni.$on(callbackName, handleSelectStorage);
|
|
|
+ uni.$u.route({
|
|
|
+ type: 'navigateTo',
|
|
|
+ url: '/plant/storage/finished-product/select-sales-batch/index',
|
|
|
+ params: {
|
|
|
+ callback: callbackName,
|
|
|
+ selectedIds: JSON.stringify(form.value.detailList),
|
|
|
+ },
|
|
|
});
|
|
|
};
|
|
|
-const deleteStorage = () => {
|
|
|
-
|
|
|
+const deleteStorage = (item: string, index: number) => {
|
|
|
+ const itemId = String(item);
|
|
|
+ form.value.detailList.splice(index, 1);
|
|
|
+ delete selectedStorageMap.value[itemId];
|
|
|
+ delete selectedStorageFormMap.value[itemId];
|
|
|
+};
|
|
|
+
|
|
|
+const changeRowInput = (item: string) => {
|
|
|
+ const itemId = String(item);
|
|
|
+ const storageItem = selectedStorageMap.value[itemId];
|
|
|
+ const formItem = selectedStorageFormMap.value[itemId];
|
|
|
+ if (!storageItem || !formItem) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const restAmount = Number(storageItem.restAmount || 0);
|
|
|
+ const restRestAmount = Number(storageItem.restRestAmount || 0);
|
|
|
+ const hasProAmount = restAmount > 0;
|
|
|
+ const hasRestAmount = restRestAmount > 0;
|
|
|
+ const hasProInput = formItem.proCount !== '' && formItem.proCount !== null && formItem.proCount !== undefined;
|
|
|
+ const hasRestInput = formItem.restFlag !== '' && formItem.restFlag !== null && formItem.restFlag !== undefined;
|
|
|
+ const proChecked = !hasProAmount || (hasProInput && Number(formItem.proCount) === restAmount);
|
|
|
+ const restChecked = !hasRestAmount || (hasRestInput && Number(formItem.restFlag) === restRestAmount);
|
|
|
+
|
|
|
+ formItem.aloneChecked = proChecked && restChecked;
|
|
|
+};
|
|
|
+
|
|
|
+const changeRowChecked = (event: any, item: string) => {
|
|
|
+ const itemId = String(item);
|
|
|
+ const checked = typeof event === 'boolean' ? event : !!event;
|
|
|
+ selectedStorageFormMap.value[itemId].aloneChecked = checked;
|
|
|
+ if (checked) {
|
|
|
+ // 选中
|
|
|
+ selectedStorageFormMap.value[itemId].proCount = selectedStorageMap.value[itemId]?.restAmount || '';
|
|
|
+ selectedStorageFormMap.value[itemId].restFlag = selectedStorageMap.value[itemId]?.restRestAmount || '';
|
|
|
+ } else {
|
|
|
+ // 取消选中
|
|
|
+ selectedStorageFormMap.value[itemId].proCount = '';
|
|
|
+ selectedStorageFormMap.value[itemId].restFlag = '';
|
|
|
+ }
|
|
|
};
|
|
|
-onLoad((options: any) => {});
|
|
|
+onHide(() => {
|
|
|
+ if (selectingStorage.value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ uni.$off(callbackName);
|
|
|
+});
|
|
|
+
|
|
|
+onUnload(() => {
|
|
|
+ uni.$off(callbackName);
|
|
|
+});
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
.close-icon {
|