Files
admin-vben5/apps/web-antd/src/views/property/greenPlantRentalManagement/orderManagement/rentalOrder-modal.vue
2025-09-12 16:39:18 +08:00

422 lines
12 KiB
Vue
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.

<script setup lang="ts">
import {computed, ref} from 'vue';
import {useVbenModal} from '@vben/common-ui';
import {$t} from '@vben/locales';
import {cloneDeep} from '@vben/utils';
import {useVbenForm} from '#/adapter/form';
import {
rentalOrderAdd,
rentalOrderInfo,
rentalOrderUpdate
} from '#/api/property/rentalOrder';
import {defaultFormValueGetter, useBeforeCloseDiff} from '#/utils/popup';
import {plantsProductList} from "#/api/property/productManagement";
import {rentalPlanInfo, rentalPlanList} from "#/api/property/rentalPlan";
import {getDictOptions} from "#/utils/dict";
import type {PropertyVO} from "#/api/property/productManagement/model";
import type {RentalPlanVO} from "#/api/property/rentalPlan/model";
import {planInfoColumns} from './data';
import {Table} from "ant-design-vue";
import { resident_unitList } from '#/api/property/resident/unit'
const emit = defineEmits<{ reload: [] }>();
const isUpdate = ref(false);
const planList = ref<RentalPlanVO[]>([]);
const plantsList = ref<PropertyVO[]>([]);
const planProducts = ref<any[]>([]);
const totalAmount = ref(0);
const singleAmount = ref('0');
const plantInfo = ref<PropertyVO>();
const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
});
const modalSchema = [
{
label: '主键',
fieldName: 'id',
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
},
{
label: '客户名称',
fieldName: 'customerName',
component: 'Input',
rules: 'required',
},
{
label: '客户类型',
fieldName: 'customerType',
component: 'Select',
componentProps: {
options: getDictOptions('wy_khlx')
},
rules: 'selectRequired',
},
{
component: 'ApiSelect',
fieldName: 'unitId',
label: '租赁单位',
componentProps: {
api: getUnitList,
resultField: 'data',
labelField: 'label',
valueField: 'value',
immediate: true,
debounceTime: 500,
allowClear: true,
placeholder: '请选择租赁单位',
filterOption: true,
},
rules:'selectRequired',
},
{
label: '租赁周期',
fieldName: 'rentalPeriod',
component: 'Select',
componentProps: {
options: getDictOptions('wy_time_unit')
},
rules: 'selectRequired',
},
{
label: '租赁时间',
fieldName: 'rentalTime',
component: 'RangePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
},
rules: 'selectRequired',
},
{
label: '租赁方式',
fieldName: 'rentalType',
component: 'Select',
componentProps: {
options: getDictOptions('wy_zlfs')
},
rules: 'selectRequired',
formItemClass: 'col-span-2'
},
{
label: '租赁方案',
fieldName: 'planId',
component: 'ApiSelect',
dependencies: {
// 仅当 租赁方式 为 2套餐 时显示
show: (formValues: any) => formValues.rentalType === '2',
triggerFields: ['rentalType'],
},
rules: 'selectRequired',
formItemClass: 'col-span-2',
componentProps: {
api: async () => {
const res = await rentalPlanList({pageNum: 1, pageSize: 1000, state: 1});
planList.value = res.rows || [];
return planList.value.map(item => ({
label: item.planName,
value: item.id,
}));
},
onChange: async (value: string) => {
await getPlanProducts(value)
},
showSearch: true,
filterOption: (input: any, option: any) =>
option.label.toLowerCase().includes(input.toLowerCase()),
}
},
{
label: '方案详情',
fieldName: 'planInfo',
component: 'Input',
slots: {default: 'planInfo'},
dependencies: {
// 仅当 租赁方式 为 2套餐 时显示
show: (formValues: any) => formValues.rentalType === '2' && formValues.planId != null,
triggerFields: ['planId', 'rentalType'],
},
formItemClass: 'col-span-2',
},
{
label: '绿植产品',
fieldName: 'productId',
component: 'ApiSelect',
dependencies: {
// 仅当 租赁方式 为 1单点 时显示
show: (formValues: any) => formValues.rentalType === '1',
triggerFields: ['rentalType'],
},
rules: 'selectRequired',
formItemClass: 'col-span-2',
componentProps: {
api: async () => {
const res = await plantsProductList({pageNum: 1, pageSize: 1000, inventory: 0});
plantsList.value = res.rows || [];
return plantsList.value.map(item => ({
label: item.plantName + '-' + item.plantCode + '\xa0\xa0租金' + item.rent + '\xa0\xa0库存数量' + item.inventory,
value: item.id,
}));
},
onChange: async (value: string) => {
plantInfo.value = plantsList.value.find(item => item.id === value);
if (plantInfo.value) {
formApi.updateSchema([{
componentProps: () => ({
min: 1,
max: plantInfo.value?.inventory,
precision: 0,
onChange: async () => {
const formValues = await formApi.getValues();
if (formValues.productNum && plantInfo.value?.rent) {
singleAmount.value = (plantInfo.value.rent * formValues.productNum).toFixed(2);
}
},
}),
fieldName: 'productNum',
}])
}
},
showSearch: true,
filterOption: (input: any, option: any) =>
option.label.toLowerCase().includes(input.toLowerCase()),
}
},
{
label: '租赁数量',
fieldName: 'productNum',
component: 'InputNumber',
componentProps: {
min: 1,
precision: 0,
step: 1,
placeholder: '租赁数量不可超出绿植产品库存数量',
onChange: async (value: number) => {
if (plantInfo.value) {
singleAmount.value = (plantInfo.value.rent * value).toFixed(2);
}
},
},
dependencies: {
// 仅当 租赁方式 为 1单点 时显示
show: (formValues: any) => formValues.rentalType === '1',
triggerFields: ['rentalType', 'productId'],
},
rules: 'required',
},
{
label: '总金额(元)',
fieldName: 'totalAmount',
component: 'InputNumber',
slots: {default: 'totalAmount'},
dependencies: {
// 仅当 租赁方式 为 1单点 时显示
show: (formValues: any) => formValues.productNum && formValues.productId && formValues.rentalType === '1',
triggerFields: ['productNum', 'rentalType'],
disabled: true,
},
labelWidth: 110
},
{
label: '是否续租',
fieldName: 'isRelet',
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
optionType: 'button',
options: getDictOptions('wy_sf'),
},
rules: 'required'
},
{
label: '合同状态',
fieldName: 'contractStatus',
component: 'Select',
componentProps: {
options: getDictOptions('wy_htzt'),
},
rules: 'selectRequired'
},
{
label: '合同编号',
fieldName: 'contractCode',
component: 'Input',
dependencies: {
show: (formValues: any) => formValues.contractStatus != null && formValues.contractStatus != 1,
triggerFields: ['contractStatus'],
},
rules: 'required'
},
{
label: '签署时间',
fieldName: 'signTime',
component: 'DatePicker',
componentProps: {
showTime: true,
format: 'YYYY-MM-DD',
valueFormat: 'YYYY-MM-DD',
},
dependencies: {
show: (formValues: any) => formValues.contractStatus != null && formValues.contractStatus != 1,
triggerFields: ['contractStatus'],
},
rules: 'required'
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
// 默认占满两列
formItemClass: 'col-span-1',
// 默认label宽度 px
labelWidth: 80,
// 通用配置项 会影响到所有表单项
componentProps: {
class: 'w-full',
}
},
schema: modalSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const {onBeforeClose, markInitialized, resetInitialized} = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [BasicModal, modalApi] = useVbenModal({
// 在这里更改宽度
class: 'w-[70%]',
fullscreenButton: false,
onBeforeClose,
onClosed: handleClosed,
onConfirm: handleConfirm,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null;
}
modalApi.modalLoading(true);
const {id} = modalApi.getData() as { id?: number | string };
isUpdate.value = !!id;
if (isUpdate.value && id) {
const record = await rentalOrderInfo(id);
await formApi.setValues(record);
}
await markInitialized();
modalApi.modalLoading(false);
},
});
async function getUnitList(){
const queryParam = {
pageNum: 1,
pageSize: 1000,
}
const res = await resident_unitList(queryParam)
const data: { value: number; label: string }[] = []
res.rows.forEach((r: any) => {
data.push({
value: r.id,
label: r.name,
})
})
return data;
}
async function handleConfirm() {
try {
modalApi.lock(true);
const {valid} = await formApi.validate();
if (!valid) {
return;
}
// getValues获取为一个readonly的对象 需要修改必须先深拷贝一次
const data = cloneDeep(await formApi.getValues());
if (data.rentalType == 1) {
data.planId = undefined;
data.totalAmount = singleAmount.value
} else {
data.productId = undefined;
data.productNum = undefined;
data.productList = planProducts.value
data.totalAmount = totalAmount.value
}
if (data.rentalTime) {
data.startTime = data.rentalTime[0];
data.endTime = data.rentalTime[1];
}
data.paymentStatus = 0
await (isUpdate.value ? rentalOrderUpdate(data) : rentalOrderAdd(data));
resetInitialized();
emit('reload');
modalApi.close();
} catch (error) {
console.error(error);
} finally {
modalApi.lock(false);
}
}
//获取有库存的绿植
async function getPlanProducts(id: string) {
const res = await rentalPlanInfo(id)
planProducts.value = res.productList.map(item => ({
id:item.productId,
plantName: item.product?.plantName,
rent: item.product?.rent,
inventory: item.productNum,
}))
totalAmount.value = planProducts.value?.reduce((sum, item: any) => sum + (item.rent * item.inventory), 0).toFixed(2)
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
</script>
<template>
<BasicModal :title="title">
<BasicForm>
<template #planInfo="slotProps">
<div v-if="planProducts.length" style="width: 100%" v-bind="slotProps">
<Table :dataSource="planProducts" :columns="planInfoColumns" :pagination="false"
bordered size="small">
<template #bodyCell="{ column, record, index }">
<template v-if="column.field === 'id'">
{{ index + 1 }}
</template>
<template v-else>
{{ record[column.field] }}
</template>
</template>
<template #footer>
<div style="text-align: right;margin-right: 20px">
<b>总金额</b>
{{ totalAmount }}
</div>
</template>
</Table>
</div>
</template>
<template #totalAmount="slotProps">
<div v-bind="slotProps">{{ singleAmount }}</div>
</template>
</BasicForm>
</BasicModal>
</template>