Procházet zdrojové kódy

光伏对接、策略优化、模型分页bug

learshaw před 4 měsíci
rodič
revize
421be16381

+ 6 - 4
ems-ui-cloud/src/views/adapter/nhjc/index.vue

@@ -315,8 +315,6 @@
           </div>
         </el-tab-pane>
 
-        <!-- 楼控设备标签页 - 已改造 -->
-        <!-- 楼控设备标签页 - 已改造 -->
         <el-tab-pane label="楼控设备" name="baDevices">
           <div class="tab-content">
             <!-- 设备类型选择 -->
@@ -491,7 +489,11 @@
             <el-table :data="callLogList" border stripe v-loading="logLoading">
               <el-table-column prop="objCode" label="对象代码" min-width="150"></el-table-column>
               <el-table-column prop="objName" label="对象名称" min-width="200"></el-table-column>
-              <el-table-column prop="abilityName" label="能力名称" min-width="150"></el-table-column>
+              <el-table-column label="能力名称" min-width="150">
+                <template slot-scope="scope">
+                  {{ scope.row.abilityName || scope.row.abilityKey }}
+                </template>
+              </el-table-column>
               <el-table-column prop="callTime" label="调用时间" width="180"></el-table-column>
               <el-table-column label="调用状态" width="100" align="center">
                 <template slot-scope="scope">
