refactor: 重构设备产品详情页面的属性、功能和事件定义
- 将属性、功能和事件定义抽离为单独的组件 - 优化了数据类型、表单类型等选项的管理 - 改进了输出参数的编辑功能 - 统一了保存和取消操作的样式 - 调整了部分UI样式,如描述字段的样式
This commit is contained in:
parent
fde2ec9bae
commit
f8619047c5
|
@ -21,3 +21,93 @@ export const deviceTypeOptions = [
|
|||
tooltip: '能挂载子设备与平台进行通信的设备',
|
||||
},
|
||||
];
|
||||
|
||||
// 数据类型选项
|
||||
export const dataTypeOptions = [
|
||||
{
|
||||
value: 'int',
|
||||
label: 'int(整数型)',
|
||||
},
|
||||
{
|
||||
value: 'long',
|
||||
label: 'long(长整数型)',
|
||||
},
|
||||
{
|
||||
value: 'float',
|
||||
label: 'float(单精度浮点型)',
|
||||
},
|
||||
{
|
||||
value: 'double',
|
||||
label: 'double(双精度浮点数)',
|
||||
},
|
||||
{
|
||||
value: 'string',
|
||||
label: 'text(字符串)',
|
||||
},
|
||||
{
|
||||
value: 'boolean',
|
||||
label: 'boolean(布尔型)',
|
||||
},
|
||||
{
|
||||
value: 'date',
|
||||
label: 'date(时间型)',
|
||||
},
|
||||
{
|
||||
value: 'enum',
|
||||
label: 'enum(枚举)',
|
||||
},
|
||||
// {
|
||||
// value: 'array',
|
||||
// label: 'array(数组)',
|
||||
// },
|
||||
// {
|
||||
// value: 'object',
|
||||
// label: 'object(结构体)',
|
||||
// },
|
||||
// {
|
||||
// value: 'file',
|
||||
// label: 'file(文件)',
|
||||
// },
|
||||
// {
|
||||
// value: 'password',
|
||||
// label: 'password(密码)',
|
||||
// },
|
||||
// {
|
||||
// value: 'geoPoint',
|
||||
// label: 'geoPoint(地理位置)',
|
||||
// }
|
||||
];
|
||||
|
||||
// 表单类型选项
|
||||
export const formTypeOptions = [
|
||||
{ label: '文本', value: 'input' },
|
||||
{ label: '开关', value: 'switch' },
|
||||
{ label: '数字', value: 'number' },
|
||||
{ label: '进度条', value: 'progress' },
|
||||
{ label: '选择器', value: 'select' },
|
||||
{ label: '时间选择器', value: 'time' },
|
||||
// { label: '文本域', value: 'textarea' },
|
||||
];
|
||||
|
||||
export const viewTypeOptions = [
|
||||
{ label: '文本', value: 'input' },
|
||||
{ label: '开关', value: 'switch' },
|
||||
{ label: '选择器', value: 'select' },
|
||||
{ label: '进度条', value: 'progress' },
|
||||
{ label: '图片', value: 'img' },
|
||||
{ label: '折线图', value: 'line' },
|
||||
{ label: '仪表盘', value: 'dashboard' },
|
||||
];
|
||||
|
||||
// 读写类型选项
|
||||
export const readWriteTypeOptions = [
|
||||
{ label: '读', value: 'R' },
|
||||
{ label: '写', value: 'W' },
|
||||
{ label: '读写', value: 'RW' },
|
||||
];
|
||||
|
||||
export const timeOptions = [
|
||||
{ label: 'yyyy-MM-dd HH:mm:ss', value: 'yyyy-MM-dd HH:mm:ss' },
|
||||
{ label: 'yyyy-MM-dd', value: 'yyyy-MM-dd' },
|
||||
{ label: 'HH:mm:ss', value: 'HH:mm:ss' },
|
||||
];
|
||||
|
|
|
@ -129,7 +129,7 @@ const productParams = computed(() =>
|
|||
<DescriptionsItem label="更新时间">
|
||||
{{ formatTime(productInfo.updateTime) }}
|
||||
</DescriptionsItem>
|
||||
<DescriptionsItem label="描述" :span="2">
|
||||
<DescriptionsItem label="描述">
|
||||
{{ productInfo.description || '暂无描述' }}
|
||||
</DescriptionsItem>
|
||||
</Descriptions>
|
||||
|
|
|
@ -0,0 +1,412 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Drawer,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
message,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Space,
|
||||
Table,
|
||||
Tag,
|
||||
Textarea,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { dataTypeOptions, formTypeOptions } from '#/constants/dicts';
|
||||
|
||||
import ParameterModal from './ParameterModal.vue';
|
||||
|
||||
interface EventData {
|
||||
id: string;
|
||||
name: string;
|
||||
sort: number;
|
||||
description: string;
|
||||
outputs: any[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
isEdit: boolean;
|
||||
data?: EventData;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:open', value: boolean): void;
|
||||
(e: 'save', data: EventData): 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 parameterType = ref('add');
|
||||
const parameterDataIndex = ref(-1);
|
||||
|
||||
// 输出参数编辑弹窗相关
|
||||
const outputParamModalVisible = ref(false);
|
||||
|
||||
const outputParamForm = ref<any>(null);
|
||||
|
||||
const outputColumns = ref([
|
||||
{
|
||||
title: '标识符',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '数据类型',
|
||||
dataIndex: 'dataType',
|
||||
key: 'dataType',
|
||||
scopedSlots: { customRender: 'dataType' },
|
||||
},
|
||||
{
|
||||
title: '是否必填',
|
||||
dataIndex: 'required',
|
||||
key: 'required',
|
||||
scopedSlots: { customRender: 'required' },
|
||||
},
|
||||
{
|
||||
title: '表单类型',
|
||||
dataIndex: 'formType',
|
||||
key: 'formType',
|
||||
scopedSlots: { customRender: 'formType' },
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 100,
|
||||
fixed: 'right',
|
||||
},
|
||||
]);
|
||||
|
||||
// 默认数据
|
||||
const defaultEventData: EventData = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 1,
|
||||
description: '',
|
||||
outputs: [],
|
||||
};
|
||||
|
||||
const formData = ref<EventData>({ ...defaultEventData });
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
id: [
|
||||
{ required: true, message: '请输入标识符', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-z]\w*$/i,
|
||||
message: '请输入以字母开头,只包含字母、数字和下划线的标识符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
// 'valueParams.dataType': [
|
||||
// { required: true, message: '请选择数据类型', trigger: 'blur' },
|
||||
// ],
|
||||
};
|
||||
|
||||
// 抽屉标题
|
||||
const drawerTitle = computed(() => {
|
||||
return props.isEdit ? '编辑事件' : '新增事件';
|
||||
});
|
||||
|
||||
// 新增输出参数
|
||||
const handleAddOutputParam = () => {
|
||||
parameterType.value = 'add';
|
||||
parameterDataIndex.value = -1;
|
||||
outputParamForm.value = null;
|
||||
outputParamModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除输出参数
|
||||
const handleDeleteOutputParam = (index: number) => {
|
||||
formData.value.outputs.splice(index, 1);
|
||||
};
|
||||
|
||||
// 确认输出参数
|
||||
const handleOutputParamsConfirm = (params: any[]) => {
|
||||
if (parameterType.value === 'add') {
|
||||
formData.value.outputs.push(params);
|
||||
} else if (parameterType.value === 'edit') {
|
||||
formData.value.outputs[parameterDataIndex.value] = params;
|
||||
} else {
|
||||
formData.value.outputs = params;
|
||||
}
|
||||
outputParamModalVisible.value = false;
|
||||
};
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
saveLoading.value = true;
|
||||
|
||||
emit('save', { ...formData.value });
|
||||
message.success('保存成功');
|
||||
visible.value = false;
|
||||
} catch {
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭抽屉
|
||||
const handleDrawerClose = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(formData.value, JSON.parse(JSON.stringify(defaultEventData)));
|
||||
};
|
||||
|
||||
// 监听数据变化
|
||||
watch(
|
||||
() => props.data,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
formData.value = { ...newVal };
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer
|
||||
v-model:open="visible"
|
||||
:title="drawerTitle"
|
||||
width="800px"
|
||||
@close="handleDrawerClose"
|
||||
>
|
||||
<Form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<Row :gutter="24">
|
||||
<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>
|
||||
|
||||
<!-- 事件特有字段 -->
|
||||
<!-- 输出参数 -->
|
||||
<Col :span="24">
|
||||
<FormItem label="输出参数" name="outputs">
|
||||
<div class="parameter-preview">
|
||||
<Table
|
||||
:columns="outputColumns"
|
||||
:data-source="formData.outputs"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'dataType'">
|
||||
{{
|
||||
dataTypeOptions.find(
|
||||
(item) => item.value === record.valueParams.dataType,
|
||||
)?.label
|
||||
}}
|
||||
</template>
|
||||
<template v-if="column.key === 'required'">
|
||||
<Tag color="processing">
|
||||
{{ record.required ? '是' : '否' }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'formType'">
|
||||
{{
|
||||
formTypeOptions.find(
|
||||
(item) => item.value === record.valueParams.formType,
|
||||
)?.label
|
||||
}}
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEditOutputParam(record, index)"
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Popconfirm
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDeleteOutputParam(index)"
|
||||
>
|
||||
<Button type="link" size="small" danger> 删除 </Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
<div class="add-button-container">
|
||||
<a-button
|
||||
@click="handleAddOutputParam"
|
||||
type="primary"
|
||||
class="add-button"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新增输出参数
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="12">
|
||||
<FormItem label="排序" name="sort">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.sort"
|
||||
placeholder="请输入排序"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="24">
|
||||
<FormItem label="描述" name="description">
|
||||
<Textarea
|
||||
v-model:value="formData.description"
|
||||
placeholder="请输入描述"
|
||||
:rows="3"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
|
||||
<template #footer>
|
||||
<Space>
|
||||
<Button @click="handleDrawerClose">取消</Button>
|
||||
<Button type="primary" @click="handleSave" :loading="saveLoading">
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
|
||||
<!-- 输入参数编辑弹窗 -->
|
||||
<ParameterModal
|
||||
v-model:open="outputParamModalVisible"
|
||||
:parameter-type="parameterType"
|
||||
:data="outputParamForm"
|
||||
@confirm="handleOutputParamsConfirm"
|
||||
/>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.enum-preview {
|
||||
.enum-items-preview {
|
||||
padding: 12px;
|
||||
margin-top: 12px;
|
||||
background-color: #fafafa;
|
||||
border-radius: 4px;
|
||||
|
||||
.preview-title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.preview-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.parameter-preview {
|
||||
.parameter-table {
|
||||
margin-top: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.header-item {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
text-align: center;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
.table-row {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.cell {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
text-align: center;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-button-container {
|
||||
padding-top: 12px;
|
||||
text-align: center;
|
||||
|
||||
.add-button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,504 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Drawer,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
InputPassword,
|
||||
message,
|
||||
Popconfirm,
|
||||
RadioButton,
|
||||
RadioGroup,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Tag,
|
||||
Textarea,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { dataTypeOptions, formTypeOptions } from '#/constants/dicts';
|
||||
|
||||
import ParameterModal from './ParameterModal.vue';
|
||||
|
||||
interface FunctionData {
|
||||
id: string;
|
||||
name: string;
|
||||
sort: number;
|
||||
description: string;
|
||||
async: boolean;
|
||||
inputs: any[];
|
||||
expands: {
|
||||
checkType: string;
|
||||
preCheck: boolean;
|
||||
staticPasswordValue: string;
|
||||
};
|
||||
outputs: any[];
|
||||
}
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
isEdit: boolean;
|
||||
data?: FunctionData;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:open', value: boolean): void;
|
||||
(e: 'save', data: FunctionData): 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 parameterType = ref('add');
|
||||
const parameterDataIndex = ref(-1);
|
||||
|
||||
// 参数编辑弹窗相关
|
||||
const inputParamModalVisible = ref(false);
|
||||
|
||||
const inputParamForm = ref<any>(null);
|
||||
|
||||
const asyncOptions = ref([
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false },
|
||||
]);
|
||||
|
||||
const preCheckOptions = ref([
|
||||
{ label: '是', value: true },
|
||||
{ label: '否', value: false },
|
||||
]);
|
||||
|
||||
const preCheckTypeOptions = ref([
|
||||
{ label: '用户密码', value: 'userPassword' },
|
||||
{ label: '固定密码', value: 'staticPassword' },
|
||||
{ label: '用户短信', value: 'userSms' },
|
||||
]);
|
||||
|
||||
const inputColumns = ref([
|
||||
{
|
||||
title: '标识符',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '数据类型',
|
||||
dataIndex: 'dataType',
|
||||
key: 'dataType',
|
||||
scopedSlots: { customRender: 'dataType' },
|
||||
},
|
||||
{
|
||||
title: '是否必填',
|
||||
dataIndex: 'required',
|
||||
key: 'required',
|
||||
scopedSlots: { customRender: 'required' },
|
||||
},
|
||||
{
|
||||
title: '表单类型',
|
||||
dataIndex: 'formType',
|
||||
key: 'formType',
|
||||
scopedSlots: { customRender: 'formType' },
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 100,
|
||||
fixed: 'right',
|
||||
},
|
||||
]);
|
||||
|
||||
// 默认数据
|
||||
const defaultFunctionData: FunctionData = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 1,
|
||||
description: '',
|
||||
async: false,
|
||||
expands: {
|
||||
// 是否开启前置校验
|
||||
preCheck: false,
|
||||
// 前置校验类型 userPassword用户密码 ,staticPassword 固定密码, userSms 用户短信
|
||||
checkType: 'userPassword',
|
||||
// 固定密码 前端md5加密
|
||||
staticPasswordValue: '',
|
||||
},
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
};
|
||||
|
||||
const formData = ref<FunctionData>({ ...defaultFunctionData });
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
id: [
|
||||
{ required: true, message: '请输入标识符', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-z]\w*$/i,
|
||||
message: '请输入以字母开头,只包含字母、数字和下划线的标识符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
// 抽屉标题
|
||||
const drawerTitle = computed(() => {
|
||||
return props.isEdit ? '编辑功能' : '新增功能';
|
||||
});
|
||||
|
||||
// 新增输入参数
|
||||
const handleAddInputParam = () => {
|
||||
parameterDataIndex.value = -1;
|
||||
parameterType.value = 'add';
|
||||
inputParamForm.value = null;
|
||||
inputParamModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 编辑输入参数
|
||||
const handleEditInputParam = (record: any, index: number) => {
|
||||
parameterDataIndex.value = index;
|
||||
parameterType.value = 'edit';
|
||||
inputParamForm.value = JSON.parse(JSON.stringify(record));
|
||||
inputParamModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 删除输入参数
|
||||
const handleDeleteInputParam = (index: number) => {
|
||||
formData.value.inputs.splice(index, 1);
|
||||
};
|
||||
|
||||
// 确认输入参数
|
||||
const handleInputParamsConfirm = (params: any) => {
|
||||
if (parameterType.value === 'add') {
|
||||
formData.value.inputs.push(params);
|
||||
} else if (parameterType.value === 'edit') {
|
||||
formData.value.inputs[parameterDataIndex.value] = params;
|
||||
} else {
|
||||
formData.value.inputs = params;
|
||||
}
|
||||
inputParamModalVisible.value = false;
|
||||
};
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
saveLoading.value = true;
|
||||
|
||||
emit('save', { ...formData.value });
|
||||
visible.value = false;
|
||||
} catch {
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭抽屉
|
||||
const handleDrawerClose = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(
|
||||
formData.value,
|
||||
JSON.parse(JSON.stringify(defaultFunctionData)),
|
||||
);
|
||||
};
|
||||
|
||||
// 监听数据变化
|
||||
watch(
|
||||
() => props.data,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
formData.value = { ...newVal };
|
||||
} else {
|
||||
resetForm();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer
|
||||
v-model:open="visible"
|
||||
:title="drawerTitle"
|
||||
width="800px"
|
||||
@close="handleDrawerClose"
|
||||
>
|
||||
<Form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<Row :gutter="24">
|
||||
<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>
|
||||
<!-- 输入参数 -->
|
||||
<Col :span="24">
|
||||
<FormItem label="输入参数" name="inputs">
|
||||
<div class="parameter-preview">
|
||||
<Table
|
||||
:columns="inputColumns"
|
||||
:data-source="formData.inputs"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'dataType'">
|
||||
{{
|
||||
dataTypeOptions.find(
|
||||
(item) => item.value === record.valueParams.dataType,
|
||||
)?.label
|
||||
}}
|
||||
</template>
|
||||
<template v-if="column.key === 'required'">
|
||||
<Tag color="processing">
|
||||
{{ record.required ? '是' : '否' }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'formType'">
|
||||
{{
|
||||
formTypeOptions.find(
|
||||
(item) => item.value === record.valueParams.formType,
|
||||
)?.label
|
||||
}}
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEditInputParam(record, index)"
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Popconfirm
|
||||
placement="left"
|
||||
title="确认删除?"
|
||||
@confirm="handleDeleteInputParam(index)"
|
||||
>
|
||||
<Button type="link" size="small" danger> 删除 </Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
<div class="add-button-container">
|
||||
<a-button
|
||||
@click="handleAddInputParam"
|
||||
type="primary"
|
||||
class="add-button"
|
||||
>
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新增输入参数
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 功能特有字段 -->
|
||||
<Col :span="12">
|
||||
<FormItem label="是否异步" name="async">
|
||||
<RadioGroup v-model:value="formData.async" button-style="solid">
|
||||
<RadioButton
|
||||
:value="item.value"
|
||||
v-for="item in asyncOptions"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RadioButton>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="12">
|
||||
<FormItem label="是否开启前置校验" name="expands.preCheck">
|
||||
<RadioGroup
|
||||
v-model:value="formData.expands.preCheck"
|
||||
button-style="solid"
|
||||
>
|
||||
<RadioButton
|
||||
:value="item.value"
|
||||
v-for="item in preCheckOptions"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RadioButton>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12" v-if="formData.expands.preCheck">
|
||||
<FormItem label="前置校验类型" name="expands.checkType">
|
||||
<Select
|
||||
v-model:value="formData.expands.checkType"
|
||||
placeholder="请选择前置校验类型"
|
||||
:options="preCheckTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12" v-if="formData.expands.checkType === 'staticPassword'">
|
||||
<FormItem label="固定密码" name="expands.staticPasswordValue">
|
||||
<InputPassword
|
||||
v-model:value="formData.expands.staticPasswordValue"
|
||||
placeholder="请输入固定密码"
|
||||
:visibility-toggle="false"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="12">
|
||||
<FormItem label="排序" name="sort">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.sort"
|
||||
placeholder="请输入排序"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="24">
|
||||
<FormItem label="描述" name="description">
|
||||
<Textarea
|
||||
v-model:value="formData.description"
|
||||
placeholder="请输入描述"
|
||||
:rows="3"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
|
||||
<template #footer>
|
||||
<Space>
|
||||
<Button @click="handleDrawerClose">取消</Button>
|
||||
<Button type="primary" @click="handleSave" :loading="saveLoading">
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
|
||||
<!-- 输入参数编辑弹窗 -->
|
||||
<ParameterModal
|
||||
v-model:open="inputParamModalVisible"
|
||||
:parameter-type="parameterType"
|
||||
:data="inputParamForm"
|
||||
@confirm="handleInputParamsConfirm"
|
||||
/>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.enum-preview {
|
||||
.enum-items-preview {
|
||||
padding: 12px;
|
||||
margin-top: 12px;
|
||||
background-color: #fafafa;
|
||||
border-radius: 4px;
|
||||
|
||||
.preview-title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.preview-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.parameter-preview {
|
||||
.parameter-table {
|
||||
margin-top: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
.header-item {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
text-align: center;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-body {
|
||||
.table-row {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.cell {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
text-align: center;
|
||||
border-right: 1px solid #f0f0f0;
|
||||
|
||||
&:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-button-container {
|
||||
padding-top: 12px;
|
||||
text-align: center;
|
||||
|
||||
.add-button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,28 +2,13 @@
|
|||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Drawer,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
message,
|
||||
Popconfirm,
|
||||
RadioButton,
|
||||
RadioGroup,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Table,
|
||||
Tag,
|
||||
Textarea,
|
||||
} from 'ant-design-vue';
|
||||
import { Button, message, Popconfirm, Space, Table, Tag } from 'ant-design-vue';
|
||||
|
||||
import EnumListModal from './EnumListModal.vue';
|
||||
import { dataTypeOptions, readWriteTypeOptions } from '#/constants/dicts';
|
||||
|
||||
import EventDrawer from './EventDrawer.vue';
|
||||
import FunctionDrawer from './FunctionDrawer.vue';
|
||||
import PropertyDrawer from './PropertyDrawer.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
metadata: any[];
|
||||
|
@ -38,139 +23,14 @@ const emit = defineEmits<{
|
|||
|
||||
const loading = ref(false);
|
||||
const drawerVisible = ref(false);
|
||||
const saveLoading = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const formRef = ref();
|
||||
|
||||
// 枚举列表弹窗相关
|
||||
const enumModalVisible = ref(false);
|
||||
const isEdit = ref(false);
|
||||
|
||||
const editDataIndex = ref(-1);
|
||||
|
||||
const tableData = ref<any[]>([]);
|
||||
|
||||
const defaultPropertiesFormData = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 1,
|
||||
description: '',
|
||||
required: false,
|
||||
expands: {
|
||||
source: 'device',
|
||||
type: 'R',
|
||||
},
|
||||
valueParams: {
|
||||
dataType: 'string',
|
||||
formType: 'input',
|
||||
length: null,
|
||||
viewType: 'input',
|
||||
unit: '',
|
||||
enumConf: [],
|
||||
},
|
||||
};
|
||||
|
||||
const formData = ref({});
|
||||
|
||||
const formRules = {
|
||||
id: [
|
||||
{ required: true, message: '请输入标识符', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-z]\w*$/i,
|
||||
message: '请输入以字母开头,只包含字母、数字和下划线的标识符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
valueParams: [{ required: true, message: '请选择数据类型', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
// 数据类型选项
|
||||
const dataTypeOptions = ref([
|
||||
{
|
||||
value: 'int',
|
||||
label: 'int(整数型)',
|
||||
},
|
||||
{
|
||||
value: 'long',
|
||||
label: 'long(长整数型)',
|
||||
},
|
||||
{
|
||||
value: 'float',
|
||||
label: 'float(单精度浮点型)',
|
||||
},
|
||||
{
|
||||
value: 'double',
|
||||
label: 'double(双精度浮点数)',
|
||||
},
|
||||
{
|
||||
value: 'string',
|
||||
label: 'text(字符串)',
|
||||
},
|
||||
{
|
||||
value: 'boolean',
|
||||
label: 'boolean(布尔型)',
|
||||
},
|
||||
{
|
||||
value: 'date',
|
||||
label: 'date(时间型)',
|
||||
},
|
||||
{
|
||||
value: 'enum',
|
||||
label: 'enum(枚举)',
|
||||
},
|
||||
// {
|
||||
// value: 'array',
|
||||
// label: 'array(数组)',
|
||||
// },
|
||||
// {
|
||||
// value: 'object',
|
||||
// label: 'object(结构体)',
|
||||
// },
|
||||
// {
|
||||
// value: 'file',
|
||||
// label: 'file(文件)',
|
||||
// },
|
||||
// {
|
||||
// value: 'password',
|
||||
// label: 'password(密码)',
|
||||
// },
|
||||
// {
|
||||
// value: 'geoPoint',
|
||||
// label: 'geoPoint(地理位置)',
|
||||
// }
|
||||
]);
|
||||
|
||||
// 表单类型选项
|
||||
const formTypeOptions = ref([
|
||||
{ label: '文本', value: 'input' },
|
||||
{ label: '开关', value: 'switch' },
|
||||
{ label: '数字', value: 'number' },
|
||||
{ label: '进度条', value: 'progress' },
|
||||
{ label: '选择器', value: 'select' },
|
||||
{ label: '时间选择器', value: 'time' },
|
||||
// { label: '文本域', value: 'textarea' },
|
||||
]);
|
||||
|
||||
const viewTypeOptions = ref([
|
||||
{ label: '文本', value: 'input' },
|
||||
{ label: '开关', value: 'switch' },
|
||||
{ label: '选择器', value: 'select' },
|
||||
{ label: '进度条', value: 'progress' },
|
||||
{ label: '图片', value: 'img' },
|
||||
{ label: '折线图', value: 'line' },
|
||||
{ label: '仪表盘', value: 'dashboard' },
|
||||
]);
|
||||
|
||||
// 读写类型选项
|
||||
const readWriteTypeOptions = ref([
|
||||
{ label: '读', value: 'R' },
|
||||
{ label: '写', value: 'W' },
|
||||
{ label: '读写', value: 'RW' },
|
||||
]);
|
||||
|
||||
const timeOptions = ref([
|
||||
{ label: 'yyyy-MM-dd HH:mm:ss', value: 'yyyy-MM-dd HH:mm:ss' },
|
||||
{ label: 'yyyy-MM-dd', value: 'yyyy-MM-dd' },
|
||||
{ label: 'HH:mm:ss', value: 'HH:mm:ss' },
|
||||
]);
|
||||
const formData = ref<any>(null);
|
||||
|
||||
// 表格列配置
|
||||
const columns = computed(() => {
|
||||
|
@ -273,11 +133,6 @@ const getTypeLabel = () => {
|
|||
return labels[props.type];
|
||||
};
|
||||
|
||||
// 抽屉标题
|
||||
const drawerTitle = computed(() => {
|
||||
return isEdit.value ? `编辑${getTypeLabel()}` : `新增${getTypeLabel()}`;
|
||||
});
|
||||
|
||||
// 加载数据
|
||||
const loadData = async () => {
|
||||
loading.value = true;
|
||||
|
@ -299,9 +154,10 @@ const handleAdd = () => {
|
|||
};
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (record: any) => {
|
||||
const handleEdit = (record: any, index: number) => {
|
||||
editDataIndex.value = index;
|
||||
isEdit.value = true;
|
||||
formData.value = structuredClone(record.value);
|
||||
formData.value = JSON.parse(JSON.stringify(record));
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
|
@ -321,54 +177,30 @@ const handleDelete = async (record: any) => {
|
|||
};
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
const handleSave = async (data: any) => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
saveLoading.value = true;
|
||||
|
||||
if (isEdit.value) {
|
||||
// 编辑模式
|
||||
const index = tableData.value.findIndex(
|
||||
(item) => item.id === formData.value.id,
|
||||
);
|
||||
if (index !== -1) {
|
||||
tableData.value[index] = { ...formData.value };
|
||||
if (editDataIndex.value === -1) {
|
||||
tableData.value.push({ ...data });
|
||||
} else {
|
||||
tableData.value[editDataIndex.value] = { ...data };
|
||||
}
|
||||
} else {
|
||||
// 新增模式
|
||||
tableData.value.push({ ...formData.value });
|
||||
tableData.value.push({ ...data });
|
||||
}
|
||||
|
||||
message.success('保存成功');
|
||||
drawerVisible.value = false;
|
||||
emit('change', tableData.value);
|
||||
} catch {
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭抽屉
|
||||
const handleDrawerClose = () => {
|
||||
drawerVisible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(formData.value, structuredClone(defaultPropertiesFormData));
|
||||
};
|
||||
|
||||
// 打开枚举列表编辑弹窗
|
||||
const handleEditEnum = () => {
|
||||
enumModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 确认枚举列表
|
||||
const handleEnumConfirm = (enumList: any[]) => {
|
||||
formData.value.valueParams.enumConf = enumList;
|
||||
enumModalVisible.value = false;
|
||||
formData.value = null;
|
||||
};
|
||||
|
||||
// 监听metadata变化
|
||||
|
@ -407,13 +239,13 @@ onMounted(() => {
|
|||
:pagination="false"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template #bodyCell="{ column, record, index }">
|
||||
<template v-if="column.key === 'action'">
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
@click="handleEdit(record)"
|
||||
@click="handleEdit(record, index)"
|
||||
v-access:code="['device:product:edit']"
|
||||
>
|
||||
编辑
|
||||
|
@ -461,247 +293,31 @@ onMounted(() => {
|
|||
</template>
|
||||
</Table>
|
||||
|
||||
<!-- 新增/编辑抽屉 -->
|
||||
<Drawer
|
||||
<!-- 属性定义抽屉 -->
|
||||
<PropertyDrawer
|
||||
v-if="type === 'properties'"
|
||||
v-model:open="drawerVisible"
|
||||
:title="drawerTitle"
|
||||
width="800px"
|
||||
@close="handleDrawerClose"
|
||||
>
|
||||
<Form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
layout="vertical"
|
||||
>
|
||||
<Row :gutter="24">
|
||||
<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>
|
||||
<!-- 值参数配置 -->
|
||||
<Col :span="24">
|
||||
<FormItem label="数据类型" name="dataType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.dataType"
|
||||
placeholder="请选择数据类型"
|
||||
:options="dataTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="表单类型" name="valueParams.formType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.formType"
|
||||
placeholder="请选择表单类型"
|
||||
:options="formTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="展示类型" name="valueParams.viewType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.viewType"
|
||||
placeholder="请选择展示类型"
|
||||
:options="viewTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="24" v-if="formData.valueParams.formType === 'switch'">
|
||||
<Row
|
||||
:gutter="24"
|
||||
style="
|
||||
padding-top: 16px;
|
||||
margin: 0;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
"
|
||||
>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关打开名称" name="valueParams.trueText">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.trueText"
|
||||
default-value="是"
|
||||
placeholder="请输入开关打开名称"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关打开值" name="valueParams.trueValue">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.trueValue"
|
||||
default-value="true"
|
||||
placeholder="请输入开关打开值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关关闭名称" name="valueParams.falseText">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.falseText"
|
||||
default-value="否"
|
||||
placeholder="请输入开关关闭名称"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关关闭值" name="valueParams.falseValue">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.falseValue"
|
||||
default-value="false"
|
||||
placeholder="请输入开关关闭值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
:is-edit="isEdit"
|
||||
:data="formData"
|
||||
@save="handleSave"
|
||||
/>
|
||||
|
||||
<Col :span="24" v-if="formData.valueParams.formType === 'select'">
|
||||
<FormItem label="枚举列表" name="valueParams.enumList">
|
||||
<a-button type="primary" @click="handleEditEnum">
|
||||
编辑枚举列表
|
||||
</a-button>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<!-- 功能定义抽屉 -->
|
||||
<FunctionDrawer
|
||||
v-if="type === 'functions'"
|
||||
v-model:open="drawerVisible"
|
||||
:is-edit="isEdit"
|
||||
:data="formData"
|
||||
@save="handleSave"
|
||||
/>
|
||||
|
||||
<Col
|
||||
:span="12"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<FormItem label="最小值" name="valueParams.min">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.min"
|
||||
placeholder="请输入最小值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col
|
||||
:span="12"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<FormItem label="最大值" name="valueParams.max">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.max"
|
||||
placeholder="请输入最大值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12" v-if="formData.valueParams.formType === 'input'">
|
||||
<FormItem label="长度" name="valueParams.length">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.length"
|
||||
placeholder="请输入长度"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col
|
||||
:span="12"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<FormItem label="小数位" name="valueParams.scale">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.scale"
|
||||
placeholder="请输入小数位"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="单位" name="valueParams.unit">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.unit"
|
||||
placeholder="请输入单位"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12" v-if="formData.valueParams.formType === 'time'">
|
||||
<FormItem label="时间格式" name="valueParams.format">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.format"
|
||||
placeholder="请选择时间格式"
|
||||
:options="timeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<!-- 属性特有字段 -->
|
||||
<FormItem label="是否必填" name="required">
|
||||
<Switch v-model:checked="formData.required" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<!-- 属性特有字段 -->
|
||||
<FormItem label="读写类型" name="type">
|
||||
<RadioGroup
|
||||
v-model:value="formData.expands.type"
|
||||
button-style="solid"
|
||||
>
|
||||
<RadioButton
|
||||
:value="item.value"
|
||||
v-for="item in readWriteTypeOptions"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RadioButton>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="12">
|
||||
<FormItem label="排序" name="sort">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.sort"
|
||||
placeholder="请输入排序"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="24">
|
||||
<FormItem label="描述" name="description">
|
||||
<Textarea
|
||||
v-model:value="formData.description"
|
||||
placeholder="请输入描述"
|
||||
:rows="3"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<Space>
|
||||
<Button @click="handleDrawerClose">取消</Button>
|
||||
<Button type="primary" @click="handleSave" :loading="saveLoading">
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Drawer>
|
||||
|
||||
<!-- 枚举列表编辑弹窗 -->
|
||||
<EnumListModal
|
||||
v-model:open="enumModalVisible"
|
||||
:enum-conf="formData.valueParams?.enumConf"
|
||||
@confirm="handleEnumConfirm"
|
||||
<!-- 事件定义抽屉 -->
|
||||
<EventDrawer
|
||||
v-if="type === 'events'"
|
||||
v-model:open="drawerVisible"
|
||||
:is-edit="isEdit"
|
||||
:data="formData"
|
||||
@save="handleSave"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,387 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
Col,
|
||||
Descriptions,
|
||||
DescriptionsItem,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
message,
|
||||
Modal,
|
||||
Row,
|
||||
Select,
|
||||
SelectOption,
|
||||
Switch,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { dataTypeOptions, formTypeOptions } from '#/constants/dicts';
|
||||
|
||||
import EnumListModal from './EnumListModal.vue';
|
||||
|
||||
interface ParameterItem {
|
||||
id: string;
|
||||
name: string;
|
||||
dataType: string;
|
||||
required: boolean;
|
||||
formType: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
parameterType: 'add' | 'edit';
|
||||
data?: ParameterItem[];
|
||||
}
|
||||
|
||||
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 defaultPropertyData: PropertyData = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 1,
|
||||
description: '',
|
||||
required: false,
|
||||
expands: {
|
||||
source: 'device',
|
||||
type: 'R',
|
||||
},
|
||||
valueParams: {
|
||||
dataType: 'string',
|
||||
formType: 'input',
|
||||
length: null,
|
||||
viewType: 'input',
|
||||
unit: '',
|
||||
enumConf: [],
|
||||
},
|
||||
};
|
||||
|
||||
const formRef = ref();
|
||||
const loading = ref(false);
|
||||
const enumModalVisible = ref(false);
|
||||
|
||||
const formData = ref<ParameterItem>({ ...defaultPropertyData });
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
id: [
|
||||
{ required: true, message: '请输入标识符', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-z]\w*$/i,
|
||||
message: '请输入以字母开头,只包含字母、数字和下划线的标识符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
dataType: [{ required: true, message: '请选择数据类型', trigger: 'blur' }],
|
||||
formType: [{ required: true, message: '请选择表单类型', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(
|
||||
formData.value,
|
||||
JSON.parse(JSON.stringify(defaultPropertyData)),
|
||||
);
|
||||
};
|
||||
|
||||
// 打开枚举列表编辑弹窗
|
||||
const handleEditEnum = () => {
|
||||
enumModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 确认枚举列表
|
||||
const handleEnumConfirm = (enumList: any[]) => {
|
||||
formData.value.valueParams.enumConf = enumList;
|
||||
enumModalVisible.value = false;
|
||||
};
|
||||
|
||||
// 弹窗标题
|
||||
const modalTitle = computed(() => {
|
||||
return props.parameterType === 'add' ? '新增参数' : '编辑参数';
|
||||
});
|
||||
|
||||
// 验证数据
|
||||
const validateData = (): boolean => {
|
||||
try {
|
||||
formRef.value.validate();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 确认
|
||||
const handleOk = async () => {
|
||||
if (!validateData()) {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
emit('confirm', JSON.parse(JSON.stringify(formData.value)));
|
||||
visible.value = false;
|
||||
message.success('保存成功');
|
||||
resetForm();
|
||||
} catch {
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 监听data变化,初始化数据
|
||||
watch(
|
||||
() => props.data,
|
||||
(newVal) => {
|
||||
if (newVal === null) {
|
||||
// 新增模式,重置表单
|
||||
resetForm();
|
||||
} else {
|
||||
// 如果有现有参数,可以用于编辑模式
|
||||
formData.value = JSON.parse(JSON.stringify(newVal));
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
:title="modalTitle"
|
||||
width="600px"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
:confirm-loading="loading"
|
||||
>
|
||||
<div class="parameter-form">
|
||||
<Form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
layout="vertical"
|
||||
>
|
||||
<FormItem label="标识符" name="id">
|
||||
<Input v-model:value="formData.id" placeholder="请输入标识符" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="名称" name="name">
|
||||
<Input v-model:value="formData.name" placeholder="请输入名称" />
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="数据类型" name="valueParams.dataType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.dataType"
|
||||
placeholder="请选择数据类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<SelectOption
|
||||
v-for="option in dataTypeOptions"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="表单类型" name="valueParams.formType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.formType"
|
||||
placeholder="请选择表单类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<SelectOption
|
||||
v-for="option in formTypeOptions"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ option.label }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<!-- 开关类型配置 -->
|
||||
<Row
|
||||
:gutter="24"
|
||||
style="
|
||||
padding-top: 16px;
|
||||
margin: 0;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
"
|
||||
v-if="formData.valueParams.formType === 'switch'"
|
||||
>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关打开名称" name="valueParams.trueText">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.trueText"
|
||||
default-value="是"
|
||||
placeholder="请输入开关打开名称"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关打开值" name="valueParams.trueValue">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.trueValue"
|
||||
default-value="true"
|
||||
placeholder="请输入开关打开值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关关闭名称" name="valueParams.falseText">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.falseText"
|
||||
default-value="否"
|
||||
placeholder="请输入开关关闭名称"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关关闭值" name="valueParams.falseValue">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.falseValue"
|
||||
default-value="false"
|
||||
placeholder="请输入开关关闭值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<!-- 选择器类型配置 -->
|
||||
<FormItem
|
||||
label="枚举列表"
|
||||
name="valueParams.enumConf"
|
||||
v-if="formData.valueParams.formType === 'select'"
|
||||
>
|
||||
<div class="enum-preview">
|
||||
<a-button type="primary" @click="handleEditEnum">
|
||||
编辑枚举列表
|
||||
</a-button>
|
||||
<Descriptions
|
||||
v-if="
|
||||
formData.valueParams.enumConf &&
|
||||
formData.valueParams.enumConf.length > 0
|
||||
"
|
||||
:column="4"
|
||||
bordered
|
||||
title=" "
|
||||
>
|
||||
<DescriptionsItem
|
||||
:label="`${item.text} :`"
|
||||
v-for="item in formData.valueParams.enumConf"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.value }}
|
||||
</DescriptionsItem>
|
||||
</Descriptions>
|
||||
</div>
|
||||
</FormItem>
|
||||
|
||||
<Row
|
||||
:gutter="24"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<Col :span="12">
|
||||
<FormItem label="最小值" name="valueParams.min">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.min"
|
||||
placeholder="请输入最小值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="最大值" name="valueParams.max">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.max"
|
||||
placeholder="请输入最大值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<FormItem
|
||||
label="小数位"
|
||||
name="valueParams.scale"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.scale"
|
||||
placeholder="请输入小数位"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label="长度"
|
||||
name="valueParams.length"
|
||||
v-if="formData.valueParams.formType === 'input'"
|
||||
>
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.length"
|
||||
placeholder="请输入长度"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label="时间格式"
|
||||
name="valueParams.format"
|
||||
v-if="formData.valueParams.formType === 'time'"
|
||||
>
|
||||
<Select
|
||||
v-model:value="formData.valueParams.format"
|
||||
placeholder="请选择时间格式"
|
||||
:options="timeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="是否必填" name="required">
|
||||
<Switch
|
||||
v-model:checked="formData.required"
|
||||
checked-children="是"
|
||||
un-checked-children="否"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<EnumListModal
|
||||
v-model:open="enumModalVisible"
|
||||
:enum-conf="formData.valueParams?.enumConf"
|
||||
@confirm="handleEnumConfirm"
|
||||
/>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.parameter-form {
|
||||
padding: 16px 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,468 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
Descriptions,
|
||||
DescriptionsItem,
|
||||
Drawer,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
message,
|
||||
RadioButton,
|
||||
RadioGroup,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Textarea,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
dataTypeOptions,
|
||||
formTypeOptions,
|
||||
readWriteTypeOptions,
|
||||
timeOptions,
|
||||
viewTypeOptions,
|
||||
} from '#/constants/dicts';
|
||||
|
||||
import EnumListModal from './EnumListModal.vue';
|
||||
|
||||
interface PropertyData {
|
||||
id: string;
|
||||
name: string;
|
||||
sort: number;
|
||||
description: string;
|
||||
required: boolean;
|
||||
expands: {
|
||||
source: string;
|
||||
type: string;
|
||||
};
|
||||
valueParams: {
|
||||
dataType: string;
|
||||
enumConf: any[];
|
||||
falseText?: string;
|
||||
falseValue?: string;
|
||||
format?: string;
|
||||
formType: string;
|
||||
length: any;
|
||||
max?: number;
|
||||
min?: number;
|
||||
scale?: number;
|
||||
trueText?: string;
|
||||
trueValue?: string;
|
||||
unit: string;
|
||||
viewType: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
isEdit: boolean;
|
||||
data?: PropertyData;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'update:open', value: boolean): void;
|
||||
(e: 'save', data: PropertyData): 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 enumModalVisible = ref(false);
|
||||
|
||||
// 默认数据
|
||||
const defaultPropertyData: PropertyData = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: 1,
|
||||
description: '',
|
||||
required: false,
|
||||
expands: {
|
||||
source: 'device',
|
||||
type: 'R',
|
||||
},
|
||||
valueParams: {
|
||||
dataType: 'string',
|
||||
formType: 'input',
|
||||
length: null,
|
||||
viewType: 'input',
|
||||
unit: '',
|
||||
enumConf: [],
|
||||
},
|
||||
};
|
||||
|
||||
const formData = ref<PropertyData>({ ...defaultPropertyData });
|
||||
|
||||
// 表单验证规则
|
||||
const formRules = {
|
||||
id: [
|
||||
{ required: true, message: '请输入标识符', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-z]\w*$/i,
|
||||
message: '请输入以字母开头,只包含字母、数字和下划线的标识符',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
// 'valueParams.dataType': [
|
||||
// { required: true, message: '请选择数据类型', trigger: 'blur' },
|
||||
// ],
|
||||
};
|
||||
|
||||
// 抽屉标题
|
||||
const drawerTitle = computed(() => {
|
||||
return props.isEdit ? '编辑属性' : '新增属性';
|
||||
});
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
Object.assign(
|
||||
formData.value,
|
||||
JSON.parse(JSON.stringify(defaultPropertyData)),
|
||||
);
|
||||
};
|
||||
|
||||
// 打开枚举列表编辑弹窗
|
||||
const handleEditEnum = () => {
|
||||
enumModalVisible.value = true;
|
||||
};
|
||||
|
||||
// 确认枚举列表
|
||||
const handleEnumConfirm = (enumList: any[]) => {
|
||||
formData.value.valueParams.enumConf = enumList;
|
||||
enumModalVisible.value = false;
|
||||
};
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await formRef.value.validate();
|
||||
saveLoading.value = true;
|
||||
|
||||
emit('save', { ...formData.value });
|
||||
visible.value = false;
|
||||
} catch {
|
||||
message.error('保存失败');
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭抽屉
|
||||
const handleDrawerClose = () => {
|
||||
visible.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 监听数据变化
|
||||
watch(
|
||||
() => props.data,
|
||||
(newVal) => {
|
||||
if (newVal === null) {
|
||||
resetForm();
|
||||
} else {
|
||||
formData.value = { ...newVal };
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Drawer
|
||||
v-model:open="visible"
|
||||
:title="drawerTitle"
|
||||
width="800px"
|
||||
@close="handleDrawerClose"
|
||||
>
|
||||
<Form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
|
||||
<Row :gutter="24">
|
||||
<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>
|
||||
|
||||
<!-- 值参数配置 -->
|
||||
<Col :span="24">
|
||||
<FormItem label="数据类型" name="valueParams.dataType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.dataType"
|
||||
placeholder="请选择数据类型"
|
||||
:options="dataTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="表单类型" name="valueParams.formType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.formType"
|
||||
placeholder="请选择表单类型"
|
||||
:options="formTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="展示类型" name="valueParams.viewType">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.viewType"
|
||||
placeholder="请选择展示类型"
|
||||
:options="viewTypeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 开关类型配置 -->
|
||||
<Col :span="24" v-if="formData.valueParams.formType === 'switch'">
|
||||
<Row
|
||||
:gutter="24"
|
||||
style="
|
||||
padding-top: 16px;
|
||||
margin: 0;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
"
|
||||
>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关打开名称" name="valueParams.trueText">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.trueText"
|
||||
default-value="是"
|
||||
placeholder="请输入开关打开名称"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关打开值" name="valueParams.trueValue">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.trueValue"
|
||||
default-value="true"
|
||||
placeholder="请输入开关打开值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关关闭名称" name="valueParams.falseText">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.falseText"
|
||||
default-value="否"
|
||||
placeholder="请输入开关关闭名称"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="开关关闭值" name="valueParams.falseValue">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.falseValue"
|
||||
default-value="false"
|
||||
placeholder="请输入开关关闭值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
|
||||
<!-- 选择器类型配置 -->
|
||||
<Col :span="24" v-if="formData.valueParams.formType === 'select'">
|
||||
<FormItem label="枚举列表" name="valueParams.enumConf">
|
||||
<div class="enum-preview">
|
||||
<a-button type="primary" @click="handleEditEnum">
|
||||
编辑枚举列表
|
||||
</a-button>
|
||||
<Descriptions
|
||||
v-if="
|
||||
formData.valueParams.enumConf &&
|
||||
formData.valueParams.enumConf.length > 0
|
||||
"
|
||||
:column="4"
|
||||
bordered
|
||||
title=" "
|
||||
>
|
||||
<DescriptionsItem
|
||||
:label="`${item.text} :`"
|
||||
v-for="item in formData.valueParams.enumConf"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.value }}
|
||||
</DescriptionsItem>
|
||||
</Descriptions>
|
||||
</div>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 数字类型配置 -->
|
||||
<Col
|
||||
:span="12"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<FormItem label="最小值" name="valueParams.min">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.min"
|
||||
placeholder="请输入最小值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col
|
||||
:span="12"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<FormItem label="最大值" name="valueParams.max">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.max"
|
||||
placeholder="请输入最大值"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12" v-if="formData.valueParams.formType === 'input'">
|
||||
<FormItem label="长度" name="valueParams.length">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.length"
|
||||
placeholder="请输入长度"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col
|
||||
:span="12"
|
||||
v-if="
|
||||
formData.valueParams.formType === 'number' ||
|
||||
formData.valueParams.formType === 'progress'
|
||||
"
|
||||
>
|
||||
<FormItem label="小数位" name="valueParams.scale">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.valueParams.scale"
|
||||
placeholder="请输入小数位"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="单位" name="valueParams.unit">
|
||||
<Input
|
||||
v-model:value="formData.valueParams.unit"
|
||||
placeholder="请输入单位"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12" v-if="formData.valueParams.formType === 'time'">
|
||||
<FormItem label="时间格式" name="valueParams.format">
|
||||
<Select
|
||||
v-model:value="formData.valueParams.format"
|
||||
placeholder="请选择时间格式"
|
||||
:options="timeOptions"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<!-- 属性特有字段 -->
|
||||
<Col :span="12">
|
||||
<FormItem label="是否必填" name="required">
|
||||
<Switch v-model:checked="formData.required" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="12">
|
||||
<FormItem label="读写类型" name="type">
|
||||
<RadioGroup
|
||||
v-model:value="formData.expands.type"
|
||||
button-style="solid"
|
||||
>
|
||||
<RadioButton
|
||||
:value="item.value"
|
||||
v-for="item in readWriteTypeOptions"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</RadioButton>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="12">
|
||||
<FormItem label="排序" name="sort">
|
||||
<InputNumber
|
||||
style="width: 100%"
|
||||
v-model:value="formData.sort"
|
||||
placeholder="请输入排序"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="24">
|
||||
<FormItem label="描述" name="description">
|
||||
<Textarea
|
||||
v-model:value="formData.description"
|
||||
placeholder="请输入描述"
|
||||
:rows="3"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
|
||||
<template #footer>
|
||||
<Space>
|
||||
<Button @click="handleDrawerClose">取消</Button>
|
||||
<Button type="primary" @click="handleSave" :loading="saveLoading">
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
|
||||
<!-- 枚举列表编辑弹窗 -->
|
||||
<EnumListModal
|
||||
v-model:open="enumModalVisible"
|
||||
:enum-conf="formData.valueParams?.enumConf"
|
||||
@confirm="handleEnumConfirm"
|
||||
/>
|
||||
</Drawer>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.enum-preview {
|
||||
.enum-items-preview {
|
||||
padding: 12px;
|
||||
margin-top: 12px;
|
||||
background-color: #fafafa;
|
||||
border-radius: 4px;
|
||||
|
||||
.preview-title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.preview-items {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue