he wei
16 小时以前 7102b09561443f8c66bdcbecafac1706afc113fd
U 修改
3个文件已添加
11个文件已修改
759 ■■■■ 已修改文件
package-lock.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/statistic.js 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/401_images/401.gif 补丁 | 查看 | 原始文档 | blame | 历史
src/components/table-column-config.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useColumnConfig.js 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/modules/statistics.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/alarm/earlyWarningAnalysis.vue 145 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/datas/addEdit.vue 265 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/datas/device.vue 148 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.vue 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/realtime/tabs/system.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -10,6 +10,7 @@
      "dependencies": {
        "@element-plus/icons-vue": "^2.3.1",
        "axios": "^1.7.2",
        "dayjs": "^1.11.13",
        "echarts": "^5.5.0",
        "echarts-gl": "^2.0.9",
        "echarts-liquidfill": "^3.1.0",
@@ -30,7 +31,7 @@
        "xlsx": "^0.18.5"
      },
      "devDependencies": {
        "@rollup/plugin-commonjs": "^28.0.3",
        "@rollup/plugin-commonjs": "^28.0.6",
        "@vitejs/plugin-vue": "^5.2.3",
        "less": "^4.2.2",
        "postcss-pxtorem": "^6.1.0",
@@ -983,9 +984,9 @@
      }
    },
    "node_modules/@rollup/plugin-commonjs": {
      "version": "28.0.3",
      "resolved": "https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.3.tgz",
      "integrity": "sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==",
      "version": "28.0.6",
      "resolved": "https://registry.npmmirror.com/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz",
      "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==",
      "dev": true,
      "license": "MIT",
      "dependencies": {
package.json
@@ -11,6 +11,7 @@
  "dependencies": {
    "@element-plus/icons-vue": "^2.3.1",
    "axios": "^1.7.2",
    "dayjs": "^1.11.13",
    "echarts": "^5.5.0",
    "echarts-gl": "^2.0.9",
    "echarts-liquidfill": "^3.1.0",
@@ -31,7 +32,7 @@
    "xlsx": "^0.18.5"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^28.0.3",
    "@rollup/plugin-commonjs": "^28.0.6",
    "@vitejs/plugin-vue": "^5.2.3",
    "less": "^4.2.2",
    "postcss-pxtorem": "^6.1.0",
src/api/statistic.js
@@ -80,13 +80,13 @@
/**
 * 蓄电池组对比分析界面(同一品牌同一时间)(1.2.15)
 */
export function getBattCompare15(data) {
  return request({
    url: "statistic/getBattCompare15Statistic",
    method: "POST",
    data
  });
}
// export function getBattCompare15(data) {
//   return request({
//     url: "statistic/getBattCompare15Statistic",
//     method: "POST",
//     data
//   });
// }
/**
 * 蓄电池组对比分析界面(不同品牌同一时间)(1.2.16)
@@ -191,3 +191,14 @@
    data
  });
}
/**
 * 蓄电池组对比分析界面(同一时间同一品牌/同一时间不同一品牌/不同一时间同一品牌)(2.5.1/2/3)
 */
export function getBattCompare15Statistic(data) {
  return request({
    url: 'compare/getBattCompare15Statistic',
    method: 'POST',
    data
  });
}
src/assets/401_images/401.gif
src/components/table-column-config.vue
New file
@@ -0,0 +1,71 @@
<script setup name="colunmConfig">
import { ref, reactive, computed, watch, onMounted } from 'vue';
import useElement from "@/hooks/useElement.js";
    const { $loading, $message, $confirm } = useElement();
  import useColumnConfig from '@/hooks/useColumnConfig.js';
const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  columns: {
    type: Array,
    default: () => ([])
  },
  pageName: {
    type: String,
  }
});
const {
 getConfig,
    columnCfgVisible,
    isColumnFixed,
    fixedColumns,
  showConfigDialog,
    setConfig, } = useColumnConfig(props.pageName);
// 限制最多可固定的列数
const limit = 5;
const emit = defineEmits(['update:visible', 'change']);
const close = () => {
  emit('update:visible', false);
}
function save() {
  setConfig();
  close();
  emit('change');
}
onMounted(() => {
});
</script>
<template>
  <div class="colunm-config">
    <!-- 把所有的列都显示出来 勾选 -->
    <el-checkbox-group v-model="fixedColumns" :max="limit">
      <el-checkbox v-for="(item, idx) in columns" :key="idx" :checked="isColumnFixed(item.prop)" :value="item.prop">{{
        item.label
      }}</el-checkbox>
    </el-checkbox-group>
    <div class="footer">
      <el-button  @click="close">关闭</el-button>
      <el-button type="primary" @click="save">保存</el-button>
    </div>
  </div>
</template>
<style scoped lang="less">
</style>
src/hooks/useColumnConfig.js
New file
@@ -0,0 +1,60 @@
import {
  ref,
  reactive,
  onMounted,
  onUnmounted,
  onActivated,
  onDeactivated,
} from "vue";
export default function (pageName) {
  const configObj = ref({});
  const columnCfgVisible = ref(false);
  // 固定列状态
  const fixedColumns = ref([]);
  // 判断列是否固定
  function isColumnFixed (prop) {
    return fixedColumns.value.includes(prop)
  }
  function setConfig() {
    configObj.value[pageName] = fixedColumns.value;
    localStorage.setItem('columnConfig', JSON.stringify(configObj.value));
  }
  // 读取配置
  function getConfig() {
    // 查询配置
    let cfg = localStorage.getItem('columnConfig');
    console.log('cfg', cfg, '=============');
    if (cfg) {
      cfg = JSON.parse(cfg);
    } else {
      cfg = {}
    };
    configObj.value = cfg;
    console.log('cfg', cfg, cfg[pageName], '=============');
    fixedColumns.value = cfg[pageName] || [];
  }
  function showConfigDialog() {
    columnCfgVisible.value = true;
  }
  onMounted(() => {
    // 查询配置
    getConfig();
  });
  return {
    columnCfgVisible,
    showConfigDialog,
    getConfig,
    isColumnFixed,
    fixedColumns,
    setConfig,
  };
}
src/router/modules/statistics.js
@@ -57,7 +57,7 @@
      path: 'batt-compare0',
      component: () => import('@/views/statistics/battCompare0.vue'),
      name: 'battCompare0',
      meta: { title: '蓄电池组对比分析1', icon: 'component', noCache: false, hidden: true }
      meta: { title: '蓄电池组对比分析1', icon: 'component', noCache: false, }
    },
    {
      path: 'batt-compare1',
src/utils/request.js
@@ -2,6 +2,7 @@
// 生产环境和开发环境切换请求地址
let baseURL = 'http://localhost:8108/pis/';
// let baseURL = 'http://192.168.1.100:8108/pis/';
if (process.env.NODE_ENV === 'production') {
  baseURL = location.protocol + '//' + location.host + '/pis/';
}
src/views/alarm/earlyWarningAnalysis.vue
@@ -336,12 +336,12 @@
const chartRefs = ref({});
function setComponentRef (prop, el) {
function setComponentRef (idx, el) {
  if (el) {
    chartRefs.value[prop] = el;
    chartRefs.value[idx] = el;
  } else {
    // 组件卸载时移除引用
    delete chartRefs.value[prop];
    delete chartRefs.value[idx];
  }
};
@@ -476,12 +476,47 @@
  // xlabels.value = recordTimes;
}
function formatData2(data2, data3) {
  let { batt, pwr } = data2;
  let subs = [];
  if (batt && batt.length && data3.batt > 0) {
    for(let i = 1, len = data3.batt; i <= len; i++) {
      let prop = batt[0][`dataName${i}`];
      subs.push({prop, name: getPropName(prop), data: [], xLabels: [], valueProp: `dataValue${i}`, from: 'batt'});
    }
  }
  if (pwr && pwr.length && data3.pwr > 0) {
    for(let i = 1, len = data3.pwr; i <= len; i++) {
      let prop = pwr[0][`dataName${i}`];
      subs.push({prop, name: getPropName(prop), data: [], xLabels: [], valueProp: `dataValue${i}`, from: 'batt'});
    }
  }
  subProp.value = subs;
  let len = batt && batt.length ? batt.length : pwr && pwr.length ? pwr.length : 0;
  for (let i = 0; i < len; i++) {
    for (let j = 0, len = subs.length; j < len; j++) {
      let sub = subs[j];
      // 取属性对应的index
      let { prop, from, valueProp } = sub;
      sub.data.push(data2[from][i][valueProp]);
      sub.xLabels.push(data2[from][i].recordTime);
    }
  }
}
function updateChart() {
  console.log('xlabels.value, mainData.value', mainData.value, '=============');
  chart0.value.updateChart(mainData.value.labels, mainData.value.data, findClosestTime(mainData.value.labels, startTime.value));
  subProp.value.forEach((v, i) => {
    chartRefs.value[v.prop].updateChart(v.xLabels, v.data, findClosestTime(v.xLabels, startTime.value));
    chartRefs.value[i].updateChart(v.xLabels, v.data, findClosestTime(v.xLabels, startTime.value));
    nextTick(() => {
      chartRefs.value[i].getChart().resize();
    });
  });
}
@@ -643,6 +678,8 @@
  if (code && data) {
    $message.success("设置成功");
    timeLong.value = form1.time;
    // 重新查询数据
    getRtData();
    timeVisible.value = false;
  } else {
    $message.error("设置失败");
@@ -688,13 +725,6 @@
        prop: data[prop],
        type: data[type],
      });
      // arr.push({
      //   pid: data[type] + '',
      //   id: data[prop],
      //   label: getPropName(data[prop]),
      //   prop: data[prop],
      //   type: data[type],
      // });
    }
  });
