houzhongjian
2024-10-31 e64ac35f0be48b2c4f88861f5da1eae314ac158e
Merge remote-tracking branch 'origin/master'
已修改5个文件
已添加3个文件
498 ■■■■■ 文件已修改
.env 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/da/point/daPointChart.ts 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/data/da/point/index.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dict.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/point/DaPointChart.vue 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/point/DaPointForm.vue 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/point/PointImportForm.vue 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/data/point/index.vue 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env
@@ -2,7 +2,7 @@
VITE_APP_TITLE=工业互联网平台
# 项目本地运行端口号
VITE_PORT=80
VITE_PORT=3000
# open 运行 npm run dev 时自动打开浏览器
VITE_OPEN=true
src/api/data/da/point/daPointChart.ts
对比新文件
@@ -0,0 +1,17 @@
import request from '@/config/axios'
export interface DaPointChartReqVO {
  pointNos?: [],
  start?: Date,
  end?: Date,
}
// 查询chart列表
export const getPointDaChart = (data: DaPointChartReqVO) => {
  return request.post({ url: '/data/api/query-points/chart', data })
}
//导出DaPointValue
export const exportDaPointValue = (params) => {
  return request.download({ url: '/data/da/point/exportValue', params })
}
src/api/data/da/point/index.ts
@@ -52,3 +52,13 @@
export const deleteDaPoint = (id: number) => {
  return request.delete({ url: '/data/da/point/delete?id=' + id })
}
//导出DaPointList
export const exportDaPoint = (params) => {
  return request.download({ url: '/data/da/point/export', params })
}
// 下载用户导入模板
export const importPointTemplate = () => {
  return request.download({ url: '/data/da/point/get-import-template' })
}
src/utils/dict.ts
@@ -179,7 +179,7 @@
  COM_IS_INT = 'com_is_int',
  DATA_POINT_TYPE = 'data_point_type',
  MINFREQID = 'minfreqid',
  VALUETYPE = 'value_type',
  MEASURE_VALUE_TYPE = 'measure_value_type',
  NVR_ONLINE_STATUS = 'nvr_online_status',
  CAMERA_BRAND = 'camera_brand',
  CAPTURE_TYPE = 'capture_type',
src/views/data/point/DaPointChart.vue
对比新文件
@@ -0,0 +1,223 @@
<template>
  <el-dialog
    title="采集值"
    :close-on-click-modal="false"
    width="50%"
    v-model="visible"
  >
    <el-form
      :inline="true"
      :model="dataForm"
      @keydown.enter="getDataList()"
    >
      <el-form-item>
        <el-date-picker
          v-model="dataForm.startTime"
          type="datetime"
          value-format="yyyy-MM-dd HH:mm:ss"
          placeholder="选择日期时间"
       />
      </el-form-item>
      <el-form-item>
        <el-date-picker
          v-model="dataForm.endTime"
          type="datetime"
          value-format="yyyy-MM-dd HH:mm:ss"
          placeholder="选择日期时间"
        />
      </el-form-item>
      <el-form-item>
        <el-button @click="getDataList()">查询</el-button>
      </el-form-item>
      <el-form-item>
        <el-button
          type="success"
          plain
          @click="handleExport"
          :loading="exportLoading"
          v-hasPermi="['data:point:export']"
        >
          <Icon icon="ep:download" />导出
        </el-button>
      </el-form-item>
    </el-form>
    <div ref="chartDom" class="result-chart"></div>
  </el-dialog>
</template>
<script lang="ts" setup>
  import {ref} from 'vue';
  import * as echarts from 'echarts';
  import * as DaPoint from '@/api/data/da/point/daPointChart'
  import download from "@/utils/download";
  const message = useMessage() // 消息弹窗
  const visible = ref(false);
  const chartDom = ref(null);
  let myChart = null;
  const dataForm = ref({
    id: "",
    pointNo: "",
    pointName: "",
    pointTypeName: "",
    startTime: getYMDHMS(),
    endTime: undefined,
  });
  const queryParams = reactive({
    codes: [],
    startDate: undefined,
    endDate: undefined,
  })
  function getYMDHMS() {
    let timestamp = new Date().getTime();
    let time = new Date(timestamp - 1000 * 60 * 30);
    let year = time.getFullYear();
    let month = (time.getMonth() + 1).toString();
    let date = time.getDate().toString();
    let hours = time.getHours().toString();
    let minute = time.getMinutes().toString();
    if (month < 10) {
      month = "0" + month;
    }
    if (date < 10) {
      date = "0" + date;
    }
    if (hours < 10) {
      hours = "0" + hours;
    }
    if (minute < 10) {
      minute = "0" + minute;
    }
    return (
      year +
      "-" +
      month +
      "-" +
      date +
      " " +
      hours +
      ":" +
      minute +
      ":" +
      "00"
    );
  }
  /** 打开弹窗 */
  const open = async (row: object) => {
    visible.value = true
    dataForm.value.id = row.id;
    dataForm.value.pointNo = row.pointNo;
    dataForm.value.pointName = row.pointName;
    dataForm.value.startTime = getYMDHMS();
    dataForm.value.endTime = "";
    getDataList();
  }
  defineExpose({open}) // 提供 open 方法,用于打开弹窗
  async function getDataList() {
    visible.value = true;
    if (dataForm.value.id) {
      try {
        queryParams.codes=[dataForm.value.pointNo];
        queryParams.startDate = dataForm.value.startTime;
        queryParams.endDate = dataForm.value.endTime;
        const data = await DaPoint.getPointDaChart(queryParams)
        let seriesData = []
        data.series.forEach(item => {
          seriesData.push({
            name: item.name,
            type: "line",
            data: item.data,
            showSymbol: true,
            smooth: false,
            lineStyle: {
              normal: {
                color: "#5B8FF9",
                width: 1,
              },
            },
          });
        })
        myChart = echarts.init(chartDom.value);
        const option = {
          title: {
            text: dataForm.value.pointName,
            top: 0,
            left: "1%",
            textStyle: {
              fontSize: 14,
            },
          },
          tooltip: {
            trigger: "axis",
            axisPointer: {
              type: "line",
              lineStyle: {
                color: "#cccccc",
                width: "1",
                type: "dashed",
              },
            },
          },
          legend: {
            show: false,
            top: 10,
          },
          grid: {
            top: 30,
            left: "3%",
            right: "5%",
            bottom: 10,
            containLabel: true,
          },
          xAxis: {
            type: "category",
            boundaryGap: false,
            data: data.categories,
          },
          yAxis: {
            type: "value",
          },
          dataZoom: [
            {
              type: "inside",
            },
          ],
          series: seriesData,
        };
        myChart.setOption(option);
      } catch (error) {
        console.error(error)
      }
    }
  }
  /** 导出按钮操作 */
  const exportLoading = ref(false)
  const handleExport = async () => {
    queryParams.pointNos=[dataForm.value.pointNo];
    queryParams.start = dataForm.value.startTime;
    queryParams.end = dataForm.value.endTime;
    try {
      // 导出的二次确认
      await message.exportConfirm()
      // 发起导出
      exportLoading.value = true
      const data = await DaPoint.exportDaPointValue(queryParams)
      download.excel(data, dataForm.value.pointName +'.xls')
    } catch {
    } finally {
      exportLoading.value = false
    }
  }
</script>
<style>
  .el-select {
    width: 100%;
  }
  .result-chart {
    height: 500px;
  }
</style>
src/views/data/point/DaPointForm.vue
@@ -1,5 +1,5 @@
<template>
  <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
  <Dialog v-model="dialogVisible" :title="dialogTitle" width="60%">
    <el-form
      ref="formRef"
      v-loading="formLoading"
@@ -137,14 +137,14 @@
      </el-row>
      <el-row v-if="formData.pointType === 'MEASURE'">
        <el-col :span="12">
          <el-form-item label="值类型" prop="valueType">
          <el-form-item label="测量值类型" prop="measurePoint.valueType">
            <el-select
              v-model="formData.measurePoint.valueType"
              clearable
              placeholder="请选择值类型"
            >
              <el-option
                v-for="dict in getDictOptions(DICT_TYPE.VALUETYPE)"
                v-for="dict in getDictOptions(DICT_TYPE.MEASURE_VALUE_TYPE)"
                :key="dict.value"
                :label="dict.label"
                :value="dict.value"
