You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
besure_web/src/views/iot/devicemodel/index.vue

885 lines
32 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" min-label-width="68px">
<el-form-item :label="t('DataCollection.DeviceModel.code')" prop="code">
<el-input
v-model="queryParams.code"
:placeholder="t('DataCollection.DeviceModel.placeholderCode')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.name')" prop="name">
<el-input
v-model="queryParams.name"
:placeholder="t('DataCollection.DeviceModel.placeholderName')"
clearable
@keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.protocol')" prop="protocol">
<el-select
v-model="queryParams.protocol"
:placeholder="t('DataCollection.DeviceModel.placeholderProtocol')"
clearable
class="!w-240px">
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_PROTOCOL)" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
<!-- <el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
placeholder="请输入备注"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> -->
<!-- <el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</el-form-item> -->
<el-form-item>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceModel.search') }}
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceModel.reset') }}
</el-button>
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['iot:device-model:create']">
<Icon icon="ep:plus" class="mr-5px" /> {{ t('DataCollection.DeviceModel.create') }}
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['iot:device-model:delete']">
<Icon icon="ep:delete" class="mr-5px" /> {{ t('DataCollection.DeviceModel.batchDelete') }}
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['iot:device-model:export']">
<Icon icon="ep:download" class="mr-5px" /> {{ t('DataCollection.DeviceModel.export') }}
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
highlight-current-row row-key="id" @selection-change="handleSelectionChange" @row-click="handleShowAttribute">
<el-table-column type="selection" width="55" reserve-selection />
<el-table-column :label="t('DataCollection.DeviceModel.code')" align="center" prop="code" sortable/>
<el-table-column :label="t('DataCollection.DeviceModel.name')" align="center" prop="name" sortable/>
<el-table-column align="center" :label="t('DataCollection.DeviceModel.protocol')" prop="protocol" min-width="150">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_PROTOCOL" :value="scope.row.protocol" />
</template>
</el-table-column>
<el-table-column :label="t('DataCollection.DeviceModel.remark')" align="center" prop="remark" />
<!-- <el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" sortable /> -->
<el-table-column :label="t('DataCollection.DeviceModel.operate')" align="center" min-width="120px">
<template #default="scope">
<el-button link type="primary" @click.stop="handleShowAttribute(scope.row)">{{ t('DataCollection.DeviceModel.attributeModuleName') }}</el-button>
<el-button link type="primary" @click="handleCopy(scope.row.id)" v-hasPermi="['iot:device-model:create']">
{{ t('action.copy') }}
</el-button>
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['iot:device-model:update']">
{{ t('action.edit') }}
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['iot:device-model:delete']">
{{ t('action.del') }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<ContentWrap>
<template v-if="attributeModelId">
<div class="mb-10px text-sm text-gray-500">
{{ t('DataCollection.DeviceModel.moduleName') }}<span class="font-medium text-gray-700">{{ attributeModelName || '-' }}</span>
</div>
<el-tabs model-value="modelAttribute">
<el-tab-pane :label="t('DataCollection.DeviceModel.attributeModuleName')" name="modelAttribute">
<ModelAttributeList :id="attributeModelId" />
</el-tab-pane>
<el-tab-pane :label="t('DataCollection.DeviceModel.ruleTabLabel')" name="modelRule">
<el-form class="-mb-15px" :model="ruleQueryParams" ref="ruleQueryFormRef" :inline="true" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleIdentifier')" prop="identifier">
<el-input
v-model="ruleQueryParams.identifier"
:placeholder="t('DataCollection.DeviceModel.ruleSearchIdentifierPlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleFieldName')" prop="fieldName">
<el-input
v-model="ruleQueryParams.fieldName"
:placeholder="t('DataCollection.DeviceModel.ruleSearchFieldNamePlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDefaultValue')" prop="defaultValue">
<el-input
v-model="ruleQueryParams.defaultValue"
:placeholder="t('DataCollection.DeviceModel.ruleSearchDefaultValuePlaceholder')"
clearable
@keyup.enter="handleRuleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleRuleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('DataCollection.DeviceModel.ruleSearch') }}
</el-button>
<el-button @click="resetRuleQuery">
<Icon icon="ep:refresh" class="mr-5px" /> {{ t('DataCollection.DeviceModel.ruleReset') }}
</el-button>
</el-form-item>
</el-form>
<div class="mb-10px text-right">
<el-button type="primary" @click="openCreateRuleForm">
{{ t('DataCollection.DeviceModel.ruleCreateButton') }}
</el-button>
</div>
<el-table
v-loading="ruleLoading"
:data="ruleList"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
>
<el-table-column :label="t('DataCollection.DeviceModel.ruleIdentifier')" align="center" prop="identifier" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleFieldName')" align="center" prop="fieldName" sortable />
<el-table-column :label="t('DataCollection.DeviceModel.ruleFieldRule')" align="center" prop="fieldRule" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleDefaultValue')" align="center" prop="defaultValue" />
<el-table-column :label="t('DataCollection.DeviceModel.ruleCreateTime')" align="center" prop="createTime" :formatter="dateFormatter" width="180px" sortable />
<el-table-column :label="t('DataCollection.DeviceModel.ruleOperate')" align="center" width="160px">
<template #default="scope">
<el-button link type="primary" @click="openRuleForm(scope.row)">
{{ t('DataCollection.DeviceModel.ruleEditRuleButton') }}
</el-button>
<el-button
v-if="(scope.row.identifier || '').toString().toUpperCase() === 'ALARM'"
link
type="danger"
@click="handleRuleDelete(scope.row.id)"
>
{{ t('DataCollection.DeviceModel.ruleDeleteRuleButton') }}
</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
:total="ruleTotal"
v-model:page="ruleQueryParams.pageNo"
v-model:limit="ruleQueryParams.pageSize"
@pagination="getRuleList"
/>
<el-dialog v-model="ruleDialogVisible" :title="t('DataCollection.DeviceModel.ruleDialogTitle')" width="880px" draggable>
<el-form :model="ruleForm" ref="ruleFormRef" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogIdentifier')">
<el-input v-model="ruleForm.identifier" disabled />
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldName')">
<el-input v-model="ruleForm.fieldName" disabled />
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogDefaultValue')">
<el-input v-model="ruleForm.defaultValue" disabled />
</el-form-item>
<el-form-item
v-if="(ruleForm.identifier || '').toString().toUpperCase() === 'ALARM'"
:label="t('DataCollection.DeviceModel.ruleDialogAlarmLevel')"
>
<el-select
v-model="ruleForm.alarmLevel"
:placeholder="t('DataCollection.DeviceModel.ruleDialogAlarmLevelPlaceholder')"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_ALARM_REGISTRATION)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<div class="flex flex-col w-full">
<div class="border border-gray-200 dark:border-gray-600 rounded-md py-12px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldRule')">
<el-select
v-model="ruleForm.fieldRule"
:placeholder="t('DataCollection.DeviceModel.ruleDialogFieldRulePlaceholder')"
class="!w-240px"
:disabled="!currentRuleOptions.length"
>
<el-option
v-for="item in currentRuleOptions"
:key="item.value"
:label="item.label"
:value="item.value"
:disabled="isRuleDisabled(item.value, ruleForm.fieldRule)"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogRule')">
<div class="flex items-center gap-8px">
<el-select
v-model="ruleForm.ruleAttributeId"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleAttributePlaceholder')"
filterable
class="!w-240px"
>
<el-option
v-for="item in ruleAttributeOptions"
:key="item.id"
:label="item.attributeName || item.attributeCode"
:value="item.id"
/>
</el-select>
<el-select
v-model="ruleForm.ruleOperator"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleOperatorPlaceholder')"
class="!w-160px"
>
<el-option
v-for="opt in ruleOperatorOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
<el-input
v-if="ruleForm.ruleOperator !== 'TRUE' && ruleForm.ruleOperator !== 'FALSE'"
v-model="ruleForm.ruleValue"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleValuePlaceholder')"
class="!w-200px"
/>
</div>
</el-form-item>
</div>
<div
v-for="(item, index) in extraPointRules"
:key="index"
class="border border-gray-200 dark:border-gray-600 rounded-md px-16px py-12px"
>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldRule')">
<el-select
v-model="item.rule"
:placeholder="t('DataCollection.DeviceModel.ruleDialogFieldRulePlaceholder')"
class="!w-240px"
>
<el-option
v-for="opt in currentRuleOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
:disabled="isRuleDisabled(opt.value, item.rule)"
/>
</el-select>
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogRule')">
<div class="flex items-center gap-8px">
<el-select
v-model="item.id"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleAttributePlaceholder')"
class="!w-240px"
>
<el-option
v-for="attr in ruleAttributeOptions"
:key="attr.id"
:label="attr.attributeName || attr.attributeCode"
:value="attr.id"
/>
</el-select>
<el-select
v-model="item.operator"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleOperatorPlaceholder')"
class="!w-160px"
>
<el-option
v-for="opt in ruleOperatorOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
<el-input
v-if="item.operator !== 'TRUE' && item.operator !== 'FALSE'"
v-model="item.operatorRule"
:placeholder="t('DataCollection.DeviceModel.ruleDialogRuleValuePlaceholder')"
class="!w-200px"
/>
<el-button type="danger" link @click="handleRemovePointRule(index)">
{{ t('DataCollection.DeviceModel.ruleDeleteRuleButton') }}
</el-button>
</div>
</el-form-item>
</div>
<el-form-item v-if="isRunningIdentifier" label=" ">
<el-button type="primary" link @click="handleAddPointRule">
+ {{ t('DataCollection.DeviceModel.ruleCreateButton') }}
</el-button>
</el-form-item>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="ruleDialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
<el-button type="primary" :loading="ruleFormLoading" @click="handleRuleSubmit">{{ t('DataCollection.DeviceModel.dialogOk') }}</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="createRuleDialogVisible" :title="t('DataCollection.DeviceModel.ruleCreateButton')" width="520px" draggable>
<el-form :model="createRuleForm" ref="createRuleFormRef" label-width="120px">
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogIdentifier')">
<el-input v-model="createRuleForm.identifier" disabled />
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogFieldName')">
<el-input
v-model="createRuleForm.fieldName"
:placeholder="t('DataCollection.DeviceModel.ruleSearchFieldNamePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('DataCollection.DeviceModel.ruleDialogDefaultValue')">
<el-input v-model="createRuleForm.defaultValue" disabled />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="createRuleDialogVisible = false">{{ t('DataCollection.DeviceModel.dialogCancel') }}</el-button>
<el-button type="primary" :loading="createRuleFormLoading" @click="handleCreateRuleSubmit">
{{ t('DataCollection.DeviceModel.dialogOk') }}
</el-button>
</span>
</template>
</el-dialog>
</el-tab-pane>
</el-tabs>
</template>
<el-empty
v-else
:description="t('DataCollection.DeviceModel.moduleName') + t('-') + t('DataCollection.DeviceModel.attributeModuleName')"
/>
</ContentWrap>
<!-- 表单弹窗:添加/修改 -->
<DeviceModelForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import request from '@/config/axios'
import { DeviceModelApi, DeviceModelVO } from '@/api/iot/devicemodel'
import { DeviceModelAttributeApi, DeviceModelAttributeVO } from '@/api/iot/devicemodelattribute'
import DeviceModelForm from './DeviceModelForm.vue'
import ModelAttributeList from './components/ModelAttributeList.vue'
/** */
defineOptions({ name: 'DeviceModel' })
const message = useMessage() //
const { t } = useI18n() //
const tableRef = ref()
const loading = ref(true) //
const list = ref<DeviceModelVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
code: undefined,
name: undefined,
protocol: undefined,
remark: undefined,
createTime: [],
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await DeviceModelApi.getDeviceModelPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const buildIdsParam = (ids: number | number[]) => {
return Array.isArray(ids) ? ids.join(',') : String(ids)
}
const handleDelete = async (ids: number | number[]) => {
try {
// 删除的二次确认
await message.delConfirm()
// 发起删除
await DeviceModelApi.deleteDeviceModel(buildIdsParam(ids))
message.success(t('common.delSuccess'))
selectedIds.value = []
tableRef.value?.clearSelection?.()
// 刷新列表
await getList()
} catch { }
}
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
return
}
await handleDelete(selectedIds.value)
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
// 导出的二次确认
await message.exportConfirm()
// 发起导出
exportLoading.value = true
const params: any = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await DeviceModelApi.exportDeviceModel(params)
download.excel(data, '采集设备模型.xls')
} catch {
} finally {
exportLoading.value = false
}
}
const attributeModelId = ref<number | undefined>(undefined)
const attributeModelName = ref('')
const modelAttributeTabLabel = computed(() => {
return '采集点'
})
const modelRuleTabLabel = computed(() => {
return '点位规则'
})
interface DeviceModelRuleVO {
id: number
identifier: string
fieldName: string
fieldRule: string
defaultValue: string
modelId: number
createTime?: string | number | Date
ruleAttributeId?: number
ruleOperator?: string
ruleValue?: string | number
alarmLevel?: string
}
const ruleLoading = ref(false)
const ruleList = ref<DeviceModelRuleVO[]>([])
const ruleTotal = ref(0)
const ruleQueryParams = reactive({
pageNo: 1,
pageSize: 10,
identifier: undefined as string | undefined,
fieldName: undefined as string | undefined,
fieldRule: undefined as string | undefined,
defaultValue: undefined as string | undefined,
alarmLevel: undefined as string | undefined,
modelId: undefined as number | undefined,
})
const ruleQueryFormRef = ref()
const ruleAttributeOptions = ref<DeviceModelAttributeVO[]>([])
const getRuleList = async () => {
if (!attributeModelId.value) return
ruleLoading.value = true
try {
const params = {
...ruleQueryParams,
modelId: attributeModelId.value,
}
const data = await request.get({ url: '/iot/device-model-rules/page', params })
const listData = Array.isArray((data as any)?.list) ? (data as any).list : (Array.isArray(data) ? data : [])
const totalData = (data as any)?.total ?? listData.length
ruleList.value = listData as DeviceModelRuleVO[]
ruleTotal.value = totalData
} finally {
ruleLoading.value = false
}
}
const handleRuleQuery = () => {
if (!attributeModelId.value) return
ruleQueryParams.pageNo = 1
getRuleList()
}
const resetRuleQuery = () => {
if (!attributeModelId.value) return
ruleQueryFormRef.value?.resetFields?.()
handleRuleQuery()
}
const loadRuleAttributeOptions = async (modelId: number) => {
try {
const res = await DeviceModelAttributeApi.getDeviceModelAttributeList(modelId)
const data = Array.isArray(res) ? res : (res as any)?.list ?? []
ruleAttributeOptions.value = data as DeviceModelAttributeVO[]
} catch {
ruleAttributeOptions.value = []
}
}
watch(
() => attributeModelId.value,
async (val) => {
ruleQueryParams.modelId = val ?? undefined
if (!val) {
ruleList.value = []
ruleTotal.value = 0
ruleAttributeOptions.value = []
return
}
ruleQueryParams.pageNo = 1
await Promise.all([getRuleList(), loadRuleAttributeOptions(val)])
}
)
const ruleDialogVisible = ref(false)
const ruleFormLoading = ref(false)
const ruleFormRef = ref()
const ruleForm = reactive<Partial<DeviceModelRuleVO>>({
id: undefined,
identifier: '',
fieldName: '',
fieldRule: '',
defaultValue: '',
modelId: undefined,
ruleAttributeId: undefined,
ruleOperator: undefined,
ruleValue: undefined,
alarmLevel: '',
})
const createRuleDialogVisible = ref(false)
const createRuleFormLoading = ref(false)
const createRuleFormRef = ref()
const createRuleForm = reactive({
identifier: 'ALARM',
fieldName: '',
defaultValue: '报警',
})
const extraPointRules = ref<
Array<{
id?: number
rule?: string
operator?: string
operatorRule?: string | number
}>
>([])
const runningRuleOptions = [
{ value: '1', label: '运行' },
{ value: '2', label: '待机中(不运行、没故障)' },
{ value: '3', label: '故障中(故障且待机)' },
{ value: '4', label: '报警中(故障且运行)' },
]
const alarmRuleOptions = [
{ value: '5', label: '报警' },
]
const currentRuleOptions = computed(() => {
const id = (ruleForm.identifier || '').toString().toUpperCase()
if (id === 'RUNNING') return runningRuleOptions
if (id === 'ALARM') return alarmRuleOptions
return []
})
const isRuleDisabled = (value: string, selfRule?: string | number) => {
if (!value) return false
const v = String(value)
const self = selfRule != null ? String(selfRule) : undefined
if (self === v) return false
if (ruleForm.fieldRule && String(ruleForm.fieldRule) === v && self !== v) return true
if (
extraPointRules.value.some(
(item) => item.rule != null && String(item.rule) === v && String(item.rule) !== self
)
) {
return true
}
return false
}
const ruleOperatorOptions = computed(() => getStrDictOptions('czsb_rules_conditions'))
const isRunningIdentifier = computed(() => {
return (ruleForm.identifier || '').toString().toUpperCase() === 'RUNNING'
})
const openCreateRuleForm = () => {
if (!attributeModelId.value) {
message.error('请先选择模型')
return
}
createRuleForm.identifier = 'ALARM'
createRuleForm.fieldName = '报警'
createRuleForm.defaultValue = '报警'
createRuleDialogVisible.value = true
}
const openRuleForm = async (row: DeviceModelRuleVO & { pointRulesVOList?: any[] }) => {
const modelId = row.modelId || attributeModelId.value
if (!modelId) {
message.error('模型信息缺失,无法加载点位规则')
return
}
await loadRuleAttributeOptions(modelId)
ruleForm.id = row.id
ruleForm.identifier = row.identifier
ruleForm.fieldName = row.fieldName
ruleForm.defaultValue = row.defaultValue
ruleForm.modelId = row.modelId
ruleForm.alarmLevel = row.alarmLevel
extraPointRules.value = []
const list = Array.isArray(row.pointRulesVOList) ? row.pointRulesVOList : []
if (list.length) {
const first = list[0] as any
const firstRule = first.rule ?? row.fieldRule
const firstAttrId = (() => {
if (first && first.code != null) {
const target = ruleAttributeOptions.value.find(
(item) => item.attributeCode === first.code
)
return target?.id
}
if (first && first.id != null) return first.id
return undefined
})()
ruleForm.fieldRule = firstRule as any
ruleForm.ruleAttributeId = firstAttrId as any
ruleForm.ruleOperator = first.operator as any
ruleForm.ruleValue = first.operatorRule as any
extraPointRules.value = list.slice(1).map((item: any) => ({
id: (() => {
if (item && item.code != null) {
const target = ruleAttributeOptions.value.find(
(opt) => opt.attributeCode === item.code
)
return target?.id
}
if (item && item.id != null) return item.id
return undefined
})(),
rule: item.rule,
operator: item.operator,
operatorRule: item.operatorRule,
}))
} else {
ruleForm.fieldRule = row.fieldRule
ruleForm.ruleAttributeId = row.ruleAttributeId
ruleForm.ruleOperator = row.ruleOperator
ruleForm.ruleValue = row.ruleValue as any
}
const options = currentRuleOptions.value
if (options.length && !options.some((item) => item.value === ruleForm.fieldRule)) {
ruleForm.fieldRule = options[0].value
}
ruleDialogVisible.value = true
}
const handleRuleSubmit = async () => {
if (!ruleForm.id) return
try {
ruleFormLoading.value = true
const pointRulesVOList: any[] = []
if (ruleForm.ruleAttributeId && ruleForm.ruleOperator) {
const attr = ruleAttributeOptions.value.find(
(item) => item.id === ruleForm.ruleAttributeId
)
if (attr && attr.attributeCode) {
pointRulesVOList.push({
code: attr.attributeCode,
rule: ruleForm.fieldRule,
operator: ruleForm.ruleOperator,
operatorRule: ruleForm.ruleValue,
})
}
}
extraPointRules.value.forEach((item) => {
if (!item.id || !item.operator) return
const attr = ruleAttributeOptions.value.find((opt) => opt.id === item.id)
if (!attr || !attr.attributeCode) return
pointRulesVOList.push({
code: attr.attributeCode,
rule: item.rule ?? ruleForm.fieldRule,
operator: item.operator,
operatorRule: item.operatorRule,
})
})
const payload = {
id: ruleForm.id,
identifier: ruleForm.identifier,
fieldName: ruleForm.fieldName,
defaultValue: ruleForm.defaultValue,
modelId: ruleForm.modelId,
alarmLevel: ruleForm.alarmLevel,
pointRulesVOList,
}
await request.put({ url: '/iot/device-model-rules/update', data: payload })
message.success('保存成功')
ruleDialogVisible.value = false
await getRuleList()
} finally {
ruleFormLoading.value = false
}
}
const handleRuleDelete = async (id: number) => {
if (!id) return
try {
await message.delConfirm()
await request.delete({ url: '/iot/device-model-rules/delete?id=' + id })
message.success(t('common.delSuccess'))
await getRuleList()
} catch { }
}
const handleAddPointRule = () => {
if (!isRunningIdentifier.value) return
const allOptions = currentRuleOptions.value || []
const used = new Set<string>()
if (ruleForm.fieldRule) used.add(String(ruleForm.fieldRule))
extraPointRules.value.forEach((item) => {
if (item.rule != null) used.add(String(item.rule))
})
const next = allOptions.find((opt) => !used.has(String(opt.value)))
if (!next) {
message.warning('已没有可用的点位规则可选')
return
}
extraPointRules.value.push({
rule: next.value as any,
id: undefined,
operator: undefined,
operatorRule: undefined,
})
}
const handleCreateRuleSubmit = async () => {
if (!attributeModelId.value) return
if (!createRuleForm.fieldName) {
message.warning('请输入名称')
return
}
try {
createRuleFormLoading.value = true
const payload = {
identifier: createRuleForm.identifier,
fieldName: createRuleForm.fieldName,
defaultValue: createRuleForm.defaultValue,
modelId: attributeModelId.value,
}
await request.post({ url: '/iot/device-model-rules/create', data: payload })
message.success('新增成功')
createRuleDialogVisible.value = false
await getRuleList()
} finally {
createRuleFormLoading.value = false
}
}
const handleRemovePointRule = (index: number) => {
if (index < 0 || index >= extraPointRules.value.length) return
extraPointRules.value.splice(index, 1)
}
const handleShowAttribute = (row: any) => {
attributeModelId.value = row?.id
attributeModelName.value = row?.name ?? ''
}
const handleCopy = async (id: number) => {
try {
// 二次确认
await message.confirm('是否复制模型?')
await DeviceModelApi.copyDeviceModel(id)
message.success('复制成功')
await getList()
} catch { }
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>