Explorar o código

[Feat 0000]联动规则列表编辑功能

bobo04052021@163.com hai 15 horas
pai
achega
c071c4c3ff

+ 118 - 0
src/views/vent/deviceManager/comment/warningTabel/RuleTableModal.vue

@@ -0,0 +1,118 @@
+<template>
+  <BasicModal @register="register" :title="title" :width="800" :min-height="400" v-bind="$attrs" @ok="onSubmit">
+    <BasicForm @register="registerForm">
+      <template #monitor="{ model, field }">
+        <div class="vent-flex-row-between">
+          <Select ref="selectRef" disabled v-model:value="pointData" :options="option" style="width: calc(100% - 65px)" />
+          <a-button class="vent-margin-b-5" type="primary" @click="selectPoint(model['strtype'])" style="position: absolute; right: 0; top: 1px"
+            >选择</a-button
+          >
+        </div>
+      </template>
+    </BasicForm>
+  </BasicModal>
+  <DevicePointTable @register="registerModal" :data-source="devicePointList" :selection-row-keys="pointData" @reload="setPoint" />
+</template>
+<script lang="ts" setup>
+import { onMounted, ref, defineEmits, unref, nextTick } from 'vue';
+import { BasicForm, useForm } from '/@/components/Form/index';
+import { BasicModal, useModalInner, useModal } from '/@/components/Modal';
+import type { FormSchema } from '/@/components/Form/src/types/form';
+import { Select, message } from 'ant-design-vue';
+import DevicePointTable from '../../../../deviceManager/comment/DevicePointTable.vue';
+import { workFacePointList } from '../../../../deviceManager/comment/warningTabel/warning.api';
+
+const props = defineProps({
+  formSchemas: {
+    type: Array as PropType<FormSchema[]>,
+    default: () => [],
+  },
+  deviceId: { type: String },
+  monitorType: {
+    type: String,
+    default: '2',
+  },
+});
+const emit = defineEmits(['add', 'update', 'register']);
+const option = ref<any[]>([]);
+const devicePointList = ref<any[]>([]);
+const pointData = ref<String[]>([]);
+const title = ref('');
+const isUpdate = ref(false);
+// 注册 form
+const [registerForm, { resetFields, setFieldsValue, validate, getFieldsValue }] = useForm({
+  schemas: props.formSchemas,
+  showActionButtonGroup: false,
+});
+
+// 注册 modal
+const [register, { setModalProps }] = useModalInner(async (data) => {
+  isUpdate.value = unref(data.isUpdate);
+  title.value = unref(data.title);
+  await resetFields();
+  if (data.isUpdate) {
+    await setFieldsValue({ ...data.record });
+    pointData.value = [data.record['monitorId']];
+  } else if (data.record) {
+    // 新增
+    await setFieldsValue({ relId: data.record['relId'] || data.record['id'], monitorId: '' });
+  }
+});
+
+const [registerModal, { openModal }] = useModal();
+
+async function getDevicePointList(strtype) {
+  try {
+    const result = await workFacePointList({ deviceType: strtype, valueTypes: '2,3,9,202,203,209' });
+    devicePointList.value = result;
+  } catch (error) {
+    devicePointList.value = [];
+  }
+}
+
+async function onSubmit() {
+  try {
+    const data = await getFieldsValue();
+    await setFieldsValue({ ...data, monitorId: pointData.value[0] });
+    const values = await validate();
+    setModalProps({ confirmLoading: true });
+    // 提交表单
+    if (!isUpdate.value) {
+      emit('add', 'add', values);
+    } else {
+      emit('update', 'update', values);
+    }
+    // //关闭弹窗
+    // closeModal();
+    // //刷新列表
+    // reload()
+  } finally {
+    setModalProps({ confirmLoading: false });
+  }
+}
+
+async function selectPoint(strtype) {
+  if (strtype) {
+    await getDevicePointList(strtype);
+    openModal();
+  } else {
+    message.info('请先选择设备!');
+  }
+}
+
+function setPoint(value) {
+  const data = value[0];
+  option.value = [
+    {
+      value: data.id,
+      label: data.valuename,
+    },
+  ];
+  nextTick(() => {
+    pointData.value = [data.id];
+  });
+}
+
+onMounted(async () => {});
+</script>
+<style scoped lang="less"></style>

+ 80 - 13
src/views/vent/home/configurable/components/preset/linkRuleEdit.vue

@@ -9,14 +9,15 @@
           <div class="edit-right">
             <div class="right-title">条件逻辑说明</div>
             <div class="right-content">
-              <template v-for="(item, index) in formData" :key="index">
-                <div class="right-item">设备名称: {{ item.alarmName }}</div>
-                <div class="right-item">监测点位: {{ item.monitorName }}</div>
-                <div class="right-item">IF {{ item.fmin ?? '' }}~{{ item.fmax ?? '' }}</div>
-                <div class="right-item">AND 持续时间:{{ item.cxTime ?? '' }}s</div>
-              </template>
-              <div class="right-item">AND 时间在生效范围内</div>
-              <div class="right-item">THEN 执行联动动作</div>
+              <div v-for="(item, index) in formData" :key="index" class="right-item-row">
+                <span class="right-item index-label">{{ index + 1 }}</span>
+                <span class="right-item">设备名称: {{ item.alarmName }}</span>
+                <span class="right-item">监测地点: {{ item.devicePos }}</span>
+                <span class="right-item">IF {{ getConditionText(item) }}</span>
+                <span class="right-item">AND 持续时间:{{ item.cxTime ?? '' }}s</span>
+                <span class="right-item">AND 时间在生效范围内</span>
+                <span class="right-item">THEN 执行联动动作</span>
+              </div>
             </div>
           </div>
         </div>
@@ -140,6 +141,44 @@ const getWarningList = async (val) => {
   const res = await getWarningDeviceList(params);
   formData.value = res.records;
 };
