docs(iot): 新增 codex 评审入口 + 登记异步竞态不修决策
- review-for-codex.md:本轮修复背景 + 决策 + 文件清单 + 给 codex 的 5 项重点关注。与 bug.md(待修源头) / bug_ignore.md(不修登记) 形成三文件分工,后续 codex / 二次评审不会丢上下文 - bug_ignore.md/I-1:登记 scene 表单 3 处异步竞态(property-selector / device-selector / device-control-config 的 watch 异步加载)不修决策。 评估理由:触发窗口极窄、低频操作、~40 行 epoch 模板代码成本不匹配、 vue3 源也未做。复评条件:API 层接入 AbortController 时顺手补、 用户实际反馈、改后端 push 模式pull/345/head
parent
df8e23542b
commit
9d665bd6b9
|
|
@ -206,7 +206,7 @@ defineExpose({
|
||||||
</Select>
|
</Select>
|
||||||
<Space>
|
<Space>
|
||||||
<Button type="primary" @click="handleQuery">
|
<Button type="primary" @click="handleQuery">
|
||||||
<IconifyIcon icon="ep:search" class="mr-5px" /> 搜索
|
<IconifyIcon icon="ep:search" class="mr-[5px]" /> 搜索
|
||||||
</Button>
|
</Button>
|
||||||
<Switch
|
<Switch
|
||||||
v-model:checked="autoRefresh"
|
v-model:checked="autoRefresh"
|
||||||
|
|
|
||||||
|
|
@ -227,23 +227,25 @@ async function handlePropertyPost() {
|
||||||
async function handleEventPost(row: ThingModelApi.ThingModel) {
|
async function handleEventPost(row: ThingModelApi.ThingModel) {
|
||||||
try {
|
try {
|
||||||
const valueStr = formData.value[row.identifier!];
|
const valueStr = formData.value[row.identifier!];
|
||||||
let params: any = {};
|
let eventValue: any;
|
||||||
|
|
||||||
if (valueStr) {
|
if (valueStr) {
|
||||||
try {
|
try {
|
||||||
params = JSON.parse(valueStr);
|
eventValue = JSON.parse(valueStr);
|
||||||
} catch {
|
} catch {
|
||||||
message.error('事件参数格式错误,请输入有效的JSON格式');
|
message.error('事件参数格式错误,请输入有效的JSON格式');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 与后端 IotDeviceEventPostReqDTO 对齐 :{ identifier, value, time }
|
||||||
await sendDeviceMessage({
|
await sendDeviceMessage({
|
||||||
deviceId: props.device.id!,
|
deviceId: props.device.id!,
|
||||||
method: IotDeviceMessageMethodEnum.EVENT_POST.method,
|
method: IotDeviceMessageMethodEnum.EVENT_POST.method,
|
||||||
params: {
|
params: {
|
||||||
identifier: row.identifier,
|
identifier: row.identifier,
|
||||||
params,
|
value: eventValue,
|
||||||
|
time: Date.now(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -309,23 +311,24 @@ async function handlePropertySet() {
|
||||||
async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
|
async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
|
||||||
try {
|
try {
|
||||||
const valueStr = formData.value[row.identifier!];
|
const valueStr = formData.value[row.identifier!];
|
||||||
let params: any = {};
|
let inputParams: any = {};
|
||||||
|
|
||||||
if (valueStr) {
|
if (valueStr) {
|
||||||
try {
|
try {
|
||||||
params = JSON.parse(valueStr);
|
inputParams = JSON.parse(valueStr);
|
||||||
} catch {
|
} catch {
|
||||||
message.error('服务参数格式错误,请输入有效的JSON格式');
|
message.error('服务参数格式错误,请输入有效的JSON格式');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 与后端 IotDeviceServiceInvokeReqDTO 对齐 :{ identifier, inputParams }
|
||||||
await sendDeviceMessage({
|
await sendDeviceMessage({
|
||||||
deviceId: props.device.id!,
|
deviceId: props.device.id!,
|
||||||
method: IotDeviceMessageMethodEnum.SERVICE_INVOKE.method,
|
method: IotDeviceMessageMethodEnum.SERVICE_INVOKE.method,
|
||||||
params: {
|
params: {
|
||||||
identifier: row.identifier,
|
identifier: row.identifier,
|
||||||
params,
|
inputParams,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ onBeforeUnmount(() => {
|
||||||
<Switch
|
<Switch
|
||||||
v-model:checked="autoRefresh"
|
v-model:checked="autoRefresh"
|
||||||
checked-children="定时刷新"
|
checked-children="定时刷新"
|
||||||
class="ml-20px"
|
class="ml-[20px]"
|
||||||
un-checked-children="定时刷新"
|
un-checked-children="定时刷新"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ onMounted(() => {
|
||||||
<Button
|
<Button
|
||||||
v-if="hasAccessByCodes(['iot:device:update'])"
|
v-if="hasAccessByCodes(['iot:device:update'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
||||||
@click="emit('edit', item)"
|
@click="emit('edit', item)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
||||||
|
|
@ -221,7 +221,7 @@ onMounted(() => {
|
||||||
<Button
|
<Button
|
||||||
v-if="hasAccessByCodes(['iot:device:query'])"
|
v-if="hasAccessByCodes(['iot:device:query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
||||||
@click="emit('detail', item.id!)"
|
@click="emit('detail', item.id!)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
||||||
|
|
@ -230,7 +230,7 @@ onMounted(() => {
|
||||||
<Button
|
<Button
|
||||||
v-if="hasAccessByCodes(['iot:device:message-query'])"
|
v-if="hasAccessByCodes(['iot:device:message-query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
||||||
@click="emit('model', item.id!)"
|
@click="emit('model', item.id!)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:database" class="mr-1" />
|
<IconifyIcon icon="lucide:database" class="mr-1" />
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ onMounted(() => {
|
||||||
<Button
|
<Button
|
||||||
v-if="hasAccessByCodes(['iot:product:update'])"
|
v-if="hasAccessByCodes(['iot:product:update'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
||||||
@click="emit('edit', item)"
|
@click="emit('edit', item)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
||||||
|
|
@ -197,7 +197,7 @@ onMounted(() => {
|
||||||
<Button
|
<Button
|
||||||
v-if="hasAccessByCodes(['iot:product:query'])"
|
v-if="hasAccessByCodes(['iot:product:query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
||||||
@click="emit('detail', item.id)"
|
@click="emit('detail', item.id)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
||||||
|
|
@ -206,7 +206,7 @@ onMounted(() => {
|
||||||
<Button
|
<Button
|
||||||
v-if="hasAccessByCodes(['iot:thing-model:query'])"
|
v-if="hasAccessByCodes(['iot:thing-model:query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
||||||
@click="emit('thingModel', item.id)"
|
@click="emit('thingModel', item.id)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:git-branch" class="mr-1" />
|
<IconifyIcon icon="lucide:git-branch" class="mr-1" />
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ async function loadThingModelProperties(productId: number) {
|
||||||
property.accessMode === IoTThingModelAccessModeEnum.WRITE_ONLY.value),
|
property.accessMode === IoTThingModelAccessModeEnum.WRITE_ONLY.value),
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载物模型属性失败:', error);
|
console.error('加载物模型属性失败 :', error);
|
||||||
thingModelProperties.value = [];
|
thingModelProperties.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
loadingThingModel.value = false;
|
loadingThingModel.value = false;
|
||||||
|
|
@ -193,7 +193,7 @@ async function loadServiceList(productId: number) {
|
||||||
|
|
||||||
serviceList.value = tslData.services;
|
serviceList.value = tslData.services;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载服务列表失败:', error);
|
console.error('加载服务列表失败 :', error);
|
||||||
serviceList.value = [];
|
serviceList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
loadingServices.value = false;
|
loadingServices.value = false;
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ async function getDeviceList() {
|
||||||
const data = await getDeviceListByProductId(props.productId);
|
const data = await getDeviceListByProductId(props.productId);
|
||||||
deviceList.value = [DEVICE_SELECTOR_OPTIONS.ALL_DEVICES, ...(data || [])];
|
deviceList.value = [DEVICE_SELECTOR_OPTIONS.ALL_DEVICES, ...(data || [])];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取设备列表失败:', error);
|
console.error('获取设备列表失败 :', error);
|
||||||
deviceList.value = [DEVICE_SELECTOR_OPTIONS.ALL_DEVICES];
|
deviceList.value = [DEVICE_SELECTOR_OPTIONS.ALL_DEVICES];
|
||||||
} finally {
|
} finally {
|
||||||
deviceLoading.value = false;
|
deviceLoading.value = false;
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ async function loadThingModelTSL() {
|
||||||
const tsl = await getThingModelTSLByProductId(props.productId);
|
const tsl = await getThingModelTSLByProductId(props.productId);
|
||||||
propertyList.value = parseThingModelData(tsl);
|
propertyList.value = parseThingModelData(tsl);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取物模型 TSL 失败:', error);
|
console.error('获取物模型 TSL 失败 :', error);
|
||||||
propertyList.value = [];
|
propertyList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ defineExpose({
|
||||||
</ElSelect>
|
</ElSelect>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<ElButton type="primary" @click="handleQuery">
|
<ElButton type="primary" @click="handleQuery">
|
||||||
<IconifyIcon icon="ep:search" class="mr-5px" /> 搜索
|
<IconifyIcon icon="ep:search" class="mr-[5px]" /> 搜索
|
||||||
</ElButton>
|
</ElButton>
|
||||||
<ElSwitch
|
<ElSwitch
|
||||||
v-model="autoRefresh"
|
v-model="autoRefresh"
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,6 @@ function useFormSchema(): VbenFormSchema[] {
|
||||||
componentProps: {
|
componentProps: {
|
||||||
placeholder: '请选择物模型属性',
|
placeholder: '请选择物模型属性',
|
||||||
filterable: true,
|
filterable: true,
|
||||||
filterMethod(input: string, option: any) {
|
|
||||||
return option.label.toLowerCase().includes(input.toLowerCase());
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
dependencies: {
|
dependencies: {
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
|
|
|
||||||
|
|
@ -119,23 +119,25 @@ async function handlePropertyPost() {
|
||||||
async function handleEventPost(row: ThingModelApi.ThingModel) {
|
async function handleEventPost(row: ThingModelApi.ThingModel) {
|
||||||
try {
|
try {
|
||||||
const valueStr = formData.value[row.identifier!];
|
const valueStr = formData.value[row.identifier!];
|
||||||
let params: any = {};
|
let eventValue: any;
|
||||||
|
|
||||||
if (valueStr) {
|
if (valueStr) {
|
||||||
try {
|
try {
|
||||||
params = JSON.parse(valueStr);
|
eventValue = JSON.parse(valueStr);
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error('事件参数格式错误,请输入有效的JSON格式');
|
ElMessage.error('事件参数格式错误,请输入有效的JSON格式');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 与后端 IotDeviceEventPostReqDTO 对齐 :{ identifier, value, time }
|
||||||
await sendDeviceMessage({
|
await sendDeviceMessage({
|
||||||
deviceId: props.device.id!,
|
deviceId: props.device.id!,
|
||||||
method: IotDeviceMessageMethodEnum.EVENT_POST.method,
|
method: IotDeviceMessageMethodEnum.EVENT_POST.method,
|
||||||
params: {
|
params: {
|
||||||
identifier: row.identifier,
|
identifier: row.identifier,
|
||||||
params,
|
value: eventValue,
|
||||||
|
time: Date.now(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -201,23 +203,24 @@ async function handlePropertySet() {
|
||||||
async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
|
async function handleServiceInvoke(row: ThingModelApi.ThingModel) {
|
||||||
try {
|
try {
|
||||||
const valueStr = formData.value[row.identifier!];
|
const valueStr = formData.value[row.identifier!];
|
||||||
let params: any = {};
|
let inputParams: any = {};
|
||||||
|
|
||||||
if (valueStr) {
|
if (valueStr) {
|
||||||
try {
|
try {
|
||||||
params = JSON.parse(valueStr);
|
inputParams = JSON.parse(valueStr);
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error('服务参数格式错误,请输入有效的JSON格式');
|
ElMessage.error('服务参数格式错误,请输入有效的JSON格式');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 与后端 IotDeviceServiceInvokeReqDTO 对齐 :{ identifier, inputParams }
|
||||||
await sendDeviceMessage({
|
await sendDeviceMessage({
|
||||||
deviceId: props.device.id!,
|
deviceId: props.device.id!,
|
||||||
method: IotDeviceMessageMethodEnum.SERVICE_INVOKE.method,
|
method: IotDeviceMessageMethodEnum.SERVICE_INVOKE.method,
|
||||||
params: {
|
params: {
|
||||||
identifier: row.identifier,
|
identifier: row.identifier,
|
||||||
params,
|
inputParams,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -287,7 +287,7 @@ onBeforeUnmount(() => {
|
||||||
<ElSwitch
|
<ElSwitch
|
||||||
v-model="autoRefresh"
|
v-model="autoRefresh"
|
||||||
active-text="定时刷新"
|
active-text="定时刷新"
|
||||||
class="ml-20px"
|
class="ml-[20px]"
|
||||||
inactive-text="定时刷新"
|
inactive-text="定时刷新"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ onMounted(() => {
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAccessByCodes(['iot:device:update'])"
|
v-if="hasAccessByCodes(['iot:device:update'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
||||||
@click="emit('edit', item)"
|
@click="emit('edit', item)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
||||||
|
|
@ -217,7 +217,7 @@ onMounted(() => {
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAccessByCodes(['iot:device:query'])"
|
v-if="hasAccessByCodes(['iot:device:query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
||||||
@click="emit('detail', item.id!)"
|
@click="emit('detail', item.id!)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
||||||
|
|
@ -226,7 +226,7 @@ onMounted(() => {
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAccessByCodes(['iot:device:message-query'])"
|
v-if="hasAccessByCodes(['iot:device:message-query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
||||||
@click="emit('model', item.id!)"
|
@click="emit('model', item.id!)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:database" class="mr-1" />
|
<IconifyIcon icon="lucide:database" class="mr-1" />
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ onMounted(() => {
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAccessByCodes(['iot:product:update'])"
|
v-if="hasAccessByCodes(['iot:product:update'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#1890ff] !text-[13px] !text-[#1890ff] transition-all duration-200 hover:!bg-[#1890ff] hover:!text-white"
|
||||||
@click="emit('edit', item)"
|
@click="emit('edit', item)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
<IconifyIcon icon="lucide:edit" class="mr-1" />
|
||||||
|
|
@ -194,7 +194,7 @@ onMounted(() => {
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAccessByCodes(['iot:product:query'])"
|
v-if="hasAccessByCodes(['iot:product:query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#52c41a] !text-[13px] !text-[#52c41a] transition-all duration-200 hover:!bg-[#52c41a] hover:!text-white"
|
||||||
@click="emit('detail', item.id)"
|
@click="emit('detail', item.id)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
<IconifyIcon icon="lucide:eye" class="mr-1" />
|
||||||
|
|
@ -203,7 +203,7 @@ onMounted(() => {
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="hasAccessByCodes(['iot:thing-model:query'])"
|
v-if="hasAccessByCodes(['iot:thing-model:query'])"
|
||||||
size="small"
|
size="small"
|
||||||
class="!h-8 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
class="!h-8 min-w-0 flex-1 rounded-md !border-[#fa8c16] !text-[13px] !text-[#fa8c16] transition-all duration-200 hover:!bg-[#fa8c16] hover:!text-white"
|
||||||
@click="emit('thingModel', item.id)"
|
@click="emit('thingModel', item.id)"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="lucide:git-branch" class="mr-1" />
|
<IconifyIcon icon="lucide:git-branch" class="mr-1" />
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ function handleOperatorChange() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gap-16px flex flex-col">
|
<div class="gap-[16px] flex flex-col">
|
||||||
<!-- 条件类型选择 -->
|
<!-- 条件类型选择 -->
|
||||||
<ElRow :gutter="16">
|
<ElRow :gutter="16">
|
||||||
<ElCol :span="8">
|
<ElCol :span="8">
|
||||||
|
|
@ -213,7 +213,7 @@ function handleOperatorChange() {
|
||||||
v-if="
|
v-if="
|
||||||
condition.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS
|
condition.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS
|
||||||
"
|
"
|
||||||
class="gap-16px flex flex-col"
|
class="gap-[16px] flex flex-col"
|
||||||
>
|
>
|
||||||
<!-- 状态和操作符选择 -->
|
<!-- 状态和操作符选择 -->
|
||||||
<ElRow :gutter="16">
|
<ElRow :gutter="16">
|
||||||
|
|
@ -266,7 +266,7 @@ function handleOperatorChange() {
|
||||||
v-else-if="
|
v-else-if="
|
||||||
condition.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY
|
condition.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY
|
||||||
"
|
"
|
||||||
class="space-y-16px"
|
class="space-y-[16px]"
|
||||||
>
|
>
|
||||||
<!-- 属性配置 -->
|
<!-- 属性配置 -->
|
||||||
<ElRow :gutter="16">
|
<ElRow :gutter="16">
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ async function loadThingModelProperties(productId: number) {
|
||||||
property.accessMode === IoTThingModelAccessModeEnum.WRITE_ONLY.value),
|
property.accessMode === IoTThingModelAccessModeEnum.WRITE_ONLY.value),
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载物模型属性失败:', error);
|
console.error('加载物模型属性失败 :', error);
|
||||||
thingModelProperties.value = [];
|
thingModelProperties.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
loadingThingModel.value = false;
|
loadingThingModel.value = false;
|
||||||
|
|
@ -206,7 +206,7 @@ async function loadServiceList(productId: number) {
|
||||||
|
|
||||||
serviceList.value = tslData.services;
|
serviceList.value = tslData.services;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载服务列表失败:', error);
|
console.error('加载服务列表失败 :', error);
|
||||||
serviceList.value = [];
|
serviceList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
loadingServices.value = false;
|
loadingServices.value = false;
|
||||||
|
|
@ -339,7 +339,7 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gap-16px flex flex-col">
|
<div class="gap-[16px] flex flex-col">
|
||||||
<!-- 产品和设备选择 - 与触发器保持一致的分离式选择器 -->
|
<!-- 产品和设备选择 - 与触发器保持一致的分离式选择器 -->
|
||||||
<ElRow :gutter="16">
|
<ElRow :gutter="16">
|
||||||
<ElCol :span="12">
|
<ElCol :span="12">
|
||||||
|
|
@ -362,7 +362,7 @@ watch(
|
||||||
</ElRow>
|
</ElRow>
|
||||||
|
|
||||||
<!-- 服务选择 - 服务调用类型时显示 -->
|
<!-- 服务选择 - 服务调用类型时显示 -->
|
||||||
<div v-if="action.productId && isServiceInvokeAction" class="space-y-16px">
|
<div v-if="action.productId && isServiceInvokeAction" class="space-y-[16px]">
|
||||||
<ElFormItem label="服务" required>
|
<ElFormItem label="服务" required>
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="action.identifier"
|
v-model="action.identifier"
|
||||||
|
|
@ -393,7 +393,7 @@ watch(
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
|
|
||||||
<!-- 服务参数配置 -->
|
<!-- 服务参数配置 -->
|
||||||
<div v-if="action.identifier" class="space-y-16px">
|
<div v-if="action.identifier" class="space-y-[16px]">
|
||||||
<ElFormItem label="服务参数" required>
|
<ElFormItem label="服务参数" required>
|
||||||
<JsonParamsInput
|
<JsonParamsInput
|
||||||
v-model="paramsValue"
|
v-model="paramsValue"
|
||||||
|
|
@ -406,7 +406,7 @@ watch(
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 控制参数配置 - 属性设置类型时显示 -->
|
<!-- 控制参数配置 - 属性设置类型时显示 -->
|
||||||
<div v-if="action.productId && isPropertySetAction" class="space-y-16px">
|
<div v-if="action.productId && isPropertySetAction" class="space-y-[16px]">
|
||||||
<!-- 参数配置 -->
|
<!-- 参数配置 -->
|
||||||
<ElFormItem label="参数" required>
|
<ElFormItem label="参数" required>
|
||||||
<JsonParamsInput
|
<JsonParamsInput
|
||||||
|
|
|
||||||
|
|
@ -93,23 +93,23 @@ function removeConditionGroup() {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gap-16px flex flex-col">
|
<div class="gap-[16px] flex flex-col">
|
||||||
<!-- 主条件配置 - 默认直接展示 -->
|
<!-- 主条件配置 - 默认直接展示 -->
|
||||||
<div class="space-y-16px">
|
<div class="space-y-[16px]">
|
||||||
<!-- 主条件配置 -->
|
<!-- 主条件配置 -->
|
||||||
<div class="gap-16px flex flex-col">
|
<div class="gap-[16px] flex flex-col">
|
||||||
<!-- 主条件配置 -->
|
<!-- 主条件配置 -->
|
||||||
<div class="space-y-16px">
|
<div class="space-y-[16px]">
|
||||||
<!-- 主条件头部 - 与附加条件组保持一致的绿色风格 -->
|
<!-- 主条件头部 - 与附加条件组保持一致的绿色风格 -->
|
||||||
<div
|
<div
|
||||||
class="p-16px rounded-8px flex items-center justify-between border border-green-200 bg-gradient-to-r from-green-50 to-emerald-50"
|
class="p-[16px] rounded-[8px] flex items-center justify-between border border-green-200 bg-gradient-to-r from-green-50 to-emerald-50"
|
||||||
>
|
>
|
||||||
<div class="gap-12px flex items-center">
|
<div class="gap-[12px] flex items-center">
|
||||||
<div
|
<div
|
||||||
class="gap-8px text-16px font-600 flex items-center text-green-700"
|
class="gap-[8px] text-[16px] font-600 flex items-center text-green-700"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="w-24px h-24px text-12px flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
class="w-[24px] h-[24px] text-[12px] flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
||||||
>
|
>
|
||||||
主
|
主
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -131,19 +131,19 @@ function removeConditionGroup() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 条件组配置 -->
|
<!-- 条件组配置 -->
|
||||||
<div class="space-y-16px">
|
<div class="space-y-[16px]">
|
||||||
<!-- 条件组配置 -->
|
<!-- 条件组配置 -->
|
||||||
<div class="gap-16px flex flex-col">
|
<div class="gap-[16px] flex flex-col">
|
||||||
<!-- 条件组容器头部 -->
|
<!-- 条件组容器头部 -->
|
||||||
<div
|
<div
|
||||||
class="p-16px rounded-8px flex items-center justify-between border border-green-200 bg-gradient-to-r from-green-50 to-emerald-50"
|
class="p-[16px] rounded-[8px] flex items-center justify-between border border-green-200 bg-gradient-to-r from-green-50 to-emerald-50"
|
||||||
>
|
>
|
||||||
<div class="gap-12px flex items-center">
|
<div class="gap-[12px] flex items-center">
|
||||||
<div
|
<div
|
||||||
class="gap-8px text-16px font-600 flex items-center text-green-700"
|
class="gap-[8px] text-[16px] font-600 flex items-center text-green-700"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="w-24px h-24px text-12px flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
class="w-[24px] h-[24px] text-[12px] flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
||||||
>
|
>
|
||||||
组
|
组
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -154,7 +154,7 @@ function removeConditionGroup() {
|
||||||
{{ trigger.conditionGroups?.length || 0 }} 个子条件组
|
{{ trigger.conditionGroups?.length || 0 }} 个子条件组
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</div>
|
</div>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<ElButton
|
<ElButton
|
||||||
type="primary"
|
type="primary"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
@ -174,7 +174,7 @@ function removeConditionGroup() {
|
||||||
<!-- 子条件组列表 -->
|
<!-- 子条件组列表 -->
|
||||||
<div
|
<div
|
||||||
v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0"
|
v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0"
|
||||||
class="space-y-16px"
|
class="space-y-[16px]"
|
||||||
>
|
>
|
||||||
<!-- 逻辑关系说明 -->
|
<!-- 逻辑关系说明 -->
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
|
|
@ -185,17 +185,17 @@ function removeConditionGroup() {
|
||||||
>
|
>
|
||||||
<!-- 子条件组容器 -->
|
<!-- 子条件组容器 -->
|
||||||
<div
|
<div
|
||||||
class="rounded-8px border-2 border-orange-200 bg-orange-50 shadow-sm transition-shadow hover:shadow-md"
|
class="rounded-[8px] border-2 border-orange-200 bg-orange-50 shadow-sm transition-shadow hover:shadow-md"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="p-16px rounded-t-6px flex items-center justify-between border-b border-orange-200 bg-gradient-to-r from-orange-50 to-yellow-50"
|
class="p-[16px] rounded-t-6px flex items-center justify-between border-b border-orange-200 bg-gradient-to-r from-orange-50 to-yellow-50"
|
||||||
>
|
>
|
||||||
<div class="gap-12px flex items-center">
|
<div class="gap-[12px] flex items-center">
|
||||||
<div
|
<div
|
||||||
class="gap-8px text-16px font-600 flex items-center text-orange-700"
|
class="gap-[8px] text-[16px] font-600 flex items-center text-orange-700"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="w-24px h-24px text-12px flex items-center justify-center rounded-full bg-orange-500 font-bold text-white"
|
class="w-[24px] h-[24px] text-[12px] flex items-center justify-center rounded-full bg-orange-500 font-bold text-white"
|
||||||
>
|
>
|
||||||
{{ subGroupIndex + 1 }}
|
{{ subGroupIndex + 1 }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -233,19 +233,19 @@ function removeConditionGroup() {
|
||||||
<!-- 子条件组间的'或'连接符 -->
|
<!-- 子条件组间的'或'连接符 -->
|
||||||
<div
|
<div
|
||||||
v-if="subGroupIndex < trigger.conditionGroups!.length - 1"
|
v-if="subGroupIndex < trigger.conditionGroups!.length - 1"
|
||||||
class="py-12px flex items-center justify-center"
|
class="py-[12px] flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<!-- 连接线 -->
|
<!-- 连接线 -->
|
||||||
<div class="w-32px h-1px bg-orange-300"></div>
|
<div class="w-[32px] h-[1px] bg-orange-300"></div>
|
||||||
<!-- 或标签 -->
|
<!-- 或标签 -->
|
||||||
<div
|
<div
|
||||||
class="px-16px py-6px rounded-full border-2 border-orange-300 bg-orange-100"
|
class="px-[16px] py-[6px] rounded-full border-2 border-orange-300 bg-orange-100"
|
||||||
>
|
>
|
||||||
<span class="text-14px font-600 text-orange-600">或</span>
|
<span class="text-[14px] font-600 text-orange-600">或</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 连接线 -->
|
<!-- 连接线 -->
|
||||||
<div class="w-32px h-1px bg-orange-300"></div>
|
<div class="w-[32px] h-[1px] bg-orange-300"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -255,13 +255,13 @@ function removeConditionGroup() {
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="p-24px rounded-8px border-2 border-dashed border-orange-200 bg-orange-50 text-center"
|
class="p-[24px] rounded-[8px] border-2 border-dashed border-orange-200 bg-orange-50 text-center"
|
||||||
>
|
>
|
||||||
<div class="gap-12px flex flex-col items-center">
|
<div class="gap-[12px] flex flex-col items-center">
|
||||||
<IconifyIcon icon="lucide:plus" class="text-32px text-orange-400" />
|
<IconifyIcon icon="lucide:plus" class="text-[32px] text-orange-400" />
|
||||||
<div class="text-orange-600">
|
<div class="text-orange-600">
|
||||||
<p class="text-14px font-500 mb-4px">暂无子条件组</p>
|
<p class="text-[14px] font-500 mb-[4px]">暂无子条件组</p>
|
||||||
<p class="text-12px">点击上方"添加子条件组"按钮开始配置</p>
|
<p class="text-[12px]">点击上方"添加子条件组"按钮开始配置</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ function updateCondition(
|
||||||
>
|
>
|
||||||
<!-- 条件配置 -->
|
<!-- 条件配置 -->
|
||||||
<div
|
<div
|
||||||
class="rounded-3px bg-fill-color-blank border border-border shadow-sm"
|
class="rounded-[3px] bg-fill-color-blank border border-border shadow-sm"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-t-1 bg-fill-color-blank flex items-center justify-between border-b border-border p-3"
|
class="rounded-t-1 bg-fill-color-blank flex items-center justify-between border-b border-border p-3"
|
||||||
|
|
|
||||||
|
|
@ -157,24 +157,24 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElCard
|
<ElCard
|
||||||
class="rounded-8px border border-[var(--el-border-color-light)]"
|
class="rounded-[8px] border border-[var(--el-border-color-light)]"
|
||||||
shadow="never"
|
shadow="never"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<IconifyIcon
|
<IconifyIcon
|
||||||
icon="ep:setting"
|
icon="ep:setting"
|
||||||
class="text-18px text-[var(--el-color-primary)]"
|
class="text-[18px] text-[var(--el-color-primary)]"
|
||||||
/>
|
/>
|
||||||
<span class="text-16px font-600 text-[var(--el-text-color-primary)]">
|
<span class="text-[16px] font-600 text-[var(--el-text-color-primary)]">
|
||||||
执行器配置
|
执行器配置
|
||||||
</span>
|
</span>
|
||||||
<ElTag size="small" type="info">
|
<ElTag size="small" type="info">
|
||||||
{{ actions.length }} 个执行器
|
{{ actions.length }} 个执行器
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</div>
|
</div>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<ElButton type="primary" size="small" @click="addAction">
|
<ElButton type="primary" size="small" @click="addAction">
|
||||||
<IconifyIcon icon="ep:plus" />
|
<IconifyIcon icon="ep:plus" />
|
||||||
添加执行器
|
添加执行器
|
||||||
|
|
@ -195,7 +195,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 执行器列表 -->
|
<!-- 执行器列表 -->
|
||||||
<div v-else class="space-y-24px">
|
<div v-else class="space-y-[24px]">
|
||||||
<div
|
<div
|
||||||
v-for="(action, index) in actions"
|
v-for="(action, index) in actions"
|
||||||
:key="`action-${index}`"
|
:key="`action-${index}`"
|
||||||
|
|
@ -205,7 +205,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
<div
|
<div
|
||||||
class="flex items-center justify-between rounded-t-lg border-b border-blue-200 bg-gradient-to-r from-blue-50 to-sky-50 p-4"
|
class="flex items-center justify-between rounded-t-lg border-b border-blue-200 bg-gradient-to-r from-blue-50 to-sky-50 p-4"
|
||||||
>
|
>
|
||||||
<div class="gap-12px flex items-center">
|
<div class="gap-[12px] flex items-center">
|
||||||
<div
|
<div
|
||||||
class="font-600 flex items-center gap-2 text-base text-blue-700"
|
class="font-600 flex items-center gap-2 text-base text-blue-700"
|
||||||
>
|
>
|
||||||
|
|
@ -224,7 +224,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
{{ getActionTypeLabel(action.type as number) }}
|
{{ getActionTypeLabel(action.type as number) }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</div>
|
</div>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="actions.length > 1"
|
v-if="actions.length > 1"
|
||||||
type="danger"
|
type="danger"
|
||||||
|
|
@ -240,12 +240,12 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 执行器内容区域 -->
|
<!-- 执行器内容区域 -->
|
||||||
<div class="p-16px space-y-16px">
|
<div class="p-[16px] space-y-[16px]">
|
||||||
<!-- 执行类型选择 -->
|
<!-- 执行类型选择 -->
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<ElFormItem label="执行类型" required>
|
<ElFormItem label="执行类型" required>
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="action.type"
|
:model-value="action.type"
|
||||||
@change="(value: any) => updateActionType(index, value)"
|
@change="(value: any) => updateActionType(index, value)"
|
||||||
placeholder="请选择执行类型"
|
placeholder="请选择执行类型"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
|
|
@ -279,7 +279,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
<!-- 触发告警提示 - 触发告警时显示 -->
|
<!-- 触发告警提示 - 触发告警时显示 -->
|
||||||
<div
|
<div
|
||||||
v-if="action.type === IotRuleSceneActionTypeEnum.ALERT_TRIGGER"
|
v-if="action.type === IotRuleSceneActionTypeEnum.ALERT_TRIGGER"
|
||||||
class="rounded-6px border border-[var(--el-border-color-light)] bg-[var(--el-fill-color-blank)] p-4"
|
class="rounded-[6px] border border-[var(--el-border-color-light)] bg-[var(--el-fill-color-blank)] p-4"
|
||||||
>
|
>
|
||||||
<div class="mb-2 flex items-center gap-2">
|
<div class="mb-2 flex items-center gap-2">
|
||||||
<IconifyIcon
|
<IconifyIcon
|
||||||
|
|
@ -301,7 +301,7 @@ function onActionTypeChange(action: RuleSceneApi.Action, type: number) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 添加提示 -->
|
<!-- 添加提示 -->
|
||||||
<div v-if="actions.length > 0" class="py-16px text-center">
|
<div v-if="actions.length > 0" class="py-[16px] text-center">
|
||||||
<ElButton type="primary" plain @click="addAction">
|
<ElButton type="primary" plain @click="addAction">
|
||||||
<IconifyIcon icon="ep:plus" />
|
<IconifyIcon icon="ep:plus" />
|
||||||
继续添加执行器
|
继续添加执行器
|
||||||
|
|
|
||||||
|
|
@ -35,28 +35,28 @@ const formData = useVModel(props, 'modelValue', emit); // 表单数据
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElCard
|
<ElCard
|
||||||
class="rounded-8px mb-10px border border-[var(--el-border-color-light)]"
|
class="rounded-[8px] mb-[10px] border border-[var(--el-border-color-light)]"
|
||||||
shadow="never"
|
shadow="never"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<IconifyIcon
|
<IconifyIcon
|
||||||
icon="ep:info-filled"
|
icon="ep:info-filled"
|
||||||
class="text-18px text-[var(--el-color-primary)]"
|
class="text-[18px] text-[var(--el-color-primary)]"
|
||||||
/>
|
/>
|
||||||
<span class="text-16px font-600 text-[var(--el-text-color-primary)]">
|
<span class="text-[16px] font-600 text-[var(--el-text-color-primary)]">
|
||||||
基础信息
|
基础信息
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="formData.status" />
|
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="formData.status" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="p-0">
|
<div class="p-0">
|
||||||
<ElRow :gutter="24" class="mb-24px">
|
<ElRow :gutter="24" class="mb-[24px]">
|
||||||
<ElCol :span="12">
|
<ElCol :span="12">
|
||||||
<ElFormItem label="场景名称" prop="name" required>
|
<ElFormItem label="场景名称" prop="name" required>
|
||||||
<ElInput
|
<ElInput
|
||||||
|
|
|
||||||
|
|
@ -135,17 +135,17 @@ onMounted(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElCard
|
<ElCard
|
||||||
class="rounded-8px mb-10px border border-[var(--el-border-color-light)]"
|
class="rounded-[8px] mb-[10px] border border-[var(--el-border-color-light)]"
|
||||||
shadow="never"
|
shadow="never"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<IconifyIcon
|
<IconifyIcon
|
||||||
icon="ep:lightning"
|
icon="ep:lightning"
|
||||||
class="text-18px text-[var(--el-color-primary)]"
|
class="text-[18px] text-[var(--el-color-primary)]"
|
||||||
/>
|
/>
|
||||||
<span class="text-16px font-600 text-[var(--el-text-color-primary)]">
|
<span class="text-[16px] font-600 text-[var(--el-text-color-primary)]">
|
||||||
触发器配置
|
触发器配置
|
||||||
</span>
|
</span>
|
||||||
<ElTag size="small" type="info">
|
<ElTag size="small" type="info">
|
||||||
|
|
@ -159,24 +159,24 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="p-16px space-y-24px">
|
<div class="p-[16px] space-y-[24px]">
|
||||||
<!-- 触发器列表 -->
|
<!-- 触发器列表 -->
|
||||||
<div v-if="triggers.length > 0" class="space-y-24px">
|
<div v-if="triggers.length > 0" class="space-y-[24px]">
|
||||||
<div
|
<div
|
||||||
v-for="(triggerItem, index) in triggers"
|
v-for="(triggerItem, index) in triggers"
|
||||||
:key="`trigger-${index}`"
|
:key="`trigger-${index}`"
|
||||||
class="rounded-8px border-2 border-green-200 bg-green-50 shadow-sm transition-shadow hover:shadow-md"
|
class="rounded-[8px] border-2 border-green-200 bg-green-50 shadow-sm transition-shadow hover:shadow-md"
|
||||||
>
|
>
|
||||||
<!-- 触发器头部 - 绿色主题 -->
|
<!-- 触发器头部 - 绿色主题 -->
|
||||||
<div
|
<div
|
||||||
class="p-16px rounded-t-6px flex items-center justify-between border-b border-green-200 bg-gradient-to-r from-green-50 to-emerald-50"
|
class="p-[16px] rounded-t-6px flex items-center justify-between border-b border-green-200 bg-gradient-to-r from-green-50 to-emerald-50"
|
||||||
>
|
>
|
||||||
<div class="gap-12px flex items-center">
|
<div class="gap-[12px] flex items-center">
|
||||||
<div
|
<div
|
||||||
class="gap-8px text-16px font-600 flex items-center text-green-700"
|
class="gap-[8px] text-[16px] font-600 flex items-center text-green-700"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="w-24px h-24px text-12px flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
class="w-[24px] h-[24px] text-[12px] flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
||||||
>
|
>
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -190,7 +190,7 @@ onMounted(() => {
|
||||||
{{ getTriggerTypeLabel(triggerItem.type as number) }}
|
{{ getTriggerTypeLabel(triggerItem.type as number) }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</div>
|
</div>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<ElButton
|
<ElButton
|
||||||
v-if="triggers.length > 1"
|
v-if="triggers.length > 1"
|
||||||
type="danger"
|
type="danger"
|
||||||
|
|
@ -206,7 +206,7 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 触发器内容区域 -->
|
<!-- 触发器内容区域 -->
|
||||||
<div class="p-16px space-y-16px">
|
<div class="p-[16px] space-y-[16px]">
|
||||||
<!-- 设备触发配置 -->
|
<!-- 设备触发配置 -->
|
||||||
<DeviceTriggerConfig
|
<DeviceTriggerConfig
|
||||||
v-if="isDeviceTrigger(triggerItem.type as number)"
|
v-if="isDeviceTrigger(triggerItem.type as number)"
|
||||||
|
|
@ -221,17 +221,17 @@ onMounted(() => {
|
||||||
<!-- 定时触发配置 -->
|
<!-- 定时触发配置 -->
|
||||||
<div
|
<div
|
||||||
v-else-if="triggerItem.type === IotRuleSceneTriggerTypeEnum.TIMER"
|
v-else-if="triggerItem.type === IotRuleSceneTriggerTypeEnum.TIMER"
|
||||||
class="gap-16px flex flex-col"
|
class="gap-[16px] flex flex-col"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="gap-8px p-12px px-16px rounded-6px flex items-center border border-[var(--el-border-color-lighter)] bg-[var(--el-fill-color-light)]"
|
class="gap-[8px] p-[12px] px-[16px] rounded-[6px] flex items-center border border-[var(--el-border-color-lighter)] bg-[var(--el-fill-color-light)]"
|
||||||
>
|
>
|
||||||
<IconifyIcon
|
<IconifyIcon
|
||||||
icon="lucide:timer"
|
icon="lucide:timer"
|
||||||
class="text-18px text-[var(--el-color-danger)]"
|
class="text-[18px] text-[var(--el-color-danger)]"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="text-14px font-500 text-[var(--el-text-color-primary)]"
|
class="text-[14px] font-500 text-[var(--el-text-color-primary)]"
|
||||||
>
|
>
|
||||||
定时触发配置
|
定时触发配置
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -239,7 +239,7 @@ onMounted(() => {
|
||||||
|
|
||||||
<!-- CRON 表达式配置 -->
|
<!-- CRON 表达式配置 -->
|
||||||
<div
|
<div
|
||||||
class="p-16px rounded-6px border border-[var(--el-border-color-lighter)] bg-[var(--el-fill-color-blank)]"
|
class="p-[16px] rounded-[6px] border border-[var(--el-border-color-lighter)] bg-[var(--el-fill-color-blank)]"
|
||||||
>
|
>
|
||||||
<ElFormItem label="CRON 表达式" required>
|
<ElFormItem label="CRON 表达式" required>
|
||||||
<CronTab
|
<CronTab
|
||||||
|
|
@ -264,12 +264,12 @@ onMounted(() => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<div v-else class="py-40px text-center">
|
<div v-else class="py-[40px] text-center">
|
||||||
<ElEmpty description="暂无触发器">
|
<ElEmpty description="暂无触发器">
|
||||||
<template #description>
|
<template #description>
|
||||||
<div class="space-y-8px">
|
<div class="space-y-[8px]">
|
||||||
<p class="text-[var(--el-text-color-secondary)]">暂无触发器配置</p>
|
<p class="text-[var(--el-text-color-secondary)]">暂无触发器配置</p>
|
||||||
<p class="text-12px text-[var(--el-text-color-placeholder)]">
|
<p class="text-[12px] text-[var(--el-text-color-placeholder)]">
|
||||||
请使用上方的「添加触发器」按钮来设置触发规则
|
请使用上方的「添加触发器」按钮来设置触发规则
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ async function getDeviceList() {
|
||||||
const data = await getDeviceListByProductId(props.productId);
|
const data = await getDeviceListByProductId(props.productId);
|
||||||
deviceList.value = data || [];
|
deviceList.value = data || [];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取设备列表失败:', error);
|
console.error('获取设备列表失败 :', error);
|
||||||
deviceList.value = [];
|
deviceList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
deviceList.value.unshift(DEVICE_SELECTOR_OPTIONS.ALL_DEVICES);
|
deviceList.value.unshift(DEVICE_SELECTOR_OPTIONS.ALL_DEVICES);
|
||||||
|
|
@ -93,18 +93,18 @@ watch(
|
||||||
:label="device.deviceName"
|
:label="device.deviceName"
|
||||||
:value="device.id"
|
:value="device.id"
|
||||||
>
|
>
|
||||||
<div class="py-4px flex w-full items-center justify-between">
|
<div class="py-[4px] flex w-full items-center justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div
|
<div
|
||||||
class="text-14px font-500 mb-2px text-[var(--el-text-color-primary)]"
|
class="text-[14px] font-500 mb-[2px] text-[var(--el-text-color-primary)]"
|
||||||
>
|
>
|
||||||
{{ device.deviceName }}
|
{{ device.deviceName }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-12px text-[var(--el-text-color-secondary)]">
|
<div class="text-[12px] text-[var(--el-text-color-secondary)]">
|
||||||
{{ device.deviceKey }}
|
{{ device.deviceKey }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="gap-4px flex items-center" v-if="device.id > 0">
|
<div class="gap-[4px] flex items-center" v-if="device.id > 0">
|
||||||
<DictTag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="device.state" />
|
<DictTag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="device.state" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -250,18 +250,18 @@ watch(
|
||||||
:label="operator.label"
|
:label="operator.label"
|
||||||
:value="operator.value"
|
:value="operator.value"
|
||||||
>
|
>
|
||||||
<div class="py-4px flex w-full items-center justify-between">
|
<div class="py-[4px] flex w-full items-center justify-between">
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)]">
|
<div class="text-[14px] font-500 text-[var(--el-text-color-primary)]">
|
||||||
{{ operator.label }}
|
{{ operator.label }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="text-12px px-6px py-2px rounded-4px bg-[var(--el-color-primary-light-9)] font-mono text-[var(--el-color-primary)]"
|
class="text-[12px] px-[6px] py-[2px] rounded-[4px] bg-[var(--el-color-primary-light-9)] font-mono text-[var(--el-color-primary)]"
|
||||||
>
|
>
|
||||||
{{ operator.symbol }}
|
{{ operator.symbol }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-12px text-[var(--el-text-color-secondary)]">
|
<div class="text-[12px] text-[var(--el-text-color-secondary)]">
|
||||||
{{ operator.description }}
|
{{ operator.description }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,14 @@ onMounted(() => {
|
||||||
:label="product.name"
|
:label="product.name"
|
||||||
:value="product.id"
|
:value="product.id"
|
||||||
>
|
>
|
||||||
<div class="py-4px flex w-full items-center justify-between">
|
<div class="py-[4px] flex w-full items-center justify-between">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div
|
<div
|
||||||
class="text-14px font-500 mb-2px text-[var(--el-text-color-primary)]"
|
class="text-[14px] font-500 mb-[2px] text-[var(--el-text-color-primary)]"
|
||||||
>
|
>
|
||||||
{{ product.name }}
|
{{ product.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-12px text-[var(--el-text-color-secondary)]">
|
<div class="text-[12px] text-[var(--el-text-color-secondary)]">
|
||||||
{{ product.productKey }}
|
{{ product.productKey }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -144,11 +144,11 @@ async function fetchThingModelTSL() {
|
||||||
thingModelTSL.value = tslData;
|
thingModelTSL.value = tslData;
|
||||||
parseThingModelData();
|
parseThingModelData();
|
||||||
} else {
|
} else {
|
||||||
console.error('获取物模型TSL失败: 返回数据为空');
|
console.error('获取物模型 TSL 失败 :返回数据为空');
|
||||||
propertyList.value = [];
|
propertyList.value = [];
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取物模型TSL失败:', error);
|
console.error('获取物模型 TSL 失败 :', error);
|
||||||
propertyList.value = [];
|
propertyList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
|
@ -280,14 +280,14 @@ watch(
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="gap-8px flex items-center">
|
<div class="gap-[8px] flex items-center">
|
||||||
<ElSelect
|
<ElSelect
|
||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
placeholder="请选择监控项"
|
placeholder="请选择监控项"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
class="!w-150px"
|
class="!w-[150px]"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
>
|
>
|
||||||
<ElOptionGroup
|
<ElOptionGroup
|
||||||
|
|
@ -301,11 +301,11 @@ watch(
|
||||||
:label="property.name"
|
:label="property.name"
|
||||||
:value="property.identifier"
|
:value="property.identifier"
|
||||||
>
|
>
|
||||||
<div class="py-2px flex w-full items-center justify-between">
|
<div class="py-[2px] flex w-full items-center justify-between">
|
||||||
<span class="text-14px font-500 flex-1 truncate text-[var(--el-text-color-primary)]">
|
<span class="text-[14px] font-500 flex-1 truncate text-[var(--el-text-color-primary)]">
|
||||||
{{ property.name }}
|
{{ property.name }}
|
||||||
</span>
|
</span>
|
||||||
<ElTag size="small" class="ml-8px flex-shrink-0">
|
<ElTag size="small" class="ml-[8px] flex-shrink-0">
|
||||||
{{ property.identifier }}
|
{{ property.identifier }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -338,9 +338,9 @@ watch(
|
||||||
<template #default>
|
<template #default>
|
||||||
<!-- 弹出层内容 -->
|
<!-- 弹出层内容 -->
|
||||||
<div class="property-detail-content">
|
<div class="property-detail-content">
|
||||||
<div class="gap-8px mb-12px flex items-center">
|
<div class="gap-[8px] mb-[12px] flex items-center">
|
||||||
<IconifyIcon icon="ep:info-filled" class="text-16px text-[var(--el-color-info)]" />
|
<IconifyIcon icon="ep:info-filled" class="text-[16px] text-[var(--el-color-info)]" />
|
||||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">
|
<span class="text-[14px] font-500 text-[var(--el-text-color-primary)]">
|
||||||
{{ selectedProperty.name }}
|
{{ selectedProperty.name }}
|
||||||
</span>
|
</span>
|
||||||
<ElTag size="small">
|
<ElTag size="small">
|
||||||
|
|
@ -348,42 +348,42 @@ watch(
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-8px ml-24px">
|
<div class="space-y-[8px] ml-[24px]">
|
||||||
<div class="gap-8px flex items-start">
|
<div class="gap-[8px] flex items-start">
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
标识符:
|
标识符:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{ selectedProperty.identifier }}
|
{{ selectedProperty.identifier }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="selectedProperty.description"
|
v-if="selectedProperty.description"
|
||||||
class="gap-8px flex items-start"
|
class="gap-[8px] flex items-start"
|
||||||
>
|
>
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
描述:
|
描述:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{ selectedProperty.description }}
|
{{ selectedProperty.description }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedProperty.unit" class="gap-8px flex items-start">
|
<div v-if="selectedProperty.unit" class="gap-[8px] flex items-start">
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
单位:
|
单位:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{ selectedProperty.unit }}
|
{{ selectedProperty.unit }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="selectedProperty.range" class="gap-8px flex items-start">
|
<div v-if="selectedProperty.range" class="gap-[8px] flex items-start">
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
取值范围:
|
取值范围:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{ selectedProperty.range }}
|
{{ selectedProperty.range }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -394,12 +394,12 @@ watch(
|
||||||
selectedProperty.type === IoTThingModelTypeEnum.PROPERTY &&
|
selectedProperty.type === IoTThingModelTypeEnum.PROPERTY &&
|
||||||
selectedProperty.accessMode
|
selectedProperty.accessMode
|
||||||
"
|
"
|
||||||
class="gap-8px flex items-start"
|
class="gap-[8px] flex items-start"
|
||||||
>
|
>
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
访问模式:
|
访问模式:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{ getAccessModeLabel(selectedProperty.accessMode) }}
|
{{ getAccessModeLabel(selectedProperty.accessMode) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -409,12 +409,12 @@ watch(
|
||||||
selectedProperty.type === IoTThingModelTypeEnum.EVENT &&
|
selectedProperty.type === IoTThingModelTypeEnum.EVENT &&
|
||||||
selectedProperty.eventType
|
selectedProperty.eventType
|
||||||
"
|
"
|
||||||
class="gap-8px flex items-start"
|
class="gap-[8px] flex items-start"
|
||||||
>
|
>
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
事件类型:
|
事件类型:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{ getEventTypeLabel(selectedProperty.eventType) }}
|
{{ getEventTypeLabel(selectedProperty.eventType) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -424,12 +424,12 @@ watch(
|
||||||
selectedProperty.type === IoTThingModelTypeEnum.SERVICE &&
|
selectedProperty.type === IoTThingModelTypeEnum.SERVICE &&
|
||||||
selectedProperty.callType
|
selectedProperty.callType
|
||||||
"
|
"
|
||||||
class="gap-8px flex items-start"
|
class="gap-[8px] flex items-start"
|
||||||
>
|
>
|
||||||
<span class="text-12px min-w-60px flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
<span class="text-[12px] min-w-[60px] flex-shrink-0 text-[var(--el-text-color-secondary)]">
|
||||||
调用类型:
|
调用类型:
|
||||||
</span>
|
</span>
|
||||||
<span class="text-12px flex-1 text-[var(--el-text-color-primary)]">
|
<span class="text-[12px] flex-1 text-[var(--el-text-color-primary)]">
|
||||||
{{
|
{{
|
||||||
getThingModelServiceCallTypeLabel(selectedProperty.callType)
|
getThingModelServiceCallTypeLabel(selectedProperty.callType)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue