Browse Source

feat: 新增表计类型及业务模块配置

yusheng 4 months ago
parent
commit
3ed830a426

+ 34 - 0
src/api/meterModel/index.js

@@ -0,0 +1,34 @@
+import request from '@/utils/request';
+
+// 列表
+export async function getPage(params) {
+  const res = await request.get(`/main/meterModel/page`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+// 修改
+export async function saveOrEdit(data) {
+  const res = await request.post(`/main/meterModel/saveOrEdit`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+// 详情
+export async function getById(id) {
+  const res = await request.get(`/main/meterModel/getById/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+// 删除
+export async function del(data) {
+  const res = await request.delete(`/main/meterModel/del`, { data });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 4 - 4
src/components/upload/imgUpload.vue

@@ -76,10 +76,10 @@
           this.$message.error('只能选择图片');
           return;
         }
-        if (file.size / 1024 / 1024 > 2) {
-          this.$message.error('大小不能超过 2MB');
-          return;
-        }
+        // if (file.size / 1024 / 1024 > 2) {
+        //   this.$message.error('大小不能超过 2MB');
+        //   return;
+        // }
         this.$emit('input', [...this.value, item]);
         this.onUpload(item);
       },

+ 10 - 1
src/enum/dict.js

@@ -86,7 +86,8 @@ export default {
   放行类型: 'checklist_type',
   实验报工类型: 'experiment_rules_report_work_type',
   实验规则类型: 'experiment_sheet',
-  实验模板样式: 'experiment_template_style'
+  实验模板样式: 'experiment_template_style',
+  表计类型: 'meter_type'
 };
 
 export const numberList = [
@@ -314,6 +315,14 @@ export const businessModule = [
     label: '项目管理',
     value: 'pro_'
   },
+  {
+    label: '能源管理',
+    value: 'ems_'
+  },
+  {
+    label: '生产管控',
+    value: 'pcs_'
+  },
   {
     label: '数据看板',
     value: 'datascreen_'

+ 600 - 0
src/views/meterModel/components/measurePointForm.vue

@@ -0,0 +1,600 @@
+<template>
+  <ele-modal
+    :visible="visible"
+    :title="title"
+    width="1000px"
+    :destroy-on-close="true"
+    @update:visible="updateVisible"
+    append-to-body
+  >
+    <el-form
+      ref="formRef"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+      size="small"
+    >
+      <!-- 第一行:测点编码 + 测点代码 -->
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="测点编码" prop="code">
+            <el-input v-model="form.code" placeholder="系统生成" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="测点代码" prop="measuringPointCode">
+            <el-input
+              v-model="form.measuringPointCode"
+              :disabled="title == '详情'"
+              placeholder="请输入"
+              clearable
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <!-- 第二行:测点名称 -->
+      <el-row>
+        <el-col :span="24">
+          <el-form-item label="测点名称" prop="name" required>
+            <el-input
+              v-model="form.name"
+              placeholder="请输入"
+              clearable
+              :disabled="title == '详情'"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <!-- 第三行:测点类型 + 排序号 -->
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="测点类型" prop="itemType" required>
+            <el-radio-group v-model="form.itemType" :disabled="title == '详情'">
+              <el-radio :label="0">数值</el-radio>
+              <el-radio :label="1">状态</el-radio>
+              <el-radio :label="2">颜色</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="排序号" prop="indexNo" required>
+            <el-input-number
+              v-model="form.indexNo"
+              :min="1"
+              :max="999"
+              controls-position="right"
+              :disabled="title == '详情'"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <!-- 状态设置区域 - 当测点类型为状态或颜色时显示 -->
+      <template v-if="form.itemType == '1'">
+        <div class="section-title">状态设置</div>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="正常" prop="statusNormalText">
+              <el-select
+                v-model="form.statusNormalText"
+                placeholder="请选择"
+                clearable
+                :disabled="title == '详情'"
+                style="width: 100%"
+              >
+                <el-option label="开" value="1"></el-option>
+                <el-option label="关" value="2"></el-option>
+                <el-option label="闭" value="3"></el-option>
+                <el-option label="合" value="3"></el-option>
+                <el-option label="断" value="3"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="异常" prop="statusAbnormalText">
+              <el-select
+                v-model="form.statusAbnormalText"
+                placeholder="请选择"
+                clearable
+                :disabled="title == '详情'"
+                style="width: 100%"
+              >
+                <el-option label="开" value="1"></el-option>
+                <el-option label="关" value="2"></el-option>
+                <el-option label="闭" value="3"></el-option>
+                <el-option label="合" value="3"></el-option>
+                <el-option label="断" value="3"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="是否告警" prop="statusAlarmFlag">
+              <el-radio-group
+                v-model="form.statusAlarmFlag"
+                :disabled="title == '详情'"
+              >
+                <el-radio :label="1">是</el-radio>
+                <el-radio :label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="告警等级" prop="statusAlarmLevel">
+              <el-select
+                v-model="form.statusAlarmLevel"
+                placeholder="请选择"
+                clearable
+                style="width: 100%"
+                :disabled="title == '详情'"
+              >
+                <el-option label="一般" :value="1"></el-option>
+                <el-option label="严重" :value="2"></el-option>
+                <el-option label="危急" :value="3"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </template>
+      <template v-if="form.itemType == '2'">
+        <div class="section-title">状态设置</div>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="正常" prop="lightNormalText">
+              <el-select
+                v-model="form.lightNormalText"
+                placeholder="请选择"
+                :disabled="title == '详情'"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="红色" value="1"></el-option>
+                <el-option label="黄色" value="2"></el-option>
+                <el-option label="蓝色" value="3"></el-option>
+                <el-option label="绿色" value="4"></el-option>
+                <el-option label="白色" value="5"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="异常" prop="lightAbnormalText">
+              <el-select
+                v-model="form.lightAbnormalText"
+                placeholder="请选择"
+                :disabled="title == '详情'"
+                clearable
+                style="width: 100%"
+              >
+                <el-option label="红色" value="1"></el-option>
+                <el-option label="黄色" value="2"></el-option>
+                <el-option label="蓝色" value="3"></el-option>
+                <el-option label="绿色" value="4"></el-option>
+                <el-option label="白色" value="5"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="是否告警" prop="statusAlarmFlag">
+              <el-radio-group
+                v-model="form.statusAlarmFlag"
+                :disabled="title == '详情'"
+              >
+                <el-radio :label="1">是</el-radio>
+                <el-radio :label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="告警等级" prop="statusAlarmLevel">
+              <el-select
+                v-model="form.statusAlarmLevel"
+                placeholder="请选择"
+                clearable
+                style="width: 100%"
+                :disabled="title == '详情'"
+              >
+                <el-option label="一般" value="1"></el-option>
+                <el-option label="严重" value="2"></el-option>
+                <el-option label="危急" value="3"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </template>
+      <!-- 告警阀值区域 - 仅当测点类型为数值时显示 -->
+      <template v-if="form.itemType == '0'">
+        <div class="section-title">告警阀值</div>
+
+        <!-- 一般告警 -->
+        <el-row :gutter="10" class="alarm-row">
+          <el-col :span="3" class="alarm-label">一般告警</el-col>
+          <el-col :span="6">
+            <el-input-number
+              v-model="form.alarm1MaxValue"
+              placeholder="请输入"
+              controls-position="right"
+              :disabled="title == '详情'"
+              style="width: 100%"
+            />
+          </el-col>
+          <el-col :span="3">
+            <el-select
+              v-model="form.alarm1MaxSymbol"
+              style="width: 100%"
+              :disabled="title == '详情'"
+            >
+              <el-option label=">" value=">"></el-option>
+              <el-option label="<" value="<"></el-option>
+              <el-option label="=" value="="></el-option>
+              <el-option label=">=" value=">="></el-option>
+              <el-option label="<=" value="<="></el-option>
+            </el-select>
+          </el-col>
+          <el-select
+            v-model="form.alarm1Type"
+            style="width: 80px"
+            :disabled="title == '详情'"
+          >
+            <el-option label="或" value="or"></el-option>
+            <el-option label="且" value="and"></el-option>
+          </el-select>
+          <el-col :span="3">
+            <el-select
+              v-model="form.alarm1MinSymbol"
+              style="width: 100%"
+              :disabled="title == '详情'"
+            >
+              <el-option label=">" value=">"></el-option>
+              <el-option label="<" value="<"></el-option>
+              <el-option label="=" value="="></el-option>
+              <el-option label=">=" value=">="></el-option>
+              <el-option label="<=" value="<="></el-option>
+            </el-select>
+          </el-col>
+          <el-col :span="6">
+            <el-input-number
+              v-model="form.alarm1MinValue"
+              placeholder="请输入"
+              controls-position="right"
+              :disabled="title == '详情'"
+              style="width: 100%"
+            />
+          </el-col>
+        </el-row>
+
+        <!-- 严重告警 -->
+        <el-row :gutter="10" class="alarm-row">
+          <el-col :span="3" class="alarm-label">严重告警</el-col>
+          <el-col :span="6">
+            <el-input-number
+              v-model="form.alarm2MaxValue"
+              placeholder="请输入"
+              controls-position="right"
+              :disabled="title == '详情'"
+              style="width: 100%"
+            />
+          </el-col>
+          <el-col :span="3">
+            <el-select
+              v-model="form.alarm2MaxSymbol"
+              style="width: 100%"
+              :disabled="title == '详情'"
+            >
+              <el-option label=">" value=">"></el-option>
+              <el-option label="<" value="<"></el-option>
+              <el-option label="=" value="="></el-option>
+              <el-option label=">=" value=">="></el-option>
+              <el-option label="<=" value="<="></el-option>
+            </el-select>
+          </el-col>
+          <el-select
+            v-model="form.alarm2Type"
+            style="width: 80px"
+            :disabled="title == '详情'"
+          >
+            <el-option label="或" value="or"></el-option>
+            <el-option label="且" value="and"></el-option>
+          </el-select>
+          <el-col :span="3">
+            <el-select
+              v-model="form.alarm2MinSymbol"
+              style="width: 100%"
+              :disabled="title == '详情'"
+            >
+              <el-option label=">" value=">"></el-option>
+              <el-option label="<" value="<"></el-option>
+              <el-option label="=" value="="></el-option>
+              <el-option label=">=" value=">="></el-option>
+              <el-option label="<=" value="<="></el-option>
+            </el-select>
+          </el-col>
+          <el-col :span="6">
+            <el-input-number
+              v-model="form.alarm2MinValue"
+              placeholder="请输入"
+              :disabled="title == '详情'"
+              controls-position="right"
+              style="width: 100%"
+            />
+          </el-col>
+        </el-row>
+
+        <!-- 危急告警 -->
+        <el-row :gutter="10" class="alarm-row">
+          <el-col :span="3" class="alarm-label">危急告警</el-col>
+          <el-col :span="6">
+            <el-input-number
+              v-model="form.alarm3MaxValue"
+              placeholder="请输入"
+              controls-position="right"
+              :disabled="title == '详情'"
+              style="width: 100%"
+            />
+          </el-col>
+          <el-col :span="3">
+            <el-select
+              v-model="form.alarm3MaxSymbol"
+              style="width: 100%"
+              :disabled="title == '详情'"
+            >
+              <el-option label=">" value=">"></el-option>
+              <el-option label="<" value="<"></el-option>
+              <el-option label="=" value="="></el-option>
+              <el-option label=">=" value=">="></el-option>
+              <el-option label="<=" value="<="></el-option>
+            </el-select>
+          </el-col>
+          <el-select
+            v-model="form.alarm3Type"
+            style="width: 80px"
+            :disabled="title == '详情'"
+          >
+            <el-option label="或" value="or"></el-option>
+            <el-option label="且" value="and"></el-option>
+          </el-select>
+          <el-col :span="3">
+            <el-select
+              v-model="form.alarm3MinSymbol"
+              style="width: 100%"
+              :disabled="title == '详情'"
+            >
+              <el-option label=">" value=">"></el-option>
+              <el-option label="<" value="<"></el-option>
+              <el-option label="=" value="="></el-option>
+              <el-option label=">=" value=">="></el-option>
+              <el-option label="<=" value="<="></el-option>
+            </el-select>
+          </el-col>
+          <el-col :span="6">
+            <el-input-number
+              v-model="form.alarm3MinValue"
+              placeholder="请输入"
+              controls-position="right"
+              :disabled="title == '详情'"
+              style="width: 100%"
+            />
+          </el-col>
+        </el-row>
+
+        <!-- 单位 -->
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="单位" prop="unitCode">
+              <el-select
+                v-model="form.unitCode"
+                placeholder="请选择"
+                clearable
+                :disabled="title == '详情'"
+                style="width: 100%"
+              >
+                <el-option label="℃" value="℃"></el-option>
+
+                <el-option label="V" value="V"></el-option>
+                <el-option label="A" value="A"></el-option>
+                <el-option label="mA" value="mA"></el-option>
+                <el-option label="kW" value="kW"></el-option>
+                <el-option label="w" value="w"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </template>
+
+      <!-- 算法区域 -->
+      <div class="section-title">算法</div>
+
+      <el-row :gutter="20">
+        <el-col :span="12">
+          <el-form-item label="算法名称" prop="unitName">
+            <el-select
+              v-model="form.unitName"
+              placeholder="请选择"
+              clearable
+              :disabled="title == '详情'"
+              style="width: 100%"
+            >
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="12">
+          <el-form-item label="值索引" prop="valueIndex">
+            <el-input-number
+              v-model="form.valueIndex"
+              :min="1"
+              :disabled="title == '详情'"
+              controls-position="right"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+      </el-row>
+
+      <el-row>
+        <el-col :span="12">
+          <el-form-item label="延时设置" prop="algDelayTimes">
+            <el-input-number
+              v-model="form.algDelayTimes"
+              :min="0"
+              :disabled="title == '详情'"
+              controls-position="right"
+              style="width: calc(100% - 40px)"
+            />
+            <span style="margin-left: 10px">s</span>
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <template slot="footer">
+      <el-button size="small" @click="handleCancel">取消</el-button>
+      <el-button
+        type="primary"
+        size="small"
+        @click="handleSubmit"
+        v-if="title != '详情'"
+        >确定</el-button
+      >
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  const defaultForm = {
+    id: null,
+    code: '',
+    measuringPointCode: '',
+    name: '',
+    itemType: 0,
+    indexNo: 100,
+    // 状态设置(状态类型)
+    statusNormalText: '',
+    statusAbnormalText: '',
+    // 状态设置(颜色类型)
+    lightNormalText: '',
+    lightAbnormalText: '',
+    // 告警设置
+    statusAlarmFlag: 0,
+    statusAlarmLevel: '',
+    // 一般告警
+    alarm1MaxValue: null,
+    alarm1MaxSymbol: '>',
+    alarm1Type: 'or',
+    alarm1MinSymbol: '>',
+    alarm1MinValue: null,
+    // 严重告警
+    alarm2MaxValue: null,
+    alarm2MaxSymbol: '>',
+    alarm2Type: 'or',
+    alarm2MinSymbol: '>',
+    alarm2MinValue: null,
+    // 危急告警
+    alarm3MaxValue: null,
+    alarm3MaxSymbol: '>',
+    alarm3Type: 'or',
+    alarm3MinSymbol: '>',
+    alarm3MinValue: null,
+    // 单位
+    unitCode: '',
+    // 算法
+    unitName: '',
+    valueIndex: 1,
+    algDelayTimes: 15
+  };
+  export default {
+    name: 'MeasurePointForm',
+    data() {
+      return {
+        visible: false,
+        title: '新增测点',
+        form: {
+          ...defaultForm
+        },
+        rules: {
+          // code: [
+          //   { required: true, message: '请输入测点编码', trigger: 'blur' }
+          // ],
+          name: [
+            { required: true, message: '请输入测点名称', trigger: 'blur' }
+          ],
+          itemType: [
+            { required: true, message: '请选择测点类型', trigger: 'change' }
+          ],
+          indexNo: [
+            { required: true, message: '请输入排序号', trigger: 'blur' }
+          ]
+        }
+      };
+    },
+    methods: {
+      open(row, type = 'add') {
+        if (row && (type === 'edit' || type === 'view')) {
+          this.title = type === 'edit' ? '编辑测点' : '详情';
+          this.form = { ...this.form, ...row };
+        } else {
+          this.title = '新增测点';
+          this.resetForm();
+        }
+        this.visible = true;
+      },
+      updateVisible(val) {
+        this.visible = val;
+        if (!val) {
+          this.resetForm();
+        }
+      },
+      resetForm() {
+        this.form = {
+          ...defaultForm
+        };
+        this.$nextTick(() => {
+          this.$refs.formRef && this.$refs.formRef.clearValidate();
+        });
+      },
+      handleSubmit() {
+        this.$refs.formRef.validate((valid) => {
+          if (valid) {
+            this.$emit('submit', this.form);
+            this.visible = false;
+          }
+        });
+      },
+      handleCancel() {
+        this.visible = false;
+      }
+    }
+  };
+</script>
+
+<style scoped>
+  .section-title {
+    font-size: 14px;
+    font-weight: bold;
+    color: #606266;
+    margin: 20px 0 15px 0;
+    padding-left: 10px;
+    border-left: 4px solid #409eff;
+  }
+
+  .alarm-row {
+    margin-bottom: 10px;
+    display: flex;
+    align-items: center;
+  }
+
+  .alarm-label {
+    text-align: right;
+    padding-right: 10px;
+    color: #606266;
+    font-size: 14px;
+  }
+</style>

+ 140 - 0
src/views/meterModel/components/parameterForm.vue

@@ -0,0 +1,140 @@
+<template>
+  <ele-modal
+    :visible="visible"
+    :title="title"
+    width="500px"
+    :destroy-on-close="true"
+    @update:visible="updateVisible"
+    append-to-body
+  >
+    <el-form
+      ref="formRef"
+      :model="form"
+      :rules="rules"
+      label-width="100px"
+      size="small"
+    >
+      <el-form-item label="参数名称" prop="paramName">
+        <el-input
+          v-model="form.paramName"
+          :disabled="title == '详情'"
+          placeholder="请输入参数名称"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="参数值" prop="paramValue">
+        <el-input
+          v-model="form.paramValue"
+          :disabled="title == '详情'"
+          placeholder="请输入参数值"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="参数说明" prop="paramDesc">
+        <el-input
+          v-model="form.paramDesc"
+          type="textarea"
+          :disabled="title == '详情'"
+          :rows="3"
+          placeholder="请输入参数说明"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item label="排序号" prop="indexNo">
+        <el-input-number
+          v-model="form.indexNo"
+          :min="1"
+          :disabled="title == '详情'"
+          :max="999"
+          controls-position="right"
+          style="width: 100%"
+        />
+      </el-form-item>
+    </el-form>
+
+    <template slot="footer">
+      <el-button
+        type="primary"
+        size="small"
+        @click="handleSubmit"
+        v-if="title != '详情'"
+        >确定</el-button
+      >
+      <el-button size="small" @click="handleCancel">取消</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+  export default {
+    name: 'ParameterForm',
+    data() {
+      return {
+        visible: false,
+        title: '新增参数',
+        form: {
+          id: null,
+          paramName: '',
+          paramValue: '',
+          paramDesc: '',
+          indexNo: 1
+        },
+        rules: {
+          paramName: [
+            { required: true, message: '请输入参数名称', trigger: 'blur' }
+          ],
+          paramValue: [
+            { required: true, message: '请输入参数值', trigger: 'blur' }
+          ],
+          indexNo: [
+            { required: true, message: '请输入排序号', trigger: 'blur' }
+          ]
+        }
+      };
+    },
+    methods: {
+      open(row, type = 'add') {
+        if (row && (type === 'edit' || type === 'view')) {
+          this.title = type === 'edit' ? '编辑参数' : '详情';
+          this.form = { ...this.form, ...row };
+        } else {
+          this.title = '新增参数';
+          this.resetForm();
+        }
+        this.visible = true;
+      },
+      updateVisible(val) {
+        this.visible = val;
+        if (!val) {
+          this.resetForm();
+        }
+      },
+      resetForm() {
+        this.form = {
+          id: null,
+          paramName: '',
+          paramValue: '',
+          paramDesc: '',
+          indexNo: 1
+        };
+        this.$nextTick(() => {
+          this.$refs.formRef && this.$refs.formRef.clearValidate();
+        });
+      },
+      handleSubmit() {
+        this.$refs.formRef.validate((valid) => {
+          if (valid) {
+            this.$emit('submit', this.form);
+            this.visible = false;
+          }
+        });
+      },
+      handleCancel() {
+        this.visible = false;
+      }
+    }
+  };
+</script>

+ 493 - 0
src/views/meterModel/energyDialog.vue

@@ -0,0 +1,493 @@
+<template>
+  <ele-modal
+    :visible="visible"
+    :title="title"
+    width="60%"
+    :destroy-on-close="true"
+    :maxable="true"
+    @update:visible="updateVisible"
+    :bodyStyle="{ padding: '30px 40px' }"
+    append-to-body
+  >
+    <el-tabs type="border-card" v-model="activeValue">
+      <el-tab-pane label="基本信息" :name="1">
+        <el-form
+          ref="formRef"
+          :model="form"
+          :rules="rules"
+          label-width="140px"
+          size="small"
+        >
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="表计模版编码" prop="code">
+                <el-input
+                  clearable
+                  v-model="form.code"
+                  placeholder="系统生成"
+                  disabled
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="表计模版编号" prop="meterTemplateNumber">
+                <el-input
+                  clearable
+                  v-model="form.meterTemplateNumber"
+                  placeholder="请选择"
+                  :disabled="title == '详情'"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="24">
+              <el-form-item label="表计模版名称" prop="name">
+                <el-input
+                  clearable
+                  v-model="form.name"
+                  placeholder="请选择"
+                  :disabled="title == '详情'"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="表计类型" prop="meterType">
+                <DictSelection
+                  dictName="表计类型"
+                  clearable
+                  v-model="form.meterType"
+                  :isProhibit="title == '详情'"
+                >
+                </DictSelection
+              ></el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="表计品牌" prop="meterBrand">
+                <el-input
+                  clearable
+                  :disabled="title == '详情'"
+                  v-model="form.meterBrand"
+                  placeholder="请选择"
+                />
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="表计图片" prop="modelImg">
+                <fileMain
+                  v-model="form.modelImg"
+                  :type="title == '详情' ? 'view' : 'add'"
+                ></fileMain>
+              </el-form-item>
+            </el-col>
+          </el-row> </el-form
+      ></el-tab-pane>
+      <el-tab-pane label="规格参数" :name="2">
+        <ele-pro-table
+          ref="table"
+          :columns="parameterColumns"
+          :datasource="parameterList"
+          max-height="400"
+          :needPage="false"
+        >
+          <!-- 表头工具栏 -->
+          <template v-slot:toolbar>
+            <el-button
+              size="small"
+              type="primary"
+              icon="el-icon-plus"
+              class="ele-btn-icon"
+              @click="handleAddOrEdit('', 'add')"
+              v-if="title != '详情'"
+            >
+              添加
+            </el-button>
+          </template>
+          <!-- 操作列 -->
+          <template v-slot:action="{ row, $index }">
+            <el-link
+              type="primary"
+              :underline="false"
+              @click="handleAddOrEdit(row, 'view')"
+              style="margin-right: 10px"
+            >
+              详情
+            </el-link>
+            <el-link
+              type="primary"
+              :underline="false"
+              icon="el-icon-edit"
+              @click="handleAddOrEdit(row, 'edit', $index)"
+              style="margin-right: 10px"
+              v-if="title != '详情'"
+            >
+              修改
+            </el-link>
+            <el-popconfirm
+              title="确定删除此参数吗?"
+              @confirm="handleDelete($index)"
+              v-if="title != '详情'"
+            >
+              <el-link
+                slot="reference"
+                type="danger"
+                :underline="false"
+                icon="el-icon-delete"
+              >
+                删除
+              </el-link>
+            </el-popconfirm>
+          </template>
+        </ele-pro-table>
+      </el-tab-pane>
+      <el-tab-pane label="表计测点" :name="3">
+        <ele-pro-table
+          ref="measureTable"
+          :columns="measureColumns"
+          :datasource="measureList"
+          max-height="400"
+          :needPage="false"
+        >
+          <!-- 表头工具栏 -->
+          <template v-slot:toolbar>
+            <el-button
+              size="small"
+              type="primary"
+              icon="el-icon-plus"
+              class="ele-btn-icon"
+              @click="handleAddOrEditMeasure('', 'add')"
+              v-if="title != '详情'"
+            >
+              添加
+            </el-button>
+          </template>
+          <!-- 操作列 -->
+          <template v-slot:action="{ row, $index }">
+            <el-link
+              type="primary"
+              :underline="false"
+              @click="handleAddOrEditMeasure(row, 'view')"
+              style="margin-right: 10px"
+            >
+              详情
+            </el-link>
+            <el-link
+              type="primary"
+              :underline="false"
+              icon="el-icon-edit"
+              @click="handleAddOrEditMeasure(row, 'edit', $index)"
+              style="margin-right: 10px"
+              v-if="title != '详情'"
+            >
+              修改
+            </el-link>
+            <el-popconfirm
+              title="确定删除此测点吗?"
+              v-if="title != '详情'"
+              @confirm="handleDeleteMeasure($index)"
+            >
+              <el-link
+                slot="reference"
+                type="danger"
+                :underline="false"
+                icon="el-icon-delete"
+              >
+                删除
+              </el-link>
+            </el-popconfirm>
+          </template>
+        </ele-pro-table>
+      </el-tab-pane>
+    </el-tabs>
+
+    <template slot="footer">
+      <el-button type="primary" size="small" @click="handleSubmit"
+        >保存</el-button
+      >
+      <el-button size="small" @click="handleCancel">取消</el-button>
+    </template>
+    <!-- 参数表单弹窗 -->
+    <parameter-form ref="parameterForm" @submit="handleParameterSubmit" />
+
+    <!-- 测点表单弹窗 -->
+    <measure-point-form ref="measurePointForm" @submit="handleMeasureSubmit" />
+  </ele-modal>
+</template>
+
+<script>
+  import imgUpload from '@/components/upload/imgUpload.vue';
+  import ParameterForm from './components/parameterForm.vue';
+  import MeasurePointForm from './components/measurePointForm.vue';
+  import { getById, saveOrEdit } from '@/api/meterModel/index.js';
+  const defaultForm = {
+    code: '',
+    meterBrand: '',
+    meterTemplateNumber: '',
+    meterType: '',
+    modelImg: [],
+    name: '',
+    paramsList: [],
+    itemList: []
+  };
+  export default {
+    name: 'EnergyDialog',
+    components: { imgUpload, ParameterForm, MeasurePointForm },
+    data() {
+      return {
+        visible: false,
+        title: '新增',
+        activeValue: 1,
+        parameterList: [],
+        measureList: [],
+        parameterColumns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center'
+          },
+          {
+            prop: 'paramName',
+            label: '参数名称',
+            align: 'center',
+            minWidth: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'paramValue',
+            label: '参数值',
+            align: 'center',
+            minWidth: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'paramDesc',
+            label: '参数说明',
+            align: 'center',
+            minWidth: 150,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'indexNo',
+            label: '排序号',
+            align: 'center',
+            width: 80
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 200,
+            align: 'center',
+            slot: 'action',
+            resizable: false
+          }
+        ],
+        measureColumns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center'
+          },
+          {
+            prop: 'code',
+            label: '测点编码',
+            align: 'center',
+            minWidth: 150,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'measuringPointCode',
+            label: '测点代码',
+            align: 'center',
+            minWidth: 200,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'name',
+            label: '测点名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'itemType',
+            label: '测点类型',
+            align: 'center',
+            width: 100,
+            formatter: (row, column) => {
+              return row.itemType == 1
+                ? '状态'
+                : row.itemType == 2
+                ? '颜色'
+                : '数值';
+            }
+          },
+
+          {
+            prop: 'indexNo',
+            label: '排序号',
+            align: 'center',
+            width: 80
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 200,
+            align: 'center',
+            slot: 'action',
+            resizable: false
+          }
+        ],
+        form: {
+          ...defaultForm
+        },
+        rules: {
+          name: [
+            { required: true, message: '请输入', trigger: 'blur' },
+            { required: true, message: '请输入', trigger: 'change' }
+          ],
+          meterBrand: [
+            { required: true, message: '请输入', trigger: 'blur' },
+            { required: true, message: '请输入', trigger: 'change' }
+          ],
+          meterType: [
+            {
+              required: true,
+              message: '请选择',
+              trigger: 'change'
+            }
+          ],
+
+          modelImg: [{ required: true, message: '请选择', trigger: 'change' }]
+        }
+      };
+    },
+    methods: {
+      // 打开弹窗
+      async open(row, type) {
+        this.activeValue = 1;
+
+        if (row) {
+          this.title = type == 'edit' ? '编辑' : '详情';
+          this.form = await getById(row.id);
+
+          this.measureList = this.form.itemList || [];
+          this.parameterList = this.form.paramsList || [];
+          // this.form = { ...row };
+        } else {
+          this.title = '新增';
+          this.resetForm();
+        }
+        this.visible = true;
+      },
+      // 打开参数表单弹窗
+      handleAddOrEdit(row, type, index) {
+        this.currentIndex = index;
+        this.$refs.parameterForm.open(row, type);
+      },
+      // 处理参数提交
+      handleParameterSubmit(formData) {
+        if (this.currentIndex || this.currentIndex === 0) {
+          this.$set(this.parameterList, this.currentIndex, { ...formData });
+        } else {
+          // 新增模式
+          const newParam = {
+            ...formData
+          };
+          this.parameterList.push(newParam);
+        }
+      },
+      // 删除参数
+      handleDelete(index) {
+        this.parameterList.splice(index, 1);
+      },
+      // 打开测点表单弹窗
+      handleAddOrEditMeasure(row, type, index) {
+        this.currentIndex = index;
+        this.$refs.measurePointForm.open(row, type);
+      },
+      // 处理测点提交
+      handleMeasureSubmit(formData) {
+        if (this.currentIndex || this.currentIndex === 0) {
+          this.$set(this.measureList, this.currentIndex, { ...formData });
+        } else {
+          // 新增模式
+          const newMeasure = {
+            ...formData
+          };
+          this.measureList.push(newMeasure);
+        }
+      },
+      // 删除测点
+      handleDeleteMeasure(index) {
+        this.measureList.splice(index, 1);
+      },
+      // 关闭弹窗
+      updateVisible(val) {
+        this.visible = val;
+        if (!val) {
+          this.resetForm();
+        }
+      },
+      // 重置表单
+      resetForm() {
+        this.form = {
+          ...defaultForm
+        };
+
+        this.measureList = [];
+        this.parameterList = [];
+        this.$nextTick(() => {
+          this.$refs.formRef && this.$refs.formRef.clearValidate();
+        });
+      },
+      // 提交
+      handleSubmit() {
+        this.$refs.formRef.validate((valid) => {
+          if (valid) {
+            if (!this.measureList.length) {
+              this.activeValue = 3;
+              this.$message.warning('请维护一条表计测点!');
+
+              return;
+            }
+            this.loading = true;
+            this.form.paramsList = this.parameterList;
+            this.form.itemList = this.measureList;
+            saveOrEdit(this.form)
+              .then((res) => {
+                this.$message.success('操作成功');
+                this.handleCancel();
+                this.$emit('reload');
+              })
+              .finally(() => {
+                this.loading = false;
+                this.visible = false;
+              });
+          } else {
+            this.$message.warning('请完善基本信息!');
+
+            this.activeValue = 1;
+          }
+        });
+      },
+      // 取消
+      handleCancel() {
+        this.visible = false;
+        this.resetForm();
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  ::v-deep .el-form-item__label {
+    color: #606266;
+  }
+
+  ::v-deep .el-input-group__append {
+    background-color: #f5f7fa;
+    color: #909399;
+    padding: 0 15px;
+  }
+</style>

+ 296 - 0
src/views/meterModel/index.vue

@@ -0,0 +1,296 @@
+<template>
+  <div class="energy-classification">
+    <el-card shadow="never" class="classification-card">
+      <!-- 搜索区域 -->
+      <div class="search-area">
+        <seek-page
+          :seekList="seekList"
+          @search="handleSearch"
+          @reset="handleReset"
+          :formLength="3"
+        />
+      </div>
+
+      <!-- 列表视图 -->
+      <div class="list-view">
+        <ele-pro-table
+          ref="table"
+          row-key="id"
+          :columns="columns"
+          :datasource="datasource"
+          @columns-change="handleColumnChange"
+          :cache-key="cacheKeyUrl"
+          height="calc(100vh - 350px)"
+        >
+          <template v-slot:code="{ row }">
+            <el-link
+              type="primary"
+              :underline="false"
+              @click="handleEdit(row, 'view')"
+            >
+              {{ row.code }}
+            </el-link>
+          </template>
+          <template v-slot:toolbar
+            ><el-button
+              type="primary"
+              size="small"
+              icon="el-icon-plus"
+              @click="handleAdd"
+              >新增</el-button
+            ></template
+          >
+
+          <template v-slot:modelImg="{ row }">
+            <fileMain v-model="row.modelImg" type="view"></fileMain>
+          </template>
+
+          <template v-slot:action="{ row }">
+            <el-link type="primary" :underline="false" @click="handleEdit(row,'edit')"
+              >编辑</el-link
+            >
+            <el-link
+              type="danger"
+              :underline="false"
+              @click="handleDelete(row)"
+              style="margin-left: 8px"
+              >删除</el-link
+            >
+          </template>
+        </ele-pro-table>
+      </div>
+
+      <!-- 备注说明 -->
+      <!-- <div class="remark-area">
+        <p>备注:二氧化碳排放系数(kgCO₂e)× 折标准煤系数(kgce)</p>
+      </div> -->
+
+      <!-- 新增/编辑弹窗 -->
+      <energy-dialog ref="energyDialogRef" @reload="$refs.table.reload()" />
+    </el-card>
+  </div>
+</template>
+
+<script>
+  import EnergyDialog from './energyDialog.vue';
+  import { getPage } from '@/api/meterModel/index.js';
+  import tabMixins from '@/mixins/tableColumnsMixin';
+  import dictMixins from '@/mixins/dictMixins';
+
+  export default {
+    mixins: [tabMixins, dictMixins],
+
+    components: {
+      EnergyDialog
+    },
+    data() {
+      return {
+        cacheKeyUrl: 'main-meterModel-index',
+
+        // 表格列配置
+        columns: [
+          {
+            columnKey: 'index',
+            label: '序号',
+            type: 'index',
+            width: 55,
+            align: 'center'
+          },
+          {
+            prop: 'code',
+            slot:'code',
+            label: '表计模版编码',
+            align: 'center',
+            minWidth: 120,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'meterTemplateNumber',
+            label: '表计模版编号',
+            align: 'center',
+            minWidth: 150,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'name',
+            label: '表计模版名称',
+            align: 'center',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'meterType',
+            label: '表计类型',
+            align: 'center',
+            minWidth: 150,
+            formatter: (row, column) => {
+              return this.getDictValue('表计类型', row.meterType);
+            },
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'meterBrand',
+            label: '表计品牌',
+            align: 'center',
+            minWidth: 140
+          },
+          {
+            prop: 'modelImg',
+            label: '图片',
+            align: 'center',
+            minWidth: 150,
+            slot: 'modelImg'
+          },
+          // {
+          //   prop: 'creator',
+          //   label: '创建人',
+          //   align: 'center',
+          //   minWidth: 100,
+          //   showOverflowTooltip: true
+          // },
+          {
+            prop: 'createTime',
+            label: '创建时间',
+            align: 'center',
+            minWidth: 160,
+            showOverflowTooltip: true
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 120,
+            align: 'center',
+            slot: 'action'
+          }
+        ],
+        cacheKeyUrl: 'ems-energy-classification-list'
+      };
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            label: '表计模版编码',
+            value: 'code',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '表计模版编号',
+            value: 'meterTemplateNumber',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '表计模版名称',
+            value: 'name',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '表计品牌',
+            value: 'meterBrand',
+            type: 'input',
+            placeholder: '请输入'
+          },
+          {
+            label: '表计类型',
+            value: 'meterType',
+            type: 'DictSelection',
+            dictName: '表计类型',
+            placeholder: ' '
+          }
+        ];
+      }
+    },
+    created() {
+      this.requestDict('表计类型');
+    },
+    methods: {
+      // 新增
+      handleAdd() {
+        this.$refs.energyDialogRef.open();
+      },
+      // 编辑
+      handleEdit(row,type) {
+        this.$refs.energyDialogRef.open(row,type);
+      },
+      // 删除
+      handleDelete(row) {
+        this.$confirm('确认删除该能源分类吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        })
+          .then(() => {
+            this.$message.success('删除成功');
+          })
+          .catch(() => {});
+      },
+      // 搜索
+      handleSearch(where) {
+        this.$refs.table.reload({ page: 1, where });
+      },
+      // 重置
+      handleReset() {
+        this.$refs.table.reload({ page: 1 });
+      },
+      // 表格数据源
+      datasource({ page, limit, where }) {
+        return getPage({
+          pageNum: page,
+          size: limit,
+          ...where
+        });
+      }
+    }
+  };
+</script>
+
+<style lang="scss" scoped>
+  .energy-classification {
+    .classification-card {
+      height: calc(100vh - 100px);
+
+      ::v-deep .el-card__body {
+        height: 100%;
+        padding: 15px;
+        display: flex;
+        flex-direction: column;
+      }
+    }
+
+    // 搜索区域
+    .search-area {
+      margin-bottom: 15px;
+      padding-bottom: 15px;
+      border-bottom: 1px solid #ebeef5;
+    }
+
+    // 列表视图
+    .list-view {
+      flex: 1;
+      overflow: hidden;
+
+      ::v-deep .ele-pro-table {
+        .el-table {
+          border: 1px solid #ebeef5;
+          border-radius: 4px;
+        }
+      }
+    }
+
+    // 备注说明
+    .remark-area {
+      margin-top: 15px;
+      padding: 10px;
+      background: #f5f7fa;
+      border-radius: 4px;
+      font-size: 12px;
+      color: #909399;
+
+      p {
+        margin: 0;
+      }
+    }
+  }
+</style>