@@ -153,8 +153,10 @@
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="平滑尺度" prop="dimension">
            <el-input-number v-model="formData.measurePoint.dimension" style="width: 100%" :controls="false"/>
          <el-form-item label="平滑尺度(min)" prop="measurePoint.dimension">
            <el-input-number v-model="formData.measurePoint.dimension" style="width: 100%"
                             :min="0" :max="100"
                             :controls="false"/>
          </el-form-item>
        </el-col>
      </el-row>
@@ -166,11 +168,11 @@
              :data="expressionList"
              border
              style="width: 100%">
<!--              <el-table-column
              <el-table-column
                type="index"
                align="center"
                width="50"
                label="序号"/>-->
                width="60"
                label="序号"/>
              <el-table-column
                prop=""
                label="左括号"
@@ -194,6 +196,7 @@
              <el-table-column
                prop=""
                label="测点"
                min-width="160"
                align="center">
                <template #default="scope">
                  <el-select
@@ -211,6 +214,7 @@
              <el-table-column
                prop=""
                label="运算值"
                min-width="120"
                align="center">
                <template #default="scope">
                  <el-input
@@ -243,7 +247,7 @@
              <el-table-column
                prop=""
                label="运算符"
                width="120"
                width="100"
                align="center">
                <template #default="scope">
                  <el-select v-model="scope.row.operator" clearable>
@@ -258,19 +262,19 @@
              <el-table-column
                prop=""
                label="操作"
                width="140"
                width="120"
                align="center">
                <template #default="scope">
                  <el-button
                    @click="addExpressionRow(scope.$index, expressionList)"
                    type="text"
                    size="small">
                    size="mini">
                    添加
                  </el-button>
                  <el-button
                    @click="deleteExpressionRow(scope.$index, expressionList)"
                    type="text"
                    size="small">
                    size="mini">
                    删除
                  </el-button>
                </template>
@@ -345,6 +349,9 @@
  pointName: [{required: true, message: '测点名称不能为空', trigger: 'blur'}],
  pointType: [{required: true, message: '测点类型不能为空', trigger: 'blur'}],
  dataType: [{required: true, message: '数据类型不能为空', trigger: 'blur'}],
  minfreqid: [{required: true, message: '采集频率不能为空', trigger: 'blur'}],
  "measurePoint.valueType": [{required: true, message: '采集频率不能为空', trigger: 'blur'}],
  "measurePoint.dimension": [{required: true, message: '采集频率不能为空', trigger: 'blur'}],
})
const formRef = ref() // 表单 Ref
@@ -438,8 +445,8 @@
    storeType: undefined,
    unit: undefined,
    unittransfactor: 1,
    defaultValue: 10,
    maxValue: 10000000,
    defaultValue: 0,
    maxValue: 100000000,
    minValue: 0,
    minfreqid: undefined,
    remark: undefined,
src/views/data/point/PointImportForm.vue
对比新文件
@@ -0,0 +1,138 @@
<template>
  <Dialog v-model="dialogVisible" title="测点导入" width="400">
    <el-upload
      ref="uploadRef"
      v-model:file-list="fileList"
      :action="importUrl + '?updateSupport=' + updateSupport"
      :auto-upload="false"
      :disabled="formLoading"
      :headers="uploadHeaders"
      :limit="1"
      :on-error="submitFormError"
      :on-exceed="handleExceed"
      :on-success="submitFormSuccess"
      accept=".xlsx, .xls"
      drag
    >
      <Icon icon="ep:upload" />
      <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
      <template #tip>
        <div class="el-upload__tip text-center">
          <div class="el-upload__tip">
            <el-checkbox v-model="updateSupport" />
            是否更新已经存在的测点数据
          </div>
          <span>仅允许导入 xls、xlsx 格式文件。</span>
          <el-link
            :underline="false"
            style="font-size: 12px; vertical-align: baseline"
            type="primary"
            @click="importTemplate"
          >
            下载模板
          </el-link>
        </div>
      </template>
    </el-upload>
    <template #footer>
      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>
