feat: 设备表单增加产品选择功能

- 为设备表单添加产品选择弹窗组件
- 实现产品选择后的数据回填和图片自动设置
- 禁用编辑模式下的产品字段
- 移除旧的产品下拉选项变更逻辑
- 添加产品选择相关的状态管理和事件处理
- 更新表单架构以支持产品选择按钮渲染
This commit is contained in:
fhysy 2025-10-09 16:09:58 +08:00
parent 2ce63301fe
commit 74717f723b
4 changed files with 137 additions and 14 deletions

View File

@ -33,10 +33,12 @@ export const querySchema: FormSchemaGetter = () => [
{ {
component: 'Select', component: 'Select',
componentProps: { componentProps: {
allowClear: true,
options: enabledOptions, options: enabledOptions,
}, },
fieldName: 'enabled', fieldName: 'enabled',
label: '启用状态', label: '启用状态',
defaultValue: '1',
}, },
]; ];

View File

@ -123,9 +123,8 @@ const [BasicDrawer, drawerApi] = useVbenDrawer({
const { id } = drawerApi.getData() as { id?: number | string }; const { id } = drawerApi.getData() as { id?: number | string };
isUpdate.value = !!id; isUpdate.value = !!id;
const record = await platformInfo(id);
if (isUpdate.value && id) { if (isUpdate.value && id) {
const record = await platformInfo(id);
formApi.setState((prev) => { formApi.setState((prev) => {
const currentSchema = prev?.schema ?? []; const currentSchema = prev?.schema ?? [];
const newSchema = []; const newSchema = [];

View File

@ -105,6 +105,7 @@ export const drawerSchema: FormSchemaGetter = () => [
{ {
label: '所属产品', label: '所属产品',
fieldName: 'productId', fieldName: 'productId',
disabled: true,
component: 'Select', component: 'Select',
componentProps: {}, componentProps: {},
rules: 'selectRequired', rules: 'selectRequired',

View File

@ -1,10 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue'; import type { ProductVO } from '#/api/device/product/model';
import { computed, defineAsyncComponent, h, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui'; import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '@vben/locales'; import { $t } from '@vben/locales';
import { cloneDeep } from '@vben/utils'; import { cloneDeep } from '@vben/utils';
import { Modal } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form'; import { useVbenForm } from '#/adapter/form';
import { deviceAdd, deviceInfo, deviceUpdate } from '#/api/device/device'; import { deviceAdd, deviceInfo, deviceUpdate } from '#/api/device/device';
import { productList } from '#/api/device/product'; import { productList } from '#/api/device/product';
@ -15,6 +19,10 @@ import { drawerSchema } from './data';
const emit = defineEmits<{ reload: [] }>(); const emit = defineEmits<{ reload: [] }>();
const ProductSelectTable = defineAsyncComponent(
() => import('../../../components/product-select/product-select-table.vue'),
);
const deviceStore = useDeviceStore(); const deviceStore = useDeviceStore();
const isUpdate = ref(false); const isUpdate = ref(false);
@ -22,6 +30,34 @@ const title = computed(() => {
return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add'); return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
}); });
//
const productSelectModalVisible = ref(false);
const selectedProduct = ref<[] | ProductVO>([]);
const schema = drawerSchema().map((item) => {
if (item.fieldName === 'productId') {
return {
...item,
// renderComponentContent: (model) => ({
// addonAfter: () =>
// h('button', { onClick: openProductSelectModal }, ''),
// }),
suffix: () =>
h(
'button',
{
class:
'w-[100px] bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-4 rounded transition duration-200',
type: 'primary',
onClick: openProductSelectModal,
},
'选择产品',
),
};
}
return item;
});
const [BasicForm, formApi] = useVbenForm({ const [BasicForm, formApi] = useVbenForm({
commonConfig: { commonConfig: {
// //
@ -33,7 +69,7 @@ const [BasicForm, formApi] = useVbenForm({
class: 'w-full', class: 'w-full',
}, },
}, },
schema: drawerSchema(), schema,
showDefaultActions: false, showDefaultActions: false,
wrapperClass: 'grid-cols-2', wrapperClass: 'grid-cols-2',
}); });
@ -68,6 +104,28 @@ const [BasicDrawer, drawerApi] = useVbenDrawer({
if (isUpdate.value && id) { if (isUpdate.value && id) {
const record = await deviceInfo(id); const record = await deviceInfo(id);
await formApi.setValues(record); await formApi.setValues(record);
//
if (record.productId) {
// productIdAPI
selectedProduct.value = [
{
id: record.productId,
productName: record.productObj?.productName || '已选择产品',
imgId: record.imgId,
},
] as ProductVO[];
//
// formApi.updateSchema([
// {
// componentProps: {
// disabled: isUpdate.value,
// onClick: openProductSelectModal,
// placeholder: selectedProduct.value[0].productName,
// },
// fieldName: 'productId',
// },
// ]);
}
} else { } else {
await formApi.setFieldValue('imgId', deviceStore.getDefaultDeviceImgId); await formApi.setFieldValue('imgId', deviceStore.getDefaultDeviceImgId);
} }
@ -105,14 +163,68 @@ async function handleConfirm() {
async function handleClosed() { async function handleClosed() {
await formApi.resetForm(); await formApi.resetForm();
resetInitialized(); resetInitialized();
//
selectedProduct.value = [];
productSelectModalVisible.value = false;
} }
//
const openProductSelectModal = () => {
const { id } = drawerApi.getData() as { id?: number | string };
if (id) {
Modal.error({
title: '不可编辑产品',
});
} else {
productSelectModalVisible.value = true;
}
};
const onProductChange = (products: ProductVO[]) => {
if (products.length > 0) {
selectedProduct.value = products;
//
formApi.setFieldValue('productId', products[0].id);
//
formApi.setFieldValue('imgId', products[0].imgId || '');
//
// formApi.updateSchema([
// {
// renderComponentContent: (model) => ({
// addonAfter: () =>
// h(
// 'button',
// {
// onClick: openProductSelectModal,
// },
// '',
// ),
// }),
// fieldName: 'productId',
// },
// ]);
}
};
const okProductSelectModal = () => {
if (selectedProduct.value.length > 0) {
productSelectModalVisible.value = false;
} else {
Modal.error({
title: '请选择产品',
});
}
};
const closeProductSelectModal = () => {
productSelectModalVisible.value = false;
};
async function getProductOptionList() { async function getProductOptionList() {
try { try {
const res = await productList({ const res = await productList({
pageNum: 1, pageNum: 1,
pageSize: 1000, pageSize: 1000,
enabled: '1',
}); });
const productOptions = res.rows.map((item) => ({ const productOptions = res.rows.map((item) => ({
@ -128,15 +240,6 @@ async function getProductOptionList() {
componentProps: { componentProps: {
options: productOptions || [], options: productOptions || [],
placeholder, placeholder,
onChange: (value: number | string) => {
//
if (value) {
const selectedProduct = productOptions.find(
(option) => option.value === value,
);
formApi.setFieldValue('imgId', selectedProduct?.imgId || '');
}
},
}, },
fieldName: 'productId', fieldName: 'productId',
}, },
@ -150,5 +253,23 @@ async function getProductOptionList() {
<template> <template>
<BasicDrawer :title="title"> <BasicDrawer :title="title">
<BasicForm /> <BasicForm />
<!-- 产品选择弹窗 -->
<Modal
title="产品选择"
:open="productSelectModalVisible"
:width="1100"
destroy-on-close
@ok="okProductSelectModal"
@cancel="closeProductSelectModal"
>
<div>
<ProductSelectTable
v-model="selectedProduct"
:multiple="false"
@change="onProductChange"
/>
</div>
</Modal>
</BasicDrawer> </BasicDrawer>
</template> </template>