@@ -1608,7 +1610,7 @@ export default {
 
         this.baDeviceList = deviceData.map(device => ({
           ...device,
-          detailTab: 'base'
+          detailTab: 'state'
         }))
 
         // 3. 批量加载设备属性值

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 645 - 214
ems-ui-cloud/src/views/adapter/pv/index.vue


+ 13 - 5
ems-ui-cloud/src/views/analysis/report/statement-consume.vue

@@ -425,13 +425,21 @@ export default {
         this.queryParams.startRecTime = this.formatDate(startDate) + ' 00:00:00'
         this.queryParams.endRecTime = this.formatDate(today) + ' 23:59:59'
       } else if (this.queryParams.timeDimension === 'month') {
-        // 月维度:当年1月到当前月
+        // 月维度:本月第一天到最后一天
+        const firstDayOfMonth = new Date(currentYear, currentMonth, 1)
+        const lastDayOfMonth = new Date(currentYear, currentMonth + 1, 0)
+
         this.monthRange = [
-          `${currentYear}-01`,
-          `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}`
+          `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}`, // 当前月
+          `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}` // 实际上是一个月,但月范围选择器需要两个值,可以设为相同
         ]
-        this.queryParams.startRecTime = `${currentYear}-01-01 00:00:00`
-        this.queryParams.endRecTime = this.formatDate(new Date(currentYear, currentMonth + 1, 0)) + ' 23:59:59'
+
+        const startMonth = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}`
+        const endMonth = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}` // 同一个月
+        this.monthRange = [startMonth, endMonth]
+
+        this.queryParams.startRecTime = this.formatDate(firstDayOfMonth) + ' 00:00:00'
+        this.queryParams.endRecTime = this.formatDate(lastDayOfMonth) + ' 23:59:59'
       } else if (this.queryParams.timeDimension === 'year') {
         // 年维度:当年
         this.yearValue = String(currentYear)

+ 13 - 5
ems-ui-cloud/src/views/analysis/report/statement-prod.vue

@@ -337,13 +337,21 @@ export default {
         this.queryParams.startRecTime = this.formatDate(startDate) + ' 00:00:00'
         this.queryParams.endRecTime = this.formatDate(today) + ' 23:59:59'
       } else if (this.tabPosition === 'month') {
-        // 月维度:当年1月到当前月
+        // 月维度:本月第一天到最后一天
+        const firstDayOfMonth = new Date(currentYear, currentMonth, 1)
+        const lastDayOfMonth = new Date(currentYear, currentMonth + 1, 0)
+
         this.monthRange = [
-          `${currentYear}-01`,
-          `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}`
+          `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}`, // 当前月
+          `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}` // 实际上是一个月,但月范围选择器需要两个值,可以设为相同
         ]
-        this.queryParams.startRecTime = `${currentYear}-01-01 00:00:00`
-        this.queryParams.endRecTime = this.formatDate(new Date(currentYear, currentMonth + 1, 0)) + ' 23:59:59'
+
+        const startMonth = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}`
+        const endMonth = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}` // 同一个月
+        this.monthRange = [startMonth, endMonth]
+
+        this.queryParams.startRecTime = this.formatDate(firstDayOfMonth) + ' 00:00:00'
+        this.queryParams.endRecTime = this.formatDate(lastDayOfMonth) + ' 23:59:59'
       } else if (this.tabPosition === 'year') {
         // 年维度:当年
         this.yearValue = String(currentYear)

+ 7 - 1
ems-ui-cloud/src/views/basecfg/device/model.vue

@@ -589,7 +589,13 @@ export default {
     /** 查询设备模型列表 */
     getList() {
       this.loading = true
-      listModel({ objType: this.activeObjType }).then(response => {
+      listModel({
+        objType: this.activeObjType,
+        pageNum: this.queryParams.pageNum,
+        pageSize: this.queryParams.pageSize,
+        modelCode: this.queryParams.modelCode,
+        modelName: this.queryParams.modelName
+      }).then(response => {
         this.modelList = response.rows
         this.total = response.total
         this.loading = false

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 503 - 473
ems-ui-cloud/src/views/mgr/chargingpile.vue


+ 334 - 56
ems-ui-cloud/src/views/mgr/strategy/components/StepConfig.vue

@@ -18,27 +18,92 @@
       <template v-if="form.stepType === 'ABILITY'">
         <el-divider content-position="left">目标配置</el-divider>
 
-        <el-form-item label="目标设备" prop="targetObjCode">
+        <!-- 新增:目标类型选择(设备/子系统) -->
+        <el-form-item label="目标类型">
+          <el-radio-group v-model="targetCategory" size="mini" @change="handleTargetCategoryChange">
+            <el-radio-button label="device">
+              <i class="el-icon-cpu"></i> 设备
+            </el-radio-button>
+            <el-radio-button label="subsystem">
+              <i class="el-icon-s-platform"></i> 子系统
+            </el-radio-button>
+          </el-radio-group>
+        </el-form-item>
+
+        <!-- 设备选择 -->
+        <template v-if="targetCategory === 'device'">
+          <el-form-item label="目标设备" prop="targetObjCode">
+            <el-select
+              v-model="form.targetObjCode"
+              placeholder="请选择目标设备"
+              filterable
+              style="width: 100%"
+              @change="handleDeviceChange"
+            >
+              <el-option
+                v-for="device in deviceList"
+                :key="device.deviceCode"
+                :label="device.deviceName"
+                :value="device.deviceCode"
+              >
+                <span>{{ device.deviceName }}</span>
+                <span style="float: right; color: #909399; font-size: 12px">{{ device.deviceCode }}</span>
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </template>
+
+        <!-- 子系统选择 -->
+        <template v-if="targetCategory === 'subsystem'">
+          <el-form-item label="目标子系统" prop="targetObjCode">
+            <el-select
+              v-model="form.targetObjCode"
+              placeholder="请选择目标子系统"
+              filterable
+              style="width: 100%"
+              :loading="loadingSubsystem"
+              @change="handleSubsystemChange"
+            >
+              <el-option
+                v-for="subsystem in subsystemList"
+                :key="subsystem.systemCode"
+                :label="subsystem.systemName"
+                :value="subsystem.systemCode"
+              >
+                <span>{{ subsystem.systemName }}</span>
+                <span style="float: right; color: #909399; font-size: 12px">{{ subsystem.shortName }}</span>
+              </el-option>
+            </el-select>
+          </el-form-item>
+
+
+        </template>
+
+        <!-- 设备/子系统能力选择 -->
+        <el-form-item label="设备能力" prop="abilityKey" v-if="targetCategory === 'device'">
           <el-select
-            v-model="form.targetObjCode"
-            placeholder="请选择目标设备"
-            filterable
+            v-model="form.abilityKey"
+            placeholder="请选择设备能力"
             style="width: 100%"
-            @change="handleDeviceChange"
+            :loading="loadingAbility"
+            @change="handleAbilityChange"
           >
             <el-option
-              v-for="device in deviceList"
-              :key="device.deviceCode"
-              :label="device.deviceName"
-              :value="device.deviceCode"
-            />
+              v-for="ability in abilityList"
+              :key="ability.abilityKey"
+              :label="ability.abilityName"
+              :value="ability.abilityKey"
+            >
+              <span>{{ ability.abilityName }}</span>
+              <span style="float: right; color: #909399; font-size: 12px">{{ ability.abilityKey }}</span>
+            </el-option>
           </el-select>
         </el-form-item>
 
-        <el-form-item label="设备能力" prop="abilityKey">
+        <el-form-item label="系统能力" prop="abilityKey" v-if="targetCategory === 'subsystem'">
           <el-select
             v-model="form.abilityKey"
-            placeholder="请选择设备能力"
+            placeholder="请选择系统能力"
             style="width: 100%"
             :loading="loadingAbility"
             @change="handleAbilityChange"
@@ -48,7 +113,10 @@
               :key="ability.abilityKey"
               :label="ability.abilityName"
               :value="ability.abilityKey"
-            />
+            >
+              <span>{{ ability.abilityName }}</span>
+              <span style="float: right; color: #909399; font-size: 12px">{{ ability.abilityKey }}</span>
+            </el-option>
           </el-select>
         </el-form-item>
 
@@ -79,29 +147,79 @@
             <el-input v-model="form.abilityParam" placeholder="请输入参数值" @input="emitChange" />
           </div>
         </el-form-item>
+
+        <el-form-item v-if="form.paramSource === 'CONTEXT'" label="上下文变量">
+          <el-select v-model="form.abilityParam" placeholder="请选择上下文变量" style="width: 100%" @change="emitChange">
+            <el-option
+              v-for="variable in contextVariables"
+              :key="variable.varKey"
+              :label="variable.varName"
+              :value="variable.varKey"
+            >
+              <span>{{ variable.varName }}</span>
+              <span style="float: right; color: #909399; font-size: 12px">{{ variable.varKey }}</span>
+            </el-option>
+          </el-select>
+        </el-form-item>
       </template>
 
       <!-- ==================== 属性查询配置 ==================== -->
       <template v-if="form.stepType === 'ATTR_QUERY'">
         <el-divider content-position="left">查询配置</el-divider>
 
-        <el-form-item label="目标设备" prop="targetObjCode">
-          <el-select
-            v-model="form.targetObjCode"
-            placeholder="请选择设备"
-            filterable
-            style="width: 100%"
-            @change="handleQueryDeviceChange"
-          >
-            <el-option
-              v-for="device in deviceList"
-              :key="device.deviceCode"
-              :label="device.deviceName"
-              :value="device.deviceCode"
-            />
-          </el-select>
+        <!-- 新增:目标类型选择(设备/子系统) -->
+        <el-form-item label="目标类型">
+          <el-radio-group v-model="targetCategory" size="mini" @change="handleTargetCategoryChange">
+            <el-radio-button label="device">
+              <i class="el-icon-cpu"></i> 设备
+            </el-radio-button>
+            <el-radio-button label="subsystem">
+              <i class="el-icon-s-platform"></i> 子系统
+            </el-radio-button>
+          </el-radio-group>
         </el-form-item>
 
+        <!-- 设备选择 -->
+        <template v-if="targetCategory === 'device'">
+          <el-form-item label="目标设备" prop="targetObjCode">
+            <el-select
+              v-model="form.targetObjCode"
+              placeholder="请选择设备"
+              filterable
+              style="width: 100%"
+              @change="handleQueryDeviceChange"
+            >
+              <el-option
+                v-for="device in deviceList"
+                :key="device.deviceCode"
+                :label="device.deviceName"
+                :value="device.deviceCode"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+
+        <!-- 子系统选择 -->
+        <template v-if="targetCategory === 'subsystem'">
+          <el-form-item label="目标子系统" prop="targetObjCode">
+            <el-select
+              v-model="form.targetObjCode"
+              placeholder="请选择子系统"
+              filterable
+              style="width: 100%"
+              :loading="loadingSubsystem"
+              @change="handleQuerySubsystemChange"
+            >
+              <el-option
+                v-for="subsystem in subsystemList"
+                :key="subsystem.systemCode"
+                :label="subsystem.systemName"
+                :value="subsystem.systemCode"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+
         <el-form-item v-if="loadingQueryAttr">
           <div style="color: #909399; font-size: 12px;">
             <i class="el-icon-loading"></i> 正在加载属性列表...
@@ -268,6 +386,7 @@
 
 <script>
 import { getModelByCode } from '@/api/basecfg/objModel'
+import { listSubsystemAll } from '@/api/adapter/subsystem'
 
 export default {
   name: 'StepConfig',
@@ -284,7 +403,7 @@ export default {
         stepName: '',
         stepType: 'ABILITY',
         targetObjCode: '',
-        targetObjType: 2,
+        targetObjType: 2, // 2=设备, 1=子系统
         targetModelCode: '',
         abilityKey: '',
         abilityParam: '',
@@ -300,6 +419,14 @@ export default {
         stepName: [{ required: true, message: '请输入步骤名称', trigger: 'blur' }]
       },
 
+      // 新增:目标类型选择
+      targetCategory: 'device', // 'device' 或 'subsystem'
+
+      // 子系统相关
+      subsystemList: [],
+      loadingSubsystem: false,
+      selectedSubsystem: null,
+
       // 能力调用相关
       abilityList: [],
       currentAbility: null,
@@ -375,7 +502,13 @@ export default {
     }
   },
 
+  created() {
+    // 预加载子系统列表
+    this.loadSubsystemList()
+  },
+
   methods: {
+    // ========== 初始化 ==========
     initFormFromStep(step) {
       this.isUpdatingFromProp = true
 
@@ -393,13 +526,30 @@ export default {
       this.continueOnFailSwitch = this.form.continueOnFail === 1
       this.enableSwitch = this.form.enable === 1
 
+      // 根据 targetObjType 判断目标类型
+      // targetObjType: 1=子系统, 2=设备
+      if (step.targetObjType === 1) {
+        this.targetCategory = 'subsystem'
+        // 加载子系统并选中
+        this.loadSubsystemList().then(() => {
+          if (step.targetObjCode) {
+            this.selectedSubsystem = this.subsystemList.find(s => s.systemCode === step.targetObjCode)
+            if (this.selectedSubsystem && this.selectedSubsystem.modelCode) {
+              this.loadAbilities(this.selectedSubsystem.modelCode)
+            }
+          }
+        })
+      } else {
+        this.targetCategory = 'device'
+      }
+
       // 循环步骤解析跳出条件
       if (step.stepType === 'LOOP' && step.loopCondition) {
         this.parseLoopCondition(step.loopCondition)
       }
 
       // 能力调用加载能力列表
-      if (step.stepType === 'ABILITY' && step.targetModelCode) {
+      if (step.stepType === 'ABILITY' && step.targetModelCode && this.targetCategory === 'device') {
         this.loadAbilities(step.targetModelCode)
       }
 
@@ -411,34 +561,47 @@ export default {
       this.$nextTick(() => { this.isUpdatingFromProp = false })
     },
 
-    parseLoopCondition(loopCondition) {
+    // ========== 子系统相关 ==========
+    async loadSubsystemList() {
+      if (this.subsystemList.length > 0) return // 已加载则跳过
+
+      this.loadingSubsystem = true
       try {
-        const condition = JSON.parse(loopCondition)
-        if (condition.breakType === 'ATTR' && condition.deviceCode) {
-          this.loopBreakType = 'ATTR'
-          this.breakConfig = {
-            deviceCode: condition.deviceCode,
-            modelCode: condition.modelCode || '',
-            attrKey: condition.attrKey || '',
-            operator: condition.operator || '==',
-            value: condition.value || ''
-          }
-          if (condition.deviceCode) {
-            const device = this.deviceList.find(d => d.deviceCode === condition.deviceCode)
-            if (device) {
-              const modelCode = device.deviceModel || device.modelCode
-              if (modelCode) this.loadBreakAttrList(modelCode)
-            }
-          }
-        } else {
-          this.loopBreakType = 'EXPR'
-        }
-      } catch {
-        this.loopBreakType = 'EXPR'
+        const res = await listSubsystemAll()
+        this.subsystemList = res.data || []
+      } catch (error) {
+        console.error('加载子系统列表失败:', error)
+        this.subsystemList = []
+      } finally {
+        this.loadingSubsystem = false
       }
     },
 
-    // ========== 能力调用相关 ==========
+    // ========== 目标类型切换 ==========
+    handleTargetCategoryChange(category) {
+      // 清空之前的选择
+      this.form.targetObjCode = ''
+      this.form.targetModelCode = ''
+      this.form.abilityKey = ''
+      this.form.abilityParam = ''
+      this.abilityList = []
+      this.currentAbility = null
+      this.selectedSubsystem = null
+      this.queryAttrList = []
+      this.lastQueryModelCode = ''
+
+      // 更新 targetObjType
+      this.form.targetObjType = category === 'subsystem' ? 1 : 2
+
+      // 如果选择子系统,确保列表已加载
+      if (category === 'subsystem') {
+        this.loadSubsystemList()
+      }
+
+      this.emitChange()
+    },
+
+    // ========== 设备选择相关 ==========
     handleDeviceChange(deviceCode) {
       const device = this.deviceList.find(d => d.deviceCode === deviceCode)
       if (device) {
@@ -452,6 +615,30 @@ export default {
       this.emitChange()
     },
 
+    // ========== 子系统选择相关 ==========
+    handleSubsystemChange(systemCode) {
+      const subsystem = this.subsystemList.find(s => s.systemCode === systemCode)
+      this.selectedSubsystem = subsystem
+
+      if (subsystem) {
+        this.form.targetModelCode = subsystem.modelCode || ''
+        this.form.targetObjType = 1 // 子系统类型
+
+        if (this.form.targetModelCode) {
+          this.loadAbilities(this.form.targetModelCode)
+        } else {
+          this.$message.warning('该子系统未配置物模型,无法获取能力列表')
+          this.abilityList = []
+        }
+      }
+
+      this.form.abilityKey = ''
+      this.form.abilityParam = ''
+      this.currentAbility = null
+      this.emitChange()
+    },
+
+    // ========== 能力加载 ==========
     async loadAbilities(modelCode) {
       if (!modelCode) return
       this.loadingAbility = true
@@ -463,6 +650,7 @@ export default {
         }
       } catch (error) {
         console.error('加载能力失败:', error)
+        this.abilityList = []
       } finally {
         this.loadingAbility = false
       }
@@ -479,13 +667,14 @@ export default {
       this.emitChange()
     },
 
-    // ========== 属性查询相关 ==========
+    // ========== 属性查询相关(设备) ==========
     async handleQueryDeviceChange(deviceCode) {
       const device = this.deviceList.find(d => d.deviceCode === deviceCode)
       if (!device) return
 
       const modelCode = device.deviceModel || device.modelCode
       this.form.targetModelCode = modelCode || ''
+      this.form.targetObjType = 2
       this.form.abilityKey = ''
       this.queryAttrList = []
       this.lastQueryModelCode = ''
@@ -498,6 +687,28 @@ export default {
       this.emitChange()
     },
 
+    // ========== 属性查询相关(子系统) ==========
+    async handleQuerySubsystemChange(systemCode) {
+      const subsystem = this.subsystemList.find(s => s.systemCode === systemCode)
+      this.selectedSubsystem = subsystem
+
+      if (!subsystem) return
+
+      const modelCode = subsystem.modelCode || ''
+      this.form.targetModelCode = modelCode
+      this.form.targetObjType = 1
+      this.form.abilityKey = ''
+      this.queryAttrList = []
+      this.lastQueryModelCode = ''
+
+      if (modelCode) {
+        await this.loadQueryAttrList(modelCode)
+      } else {
+        this.$message.warning('该子系统未配置物模型')
+      }
+      this.emitChange()
+    },
+
     async loadQueryAttrList(modelCode) {
       if (!modelCode || modelCode === this.lastQueryModelCode) return
       if (this.loadingQueryAttr) return
@@ -526,7 +737,34 @@ export default {
       this.emitChange()
     },
 
-    // ========== 循环跳出条件相关 ==========
+    // ========== 循环跳出条件 ==========
+    parseLoopCondition(loopCondition) {
+      try {
+        const condition = JSON.parse(loopCondition)
+        if (condition.breakType === 'ATTR' && condition.deviceCode) {
+          this.loopBreakType = 'ATTR'
+          this.breakConfig = {
+            deviceCode: condition.deviceCode,
+            modelCode: condition.modelCode || '',
+            attrKey: condition.attrKey || '',
+            operator: condition.operator || '==',
+            value: condition.value || ''
+          }
+          if (condition.deviceCode) {
+            const device = this.deviceList.find(d => d.deviceCode === condition.deviceCode)
+            if (device) {
+              const modelCode = device.deviceModel || device.modelCode
+              if (modelCode) this.loadBreakAttrList(modelCode)
+            }
+          }
+        } else {
+          this.loopBreakType = 'EXPR'
+        }
+      } catch {
+        this.loopBreakType = 'EXPR'
+      }
+    },
+
     switchBreakType(type) {
       this.loopBreakType = type
       if (type === 'ATTR') {
@@ -688,6 +926,33 @@ export default {
     margin: 16px 0 12px;
   }
 
+  // 目标信息卡片
+  .target-info-card,
+  .ability-info-card {
+    background: #f5f7fa;
+    border-radius: 6px;
+    padding: 12px;
+    border-left: 3px solid #409eff;
+
+    .info-row {
+      display: flex;
+      align-items: center;
+      margin-bottom: 8px;
+      &:last-child { margin-bottom: 0; }
+
+      .info-label {
+        color: #909399;
+        font-size: 12px;
+        width: 70px;
+        flex-shrink: 0;
+      }
+    }
+  }
+
+  .ability-info-card {
+    border-left-color: #67c23a;
+  }
+
   .attr-info-card {
     background: #f5f7fa;
     border-radius: 6px;
@@ -747,5 +1012,18 @@ export default {
     display: flex;
     gap: 8px;
   }
+
+  // 单选按钮组样式优化
+  :deep(.el-radio-group) {
+    .el-radio-button__inner {
+      display: flex;
+      align-items: center;
+      gap: 4px;
+
+      i {
+        font-size: 14px;
+      }
+    }
+  }
 }
 </style>

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů