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',
componentProps: {
allowClear: true,
options: enabledOptions,
},
fieldName: 'enabled',
label: '启用状态',
defaultValue: '1',
},
];

View File

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

View File

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

View File

@ -1,10 +1,14 @@
<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 { $t } from '@vben/locales';
import { cloneDeep } from '@vben/utils';
import { Modal } from 'ant-design-vue';
import { useVbenForm } from '#/adapter/form';
import { deviceAdd, deviceInfo, deviceUpdate } from '#/api/device/device';
import { productList } from '#/api/device/product';
@ -15,6 +19,10 @@ import { drawerSchema } from './data';
const emit = defineEmits<{ reload: [] }>();
const ProductSelectTable = defineAsyncComponent(
() => import('../../../components/product-select/product-select-table.vue'),
);
const deviceStore = useDeviceStore();
const isUpdate = ref(false);
@ -22,6 +30,34 @@ const title = computed(() => {
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({
commonConfig: {
//
@ -33,7 +69,7 @@ const [BasicForm, formApi] = useVbenForm({
class: 'w-full',
},
},
schema: drawerSchema(),
schema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
@ -68,6 +104,28 @@ const [BasicDrawer, drawerApi] = useVbenDrawer({
if (isUpdate.value && id) {
const record = await deviceInfo(id);
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 {
await formApi.setFieldValue('imgId', deviceStore.getDefaultDeviceImgId);
}
@ -105,14 +163,68 @@ async function handleConfirm() {
async function handleClosed() {
await formApi.resetForm();
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() {
try {
const res = await productList({
pageNum: 1,
pageSize: 1000,
enabled: '1',
});
const productOptions = res.rows.map((item) => ({
@ -128,15 +240,6 @@ async function getProductOptionList() {
componentProps: {
options: productOptions || [],
placeholder,
onChange: (value: number | string) => {
//
if (value) {
const selectedProduct = productOptions.find(
(option) => option.value === value,
);
formApi.setFieldValue('imgId', selectedProduct?.imgId || '');
}
},
},
fieldName: 'productId',
},
@ -150,5 +253,23 @@ async function getProductOptionList() {
<template>
<BasicDrawer :title="title">
<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>
</template>