feat: 新增属性分组功能
- 在产品详情页面添加属性分组标签页 - 实现属性分组的创建、编辑和删除功能 - 添加属性分组的排序和描述信息 - 优化属性选择界面,支持搜索和过滤功能
This commit is contained in:
parent
f8619047c5
commit
0c0a1994b2
|
@ -1,3 +1,5 @@
|
||||||
|
启动项目pnpm run dev:antd
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://github.com/anncwb/vue-vben-admin">
|
<a href="https://github.com/anncwb/vue-vben-admin">
|
||||||
<img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp">
|
<img alt="VbenAdmin Logo" width="215" src="https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp">
|
||||||
|
|
|
@ -118,6 +118,7 @@ const formRules = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
|
||||||
// 'valueParams.dataType': [
|
// 'valueParams.dataType': [
|
||||||
// { required: true, message: '请选择数据类型', trigger: 'blur' },
|
// { required: true, message: '请选择数据类型', trigger: 'blur' },
|
||||||
// ],
|
// ],
|
||||||
|
|
|
@ -155,6 +155,7 @@ const formRules = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
|
||||||
};
|
};
|
||||||
|
|
||||||
// 抽屉标题
|
// 抽屉标题
|
||||||
|
|
|
@ -38,6 +38,7 @@ const currentMetadata = ref<any>({
|
||||||
properties: [],
|
properties: [],
|
||||||
functions: [],
|
functions: [],
|
||||||
events: [],
|
events: [],
|
||||||
|
propertyGroups: [], // 新增属性分组
|
||||||
});
|
});
|
||||||
|
|
||||||
// 标签页切换
|
// 标签页切换
|
||||||
|
@ -97,6 +98,7 @@ const loadMetadata = async () => {
|
||||||
properties: [],
|
properties: [],
|
||||||
functions: [],
|
functions: [],
|
||||||
events: [],
|
events: [],
|
||||||
|
propertyGroups: [], // 新增属性分组
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
currentMetadata.value = props.productInfo.metadata
|
currentMetadata.value = props.productInfo.metadata
|
||||||
|
@ -212,6 +214,7 @@ const handleSave = async () => {
|
||||||
metadata.properties.sort((a: any, b: any) => a.sort - b.sort);
|
metadata.properties.sort((a: any, b: any) => a.sort - b.sort);
|
||||||
metadata.functions.sort((a: any, b: any) => a.sort - b.sort);
|
metadata.functions.sort((a: any, b: any) => a.sort - b.sort);
|
||||||
metadata.events.sort((a: any, b: any) => a.sort - b.sort);
|
metadata.events.sort((a: any, b: any) => a.sort - b.sort);
|
||||||
|
metadata.propertyGroups.sort((a: any, b: any) => a.sort - b.sort); // 新增属性分组排序
|
||||||
await productUpdateById(props.productInfo.id, {
|
await productUpdateById(props.productInfo.id, {
|
||||||
id: props.productInfo.id,
|
id: props.productInfo.id,
|
||||||
metadata: JSON.stringify(metadata),
|
metadata: JSON.stringify(metadata),
|
||||||
|
@ -244,6 +247,11 @@ const handleMetadataChange = (data: any) => {
|
||||||
currentMetadata.value.properties = data;
|
currentMetadata.value.properties = data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'propertyGroups': {
|
||||||
|
// 新增属性分组处理
|
||||||
|
currentMetadata.value.propertyGroups = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
// No default
|
// No default
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -328,6 +336,16 @@ loadMetadata();
|
||||||
@refresh="loadMetadata"
|
@refresh="loadMetadata"
|
||||||
/>
|
/>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
|
<TabPane key="propertyGroups" tab="属性分组">
|
||||||
|
<MetadataTable
|
||||||
|
type="propertyGroups"
|
||||||
|
:product-id="productInfo.id"
|
||||||
|
:metadata="currentMetadata.propertyGroups"
|
||||||
|
:available-properties="currentMetadata.properties"
|
||||||
|
@change="handleMetadataChange"
|
||||||
|
@refresh="loadMetadata"
|
||||||
|
/>
|
||||||
|
</TabPane>
|
||||||
<TabPane key="functions" tab="功能定义">
|
<TabPane key="functions" tab="功能定义">
|
||||||
<MetadataTable
|
<MetadataTable
|
||||||
type="functions"
|
type="functions"
|
||||||
|
|
|
@ -9,11 +9,13 @@ import { dataTypeOptions, readWriteTypeOptions } from '#/constants/dicts';
|
||||||
import EventDrawer from './EventDrawer.vue';
|
import EventDrawer from './EventDrawer.vue';
|
||||||
import FunctionDrawer from './FunctionDrawer.vue';
|
import FunctionDrawer from './FunctionDrawer.vue';
|
||||||
import PropertyDrawer from './PropertyDrawer.vue';
|
import PropertyDrawer from './PropertyDrawer.vue';
|
||||||
|
import PropertyGroupDrawer from './PropertyGroupDrawer.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
availableProperties?: any[]; // 可用的属性列表(用于属性分组)
|
||||||
metadata: any[];
|
metadata: any[];
|
||||||
productId: string;
|
productId: string;
|
||||||
type: 'events' | 'functions' | 'properties' | 'tags';
|
type: 'events' | 'functions' | 'properties' | 'propertyGroups' | 'tags';
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -67,6 +69,18 @@ const columns = computed(() => {
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 属性分组特殊列
|
||||||
|
if (props.type === 'propertyGroups') {
|
||||||
|
baseColumns.splice(3, 0, {
|
||||||
|
title: '属性数',
|
||||||
|
dataIndex: 'properties',
|
||||||
|
key: 'count',
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ record }: any) => record.properties?.length || 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 功能定义特殊列
|
// 功能定义特殊列
|
||||||
if (props.type === 'properties') {
|
if (props.type === 'properties') {
|
||||||
baseColumns.splice(
|
baseColumns.splice(
|
||||||
|
@ -129,6 +143,7 @@ const getTypeLabel = () => {
|
||||||
functions: '功能',
|
functions: '功能',
|
||||||
events: '事件',
|
events: '事件',
|
||||||
tags: '标签',
|
tags: '标签',
|
||||||
|
propertyGroups: '分组',
|
||||||
};
|
};
|
||||||
return labels[props.type];
|
return labels[props.type];
|
||||||
};
|
};
|
||||||
|
@ -319,6 +334,16 @@ onMounted(() => {
|
||||||
:data="formData"
|
:data="formData"
|
||||||
@save="handleSave"
|
@save="handleSave"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 属性分组抽屉 -->
|
||||||
|
<PropertyGroupDrawer
|
||||||
|
v-if="type === 'propertyGroups'"
|
||||||
|
v-model:open="drawerVisible"
|
||||||
|
:is-edit="isEdit"
|
||||||
|
:data="formData"
|
||||||
|
:available-properties="props.availableProperties || []"
|
||||||
|
@save="handleSave"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ const formRules = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
|
||||||
// 'valueParams.dataType': [
|
// 'valueParams.dataType': [
|
||||||
// { required: true, message: '请选择数据类型', trigger: 'blur' },
|
// { required: true, message: '请选择数据类型', trigger: 'blur' },
|
||||||
// ],
|
// ],
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Col,
|
||||||
|
Drawer,
|
||||||
|
Form,
|
||||||
|
FormItem,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
message,
|
||||||
|
Row,
|
||||||
|
Space,
|
||||||
|
Table,
|
||||||
|
Textarea,
|
||||||
|
} from 'ant-design-vue';
|
||||||
|
|
||||||
|
import PropertySelectionModal from './PropertySelectionModal.vue';
|
||||||
|
|
||||||
|
interface PropertyGroupData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
sort: number;
|
||||||
|
description: string;
|
||||||
|
properties: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
open: boolean;
|
||||||
|
isEdit: boolean;
|
||||||
|
data?: PropertyGroupData;
|
||||||
|
availableProperties: any[]; // 可用的属性列表
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:open', value: boolean): void;
|
||||||
|
(e: 'save', data: PropertyGroupData): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const visible = computed({
|
||||||
|
get: () => props.open,
|
||||||
|
set: (value) => emit('update:open', value),
|
||||||
|
});
|
||||||
|
|
||||||
|
const formRef = ref();
|
||||||
|
const saveLoading = ref(false);
|
||||||
|
|
||||||
|
// 属性选择弹窗
|
||||||
|
const propertySelectionVisible = ref(false);
|
||||||
|
|
||||||
|
// 默认数据
|
||||||
|
const defaultPropertyGroupData: PropertyGroupData = {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
sort: 1,
|
||||||
|
description: '',
|
||||||
|
properties: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const formData = ref<PropertyGroupData>({ ...defaultPropertyGroupData });
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const formRules = {
|
||||||
|
id: [
|
||||||
|
{ required: true, message: '请输入标识', trigger: 'blur' },
|
||||||
|
{
|
||||||
|
pattern: /^[a-z]\w*$/i,
|
||||||
|
message: '请输入以字母开头,只包含字母、数字和下划线的标识',
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||||
|
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
// 属性表格列配置
|
||||||
|
const propertyColumns = [
|
||||||
|
{
|
||||||
|
title: '标识符',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
width: 150,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
width: 80,
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
const resetForm = () => {
|
||||||
|
formData.value = { ...defaultPropertyGroupData };
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听数据变化
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
(newData) => {
|
||||||
|
if (newData) {
|
||||||
|
formData.value = JSON.parse(JSON.stringify(newData));
|
||||||
|
} else {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// 添加属性
|
||||||
|
const handleAddProperty = () => {
|
||||||
|
propertySelectionVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除属性
|
||||||
|
const handleDeleteProperty = (propertyId: string) => {
|
||||||
|
const index = formData.value.properties.findIndex((p) => p.id === propertyId);
|
||||||
|
if (index !== -1) {
|
||||||
|
formData.value.properties.splice(index, 1);
|
||||||
|
message.success('删除属性成功');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 属性选择确认
|
||||||
|
const handlePropertySelectionConfirm = (selectedProperties: any[]) => {
|
||||||
|
// 过滤掉已经选择的属性
|
||||||
|
const newProperties = selectedProperties.filter(
|
||||||
|
(prop) => !formData.value.properties.some((p) => p.id === prop.id),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (newProperties.length > 0) {
|
||||||
|
formData.value.properties.push(...newProperties);
|
||||||
|
message.success(`成功添加 ${newProperties.length} 个属性`);
|
||||||
|
} else {
|
||||||
|
message.warning('没有可添加的新属性');
|
||||||
|
}
|
||||||
|
|
||||||
|
propertySelectionVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
const handleSave = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value.validate();
|
||||||
|
saveLoading.value = true;
|
||||||
|
|
||||||
|
emit('save', JSON.parse(JSON.stringify(formData.value)));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('表单验证失败:', error);
|
||||||
|
} finally {
|
||||||
|
saveLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭抽屉
|
||||||
|
const handleClose = () => {
|
||||||
|
visible.value = false;
|
||||||
|
resetForm();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Drawer
|
||||||
|
v-model:open="visible"
|
||||||
|
:title="isEdit ? '编辑分组' : '添加'"
|
||||||
|
width="800px"
|
||||||
|
@close="handleClose"
|
||||||
|
>
|
||||||
|
<Form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||||
|
<Row :gutter="16">
|
||||||
|
<Col :span="12">
|
||||||
|
<FormItem label="标识" name="id">
|
||||||
|
<Input v-model:value="formData.id" placeholder="请输入" />
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
<Col :span="12">
|
||||||
|
<FormItem label="名称" name="name">
|
||||||
|
<Input v-model:value="formData.name" placeholder="请输入" />
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Col :span="24">
|
||||||
|
<FormItem label="属性列表" name="properties">
|
||||||
|
<Table
|
||||||
|
:columns="propertyColumns"
|
||||||
|
:data-source="formData.properties"
|
||||||
|
:pagination="false"
|
||||||
|
row-key="id"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
@click="handleDeleteProperty(record.id)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
<div class="add-button-container">
|
||||||
|
<a-button
|
||||||
|
@click="handleAddProperty"
|
||||||
|
type="primary"
|
||||||
|
class="add-button"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<PlusOutlined />
|
||||||
|
</template>
|
||||||
|
添加属性
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
<Col :span="12">
|
||||||
|
<FormItem label="排序" name="sort">
|
||||||
|
<InputNumber
|
||||||
|
v-model:value="formData.sort"
|
||||||
|
:min="1"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请输入"
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
<Col :span="24">
|
||||||
|
<FormItem label="描述" name="description">
|
||||||
|
<Textarea
|
||||||
|
v-model:value="formData.description"
|
||||||
|
placeholder="请输入"
|
||||||
|
:rows="3"
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
</Col>
|
||||||
|
</Form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<Space>
|
||||||
|
<Button @click="handleClose">取消</Button>
|
||||||
|
<Button type="primary" :loading="saveLoading" @click="handleSave">
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 属性选择弹窗 -->
|
||||||
|
<PropertySelectionModal
|
||||||
|
v-model:open="propertySelectionVisible"
|
||||||
|
:available-properties="props.availableProperties"
|
||||||
|
:selected-properties="formData.properties"
|
||||||
|
@confirm="handlePropertySelectionConfirm"
|
||||||
|
/>
|
||||||
|
</Drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.property-section {
|
||||||
|
padding-top: 16px;
|
||||||
|
margin: 24px 0;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #262626;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-button-container {
|
||||||
|
padding-top: 12px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.add-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,231 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { Button, Input, Modal, Space, Table, Tag } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { dataTypeOptions, readWriteTypeOptions } from '#/constants/dicts';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
open: boolean;
|
||||||
|
availableProperties: any[]; // 可用的属性列表
|
||||||
|
selectedProperties: any[]; // 已选择的属性列表
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:open', value: boolean): void;
|
||||||
|
(e: 'confirm', value: any[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const visible = computed({
|
||||||
|
get: () => props.open,
|
||||||
|
set: (value) => emit('update:open', value),
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchName = ref('');
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'selection',
|
||||||
|
key: 'selection',
|
||||||
|
width: 40,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '标识',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据类型',
|
||||||
|
dataIndex: 'dataType',
|
||||||
|
key: 'dataType',
|
||||||
|
width: 120,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '读写类型',
|
||||||
|
dataIndex: 'readWriteType',
|
||||||
|
key: 'readWriteType',
|
||||||
|
width: 100,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '说明',
|
||||||
|
dataIndex: 'description',
|
||||||
|
key: 'description',
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 过滤后的属性列表
|
||||||
|
const filteredProperties = computed(() => {
|
||||||
|
let result = [...props.availableProperties];
|
||||||
|
|
||||||
|
// 过滤掉已选择的属性
|
||||||
|
result = result.filter(
|
||||||
|
(prop) => !props.selectedProperties.some((p) => p.id === prop.id),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 按名称过滤
|
||||||
|
if (searchName.value) {
|
||||||
|
result = result.filter(
|
||||||
|
(prop) =>
|
||||||
|
prop.name.toLowerCase().includes(searchName.value.toLowerCase()) ||
|
||||||
|
prop.id.toLowerCase().includes(searchName.value.toLowerCase()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 选中的属性
|
||||||
|
const selectedPropertyIds = ref<string[]>([]);
|
||||||
|
|
||||||
|
// 重置搜索
|
||||||
|
const handleReset = () => {
|
||||||
|
searchName.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
const handleSearch = () => {
|
||||||
|
// 搜索逻辑已在computed中实现
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认选择
|
||||||
|
const handleConfirm = () => {
|
||||||
|
const selectedProperties = filteredProperties.value.filter((prop) =>
|
||||||
|
selectedPropertyIds.value.includes(prop.id),
|
||||||
|
);
|
||||||
|
emit('confirm', selectedProperties);
|
||||||
|
selectedPropertyIds.value = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消
|
||||||
|
const handleCancel = () => {
|
||||||
|
selectedPropertyIds.value = [];
|
||||||
|
visible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听弹窗打开,重置选择
|
||||||
|
watch(
|
||||||
|
() => visible.value,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
selectedPropertyIds.value = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// 获取数据类型标签
|
||||||
|
const getDataTypeLabel = (dataType: string) => {
|
||||||
|
const option = dataTypeOptions.find((item) => item.value === dataType);
|
||||||
|
return option ? option.label : dataType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取读写类型标签
|
||||||
|
const getReadWriteTypeLabel = (type: string) => {
|
||||||
|
const option = readWriteTypeOptions.find((item) => item.value === type);
|
||||||
|
return option ? option.label : type;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
v-model:open="visible"
|
||||||
|
title="选择属性"
|
||||||
|
width="1000px"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
@ok="handleConfirm"
|
||||||
|
ok-text="确定"
|
||||||
|
cancel-text="取消"
|
||||||
|
>
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<div class="search-section">
|
||||||
|
<Space>
|
||||||
|
标识/名称:
|
||||||
|
<Input
|
||||||
|
v-model:value="searchName"
|
||||||
|
placeholder="请输入标识和名称搜索"
|
||||||
|
style="width: 200px"
|
||||||
|
allow-clear
|
||||||
|
/>
|
||||||
|
<Button @click="handleReset">重置</Button>
|
||||||
|
<Button type="primary" @click="handleSearch">查询</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 属性列表 -->
|
||||||
|
<Table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="filteredProperties"
|
||||||
|
:pagination="false"
|
||||||
|
row-key="id"
|
||||||
|
size="small"
|
||||||
|
:row-selection="{
|
||||||
|
selectedRowKeys: selectedPropertyIds,
|
||||||
|
onChange: (selectedRowKeys: string[]) => {
|
||||||
|
selectedPropertyIds = selectedRowKeys;
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'dataType'">
|
||||||
|
<Tag color="processing">
|
||||||
|
{{
|
||||||
|
getDataTypeLabel(record.valueParams?.dataType || record.dataType)
|
||||||
|
}}
|
||||||
|
</Tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'readWriteType'">
|
||||||
|
<Tag color="processing">
|
||||||
|
{{
|
||||||
|
getReadWriteTypeLabel(
|
||||||
|
record.expands?.type || record.readWriteType,
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</Tag>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'description'">
|
||||||
|
{{ record.description || '-' }}
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
<!-- 分页信息 -->
|
||||||
|
<div class="pagination-info">
|
||||||
|
<span>
|
||||||
|
第 1-{{ filteredProperties.length }} 条/总共{{
|
||||||
|
filteredProperties.length
|
||||||
|
}}
|
||||||
|
条
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.search-section {
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue