top推荐

This commit is contained in:
2025-11-25 16:00:09 +08:00
parent 24c5188eb0
commit 48ee6442b3
6 changed files with 414 additions and 138 deletions

View File

@@ -0,0 +1,191 @@
<template>
<div class="params-container" v-if="paramsSchema && paramsSchema.length">
<div
v-for="param in paramsSchema"
:key="param.name"
class="param-item"
>
<span class="param-label">
{{ param.description }}
<span class="param-type">({{ param.type }})</span>
</span>
<!-- 文本输入框 -->
<el-input
v-if="param.type === 'Input'"
v-model="innerValue[param.name]"
:placeholder="`请输入${param.description}`"
clearable
/>
<!-- 数字输入框 -->
<el-input-number
v-else-if="param.type === 'InputNumber'"
v-model="innerNumberMap[param.name]"
:placeholder="`请输入${param.description}`"
controls-position="right"
style="width: 100%"
/>
<!-- 日期选择器 -->
<el-date-picker
v-else-if="param.type === 'DatePicker'"
v-model="innerValue[param.name]"
type="date"
:placeholder="`请选择${param.description}`"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
clearable
style="width: 100%"
/>
<!-- 日期范围选择器 -->
<el-date-picker
v-else-if="param.type === 'DateRangePicker'"
v-model="innerValue[param.name]"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
clearable
style="width: 100%"
/>
<!-- 布尔开关 -->
<el-switch
v-else-if="param.type === 'Switch'"
v-model="innerBoolMap[param.name]"
active-text=""
inactive-text=""
/>
<!-- 下拉选择器 -->
<el-select
v-else-if="param.type === 'Select'"
v-model="innerValue[param.name]"
:placeholder="`请选择${param.description}`"
clearable
style="width: 100%"
>
<el-option
v-for="option in param.options || []"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, watch, reactive } from 'vue';
interface ParamOption {
label: string;
value: string | number | boolean;
}
interface ParamSchemaItem {
name: string;
description: string;
type:
| 'Input'
| 'InputNumber'
| 'DatePicker'
| 'DateRangePicker'
| 'Switch'
| 'Select';
valueType?: string;
value?: any;
required?: boolean;
options?: ParamOption[];
}
interface Props {
paramsSchema: ParamSchemaItem[];
modelValue: Record<string, any>;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(e: 'update:modelValue', value: Record<string, any>): void;
}>();
// 内部值使用 reactive保证双向绑定
const innerValue = reactive<Record<string, any>>({});
// 为了兼容不同类型控件,做一些视图层的映射
const innerNumberMap = computed({
get() {
return innerValue as Record<string, number | undefined>;
},
set(val: Record<string, number | undefined>) {
Object.assign(innerValue, val);
}
});
const innerBoolMap = computed({
get() {
return innerValue as Record<string, boolean | undefined>;
},
set(val: Record<string, boolean | undefined>) {
Object.assign(innerValue, val);
}
});
// 初始化 / 外部变更时同步
watch(
() => props.modelValue,
(val) => {
Object.keys(innerValue).forEach((k) => delete innerValue[k]);
if (val) {
Object.assign(innerValue, val);
}
},
{ immediate: true, deep: true }
);
// 内部变更时向外同步
watch(
innerValue,
(val) => {
emit('update:modelValue', { ...val });
},
{ deep: true }
);
</script>
<style scoped lang="scss">
.params-container {
padding: 12px;
background-color: #f8f9fa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
.param-item {
margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
.param-label {
display: block;
margin-bottom: 8px;
font-size: 13px;
color: #606266;
font-weight: 500;
.param-type {
color: #909399;
font-weight: normal;
font-size: 12px;
margin-left: 4px;
}
}
}
</style>

View File

@@ -12,3 +12,4 @@ export { default as GenericSelector } from './GenericSelector.vue';
export { default as TreeNode } from './TreeNode.vue';
export { default as Notice } from './Notice.vue';
export { default as ChangeHome } from './ChangeHome.vue';
export { default as DynamicParamForm} from './DynamicParamForm.vue'