JiShe.IOT.UI/apps/web-antd/src/views/components/DataPushRuleEditor.vue
2026-07-03 10:29:08 +08:00

161 lines
4.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import type { DataPushRule } from '#/api-client';
import { ref, toRaw, watch } from 'vue';
import { Input, Select } from 'ant-design-vue';
defineOptions({
name: 'DataPushRuleEditor',
});
const props = defineProps<{
// 是否禁用编辑(如设备未开启"覆盖产品配置"时)
disabled?: boolean;
rules?: DataPushRule[] | null;
}>();
const emit = defineEmits<{
(e: 'update:rules', value: DataPushRule[]): void;
}>();
// 枚举以数值传输(与后端一致;生成的字符串字面量类型仅为 Swagger 展示)
const dataTypeOptions = [
{ label: '属性', value: 1 },
{ label: '事件', value: 2 },
{ label: '状态', value: 3 },
];
const pushTypeOptions = [
{ label: 'HTTP POST', value: 1 },
{ label: 'Redis 普通订阅', value: 2 },
{ label: 'Redis 可靠订阅', value: 3 },
{ label: 'Redis List', value: 4 },
];
// 统一推送:整个产品/设备只有一种推送方式 + 一个目的地,数据类型可多选。
// 后端仍存多规则(每个类型一条、同目的地),此处负责"统一配置 ⇄ 多规则"互转。
const selectedTypes = ref<number[]>([]);
const pushType = ref<number>(1);
const pushServer = ref<string>('');
const pushInfo = ref<string>('');
const ruleName = ref<string>('');
// 记录最近一次抛出的数组引用,识别 v-model 回环,避免重置输入框(父级用 ref 存储会包 reactive 代理,故用 toRaw 比较)
let lastEmitted: DataPushRule[] | null = null;
// 兼容后端可能返回数值或字符串形式的枚举
function toNum(value: any): number {
if (typeof value === 'number') {
return value;
}
const map: Record<string, number> = {
Property: 1,
Event: 2,
Status: 3,
HttpPost: 1,
NormalReisSubscription: 2,
ReliableReisSubscription: 3,
RedisListPush: 4,
};
return map[value] ?? Number(value);
}
watch(
() => props.rules,
(val) => {
if (toRaw(val) === lastEmitted) {
return;
}
const list = Array.isArray(val) ? val : [];
if (list.length === 0) {
selectedTypes.value = [];
pushType.value = 1;
pushServer.value = '';
pushInfo.value = '';
ruleName.value = '';
return;
}
// 统一模式:各规则推送方式/目的地一致,取首条;数据类型收集去重
const first = list[0];
selectedTypes.value = [...new Set(list.map((r) => toNum(r.dataType)))];
pushType.value = toNum(first.pushType);
pushServer.value = first.pushServer ?? '';
pushInfo.value = first.pushInfo ?? '';
ruleName.value = first.ruleName ?? '';
},
{ immediate: true },
);
function emitChange() {
// 把"多选类型 + 单一目的地"展开为多条同目的地规则
const out = selectedTypes.value.map((t) => ({
ruleName: ruleName.value,
enabled: true,
dataType: t,
includeNames: null,
pushType: pushType.value,
pushServer: pushServer.value,
pushInfo: pushInfo.value,
}));
lastEmitted = out as unknown as DataPushRule[];
emit('update:rules', lastEmitted);
}
</script>
<template>
<div class="space-y-3">
<div class="flex items-center gap-2">
<span class="w-28 flex-shrink-0 text-sm text-gray-600">数据类型</span>
<Select
v-model:value="selectedTypes"
mode="multiple"
:options="dataTypeOptions"
:disabled="disabled"
class="flex-1"
placeholder="选择要推送的数据类型(可多选)"
@change="emitChange"
/>
</div>
<div class="flex items-center gap-2">
<span class="w-28 flex-shrink-0 text-sm text-gray-600">推送方式</span>
<Select
v-model:value="pushType"
:options="pushTypeOptions"
:disabled="disabled"
class="flex-1"
@change="emitChange"
/>
</div>
<div class="flex items-center gap-2">
<span class="w-28 flex-shrink-0 text-sm text-gray-600">服务地址</span>
<Input
v-model:value="pushServer"
:disabled="disabled"
class="flex-1"
placeholder="HTTPhttp://ip:portRedisip:port"
@change="emitChange"
/>
</div>
<div class="flex items-center gap-2">
<span class="w-28 flex-shrink-0 text-sm text-gray-600">路径 / 主题 / KEY</span>
<Input
v-model:value="pushInfo"
:disabled="disabled"
class="flex-1"
placeholder="HTTP 为推送路径Redis 为主题或 key"
@change="emitChange"
/>
</div>
<div class="flex items-center gap-2">
<span class="w-28 flex-shrink-0 text-sm text-gray-600">备注</span>
<Input
v-model:value="ruleName"
:disabled="disabled"
class="flex-1"
placeholder="可空"
@change="emitChange"
/>
</div>
</div>
</template>