From 328968f75a4dd4292ebc71f01d759a824765ac72 Mon Sep 17 00:00:00 2001 From: Jay <csj123456> Date: 星期五, 22 十一月 2024 10:00:42 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- src/views/data/video/nvr/index.vue | 187 +- src/api/data/plan/item/index.ts | 2 types/env.d.ts | 2 src/views/bpm/model/index.vue | 17 src/views/model/pre/item/MmPredictItemChart.vue | 253 ++++ src/views/model/wiki/index.vue | 4 .env.local | 5 .env.test | 6 src/api/data/video/image/index.ts | 50 src/api/model/pre/dm/index.ts | 2 src/views/data/wiki/index.vue | 4 src/views/model/mpk/file/MpkRun.vue | 3 src/api/model/mcs/index.ts | 30 src/views/data/video/camera/index.vue | 197 ++- src/views/data/channel/modbus/tag/index.vue | 19 src/views/data/channel/http/api/tag/index.vue | 20 src/router/modules/remaining.ts | 21 src/views/data/video/nvr/NvrCamera.vue | 174 +- src/views/model/pre/item/index.vue | 34 src/views/data/channel/opcua/tag/index.vue | 25 src/api/model/pre/item/index.ts | 145 ++ src/views/Home/Index.vue | 29 src/views/model/pre/type/ItemTypeForm.vue | 2 src/utils/is.ts | 3 src/views/model/pre/analysis/index.vue | 1100 ++++++++++--------- src/views/model/pre/item/MmPredictItemForm.vue | 243 ++- /dev/null | 149 -- src/api/model/pre/type/index.ts | 43 src/views/model/pre/type/index.vue | 2 src/views/Login/components/LoginForm.vue | 32 .env.dev | 10 src/utils/hostMap.ts | 2 src/utils/dict.ts | 3 src/views/model/mpk/file/MpkForm.vue | 4 src/api/model/sche/model/index.ts | 23 src/views/data/channel/opcda/tag/index.vue | 19 src/views/data/channel/kio/tag/index.vue | 19 src/views/data/video/camera/CameraImage.vue | 114 ++ src/views/data/point/DaPointChart.vue | 213 ++- src/views/model/mpk/icon/index.vue | 4 40 files changed, 1,944 insertions(+), 1,270 deletions(-) diff --git a/.env.dev b/.env.dev index 304200e..82ec13b 100644 --- a/.env.dev +++ b/.env.dev @@ -24,13 +24,19 @@ VITE_SOURCEMAP=true # 打包路径 -VITE_BASE_PATH=/ +VITE_BASE_PATH=/plat # 输出路径 VITE_OUT_DIR=dist + +# 公共静态文件路径 +VITE_STATIC_DIR=/ # 商城H5会员端域名iai VITE_MALL_H5_DOMAIN='http://' # 验证码的开关 -VITE_APP_CAPTCHA_ENABLE=true +VITE_APP_CAPTCHA_ENABLE=false + +# MDK模型上传路径 +MDK_UPLOAD_URL='http://localhost:48080/admin-api/model//pre/item/upload-model' diff --git a/.env.local b/.env.local index 005d2f0..b28e8e2 100644 --- a/.env.local +++ b/.env.local @@ -24,7 +24,10 @@ VITE_SOURCEMAP=false # 打包路径 -VITE_BASE_PATH=/ +VITE_BASE_PATH=/plat + +# 公共静态文件路径 +VITE_STATIC_DIR=/ # 商城H5会员端域名 VITE_MALL_H5_DOMAIN='http://localhost:3000' diff --git a/.env.test b/.env.test index a087496..65af8e8 100644 --- a/.env.test +++ b/.env.test @@ -26,9 +26,15 @@ # 打包路径 VITE_BASE_PATH=/plat +# 数据采集服务所在服务器,映射截图图片用 +VITE_VIDEO_CAMERA_DOMAIN='172.16.59.105' + # 输出路径 VITE_OUT_DIR=dist +# 公共静态文件路径 +VITE_STATIC_DIR=/plat/ + # 商城H5会员端域名 VITE_MALL_H5_DOMAIN='http://' diff --git a/src/api/data/plan/item/index.ts b/src/api/data/plan/item/index.ts index aeefbc6..0273cbd 100644 --- a/src/api/data/plan/item/index.ts +++ b/src/api/data/plan/item/index.ts @@ -50,7 +50,7 @@ //获取下拉集合 export const getItemList = (params: PageParam) => { - return request.get({ url: '/data/plan-item/getList', params}) + return request.get({ url: '/data/plan-item/list', params}) } // 查询Plan图表 diff --git a/src/api/data/video/image/index.ts b/src/api/data/video/image/index.ts new file mode 100644 index 0000000..d2d5f7a --- /dev/null +++ b/src/api/data/video/image/index.ts @@ -0,0 +1,50 @@ +import request from '@/config/axios' + +export interface ImageVO { + id: undefined, + cameraId: string, + imagePath: string, + imageUrl: string, + createDate: undefined, +} + +// 查询列表 +export const getImagePage = (params: PageParam) => { + return request.get({url: '/data/video/image/page', params}) +} + +// 获得 +export const getImage = (id: number) => { + return request.get({url: '/data/video/image/get?id=' + id}) +} + +// 查询应用列表 +export const getImageList = () => { + return request.get({url: '/data/video/image/list'}) +} + +// 新增 +export const createImage = (data: ImageVO) => { + return request.post({url: '/data/video/image/create', data}) +} + +// 修改 +export const updateImage = (data: ImageVO) => { + return request.put({url: '/data/video/image/update', data}) +} + +// 删除 +export const deleteImage = (id: number) => { + return request.delete({url: '/data/video/image/delete?id=' + id}) +} + +// 导出 +export const exportImage = (params: ImageVO) => { + return request.download({url: '/data/video/image/export-excel', params}) +} + +//预览摄像头截图 +export const getPreviewUrl = (url: string) => { + const host = import.meta.env.VITE_VIDEO_CAMERA_DOMAIN ? import.meta.env.VITE_VIDEO_CAMERA_DOMAIN : window.location.host + return `http://${host}:8899` + url +} diff --git a/src/api/model/mcs/index.ts b/src/api/model/mcs/index.ts new file mode 100644 index 0000000..4f55207 --- /dev/null +++ b/src/api/model/mcs/index.ts @@ -0,0 +1,30 @@ +import request from '@/config/axios' + +export interface PreDataBarLineReqVO { + outIds: string[], + predictTime: string, + startTime: string, + endTime: string +} + +export interface PreDataItemChartReqVO { + itemId: string, + startTime: string, + endTime: string +} + +export const getPredictItemTree = () => { + return request.get({ url: '/model/api/mcs/predict-item/tree'}) +} + +export const getPreDataCharts = (data: PreDataBarLineReqVO) => { + return request.post({ url: '/model/api/mcs/predict-data/charts', data }) +} + +export const getPreDataItemChart = (data: PreDataItemChartReqVO) => { + return request.post({ url: '/model/api/mcs/predict-data/item-chart', data }) +} + +export const exportPredictValue = (params) => { + return request.download({ url: '/model/api/mcs/predict-data/exportValue', params }) +} diff --git a/src/api/model/pre/dm/index.ts b/src/api/model/pre/dm/index.ts index aa652b6..69e13c3 100644 --- a/src/api/model/pre/dm/index.ts +++ b/src/api/model/pre/dm/index.ts @@ -1,7 +1,7 @@ import request from '@/config/axios' export interface DmModuleVO { - id: string + id: string, modulename: string, moduletype: string, cycle: string diff --git a/src/api/model/pre/item/index.ts b/src/api/model/pre/item/index.ts index 795ca65..e27d8c4 100644 --- a/src/api/model/pre/item/index.ts +++ b/src/api/model/pre/item/index.ts @@ -1,43 +1,140 @@ import request from '@/config/axios' +import {UploadRequestOptions} from "element-plus/es/components/upload/src/upload"; -export interface MmItemTypeVO { - id: string +export interface MmPredictItemVO { + id: string, itemtypename: string, - itemclasstype: string, - assemblyname: string + mmPredictItem: { + id: string, + itemno: string, + itemname: string, + caltypeid: string, + itemtypeid: string, + predictlength: string, + granularity: number, + status: string, + isfuse: number, + predictphase: string, + workchecked: number, + unittransfactor: string, + saveindex: string + }, + dmModuleItem: { + id: string, + moduleid: string, + itemid: string, + itemorder: number, + status: number, + categoryid: string + }, + mmItemOutput: { + id: string, + itemid: string, + pointid: string, + resulttableid: string, + tagname: string, + outputorder: number + }, + mmPredictModel: { + id: string, + modelno: string, + modelname: string, + itemid: string, + arithid: string, + trainsamplength: number, + predictsamplength: string, + isonlinetrain: string, + modelpath: string, + isnormal: string, + normalmax: string, + normalmin: string, + status: number, + classname: string, + methodname: string, + modelparamstructure: string, + resultstrid: string, + settingmap: string + }, + mmPredictMergeItem: { + id: string, + itemid: string, + expression: string, + num: string + }, + modelparamtypeList: [], + mmModelArithSettingsList: [], + mmModelParamList: [] } -export interface MmItemTypePageReqVO extends PageParam { - itemtypename?: string +export interface MmPredictItemPageReqVO extends PageParam { + itemno?: string, + itemname?: string, } -// 查询MmItemType列表 -export const getMmItemTypePage = (params: MmItemTypePageReqVO) => { - return request.get({ url: '/model/pre/item-type/page', params }) +// 查询MmPredictItem列表 +export const getMmPredictItemPage = (params: MmPredictItemPageReqVO) => { + return request.get({ url: '/model/pre/item/page', params }) } -// 查询MmItemType详情 -export const getMmItemType = (id: number) => { - return request.get({ url: `/model/pre/item-type/get/${id}`}) +// 查询MmPredictItem详情 +export const getMmPredictItem = (id: number) => { + return request.get({ url: `/model/pre/item/get/${id}`}) } -// 新增MmItemType -export const createMmItemType = (data: MmItemTypeVO) => { - return request.post({ url: '/model/pre/item-type/create', data }) +// 新增MmPredictItem +export const createMmPredictItem = (data: MmPredictItemVO) => { + return request.post({ url: '/model/pre/item/create', data }) } -// 修改MmItemType -export const updateMmItemType = (data: MmItemTypeVO) => { - return request.put({ url: '/model/pre/item-type/update', data }) +// 修改MmPredictItem +export const updateMmPredictItem = (data: MmPredictItemVO) => { + return request.put({ url: '/model/pre/item/update', data }) } -// 删除MmItemType -export const deleteMmItemType = (id: number) => { - return request.delete({ url: '/model/pre/item-type/delete?id=' + id }) +// 删除MmPredictItem +export const deleteMmPredictItem = (id: number) => { + return request.delete({ url: '/model/pre/item/delete?id=' + id }) } +// 查询MmPredictItem列表 +export const getMmPredictItemList = (params) => { + return request.get({ url: `/model/pre/item/list`, params}) +} -// 查询getItemTypeList详情 -export const getItemTypeList = () => { - return request.get({ url: `/model/pre/item-type/list`}) +export const updateModel = (data: any) => { + return request.upload({ url: '/model/pre/item/upload-model', data }) +} + +export const useUpload = () => { + const uploadUrl = import.meta.env.VITE_BASE_URL + '/admin-api/model/pre/item/upload-model' + + const httpRequest = async (options: UploadRequestOptions) => { + return new Promise((resolve, reject) => { + updateModel({ file: options.file }) + .then((res) => { + if (res.code === 0) { + resolve(res) + } else { + reject(res) + } + }) + .catch((res) => { + reject(res) + }) + }) + + } + + return { + uploadUrl, + httpRequest + } +} + +export const getMmPredictItemTree = () => { + return request.get({ url: `/model/pre/item/tree`}) +} + +export const getViewCharts = (params) => { + return request.get({ url: `/model/pre/item/view-charts`,params}) } diff --git a/src/api/model/pre/predict/index.ts b/src/api/model/pre/predict/index.ts deleted file mode 100644 index e27d8c4..0000000 --- a/src/api/model/pre/predict/index.ts +++ /dev/null @@ -1,140 +0,0 @@ -import request from '@/config/axios' -import {UploadRequestOptions} from "element-plus/es/components/upload/src/upload"; - -export interface MmPredictItemVO { - id: string, - itemtypename: string, - mmPredictItem: { - id: string, - itemno: string, - itemname: string, - caltypeid: string, - itemtypeid: string, - predictlength: string, - granularity: number, - status: string, - isfuse: number, - predictphase: string, - workchecked: number, - unittransfactor: string, - saveindex: string - }, - dmModuleItem: { - id: string, - moduleid: string, - itemid: string, - itemorder: number, - status: number, - categoryid: string - }, - mmItemOutput: { - id: string, - itemid: string, - pointid: string, - resulttableid: string, - tagname: string, - outputorder: number - }, - mmPredictModel: { - id: string, - modelno: string, - modelname: string, - itemid: string, - arithid: string, - trainsamplength: number, - predictsamplength: string, - isonlinetrain: string, - modelpath: string, - isnormal: string, - normalmax: string, - normalmin: string, - status: number, - classname: string, - methodname: string, - modelparamstructure: string, - resultstrid: string, - settingmap: string - }, - mmPredictMergeItem: { - id: string, - itemid: string, - expression: string, - num: string - }, - modelparamtypeList: [], - mmModelArithSettingsList: [], - mmModelParamList: [] -} - -export interface MmPredictItemPageReqVO extends PageParam { - itemno?: string, - itemname?: string, -} - -// 查询MmPredictItem列表 -export const getMmPredictItemPage = (params: MmPredictItemPageReqVO) => { - return request.get({ url: '/model/pre/item/page', params }) -} - -// 查询MmPredictItem详情 -export const getMmPredictItem = (id: number) => { - return request.get({ url: `/model/pre/item/get/${id}`}) -} - -// 新增MmPredictItem -export const createMmPredictItem = (data: MmPredictItemVO) => { - return request.post({ url: '/model/pre/item/create', data }) -} - -// 修改MmPredictItem -export const updateMmPredictItem = (data: MmPredictItemVO) => { - return request.put({ url: '/model/pre/item/update', data }) -} - -// 删除MmPredictItem -export const deleteMmPredictItem = (id: number) => { - return request.delete({ url: '/model/pre/item/delete?id=' + id }) -} - -// 查询MmPredictItem列表 -export const getMmPredictItemList = (params) => { - return request.get({ url: `/model/pre/item/list`, params}) -} - -export const updateModel = (data: any) => { - return request.upload({ url: '/model/pre/item/upload-model', data }) -} - -export const useUpload = () => { - const uploadUrl = import.meta.env.VITE_BASE_URL + '/admin-api/model/pre/item/upload-model' - - const httpRequest = async (options: UploadRequestOptions) => { - return new Promise((resolve, reject) => { - updateModel({ file: options.file }) - .then((res) => { - if (res.code === 0) { - resolve(res) - } else { - reject(res) - } - }) - .catch((res) => { - reject(res) - }) - }) - - } - - return { - uploadUrl, - httpRequest - } -} - -export const getMmPredictItemTree = () => { - return request.get({ url: `/model/pre/item/tree`}) -} - -export const getViewCharts = (params) => { - return request.get({ url: `/model/pre/item/view-charts`,params}) -} diff --git a/src/api/model/pre/result/index.ts b/src/api/model/pre/result/index.ts deleted file mode 100644 index 5561e94..0000000 --- a/src/api/model/pre/result/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import request from '@/config/axios' - -export interface MmResultTableVO { - id: string - tablename: string, -} - -export interface MmResultTablePageReqVO extends PageParam { - tablename?: string -} - -// 查询MmResultTable列表 -export const getMmResultTablePage = (params: MmResultTablePageReqVO) => { - return request.get({ url: '/model/pre/result-table/page', params }) -} - -// 查询MmResultTable详情 -export const getMmResultTable = (id: number) => { - return request.get({ url: `/model/pre/result-table/get/${id}`}) -} - -// 新增MmResultTable -export const createMmResultTable = (data: MmResultTableVO) => { - return request.post({ url: '/model/pre/result-table/create', data }) -} - -// 修改MmResultTable -export const updateMmResultTable = (data: MmResultTableVO) => { - return request.put({ url: '/model/pre/result-table/update', data }) -} - -// 删除MmResultTable -export const deleteMmResultTable = (id: number) => { - return request.delete({ url: '/model/pre/result-table/delete?id=' + id }) -} - - -// 查询getResulttableList详情 -export const getResulttableList = () => { - return request.get({ url: `/model/pre/result-table/list`}) -} - -// 查询getResulttableList详情 -export const getResultstridList = () => { - return request.get({ url: `/model/pre/model-resultstr/list`}) -} diff --git a/src/api/model/pre/type/index.ts b/src/api/model/pre/type/index.ts new file mode 100644 index 0000000..795ca65 --- /dev/null +++ b/src/api/model/pre/type/index.ts @@ -0,0 +1,43 @@ +import request from '@/config/axios' + +export interface MmItemTypeVO { + id: string + itemtypename: string, + itemclasstype: string, + assemblyname: string +} + +export interface MmItemTypePageReqVO extends PageParam { + itemtypename?: string +} + +// 查询MmItemType列表 +export const getMmItemTypePage = (params: MmItemTypePageReqVO) => { + return request.get({ url: '/model/pre/item-type/page', params }) +} + +// 查询MmItemType详情 +export const getMmItemType = (id: number) => { + return request.get({ url: `/model/pre/item-type/get/${id}`}) +} + +// 新增MmItemType +export const createMmItemType = (data: MmItemTypeVO) => { + return request.post({ url: '/model/pre/item-type/create', data }) +} + +// 修改MmItemType +export const updateMmItemType = (data: MmItemTypeVO) => { + return request.put({ url: '/model/pre/item-type/update', data }) +} + +// 删除MmItemType +export const deleteMmItemType = (id: number) => { + return request.delete({ url: '/model/pre/item-type/delete?id=' + id }) +} + + +// 查询getItemTypeList详情 +export const getItemTypeList = () => { + return request.get({ url: `/model/pre/item-type/list`}) +} diff --git a/src/api/model/sche/model/index.ts b/src/api/model/sche/model/index.ts index b0bf106..8863d31 100644 --- a/src/api/model/sche/model/index.ts +++ b/src/api/model/sche/model/index.ts @@ -1,7 +1,9 @@ import request from '@/config/axios' import * as DataPointApi from '@/api/data/da/point' -import * as PredictItemApi from '@/api/model/pre/predict' +import * as PredictItemApi from '@/api/model/pre/item' +import * as PlanItemApi from '@/api/data/plan/item' import {CommonEnabled} from "@/utils/constants"; +import {getItemList, ItemVO} from "@/api/data/plan/item"; export interface ScheduleModelVO { id: string @@ -100,8 +102,25 @@ ) }) } + + const planItemList = ref([] as PlanItemApi.ItemVO) + planItemList.value = await PlanItemApi.getItemList({ + }) + const planList = [] + if (planItemList.value) { + planItemList.value.forEach(item => { + planList.push( + { + id: item.id, + name: item.itemName + } + ) + }) + } + return { 'DATAPOINT':pointList, - 'PREDICTITEM': itemList + 'PREDICTITEM': itemList, + 'PLAN': planList, } } diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index dcf55c7..5de3d74 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -50,6 +50,15 @@ noTagsView: true } }, + // { + // path: '/shasteel', + // component: () => import('@/views/micro/index.vue'), + // name: 'shasteel', + // meta: { + // hidden: true, + // noTagsView: true + // }, + // }, { path: '/home2', component: () => import('@/views/Home/Index2.vue'), @@ -274,18 +283,6 @@ hidden: true, canTo: true, title: '设计流程', - activeMenu: '/bpm/manager/model' - } - }, - { - path: 'manager/simple/workflow/model/edit', - component: () => import('@/views/bpm/simpleWorkflow/index.vue'), - name: 'SimpleWorkflowDesignEditor', - meta: { - noCache: true, - hidden: true, - canTo: true, - title: '仿钉钉设计流程', activeMenu: '/bpm/manager/model' } }, diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 86bd05a..9347dfc 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -162,6 +162,8 @@ MODEL_TYPE = 'model_type', MODEL_METHOD_SETTING_TYPE = 'model_method_setting_type', MODEL_METHOD_SETTING_VALUE_TYPE = 'model_method_setting_value_type', + PRED_GRANULARITY = 'pred_granularity', + ITEM_RUN_STATUS = 'item_run_status', // ========== DATA - 数据平台模块 ========== DATA_FIELD_TYPE = 'data_field_type', @@ -183,4 +185,5 @@ NVR_ONLINE_STATUS = 'nvr_online_status', CAMERA_BRAND = 'camera_brand', CAPTURE_TYPE = 'capture_type', + MODEL_RESULT_TYPE = 'model_result_type', } diff --git a/src/utils/hostMap.ts b/src/utils/hostMap.ts index 81df37d..c2904af 100644 --- a/src/utils/hostMap.ts +++ b/src/utils/hostMap.ts @@ -1,6 +1,6 @@ const map = { "//localhost:7200/": "//wujie-micro.github.io/demo-vue2/", - "//localhost:90/": "//localhost:90/", + "//localhost:9000/": "//localhost:9000/", "//localhost:8000/": "//wujie-micro.github.io/demo-main-vue/", }; diff --git a/src/utils/is.ts b/src/utils/is.ts index eec86a9..39812b6 100644 --- a/src/utils/is.ts +++ b/src/utils/is.ts @@ -98,8 +98,9 @@ export const isClient = !isServer export const isUrl = (path: string): boolean => { + // fix:修复hash路由无法跳转的问题 const reg = - /(((^https?:(?:\/\/)?)(?:[-:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&%@.\w_]*)#?(?:[\w]*))?)$/ + /(((^https?:(?:\/\/)?)(?:[-:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%#\/.\w-_]*)?\??(?:[-\+=&%@.\w_]*)#?(?:[\w]*))?)$/ return reg.test(path) } diff --git a/src/views/Home/Index.vue b/src/views/Home/Index.vue index aa64a85..822f800 100644 --- a/src/views/Home/Index.vue +++ b/src/views/Home/Index.vue @@ -5,9 +5,9 @@ <el-skeleton :loading="loading" animated> <div id="app" v-for="(item, index) in appList" :key="`dynamics-${index}`"> <div class="card" @click="gotoApp(item)"> - <img :src="item.icon" style="width: 100px; height: 100px" /> + <img :src="item.icon" style="width: 100px; height: 100px"/> <div> - {{item.appName}} + {{ item.appName }} </div> </div> </div> @@ -19,12 +19,11 @@ import * as AppApi from '@/api/system/app' import {Apps} from "@/views/Home/types"; import {CACHE_KEY, useCache} from "@/hooks/web/useCache"; -import * as authUtil from "@/utils/auth"; -defineOptions({ name: 'Home' }) +defineOptions({name: 'Home'}) -const { wsCache } = useCache() +const {wsCache} = useCache() const loading = ref(true) @@ -35,7 +34,7 @@ appList = Object.assign(appList, data) } -const getAppMenuList = async (id) => { +const getAppMenuList = async (id, appCode) => { const data = await AppApi.getAppMenuList(id) let userInfo = wsCache.get(CACHE_KEY.USER) userInfo.menus = data @@ -55,32 +54,38 @@ // 进入应用 const gotoApp = async (item) => { + let path = window.location.pathname + let appName = path.split("/")[0] + console.log(appName) let id = item.id let type = item.type - if(type === 0) { - getAppMenuList(id) + let appCode = item.appCode + if (type === 0) { + await getAppMenuList(id, appCode) } else { const data = await AppApi.getAppMenuList(id) let userInfo = wsCache.get(CACHE_KEY.USER) userInfo.menus = data wsCache.set(CACHE_KEY.USER, userInfo) wsCache.set(CACHE_KEY.ROLE_ROUTERS, data) - // await OAuth2Login(formData.value) - // window.open(item.appDomain + '/login?appid=' + item.id + "&username=" + authUtil.getLoginForm().username, '_blank') window.open(item.appDomain + '/index', '_blank') + // window.open('/plat/shasteel', '_blank') + // window.location.href = '/plat/shasteel' + // window.location.href = `/plat/shasteel?key=energy&url=http://localhost:9000&energy=/energy/demo` } } </script> <style lang="scss" scoped> -#app{ +#app { width: 300px; height: 200px; display: inline-block; background: transparent; } -.card{ + +.card { border: thin dashed gainsboro; width: 150px; height: 120px; diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 22a80b2..bc3a32a 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -12,7 +12,7 @@ <el-row style="margin-right: -10px; margin-left: -10px"> <el-col :span="24" style="padding-right: 10px; padding-left: 10px"> <el-form-item> - <LoginFormTitle style="width: 100%" /> + <LoginFormTitle style="width: 100%"/> </el-form-item> </el-col> <el-col :span="24" style="padding-right: 10px; padding-left: 10px"> @@ -86,27 +86,27 @@ </el-form> </template> <script lang="ts" setup> -import { ElLoading } from 'element-plus' +import {ElLoading} from 'element-plus' import LoginFormTitle from './LoginFormTitle.vue' -import type { RouteLocationNormalizedLoaded } from 'vue-router' +import type {RouteLocationNormalizedLoaded} from 'vue-router' -import { useIcon } from '@/hooks/web/useIcon' +import {useIcon} from '@/hooks/web/useIcon' import * as authUtil from '@/utils/auth' -import { usePermissionStore } from '@/store/modules/permission' +import {usePermissionStore} from '@/store/modules/permission' import * as LoginApi from '@/api/login' -import { LoginStateEnum, useFormValid, useLoginState } from './useLogin' +import {LoginStateEnum, useFormValid, useLoginState} from './useLogin' -defineOptions({ name: 'LoginForm' }) +defineOptions({name: 'LoginForm'}) -const { t } = useI18n() -const iconHouse = useIcon({ icon: 'ep:house' }) -const iconAvatar = useIcon({ icon: 'ep:avatar' }) -const iconLock = useIcon({ icon: 'ep:lock' }) +const {t} = useI18n() +const iconHouse = useIcon({icon: 'ep:house'}) +const iconAvatar = useIcon({icon: 'ep:avatar'}) +const iconLock = useIcon({icon: 'ep:lock'}) const formLogin = ref() -const { validForm } = useFormValid(formLogin) -const { getLoginState } = useLoginState() -const { currentRoute, push } = useRouter() +const {validForm} = useFormValid(formLogin) +const {getLoginState} = useLoginState() +const {currentRoute, push} = useRouter() const permissionStore = usePermissionStore() const redirect = ref<string>('') const loginLoading = ref(false) @@ -199,14 +199,14 @@ authUtil.removeLoginForm() } authUtil.setToken(res) - if (!redirect.value) { + if (!redirect.value || redirect.value == "/") { redirect.value = '/index' } // 判断是否为SSO登录 if (redirect.value.indexOf('sso') !== -1) { window.location.href = window.location.href.replace('/login?redirect=', '') } else { - push({ path: redirect.value || permissionStore.addRouters[0].path }) + push({path: redirect.value || permissionStore.addRouters[0].path}) } } finally { loginLoading.value = false diff --git a/src/views/bpm/model/index.vue b/src/views/bpm/model/index.vue index f8b0b75..a20ea4e 100644 --- a/src/views/bpm/model/index.vue +++ b/src/views/bpm/model/index.vue @@ -163,14 +163,6 @@ <el-button link type="primary" - @click="handleSimpleDesign(scope.row.id)" - v-hasPermi="['bpm:model:update']" - > - 仿钉钉设计流程 - </el-button> - <el-button - link - type="primary" @click="handleDeploy(scope.row)" v-hasPermi="['bpm:model:deploy']" > @@ -328,15 +320,6 @@ const handleDesign = (row) => { push({ name: 'BpmModelEditor', - query: { - modelId: row.id - } - }) -} - -const handleSimpleDesign = (row) => { - push({ - name: 'SimpleWorkflowDesignEditor', query: { modelId: row.id } diff --git a/src/views/bpm/simpleWorkflow/index.vue b/src/views/bpm/simpleWorkflow/index.vue deleted file mode 100644 index 144615e..0000000 --- a/src/views/bpm/simpleWorkflow/index.vue +++ /dev/null @@ -1,28 +0,0 @@ -<template> - <div> - <section class="dingflow-design"> - <div class="box-scale"> - <nodeWrap v-model:nodeConfig="nodeConfig" /> - <div class="end-node"> - <div class="end-node-circle"></div> - <div class="end-node-text">流程结束</div> - </div> - </div> - </section> - </div> -</template> -<script lang="ts" setup> -import nodeWrap from '@/components/SimpleProcessDesigner/src/nodeWrap.vue' -defineOptions({ name: 'SimpleWorkflowDesignEditor' }) -let nodeConfig = ref({ - nodeName: '发起人', - type: 0, - id: 'root', - formPerms: {}, - nodeUserList: [], - childNode: {} -}) -</script> -<style> -@import url('@/components/SimpleProcessDesigner/theme/workflow.css'); -</style> \ No newline at end of file diff --git a/src/views/data/channel/http/api/tag/index.vue b/src/views/data/channel/http/api/tag/index.vue index 5f16d44..9a38a69 100644 --- a/src/views/data/channel/http/api/tag/index.vue +++ b/src/views/data/channel/http/api/tag/index.vue @@ -1,7 +1,7 @@ <template> <el-drawer v-model="drawer" - size="50%" + size="60%" title="Http Tag" :direction="direction" :before-close="handleClose" @@ -107,20 +107,22 @@ label="数据值" header-align="center" align="center" + min-width="100" :formatter="(row) => {if (row.dataValue === -2.0) {return '--';}return row.dataValue;}" /> <el-table-column - prop="quality" + prop="dataTime" + label="数据时间" + header-align="center" + align="center" + min-width="150" + /> + <el-table-column + prop="dataQuality" label="数据质量" header-align="center" align="center" - > - <template #default="scope"> - <el-tag v-if="scope.row.dataValue === Number(-2.0)" type="danger" size="small">bad - </el-tag> - <el-tag v-else size="small">good</el-tag> - </template> - </el-table-column> + /> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> <el-button diff --git a/src/views/data/channel/kio/tag/index.vue b/src/views/data/channel/kio/tag/index.vue index d334fb4..735b1d8 100644 --- a/src/views/data/channel/kio/tag/index.vue +++ b/src/views/data/channel/kio/tag/index.vue @@ -1,7 +1,7 @@ <template> <el-drawer v-model="drawer" - size="50%" + size="60%" title="Kio Tag" :direction="direction" :before-close="handleClose" @@ -105,19 +105,22 @@ label="数据值" header-align="center" align="center" + min-width="100" :formatter="(row) => {if (row.dataValue === -2.0) {return '--';}return row.dataValue;}" /> <el-table-column - prop="quality" + prop="dataTime" + label="数据时间" + header-align="center" + align="center" + min-width="150" + /> + <el-table-column + prop="dataQuality" label="数据质量" header-align="center" align="center" - > - <template #default="scope"> - <el-tag v-if="scope.row.dataValue === Number(-2.0)" type="danger" size="small">bad</el-tag> - <el-tag v-else size="small">good</el-tag> - </template> - </el-table-column> + /> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> <el-button diff --git a/src/views/data/channel/modbus/tag/index.vue b/src/views/data/channel/modbus/tag/index.vue index 7739240..528d368 100644 --- a/src/views/data/channel/modbus/tag/index.vue +++ b/src/views/data/channel/modbus/tag/index.vue @@ -1,7 +1,7 @@ <template> <el-drawer v-model="drawer" - size="50%" + size="60%" title="ModBus Tag" :direction="direction" :before-close="handleClose" @@ -133,19 +133,22 @@ label="数据值" header-align="center" align="center" + min-width="100" :formatter="(row) => {if (row.dataValue === -2.0) {return '--';}return row.dataValue;}" /> <el-table-column - prop="quality" + prop="dataTime" + label="数据时间" + header-align="center" + align="center" + min-width="150" + /> + <el-table-column + prop="dataQuality" label="数据质量" header-align="center" align="center" - > - <template #default="scope"> - <el-tag v-if="scope.row.dataValue === Number(-2.0)" type="danger" size="small">bad</el-tag> - <el-tag v-else size="small">good</el-tag> - </template> - </el-table-column> + /> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> <el-button diff --git a/src/views/data/channel/opcda/tag/index.vue b/src/views/data/channel/opcda/tag/index.vue index 53b3a4a..fc11b57 100644 --- a/src/views/data/channel/opcda/tag/index.vue +++ b/src/views/data/channel/opcda/tag/index.vue @@ -1,7 +1,7 @@ <template> <el-drawer v-model="drawer" - size="50%" + size="60%" title="OpcDA Tag" :direction="direction" :before-close="handleClose" @@ -98,19 +98,22 @@ label="数据值" header-align="center" align="center" + min-width="100" :formatter="(row) => {if (row.dataValue === -2.0) {return '--';}return row.dataValue;}" /> <el-table-column - prop="quality" + prop="dataTime" + label="数据时间" + header-align="center" + align="center" + min-width="150" + /> + <el-table-column + prop="dataQuality" label="数据质量" header-align="center" align="center" - > - <template #default="scope"> - <el-tag v-if="scope.row.dataValue === Number(-2.0)" type="danger" size="small">bad</el-tag> - <el-tag v-else size="small">good</el-tag> - </template> - </el-table-column> + /> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> <el-button diff --git a/src/views/data/channel/opcua/tag/index.vue b/src/views/data/channel/opcua/tag/index.vue index 524f4b5..2c8d799 100644 --- a/src/views/data/channel/opcua/tag/index.vue +++ b/src/views/data/channel/opcua/tag/index.vue @@ -1,7 +1,7 @@ <template> <el-drawer v-model="drawer" - size="50%" + size="60%" title="Opcua Tag" :direction="direction" :before-close="handleClose" @@ -67,6 +67,12 @@ <Icon icon="ep:download" />导出 </el-button> </el-form-item> + <el-form-item label="更新当前值" label-width="100px"> + <el-switch + v-model="queryParams.currentValue" + active-color="#13ce66" + inactive-color="#ff4949"/> + </el-form-item> </el-form> </ContentWrap> <!-- 列表 --> @@ -113,19 +119,22 @@ label="数据值" header-align="center" align="center" + min-width="100" :formatter="(row) => {if (row.dataValue === -2.0) {return '--';}return row.dataValue;}" /> <el-table-column - prop="quality" + prop="dataTime" + label="数据时间" + header-align="center" + align="center" + min-width="150" + /> + <el-table-column + prop="dataQuality" label="数据质量" header-align="center" align="center" - > - <template #default="scope"> - <el-tag v-if="scope.row.dataValue === Number(-2.0)" type="danger" size="small">bad</el-tag> - <el-tag v-else size="small">good</el-tag> - </template> - </el-table-column> + /> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> <el-button diff --git a/src/views/data/point/DaPointChart.vue b/src/views/data/point/DaPointChart.vue index 19a6b23..8713861 100644 --- a/src/views/data/point/DaPointChart.vue +++ b/src/views/data/point/DaPointChart.vue @@ -41,7 +41,8 @@ :loading="exportLoading" v-hasPermi="['data:point:export']" > - <Icon icon="ep:download" />导出 + <Icon icon="ep:download"/> + 导出 </el-button> </el-form-item> </el-form> @@ -50,39 +51,41 @@ </template> <script lang="ts" setup> - import {ref} from 'vue'; - import * as echarts from 'echarts'; - import * as DaPoint from '@/api/data/da/point/daPointChart' - import {getYMDHM0} from "@/utils/dateUtil" - import download from "@/utils/download"; - const message = useMessage() // 消息弹窗 - const visible = ref(false); - const chartDom = ref(null); - let myChart = null; - const chartParams = reactive({ - codes:[], - startDate : undefined, - endDate: undefined, - }) - const dataForm = ref({ - id: "", - pointNo: "", - pointName: "", - pointTypeName: "", - startTime: getYMDHM0(new Date() - 60 * 60 * 1000), - endTime: "", - }); - const loading = ref(true) // 列表的加载中 - /** 打开弹窗 */ - const open = async (row: object) => { - visible.value = true - dataForm.value.id = row.id; - dataForm.value.pointNo = row.pointNo; - dataForm.value.pointName = row.pointName; - getDataList(); - } +import {ref} from 'vue'; +import * as echarts from 'echarts'; +import * as DaPoint from '@/api/data/da/point/daPointChart' +import {getYMDHM0} from "@/utils/dateUtil" +import download from "@/utils/download"; - defineExpose({open}) // 提供 open 方法,用于打开弹窗 +const message = useMessage() // 消息弹窗 +const visible = ref(false); +const chartDom = ref(null); +let myChart = null; +const chartParams = reactive({ + codes: [], + pointNo: undefined, + startDate: undefined, + endDate: undefined, +}) +const dataForm = ref({ + id: "", + pointNo: "", + pointName: "", + pointTypeName: "", + startTime: getYMDHM0(new Date() - 60 * 60 * 1000), + endTime: "", +}); + +/** 打开弹窗 */ +const open = async (row: object) => { + visible.value = true + dataForm.value.id = row.id; + dataForm.value.pointNo = row.pointNo; + dataForm.value.pointName = row.pointName; + getDataList(); +} + +defineExpose({open}) // 提供 open 方法,用于打开弹窗 async function getDataList() { visible.value = true; @@ -111,84 +114,86 @@ }); }) - myChart = echarts.init(chartDom.value); - const option = { - title: { - text: dataForm.value.pointName, - top: 0, - left: "1%", - textStyle: { - fontSize: 14, + 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", }, }, - 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", }, - 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) - } + ], + series: seriesData, + }; + myChart.setOption(option); + } catch (error) { + console.error(error) } } - /** 导出按钮操作 */ - const exportLoading = ref(false) - const handleExport = async () => { - chartParams.codes=[dataForm.value.pointNo]; - chartParams.startDate = dataForm.value.startTime; - chartParams.endDate = dataForm.value.endTime; - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - const data = await DaPoint.exportDaPointValue(chartParams) - download.excel(data, dataForm.value.pointName +'.xls') - } catch { - } finally { - exportLoading.value = false - } +} + +/** 导出按钮操作 */ +const exportLoading = ref(false) +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await DaPoint.exportDaPointValue({ + pointNo: dataForm.value.pointNo, + start: dataForm.value.startTime, + end: dataForm.value.endTime + }) + download.excel(data, dataForm.value.pointName + '.xls') + } catch { + } finally { + exportLoading.value = false } +} </script> <style> - .el-select { - width: 100%; - } +.el-select { + width: 100%; +} - .result-chart { - height: 500px; - } +.result-chart { + height: 500px; +} </style> diff --git a/src/views/data/video/camera/CameraImage.vue b/src/views/data/video/camera/CameraImage.vue new file mode 100644 index 0000000..335983b --- /dev/null +++ b/src/views/data/video/camera/CameraImage.vue @@ -0,0 +1,114 @@ +<template> + <el-dialog v-model="dialogVisible" :title="dialogTitle" :close="handleClose" + style="width: 50%; margin-top: 20px; overflow: auto; z-index: 1"> + <!-- 列表 --> + <el-table v-loading="loading" :data="list"> + <el-table-column + label="截图时间" + align="center" + prop="createDate" + :formatter="dateFormatter" + width="200" + /> + <el-table-column label="图片路径" align="center" prop="imagePath" width="500" + :show-overflow-tooltip="true"/> + <el-table-column label="图片预览" align="center" prop="imageUrl"> + <template #default="scope"> + <el-image style="height: 50px; z-index: 1" + :src="getPreviewUrl(scope.row.imageUrl)" + :preview-src-list="getPreviewSrcList(scope.row.imageUrl)" fit="cover" + preview-teleported/> + </template> + </el-table-column> + <el-table-column label="操作" align="center" min-width="60" fixed="right"> + <template #default="scope"> + <el-button + link + type="danger" + style="z-index: 1" + @click="handleDelete(scope.row.id)" + v-hasPermi="['video:camera:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="open" + /> + </el-dialog> +</template> +<script lang="ts" setup> +import * as ImageApi from '@/api/data/video/image' +import {getPreviewUrl} from "@/api/data/video/image"; +import {dateFormatter} from "@/utils/formatTime"; + +defineOptions({name: 'CameraImage'}) + +const message = useMessage() // 消息弹窗 +const {t} = useI18n() // 国际化 +const dialogTitle = ref('截图列表') +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + id: undefined, + brand: undefined, + code: undefined, + device: undefined, + cameraId: '', + imagePath: undefined, + imageUrl: undefined, + createDate: undefined, +}) +const cameraId = ref('') +const dialogVisible = ref(false) + +/** 查询列表 */ +const open = async (camera_id: string) => { + dialogVisible.value = true + cameraId.value = camera_id + queryParams.cameraId = camera_id + loading.value = true + try { + const data = await ImageApi.getImagePage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +const handleClose = async () => { + dialogVisible.value = false +} + +const getPreviewSrcList = (imageUrl: string) => { + let previewSrcList: string[] = [] + previewSrcList.push(getPreviewUrl(imageUrl)) + return previewSrcList +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await ImageApi.deleteImage(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await open(cameraId.value) + } catch { + } +} +</script> diff --git a/src/views/data/video/camera/index.vue b/src/views/data/video/camera/index.vue index d0fbbe6..add49c5 100644 --- a/src/views/data/video/camera/index.vue +++ b/src/views/data/video/camera/index.vue @@ -61,11 +61,11 @@ </el-form-item> <el-form-item> <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> + <Icon icon="ep:search" class="mr-5px"/> 搜索 </el-button> <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> + <Icon icon="ep:refresh" class="mr-5px"/> 重置 </el-button> <el-button @@ -74,7 +74,7 @@ @click="openForm('create')" v-hasPermi="['video:camera:save']" > - <Icon icon="ep:plus" class="mr-5px" /> + <Icon icon="ep:plus" class="mr-5px"/> 新增 </el-button> <el-button @@ -84,7 +84,7 @@ :loading="exportLoading" v-hasPermi="['video:camera:export']" > - <Icon icon="ep:download" class="mr-5px" /> + <Icon icon="ep:download" class="mr-5px"/> 导出 </el-button> </el-form-item> @@ -96,20 +96,21 @@ <el-table v-loading="loading" :data="list"> <el-table-column label="品牌" align="center" prop="brand" width="80"> <template #default="scope"> - <dict-tag :type="DICT_TYPE.CAMERA_BRAND" :value="scope.row.brand" /> + <dict-tag :type="DICT_TYPE.CAMERA_BRAND" :value="scope.row.brand"/> </template> </el-table-column> <el-table-column label="设备类型" align="center" prop="device" width="200"/> <el-table-column label="编码" align="center" prop="code" width="200"/> - <el-table-column label="IP" align="center" prop="ip" /> - <el-table-column label="端口" align="center" prop="port" width="100"/> + <el-table-column label="IP" align="center" prop="ip"/> + <el-table-column label="端口" align="center" prop="port" width="80"/> + <el-table-column label="通道" align="center" prop="channel" width="80"/> <el-table-column label="用户名" align="center" prop="username" width="100"/> <el-table-column label="状态" prop="status" width="80"> <template #default="scope"> - <dict-tag :type="DICT_TYPE.NVR_ONLINE_STATUS" :value="scope.row.status" /> + <dict-tag :type="DICT_TYPE.NVR_ONLINE_STATUS" :value="scope.row.status"/> </template> </el-table-column> - <el-table-column label="位置" align="center" prop="location" /> + <el-table-column label="位置" align="center" prop="location"/> <el-table-column label="备注" align="center" prop="remark" width="150"/> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> @@ -129,6 +130,14 @@ > 删除 </el-button> + <el-button + link + type="success" + @click="imageHandle(scope.row.id)" + v-hasPermi="['video:image:query']" + > + 查看截图 + </el-button> </template> </el-table-column> </el-table> @@ -142,99 +151,109 @@ </ContentWrap> <!-- 表单弹窗:添加/修改 --> - <CameraForm ref="formRef" @success="getList" /> + <CameraForm ref="formRef" @success="getList"/> + <CameraImage ref="imageFormRef"/> </template> <script lang="ts" setup> import {DICT_TYPE, getIntDictOptions} from '@/utils/dict' - import download from '@/utils/download' - import * as CameraApi from '@/api/data/video/camera' - import CameraForm from './CameraForm.vue' +import download from '@/utils/download' +import * as CameraApi from '@/api/data/video/camera' +import CameraForm from './CameraForm.vue' +import CameraImage from './CameraImage.vue' - defineOptions({name: 'Camera'}) - const message = useMessage() // 消息弹窗 - const {t} = useI18n() // 国际化 +defineOptions({name: 'Camera'}) - const loading = ref(true) // 列表的加载中 - const total = ref(0) // 列表的总页数 - const list = ref([]) // 列表的数据 - const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - type: 1, - brand: undefined, - ip: undefined, - code: undefined, - device: undefined, - location: undefined, - status: undefined - }) - const queryFormRef = ref() // 搜索的表单 - const exportLoading = ref(false) // 导出的加载中 +const message = useMessage() // 消息弹窗 +const {t} = useI18n() // 国际化 - /** 查询列表 */ - const getList = async () => { - loading.value = true - try { - const data = await CameraApi.getCameraPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + type: 1, + brand: undefined, + ip: undefined, + code: undefined, + device: undefined, + location: undefined, + status: undefined +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await CameraApi.getCameraPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false } +} - /** 搜索按钮操作 */ - const handleQuery = () => { - queryParams.pageNo = 1 - getList() - } +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} - /** 重置按钮操作 */ - const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() - } +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + queryParams.brand = undefined + handleQuery() +} - /** 添加/修改操作 */ - const formRef = ref() - const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) - } +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} - /** 删除按钮操作 */ - const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await CameraApi.deleteCamera(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch { - } - } - - /** 导出按钮操作 */ - const handleExport = async () => { - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - const data = await CameraApi.exportCamera(queryParams) - download.excel(data, '录像机列表.xls') - } catch { - } finally { - exportLoading.value = false - } - } - - /** 初始化 **/ - onMounted(async () => { +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await CameraApi.deleteCamera(id) + message.success(t('common.delSuccess')) + // 刷新列表 await getList() - }) + } catch { + } +} + +/** 查看截图 */ +const imageFormRef = ref() +const imageHandle = (id: string) => { + imageFormRef.value.open(id) +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await CameraApi.exportCamera(queryParams) + download.excel(data, '录像机列表.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(async () => { + await getList() +}) </script> diff --git a/src/views/data/video/nvr/NvrCamera.vue b/src/views/data/video/nvr/NvrCamera.vue index 0ff49b3..212ff57 100644 --- a/src/views/data/video/nvr/NvrCamera.vue +++ b/src/views/data/video/nvr/NvrCamera.vue @@ -6,95 +6,104 @@ @close="handleClose" size="60%"> <div class="mod-dev__camera" style="padding: 10px;"> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="监控区域" prop="code"> - <el-input - v-model="queryParams.location" - placeholder="请输入监控区域" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> - 搜索 - </el-button> - <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> - 重置 - </el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - > - <Icon icon="ep:plus" class="mr-5px" /> - 新增 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['dev:camera:export']" - > - <Icon icon="ep:download" class="mr-5px" /> - 导出 - </el-button> - </el-form-item> - </el-form> - - <!-- 列表 --> - <el-table v-loading="loading" :data="list"> - <el-table-column label="编码" align="center" prop="code" width="80" /> - <el-table-column label="抓图方式" align="center" prop="captureType" width="80"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.CAPTURE_TYPE" :value="scope.row.captureType" /> - </template> - </el-table-column> - <el-table-column label="通道" align="center" prop="channel" width="80" /> - <el-table-column label="监控区域" align="center" prop="location" /> - <el-table-column label="备注" align="center" prop="remark" width="200" /> - <el-table-column label="操作" align="center" min-width="110" fixed="right"> - <template #default="scope"> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="监控区域" prop="code"> + <el-input + v-model="queryParams.location" + placeholder="请输入监控区域" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon icon="ep:search" class="mr-5px"/> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon icon="ep:refresh" class="mr-5px"/> + 重置 + </el-button> <el-button - link type="primary" - @click="openForm('update', scope.row.id)" + plain + @click="openForm('create')" > - 编辑 + <Icon icon="ep:plus" class="mr-5px"/> + 新增 </el-button> <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['dev:camera:export']" > - 删除 + <Icon icon="ep:download" class="mr-5px"/> + 导出 </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> + </el-form-item> + </el-form> + + <!-- 列表 --> + <el-table v-loading="loading" :data="list"> + <el-table-column label="编码" align="center" prop="code" width="80"/> + <el-table-column label="抓图方式" align="center" prop="captureType" width="80"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.CAPTURE_TYPE" :value="scope.row.captureType"/> + </template> + </el-table-column> + <el-table-column label="通道" align="center" prop="channel" width="80"/> + <el-table-column label="监控区域" align="center" prop="location"/> + <el-table-column label="备注" align="center" prop="remark" width="200"/> + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + > + 删除 + </el-button> + <el-button + link + type="success" + @click="imageHandle(scope.row.id)" + v-hasPermi="['video:image:query']" + > + 查看截图 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> </div> </el-drawer> <!-- 表单弹窗:添加/修改 --> - <NvrCameraForm ref="formRef" @success="getList" /> + <NvrCameraForm ref="formRef" @success="getList"/> + <CameraImage ref="imageFormRef"/> </template> <script lang="ts" setup> @@ -102,6 +111,7 @@ import * as CameraApi from '@/api/data/video/camera' import NvrCameraForm from './NvrCameraForm.vue' import {DICT_TYPE} from "@/utils/dict"; +import CameraImage from "../camera/CameraImage.vue"; defineOptions({name: 'NvrCamera'}) @@ -134,7 +144,7 @@ await getList() } -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 +defineExpose({open}) // 提供 open 方法,用于打开弹窗 /** 查询列表 */ const getList = async () => { @@ -148,6 +158,12 @@ } } +/** 查看截图 */ +const imageFormRef = ref() +const imageHandle = (id: string) => { + imageFormRef.value.open(id) +} + /** 搜索按钮操作 */ const handleQuery = () => { queryParams.pageNo = 1 @@ -156,7 +172,7 @@ /** 重置按钮操作 */ const resetQuery = () => { - queryFormRef.value.resetFields() + queryParams.location = undefined handleQuery() } diff --git a/src/views/data/video/nvr/index.vue b/src/views/data/video/nvr/index.vue index 61d0163..b780a0e 100644 --- a/src/views/data/video/nvr/index.vue +++ b/src/views/data/video/nvr/index.vue @@ -52,11 +52,11 @@ </el-form-item> <el-form-item> <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> + <Icon icon="ep:search" class="mr-5px"/> 搜索 </el-button> <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> + <Icon icon="ep:refresh" class="mr-5px"/> 重置 </el-button> <el-button @@ -65,7 +65,7 @@ @click="openForm('create')" v-hasPermi="['video:nvr:save']" > - <Icon icon="ep:plus" class="mr-5px" /> + <Icon icon="ep:plus" class="mr-5px"/> 新增 </el-button> <el-button @@ -75,7 +75,7 @@ :loading="exportLoading" v-hasPermi="['video:nvr:export']" > - <Icon icon="ep:download" class="mr-5px" /> + <Icon icon="ep:download" class="mr-5px"/> 导出 </el-button> </el-form-item> @@ -87,20 +87,19 @@ <el-table v-loading="loading" :data="list"> <el-table-column label="品牌" align="center" prop="brand" width="80"> <template #default="scope"> - <dict-tag :type="DICT_TYPE.CAMERA_BRAND" :value="scope.row.brand" /> + <dict-tag :type="DICT_TYPE.CAMERA_BRAND" :value="scope.row.brand"/> </template> </el-table-column> <el-table-column label="编码" align="center" prop="code" width="100"/> <el-table-column label="名称" align="center" prop="name"/> - <el-table-column label="IP" align="center" prop="ip" /> + <el-table-column label="IP" align="center" prop="ip"/> <el-table-column label="端口" align="center" prop="port" width="100"/> <el-table-column label="用户名" align="center" prop="username" width="100"/> <el-table-column label="状态" prop="status" width="80"> <template #default="scope"> - <dict-tag :type="DICT_TYPE.NVR_ONLINE_STATUS" :value="scope.row.status" /> + <dict-tag :type="DICT_TYPE.NVR_ONLINE_STATUS" :value="scope.row.status"/> </template> </el-table-column> - <el-table-column label="位置" align="center" prop="position" /> <el-table-column label="备注" align="center" prop="remark" width="150"/> <el-table-column label="操作" align="center" min-width="110" fixed="right"> <template #default="scope"> @@ -120,7 +119,8 @@ > 删除 </el-button> - <el-button link type="success" size="small" @click="cameraHandle(scope.row.id)">摄像头</el-button> + <el-button link type="success" size="small" @click="cameraHandle(scope.row.id)">摄像头 + </el-button> </template> </el-table-column> </el-table> @@ -134,7 +134,7 @@ </ContentWrap> <!-- 表单弹窗:添加/修改 --> - <NvrForm ref="formRef" @success="getList" /> + <NvrForm ref="formRef" @success="getList"/> <!-- 弹窗, 摄像头 --> <NvrCamera ref="videoCameraRef"/> @@ -142,99 +142,100 @@ </template> <script lang="ts" setup> import {DICT_TYPE, getIntDictOptions} from '@/utils/dict' - import download from '@/utils/download' - import * as NvrApi from '@/api/data/video/nvr' - import NvrForm from './NvrForm.vue' - import NvrCamera from './NvrCamera.vue' +import download from '@/utils/download' +import * as NvrApi from '@/api/data/video/nvr' +import NvrForm from './NvrForm.vue' +import NvrCamera from './NvrCamera.vue' - defineOptions({name: 'Nvr'}) +defineOptions({name: 'Nvr'}) - const message = useMessage() // 消息弹窗 - const {t} = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const {t} = useI18n() // 国际化 - const loading = ref(true) // 列表的加载中 - const total = ref(0) // 列表的总页数 - const list = ref([]) // 列表的数据 - const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - brand: undefined, - ip: undefined, - code: undefined, - name: undefined, - status: undefined - }) - const queryFormRef = ref() // 搜索的表单 - const exportLoading = ref(false) // 导出的加载中 +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + brand: undefined, + ip: undefined, + code: undefined, + name: undefined, + status: undefined +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 - const videoCameraRef = ref() +const videoCameraRef = ref() - /** 查询列表 */ - const getList = async () => { - loading.value = true - try { - const data = await NvrApi.getNvrPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await NvrApi.getNvrPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false } +} - const cameraHandle = (id: string) => { - // devCameraVisible.value = true - videoCameraRef.value.open(id) - } +const cameraHandle = (id: string) => { + // devCameraVisible.value = true + videoCameraRef.value.open(id) +} - /** 搜索按钮操作 */ - const handleQuery = () => { - queryParams.pageNo = 1 - getList() - } +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} - /** 重置按钮操作 */ - const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() - } +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + queryParams.brand = undefined + handleQuery() +} - /** 添加/修改操作 */ - const formRef = ref() - const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) - } +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} - /** 删除按钮操作 */ - const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await NvrApi.deleteNvr(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch { - } - } - - /** 导出按钮操作 */ - const handleExport = async () => { - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - const data = await NvrApi.exportNvr(queryParams) - download.excel(data, '录像机列表.xls') - } catch { - } finally { - exportLoading.value = false - } - } - - /** 初始化 **/ - onMounted(async () => { +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await NvrApi.deleteNvr(id) + message.success(t('common.delSuccess')) + // 刷新列表 await getList() - }) + } catch { + } +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await NvrApi.exportNvr(queryParams) + download.excel(data, '录像机列表.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(async () => { + await getList() +}) </script> diff --git a/src/views/data/swagger/index.vue b/src/views/data/wiki/index.vue similarity index 80% rename from src/views/data/swagger/index.vue rename to src/views/data/wiki/index.vue index d9e9e4e..5f53507 100644 --- a/src/views/data/swagger/index.vue +++ b/src/views/data/wiki/index.vue @@ -6,7 +6,7 @@ <script lang="ts" setup> import * as ConfigApi from '@/api/infra/config' -defineOptions({ name: 'DataSwagger' }) +defineOptions({ name: 'DataWiki' }) const loading = ref(true) // 是否加载中 const src = ref(import.meta.env.VITE_BASE_URL + '/doc.html') @@ -14,7 +14,7 @@ /** 初始化 */ onMounted(async () => { try { - const data = await ConfigApi.getConfigKey('data.swagger') + const data = await ConfigApi.getConfigKey('data.wiki') if (data && data.length > 0) { src.value = data } diff --git a/src/views/model/mpk/file/MpkForm.vue b/src/views/model/mpk/file/MpkForm.vue index 6466eaf..102765c 100644 --- a/src/views/model/mpk/file/MpkForm.vue +++ b/src/views/model/mpk/file/MpkForm.vue @@ -116,7 +116,7 @@ float: right; color: var(--el-text-color-secondary); font-size: 13px;"> - <img :src="'/SimtreeUnitImage/' + item.iconName" style="height: 24px;" :alt=" item.iconDesc" /> + <img :src="staticDir + 'SimtreeUnitImage/' + item.iconName" style="height: 24px;" :alt=" item.iconDesc" /> </span> </el-option> </el-select> @@ -268,6 +268,8 @@ const route = useRoute() // 路由 const router = useRouter(); + const staticDir = ref(import.meta.env.VITE_STATIC_DIR) + const treeData = ref([]) const iconList = ref([] as MpkIconApi.MpkIconVO) const pkgNameList = ref([] as MpkPackApi.MpkPackVO) diff --git a/src/views/model/mpk/file/MpkRun.vue b/src/views/model/mpk/file/MpkRun.vue index d3ff1c9..a99ae2b 100644 --- a/src/views/model/mpk/file/MpkRun.vue +++ b/src/views/model/mpk/file/MpkRun.vue @@ -36,7 +36,7 @@ <el-divider content-position="left">模型参数信息</el-divider> <el-row :gutter="20"> <el-col :span="2" style="margin-bottom: 10px;margin-left: 20px"> - <el-button tag="a" href="/template/模型参数导入模板.xlsx" download="模型参数导入模板.xlsx" style="text-decoration: none;" type="primary" size="small" link>模板下载</el-button> + <el-button tag="a" :href="staticDir + '/template/模型参数导入模板.xlsx'" download="模型参数导入模板.xlsx" style="text-decoration: none;" type="primary" size="small" link>模板下载</el-button> </el-col> <el-col :span="2" style="margin-bottom: 10px;"> <el-upload @@ -116,6 +116,7 @@ import * as MpkApi from '@/api/model/mpk/mpk' import {FormRules} from "element-plus"; import {getAccessToken, getTenantId} from "@/utils/auth"; + const staticDir = ref(import.meta.env.VITE_STATIC_DIR) const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 diff --git a/src/views/model/mpk/icon/index.vue b/src/views/model/mpk/icon/index.vue index 8d0f95f..2f97330 100644 --- a/src/views/model/mpk/icon/index.vue +++ b/src/views/model/mpk/icon/index.vue @@ -50,7 +50,7 @@ <el-table-column prop="iconDesc" label="描述"/> <el-table-column align="center" label="图标" prop="icon" width="100"> <template #default="scope"> - <img :src="'/SimtreeUnitImage/' + scope.row.iconName" class="mpk-icon-list" :alt=" scope.row.iconDesc" /> + <img :src="staticDir + 'SimtreeUnitImage/' + scope.row.iconName" class="mpk-icon-list" :alt=" scope.row.iconDesc" /> </template> </el-table-column> <el-table-column prop="sort" label="排序"/> @@ -91,6 +91,8 @@ defineOptions({name: 'MpkIcon'}) +const staticDir = ref(import.meta.env.VITE_STATIC_DIR) + const message = useMessage() // 消息弹窗 const {t} = useI18n() // 国际化 diff --git a/src/views/model/pre/analysis/index.vue b/src/views/model/pre/analysis/index.vue index 5418745..b0939c3 100644 --- a/src/views/model/pre/analysis/index.vue +++ b/src/views/model/pre/analysis/index.vue @@ -4,37 +4,42 @@ <el-form :inline="true" :model="formData" label-width="80px"> <el-form-item label="开始时间"> <el-date-picker - size="mini" - v-model="formData.startTime" - type="datetime" - placeholder="选择日期时间"/> + v-model="formData.startTime" + type="datetime" + format="YYYY-MM-DD HH:mm:00" + value-format="YYYY-MM-DD HH:mm:00" + placeholder="选择日期时间"/> </el-form-item> <el-form-item label="结束时间"> <el-date-picker - size="mini" - v-model="formData.endTime" - type="datetime" - placeholder="选择日期时间"/> + v-model="formData.endTime" + type="datetime" + format="YYYY-MM-DD HH:mm:00" + value-format="YYYY-MM-DD HH:mm:00" + placeholder="选择日期时间"/> </el-form-item> <el-form-item label="预测时间"> <el-date-picker - size="mini" - v-model="formData.predictTime" - type="datetime" - placeholder="选择日期时间"/> + v-model="formData.predictTime" + type="datetime" + format="YYYY-MM-DD HH:mm:00" + value-format="YYYY-MM-DD HH:mm:00" + placeholder="选择日期时间"/> </el-form-item> <el-form-item label="预测频率"> - <el-input-number size="mini" v-model="formData.predictFreq" controls-position="right" :min="1" + <el-input-number v-model="formData.predictFreq" controls-position="right" + :min="1" :max="10"/> </el-form-item> <el-form-item> <el-button-group> - <el-button size="mini" type="primary" plain :icon="ArrowLeft" - v-loading="loading1" @click="leftSearchDataByRange()"/> - <el-button size="mini" type="primary" plain :icon="Search" - v-loading="loading1" @click="getList()">查询</el-button> - <el-button size="mini" type="primary" plain :icon="ArrowRight" - v-loading="loading1" @click="rightSearchDataByRange()"/> + <el-button type="primary" plain :icon="ArrowLeft" + :loading="loading1" @click="leftSearchDataByRange()"/> + <el-button type="primary" plain :icon="Search" + :loading="loading1" @click="getList()">查询 + </el-button> + <el-button type="primary" plain :icon="ArrowRight" + :loading="loading1" @click="rightSearchDataByRange()"/> </el-button-group> </el-form-item> @@ -42,46 +47,52 @@ <div class="his-body-left"> <div class="his-body-tree"> <el-tree - :data="treeData" - show-checkbox - node-key="id" - ref="tree" - highlight-current - :props="defaultProps" - @check="onCheckTree"/> + :data="treeData" + show-checkbox + node-key="id" + ref="tree" + highlight-current + :props="defaultProps" + @check="onCheckTree"/> </div> </div> <div class="his-body-right"> <div class="his-body-chart"> - <el-form :inline="true" :model="calRateForm" :rules="formRules" ref="calRateForm" label-width="108px"> + <el-form :inline="true" :model="calRateForm" :rules="formRules" ref="calRateFormRef" + label-width="108px"> <el-row> - <el-col :span="6" > + <el-col :span="6"> <el-form-item label="预测项" prop="calItem" style="width: 90%"> - <el-select v-model="calRateForm.calItem" @change="calItemBaseVale" placeholder="请选择"> + <el-select size="small" v-model="calRateForm.calItem" + @change="calItemBaseVale" + placeholder="请选择"> <el-option - v-for="item in formData.checkedItemData" - :key="item.id" - :label="item.label" - :value="item.id"/> + v-for="itemOut in formData.checkedItemData" + :key="itemOut.id" + :label="itemOut.label" + :value="itemOut.id"/> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="精准度偏差" prop="IN_DEVIATION"> - <el-input-number size="mini" v-model="calRateForm.IN_DEVIATION" controls-position="right" :min="1" + <el-input-number size="small" v-model="calRateForm.IN_DEVIATION" + controls-position="right" :min="1" :max="10"/> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="不可信率偏差" prop="OUT_DEVIATION"> - <el-input-number size="mini" v-model="calRateForm.OUT_DEVIATION" controls-position="right" + <el-input-number size="small" v-model="calRateForm.OUT_DEVIATION" + controls-position="right" :min="1" :max="20"/> </el-form-item> </el-col> <el-col :span="4"> <el-form-item> - <el-button size="mini" type="primary" plain :loading="loading2" @click="calAccuracyRate">计算精准度 + <el-button size="small" type="primary" plain :loading="loading2" + @click="calAccuracyRate">计算精准度 </el-button> </el-form-item> </el-col> @@ -89,54 +100,54 @@ <el-row> <el-col :span="4"> <el-form-item label="精准度:"> - {{calRateForm.IN_ACCURACY_RATE}}% + {{ calRateForm.IN_ACCURACY_RATE }}% </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="预测平均值:"> - {{calRateForm.itemPreAvg}} + {{ calRateForm.itemPreAvg }} </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="预测最大值:"> - {{calRateForm.itemPreMax}} + {{ calRateForm.itemPreMax }} </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="预测最小值:"> - {{calRateForm.itemPreMin}} + {{ calRateForm.itemPreMin }} </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="预测累积量:"> - {{calRateForm.preCumulant}} + {{ calRateForm.preCumulant }} </el-form-item> </el-col> </el-row> <el-row> <el-col :span="4"> <el-form-item label="不可信率:"> - {{calRateForm.OUT_ACCURACY_RATE}}% + {{ calRateForm.OUT_ACCURACY_RATE }}% </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="真实平均值:"> - {{calRateForm.itemAvg}} + {{ calRateForm.itemAvg }} </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="真实最大值:"> - {{calRateForm.itemMax}} + {{ calRateForm.itemMax }} </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="真实最小值:"> - {{calRateForm.itemMin}} + {{ calRateForm.itemMin }} </el-form-item> </el-col> <el-col :span="4"> <el-form-item label="真实累积量:"> - {{calRateForm.realCumulant}} + {{ calRateForm.realCumulant }} </el-form-item> </el-col> </el-row> @@ -146,54 +157,506 @@ <el-col :span="12"> <el-form-item label="数据类型"> <el-checkbox-group v-model="formData.chartCheck" @change="changeChartCheck"> - <el-checkbox v-for="item in formData.chartOptions" :label="item" :key="item">{{item}} + <el-checkbox v-for="item in formData.chartOptions" :label="item" + :key="item">{{ item }} </el-checkbox> </el-checkbox-group> </el-form-item> </el-col> <el-col :span="6"> <el-form-item> - <el-radio v-model="formData.isMultipleY" :label="false" @input="onChangeMultipleY">单坐标轴</el-radio> - <el-radio v-model="formData.isMultipleY" :label="true" @input="onChangeMultipleY">多坐标轴</el-radio> + <el-radio v-model="formData.isMultipleY" :label="false" + @input="onChangeMultipleY">单坐标轴 + </el-radio> + <el-radio v-model="formData.isMultipleY" :label="true" + @input="onChangeMultipleY">多坐标轴 + </el-radio> </el-form-item> </el-col> </el-row> </el-form> - <div id="data-analysis" style="height: 500px;"></div> + <div ref="dataAnalysisChart" style="height: 500px;"></div> </div> </div> </div> </el-form> - </div> </el-card> </template> <script lang="ts" setup> - import {getYMDHMS} from "@/utils/dateUtil" - import * as CategoryApi from "@/api/data/ind/category"; - import * as DmModule from '@/api/model/pre/dm' - import * as ItemApi from "@/api/data/ind/item/item"; - import * as MmPredictItem from '@/api/model/pre/predict' - import * as echarts from "echarts"; - import { onMounted, ref } from 'vue'; - import { Search, ArrowLeft, ArrowRight,} from '@element-plus/icons-vue' +import {getYMDHMS} from "@/utils/dateUtil" +import * as McsApi from '@/api/model/mcs' +import * as echarts from "echarts"; +import {Search, ArrowLeft, ArrowRight,} from '@element-plus/icons-vue' - defineOptions({name: 'AnalysisformData'}) +defineOptions({name: 'AnalysisformData'}) - const message = useMessage() // 消息弹窗 - const { t } = useI18n() // 国际化 - const dataCategoryList = ref([] as CategoryApi.IndItemCategoryVO[]) - const loading1 = ref(false) // 列表的加载中 - const loading2 = ref(false) // 列表的加载中 - const total = ref(0) // 列表的总页数 - const list = ref([]) // 字典表格数据 - const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - itemno: '', - itemname: '', +const message = useMessage() // 消息弹窗 +const {t} = useI18n() // 国际化 +const dataAnalysisChart = ref(null); +const loading1 = ref(false) // 列表的加载中 +const loading2 = ref(false) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 字典表格数据 +let formData = ref({ + rangeDate: '', + startTime: '', + endTime: '', + predictTime: '', + predictTimeStr: '', + startTimeStr: '', + endTimeStr: '', + predictTimeStamp: 0, + startTimeStamp: 0, + endTimeStamp: 0, + currentStamp: '', + currentStamp60: '', + predictStamp: '', + chartCheck: ['T+L', '真实值'], + chartOptions: ['T+N', 'T+L', '当时', '真实值', '调整值'], + checkedItemData: [], + backItem: '', + backValue: 0, + backCoe: 1, + preCumulant: 0, + realCumulant: 0, + queryStep: 2, + isMultipleYRadio: '单坐标轴', + isMultipleY: false, + predictFreq: 3, +}) +const calRateFormRef = ref() +const calRateForm = ref({ + calItem: undefined, + IN_DEVIATION: 0, + OUT_DEVIATION: 0, + IN_ACCURACY_RATE: 0, + OUT_ACCURACY_RATE: 0, + itemAvg: 0, + itemMax: 0, + itemMin: 0, + itemPreAvg: 0, + itemPreMax: 0, + itemPreMin: 0, + preCumulant: 0, + realCumulant: 0 +}) +let itemData = ref({ + currentTreeList: [], + chart: {}, + option: {} +}) +const treeData = ref([]) +const itemDataObject = ref() +const timer = ref() +let myChart = null; + +const formRules = reactive({ + calItem: [{required: true, message: '预测项不能为空', trigger: 'blur'}], + IN_DEVIATION: [{required: true, message: '精准度偏差不能为空', trigger: 'blur'}], + OUT_DEVIATION: [{required: true, message: '不可信率偏差不能为空', trigger: 'blur'}], +}) + +/** 查询列表 */ +const getList = async () => { + loading1.value = true + try { + if (!formData.value.chartCheck) { + formData.value.chartCheck = ['真实值'] + } + let chartCheckArray = formData.value.chartCheck; + if (!formData.value.checkedItemData || formData.value.checkedItemData.length == 0) { + itemData.value.option = {}; + return; + } + let outIds = formData.value.checkedItemData.map(item => { + return item.id + }) + const params = reactive({ + outIds: outIds, + predictTime: formData.value.predictTime, + startTime: formData.value.startTime, + endTime: formData.value.endTime + }) + const data = await McsApi.getPreDataCharts(params) + formData.value.predictTime = data.predictTime; + formData.value.startTime = data.startTime + formData.value.endTime = data.endTime + + let xAxisData = data.categories; + let yAxisData = []; + let offset = 0; + let yAxisIndex = 0; + let legendData = []; + let yMaxArr = []; + let seriesData = []; + seriesData.push({ + name: '', + data: [null], + type: 'line', + smooth: true, + color: 'green', + markLine: { + silent: true, + lineStyle: { + color: '#32a487', + width: 2 + }, + data: [{ + xAxis: formData.value.predictTime + }], + label: { + normal: { + formatter: formData.value.predictTime + } + }, + symbol: ['circle', 'none'], + }, + }); + itemDataObject.value = {} + for (let i = 0; i < data.dataViewList.length; i++) { + let dataView = data.dataViewList[i] + itemDataObject.value[dataView.outId] = dataView; + let maxValue = dataView.maxValue; + let minValue = dataView.minValue; + yAxisIndex = formData.value.isMultipleY ? i : 0; + let yMax = maxValue; + if (maxValue < 0) { + maxValue = 1; + } else if (maxValue < 10) { + yMax = (Math.ceil(maxValue * 11) / 10).toFixed(1); + } else if (maxValue < 100) { + yMax = (Math.ceil(maxValue * 1.1 / 5) * 5); + } else { + yMax = (Math.ceil(maxValue * 1.1 / 10) * 10); + } + yMaxArr.push(yMax); + let yMin = minValue; + if (minValue >= 0) { + yMin = 0; + } else if (minValue > -10) { + yMin = (Math.floor(minValue * 11) / 10).toFixed(1); + } else if (minValue > -100) { + yMin = (Math.floor(minValue * 1.1 / 5) * 5); + } else { + yMin = (Math.floor(minValue * 1.1 / 10) * 10); + } + yAxisData.push({ + type: 'value', + name: "", + min: yMin, + max: yMax, + position: 'left', + offset: offset, + splitLine: { + show: false + }, + axisLine: { + show: true, + lineStyle: {} + }, + axisLabel: { + formatter: '{value}' + } + }) + offset = offset + 40 + if (chartCheckArray.indexOf('真实值') !== -1) { + let legendName = dataView.resultstr + '(真实)'; + legendData.push(legendName); + seriesData.push({ + name: legendName, + data: dataView.realData || [], + type: 'line', + yAxisIndex: yAxisIndex, + showSymbol: false, + smooth: true, + lineStyle: { + width: 2 + } + }); + } + if (chartCheckArray.indexOf('T+N') !== -1) { + let legendName = dataView.resultstr + '(T+N)'; + seriesData.push({ + name: legendName, + data: dataView.preDataN || [], + type: 'line', + yAxisIndex: yAxisIndex, + showSymbol: false, + smooth: true, + lineStyle: { + width: 2 + } + }); + } + if (chartCheckArray.indexOf('T+L') !== -1) { + let legendName = dataView.resultstr + '(T+L)'; + legendData.push(legendName); + seriesData.push({ + name: legendName, + data: dataView.preDataL || [], + type: 'line', + showSymbol: false, + connectNulls: true, + yAxisIndex: yAxisIndex, + smooth: true, + lineStyle: { + width: 2 + } + }); + } + if (chartCheckArray.indexOf('当时') !== -1) { + let legendName = dataView.resultstr + '(当时)'; + legendData.push(legendName); + seriesData.push({ + name: legendName, + data: dataView.curData || [], + type: 'line', + yAxisIndex: yAxisIndex, + showSymbol: false, + smooth: true, + lineStyle: { + width: 2 + } + }); + } + if (chartCheckArray.indexOf('调整值') !== -1) { + let legendName = dataView.resultstr + '(调整值)'; + legendData.push(legendName); + seriesData.push({ + name: legendName, + data: dataView.adjData || [], + type: 'line', + yAxisIndex: yAxisIndex, + showSymbol: false, + connectNulls: true, + smooth: true, + lineStyle: { + width: 2, + type: 'dashed' + } + }); + } + } + //如果最大值相差不大,改成一致大小 + if (yMaxArr.length > 1) { + let max = Math.max.apply(null, yMaxArr); + let min = Math.min.apply(null, yMaxArr); + if (Math.abs((max - min) / max) <= 0.2) { + for (let i = 0; i < yAxisData.length; i++) { + yAxisData[i].max = max; + } + } + } + myChart = echarts.init(dataAnalysisChart.value); + let option = { + title: { + text: '' + }, + tooltip: { + trigger: 'axis' + }, + legend: { + show: true, + data: legendData, + top: 10 + }, + grid: { + top: '20%', + left: '3%', + right: '6%', + bottom: '3%', + containLabel: true + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: xAxisData + }, + yAxis: formData.value.isMultipleY ? yAxisData : { + type: 'value', + splitLine: {show: false}, + axisLine: {show: true} + }, + dataZoom: [ + { + type: 'inside', + start: 0, + end: 100 + }, + { + start: 0, + end: 10 + } + ], + series: seriesData + } + myChart.clear() + myChart.setOption(option) + } finally { + loading1.value = false + } +} + +onMounted(() => { + resetForm() + getPreItemTree() +}) + +async function getPreItemTree() { + treeData.value = await McsApi.getPredictItemTree() +} + +function leftSearchDataByRange() { + let mins = getRangeMins(); + let startTime = formData.value.startTime; + let endTime = formData.value.endTime; + let predictTime = formData.value.predictTime; + if (predictTime) { + predictTime = getYMDHMS(new Date(predictTime) - 1000 * 60 * mins); + formData.value.predictTime = predictTime; + } + if (startTime) { + startTime = getYMDHMS(new Date(startTime) - 1000 * 60 * mins); + formData.value.startTime = startTime; + } + if (endTime) { + endTime = getYMDHMS(new Date(endTime) - 1000 * 60 * mins); + formData.value.endTime = endTime; + } + getList(); +} + +function getRangeMins() { + let result: string | number = 0; + if (formData.value.startTime && formData.value.endTime) { + let startStamp = new Date(formData.value.startTime).getTime(); + let endStamp = new Date(formData.value.endTime).getTime(); + let queryStep = ((endStamp - startStamp) / (1000 * 60)).toFixed(0); + result = queryStep >= 0 ? queryStep : 0; + } + return result; +} + +function onCheckTree(data, checked, indeterminate) { + formData.value.checkedItemData = []; + if (checked.checkedNodes) { + formData.value.checkedItemData = [...checked.checkedNodes] + } + debounce(getList, 1000); +} + +function debounce(func, wait) { + let args = []; + if (timer.value) { + clearTimeout(timer.value); + } + timer.value = setTimeout(() => { + func.apply(this, args); + timer.value = null; + }, wait) +} + +function calItemBaseVale() { + if (!calRateForm.value.calItem) { + calRateForm.value.itemPreMax = 0; + calRateForm.value.itemPreMin = 0; + calRateForm.value.itemPreAvg = 0; + calRateForm.value.preCumulant = 0; + calRateForm.value.itemMax = 0; + calRateForm.value.itemMin = 0; + calRateForm.value.itemAvg = 0; + calRateForm.value.realCumulant = 0; + } else { + let dataView = itemDataObject.value[calRateForm.value.calItem] + calRateForm.value.itemPreMax = dataView.preMax; + calRateForm.value.itemPreMin = dataView.preMin; + calRateForm.value.itemPreAvg = dataView.preAvg; + calRateForm.value.preCumulant = dataView.preCumulant; + calRateForm.value.itemMax = dataView.hisMax; + calRateForm.value.itemMin = dataView.hisMin; + calRateForm.value.itemAvg = dataView.hisAvg; + calRateForm.value.realCumulant = dataView.hisCumulant; + } +} + +function calAccuracyRate() { + this.$refs['calRateForm'].validate((valid) => { + if (!valid) { + return false + } + let dataView = itemDataObject[calRateForm.value.calItem] + let seriesReaData = dataView.realData; + let seriesPreData = dataView.preDataL; + if (seriesReaData == null || seriesPreData == null || + seriesReaData.length === 0 || seriesPreData.length === 0) { + loading2.value = false; + return; + } + let predictValueMap = {}; + seriesPreData.forEach(function (item) { + predictValueMap[item[0]] = item[1]; + }) + let pointValueMap = {}; + seriesReaData.forEach(function (item) { + pointValueMap[item[0]] = item[1]; + }) + let inDeviation = Number(calRateForm.value.IN_DEVIATION); + let outDeviation = Number(calRateForm.value.OUT_DEVIATION); + if (inDeviation === 0 && outDeviation === 0) { + loading2.value = false; + return; + } + let inDeviationCount = 0; + let outDeviationCount = 0; + let totalCount = 0; + for (let key in predictValueMap) { + let predictValue = predictValueMap[key]; + let pointValue = pointValueMap[key]; + if (pointValue == null || "" === pointValue || predictValue == null || "" === predictValue) { + continue; + } + let deviationAbs = (predictValue - pointValue) >= 0 ? (predictValue - pointValue) : (predictValue - pointValue) * -1; + if (deviationAbs < inDeviation) { + inDeviationCount = inDeviationCount + 1; + } + if (deviationAbs > outDeviation) { + outDeviationCount = outDeviationCount + 1; + } + totalCount = totalCount + 1; + } + + let rateIn = (inDeviationCount / totalCount * 100).toFixed(2); + let rateOut = (outDeviationCount / totalCount * 100).toFixed(2); + calRateForm.value.IN_ACCURACY_RATE = Number(rateIn); + calRateForm.value.OUT_ACCURACY_RATE = Number(rateOut); + loading2.value = false; }) - let formData = ref({ +} + +function rightSearchDataByRange() { + let mins = getRangeMins(); + let startTime = formData.value.startTime; + let endTime = formData.value.endTime; + let predictTime = formData.value.predictTime; + if (predictTime) { + predictTime = getYMDHMS(new Date(predictTime) - 0 + 1000 * 60 * mins); + formData.value.predictTime = predictTime; + } + if (startTime) { + startTime = getYMDHMS(new Date(startTime) - 0 + 1000 * 60 * mins); + formData.value.startTime = startTime; + } + if (endTime) { + endTime = getYMDHMS(new Date(endTime) - 0 + 1000 * 60 * mins); + formData.value.endTime = endTime; + } + getList(); +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { rangeDate: '', startTime: '', endTime: '', @@ -219,9 +682,9 @@ isMultipleYRadio: '单坐标轴', isMultipleY: false, predictFreq: 3, - }) - let calRateForm = ref({ - calItem: '', + } + calRateForm.value = { + calItem: undefined, IN_DEVIATION: 0, OUT_DEVIATION: 0, IN_ACCURACY_RATE: 0, @@ -232,462 +695,47 @@ itemPreAvg: 0, itemPreMax: 0, itemPreMin: 0, - preCumulant:0, - realCumulant:0 - }) - let itemData = ref({ - currentTreeList: [], - chart: {}, - option: {} - }) - const chartContainer = ref(null); - const treeData = ref([]) - const itemDataObject = ref() - const timer = ref() - - const formRules = reactive({ - calItem: [{required: true, message: '预测项不能为空', trigger: 'blur'}], - IN_DEVIATION: [{required: true, message: '精准度偏差不能为空', trigger: 'blur'}], - OUT_DEVIATION: [{required: true, message: '不可信率偏差不能为空', trigger: 'blur'}], - }) - //const myChart = echarts.init(document.getElementById("data-analysis")); - /** 查询列表 */ - const getList = async () => { - loading1.value = true - try { - const data = formData.value - if (!formData.value.chartCheck) { - formData.value.chartCheck = ['真实值'] - } - let chartCheckArray = formData.value.chartCheck; - if (!formData.value.checkedItemData || formData.value.checkedItemData.length == 0) { - itemData.value.option = {}; - return; - } - let itemIdList = formData.value.checkedItemData.map(item => { - return item.id - }) - const params = ref({ - itemIds: itemIdList.join(','), - predictTime: formData.value.predictTime, - startTime: formData.value.startTime, - endTime: formData.value.endTime - }) - const res = await MmPredictItem.getViewCharts(params) - if (res.code !== 0) { - return message.error(res.msg) - } - formData.value.predictTime = res.data.predictTime; - formData.value.startTime = res.data.startTime - formData.value.endTime = res.data.endTime - - let xAxisData = res.data.categories; - let yAxisData = []; - let offset = 0; - let yAxisIndex = 0; - let legendData = []; - let yMaxArr = []; - let seriesData = []; - seriesData.push({ - name: '', - data: [null], - type: 'line', - smooth: true, - color: 'green', - markLine: { - silent: true, - lineStyle: { - color: '#32a487', - width: 2 - }, - data: [{ - xAxis: formData.value.predictTime - }], - label: { - normal: { - formatter: formData.value.predictTime - } - }, - symbol: ['circle', 'none'], - }, - }); - itemDataObject.value = {} - for (let i = 0; i < res.data.dataViewList.length; i++) { - let dataView = res.data.dataViewList[i] - itemDataObject.value.dataView.itemId = dataView; - let maxValue = dataView.maxValue; - let minValue = dataView.minValue; - yAxisIndex = formData.value.isMultipleY ? i : 0; - let yMax = maxValue; - if (maxValue < 0) { - maxValue = 1; - } else if (maxValue < 10) { - yMax = (Math.ceil(maxValue * 11) / 10).toFixed(1); - } else if (maxValue < 100) { - yMax = (Math.ceil(maxValue * 1.1 / 5) * 5); - } else { - yMax = (Math.ceil(maxValue * 1.1 / 10) * 10); - } - yMaxArr.push(yMax); - let yMin = minValue; - if (minValue >= 0) { - yMin = 0; - } else if (minValue > -10) { - yMin = (Math.floor(minValue * 11) / 10).toFixed(1); - } else if (minValue > -100) { - yMin = (Math.floor(minValue * 1.1 / 5) * 5); - } else { - yMin = (Math.floor(minValue * 1.1 / 10) * 10); - } - yAxisData.push({ - type: 'value', - name: "", - min: yMin, - max: yMax, - position: 'left', - offset: offset, - splitLine: { - show: false - }, - axisLine: { - show: true, - lineStyle: {} - }, - axisLabel: { - formatter: '{value}' - } - }) - offset = offset + 40 - if (chartCheckArray.indexOf('真实值') !== -1) { - let legendName = dataView.itemName + '(真实)'; - legendData.push(legendName); - seriesData.push({ - name: legendName, - data: dataView.realData || [], - type: 'line', - yAxisIndex: yAxisIndex, - showSymbol: false, - smooth: true, - lineStyle: { - width: 3 - } - }); - } - if (chartCheckArray.indexOf('T+N') !== -1) { - let legendName = dataView.itemName + '(T+N)'; - seriesData.push({ - name: legendName, - data: dataView.preDataN || [], - type: 'line', - yAxisIndex: yAxisIndex, - showSymbol: false, - smooth: true, - lineStyle: { - width: 3 - } - }); - } - if (chartCheckArray.indexOf('T+L') !== -1) { - let legendName = dataView.itemName + '(T+L)'; - legendData.push(legendName); - seriesData.push({ - name: legendName, - data: dataView.preDataL || [], - type: 'line', - showSymbol: false, - connectNulls: true, - yAxisIndex: yAxisIndex, - smooth: true, - lineStyle: { - width: 3 - } - }); - } - if (chartCheckArray.indexOf('当时') !== -1) { - let legendName = dataView.itemName + '(当时)'; - legendData.push(legendName); - seriesData.push({ - name: legendName, - data: dataView.curData || [], - type: 'line', - yAxisIndex: yAxisIndex, - showSymbol: false, - smooth: true, - lineStyle: { - width: 3 - } - }); - } - if (chartCheckArray.indexOf('调整值') !== -1) { - let legendName = dataView.itemName + '(调整值)'; - legendData.push(legendName); - seriesData.push({ - name: legendName, - data: dataView.adjData || [], - type: 'line', - yAxisIndex: yAxisIndex, - showSymbol: false, - connectNulls: true, - smooth: true, - lineStyle: { - width: 3, - type: 'dashed' - } - }); - } - } - //如果最大值相差不大,改成一致大小 - if (yMaxArr.length > 1) { - let max = Math.max.apply(null, yMaxArr); - let min = Math.min.apply(null, yMaxArr); - if (Math.abs((max - min) / max) <= 0.2) { - for (let i = 0; i < yAxisData.length; i++) { - yAxisData[i].max = max; - } - } - } - let option = { - title: { - text: '' - }, - tooltip: { - trigger: 'axis' - }, - legend: { - show: true, - data: legendData, - top: 10 - }, - grid: { - top: 50, - left: '3%', - right: '6%', - bottom: '3%', - containLabel: true - }, - xAxis: { - type: 'category', - boundaryGap: false, - data: xAxisData - }, - yAxis: formData.value.isMultipleY ? yAxisData : { - type: 'value', - splitLine: {show: false}, - axisLine: {show: true} - }, - dataZoom: [ - { - type: 'inside', - start: 0, - end: 100 - }, - { - start: 0, - end: 10 - } - ], - series: seriesData - } - //chart.setOption(option) - } finally { - loading1.value = false - } + preCumulant: 0, + realCumulant: 0 } - - onMounted(() => { - getPreItemTree() - getList() - }) - - async function getPreItemTree() { - treeData.value = await MmPredictItem.getMmPredictItemTree() - } - - function leftSearchDataByRange() { - let mins = getRangeMins(); - let startTime = formData.value.startTime; - let endTime = formData.value.endTime; - let predictTime = formData.value.predictTime; - if (predictTime) { - predictTime = getYMDHMS(new Date(predictTime) - 1000 * 60 * mins); - formData.value.predictTime = predictTime; - } - if (startTime) { - startTime = getYMDHMS(new Date(startTime) - 1000 * 60 * mins); - formData.value.startTime = startTime; - } - if (endTime) { - endTime = getYMDHMS(new Date(endTime) - 1000 * 60 * mins); - formData.value.endTime = endTime; - } - getList(); - } - - function getRangeMins () { - let result: string | number = 0; - if(formData.value.startTime && formData.value.endTime) { - let startStamp = new Date(formData.value.startTime).getTime(); - let endStamp = new Date(formData.value.endTime).getTime(); - let queryStep = ((endStamp - startStamp) / (1000 * 60)).toFixed(0); - result = queryStep >= 0 ? queryStep : 0; - } - return result; - } - - function onCheckTree(data, checked, indeterminate) { - formData.value.checkedItemData = []; - if (checked.checkedNodes) { - formData.value.checkedItemData = [...checked.checkedNodes] - } - //myChart.clear() - debounce(getList(), 1000); - } - - function debounce(func, wait) { - let args = []; - if (timer.value) { - clearTimeout(timer.value); - } - timer.value = setTimeout(() => { - func.apply(this, args); - timer.value = null; - }, wait) - } - - function calItemBaseVale() { - if (!calRateForm.value.calItem) { - calRateForm.value.itemPreMax = 0; - calRateForm.value.itemPreMin = 0; - calRateForm.value.itemPreAvg = 0; - calRateForm.value.preCumulant = 0; - calRateForm.value.itemMax = 0; - calRateForm.value.itemMin = 0; - calRateForm.value.itemAvg = 0; - calRateForm.value.realCumulant = 0; - return - } else { - let dataView = itemDataObject[calRateForm.value.calItem] - calRateForm.value.itemPreMax = dataView.preMax; - calRateForm.value.itemPreMin = dataView.preMin; - calRateForm.value.itemPreAvg = dataView.preAvg; - calRateForm.value.preCumulant = dataView.preCumulant; - calRateForm.value.itemMax = dataView.hisMax; - calRateForm.value.itemMin = dataView.hisMin; - calRateForm.value.itemAvg = dataView.hisAvg; - calRateForm.value.realCumulant = dataView.hisCumulant; - } - } - - function calAccuracyRate() { - this.$refs['calRateForm'].validate((valid) => { - if (!valid) { - return false - } - let dataView = itemDataObject[calRateForm.value.calItem] - let seriesReaData = dataView.realData; - let seriesPreData = dataView.preDataL; - if (seriesReaData == null || seriesPreData == null || - seriesReaData.length === 0 || seriesPreData.length === 0) { - loading2.value = false; - return; - } - let predictValueMap = {}; - seriesPreData.forEach(function (item) { - predictValueMap[item[0]] = item[1]; - }) - let pointValueMap = {}; - seriesReaData.forEach(function (item) { - pointValueMap[item[0]] = item[1]; - }) - let inDeviation = Number(calRateForm.value.IN_DEVIATION); - let outDeviation = Number(calRateForm.value.OUT_DEVIATION); - if (inDeviation === 0 && outDeviation === 0) { - loading2.value = false; - return; - } - let inDeviationCount = 0; - let outDeviationCount = 0; - let totalCount = 0; - for (let key in predictValueMap) { - let predictValue = predictValueMap[key]; - let pointValue = pointValueMap[key]; - if (pointValue == null || "" === pointValue || predictValue == null || "" === predictValue) { - continue; - } - let deviationAbs = (predictValue - pointValue) >= 0 ? (predictValue - pointValue) : (predictValue - pointValue) * -1; - if (deviationAbs < inDeviation) { - inDeviationCount = inDeviationCount + 1; - } - if (deviationAbs > outDeviation) { - outDeviationCount = outDeviationCount + 1; - } - totalCount = totalCount + 1; - } - - let rateIn = (inDeviationCount / totalCount * 100).toFixed(2); - let rateOut = (outDeviationCount / totalCount * 100).toFixed(2); - calRateForm.value.IN_ACCURACY_RATE = Number(rateIn); - calRateForm.value.OUT_ACCURACY_RATE = Number(rateOut); - loading2.value = false; - }) - } - - function rightSearchDataByRange() { - let mins = getRangeMins(); - let startTime = formData.value.startTime; - let endTime = formData.value.endTime; - let predictTime = formData.value.predictTime; - if (predictTime) { - predictTime = getYMDHMS(new Date(predictTime) - 0 + 1000 * 60 * mins); - formData.value.predictTime = predictTime; - } - if (startTime) { - startTime = getYMDHMS(new Date(startTime) - 0 + 1000 * 60 * mins); - formData.value.startTime = startTime; - } - if (endTime) { - endTime = getYMDHMS(new Date(endTime) - 0 + 1000 * 60 * mins); - formData.value.endTime = endTime; - } - getList(); - } - + calRateFormRef.value?.resetFields() +} </script> <style scoped> - .el-form-item { - margin-bottom: 0 !important; - } +.el-form-item { + margin-bottom: 0 !important; +} - .his-body-chart { - height: 100%; - border: 1px solid lightgray; - padding: 10px; - } +.his-body-chart { + height: 100%; + border: 1px solid lightgray; + padding: 10px; +} - .his-body-tree { - height: 100%; - border: 1px solid lightgray; - padding: 10px; - } +.his-body-tree { + height: 100%; + border: 1px solid lightgray; + padding: 10px; +} - .his-body-right { - width: 80%; - height: 100%; - padding-top: 10px; - } +.his-body-right { + width: 80%; + height: 100%; + padding-top: 10px; +} - .his-body-left { - width: 20%; - height: 100%; - padding: 10px 10px 0 0; - } +.his-body-left { + width: 20%; + height: 100%; + padding: 10px 10px 0 0; +} - .his-body { - width: 100%; - height: calc(calc(100vh - 48px - 38px - 130px)); - display: flex; - flex-direction: row; - justify-content: flex-start; - align-content: flex-start; - } +.his-body { + width: 100%; + height: calc(calc(100vh - 68px - 38px - 160px)); + display: flex; + flex-direction: row; + justify-content: flex-start; + align-content: flex-start; +} </style> diff --git a/src/views/model/pre/item/MmPredictItemChart.vue b/src/views/model/pre/item/MmPredictItemChart.vue new file mode 100644 index 0000000..a0f867a --- /dev/null +++ b/src/views/model/pre/item/MmPredictItemChart.vue @@ -0,0 +1,253 @@ +<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 label="开始时间"> + <el-date-picker + size="mini" + v-model="dataForm.startTime" + format="YYYY-MM-DD HH:mm:00" + value-format="YYYY-MM-DD HH:mm:00" + type="datetime" + :clearable="false" + placeholder="选择日期时间"/> + </el-form-item> + <el-form-item label="结束时间"> + <el-date-picker + size="mini" + v-model="dataForm.endTime" + format="YYYY-MM-DD HH:mm:00" + value-format="YYYY-MM-DD HH:mm:00" + type="datetime" + :clearable="false" + 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" + > + <Icon icon="ep:download"/> + 导出 + </el-button> + </el-form-item> + </el-form> + <div ref="chartDomPre" class="result-chart"></div> + </el-dialog> +</template> + +<script lang="ts" setup> +import {ref} from 'vue'; +import * as echarts from 'echarts'; +import * as McsApi from '@/api/model/mcs' +import {getYMDHM0} from "@/utils/dateUtil" +import download from "@/utils/download"; + +const message = useMessage() // 消息弹窗 +const visible = ref(false); +const chartDomPre = ref(null); +let myChart = null; +const chartParams = reactive({ + itemId: undefined, + startTime: undefined, + endTime: undefined, +}) +const dataForm = ref({ + id: "", + itemName: "", + startTime: getYMDHM0(new Date() - 60 * 60 * 1000), + endTime: getYMDHM0(new Date() + 60 * 60 * 1000), +}); + +/** 打开弹窗 */ +const open = async (row: object) => { + visible.value = true + resetForm() + dataForm.value.id = row.id; + dataForm.value.itemName = row.itemname; + if (row.id) { + getDataList(); + } +} + +defineExpose({open}) // 提供 open 方法,用于打开弹窗 + +async function getDataList() { + visible.value = true; + if (dataForm.value.id) { + try { + chartParams.itemId = dataForm.value.id; + chartParams.startTime = dataForm.value.startTime; + chartParams.endTime = dataForm.value.endTime; + const data = await McsApi.getPreDataItemChart(chartParams) + let legendData = [] + if (data.legend && data.legend.length > 0) { + data.legend.forEach(item => { + legendData.push(item + ":" + '真实值') + legendData.push(item + ":" + '预测值') + }) + } + + let seriesData = [] + if (data.predictTime) { + seriesData.push({ + name: '', + data: [null], + type: 'line', + smooth: true, + color: 'green', + markLine: { + silent: true, + lineStyle: { + color: '#32a487', + width: 2 + }, + data: [{ + xAxis: data.predictTime + }], + label: { + normal: { + formatter: data.predictTime + } + }, + symbol: ['circle', 'none'], + }, + }); + } + + if (data.viewMap) { + Object.keys(data.viewMap).forEach(key => { + let viewData = data.viewMap[key] + seriesData.push({ + name: key + ":" + '真实值', + type: "line", + data: viewData.realData, + showSymbol: false, + smooth: false, + lineStyle: { + normal: { + width: 1, + }, + }, + }) + seriesData.push({ + name: key + ":" + '预测值', + type: "line", + data: viewData.preDataN, + showSymbol: false, + smooth: false, + lineStyle: { + normal: { + width: 1, + }, + }, + }) + }) + } + + myChart = echarts.init(chartDomPre.value); + const option = { + title: { + text: dataForm.value.itemName, + top: 0, + left: "1%", + textStyle: { + fontSize: 14, + }, + }, + tooltip: { + trigger: "axis", + axisPointer: { + type: "line", + lineStyle: { + color: "#cccccc", + width: "1", + type: "dashed", + }, + }, + }, + legend: { + show: true, + top: 20, + data: legendData + }, + grid: { + top: "20%", + 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 () => { + chartParams.itemId = dataForm.value.id; + chartParams.startTime = dataForm.value.startTime?dataForm.value.startTime:""; + chartParams.endTime = dataForm.value.endTime?dataForm.value.endTime:""; + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await McsApi.exportPredictValue(chartParams) + download.excel(data, dataForm.value.itemName + '.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + dataForm.value = { + id: undefined, + itemName: undefined, + startTime: undefined, + endTime: undefined + } +} +</script> +<style> +.el-select { + width: 100%; +} + +.result-chart { + height: 500px; +} +</style> diff --git a/src/views/model/pre/item/MmPredictItemForm.vue b/src/views/model/pre/item/MmPredictItemForm.vue index 9e5fb9f..cb01f79 100644 --- a/src/views/model/pre/item/MmPredictItemForm.vue +++ b/src/views/model/pre/item/MmPredictItemForm.vue @@ -17,7 +17,8 @@ </el-col> <el-col :span="12"> <el-form-item label="编号" prop="mmPredictItem.itemno"> - <el-input v-model="dataForm.mmPredictItem.itemno" placeholder="编号" maxlength="50" readonly/> + <el-input v-model="dataForm.mmPredictItem.itemno" placeholder="编号" maxlength="50" + readonly/> </el-form-item> </el-col> </el-row> @@ -39,7 +40,7 @@ <el-form-item label="粒度" prop="mmPredictItem.granularity"> <el-select v-model="dataForm.mmPredictItem.granularity" placeholder="请选择"> <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.TIME_GRANULARITY)" + v-for="dict in getIntDictOptions(DICT_TYPE.PRED_GRANULARITY)" :key="dict.value" :label="dict.label" :value="dict.value" @@ -99,21 +100,6 @@ controls-position="right"/> </el-form-item> </el-col> - <el-col :span="12"> - <el-form-item label="数据点" prop="mmItemOutput.pointid"> - <el-select - v-model="dataForm.mmItemOutput.pointid" - filterable - @change="changeOutputPoint" - placeholder="请选择"> - <el-option - v-for="item in pointList" - :key="item.id" - :label="item.pointName" - :value="item.id"/> - </el-select> - </el-form-item> - </el-col> </el-row> <el-row v-if="dataForm.itemtypename === 'MergeItem'"> <el-col :span="12"> @@ -143,6 +129,7 @@ :on-success="uploadModelSuccess" :on-error="uploadModelError" :action="uploadUrl" + :show-file-list="false" :http-request="httpRequest"> <el-button type="primary" @click="setReplaceModelOnly(false)"> <Icon icon="ep:upload"/> @@ -158,18 +145,7 @@ </el-col> </el-row> <el-row v-if="dataForm.itemtypename === 'NormalItem'"> - <el-col :span="8"> - <el-form-item label="结果"> - <el-select v-model="dataForm.mmPredictModel.resultstrid" placeholder="请选择"> - <el-option - v-for="item in resultstridList" - :key="item.id" - :label="item.resultstr" - :value="item.id"/> - </el-select> - </el-form-item> - </el-col> - <el-col :span="8"> + <el-col :span="12"> <el-form-item label="关联项目"> <el-select v-model="dataForm.mmPredictModel.mpkprojectid" placeholder="请选择"> <el-option @@ -180,7 +156,7 @@ </el-select> </el-form-item> </el-col> - <el-col :span="8"> + <el-col :span="12"> <el-form-item label="编号"> <el-input v-model="dataForm.mmPredictModel.modelno" placeholder="编号" maxlength="30" readonly @@ -222,14 +198,83 @@ </el-form-item> </el-col> </el-row> + <el-divider content-position="left" v-if="dataForm.itemtypename === 'NormalItem'">模型输出 + </el-divider> + <el-button + @click="addItemOutput(dataForm.mmItemOutputList)" + type="primary" + size="small"> + 添加 + </el-button> + <el-table + v-if="dataForm.itemtypename === 'NormalItem'" + :data="dataForm.mmItemOutputList" + border + style="width: 100%; margin-top: 5px;"> + <el-table-column prop="outputorder" label="排序" align="center" width="80px"/> + <el-table-column label="结果" align="center" width="150px"> + <template #default="scope"> + <el-input v-model="scope.row.resultstr" placeholder="请输入"/> + </template> + </el-table-column> + <el-table-column label="结果数据类型" align="center" width="150px"> + <template #default="scope"> + <el-select + v-model="scope.row.resultType" + @change="(value) => resultTypeChange(value,scope.row)" + filterable + placeholder="请选择"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.MODEL_RESULT_TYPE)" + :key="dict.value" + :label="dict.label" + :value="dict.value"/> + </el-select> + </template> + </el-table-column> + <el-table-column label="索引" align="center" width="120px"> + <template #default="scope"> + <el-input-number style="width:100%;hight:100%" :disabled="scope.row.resultType !== 2" + v-model="scope.row.resultIndex" :min="0" step-strictly + controls-position="right"/> + </template> + </el-table-column> + <el-table-column label="数据点" align="center"> + <template #default="scope"> + <el-select + v-model="scope.row.pointid" + filterable + @change="(value) => changeOutputPoint(value,scope.row)" + placeholder="请选择"> + <el-option + v-for="item in pointList" + :key="item.id" + :label="item.pointName" + :value="item.id"/> + </el-select> + </template> + </el-table-column> + <el-table-column prop="" label="操作" width="80" align="center"> + <template #default="scope"> + <el-button + @click="deleteItemOutput(scope.$index, dataForm.mmItemOutputList)" + type="text" + size="small"> + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <el-divider content-position="left" v-if="dataForm.itemtypename === 'NormalItem'">模型设置参数 + </el-divider> <el-table v-if="dataForm.itemtypename === 'NormalItem'" :data="dataForm.mmModelArithSettingsList" border style="width: 100%; margin-top: 5px;"> - <el-table-column prop="key" label="键" align="center"/> - <el-table-column prop="name" label="名称" align="center"/> - <el-table-column prop="valuetype" label="类型" align="center"/> + <el-table-column prop="key" label="键" align="center" min-width="150"/> + <el-table-column prop="name" label="名称" align="center" min-width="150"/> + <el-table-column prop="valuetype" label="类型" align="center" min-width="150"/> <el-table-column prop="" label="值" align="center" min-width="150"> <template #default="scope"> <el-input size="mini" v-model="scope.row.value" maxlength="256" @@ -237,7 +282,7 @@ </template> </el-table-column> </el-table> - <el-divider content-position="left" v-if="dataForm.itemtypename === 'NormalItem'">输入参数 + <el-divider content-position="left" v-if="dataForm.itemtypename === 'NormalItem'">模型输入参数 </el-divider> <el-table v-if="dataForm.itemtypename === 'NormalItem'" @@ -248,7 +293,9 @@ <el-table-column prop="modelparamorder" label="序号" width="60" align="center"/> <el-table-column prop="" label="类型" width="200" align="center"> <template #default="scope"> - <el-select v-model="scope.row.modelparamtype" placeholder="请选择"> + <el-select v-model="scope.row.modelparamtype" + @change="changeModelparamtype(scope.row)" + placeholder="请选择"> <el-option v-for="dict in getStrDictOptions(DICT_TYPE.MODEL_PARAM_TYPE)" :key="dict.value" @@ -280,18 +327,18 @@ style="width:100%;hight:100%"/> </template> </el-table-column> - <el-table-column prop="" label="操作" width="140" align="center"> + <el-table-column prop="" label="操作" width="120" align="center"> <template #default="scope"> <el-button @click="addRow(scope.$index, dataForm.mmModelParamList)" type="text" - size="small"> + size="mini"> 添加 </el-button> <el-button @click="deleteRow(scope.$index, dataForm.mmModelParamList)" type="text" - size="small"> + size="mini"> 删除 </el-button> </template> @@ -316,8 +363,8 @@ <el-option v-for="(item, index) in predictItemList" :key="index" - :label="item.name" - :value="item.code"/> + :label="item.itemname" + :value="item.itemno"/> </el-select> </template> </el-table-column> @@ -330,7 +377,7 @@ label="运算符" align="center"> <template #default="scope"> - <el-select v-model="scope.row.operator" placeholder="请选择"> + <el-select v-model="scope.row.operator" placeholder="请选择" clearable> <el-option v-for="item in operatorList" :key="item" @@ -369,13 +416,12 @@ </template> <script lang="ts" setup> import {DICT_TYPE, getIntDictOptions, getStrDictOptions} from '@/utils/dict' -import * as MmPredictItem from '@/api/model/pre/predict' -import * as MmItemType from '@/api/model/pre/item' +import * as MmPredictItem from '@/api/model/pre/item' +import * as MmItemType from '@/api/model/pre/type' import * as DmModule from '@/api/model/pre/dm' -import * as MmResultTable from '@/api/model/pre/result' import * as ProjectApi from '@/api/model/mpk/project' import * as DaPoint from '@/api/data/da/point' -import {useUpload} from '@/api/model/pre/predict' +import {useUpload} from '@/api/model/pre/item' import * as ScheduleModelApi from '@/api/model/sche/model' const {uploadUrl, httpRequest} = useUpload() @@ -391,7 +437,6 @@ const itemTypeList = ref([]) const itemTypeMap = ref({}) const moduleList = ref([]) -const resultstridList = ref([]) const mpkProjectList = ref([]) const pointNoList = ref([]) const pointList = ref([]) @@ -435,14 +480,7 @@ status: undefined, categoryid: undefined }, - mmItemOutput: { - id: undefined, - itemid: undefined, - pointid: undefined, - resulttableid: undefined, - tagname: undefined, - outputorder: undefined - }, + mmItemOutputList: [], mmPredictModel: { id: undefined, modelno: undefined, @@ -489,7 +527,6 @@ 'mmPredictItem.status': [{required: true, message: '是否启用不能为空', trigger: 'blur'}], 'dmModuleItem.moduleid': [{required: true, message: '管网不能为空', trigger: 'blur'}], 'dmModuleItem.itemorder': [{required: true, message: '排序不能为空', trigger: 'blur'}], - 'mmItemOutput.pointid': [{required: true, message: '数据点不能为空', trigger: 'blur'}], }) const formRef = ref() // 表单 Ref @@ -503,15 +540,6 @@ resetForm() resetFields(dataForm.value) setDefaultFields() - // 修改时,设置数据 - if (id) { - formLoading.value = true - try { - getInfo(id) - } finally { - /*formLoading.value = false*/ - } - } // 加载参数列表 modelparamListMap.value = await ScheduleModelApi.getModelParamList() @@ -524,26 +552,37 @@ if (!dataForm.value.id) { dataForm.value.mmPredictItem.itemtypeid = itemTypeList.value[0].id } - dataForm.value.itemtypename = itemTypeMap[dataForm.value.mmPredictItem.itemtypeid] // 获取管网列表 moduleList.value = await DmModule.getModuleList() - // 获取结果字符串列表 - resultstridList.value = await MmResultTable.getResultstridList() - // 获取mpk项目列表 mpkProjectList.value = await ProjectApi.list() + + // 获取normal列表 + predictItemList.value = await MmPredictItem.getMmPredictItemList({ + itemtypename: 'NormalItem' + }) // 获取数据点列表 pointNoList.value = await DaPoint.getPointList(queryParams) if (pointNoList.value.length > 0) { + pointList.value = [] pointNoList.value.forEach(function (value) { pointList.value.push(value) - pointMap[value.id] = value.pointname + pointMap[value.id] = value.pointName }) } + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + getInfo(id) + } finally { + formLoading.value = false + } + } formLoading.value = false } defineExpose({open}) // 提供 open 方法,用于打开弹窗 @@ -555,6 +594,22 @@ if (!formRef) return const valid = await formRef.value.validate() if (!valid) return + + //校验模型输出 + if (dataForm.value.mmItemOutputList == undefined || dataForm.value.mmItemOutputList.length <= 0) { + message.error("模型输出不为空") + return + } + + let flag = false + dataForm.value.mmItemOutputList.forEach(e => { + if (e.resultstr == undefined || e.resultstr === '' || e.resultType == undefined || e.resultType === '' || e.pointid == undefined || e.pointid === '' || (e.resultType === 2 && (e.resultIndex == undefined || e.resultIndex === ''))) { + message.error("模型输出数据异常") + flag = true + } + }) + if (flag) return + // 提交请求 formLoading.value = true try { @@ -608,6 +663,7 @@ const getInfo = async (id) => { dataForm.value = await MmPredictItem.getMmPredictItem(id) + dataForm.value.itemtypename = itemTypeMap[dataForm.value.mmPredictItem.itemtypeid] expressionList.value = [] if (dataForm.value.mmPredictMergeItem && dataForm.value.mmPredictMergeItem.expression) { let expression = dataForm.value.mmPredictMergeItem.expression @@ -710,12 +766,12 @@ dataForm.value.itemtypename = itemTypeMap[value] } -function changeModelparamtype(value, row) { +function changeModelparamtype(row) { row.modelparamid = '' } -function changeOutputPoint(value) { - dataForm.value.mmItemOutput.tagname = pointMap[value] +function changeOutputPoint(value, row) { + row.tagname = pointMap[value] } function deleteExpressionRow(index, rows) { @@ -742,6 +798,37 @@ orderRow(rows) } +function addItemOutput(list) { + list.push({}) + orderItemOutput(list) +} + +function deleteItemOutput(index: string, rows) { + if (!rows || rows.length === 1) { + message.error('不能全部删除!') + return + } + rows.splice(index, 1) + orderItemOutput(rows) +} + +function orderItemOutput(list) { + list.sort((a, b) => a.outputorder - b.outputorder); + let outputorder = 1 + list.forEach(function (value) { + value.outputorder = outputorder + outputorder++ + }) +} + +function resultTypeChange(value, row) { + if (value === 1) { + row.resultIndex = undefined + } else if (value === 2) { + row.resultIndex = 0 + } +} + function orderRow(rows) { let modelparamorder = 0 let modelparamportorder = 0 @@ -766,8 +853,7 @@ dataForm.value.mmPredictModel.trainsamplength = 60 dataForm.value.mmPredictModel.isonlinetrain = 0 dataForm.value.mmPredictModel.status = 1 - dataForm.value.mmItemOutput.outputorder = 1 - dataForm.value.mmItemOutput.resulttableid = '3cc2b483-3a01-40f7-a419-0c260210d8eb' + dataForm.value.mmItemOutputList = [] expressionList.value = [{ point: '', operator: '' @@ -805,14 +891,7 @@ status: 1, categoryid: '' }, - mmItemOutput: { - id: '', - itemid: '', - pointid: '', - resulttableid: '3cc2b483-3a01-40f7-a419-0c260210d8eb', - tagname: '', - outputorder: 1 - }, + mmItemOutputList: [], mmPredictModel: { id: '', modelno: '', diff --git a/src/views/model/pre/item/index.vue b/src/views/model/pre/item/index.vue index e0e8861..ffc12bd 100644 --- a/src/views/model/pre/item/index.vue +++ b/src/views/model/pre/item/index.vue @@ -51,18 +51,18 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list"> - <el-table-column label="编号" align="center" prop="itemno"/> + <el-table-column label="编号" align="center" min-width="150" prop="itemno"/> <el-table-column label="预测项名" header-align="center" align="left" min-width="200" prop="itemname"/> - <el-table-column label="类型名称" align="center" prop="itemtypename"> + <el-table-column label="类型名称" align="center" min-width="120" prop="itemtypename"> <template #default="scope"> <el-tag v-if="scope.row.itemtypename === 'NormalItem'" size="small" type="success">{{scope.row.itemtypename}}</el-tag> <el-tag v-else size="small" type="primary">{{scope.row.itemtypename}}</el-tag> </template> </el-table-column> - <el-table-column label="预测长度" align="center" prop="predictlength"/> + <el-table-column label="预测长度(min)" align="center" prop="predictlength"/> <el-table-column label="粒度" align="center" prop="granularity"> <template #default="scope"> - <dict-tag :type="DICT_TYPE.TIME_GRANULARITY" :value="scope.row.granularity" /> + <dict-tag :type="DICT_TYPE.PRED_GRANULARITY" :value="scope.row.granularity" /> </template> </el-table-column> <el-table-column label="是否融合" align="center" prop="isfuse"> @@ -80,21 +80,29 @@ <dict-tag :type="DICT_TYPE.COM_IS_INT" :value="scope.row.status" /> </template> </el-table-column> - <el-table-column label="数据点名称" align="center" prop="tagname"/> - <el-table-column label="存放表" align="center" prop="tablename"/> - <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <el-table-column label="运行时间" min-width="150" align="center" prop="lastTime"/> + <el-table-column label="运行状态" align="center" prop="runStatus"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.ITEM_RUN_STATUS" :value="scope.row.runStatus" /> + </template> + </el-table-column> + <el-table-column label="运行耗时(s)" align="center" prop="duration"/> + <el-table-column label="操作" align="center" min-width="120" fixed="right"> <template #default="scope"> <el-button link type="primary" + size="mini" @click="openForm('update', scope.row.id, scope.row.itemtypename)" v-hasPermi="['model:pre-item:update']" > 编辑 </el-button> + <el-button link size="mini" type="primary" @click="chartHandle(scope.row)">数据</el-button> <el-button link type="danger" + size="mini" @click="handleDelete(scope.row.id)" v-hasPermi="['model:pre-item:delete']" > @@ -115,10 +123,14 @@ <!-- 表单弹窗:添加/修改 --> <MmPredictItemForm ref="formRef" @success="getList"/> + <!-- 表单弹窗:数据 --> + <MmPredictItemChart ref="chartView" @success="getList"/> + </template> <script lang="ts" setup> import MmPredictItemForm from './MmPredictItemForm.vue' -import * as MmPredictItem from '@/api/model/pre/predict' +import MmPredictItemChart from './MmPredictItemChart.vue' +import * as MmPredictItem from '@/api/model/pre/item' import {DICT_TYPE} from "@/utils/dict"; defineOptions({name: 'DataMmPredictItem'}) @@ -171,6 +183,12 @@ handleQuery() } +/** 查看数据操作 */ +const chartView = ref() +const chartHandle = (raw: object) => { + chartView.value.open(raw) +} + /** 添加/修改操作 */ const formRef = ref() const openForm = (type: string, id?: number, itemtypename?: string) => { diff --git a/src/views/model/pre/result/MmResultTableForm.vue b/src/views/model/pre/result/MmResultTableForm.vue deleted file mode 100644 index bcb0afa..0000000 --- a/src/views/model/pre/result/MmResultTableForm.vue +++ /dev/null @@ -1,96 +0,0 @@ -<template> - <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> - <el-form - ref="formRef" - v-loading="formLoading" - :model="formData" - :rules="formRules" - label-width="120px" - > - <el-row> - <el-col :span="12"> - <el-form-item label="表名" prop="tablename"> - <el-input v-model="formData.tablename" placeholder="请输入表名"/> - </el-form-item> - </el-col> - </el-row> - </el-form> - <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 MmResultTable from '@/api/model/pre/result' - -defineOptions({name: 'DataMmResultTableForm'}) - -const {t} = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined, - tablename: undefined, -}) -const formRules = reactive({ - tablename: [{required: true, message: '表名不能为空', trigger: 'blur'}], -}) -const formRef = ref() // 表单 Ref - -/** 打开弹窗 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 修改时,设置数据 - if (id) { - formLoading.value = true - try { - formData.value = await MmResultTable.getMmResultTable(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({open}) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return - // 提交请求 - formLoading.value = true - try { - const data = formData.value as unknown as MmResultTable.MmResultTableVO - if (formType.value === 'create') { - await MmResultTable.createMmResultTable(data) - message.success(t('common.createSuccess')) - } else { - await MmResultTable.updateMmResultTable(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined, - tablename: undefined, - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/model/pre/result/index.vue b/src/views/model/pre/result/index.vue deleted file mode 100644 index 271e8d6..0000000 --- a/src/views/model/pre/result/index.vue +++ /dev/null @@ -1,149 +0,0 @@ -<template> - <!-- 搜索 --> - <ContentWrap> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="表名" prop="tablename"> - <el-input - v-model="queryParams.tablename" - placeholder="请输入表名" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon icon="ep:search" class="mr-5px" /> - 搜索 - </el-button> - <el-button @click="resetQuery"> - <Icon icon="ep:refresh" class="mr-5px" /> - 重置 - </el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['model:pre-result:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> - 新增 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 列表 --> - <ContentWrap> - <el-table v-loading="loading" :data="list"> - <el-table-column label="表名" align="center" prop="tablename" /> - - <el-table-column label="操作" align="center" min-width="110" fixed="right"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['model:pre-result:update']" - > - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['model:pre-result:delete']" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 表单弹窗:添加/修改 --> - <MmResultTableForm ref="formRef" @success="getList" /> - -</template> -<script lang="ts" setup> -import MmResultTableForm from './MmResultTableForm.vue' -import * as MmResultTable from '@/api/model/pre/result' - -defineOptions({name: 'DataMmResultTable'}) - - const message = useMessage() // 消息弹窗 - const {t} = useI18n() // 国际化 - - const loading = ref(true) // 列表的加载中 - const total = ref(0) // 列表的总页数 - const list = ref([]) // 列表的数据 - const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - tablename: undefined, - }) - const queryFormRef = ref() // 搜索的表单 - const exportLoading = ref(false) // 导出的加载中 - - /** 查询列表 */ - const getList = async () => { - loading.value = true - try { - const page = await MmResultTable.getMmResultTablePage(queryParams) - list.value = page.list - total.value = page.total - } finally { - loading.value = false - } - } - - /** 搜索按钮操作 */ - const handleQuery = () => { - queryParams.pageNo = 1 - getList() - } - - /** 重置按钮操作 */ - const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() - } - - /** 添加/修改操作 */ - const formRef = ref() - const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) - } - - /** 删除按钮操作 */ - const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await MmResultTable.deleteMmResultTable(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch { - } - } - - /** 初始化 **/ - onMounted(async () => { - await getList() - }) -</script> diff --git a/src/views/model/pre/type/ItemTypeForm.vue b/src/views/model/pre/type/ItemTypeForm.vue index 5131d27..eb457f4 100644 --- a/src/views/model/pre/type/ItemTypeForm.vue +++ b/src/views/model/pre/type/ItemTypeForm.vue @@ -36,7 +36,7 @@ </Dialog> </template> <script lang="ts" setup> -import * as MmItemType from '@/api/model/pre/item' +import * as MmItemType from '@/api/model/pre/type' defineOptions({name: 'DataMmItemTypeForm'}) diff --git a/src/views/model/pre/type/index.vue b/src/views/model/pre/type/index.vue index 39d8216..601d7c1 100644 --- a/src/views/model/pre/type/index.vue +++ b/src/views/model/pre/type/index.vue @@ -82,7 +82,7 @@ </template> <script lang="ts" setup> import MmItemTypeForm from './ItemTypeForm.vue' -import * as MmItemType from '@/api/model/pre/item' +import * as MmItemType from '@/api/model/pre/type' defineOptions({name: 'DataMmItemType'}) diff --git a/src/views/model/swagger/index.vue b/src/views/model/wiki/index.vue similarity index 83% rename from src/views/model/swagger/index.vue rename to src/views/model/wiki/index.vue index 8b09f85..cf19ad3 100644 --- a/src/views/model/swagger/index.vue +++ b/src/views/model/wiki/index.vue @@ -6,7 +6,7 @@ <script lang="ts" setup> import * as ConfigApi from '@/api/infra/config' -defineOptions({ name: 'ModelSwagger' }) +defineOptions({ name: 'ModelWiki' }) const loading = ref(true) // 是否加载中 const src = ref(import.meta.env.VITE_BASE_URL + '/doc.html') @@ -15,7 +15,7 @@ /** 初始化 */ onMounted(async () => { try { - const data = await ConfigApi.getConfigKey('model.swagger') + const data = await ConfigApi.getConfigKey('model.wiki') if (data && data.length > 0) { src.value = data } diff --git a/types/env.d.ts b/types/env.d.ts index 40ce343..25cef34 100644 --- a/types/env.d.ts +++ b/types/env.d.ts @@ -25,10 +25,12 @@ readonly VITE_UPLOAD_URL: string readonly VITE_API_URL: string readonly VITE_BASE_PATH: string + readonly VITE_VIDEO_CAMERA_DOMAIN: string readonly VITE_DROP_DEBUGGER: string readonly VITE_DROP_CONSOLE: string readonly VITE_SOURCEMAP: string readonly VITE_OUT_DIR: string + readonly VITE_STATIC_DIR: string } declare global { -- Gitblit v1.9.3