@@ -710,36 +740,30 @@
  transferRef.value.removeToSource(false);
  transferRef.value.addToAims(false);
  toData.value = arr;
  // 左侧数据要去掉已经选中的数据
  fromData.value = fromData.value.map(v => {
    return {
      ...v,
      children: v.children.filter(vv => {
        if (!obj[v.id]) return true;
        return !obj[v.id].some(vvv => vvv.id == vv.id)
      })
    }
  }).filter(v => v.children.length);
}
function propSetOk() {
}
async function add (_fromData,_toData,{ checkedKeys, checkedNodes, harfKeys, harfNodes }) {
  console.log('fromData,toData,obj', _fromData,_toData, checkedKeys, checkedNodes, harfKeys, harfNodes , '=============');
async function propSetOk() {
  let params = {
    battgroupId: battId.value,
    powerId: currAlm.value.powerId,
    startTime: currAlm.value.almStartTime,
  }
  let arr = [];
  _toData.forEach((v) => {
    arr.push(...v.children);
  });
  let len = arr.length;
  if (len > 4) {
    $message.error('最多设置4个属性');
    console.log('toData', _toData, toData, '=============');
    toData.value = toData.value.map(v => ({
      ...v,
      children: v.children.filter(vv => !checkedKeys.includes(vv.id))
    }));
  let i = 0;
  if (!toData.value.length) {
    $message.error('请选择属性');
    return false;
  }
  let i = 0;
  _toData.forEach((item) => {
  toData.value.forEach((item) => {
    item.children.forEach((v) => {
      i++;
      params[`dataName${i}`] = v.id;
@@ -749,9 +773,60 @@
  });
  console.log('params', params, '=============');
  let loading = $loading();
  let res = await getHisRealWithChage(params);
  let { code, data, data2, data3, data4 } = res;
  loading.close();
  propInfo.value = data4;
  if (code && data) {
    formatData2(data2, data3);
    nextTick(() => {
      updateChart();
    });
    propVisible.value = false;
  } else {
    $message.error('查询出错');
  }
}
function add (_fromData,_toData,{ checkedKeys, checkedNodes, harfKeys, harfNodes }) {
  console.log('fromData,toData,obj', _fromData,_toData, checkedKeys, checkedNodes, harfKeys, harfNodes , '=============');
  let arr = [];
  _toData.forEach((v) => {
    arr.push(...v.children);
  });
  let len = arr.length;
  if (len > 4) {
    $message.error('最多设置4个属性');
    console.log('toData', _toData, toData, '=============');
    // 把这次选择的数据从右侧列表去掉
    toData.value = toData.value.map(v => ({
      ...v,
      children: v.children.filter(vv => !checkedKeys.includes(vv.id))
    })).filter(v => v.children.length);
    // 把这次操作的节点添加回左侧列表
    checkedNodes.forEach(v => {
      // 排除非叶子节点
      if (v.pid == 0) return;
      // 说明左侧列表还有这个节点的父节点
      if (_fromData.some(vv => vv.id == v.pid)) {
        _fromData.find(vv => vv.id == v.pid).children.push(v);
        // 左侧无此节点的父节点
      } else {
        _fromData.push({
          id: v.pid,
          pid: 0,
          label: v.fieldTypeName,
          children: [v],
        });
      }
    });
    fromData.value = _fromData;
    return false;
  }
}
function remove(fromData,toData,obj) {
@@ -1551,7 +1626,7 @@
            >
          </div>
          <div class="item">
            <el-button type="primary" size="small" @click="setProp"
            <el-button type="primary" size="small" :disabled="!currAlm.almId" @click="setProp"
              >关注属性</el-button
            >
          </div>
@@ -1563,7 +1638,7 @@
          <template v-for="(sub, idx) in subProp" :key="'sub_' + idx">
            <card :title="sub.name">
              <line-chart
                :ref="(el) => setComponentRef(sub.prop, el)"
                :ref="(el) => setComponentRef(idx, el)"
              ></line-chart>
            </card>
          </template>
@@ -1623,7 +1698,7 @@
      </tree-transfer>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="propVisible = false">取 消</el-button>
          <el-button @click="propVisible = false">关闭</el-button>
          <el-button type="primary" @click="propSetOk">确 定</el-button>
        </span>
      </template>
src/views/datas/addEdit.vue
@@ -1,6 +1,7 @@
<script setup>
  import { ref, reactive, watchEffect, computed, onMounted } from "vue";
import { ElMessageBox } from 'element-plus'
  import useStation from "@/hooks/useStationList.js";
  const { provice, city, country, stationName,
    proviceList, cityList, countryList, stationList,
@@ -21,6 +22,8 @@
    addBatt,
    getMonCapByUid,
  } from "@/api/station";
import { checkSnId } from '@/api/user.js';
  import getBinaryDigits from '@/utils/getBinaryDigits.js';
@@ -69,7 +72,17 @@
    moncount: '',
    product: "",
    battModel: "",
    acvolHighLimit: '',
    acvolLowLimit: '',
    dcoutvolLowLimit: '',
    floatCurrLevel: '',
    maxDisCurr: '',
    signType: '',
    commPort: '',
    loadCurr: '',
    videoUrl: '',
    powerType: 1,
    updateReason: '',
    powerInuseTime: moment().format('YYYY-MM-DD'),
    inuseTime: moment().format('YYYY-MM-DD'),
  });
@@ -126,6 +139,69 @@
      },
    ],
    stationType: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    acvolHighLimit: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    acvolLowLimit: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    dcoutvolLowLimit: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    floatCurrLevel: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    maxDisCurr: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    commPort: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    loadCurr: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    videoUrl: [
        {
            required: true,
            message: "不能为空",
            trigger: ["blur", "change"],
        },
    ],
    updateReason: [
      {
        required: true,
        message: "不能为空",
@@ -203,6 +279,58 @@
      $message.error("表单验证失败");
      return false;
    }
    // 修改之前需要先验证用户密码
    let re = await ElMessageBox.prompt('请输入用户密码', '安全验证', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
    inputType: 'password',
    inputPlaceholder: '请输入密码',
        // 关键:关闭前的钩子
        beforeClose: async (action, instance, done) => {
            // 处理取消操作(直接关闭)
            if (action == 'cancel') {
                done();
                return false;
            }
            // 处理确认操作
            const value = instance.inputValue.trim();
            // 验证逻辑
            if (!value) {
                // 空值验证失败
                $message.error("密码不能为空");
                // 阻止窗口关闭(不调用done())
                return false;
            }
            let res = await checkSnId(value);
      let { code, data } = res;
            if (code && data) {
                // 验证失败
                $message.success("密码正确");
                done();
            } else {
        // 验证失败
        $message.error("密码错误");
        // 阻止窗口关闭(不调用done())
        return false;
      }
            // 验证通过,关闭窗口
            done();
        }
    }).then((res) => res)
        .catch((err) => {
            console.log(err);
            return false;
        });
    if (!re) {
        return false;
    }
    let params = {};
    for (let key in form1) {
@@ -512,7 +640,7 @@
<template>
  <div class="">
    <el-form ref="formRef" :model="form1" label-width="8em" :rules="rules">
    <el-form ref="formRef" :model="form1" label-width="10em" :rules="rules">
      <el-row :gutter="layout.gutter">
        <el-col :span="layout.span">
          <el-form-item label="省" prop="provice">
@@ -621,25 +749,25 @@
              placeholder="请选择"
              style="width: 180px"
            >
              <el-option
                label="非节点站"
                :value="0"
              />
              <el-option
                label="节点站"
                :value="1"
              />
              <el-option label="非节点站" :value="0" />
              <el-option label="节点站" :value="1" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="layout.span">
          <el-form-item label="经度" prop="longitude">
            <el-input v-model="form1.longitude" :disabled="info.addBattFlag"></el-input>
            <el-input
              v-model="form1.longitude"
              :disabled="info.addBattFlag"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="layout.span">
          <el-form-item label="纬度" prop="latitude">
            <el-input v-model="form1.latitude" :disabled="info.addBattFlag"></el-input>
            <el-input
              v-model="form1.latitude"
              :disabled="info.addBattFlag"
            ></el-input>
          </el-form-item>
        </el-col>
      </el-row>
@@ -724,7 +852,10 @@
      <el-row :gutter="layout.gutter">
        <el-col :span="layout.span">
          <el-form-item label="电源IP" prop="powerIp">
            <el-input v-model="form1.powerIp" :disabled="info.addBattFlag"></el-input>
            <el-input
              v-model="form1.powerIp"
              :disabled="info.addBattFlag"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="layout.span * 2">
@@ -766,6 +897,32 @@
        </el-col>
      </el-row>
      <el-row :gutter="layout.gutter">
        <el-col :span="layout.span">
          <el-form-item label="交流上限阈值" prop="acvolHighLimit">
            <el-input
              v-model="form1.acvolHighLimit"
              :disabled="info.addBattFlag"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="layout.span">
          <el-form-item label="交流下限阈值" prop="acvolLowLimit">
            <el-input
              v-model="form1.acvolLowLimit"
              :disabled="info.addBattFlag"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :span="layout.span">
          <el-form-item label="直流输出电压下限" prop="dcoutvolLowLimit">
            <el-input
              v-model="form1.dcvolLowLimit"
              :disabled="info.addBattFlag"
            ></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row :gutter="layout.gutter">
        <el-col :span="layout.span" v-if="!info.addBattFlag">
          <el-form-item label="有无电池组">
            <el-select
@@ -776,14 +933,8 @@
              placeholder="请选择"
              style="width: 180px"
            >
              <el-option
                label="有电池组"
                :value="1"
              />
              <el-option
                label="无电池组"
                :value="0"
              />
              <el-option label="有电池组" :value="1" />
              <el-option label="无电池组" :value="0" />
            </el-select>
          </el-form-item>
        </el-col>
@@ -798,14 +949,8 @@
              @change="devChange"
              style="width: 180px"
            >
              <el-option
                label="创建新设备"
                :value="1"
              />
              <el-option
                label="当前设备"
                :value="0"
              />
              <el-option label="创建新设备" :value="1" />
              <el-option label="当前设备" :value="0" />
            </el-select>
          </el-form-item>
        </el-col>
@@ -831,7 +976,10 @@
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="设备IP" prop="devIp">
              <el-input v-model="form1.devIp" :disabled="info.addBattFlag && !addDevFlag"></el-input>
              <el-input
                v-model="form1.devIp"
                :disabled="info.addBattFlag && !addDevFlag"
              ></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
@@ -885,6 +1033,47 @@
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="浮充电流阈值" prop="floatCurrLevel">
              <el-input v-model="form1.floatCurrLevel"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="最大核容电流" prop="maxDisCurr">
              <el-input v-model="form1.maxDisCurr"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="验签格式" prop="signType">
              <el-select
                v-model="form1.signType"
                filterable
                allow-create
                placeholder="请选择"
                style="width: 180px"
              >
                <el-option label="常规" :value="0" />
                <el-option label="正常1拖2" :value="1" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="通信端口号" prop="commPort">
              <el-input v-model="form1.commPort"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="负载电流" prop="loadCurr">
              <el-input v-model="form1.loadCurr"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="layout.gutter">
          <el-col :span="layout.span">
            <el-form-item label="视频监控序列号" prop="videoUrl">
              <el-input v-model="form1.videoUrl"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="layout.span">
            <el-form-item label="电池品牌" prop="product">
              <el-select
                v-model="form1.product"
@@ -902,8 +1091,6 @@
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="layout.gutter">
          <el-col :span="layout.span">
            <el-form-item label="电池型号" prop="battModel">
              <el-input v-model="form1.battModel"></el-input>
@@ -925,9 +1112,20 @@
          </el-col>
        </el-row>
      </template>
      <el-row :gutter="layout.gutter" v-if="isEdit && !info.addBattFlag">
        <el-col :span="layout.span * 3">
          <el-form-item label="修改说明" prop="updateReason">
            <el-input type="textarea" :rows="2" v-model="form1.updateReason" />
          </el-form-item>
        </el-col>
      </el-row>
      <div class="form-footer">
        <el-button v-if="info.addBattFlag" type="primary" @click="addBattFn">添加电池组</el-button>
        <el-button v-else-if="isEdit" type="primary" @click="update">修改</el-button>
        <el-button v-if="info.addBattFlag" type="primary" @click="addBattFn"
          >添加电池组</el-button
        >
        <el-button v-else-if="isEdit" type="primary" @click="update"
          >修改</el-button
        >
        <el-button v-else type="primary" @click="onSubmit">新增</el-button>
        <el-button @click="close">取消</el-button>
      </div>
@@ -939,6 +1137,7 @@
:deep(.select) {
  width: 100%;
}
.form-footer {
  padding: 10px;
  text-align: right;
src/views/datas/device.vue
@@ -13,6 +13,18 @@
    proviceList, cityList, countryList, stationList,
  } = useStation();
import useColumnConfig from '@/hooks/useColumnConfig.js';
import tableColumnConfig from '@/components/table-column-config.vue';
const pageName = 'datas_device';
const { getConfig,
    columnCfgVisible,
    isColumnFixed,
    fixedColumns,
  showConfigDialog,
    setConfig, } = useColumnConfig(pageName);
  import powerTypes from '@/utils/const/const_powerType.js';
  import {
    delBatt,
@@ -322,6 +334,7 @@
    onMounted(() => {
  // console.log('fixedColumns', fixedColumns, '=============');
    getCompanyList();
    getVolLevels();
        getList();
@@ -468,20 +481,59 @@
          <div class="page-content-table">
            <div class="pos-rel">
              <div class="pos-abs">
                <el-table class="yc-table" stripe height="100%" size="small" :data="datas.tableData" style="width: 100%">
                  <el-table-column type="index" fixed="left" label="序号" width="60"></el-table-column>
                  <el-table-column v-for="header in headers" :key="header.prop" :prop="header.prop" :label="header.label"
                    :min-width="header.width" align="center">
                    <template #default="scope">{{ scope.row[header.prop] || '--' }}</template>
                <el-table
                  class="yc-table"
                  stripe
                  height="100%"
                  size="small"
                  :data="datas.tableData"
                  style="width: 100%"
                >
                  <el-table-column
                    type="index"
                    fixed="left"
                    label="序号"
                    width="60"
                  ></el-table-column>
                  <el-table-column
                    v-for="header in headers"
                    :key="header.prop"
                    :prop="header.prop"
                    :label="header.label"
                    :fixed="isColumnFixed(header.prop) ? 'left' : false"
                    :min-width="header.width"
                    align="center"
                  >
                    <template
                      #default="scope"
                      >{{ scope.row[header.prop] || '--' }}</template
                    >
                  </el-table-column>
                  <el-table-column label="操作" fixed="right" width="240" align="center">
                  <el-table-column
                    label="操作"
                    fixed="right"
                    width="240"
                    align="center"
                  >
                    <template #default="scope">
                      <el-button type="primary" size="small"
                        @click="edit(scope.row)">编辑</el-button>
                      <el-button type="danger" size="small"
                        @click="confirmRemove(scope.row)">删除</el-button>
                      <el-button type="primary" size="small"
                        @click="addBatt(scope.row)">添加电池组</el-button>
                      <el-button
                        type="primary"
                        size="small"
                        @click="edit(scope.row)"
                        >编辑</el-button
                      >
                      <el-button
                        type="danger"
                        size="small"
                        @click="confirmRemove(scope.row)"
                        >删除</el-button
                      >
                      <el-button
                        type="primary"
                        size="small"
                        @click="addBatt(scope.row)"
                        >添加电池组</el-button
                      >
                    </template>
                  </el-table-column>
                </el-table>
@@ -490,25 +542,77 @@
          </div>
          <div class="page-content-page">
            <div class="page-tool">
              <el-button type="primary" round size="small" @click="add" :icon="Plus">添加</el-button>
              <el-button type="primary" round size="small" @click="getList" :icon="Search">查询</el-button>
              <el-button
                type="primary"
                round
                size="small"
                @click="add"
                :icon="Plus"
                >添加</el-button
              >
              <el-button
                type="primary"
                round
                size="small"
                @click="getList"
                :icon="Search"
                >查询</el-button
              >
            </div>
            <div class="el-page-container">
              <el-pagination v-model:current-page="pageCurr" v-model:page-size="pageSize"
                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]" size="small" :disabled="disabled"
                :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total"
                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
              <el-pagination
                v-model:current-page="pageCurr"
                v-model:page-size="pageSize"
                :page-sizes="[20, 40, 60, 80, 100, 200, 300, 400]"
                size="small"
                :disabled="disabled"
                :background="background"
                layout="total, sizes, prev, pager, next, jumper"
                :total="total"
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
              />
            </div>
            <div class="page-tool"></div>
            <div class="page-tool">
              <el-button type="primary" round size="small" @click="showConfigDialog"
                >配置固定列</el-button
              >
            </div>
          </div>
        </div>
      </yc-card>
    </div>
    <div class="page-footer"></div>
    <!-- 设置固定列 -->
    <el-dialog
      title="设置固定列"
      v-model="columnCfgVisible"
      top="0"
      draggable
      :close-on-click-modal="false"
      class="dialog-center"
      width="480px"
      center
    >
      <table-column-config v-model:visible="columnCfgVisible" :columns="headers" :pageName="pageName" @change="getConfig"></table-column-config>
    </el-dialog>
    <!-- 弹窗 -->
    <el-dialog :title="dialogTitle" v-model="addEditVisible" top="0" :close-on-click-modal="false" class="dialog-center"
      width="1000px" center>
      <add-edit v-if="addEditVisible" @success="onOk" :info="datas.rowData" @cancel="onCanel"></add-edit>
    <el-dialog
      :title="dialogTitle"
      v-model="addEditVisible"
      top="0"
      draggable
      :close-on-click-modal="false"
      class="dialog-center"
      width="1200px"
      center
    >
      <add-edit
        v-if="addEditVisible"
        @success="onOk"
        :info="datas.rowData"
        @cancel="onCanel"
      ></add-edit>
    </el-dialog>
  </div>
</template>
src/views/login/index.vue
@@ -3,7 +3,6 @@
    <div class="site-title">
      <div class="logo"><img :src="logUrl" alt=""></div>{{ platformName }}
    </div>
    <div class="img-hm"></div>
    <div class="login-wrap">
      <el-form
        ref="loginFormRef"
@@ -461,15 +460,15 @@
    }
  }
  .img-hm {
    position: absolute;
    width: clamp(500px, 50vw, 800px);
    height: clamp(300px, 80vh, 80vh);
    background: url(@/assets/images/img-hm.png) center center / contain no-repeat;
    left: 0;
    top: 20%;
    transform: translate(clamp(0px, calc(24vw - 50%), 50vw), 0);
  }
  // .img-hm {
  //   position: absolute;
  //   width: clamp(500px, 50vw, 800px);
  //   height: clamp(300px, 80vh, 80vh);
  //   background: url(@/assets/images/img-hm.png) center center / contain no-repeat;
  //   left: 0;
  //   top: 20%;
  //   transform: translate(clamp(0px, calc(24vw - 50%), 50vw), 0);
  // }
  .svg-container {
    padding: 6px 5px 6px 15px;
src/views/realtime/tabs/system.vue
@@ -1007,7 +1007,7 @@
    }
  }
  .svg-diagram {}
  // .svg-diagram {}
  .btn-setting {
    display: inline-block;
vite.config.js
@@ -14,6 +14,9 @@
  const env = loadEnv(mode, process.cwd(), '');
  return {
    plugins: [
      commonjs({
        include: ['node_modules/**'],
      }),
      vue(),
      Inspect(),
      VueSetupExtend(),
@@ -25,9 +28,6 @@
          return 'icon-' + filename.substring(0, filename.lastIndexOf('.'));
        }
      }),
      commonjs({
        include: ['node_modules/**'],
      }),
    ],
    base: './',
    define: {
@@ -35,7 +35,8 @@
    },
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url))
        '@': fileURLToPath(new URL('./src', import.meta.url)),
        'dayjs': 'dayjs/esm'
      },
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
    },