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图表 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 } src/api/model/mcs/index.ts
@@ -1,7 +1,7 @@ import request from '@/config/axios' export interface PreDataBarLineReqVO { queryIds: string[], outIds: string[], predictTime: string, startTime: string, endTime: string @@ -13,6 +13,9 @@ 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 }) 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/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, } } 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/", }; 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) } 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; 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 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 } src/views/bpm/simpleWorkflow/index.vue
文件已删除 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> 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> 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() } 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> 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,20 +157,25 @@ <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> @@ -168,31 +184,479 @@ </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/item' 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: '', @@ -218,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, @@ -231,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 - 68px - 38px - 160px)); 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> 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> @@ -210,13 +211,13 @@ :data="dataForm.mmItemOutputList" border style="width: 100%; margin-top: 5px;"> <el-table-column prop="outputorder" label="排序" align="center" width="80px" /> <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"> <el-table-column label="结果数据类型" align="center" width="150px"> <template #default="scope"> <el-select v-model="scope.row.resultType" @@ -233,7 +234,9 @@ </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"/> <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"> @@ -290,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" @@ -761,11 +766,11 @@ dataForm.value.itemtypename = itemTypeMap[value] } function changeModelparamtype(value, row) { function changeModelparamtype(row) { row.modelparamid = '' } function changeOutputPoint(value,row) { function changeOutputPoint(value, row) { row.tagname = pointMap[value] } @@ -792,10 +797,12 @@ rows.splice(index, 0, row) orderRow(rows) } function addItemOutput(list) { list.push({}) orderItemOutput(list) } function deleteItemOutput(index: string, rows) { if (!rows || rows.length === 1) { message.error('不能全部删除!') @@ -804,6 +811,7 @@ rows.splice(index, 1) orderItemOutput(rows) } function orderItemOutput(list) { list.sort((a, b) => a.outputorder - b.outputorder); let outputorder = 1 @@ -816,7 +824,7 @@ function resultTypeChange(value, row) { if (value === 1) { row.resultIndex = undefined }else if (value === 2) { } else if (value === 2) { row.resultIndex = 0 } } types/env.d.ts
@@ -25,6 +25,7 @@ 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