+// 获取单位
+const getSensorUnit = (item: any) => {
+  const type = item.deviceType;
+  if (type === 'modelsensor_co' || type === 'modelsensor_hcl') return 'ppm';
+  if (type === 'modelsensor_temperature') return '℃';
+  return '%';
+};
+// 拼接IF条件文本
+const getConditionText = (item: any) => {
+  const { fmin, fmax, deviceType } = item;
+  const unit = getSensorUnit(item);
+  const minVal = fmin ?? '';
+  const maxVal = fmax ?? '';
+
+  // 同时存在最小值、最大值:区间 fmin~fmax
+  if (minVal !== '' && maxVal !== '') {
+    return `${minVal}~${maxVal} ${unit}`;
+  }
+
+  // 只有最大值,无最小值
+  if (maxVal !== '' && minVal === '') {
+    if (deviceType === 'modelsensor_co') {
+      // CO:大于fmax
+      return `> ${maxVal} ${unit}`;
+    } else if (deviceType === 'modelsensor_hcl' || deviceType === 'modelsensor_temperature') {
+      // HCl / 温度:大于等于fmax
+      return `≥ ${maxVal} ${unit}`;
+    } else {
+      return `≥ ${maxVal} ${unit}`;
+    }
+  }
+  // 只有最小值(无最大值),直接显示最小值+单位
+  if (minVal !== '' && maxVal === '') {
+    return `${minVal} ${unit}`;
+  }
+  // 两者都为空兜底
+  return '';
+};
 onMounted(() => {
   fetchStepStatus();
   if (currentSelectedRow.value) {
@@ -235,13 +274,41 @@ const updateFormData = (row: any) => {
   }
 
   .right-content {
-    flex: 1;
     display: flex;
-    flex-direction: row;
-    margin-top: 5px;
-    margin-left: 10px;
+    flex-direction: column;
+    gap: 6px;
+    max-height: 300px;
+    overflow-y: auto;
+  }
+
+  .right-item-row {
+    display: flex;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 8px;
+    padding: 6px 20px;
+    background: rgba(255, 255, 255, 0.03);
+    border-radius: 4px;
+    border: 1px solid rgba(255, 255, 255, 0.06);
   }
 
+  .right-item {
+    font-size: 14px;
+    color: #e0f2fe;
+    white-space: nowrap;
+  }
+
+  /* 方案二:序号样式 */
+  .index-label {
+    color: #7dd3fc;
+    font-weight: 600;
+    min-width: 30px;
+  }
+
+  /* 方案三:内联样式 */
+  .right-item.inline {
+    display: inline-block;
+  }
   .right-item {
     color: #29a1d4;
     font-size: 12px;
@@ -249,7 +316,7 @@ const updateFormData = (row: any) => {
     font-weight: bold;
     padding: 0 5px;
   }
-  .right-item:nth-child(3) {
+  .right-item:nth-child(4) {
     color: #fc002a;
   }
   .right-item:first-child {

+ 56 - 5
src/views/vent/home/configurable/components/preset/ruleTable.vue

@@ -62,7 +62,7 @@
             >
               <td v-for="col in config.type === 'C' ? config.columns : filterDeviceColumns" :key="col.dataIndex || col.prop" class="table-cell">
                 <template v-if="config.type === 'C' && col.prop === 'operation'">
-                  <span class="text-look" @click="handleEditClick(row)">确认</span>
+                  <span class="text-look" @click="handleEditClick(row)">编辑</span>
                 </template>
                 <template v-else>
                   <span class="text-ellipsis" :title="getCellText(row, col)">
@@ -83,6 +83,7 @@
       :select-sys-alarm-id="currentSelectInfo.alarmId"
       :select-sys-id="currentSelectInfo.sysId"
     />
+    <RuleTableModal @register="register" @update="onSubmit" :destroy-on-close="true" :form-schemas="workFaceWarningSchemas" />
   </div>
 </template>
 
@@ -96,14 +97,15 @@ import { getAlarmLogList } from '../../configurable.api';
 import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
 import { func } from 'vue-types';
 import { useLinkRuleStore } from '/@/store/modules/linkRule';
-
+import RuleTableModal from '../../../../deviceManager/comment/warningTabel/RuleTableModal.vue';
+import { FormSchema } from '/@/components/Table';
+import { warningLogEdit, warningLogList } from '../../../../deviceManager/comment/warningTabel/warning.api';
+import { workFaceWarningFormSchemas } from '../../../../deviceManager/comment/warningTabel/warning.data';
 const FIXED_STRTYPE = 'sys_openair_fire';
 const deviceType = ref('managesys');
 const isUpdate = ref(false);
-
 const instanceId = ref(`${Date.now()}_${Math.floor(Math.random() * 10000)}`);
 const [registerModal, { openModal, closeModal }] = useModal(instanceId.value);
-
 const linkRuleStore = useLinkRuleStore();
 const emit = defineEmits(['row-change']);
 const currentSelectInfo = ref({
@@ -149,7 +151,56 @@ const props = defineProps<{
   selectedRow?: any | null;
 }>();
 
-const handleEditClick = (row: any) => {};
+const handleEditClick = (row: any) => {
+  openModalRule(true, {
+    isUpdate: true,
+    record: row,
+  });
+};
+
+const workFaceWarningSchemas: FormSchema[] = [
+  ...workFaceWarningFormSchemas,
+  {
+    label: '关联条目',
+    field: 'relatedEntries',
+    component: 'ApiSelect',
+    componentProps: {
+      labelField: 'alarmName',
+      valueField: 'id',
+      resultField: 'records',
+      api: warningLogList.bind(null, { sysId: currentSelectInfo.value.sysId }),
+    },
+  },
+  {
+    label: '预警后自动控制',
+    field: 'isAutoControl',
+    component: 'RadioGroup',
+    componentProps: {
+      //options里面由一个一个的radio组成,支持disabled
+      options: [
+        { label: '是', value: true },
+        { label: '否', value: false },
+      ],
+    },
+  },
+  {
+    label: '解除后自动复位',
+    field: 'isAutoReset',
+    component: 'RadioGroup',
+    componentProps: {
+      //options里面由一个一个的radio组成,支持disabled
+      options: [
+        { label: '是', value: true },
+        { label: '否', value: false },
+      ],
+    },
+  },
+];
+const [register, { openModal: openModalRule, closeModal: closeModalRule }] = useModal();
+async function onSubmit(flag, values) {
+  await warningLogEdit(values);
+  closeModalRule();
+}
 // C类型数据源
 const tableList = ref<any[]>([]);
 // D类型数据源