<script lang="ts" setup>
import * as DaPointApi from '@/api/data/da/point'
import { getAccessToken, getTenantId } from '@/utils/auth'
import download from '@/utils/download'
defineOptions({ name: 'PointImportForm' })
const message = useMessage() // 消息弹窗
const dialogVisible = ref(false) // 弹窗的是否展示
const formLoading = ref(false) // 表单的加载中
const uploadRef = ref()
const importUrl =
  import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/data/da/point/import'
const uploadHeaders = ref() // 上传 Header 头
const fileList = ref([]) // 文件列表
const updateSupport = ref(0) // 是否更新已经存在的测点数据
/** 打开弹窗 */
const open = () => {
  dialogVisible.value = true
  updateSupport.value = 0
  fileList.value = []
  resetForm()
}
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 提交表单 */
const submitForm = async () => {
  if (fileList.value.length == 0) {
    message.error('请上传文件')
    return
  }
  // 提交请求
  uploadHeaders.value = {
    Authorization: 'Bearer ' + getAccessToken(),
    'tenant-id': getTenantId()
  }
  formLoading.value = true
  uploadRef.value!.submit()
}
/** 文件上传成功 */
const emits = defineEmits(['success'])
const submitFormSuccess = (response: any) => {
  if (response.code !== 0) {
    message.error(response.msg)
    formLoading.value = false
    return
  }
  // 拼接提示语
  const data = response.data
  let text = '上传成功数量:' + data.createPointnames.length + ';'
  for (let pointname of data.createPointnames) {
    text += '< ' + pointname + ' >'
  }
  text += '更新成功数量:' + data.updatePointnames.length + ';'
  for (const pointname of data.updatePointnames) {
    text += '< ' + pointname + ' >'
  }
  text += '更新失败数量:' + Object.keys(data.failurePointnames).length + ';'
  for (const pointname in data.failurePointnames) {
    text += '< ' + pointname + ': ' + data.failurePointnames[pointname] + ' >'
  }
  message.alert(text)
  formLoading.value = false
  dialogVisible.value = false
  // 发送操作成功的事件
  emits('success')
}
/** 上传错误提示 */
const submitFormError = (): void => {
  message.error('上传失败,请您重新上传!')
  formLoading.value = false
}
/** 重置表单 */
const resetForm = async (): Promise<void> => {
  // 重置上传状态和文件
  formLoading.value = false
  await nextTick()
  uploadRef.value?.clearFiles()
}
/** 文件数超出提示 */
const handleExceed = (): void => {
  message.error('最多只能上传一个文件!')
}
/** 下载模板操作 */
const importTemplate = async () => {
  const res = await DaPointApi.importPointTemplate()
  download.excel(res, '测点导入模版.xls')
}
</script>
src/views/data/point/index.vue
@@ -53,6 +53,23 @@
          <Icon icon="ep:plus" class="mr-5px" />
          新增
        </el-button>
        <el-button
          type="warning"
          plain
          @click="handleImport"
          v-hasPermi="['data:point:import']"
        >
          <Icon icon="ep:upload" /> 导入
        </el-button>
        <el-button
          type="success"
          plain
          @click="handleExport"
          :loading="exportLoading"
          v-hasPermi="['data:point:export']"
        >
          <Icon icon="ep:download" />导出
        </el-button>
      </el-form-item>
    </el-form>
  </ContentWrap>
@@ -60,7 +77,7 @@
  <!-- 列表 -->
  <ContentWrap>
    <el-table border stripe v-loading="loading" :data="list">
      <el-table-column fixed label="测点编码" header-align="center" align="left" min-width="110" prop="pointNo" />
      <el-table-column fixed label="测点编码" header-align="center" align="left" min-width="120" prop="pointNo" />
      <el-table-column label="测点名称" header-align="center" align="left" min-width="200" prop="pointName" />
      <el-table-column label="测点类型" align="center" prop="pointType" width="100">
        <template #default="scope">
@@ -77,12 +94,12 @@
          <dict-tag :type="DICT_TYPE.VALUETYPE" :value="scope.row.valueType" />
        </template>
      </el-table-column>
      <el-table-column label="测量单位" align="center" prop="unit" width="100"/>
      <el-table-column label="测量单位" align="center" prop="unit" width="80"/>
      <el-table-column label="单位转换" align="center" prop="unittransfactor" />
      <el-table-column label="默认值" align="center" prop="defaultValue" />
      <el-table-column label="默认值" align="center" prop="defaultValue" width="100"/>
      <el-table-column label="采集频率" align="center" prop="minfreqid" width="100"/>
      <el-table-column label="数据源类型" align="center" prop="sourceType" width="100"/>
      <el-table-column label="数据源名称" align="center" prop="sourceName" width="100"/>
      <el-table-column label="数据源类型" align="center" prop="sourceType" min-width="100"/>
      <el-table-column label="数据源名称" align="center" prop="sourceName" min-width="100"/>
      <el-table-column label="测点Tag" header-align="center" align="left" prop="tagNo" min-width="150"/>
      <el-table-column label="是否启用" align="center" prop="isEnable" width="100">
        <template #default="scope">
@@ -91,18 +108,21 @@
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" min-width="110" fixed="right" width="120">
      <el-table-column label="操作" align="center" min-width="130" fixed="right" width="160">
        <template #default="scope">
          <el-button
            link
            size="mini"
            type="primary"
            @click="openForm('update', scope.row.id)"
            v-hasPermi="['data:point:update']"
          >
            编辑
          </el-button>
          <el-button link size="mini" type="primary" @click="chartHandle(scope.row)">数据</el-button>
          <el-button
            link
            size="mini"
            type="danger"
            @click="handleDelete(scope.row.id)"
            v-hasPermi="['data:point:delete']"
@@ -124,11 +144,19 @@
  <!-- 表单弹窗:添加/修改 -->
  <DaPointForm ref="formRef" @success="getList" />
  <DaPointChart ref="chartView" />
  <!-- 用户导入对话框 -->
  <PointImportForm ref="importFormRef" @success="getList" />
</template>
<script lang="ts" setup>
import DaPointForm from './DaPointForm.vue'
import * as DaPoint from '@/api/data/da/point'
import {DICT_TYPE} from "@/utils/dict";
import {ref} from "vue";
import download from "@/utils/download";
import {DICT_TYPE, getDictOptions} from "@/utils/dict";
import DaPointForm from './DaPointForm.vue'
import DaPointChart from './DaPointChart.vue'
import * as UserApi from "@/api/system/user";
defineOptions({name: 'DataPoint'})
@@ -146,7 +174,6 @@
    tagNo: undefined,
  })
  const queryFormRef = ref() // 搜索的表单
  const exportLoading = ref(false) // 导出的加载中
  /** 查询列表 */
  const getList = async () => {
@@ -164,6 +191,12 @@
  const handleQuery = () => {
    queryParams.pageNo = 1
    getList()
  }
  /** 查看数据操作 */
  const chartView  = ref()
  const chartHandle = (raw: object) => {
    chartView.value.open(raw)
  }
  /** 重置按钮操作 */
@@ -191,7 +224,27 @@
    } catch {
    }
  }
  /** 测点导入 */
  const importFormRef = ref()
  const handleImport = () => {
    importFormRef.value.open()
  }
  /** 导出按钮操作 */
  const exportLoading = ref(false)
  const handleExport = async () => {
    try {
      // 导出的二次确认
      await message.exportConfirm()
      // 发起导出
      exportLoading.value = true
      const data = await DaPoint.exportDaPoint(queryParams)
      download.excel(data, '测点列表.xlsx')
    } catch {
    } finally {
      exportLoading.value = false
    }
  }
  /** 初始化 **/
  onMounted(async () => {
    await getList()