Merge pull request '数据大屏' (#3) from pht/SamATV:main into main
Reviewed-on: #3
1
global.d.ts
vendored
@ -3,4 +3,5 @@ declare global {
|
||||
interface Window {
|
||||
$microWidgetProps: any;//全局变量名
|
||||
}
|
||||
type TimeProp= NodeJS.Timeout
|
||||
}
|
3117
package-lock.json
generated
19
package.json
@ -12,12 +12,15 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.0.10",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@fortawesome/vue-fontawesome": "^3.0.8",
|
||||
"@kjgl77/datav-vue3": "^1.7.4",
|
||||
"@wangeditor/editor": "^5.1.21",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^1.1.3",
|
||||
"axios": "^1.9.0",
|
||||
"countup.js": "^2.2.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"echarts": "^5.4.0",
|
||||
"echarts-gl": "^2.0.9",
|
||||
"echarts-liquidfill": "^3.1.0",
|
||||
@ -30,7 +33,9 @@
|
||||
"jsplumb": "^2.15.6",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.0",
|
||||
"mockjs": "^1.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.23",
|
||||
@ -46,6 +51,7 @@
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-cropper": "next",
|
||||
"vue-cropperjs": "^5.0.0",
|
||||
"vue-echarts": "^7.0.3",
|
||||
"vue-grid-layout": "next",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-native-websocket-vue3": "^3.1.7",
|
||||
@ -56,6 +62,7 @@
|
||||
"wangeditor": "^4.7.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mockjs": "^1.0.10",
|
||||
"@types/node": "^18.8.3",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/qs": "^6.9.7",
|
||||
@ -64,13 +71,19 @@
|
||||
"@typescript-eslint/parser": "^5.39.0",
|
||||
"@vitejs/plugin-vue": "^3.1.2",
|
||||
"@vue/compiler-sfc": "^3.2.40",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.25.0",
|
||||
"eslint-plugin-vue": "^9.6.0",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "^2.7.1",
|
||||
"sass": "^1.55.0",
|
||||
"sass-loader": "^13.0.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^4.8.4",
|
||||
"unplugin-auto-import": "^0.17.5",
|
||||
"unplugin-element-plus": "^0.8.0",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^3.1.7",
|
||||
"vue-eslint-parser": "^9.1.0"
|
||||
},
|
||||
|
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
@ -129,3 +129,7 @@ G:\Projects\VueProject\SamATV\src\views\common
|
||||
src/views/common/dashboard/big/index.vue dashboard仪表盘
|
||||
|
||||
前端路由:G:\Projects\VueProject\SamATV\src\router\route.ts
|
||||
|
||||
先把请求拦截器和响应拦截器注释掉了
|
||||
G:\Projects\VueProject\SamATV\src\utils\ajax\request.ts
|
||||
scr/api 接口请求
|
48
src/layout/FullScreenLayout.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<!--大屏布局组件-->
|
||||
<template>
|
||||
<div class="full-screen-container">
|
||||
<!-- 大屏内容 -->
|
||||
<!-- <router-view />-->
|
||||
<Screen/>
|
||||
<!-- 返回按钮(固定在左上角) -->
|
||||
<div class="back-button" >
|
||||
<el-button type="primary" icon="el-icon-back" @click="goBack">返回主页</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import Screen from '/@/views/common/screen-vue3/views/HomeView.vue'
|
||||
export default defineComponent({
|
||||
name: 'FullScreenLayout',
|
||||
components: {Screen},
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const goBack = () => {
|
||||
// 返回主布局的首页(或指定页面)
|
||||
router.push('/home');
|
||||
};
|
||||
return { goBack };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.full-screen-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
z-index: 999;
|
||||
}
|
||||
.back-button {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style>
|
@ -87,6 +87,23 @@ export default defineComponent({
|
||||
const setFilterRoutes = () => {
|
||||
if (themeConfig.value.layout === 'columns') return false;
|
||||
(state.menuList as any) = filterRoutesFun(routesList.value);
|
||||
// console.log("menuList",state.menuList);
|
||||
//自定义的侧边栏按钮
|
||||
const bigScreenButton = {
|
||||
path: '/big-screen',
|
||||
name: 'big-screen',
|
||||
// 改为使用全屏布局组件,而非主布局
|
||||
component: () => import('/@/layout/FullScreenLayout.vue'),
|
||||
meta: {
|
||||
isKeepAlive: true,
|
||||
title: '数据大屏',
|
||||
roles: ['admin'],
|
||||
isIframe: false, isLink: '/big-screen',
|
||||
isHide: false, isAffix: false,
|
||||
icon: 'fa fa-window-restore'
|
||||
}
|
||||
};
|
||||
(state.menuList as any[]).splice(1,0,bigScreenButton); // 通过 as any[] 断言为任意类型数组 state.menuList.unshift(bigScreenButton);
|
||||
};
|
||||
// 路由过滤递归函数
|
||||
const filterRoutesFun = (arr: Array<string>) => {
|
||||
@ -144,6 +161,8 @@ export default defineComponent({
|
||||
state.menuList = res.children;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
proxy.mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||
setFilterRoutes();
|
||||
});
|
||||
|
@ -1,3 +1,5 @@
|
||||
<!--Vertical 组件是一个用于生成垂直菜单的组件,它接收一个路由列表(menuList),
|
||||
并根据路由的配置生成相应的菜单结构。该组件主要用于侧边栏导航,支持菜单的展开与收起、菜单项的点击导航、菜单高亮以及国际化等功能。-->
|
||||
<template>
|
||||
<el-menu router :default-active="defaultActive" background-color="transparent" :collapse="isCollapse"
|
||||
:unique-opened="getThemeConfig.isUniqueOpened" :collapse-transition="false">
|
||||
@ -49,6 +51,8 @@ export default defineComponent({
|
||||
defaultActive: route.meta.isDynamic ? route.meta.isDynamicPath : route.path,
|
||||
isCollapse: false,
|
||||
});
|
||||
|
||||
|
||||
// 获取父级菜单数据
|
||||
const menuLists = computed(() => {
|
||||
return props.menuList as any;
|
||||
|
13
src/main.ts
@ -21,8 +21,18 @@ import { getDictData } from "./api/system/sysApi"
|
||||
import { isNull } from '/@/utils/sam/validate';
|
||||
//index.ts
|
||||
import { addDateRange, parseTime, handleTree, selectDictLabel, } from '/@/utils'
|
||||
import DataVVue3 from "@kjgl77/datav-vue3";
|
||||
|
||||
//数据大屏需要
|
||||
import {registerEcharts} from "/@/views/common/screen-vue3/plugins/echarts"
|
||||
//不使用mock 请注释掉
|
||||
import { mockXHR } from "/@/views/common/screen-vue3/mock/index";
|
||||
mockXHR()
|
||||
import '/src/views/common/screen-vue3/assets/css/main.scss';
|
||||
import '/src/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
|
||||
const app = createApp(App);
|
||||
registerEcharts(app) //数据大屏需要
|
||||
directive(app);
|
||||
other.elSvg(app);
|
||||
app.use(pinia)
|
||||
@ -30,6 +40,7 @@ app.use(pinia)
|
||||
//设置element-plus国际化 原来的: 升级后不行,原因不明
|
||||
.use(ElementPlus, { i18n: i18n.global.t })
|
||||
.use(i18n)
|
||||
.use(DataVVue3)
|
||||
.use(VueGridLayout).mount('#app');
|
||||
|
||||
//全局方法挂载
|
||||
@ -40,6 +51,8 @@ app.config.globalProperties.getDicts = getDictData
|
||||
app.config.globalProperties.mittBus = mitt();
|
||||
app.config.globalProperties.selectDictLabel = selectDictLabel
|
||||
app.config.globalProperties.addDateRange = addDateRange;
|
||||
// import * as echarts from 'echarts';
|
||||
// app.config.globalProperties.$echarts = echarts;
|
||||
|
||||
//自定义表格工具扩展
|
||||
import RightToolbar from "/@/components/sam/RightToolbar/index.vue"
|
||||
|
@ -29,6 +29,15 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
||||
* isIframe:true 内置;false:重启一个页面
|
||||
* component: () => import('/@/layout/routerView/iframes.vue'),
|
||||
*/
|
||||
// {
|
||||
// path: '/big-screen', name: 'big-screen',
|
||||
// component: () => import('/@/views/common/big-screen/pages/screen/Screen.vue'),
|
||||
// meta: {
|
||||
// title: '数据大屏', isIframe: false, isLink: '/big-screen',
|
||||
// isHide: false, isKeepAlive: false, isAffix: false,
|
||||
// roles: ['admin'], icon: 'fa fa-window-restore'
|
||||
// },
|
||||
// },
|
||||
{
|
||||
path: '/big', name: 'grafana',
|
||||
component: () => import('/@/views/common/dashboard/big/index.vue'),
|
||||
@ -56,778 +65,25 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
||||
roles: ['admin'], icon: 'fa fa-window-restore'
|
||||
},
|
||||
},
|
||||
// //实时监控
|
||||
// {
|
||||
// path: '/atv/equip/online', name: 'onlineEquip',
|
||||
// component: () => import('/@/views/atv/equip/online/RealList/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.liveMonitorMag', isIframe: false, isLink: '',
|
||||
// isHide: false, isKeepAlive: true, isAffix: false,
|
||||
// roles: ['admin'], icon: 'fa fa-heart',
|
||||
// },
|
||||
// },
|
||||
// //故障统计
|
||||
// {
|
||||
// path: '/atv/big/faultStatistics', name: 'faultStatisticsIndex',
|
||||
// component: () => import('/@/views/atv/big/faultStatistics.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.faultStatistics', isIframe: false, isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false,
|
||||
// roles: ['admin'], icon: 'fa fa-bell-slash',
|
||||
// },
|
||||
// },
|
||||
// //'实时客流
|
||||
// {
|
||||
// path: '/atv/big/realPassenger', name: 'realPassengerIndex',
|
||||
// component: () => import('/@/views/atv/big/realPassenger.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.realPassenger', isIframe: false, isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false,
|
||||
// roles: ['admin'], icon: 'fa fa-female',
|
||||
// },
|
||||
// },
|
||||
// //预警模型
|
||||
// {
|
||||
// path: '/atv/big/warnModel', name: 'warnModelIndex',
|
||||
// component: () => import('/@/views/atv/big/warnModel.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.warnModel', isIframe: false, isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false,
|
||||
// roles: ['admin'], icon: 'fa fa-umbrella',
|
||||
// },
|
||||
// },
|
||||
// //远程广播
|
||||
// {
|
||||
// path: '/atv/broadcast', name: 'broadcastMag',
|
||||
// component: () => import('/@/views/atv/broadcast/tts/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.broadcastMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-volume-up',
|
||||
// },
|
||||
// },
|
||||
// //日志管理
|
||||
// {
|
||||
// path: '/atv/logMag', name: 'logMag',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/log/downLog',
|
||||
// meta: {
|
||||
// title: 'message.router.logMag', isLink: '', isHide: false,
|
||||
// isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-tripadvisor',
|
||||
// },
|
||||
// children: [
|
||||
// //上传广播音频文件列表
|
||||
// {
|
||||
// path: '/atv/log/audioLogIndex', name: 'audioLogList',
|
||||
// component: () => import('/@/views/atv/log/audioLogIndex.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.audioLogList', isLink: '',
|
||||
// isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-arrow-down',
|
||||
// },
|
||||
// },
|
||||
// //设备下载日志文件列表
|
||||
// {
|
||||
// path: '/atv/log/equipLogIndex', name: 'equipLogList',
|
||||
// component: () => import('/@/views/atv/log/equipLogIndex.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.equipLogList', isLink: '',
|
||||
// isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-arrow-down',
|
||||
// },
|
||||
// },
|
||||
// /*
|
||||
// //日志回放
|
||||
// {
|
||||
// path: '/atv/log/playback', name: 'playList',
|
||||
// component: () => import('/@/views/atv/log/playback/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.logPlayback', isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-retweet',
|
||||
// },
|
||||
// },
|
||||
// //日志信息
|
||||
// {
|
||||
// path: '/atv/log/warnIndex', name: 'warnLogInfo',
|
||||
// component: () => import('/@/views/atv/log/warnIndex.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.warnLogInfo', isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-tint',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/atv/log/trainIndex', name: 'trainLogInfo',
|
||||
// component: () => import('/@/views/atv/log/trainIndex.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.trainLogInfo', isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-train',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/atv/log/equipIndex', name: 'equipLogInfo',
|
||||
// component: () => import('/@/views/atv/log/equipIndex.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.equipLogInfo', isLink: '',
|
||||
// isHide: true, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-medkit',
|
||||
// },
|
||||
// },*/
|
||||
// ]
|
||||
// },
|
||||
// //故障管理
|
||||
// {
|
||||
// path: '/atv/faultMag', name: 'faultMag',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/fault/index',
|
||||
// meta: {
|
||||
// title: 'message.router.faultMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-ambulance',
|
||||
// },
|
||||
// children: [
|
||||
// //故障列表
|
||||
// {
|
||||
// path: '/atv/fault', name: 'faultList',
|
||||
// component: () => import('/@/views/atv/fault/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.faultList',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-list',
|
||||
// },
|
||||
// },
|
||||
// //知识库
|
||||
// {
|
||||
// path: '/atv/knowledge', name: 'knowledgeList',
|
||||
// component: () => import('/@/views/atv/knowledge/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.knowledgeList',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-connectdevelop',
|
||||
// },
|
||||
// },
|
||||
// //故障统计
|
||||
// {
|
||||
// path: '/atv/fault/analysis', name: 'analysisList',
|
||||
// component: () => import('/@/views/atv/analysis/fault/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.faultStatic',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-line-chart',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// //设备管理
|
||||
// {
|
||||
// path: '/atv/equipMag', name: 'equipMag',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/equip/index',
|
||||
// meta: {
|
||||
// title: 'message.router.equipMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-wrench',
|
||||
// },
|
||||
// children: [
|
||||
// //设备列表
|
||||
// {
|
||||
// path: '/atv/equip', name: 'equipList',
|
||||
// component: () => import('/@/views/atv/equip/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.equipList',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-list',
|
||||
// },
|
||||
// },
|
||||
// //设备查看
|
||||
// {
|
||||
// path: '/atv/equip/check', name: 'equipCheck',
|
||||
// component: () => import('/@/views/atv/equip/check/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.equipCheck',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-eye',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// //库存管理
|
||||
// {
|
||||
// path: '/atv/stockMag', name: 'stockMag',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/stock/index',
|
||||
// meta: {
|
||||
// title: 'message.router.stockMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-home',
|
||||
// },
|
||||
// children: [
|
||||
// //仓库管理
|
||||
// {
|
||||
// path: '/atv/stock', name: 'stockInfo',
|
||||
// component: () => import('/@/views/atv/stock/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.stockList',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-hourglass',
|
||||
// },
|
||||
// },
|
||||
// //出入库单
|
||||
// {
|
||||
// path: '/atv/stock/warehouseing', name: 'stockWarehousing',
|
||||
// component: () => import('/@/views/atv/stock/warehousing/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.stockInOut',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-exchange',
|
||||
// },
|
||||
// },
|
||||
// //出入库明细
|
||||
// {
|
||||
// path: '/atv/stock/detail', name: 'stockDetail',
|
||||
// component: () => import('/@/views/atv/stock/detail/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.stockDetail',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-registered',
|
||||
// },
|
||||
// },
|
||||
// //进销存报表
|
||||
// {
|
||||
// path: '/atv/stock/report', name: 'stockReport',
|
||||
// component: () => import('/@/views/atv/stock/report/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.stockReport',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-print',
|
||||
// },
|
||||
// },
|
||||
// //入库单
|
||||
// {
|
||||
// path: '/atv/stock/component/inStockModule', name: 'inStockJump',
|
||||
// component: () => import('/@/views/atv/stock/component/inStockModule.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.stockIn',
|
||||
// isLink: '', isHide: true, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-print',
|
||||
// },
|
||||
// },
|
||||
// //出库单
|
||||
// {
|
||||
// path: '/atv/stock/component/outStockModule', name: 'outStockJump',
|
||||
// component: () => import('/@/views/atv/stock/component/outStockModule.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.stockOut',
|
||||
// isLink: '', isHide: true, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-print',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// /**板卡档案
|
||||
// {
|
||||
// path: '/atv/board', name: 'boardInfo',
|
||||
// component: () => import('/@/views/atv/board/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.boardMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-sitemap',
|
||||
// },
|
||||
// },*/
|
||||
// //板卡档案
|
||||
// {
|
||||
// path: '/atv/boardMag', name: 'boardMag',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/board',
|
||||
// meta: {
|
||||
// title: 'message.router.boardMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-sitemap',
|
||||
// },
|
||||
// children: [
|
||||
// //板卡信息
|
||||
// {
|
||||
// path: '/atv/board', name: 'boardInfo',
|
||||
// component: () => import('/@/views/atv/board/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.boardInfo',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-database',
|
||||
// },
|
||||
// },
|
||||
// //板卡测试信息
|
||||
// {
|
||||
// path: '/atv/board/test', name: 'boardTestInfo',
|
||||
// component: () => import('/@/views/atv/board/test/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.boardTestInfo',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-random',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// //基础设置
|
||||
// {
|
||||
// path: '/atv/basicData', name: 'basicData',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/basicData/line/index',
|
||||
// meta: {
|
||||
// title: 'message.router.metadataMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-database',
|
||||
// },
|
||||
// children: [
|
||||
// //线路管理
|
||||
// {
|
||||
// path: '/basicData/lineInfo', name: 'basicLine',
|
||||
// component: () => import('/@/views/atv/basicData/line/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.metaLine',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-random',
|
||||
// },
|
||||
// },
|
||||
// //车辆管理
|
||||
// {
|
||||
// path: '/basicData/vehicleInfo', name: 'basicVehicle',
|
||||
// component: () => import('/@/views/atv/basicData/vehicle/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.metaVehicle',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-bus',
|
||||
// },
|
||||
// },
|
||||
// //阈值设置
|
||||
// {
|
||||
// path: '/basicData/warningInfo', name: 'basicWarning',
|
||||
// component: () => import('/@/views/atv/basicData/warning/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.metaWarn',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-bug',
|
||||
// },
|
||||
// },
|
||||
// //字典基础信息
|
||||
// {
|
||||
// path: '/atv/basicData/dict', name: 'basicDict',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/basicData/dict/country',
|
||||
// meta: {
|
||||
// title: '字典信息',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-book',
|
||||
// },
|
||||
// children: [
|
||||
// //国家信息
|
||||
// {
|
||||
// path: '/atv/basicData/dict/country', name: 'basicCountry',
|
||||
// component: () => import('/@/views/atv/basicData/dict/country/index.vue'),
|
||||
// meta: {
|
||||
// title: '国家信息',
|
||||
// isLink: '', isHide: false, isKeepAlive: false, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-flag-checkered',
|
||||
// },
|
||||
// },
|
||||
// //区域信息
|
||||
// {
|
||||
// path: '/atv/basicData/dict/area', name: 'basicArea',
|
||||
// component: () => import('/@/views/atv/basicData/dict/area/index.vue'),
|
||||
// meta: {
|
||||
// title: '区域信息',
|
||||
// isLink: '', isHide: false, isKeepAlive: false, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-delicious',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// //仓库基础信息
|
||||
// {
|
||||
// path: '/atv/basicData/stock', name: 'basicStock',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/atv/basicData/stock/supplier',
|
||||
// meta: {
|
||||
// title: '仓库基础信息',
|
||||
// isLink: '', isHide: false, isKeepAlive: true, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-road',
|
||||
// },
|
||||
// children: [
|
||||
// //供应商管理
|
||||
// {
|
||||
// path: '/atv/basicData/stock/supplier', name: 'basicStockSupplier',
|
||||
// component: () => import('/@/views/atv/basicData/stock/supplier/index.vue'),
|
||||
// meta: {
|
||||
// title: '供应商管理',
|
||||
// isLink: '', isHide: false, isKeepAlive: false, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-shopping-cart',
|
||||
// },
|
||||
// },
|
||||
// //商品信息
|
||||
// {
|
||||
// path: '/atv/basicData/stock/categoryInfo', name: 'basicCategoryInfo',
|
||||
// component: () => import('/@/views/atv/basicData/stock/categoryInfo/index.vue'),
|
||||
// meta: {
|
||||
// title: '商品管理',
|
||||
// isLink: '', isHide: false, isKeepAlive: false, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-qrcode',
|
||||
// },
|
||||
// },
|
||||
// //商品类型
|
||||
// {
|
||||
// path: '/atv/basicData/stock/categoryType', name: 'basicCategoryType',
|
||||
// component: () => import('/@/views/atv/basicData/stock/categoryType/index.vue'),
|
||||
// meta: {
|
||||
// title: '商品类型',
|
||||
// isLink: '', isHide: false, isKeepAlive: false, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-indent',
|
||||
// },
|
||||
// },
|
||||
// //仓库管理
|
||||
// {
|
||||
// path: '/atv/basicData/stock/warehousing', name: 'basicWarehousing',
|
||||
// component: () => import('/@/views/atv/basicData/stock/warehousing/index.vue'),
|
||||
// meta: {
|
||||
// title: '仓库管理',
|
||||
// isLink: '', isHide: false, isKeepAlive: false, isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-home',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// //系统管理
|
||||
// {
|
||||
// path: '/system', name: 'system',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/system/user',
|
||||
// meta: {
|
||||
// title: 'message.router.systemMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'], icon: 'fa fa-windows',
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: '/system/user', name: 'systemUser',
|
||||
// component: () => import('/@/views/system/user/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemUser',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-user-circle',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/role', name: 'systemRole',
|
||||
// component: () => import('/@/views/system/role/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemRole',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-user-plus',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/perm', name: 'systemPerm',
|
||||
// component: () => import('/@/views/system/perm/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.rolePerm',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-balance-scale',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/menu', name: 'systemMenu',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/system/menu/static',
|
||||
// meta: {
|
||||
// title: 'message.router.systemMenu',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-stack-exchange',
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: '/system/menu/static', name: 'staticMenu',
|
||||
// component: () => import('/@/views/system/menu/static/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.staticMenu',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-skype',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/menu/dynamic', name: 'dynamicMenu',
|
||||
// component: () => import('/@/views/system/menu/dynamic/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.dynamicMenu',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-magic',
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/system/dept', name: 'systemDept',
|
||||
// component: () => import('/@/views/system/dept/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemDept',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-sitemap',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/post', name: 'systemPost',
|
||||
// component: () => import('/@/views/system/post/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemPost',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-street-view',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/dict', name: 'systemDict',
|
||||
// component: () => import('/@/views/system/dict/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemDict',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-google-plus-square',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/fillRule', name: 'fillRule',
|
||||
// component: () => import('/@/views/system/fillrule/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemFillRule',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-qrcode',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/config', name: 'systemConfig',
|
||||
// component: () => import('/@/views/system/config/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemConfig',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-wrench',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/news', name: 'systemNews',
|
||||
// component: () => import('/@/views/system/news/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.systemNews',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-rss-square',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/editNews', name: 'editNews',
|
||||
// component: () => import('/@/views/system/news/component/EditNews.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.editNews',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-random',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/system/detailNews', name: 'detailNews',
|
||||
// component: () => import('/@/views/system/news/component/DetailNews.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.detailNews',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-map',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// //系统监控
|
||||
// {
|
||||
// path: '/monitor', name: 'monitor',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/monitor/log',
|
||||
// meta: {
|
||||
// title: 'message.router.monitorMag',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-heartbeat',
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: '/monitor/job', name: 'mmonitorJob',
|
||||
// component: () => import('/@/views/monitor/job/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorJob',
|
||||
// isLink: '',
|
||||
// isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-clock-o',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/monitor/log', name: 'monitorLog',
|
||||
// component: () => import('/@/layout/routerView/parent.vue'),
|
||||
// redirect: '/monitor/log/logininfo',
|
||||
// meta: {
|
||||
// title: 'message.router.monitorLog',
|
||||
// isLink: '', isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-calendar',
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: '/monitor/logininfo', name: 'monitorLogininfo',
|
||||
// component: () => import('/@/views/monitor/log/logininfo/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorLogininfo',
|
||||
// isLink: '',
|
||||
// isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-keyboard-o',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/monitor/operlog', name: 'monitorOperlog',
|
||||
// component: () => import('/@/views/monitor/log/operlog/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorOperlog',
|
||||
// isLink: '',
|
||||
// isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-wrench',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/monitor/jobLog', name: 'monitorJobLog',
|
||||
// component: () => import('../views/monitor/log/joblog/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorJobLog',
|
||||
// isLink: '',
|
||||
// isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-power-off',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: '/monitor/online', name: 'monitorOnline',
|
||||
// component: () => import('/@/views/monitor/online/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorOnline',
|
||||
// isLink: '',
|
||||
// isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-user-circle',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/monitor/server', name: 'monitorServer',
|
||||
// component: () => import('/@/views/monitor/server/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorServer',
|
||||
// isLink: '',
|
||||
// isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-heartbeat',
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// path: '/monitor/cache', name: 'monitorCache',
|
||||
// component: () => import('/@/views/monitor/cache/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.monitorCache',
|
||||
// isLink: '',
|
||||
// isHide: false, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'],
|
||||
// icon: 'fa fa-delicious',
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// //公告主页面不显示
|
||||
// {
|
||||
// path: '/facade/notice', name: 'facadeNotice',
|
||||
// component: () => import('/@/views/common/dashboard/atv/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.facadeNotice',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-rss-square',
|
||||
// },
|
||||
// },
|
||||
// //登陆页面不显示
|
||||
// {
|
||||
// path: '/login', name: 'facadeLogin',
|
||||
// component: () => import('/@/views/facade/login/index.vue'),
|
||||
// meta: { isHide: true, title: 'message.router.login', },
|
||||
// },
|
||||
// //个人信息 不显示
|
||||
// //component: () => import('/@/views/facade/personal/index.vue'),
|
||||
// {
|
||||
// path: '/personal', name: 'personal',
|
||||
// component: () => import('/@/views/facade/personal/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.personal',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin', 'common'], icon: 'fa fa-male',
|
||||
// },
|
||||
// },
|
||||
// //权限设置2 不显示
|
||||
// {
|
||||
// path: '/system/perm/rolePerm', name: 'rolePerm',
|
||||
// component: () => import('/@/views/system/perm/perm/index.vue'),
|
||||
// meta: {
|
||||
// title: 'message.router.rolePerm',
|
||||
// isLink: '', isHide: true, isKeepAlive: true,
|
||||
// isAffix: false, isIframe: false,
|
||||
// roles: ['admin'],
|
||||
// icon: 'fa fa-balance-scale',
|
||||
// },
|
||||
// },
|
||||
|
||||
|
||||
],
|
||||
|
||||
|
||||
},
|
||||
// 重点:大屏路由使用独立布局
|
||||
{
|
||||
path: '/big-screen',
|
||||
name: 'big-screen',
|
||||
// 改为使用全屏布局组件,而非主布局
|
||||
component: () => import('/@/layout/FullScreenLayout.vue'),
|
||||
meta: {
|
||||
isKeepAlive: true,
|
||||
title: '数据大屏',
|
||||
roles: ['admin']
|
||||
},
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
254
src/views/common/screen-vue3/api/api.ts
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* @LastEditors: 刘嘉威 daidaibg@163.com
|
||||
* @LastEditTime: 2024-03-28 16:52:31
|
||||
*/
|
||||
import axios from "axios";
|
||||
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import { StorageEnum, RequestEnum } from "/@/views/common/screen-vue3/enums";
|
||||
import { getLocalStorage } from "/@/views/common/screen-vue3/utils";
|
||||
|
||||
import UtilVar from "../config/UtilVar";
|
||||
let baseUrl = UtilVar.baseUrl;
|
||||
const CancelToken = axios.CancelToken;
|
||||
|
||||
export { baseUrl };
|
||||
// axios.defaults.withCredentials = true;
|
||||
// 添加请求拦截器
|
||||
axios.interceptors.request.use(
|
||||
function (config: any) {
|
||||
// 在发送请求之前做些什么 传token
|
||||
let token: any = getLocalStorage(StorageEnum.GB_TOKEN_STORE);
|
||||
if (token) {
|
||||
// @ts-ignore
|
||||
config.headers.common[RequestEnum.GB_TOKEN_KEY] = token;
|
||||
}
|
||||
// @ts-ignore
|
||||
config.headers["Content-Type"] = "application/json;charset=utf-8";
|
||||
|
||||
return config;
|
||||
},
|
||||
function (error: any) {
|
||||
// 对请求错误做些什么
|
||||
console.log(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export type Params = { [key: string]: string | number };
|
||||
export type FileConfig = {
|
||||
setCancel?: Function;
|
||||
onProgress?: Function;
|
||||
[key: string]: any;
|
||||
};
|
||||
// @ts-ignore
|
||||
/**
|
||||
* @响应拦截
|
||||
*/
|
||||
axios.interceptors.response.use(
|
||||
(response: any) => {
|
||||
// console.log("response", response);
|
||||
if (response.status !== 200) {
|
||||
return Promise.reject(response);
|
||||
}
|
||||
/**
|
||||
* @code 登录过期 token验证失败 根据后端调
|
||||
*/
|
||||
if (response.data.code == UtilVar.code) {
|
||||
// router.push("/login")
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
},
|
||||
(error: any) => {
|
||||
console.log("error", error);
|
||||
let err = {
|
||||
success: false,
|
||||
msg: "未知异常,请联系管理员!",
|
||||
code: 400,
|
||||
};
|
||||
if (JSON.stringify(error).indexOf("Network Error") != -1) {
|
||||
err.msg = "网络错误或服务错误!";
|
||||
}
|
||||
if (error.message == "canceled") {
|
||||
err.msg = "取消请求";
|
||||
err.code = 488;
|
||||
}
|
||||
// console.log(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
);
|
||||
|
||||
//判断是否是加密参数,是的话处理
|
||||
let isEncryptionParam = (params: Params) => {
|
||||
return params;
|
||||
};
|
||||
/**
|
||||
* @description: get 请求方法
|
||||
* @param {string} url 请求地址
|
||||
* @param {Params} params 请求参数
|
||||
* @return {*}
|
||||
*/
|
||||
export const GET = async (url: string, params: Params): Promise<any> => {
|
||||
try {
|
||||
params = isEncryptionParam(params);
|
||||
const data = await axios.get(`${baseUrl}${url}`, {
|
||||
params: params,
|
||||
});
|
||||
return data.data;
|
||||
} catch (error: any) {
|
||||
return Promise.reject(error.msg);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @description: post请求方法
|
||||
* @param {any} url
|
||||
* @param {any} params
|
||||
* @return {any}
|
||||
*/
|
||||
export const POST = async (url: string, params: Params): Promise<any> => {
|
||||
try {
|
||||
params = isEncryptionParam(params);
|
||||
const data = await axios.post(`${baseUrl}${url}`, params);
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @description: 没有基地址 访问根目录下文件
|
||||
* @param {string} url
|
||||
* @param {Params} params
|
||||
* @return {*}
|
||||
*/
|
||||
export const GETNOBASE = async (url: string, params?: Params): Promise<any> => {
|
||||
try {
|
||||
const data = await axios.get(url, {
|
||||
params: params,
|
||||
});
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
// 定义文件类型提交方法
|
||||
interface fileconfigs {
|
||||
[headers: string]: {
|
||||
"Content-Type": string;
|
||||
};
|
||||
}
|
||||
let configs: fileconfigs = {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
};
|
||||
/**
|
||||
* @description: @文件类型提交方法
|
||||
* @param {string} url
|
||||
* @param {Params} params
|
||||
* @param {FileConfig} config
|
||||
* @return {*}
|
||||
*/
|
||||
export const FILEPOST = async (url: string, params: Params, config: FileConfig = {}): Promise<any> => {
|
||||
try {
|
||||
const data = await axios.post(`${baseUrl}${url}`, params, {
|
||||
...configs,
|
||||
cancelToken: new CancelToken(function executor(c: any) {
|
||||
config.setCancel && config.setCancel(c);
|
||||
}),
|
||||
// 上传进度
|
||||
onUploadProgress: (e: any) => {
|
||||
if (e.total > 0) {
|
||||
e.percent = (e.loaded / e.total) * 100;
|
||||
}
|
||||
config.onProgress && config.onProgress(e);
|
||||
},
|
||||
});
|
||||
return data;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 下载文档流
|
||||
* @param {config.responseType} 下载文件流根据后端 配置 arraybuffer || blod
|
||||
*/
|
||||
export const FILE = async (config: FileConfig = {}) => {
|
||||
try {
|
||||
const data = await axios({
|
||||
method: config.method || "get",
|
||||
url: `${baseUrl}${config.url}`,
|
||||
data: config.body || {},
|
||||
params: config.param || {},
|
||||
responseType: config.responseType || "blod",
|
||||
onDownloadProgress: (e: any) => {
|
||||
// console.log(e,e.currentTarget)
|
||||
// if (e.currentTarget.response.size > 0) {
|
||||
// e.percent = e.loaded / e.currentTarget.response.size * 100;
|
||||
// }
|
||||
// event.srcElement.getResponseHeader('content-length')
|
||||
config.onProgress && config.onProgress(e);
|
||||
},
|
||||
});
|
||||
return data;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const PUT = async (url: string, params: Params) => {
|
||||
try {
|
||||
params = isEncryptionParam(params);
|
||||
const data = await axios.put(`${baseUrl}${url}`, params);
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
export const DELETE = async (url: string, params: Params) => {
|
||||
// console.log(params)
|
||||
try {
|
||||
params = isEncryptionParam(params);
|
||||
const data = await axios.delete(`${baseUrl}${url}`, { data: params });
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
// switch (error.response?.status) {
|
||||
// case 400:
|
||||
// error.message = '请求错误(400)';
|
||||
// break;
|
||||
// case 401:
|
||||
// error.message = '未授权(401)';
|
||||
// break;
|
||||
// case 403:
|
||||
// error.message = '拒绝访问(403)';
|
||||
// break;
|
||||
// case 404:
|
||||
// error.message = '请求出错(404)';
|
||||
// break;
|
||||
// case 408:
|
||||
// error.message = '请求超时(408)';
|
||||
// break;
|
||||
// case 500:
|
||||
// error.message = '服务器错误(500)';
|
||||
// break;
|
||||
// case 501:
|
||||
// error.message = '服务未实现(501)';
|
||||
// break;
|
||||
// case 502:
|
||||
// error.message = '网络错误(502)';
|
||||
// break;
|
||||
// case 503:
|
||||
// error.message = '服务不可用(503)';
|
||||
// break;
|
||||
// case 504:
|
||||
// error.message = '网络超时(504)';
|
||||
// break;
|
||||
// case 505:
|
||||
// error.message = 'HTTP版本不受支持(505)';
|
||||
// break;
|
||||
// default:
|
||||
// error.message = `连接出错(${error.response?.status})!`;
|
||||
// }
|
11
src/views/common/screen-vue3/api/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* @Author: daidai
|
||||
* @Date: 2021-12-23 11:18:37
|
||||
|
||||
* @LastEditTime: 2024-03-28 16:07:20
|
||||
* @FilePath: \web-pc-svn\src\api\modules\index.js
|
||||
*/
|
||||
|
||||
import {GETNOBASE} from "./api";
|
||||
export * from "./modules/index"
|
||||
export {GETNOBASE}
|
54
src/views/common/screen-vue3/api/modules/index.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import {GET,POST,FILE,FILEPOST,PUT,GETNOBASE} from "../api";
|
||||
const indexUrl= {
|
||||
'leftTop':'/bigscreen/countDeviceNum',//左上
|
||||
'leftCenter':'/bigscreen/countUserNum',//左中
|
||||
"centerMap":"/bigscreen/centerMap",
|
||||
"centerBottom":"/bigscreen/installationPlan",
|
||||
|
||||
'leftBottom':"/bigscreen/leftBottom", //坐下
|
||||
'rightTop':"/bigscreen/alarmNum", //报警次数
|
||||
'rightBottom':'/bigscreen/rightBottom',//右下
|
||||
'rightCenter':'/bigscreen/ranking',// 报警排名
|
||||
}
|
||||
|
||||
export default indexUrl
|
||||
|
||||
/**左上--设备内总览 */
|
||||
export const countDeviceNum=(param:any={})=>{
|
||||
return GET(indexUrl.leftTop,param)
|
||||
}
|
||||
|
||||
/**左中--用户总览 */
|
||||
export const countUserNum=(param:any={})=>{
|
||||
return GET(indexUrl.leftCenter,param)
|
||||
}
|
||||
|
||||
/**左下--设备提醒 */
|
||||
export const leftBottom=(param:any={})=>{
|
||||
return GET(indexUrl.leftBottom,param)
|
||||
}
|
||||
|
||||
/**中上--地图 */
|
||||
export const centerMap=(param:any={})=>{
|
||||
return GET(indexUrl.centerMap,param)
|
||||
}
|
||||
|
||||
/**中下--安装计划 */
|
||||
export const installationPlan=(param:any={})=>{
|
||||
return GET(indexUrl.centerBottom,param)
|
||||
}
|
||||
|
||||
/**右上--报警次数 */
|
||||
export const alarmNum=(param:any={})=>{
|
||||
return GET(indexUrl.rightTop,param)
|
||||
}
|
||||
|
||||
/**右中--报警排名 */
|
||||
export const ranking=(param:any={})=>{
|
||||
return GET(indexUrl.rightCenter,param)
|
||||
}
|
||||
|
||||
/**右下--设备状态 */
|
||||
export const rightBottom=(param:any={})=>{
|
||||
return GET(indexUrl.rightBottom,param)
|
||||
}
|
98
src/views/common/screen-vue3/assets/css/main.scss
Normal file
@ -0,0 +1,98 @@
|
||||
html,body{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
#app{
|
||||
.content_wrap{
|
||||
color: #d3d6dd;
|
||||
}
|
||||
}
|
||||
|
||||
html .el-message {
|
||||
--yh-bg-color-container:#242424;
|
||||
--yh-shadow-3: 0 16px 24px rgba(0, 0, 0, .14), 0 6px 30px rgba(0, 0, 0, 12%), 0 8px 10px rgba(0, 0, 0, 20%);
|
||||
--yh-shadow-inset-top: inset 0 .5px 0 #5e5e5e;
|
||||
--yh-shadow-inset-right: inset .5px 0 0 #5e5e5e;
|
||||
--yh-shadow-inset-bottom: inset 0 -.5px 0 #5e5e5e;
|
||||
--yh-shadow-inset-left: inset -.5px 0 0 #5e5e5e;
|
||||
--yh-text-color-primary:rgba(255, 255, 255, .9);
|
||||
--yh-brand-color: #0052d9;
|
||||
--yh-success-color: #059465;
|
||||
--yh-error-color: #c64751;
|
||||
--yh-warning-color: #cf6e2d;
|
||||
|
||||
background-color: var(--yh-bg-color-container) ;
|
||||
box-shadow: var(--yh-shadow-3), var(--yh-shadow-inset-top),
|
||||
var(--yh-shadow-inset-right), var(--yh-shadow-inset-bottom),
|
||||
var(--yh-shadow-inset-left);
|
||||
border: none ;
|
||||
color: var(--yh-text-color-primary) ;
|
||||
margin-top: 90px;
|
||||
.el-message__icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
&.el-message--info .el-message__icon {
|
||||
color: var(--yh-brand-color);
|
||||
}
|
||||
|
||||
&.el-message--success .el-message__icon {
|
||||
color: var(--yh-success-color);
|
||||
}
|
||||
|
||||
&.el-message--warning .el-message__icon {
|
||||
color: var(--yh-warning-color);
|
||||
}
|
||||
|
||||
&.el-message--error .el-message__icon {
|
||||
color: var(--yh-error-color);
|
||||
}
|
||||
|
||||
.el-message__content {
|
||||
color: var(--yh-text-color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
.beautify-scroll-def {
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
//滚动条的设置
|
||||
background-color: rgba(14, 59, 150, 0);
|
||||
background-clip: padding-box;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
//滚动条的设置
|
||||
background-color: rgba(14, 59, 150, 0.5);
|
||||
background-clip: padding-box;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
//滚动条凹槽的颜色,还可以设置边框属性
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
//滚动条的宽度
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(14, 59, 150, .8);
|
||||
}
|
||||
}
|
||||
|
||||
.text-content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
min-height: calc(100% - 60px);
|
||||
justify-content: space-between;
|
||||
}
|
7
src/views/common/screen-vue3/assets/css/tailwind.css
Normal file
@ -0,0 +1,7 @@
|
||||
@import "tailwindcss/base";
|
||||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
||||
|
||||
/* @tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities; */
|
1
src/views/common/screen-vue3/assets/css/variable.scss
Normal file
@ -0,0 +1 @@
|
||||
$primary-color: #1890ff;
|
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 25 KiB |
BIN
src/views/common/screen-vue3/assets/img/guang.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
src/views/common/screen-vue3/assets/img/headers/juxing1.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/views/common/screen-vue3/assets/img/headers/juxing2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/views/common/screen-vue3/assets/img/headers/setting.png
Normal file
After Width: | Height: | Size: 323 B |
BIN
src/views/common/screen-vue3/assets/img/left_top_hong.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
src/views/common/screen-vue3/assets/img/left_top_huang.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
src/views/common/screen-vue3/assets/img/left_top_lan.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
src/views/common/screen-vue3/assets/img/left_top_lv.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
src/views/common/screen-vue3/assets/img/pageBg.png
Normal file
After Width: | Height: | Size: 289 KiB |
BIN
src/views/common/screen-vue3/assets/img/titles/you.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/views/common/screen-vue3/assets/img/titles/zuo.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
src/views/common/screen-vue3/assets/img/top.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
src/views/common/screen-vue3/assets/img/xieyou.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/views/common/screen-vue3/assets/img/xiezuo.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/views/common/screen-vue3/assets/img/zuo_xuxian.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,3 @@
|
||||
import MessageContent from './index.vue';
|
||||
|
||||
export default MessageContent ;
|
@ -0,0 +1,8 @@
|
||||
<!-- eslint-disable vue/valid-template-root -->
|
||||
<template></template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
//挂载在 window 方便与在js中使用
|
||||
window['$message'] = ElMessage
|
||||
</script>
|
146
src/views/common/screen-vue3/components/count-up/count-up.vue
Normal file
@ -0,0 +1,146 @@
|
||||
<script lang="ts">
|
||||
export type { CountUp as ICountUp, CountUpOptions } from 'countup.js'
|
||||
export default {
|
||||
name: 'CountUp'
|
||||
}
|
||||
</script>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { CountUp } from 'countup.js'
|
||||
import type { CountUpOptions } from 'countup.js'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 结束数值
|
||||
endVal: number | string
|
||||
// 开始数值
|
||||
startVal?: number | string
|
||||
// 动画时长,单位 s
|
||||
duration?: number | string
|
||||
// 是否自动计数
|
||||
autoplay?: boolean
|
||||
// 循环次数,有限次数 / 无限循环
|
||||
loop?: boolean | number | string
|
||||
// 延时,单位 s
|
||||
delay?: number
|
||||
// countup 配置项
|
||||
options?: CountUpOptions
|
||||
}>(),
|
||||
{
|
||||
startVal: 0,
|
||||
duration: 2.5,
|
||||
autoplay: true,
|
||||
loop: false,
|
||||
delay: 0,
|
||||
options: undefined
|
||||
}
|
||||
)
|
||||
const emits = defineEmits<{
|
||||
// countup init complete
|
||||
(event: 'init', countup: CountUp): void
|
||||
// count complete
|
||||
(event: 'finished'): void
|
||||
}>()
|
||||
|
||||
let elRef = ref<HTMLElement>()
|
||||
let countUp = ref<CountUp>()
|
||||
|
||||
const initCountUp = () => {
|
||||
if (!elRef.value) return
|
||||
const startVal = Number(props.startVal)
|
||||
const endVal = Number(props.endVal)
|
||||
const duration = Number(props.duration)
|
||||
countUp.value = new CountUp(elRef.value, endVal, {
|
||||
startVal,
|
||||
duration,
|
||||
...props.options
|
||||
})
|
||||
if (countUp.value.error) {
|
||||
console.error(countUp.value.error)
|
||||
return
|
||||
}
|
||||
emits('init', countUp.value)
|
||||
}
|
||||
|
||||
const startAnim = (cb?: () => void) => {
|
||||
countUp.value?.start(cb)
|
||||
}
|
||||
|
||||
// endVal change & autoplay: true, restart animate
|
||||
watch(
|
||||
() => props.endVal,
|
||||
(value) => {
|
||||
if (props.autoplay) {
|
||||
countUp.value?.update(value)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// loop animation
|
||||
const finished = ref(false)
|
||||
let loopCount = 0
|
||||
const loopAnim = () => {
|
||||
loopCount++
|
||||
startAnim(() => {
|
||||
const isTruely = typeof props.loop === 'boolean' && props.loop
|
||||
if (isTruely || props.loop > loopCount) {
|
||||
delay(() => {
|
||||
countUp.value?.reset()
|
||||
loopAnim()
|
||||
}, props.delay)
|
||||
} else {
|
||||
finished.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
watch(finished, (flag) => {
|
||||
if (flag) {
|
||||
emits('finished')
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
initCountUp()
|
||||
if (props.autoplay) {
|
||||
loopAnim()
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
cancelAnimationFrame(dalayRafId)
|
||||
countUp.value?.reset()
|
||||
})
|
||||
|
||||
let dalayRafId: number
|
||||
// delay to execute callback function
|
||||
const delay = (cb: () => unknown, seconds = 1) => {
|
||||
let startTime: number
|
||||
function count(timestamp: number) {
|
||||
if (!startTime) startTime = timestamp
|
||||
const diff = timestamp - startTime
|
||||
if (diff < seconds * 1000) {
|
||||
dalayRafId = requestAnimationFrame(count)
|
||||
} else {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
dalayRafId = requestAnimationFrame(count)
|
||||
}
|
||||
|
||||
const restart = () => {
|
||||
initCountUp()
|
||||
startAnim()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
init: initCountUp,
|
||||
restart
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="countup-wrap">
|
||||
<slot name="prefix"></slot>
|
||||
<span ref="elRef"> </span>
|
||||
<slot name="suffix"></slot>
|
||||
</div>
|
||||
</template>
|
@ -0,0 +1,3 @@
|
||||
import CountUp from "./count-up.vue"
|
||||
export default CountUp
|
||||
|
@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref ,onBeforeUpdate, nextTick} from "vue";
|
||||
import { merge } from "lodash-es";
|
||||
import { useElementSize } from "@vueuse/core";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
type: Array as unknown as PropType<[string, string]>,
|
||||
default: () => [],
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: "transparent",
|
||||
},
|
||||
});
|
||||
const defaultColor = ["#6586ec", "#2cf7fe"];
|
||||
const domRef = ref(null);
|
||||
const { width, height } = useElementSize(domRef,{width:0,height:0}, { box: 'border-box' });
|
||||
const mergedColor = computed<[string, string]>(() => {
|
||||
return merge(defaultColor, props.color);
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dv-border-box-13 dv-border-box" ref="domRef">
|
||||
<svg :width="width" :height="height" class="dv-border-svg-container">
|
||||
<path
|
||||
:fill="backgroundColor"
|
||||
:stroke="mergedColor[0]"
|
||||
:d="`
|
||||
M 5 20 L 5 10 L 12 3 L 60 3 L 68 10
|
||||
L ${width - 20} 10 L ${width - 5} 25
|
||||
L ${width - 5} ${height - 5} L 20 ${height - 5}
|
||||
L 5 ${height - 20} L 5 20
|
||||
`"
|
||||
/>
|
||||
|
||||
<path
|
||||
fill="transparent"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
stroke-dasharray="10, 5"
|
||||
:stroke="mergedColor[0]"
|
||||
:d="`M 16 9 L 61 9`"
|
||||
/>
|
||||
|
||||
<path
|
||||
fill="transparent"
|
||||
stroke="{mergedColor[1]}"
|
||||
:d="`M 5 20 L 5 10 L 12 3 L 60 3 L 68 10`"
|
||||
/>
|
||||
|
||||
<path
|
||||
fill="transparent"
|
||||
:stroke="mergedColor[1]"
|
||||
:d="`M ${width - 5} ${height - 30} L ${width - 5} ${height - 5} L ${
|
||||
width - 30
|
||||
} ${height - 5}`"
|
||||
/>
|
||||
</svg>
|
||||
<div class="dv-border-box-content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dv-border-box {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.dv-border-svg-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
display: block;
|
||||
}
|
||||
.dv-border-box-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,3 @@
|
||||
import BorderBox13 from "./border-box-13.vue"
|
||||
|
||||
export default BorderBox13
|
@ -0,0 +1,186 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref, watch } from "vue";
|
||||
import type { DefaultConfigType } from "./index.d";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { merge } from "lodash-es";
|
||||
const mergedConfig = ref<any>(null);
|
||||
const capsuleLength = ref<any>([]);
|
||||
const capsuleValue = ref<any>([]);
|
||||
const labelData = ref<any>([]);
|
||||
// const labelDataLength = ref<any>([]);
|
||||
|
||||
const defaultConfig = reactive<DefaultConfigType>({
|
||||
// Colors (hex|rgb|rgba|color keywords) ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red']
|
||||
colors: [
|
||||
"#37a2da",
|
||||
"#32c5e9",
|
||||
"#67e0e3",
|
||||
"#9fe6b8",
|
||||
"#ffdb5c",
|
||||
"#ff9f7f",
|
||||
"#fb7293",
|
||||
],
|
||||
unit: "",
|
||||
showValue: false, // Show item value
|
||||
});
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
config: object | any;
|
||||
data: Array<{
|
||||
name: string;
|
||||
value: string | number;
|
||||
}>;
|
||||
}>(),
|
||||
{
|
||||
config: () => { },
|
||||
data: () => [],
|
||||
}
|
||||
);
|
||||
const calcData = () => {
|
||||
mergeConfig();
|
||||
calcCapsuleLengthAndLabelData();
|
||||
};
|
||||
const mergeConfig = () => {
|
||||
mergedConfig.value = merge(cloneDeep(defaultConfig), props.config || {});
|
||||
};
|
||||
const calcCapsuleLengthAndLabelData = () => {
|
||||
if (!props.data.length) return;
|
||||
const newcapsuleValue = props.data.map((item: any) => item.value);
|
||||
const maxValue = Math.max(...newcapsuleValue);
|
||||
capsuleValue.value = newcapsuleValue;
|
||||
capsuleLength.value = newcapsuleValue.map((v: any) =>
|
||||
maxValue ? v / maxValue : 0
|
||||
);
|
||||
const oneFifth = maxValue / 5;
|
||||
const newlabelData = Array.from(
|
||||
new Set(new Array(6).fill(0).map((v, i) => Math.ceil(i * oneFifth)))
|
||||
);
|
||||
labelData.value = newlabelData;
|
||||
// labelDataLength.value = Array.from(newlabelData).map((v) =>
|
||||
// maxValue ? v / maxValue : 0
|
||||
// );
|
||||
// console.log(labelDataLength.value);
|
||||
};
|
||||
watch(
|
||||
() => props.data,
|
||||
(newval: any) => {
|
||||
calcData();
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => props.config,
|
||||
(newval: any) => {
|
||||
calcData();
|
||||
},
|
||||
);
|
||||
onMounted(() => {
|
||||
calcData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dv-capsule-chart">
|
||||
<template v-if="mergedConfig">
|
||||
<div class="label-column">
|
||||
<div v-for="item in data" :key="item.name">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
<div> </div>
|
||||
</div>
|
||||
<div class="capsule-container">
|
||||
<div class="capsule-item" v-for="(capsule, index) in capsuleLength" :key="index">
|
||||
<div class="capsule-item-column" :style="`width: ${capsule * 100}%; background-color: ${mergedConfig.colors[index % mergedConfig.colors.length]
|
||||
};`">
|
||||
<div v-if="mergedConfig.showValue" class="capsule-item-value">
|
||||
{{ capsuleValue[index] }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="unit-label">
|
||||
<div v-for="(label, index) in labelData" :key="label + index">
|
||||
{{ label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="unit-text" v-if="mergedConfig.unit">
|
||||
{{ mergedConfig.unit }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dv-capsule-chart {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
|
||||
.label-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding-right: 10px;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
|
||||
div {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.capsule-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.capsule-item {
|
||||
box-shadow: 0 0 3px #999;
|
||||
height: 10px;
|
||||
margin: 5px 0px;
|
||||
border-radius: 5px;
|
||||
|
||||
.capsule-item-column {
|
||||
position: relative;
|
||||
height: 8px;
|
||||
margin-top: 1px;
|
||||
border-radius: 5px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
.capsule-item-value {
|
||||
font-size: 12px;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unit-label {
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.unit-text {
|
||||
text-align: right;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
6
src/views/common/screen-vue3/components/datav/capsule-chart/index.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export interface DefaultConfigType {
|
||||
|
||||
colors: Array<String>;
|
||||
unit:string,
|
||||
showValue:Boolean
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
import CapsuleChart from "./capsule-chart.vue"
|
||||
export * from "./index.d"
|
||||
export default CapsuleChart
|
@ -0,0 +1,9 @@
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
@ -0,0 +1,2 @@
|
||||
import EmptyCom from "./empty-com.vue"
|
||||
export default EmptyCom
|
@ -0,0 +1,2 @@
|
||||
import ItemWrap from "./item-wrap.vue"
|
||||
export default ItemWrap
|
@ -0,0 +1,81 @@
|
||||
<script setup lang="ts">
|
||||
import BorderBox13 from "/@/views/common/screen-vue3/components/datav/border-box-13";
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 标题
|
||||
title: number | string;
|
||||
}>(),
|
||||
{
|
||||
title: "",
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BorderBox13>
|
||||
<div class="item_title" v-if="title !== ''">
|
||||
<div class="zuo"></div>
|
||||
<span class="title-inner"> {{ title }} </span>
|
||||
<div class="you"></div>
|
||||
</div>
|
||||
<div
|
||||
:class="title !== '' ? 'item_title_content' : 'item_title_content_def'"
|
||||
>
|
||||
<slot></slot></div
|
||||
></BorderBox13>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$item-title-height: 38px;
|
||||
$item_title_content-height: calc(100% - 38px);
|
||||
|
||||
.item_title {
|
||||
height: $item-title-height;
|
||||
line-height: $item-title-height;
|
||||
width: 100%;
|
||||
color: #31abe3;
|
||||
text-align: center;
|
||||
// background: linear-gradient(to right, transparent, #0f0756, transparent);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.zuo,
|
||||
.you {
|
||||
width: 58px;
|
||||
height: 14px;
|
||||
background-image: url("@/assets/img/titles/zuo.png");
|
||||
}
|
||||
|
||||
.you {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.title-inner {
|
||||
font-weight: 900;
|
||||
letter-spacing: 2px;
|
||||
background: linear-gradient(
|
||||
92deg,
|
||||
#0072ff 0%,
|
||||
#00eaff 48.8525390625%,
|
||||
#01aaff 100%
|
||||
);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.dv-border-box-content) {
|
||||
box-sizing: border-box;
|
||||
padding: 6px 16px 0px;
|
||||
}
|
||||
|
||||
.item_title_content {
|
||||
height: $item_title_content-height;
|
||||
}
|
||||
|
||||
.item_title_content_def {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,3 @@
|
||||
import ScaleScreen from './scale-screen.vue'
|
||||
|
||||
export default ScaleScreen
|
@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<section
|
||||
:style="{ ...styles.box, ...boxStyle }"
|
||||
class="v-screen-box"
|
||||
ref="box"
|
||||
>
|
||||
<div
|
||||
:style="{ ...styles.wrapper, ...wrapperStyle }"
|
||||
class="screen-wrapper"
|
||||
ref="screenWrapper"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
||||
import type { CSSProperties, PropType } from "vue";
|
||||
/**
|
||||
* 防抖函数
|
||||
* @param {Function} fn
|
||||
* @param {number} delay
|
||||
* @returns {() => void}
|
||||
*/
|
||||
function debounce(fn: Function, delay: number): () => void {
|
||||
// let timer: NodeJS.Timer;
|
||||
let timer: any;
|
||||
return function (...args: any[]): void {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(
|
||||
() => {
|
||||
typeof fn === "function" && fn.apply(null, args);
|
||||
clearTimeout(timer);
|
||||
},
|
||||
delay > 0 ? delay : 100
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
interface IState {
|
||||
originalWidth: string | number;
|
||||
originalHeight: string | number;
|
||||
width?: string | number;
|
||||
height?: string | number;
|
||||
observer: null | MutationObserver;
|
||||
}
|
||||
type IAutoScale =
|
||||
| boolean
|
||||
| {
|
||||
x?: boolean;
|
||||
y?: boolean;
|
||||
};
|
||||
const props = defineProps({
|
||||
width: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: 1920,
|
||||
},
|
||||
height: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
default: 1080,
|
||||
},
|
||||
fullScreen: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
autoScale: {
|
||||
type: [Object, Boolean] as PropType<IAutoScale>,
|
||||
default: true,
|
||||
},
|
||||
delay: {
|
||||
type: Number as PropType<number>,
|
||||
default: 500,
|
||||
},
|
||||
boxStyle: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: () => ({}),
|
||||
},
|
||||
wrapperStyle: {
|
||||
type: Object as PropType<CSSProperties>,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const state = reactive<IState>({
|
||||
width: 0,
|
||||
height: 0,
|
||||
originalWidth: 0,
|
||||
originalHeight: 0,
|
||||
observer: null,
|
||||
});
|
||||
|
||||
const styles: Record<string, CSSProperties> = {
|
||||
box: {
|
||||
overflow: "hidden",
|
||||
backgroundSize: `100% 100%`,
|
||||
background: `#000`,
|
||||
width: `100vw`,
|
||||
height: `100vh`,
|
||||
},
|
||||
wrapper: {
|
||||
transitionProperty: `all`,
|
||||
transitionTimingFunction: `cubic-bezier(0.4, 0, 0.2, 1)`,
|
||||
transitionDuration: `500ms`,
|
||||
position: `relative`,
|
||||
overflow: `hidden`,
|
||||
zIndex: 100,
|
||||
transformOrigin: `left top`,
|
||||
},
|
||||
};
|
||||
|
||||
const screenWrapper = ref<HTMLElement>();
|
||||
const box = ref<HTMLElement>();
|
||||
|
||||
watch(
|
||||
() => props.autoScale,
|
||||
async (newVal: any) => {
|
||||
if (newVal) {
|
||||
onResize();
|
||||
addListener();
|
||||
} else {
|
||||
clearListener();
|
||||
clearScreenWrapperStyle();
|
||||
}
|
||||
}
|
||||
);
|
||||
/**
|
||||
* 初始化大屏容器宽高
|
||||
*/
|
||||
const initSize = () => {
|
||||
return new Promise<void>((resolve) => {
|
||||
box.value!.scrollLeft = 0;
|
||||
box.value!.scrollTop = 0;
|
||||
nextTick(() => {
|
||||
// region 获取大屏真实尺寸
|
||||
if (props.width && props.height) {
|
||||
state.width = props.width;
|
||||
state.height = props.height;
|
||||
} else {
|
||||
state.width = screenWrapper.value?.clientWidth;
|
||||
state.height = screenWrapper.value?.clientHeight;
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 获取画布尺寸
|
||||
if (!state.originalHeight || !state.originalWidth) {
|
||||
state.originalWidth = window.screen.width;
|
||||
state.originalHeight = window.screen.height;
|
||||
}
|
||||
// endregion
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新大屏容器宽高
|
||||
*/
|
||||
const updateSize = () => {
|
||||
if (state.width && state.height) {
|
||||
screenWrapper.value!.style.width = `${state.width}px`;
|
||||
screenWrapper.value!.style.height = `${state.height}px`;
|
||||
} else {
|
||||
screenWrapper.value!.style.width = `${state.originalWidth}px`;
|
||||
screenWrapper.value!.style.height = `${state.originalHeight}px`;
|
||||
}
|
||||
};
|
||||
const clearScreenWrapperStyle = () => {
|
||||
screenWrapper.value!.style.transform = "";
|
||||
screenWrapper.value!.style.margin = "";
|
||||
};
|
||||
const autoScale = (scale: number) => {
|
||||
if (!props.autoScale) {
|
||||
return;
|
||||
}
|
||||
const domWidth = screenWrapper.value!.clientWidth;
|
||||
const domHeight = screenWrapper.value!.clientHeight;
|
||||
const currentWidth = document.body.clientWidth;
|
||||
const currentHeight = document.body.clientHeight;
|
||||
screenWrapper.value!.style.transform = `scale(${scale},${scale})`;
|
||||
let mx = Math.max((currentWidth - domWidth * scale) / 2, 0);
|
||||
let my = Math.max((currentHeight - domHeight * scale) / 2, 0);
|
||||
if (typeof props.autoScale === "object") {
|
||||
!props.autoScale.x && (mx = 0);
|
||||
!props.autoScale.y && (my = 0);
|
||||
}
|
||||
screenWrapper.value!.style.margin = `${my}px ${mx}px`;
|
||||
};
|
||||
const updateScale = () => {
|
||||
// 获取真实视口尺寸
|
||||
const currentWidth = document.body.clientWidth;
|
||||
const currentHeight = document.body.clientHeight;
|
||||
// 获取大屏最终的宽高
|
||||
const realWidth = state.width || state.originalWidth;
|
||||
const realHeight = state.height || state.originalHeight;
|
||||
// 计算缩放比例
|
||||
const widthScale = currentWidth / +realWidth;
|
||||
const heightScale = currentHeight / +realHeight;
|
||||
// 若要铺满全屏,则按照各自比例缩放
|
||||
if (props.fullScreen) {
|
||||
screenWrapper.value!.style.transform = `scale(${widthScale},${heightScale})`;
|
||||
return false;
|
||||
}
|
||||
// 按照宽高最小比例进行缩放
|
||||
const scale = Math.min(widthScale, heightScale);
|
||||
autoScale(scale);
|
||||
};
|
||||
|
||||
const onResize = debounce(async () => {
|
||||
await initSize();
|
||||
updateSize();
|
||||
updateScale();
|
||||
}, props.delay);
|
||||
const initMutationObserver = () => {
|
||||
const observer = (state.observer = new MutationObserver(() => {
|
||||
onResize();
|
||||
}));
|
||||
observer.observe(screenWrapper.value!, {
|
||||
attributes: true,
|
||||
attributeFilter: ["style"],
|
||||
attributeOldValue: true,
|
||||
});
|
||||
};
|
||||
|
||||
const clearListener = () => {
|
||||
window.removeEventListener("resize", onResize);
|
||||
// state.observer?.disconnect();
|
||||
};
|
||||
|
||||
const addListener = () => {
|
||||
window.addEventListener("resize", onResize);
|
||||
// initMutationObserver();
|
||||
};
|
||||
onMounted(() => {
|
||||
nextTick(async () => {
|
||||
await initSize();
|
||||
updateSize();
|
||||
updateScale();
|
||||
addListener();
|
||||
// initMutationObserver();
|
||||
});
|
||||
});
|
||||
onUnmounted(() => {
|
||||
clearListener();
|
||||
// state.observer?.disconnect();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,2 @@
|
||||
import SeamlessScroll from "./seamless-scroll.vue"
|
||||
export default SeamlessScroll
|
@ -0,0 +1,408 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
onBeforeMount,
|
||||
onMounted,
|
||||
ref,
|
||||
watch,
|
||||
nextTick,
|
||||
} from "vue";
|
||||
import type { CSSProperties } from "vue";
|
||||
import { throttle } from "lodash-es";
|
||||
type propsType = {
|
||||
modelValue?: boolean;
|
||||
list: Array<any>;
|
||||
step?: number;
|
||||
limitScrollNum?: number;
|
||||
hover?: boolean;
|
||||
direction?: string;
|
||||
singleHeight?: number;
|
||||
singleWidth?: number;
|
||||
singleWaitTime?: number;
|
||||
isRemUnit?: boolean;
|
||||
isWatch?: boolean;
|
||||
delay?: number;
|
||||
ease?: any;
|
||||
count?: number;
|
||||
copyNum?: number;
|
||||
wheel?: boolean;
|
||||
singleLine?: boolean;
|
||||
};
|
||||
const props = withDefaults(defineProps<propsType>(), {
|
||||
// 是否开启自动滚动
|
||||
modelValue: true,
|
||||
// 原始数据列表
|
||||
list: () => [],
|
||||
// 步进速度,step 需是单步大小的约数
|
||||
step: 1,
|
||||
// 开启滚动的数据量
|
||||
limitScrollNum: 3,
|
||||
// 是否开启鼠标悬停
|
||||
hover: false,
|
||||
// 控制滚动方向
|
||||
direction: "up",
|
||||
// 单步运动停止的高度
|
||||
singleHeight: 0,
|
||||
// 单步运动停止的宽度
|
||||
singleWidth: 0,
|
||||
// 单步停止等待时间 (默认值 1000ms)
|
||||
singleWaitTime: 1000,
|
||||
// 是否开启 rem 度量
|
||||
isRemUnit: false,
|
||||
// 开启数据更新监听
|
||||
isWatch: true,
|
||||
// 动画时间
|
||||
delay: 0,
|
||||
// 动画方式
|
||||
ease: "ease-in",
|
||||
// 动画循环次数,-1 表示一直动画
|
||||
count: -1,
|
||||
// 拷贝几份滚动列表
|
||||
copyNum: 1,
|
||||
// 开启鼠标悬停时支持滚轮滚动
|
||||
wheel: false,
|
||||
// 启用单行滚动
|
||||
singleLine: false,
|
||||
});
|
||||
interface Emits {
|
||||
(event: "count", _count: number): void;
|
||||
(event: "stop", _count: number): void;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
const scrollRef = ref(null);
|
||||
const slotListRef = ref<HTMLDivElement | null>(null);
|
||||
const realBoxRef = ref<HTMLDivElement | null>(null);
|
||||
const reqFrame = ref<number | null>(null);
|
||||
type TimeProp= NodeJS.Timeout
|
||||
const singleWaitTimeout = ref<TimeProp | null>(null);
|
||||
const realBoxWidth = ref(0);
|
||||
const realBoxHeight = ref(0);
|
||||
const xPos = ref(0);
|
||||
const yPos = ref(0);
|
||||
const isHover = ref(false);
|
||||
const _count = ref(0);
|
||||
const isScroll = computed(() =>
|
||||
props.list ? props.list.length >= props.limitScrollNum : false
|
||||
);
|
||||
const realBoxStyle = computed(() => {
|
||||
return {
|
||||
width: realBoxWidth.value ? `${realBoxWidth.value}px` : "auto",
|
||||
transform: `translate(${xPos.value}px,${yPos.value}px)`,
|
||||
transition: `all ${
|
||||
typeof props.ease === "string"
|
||||
? props.ease
|
||||
: "cubic-bezier(" +
|
||||
props.ease.x1 +
|
||||
"," +
|
||||
props.ease.y1 +
|
||||
"," +
|
||||
props.ease.x2 +
|
||||
"," +
|
||||
props.ease.y2 +
|
||||
")"
|
||||
} ${props.delay}ms`,
|
||||
overflow: "hidden",
|
||||
display: props.singleLine ? "flex" : "block",
|
||||
};
|
||||
});
|
||||
const isHorizontal = computed(
|
||||
() => props.direction == "left" || props.direction == "right"
|
||||
);
|
||||
|
||||
function dataWarm(list: any) {
|
||||
if (list && typeof list !== "boolean" && list.length > 100) {
|
||||
console.warn(
|
||||
`数据达到了${list.length}条有点多哦~,可能会造成部分老旧浏览器卡顿。`
|
||||
);
|
||||
}
|
||||
}
|
||||
const floatStyle = computed<CSSProperties>(() => {
|
||||
return isHorizontal.value
|
||||
? {
|
||||
float: "left",
|
||||
overflow: "hidden",
|
||||
display: props.singleLine ? "flex" : "block",
|
||||
flexShrink: props.singleLine ? 0 : 1,
|
||||
}
|
||||
: { overflow: "hidden" };
|
||||
});
|
||||
const baseFontSize = computed(() => {
|
||||
return props.isRemUnit
|
||||
? parseInt(
|
||||
globalThis.window.getComputedStyle(
|
||||
globalThis.document.documentElement,
|
||||
null
|
||||
).fontSize
|
||||
)
|
||||
: 1;
|
||||
});
|
||||
const realSingleStopWidth = computed(
|
||||
() => props.singleWidth * baseFontSize.value
|
||||
);
|
||||
|
||||
const realSingleStopHeight = computed(
|
||||
() => props.singleHeight * baseFontSize.value
|
||||
);
|
||||
|
||||
const step = computed(() => {
|
||||
let singleStep: number;
|
||||
let _step = props.step;
|
||||
if (isHorizontal.value) {
|
||||
singleStep = realSingleStopWidth.value;
|
||||
} else {
|
||||
singleStep = realSingleStopHeight.value;
|
||||
}
|
||||
if (singleStep > 0 && singleStep % _step > 0) {
|
||||
console.error(
|
||||
"如果设置了单步滚动,step 需是单步大小的约数,否则无法保证单步滚动结束的位置是否准确。~~~~~"
|
||||
);
|
||||
}
|
||||
return _step;
|
||||
});
|
||||
|
||||
const cancle = () => {
|
||||
cancelAnimationFrame(reqFrame.value as number);
|
||||
reqFrame.value = null;
|
||||
};
|
||||
const animation = (
|
||||
_direction: "up" | "down" | "left" | "right",
|
||||
_step: number,
|
||||
isWheel?: boolean
|
||||
) => {
|
||||
// console.log("animation",_direction,_step,isWheel);
|
||||
reqFrame.value = requestAnimationFrame(function () {
|
||||
const h = realBoxHeight.value / 2;
|
||||
const w = realBoxWidth.value / 2;
|
||||
if (_direction === "up") {
|
||||
if (Math.abs(yPos.value) >= h) {
|
||||
yPos.value = 0;
|
||||
_count.value += 1;
|
||||
emit("count", _count.value);
|
||||
}
|
||||
yPos.value -= _step;
|
||||
} else if (_direction === "down") {
|
||||
if (yPos.value >= 0) {
|
||||
yPos.value = h * -1;
|
||||
_count.value += 1;
|
||||
emit("count", _count.value);
|
||||
}
|
||||
yPos.value += _step;
|
||||
} else if (_direction === "left") {
|
||||
if (Math.abs(xPos.value) >= w) {
|
||||
xPos.value = 0;
|
||||
_count.value += 1;
|
||||
emit("count", _count.value);
|
||||
}
|
||||
xPos.value -= _step;
|
||||
} else if (_direction === "right") {
|
||||
if (xPos.value >= 0) {
|
||||
xPos.value = w * -1;
|
||||
_count.value += 1;
|
||||
emit("count", _count.value);
|
||||
}
|
||||
xPos.value += _step;
|
||||
}
|
||||
if (isWheel) {
|
||||
return;
|
||||
}
|
||||
let { singleWaitTime } = props;
|
||||
if (singleWaitTimeout.value) {
|
||||
clearTimeout(singleWaitTimeout.value);
|
||||
}
|
||||
if (!!realSingleStopHeight.value) {
|
||||
if (Math.abs(yPos.value) % realSingleStopHeight.value < _step) {
|
||||
singleWaitTimeout.value = setTimeout(() => {
|
||||
move();
|
||||
}, singleWaitTime);
|
||||
} else {
|
||||
move();
|
||||
}
|
||||
} else if (!!realSingleStopWidth.value) {
|
||||
if (Math.abs(xPos.value) % realSingleStopWidth.value < _step) {
|
||||
singleWaitTimeout.value = setTimeout(() => {
|
||||
move();
|
||||
}, singleWaitTime);
|
||||
} else {
|
||||
move();
|
||||
}
|
||||
} else {
|
||||
move();
|
||||
}
|
||||
});
|
||||
};
|
||||
const move = () => {
|
||||
cancle();
|
||||
if (isHover.value || !isScroll.value || _count.value === props.count) {
|
||||
emit("stop", _count.value);
|
||||
_count.value = 0;
|
||||
return;
|
||||
}
|
||||
animation(
|
||||
props.direction as "up" | "down" | "left" | "right",
|
||||
step.value,
|
||||
false
|
||||
);
|
||||
};
|
||||
const initMove = () => {
|
||||
dataWarm(props.list);
|
||||
if (isHorizontal.value) {
|
||||
let slotListWidth = (slotListRef.value as HTMLDivElement).offsetWidth;
|
||||
slotListWidth = slotListWidth * 2 + 1;
|
||||
realBoxWidth.value = slotListWidth;
|
||||
}
|
||||
if (isScroll.value) {
|
||||
realBoxHeight.value = (realBoxRef.value as HTMLDivElement).offsetHeight;
|
||||
if (props.modelValue) {
|
||||
move();
|
||||
}
|
||||
} else {
|
||||
cancle();
|
||||
yPos.value = xPos.value = 0;
|
||||
}
|
||||
// console.log("initMove","isHorizontal",isHorizontal.value,"isScroll",isScroll.value,realBoxRef.value?.offsetHeight);
|
||||
};
|
||||
const startMove = () => {
|
||||
isHover.value = false;
|
||||
move();
|
||||
};
|
||||
|
||||
const stopMove = () => {
|
||||
isHover.value = true;
|
||||
if (singleWaitTimeout.value) {
|
||||
clearTimeout(singleWaitTimeout.value);
|
||||
}
|
||||
cancle();
|
||||
};
|
||||
|
||||
const hoverStop = computed(
|
||||
() => props.hover && props.modelValue && isScroll.value
|
||||
);
|
||||
const throttleFunc = throttle((e: WheelEvent) => {
|
||||
cancle();
|
||||
const singleHeight = !!realSingleStopHeight.value
|
||||
? realSingleStopHeight.value
|
||||
: 15;
|
||||
if (e.deltaY < 0) {
|
||||
animation("down", singleHeight, true);
|
||||
}
|
||||
if (e.deltaY > 0) {
|
||||
animation("up", singleHeight, true);
|
||||
}
|
||||
}, 30);
|
||||
|
||||
const onWheel = (e: WheelEvent) => {
|
||||
throttleFunc(e);
|
||||
};
|
||||
const reset = () => {
|
||||
cancle();
|
||||
isHover.value = false;
|
||||
initMove();
|
||||
};
|
||||
const Reset = () => {
|
||||
reset();
|
||||
};
|
||||
defineExpose({
|
||||
Reset,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.list,
|
||||
() => {
|
||||
if (props.isWatch) {
|
||||
nextTick(() => {
|
||||
reset();
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
startMove();
|
||||
} else {
|
||||
stopMove();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.count,
|
||||
(newValue) => {
|
||||
if (newValue !== 0) {
|
||||
startMove();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onBeforeMount(() => {
|
||||
cancle();
|
||||
clearTimeout(singleWaitTimeout.value as unknown as number);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (isScroll.value) {
|
||||
initMove();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="props.wheel && props.hover"
|
||||
ref="realBoxRef"
|
||||
:style="realBoxStyle"
|
||||
@mouseenter="
|
||||
() => {
|
||||
hoverStop && stopMove();
|
||||
}
|
||||
"
|
||||
@mouseleave="
|
||||
() => {
|
||||
hoverStop && startMove();
|
||||
}
|
||||
"
|
||||
@wheel="
|
||||
(e) => {
|
||||
hoverStop && onWheel(e);
|
||||
}
|
||||
"
|
||||
>
|
||||
<div ref="slotListRef" :style="floatStyle">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div :style="floatStyle">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
:style="realBoxStyle"
|
||||
ref="realBoxRef"
|
||||
@mouseenter="
|
||||
() => {
|
||||
hoverStop && stopMove();
|
||||
}
|
||||
"
|
||||
@mouseleave="
|
||||
() => {
|
||||
hoverStop && startMove();
|
||||
}
|
||||
"
|
||||
>
|
||||
<div ref="slotListRef" :style="floatStyle">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div :style="floatStyle">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
32
src/views/common/screen-vue3/config/UtilVar.ts
Normal file
@ -0,0 +1,32 @@
|
||||
interface UtilVarType {
|
||||
baseUrl:string,
|
||||
code:string|number,
|
||||
noContentCode:number,
|
||||
ENC:boolean,//是否进行加密
|
||||
}
|
||||
|
||||
const UtilVar:UtilVarType = {
|
||||
baseUrl:"",
|
||||
code:401, //登陆过期
|
||||
noContentCode:204, //请求成功但没有内容
|
||||
ENC:false,
|
||||
|
||||
}
|
||||
const runtimeType:any = {
|
||||
|
||||
production: () => {
|
||||
|
||||
},
|
||||
//开发环境
|
||||
development: () => {
|
||||
// UtilVar.baseUrl= `http://www.xihuanmantou.cn:19527`
|
||||
|
||||
},
|
||||
hash:()=>{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// console.log(import.meta.env)
|
||||
runtimeType[import.meta.env.MODE]&&runtimeType[import.meta.env.MODE]()
|
||||
export default UtilVar
|
2
src/views/common/screen-vue3/enums/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./storage-enum"
|
||||
export * from "./request-enums"
|
12
src/views/common/screen-vue3/enums/request-enums.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export enum RequestEnum {
|
||||
// token key
|
||||
GB_TOKEN_KEY = 'auth-token',
|
||||
// 验签key
|
||||
GB_SIGN_KEY = "sign",
|
||||
// 时间戳 key
|
||||
GB_TIMESTAMP_KEY = "timestamp"
|
||||
}
|
||||
export enum ReqCodeEnum {
|
||||
Unauthorized = 401,// token过期
|
||||
Success = 200,//成功
|
||||
}
|
9
src/views/common/screen-vue3/enums/storage-enum.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export enum StorageEnum {
|
||||
// token
|
||||
GB_TOKEN_STORE = 'GB_TOKEN_STORE',
|
||||
|
||||
// 语言
|
||||
YH_LANG_STORE = 'YH_LANG',
|
||||
//皮肤
|
||||
YH_THEME_STORE = 'YH_THEME',
|
||||
}
|
10
src/views/common/screen-vue3/mock/index.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export interface MockParams {
|
||||
url: string;
|
||||
type: string;
|
||||
data?: any;
|
||||
params?: any;
|
||||
response(option?: any): Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function mockXHR(): any;
|
||||
|
13
src/views/common/screen-vue3/mock/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import Mock from 'mockjs'
|
||||
import type { MockParams } from "./index.d";
|
||||
import MockIndex from "./mock-index"
|
||||
Mock.setup({
|
||||
timeout: "300",
|
||||
});
|
||||
const mocks = [...MockIndex];
|
||||
export function mockXHR() {
|
||||
let i: MockParams;
|
||||
for (i of mocks) {
|
||||
Mock.mock(new RegExp(i.url), i.type || "get", i.response);
|
||||
}
|
||||
}
|
223
src/views/common/screen-vue3/mock/mock-index.ts
Normal file
@ -0,0 +1,223 @@
|
||||
import Mock from "mockjs";
|
||||
//处理路径传参
|
||||
import { parameteUrl } from "/@/views/common/screen-vue3/utils/query-param"
|
||||
|
||||
function ArrSet(Arr: any[], id: string): any[] {
|
||||
let obj: any = {}
|
||||
const arrays = Arr.reduce((setArr, item) => {
|
||||
obj[item[id]] ? '' : (obj[item[id]] = true && setArr.push(item))
|
||||
return setArr
|
||||
}, [])
|
||||
return arrays
|
||||
}
|
||||
/**
|
||||
* @description: min ≤ r ≤ max 随机数
|
||||
* @param {*} Min
|
||||
* @param {*} Max
|
||||
* @return {*}
|
||||
*/
|
||||
function RandomNumBoth(Min: any, Max: any) {
|
||||
var Range = Max - Min;
|
||||
var Rand = Math.random();
|
||||
var num = Min + Math.round(Rand * Range); //四舍五入
|
||||
return num;
|
||||
}
|
||||
//左中
|
||||
export default [
|
||||
{
|
||||
url: "/bigscreen/countUserNum",
|
||||
type: "get",
|
||||
response: () => {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
offlineNum: '@integer(50, 100)',
|
||||
alarmNum: '@integer(20, 100)',
|
||||
lockNum: '@integer(10, 50)',
|
||||
totalNum: 368
|
||||
}
|
||||
})
|
||||
a.data.onlineNum = a.data.totalNum - a.data.offlineNum - a.data.lockNum - a.data.alarmNum
|
||||
return a
|
||||
},
|
||||
},
|
||||
{
|
||||
url: "/bigscreen/countDeviceNum",
|
||||
type: "get",
|
||||
response: () => {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
alarmNum: '@integer(100, 1000)',
|
||||
offlineNum: '@integer(0, 50)',
|
||||
totalNum: 698
|
||||
}
|
||||
})
|
||||
a.data.onlineNum = a.data.totalNum - a.data.offlineNum
|
||||
return a
|
||||
}
|
||||
},
|
||||
//左下
|
||||
{
|
||||
url: "/bigscreen/leftBottom",
|
||||
type: "get",
|
||||
response: () => {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
"list|20": [
|
||||
{
|
||||
provinceName: "@province()",
|
||||
cityName: '@city()',
|
||||
countyName: "@county()",
|
||||
createTime: "@datetime('yyyy-MM-dd HH:mm:ss')",
|
||||
deviceId: "6c512d754bbcd6d7cd86abce0e0cac58",
|
||||
"gatewayno|+1": 10000,
|
||||
"onlineState|1": [0, 1],
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
return a
|
||||
}
|
||||
},
|
||||
//右上
|
||||
{
|
||||
url: "/bigscreen/alarmNum",
|
||||
type: "get",
|
||||
response: () => {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
dateList: ['2021-11', '2021-12', '2022-01', '2022-02', '2022-03', "2022-04"],
|
||||
"numList|6": [
|
||||
'@integer(0, 1000)'
|
||||
],
|
||||
"numList2|6": [
|
||||
'@integer(0, 1000)'
|
||||
]
|
||||
}
|
||||
})
|
||||
return a
|
||||
}
|
||||
},
|
||||
//右中
|
||||
{
|
||||
url: "/bigscreen/ranking",
|
||||
type: "get",
|
||||
response: () => {
|
||||
let num = Mock.mock({ "list|80": [{ value: "@integer(50,1000)", name: "@city()" }] }).list
|
||||
// console.log("ranking",num);
|
||||
let newNum: any = [], numObj: any = {}
|
||||
num.map((item: any) => {
|
||||
if (!numObj[item.name] && newNum.length < 8) {
|
||||
numObj[item.name] = true
|
||||
newNum.push(item)
|
||||
}
|
||||
})
|
||||
let arr = newNum.sort((a: any, b: any) => {
|
||||
return b.value - a.value
|
||||
})
|
||||
let a = {
|
||||
success: true,
|
||||
data: arr
|
||||
}
|
||||
return a
|
||||
}
|
||||
},
|
||||
//右下
|
||||
{
|
||||
url: "/bigscreen/rightBottom",
|
||||
type: "get",
|
||||
response: () => {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
"list|40": [{
|
||||
alertdetail: "@csentence(5,10)",
|
||||
"alertname|1": ["水浸告警", "各种报警"],
|
||||
alertvalue: "@float(60, 200)",
|
||||
createtime: "2022-04-19 08:38:33",
|
||||
deviceid: null,
|
||||
"gatewayno|+1": 10000,
|
||||
phase: "A1",
|
||||
sbInfo: "@csentence(10,18)",
|
||||
"terminalno|+1": 100,
|
||||
provinceName: "@province()",
|
||||
cityName: '@city()',
|
||||
countyName: "@county()",
|
||||
}],
|
||||
|
||||
}
|
||||
})
|
||||
return a
|
||||
}
|
||||
},
|
||||
//安装计划
|
||||
{
|
||||
url: "/bigscreen/installationPlan",
|
||||
type: "get",
|
||||
response: () => {
|
||||
|
||||
let num = RandomNumBoth(26, 32);
|
||||
const a = Mock.mock({
|
||||
["category|" + num]: ["@city()"],
|
||||
["barData|" + num]: ["@integer(10, 100)"],
|
||||
})
|
||||
let lineData = [], rateData = [];
|
||||
for (let index = 0; index < num; index++) {
|
||||
let lineNum = Mock.mock('@integer(0, 100)') + a.barData[index]
|
||||
lineData.push(lineNum)
|
||||
let rate = a.barData[index] / lineNum;
|
||||
rateData.push((rate * 100).toFixed(0))
|
||||
}
|
||||
a.lineData = lineData
|
||||
a.rateData = rateData
|
||||
return {
|
||||
success: true,
|
||||
data: a
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
url: "/bigscreen/centerMap",
|
||||
type: "get",
|
||||
response: (options: any) => {
|
||||
let params = parameteUrl(options.url)
|
||||
//不是中国的时候
|
||||
if (params.regionCode && !["china"].includes(params.regionCode)) {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
"dataList|100": [
|
||||
{
|
||||
name: "@city()",
|
||||
value: '@integer(1, 1000)'
|
||||
}
|
||||
],
|
||||
regionCode: params.regionCode,//-代表中国
|
||||
}
|
||||
})
|
||||
return a
|
||||
} else {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
"dataList|12": [
|
||||
{
|
||||
name: "@province()",
|
||||
value: '@integer(1, 1100)'
|
||||
}
|
||||
],
|
||||
regionCode: 'china',
|
||||
}
|
||||
})
|
||||
// 去重
|
||||
a.data.dataList = ArrSet(a.data.dataList, "name")
|
||||
return a
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
167
src/views/common/screen-vue3/mock/mock-local.ts
Normal file
@ -0,0 +1,167 @@
|
||||
import Mock from "mockjs";
|
||||
import { parameteUrl } from "/@/views/common/screen-vue3/utils/query-param";
|
||||
|
||||
// ------------------------------
|
||||
// 工具函数(保持原样)
|
||||
// ------------------------------
|
||||
function ArrSet(Arr: any[], id: string): any[] {
|
||||
let obj: any = {};
|
||||
const arrays = Arr.reduce((setArr, item) => {
|
||||
obj[item[id]] ? '' : (obj[item[id]] = true && setArr.push(item));
|
||||
return setArr;
|
||||
}, []);
|
||||
return arrays;
|
||||
}
|
||||
|
||||
function RandomNumBoth(Min: number, Max: number): number {
|
||||
const Range = Max - Min;
|
||||
const Rand = Math.random();
|
||||
return Min + Math.round(Rand * Range);
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
// 将每个接口的 response 改造成独立函数
|
||||
// ------------------------------
|
||||
|
||||
/** 左中:用户数量统计 */
|
||||
export function getCountUserNum() {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
offlineNum: '@integer(50, 100)',
|
||||
alarmNum: '@integer(20, 100)',
|
||||
lockNum: '@integer(10, 50)',
|
||||
totalNum: 368
|
||||
}
|
||||
});
|
||||
a.data.onlineNum = a.data.totalNum - a.data.offlineNum - a.data.lockNum - a.data.alarmNum;
|
||||
return a;
|
||||
}
|
||||
|
||||
/** 左中:设备数量统计 */
|
||||
export function getCountDeviceNum() {
|
||||
const a = Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
alarmNum: '@integer(100, 1000)',
|
||||
offlineNum: '@integer(0, 50)',
|
||||
totalNum: 698
|
||||
}
|
||||
});
|
||||
a.data.onlineNum = a.data.totalNum - a.data.offlineNum;
|
||||
return a;
|
||||
}
|
||||
|
||||
/** 左下:设备列表 */
|
||||
export function getLeftBottomList() {
|
||||
return Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
"list|20": [
|
||||
{
|
||||
provinceName: "@province()",
|
||||
cityName: '@city()',
|
||||
countyName: "@county()",
|
||||
createTime: "@datetime('yyyy-MM-dd HH:mm:ss')",
|
||||
deviceId: "6c512d754bbcd6d7cd86abce0e0cac58",
|
||||
"gatewayno|+1": 10000,
|
||||
"onlineState|1": [0, 1],
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 右上:告警数量趋势 */
|
||||
export function getAlarmTrend() {
|
||||
return Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
dateList: ['2021-11', '2021-12', '2022-01', '2022-02', '2022-03', "2022-04"],
|
||||
"numList|6": ['@integer(0, 1000)'],
|
||||
"numList2|6": ['@integer(0, 1000)']
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 右中:城市排名 */
|
||||
export function getCityRanking() {
|
||||
let num = Mock.mock({ "list|80": [{ value: "@integer(50,1000)", name: "@city()" }] }).list;
|
||||
let newNum: any = [], numObj: any = {};
|
||||
num.map((item: any) => {
|
||||
if (!numObj[item.name] && newNum.length < 8) {
|
||||
numObj[item.name] = true;
|
||||
newNum.push(item);
|
||||
}
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
data: newNum.sort((a: any, b: any) => b.value - a.value)
|
||||
};
|
||||
}
|
||||
|
||||
/** 右下:告警详情列表 */
|
||||
export function getRightBottomAlerts() {
|
||||
return Mock.mock({
|
||||
success: true,
|
||||
data: {
|
||||
"list|40": [{
|
||||
alertdetail: "@csentence(5,10)",
|
||||
"alertname|1": ["水浸告警", "各种报警"],
|
||||
alertvalue: "@float(60, 200)",
|
||||
createtime: "2022-04-19 08:38:33",
|
||||
deviceid: null,
|
||||
"gatewayno|+1": 10000,
|
||||
phase: "A1",
|
||||
sbInfo: "@csentence(10,18)",
|
||||
"terminalno|+1": 100,
|
||||
provinceName: "@province()",
|
||||
cityName: '@city()',
|
||||
countyName: "@county()",
|
||||
}]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 安装计划数据 */
|
||||
export function getInstallationPlan() {
|
||||
const num = RandomNumBoth(26, 32);
|
||||
const a = Mock.mock({
|
||||
["category|" + num]: ["@city()"],
|
||||
["barData|" + num]: ["@integer(10, 100)"],
|
||||
});
|
||||
const lineData = [], rateData = [];
|
||||
for (let index = 0; index < num; index++) {
|
||||
const lineNum = Mock.mock('@integer(0, 100)') + a.barData[index];
|
||||
lineData.push(lineNum);
|
||||
rateData.push(Number((a.barData[index] / lineNum * 100).toFixed(0)));
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: { ...a, lineData, rateData }
|
||||
};
|
||||
}
|
||||
|
||||
/** 地图数据(添加参数 regionCode) */
|
||||
export function getCenterMap(params: { regionCode?: string } = {}) {
|
||||
const regionCode = params.regionCode || "china";
|
||||
|
||||
if (regionCode && !["china"].includes(regionCode)) {
|
||||
const dataList = Mock.mock({
|
||||
"list|100": [{
|
||||
name: "@city()",
|
||||
value: '@integer(1, 1000)'
|
||||
}]
|
||||
}).list;
|
||||
return {
|
||||
success: true,
|
||||
data: { dataList, regionCode }
|
||||
};
|
||||
} else {
|
||||
const dataList = ArrSet(
|
||||
Mock.mock({ "list|12": [{ name: "@province()", value: '@integer(1, 1100)' }] }).list,
|
||||
"name"
|
||||
);
|
||||
return { success: true, data: { dataList, regionCode: 'china' } };
|
||||
}
|
||||
}
|
36
src/views/common/screen-vue3/plugins/echarts.ts
Normal file
@ -0,0 +1,36 @@
|
||||
// vue-echarts
|
||||
import ECharts from 'vue-echarts'
|
||||
import { use } from "echarts/core"
|
||||
import {
|
||||
CanvasRenderer
|
||||
} from 'echarts/renderers'
|
||||
import {
|
||||
BarChart,PieChart,MapChart,EffectScatterChart,LineChart
|
||||
} from 'echarts/charts'
|
||||
import {
|
||||
GridComponent,
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
LegendComponent,
|
||||
DatasetComponent,
|
||||
VisualMapComponent,
|
||||
GeoComponent,
|
||||
MarkPointComponent
|
||||
} from 'echarts/components'
|
||||
|
||||
use([
|
||||
CanvasRenderer,
|
||||
BarChart,PieChart,MapChart,EffectScatterChart,LineChart,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
TooltipComponent,
|
||||
TitleComponent,
|
||||
DatasetComponent,
|
||||
VisualMapComponent,
|
||||
GeoComponent,
|
||||
MarkPointComponent
|
||||
])
|
||||
|
||||
export const registerEcharts= (app:any)=>{
|
||||
app.component('v-chart', ECharts)
|
||||
}
|
1
src/views/common/screen-vue3/stores/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./setting/setting"
|
51
src/views/common/screen-vue3/stores/setting/setting.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
// import { storeToRefs } from 'pinia';
|
||||
export const useSettingStore = defineStore('setting', () => {
|
||||
const settingShow = ref(false);//设置弹窗显隐
|
||||
const isScale = ref(false);//是否进行全局适配
|
||||
const indexConfig = ref({
|
||||
leftBottomSwiper: true,//左轮播
|
||||
rightBottomSwiper: true,//右下轮播
|
||||
})
|
||||
const defaultOption = ref({
|
||||
step: 4, // 数值越大速度滚动越快
|
||||
hover: true, // 是否开启鼠标悬停stop
|
||||
wheel: false,//在开启鼠标悬停的情况下是否开启滚轮滚动,默认不开启
|
||||
openWatch: true, // 开启数据实时监控刷新dom
|
||||
direction: 1, // 0向下 1向上 2向左 3向右
|
||||
limitScrollNum: 4, // 开始无缝滚动的数据量 this.dataList.length
|
||||
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
|
||||
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
|
||||
singleWaitTime: 3000 // 单步运动停止的时间(默认值1000ms)
|
||||
})
|
||||
const setSettingShow = (flag: boolean) => {
|
||||
settingShow.value = flag
|
||||
}
|
||||
const setIsScale = (flag: boolean) => {
|
||||
isScale.value = flag
|
||||
setSettingData()
|
||||
}
|
||||
const setIndexConfig = (Config: any) => {
|
||||
indexConfig.value = Config
|
||||
localStorage.setItem('loftv-indexConfig', JSON.stringify(indexConfig.value))
|
||||
}
|
||||
const initSetting = () => {
|
||||
let settingData: any = localStorage.getItem('loftv-settingData')
|
||||
if (settingData) {
|
||||
settingData = JSON.parse(settingData)
|
||||
setIsScale(settingData.isScale)
|
||||
}
|
||||
let settingIndexConfig: any = localStorage.getItem('loftv-indexConfig')
|
||||
if (settingIndexConfig) {
|
||||
settingIndexConfig = JSON.parse(settingIndexConfig)
|
||||
setIndexConfig(settingIndexConfig)
|
||||
}
|
||||
}
|
||||
const setSettingData = () => {
|
||||
localStorage.setItem('loftv-settingData', JSON.stringify({
|
||||
isScale: isScale.value
|
||||
}))
|
||||
}
|
||||
return { settingShow, setSettingShow, isScale, setIsScale, initSetting, setSettingData, defaultOption, indexConfig, setIndexConfig }
|
||||
})
|
2
src/views/common/screen-vue3/utils/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./storage";
|
||||
|
36
src/views/common/screen-vue3/utils/query-param.ts
Normal file
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @description: 获取路径参数
|
||||
* @param {*} url
|
||||
* @return {*}
|
||||
*/
|
||||
export function parameteUrl(url: string) {
|
||||
var json: any = {}
|
||||
if (/\?/.test(url)) {
|
||||
var urlString = url.substring(url.indexOf("?") + 1);
|
||||
var urlArray = urlString.split("&");
|
||||
for (var i = 0; i < urlArray.length; i++) {
|
||||
var urlItem = urlArray[i];
|
||||
var item = urlItem.split("=");
|
||||
// console.log(item);
|
||||
json[item[0]] = item[1];
|
||||
}
|
||||
return json;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// get请求从config.url获取参数,post从config.body中获取参数
|
||||
export function paramObj(url:string) {
|
||||
const search = url.split('?')[1]
|
||||
if (!search) {
|
||||
return {}
|
||||
}
|
||||
return JSON.parse(
|
||||
'{"' +
|
||||
decodeURIComponent(search)
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/&/g, '","')
|
||||
.replace(/=/g, '":"') +
|
||||
'"}'
|
||||
)
|
||||
}
|
71
src/views/common/screen-vue3/utils/storage.ts
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
/**
|
||||
* * 存储本地会话数据
|
||||
* @param k 键名
|
||||
* @param v 键值(无需stringiiy)
|
||||
* @returns RemovableRef
|
||||
*/
|
||||
export const setLocalStorage = <T>(k: string, v: T) => {
|
||||
try {
|
||||
window.localStorage.setItem(k, JSON.stringify(v))
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取本地会话数据
|
||||
* @param k 键名
|
||||
* @returns any
|
||||
*/
|
||||
export const getLocalStorage = (k: string) => {
|
||||
const item = window.localStorage.getItem(k)
|
||||
try {
|
||||
return item ? JSON.parse(item) : item
|
||||
} catch (err) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 清除本地会话数据
|
||||
* @param name
|
||||
*/
|
||||
export const clearLocalStorage = (name: string) => {
|
||||
window.localStorage.removeItem(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* * 存储临时会话数据
|
||||
* @param k 键名
|
||||
* @param v 键值
|
||||
* @returns RemovableRef
|
||||
*/
|
||||
export const setSessionStorage = <T>(k: string, v: T) => {
|
||||
try {
|
||||
window.sessionStorage.setItem(k, JSON.stringify(v))
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 获取临时会话数据
|
||||
* @returns any
|
||||
*/
|
||||
export const getSessionStorage: (k: string) => any = (k: string) => {
|
||||
const item = window.sessionStorage.getItem(k)
|
||||
try {
|
||||
return item ? JSON.parse(item) : item
|
||||
} catch (err) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 清除本地会话数据
|
||||
* @param name
|
||||
*/
|
||||
export const clearSessioStorage = (name: string) => {
|
||||
window.sessionStorage.removeItem(name)
|
||||
}
|
48
src/views/common/screen-vue3/views/HomeView.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { RouterView } from "vue-router";
|
||||
import ScaleScreen from "/@/views/common/screen-vue3/components/scale-screen";
|
||||
import Headers from "./header.vue";
|
||||
import Setting from "./setting.vue";
|
||||
import { useSettingStore } from "/@/views/common/screen-vue3/stores/index";
|
||||
import { storeToRefs } from "pinia";
|
||||
import MessageContent from "/@/views/common/screen-vue3/components/Plugins/MessageContent";
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const { isScale } = storeToRefs(settingStore);
|
||||
const wrapperStyle = {};
|
||||
import ScreenIndex from "/src/views/common/screen-vue3/views/index/index.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<scale-screen
|
||||
width="1920"
|
||||
height="1080"
|
||||
:delay="500"
|
||||
:fullScreen="false"
|
||||
:boxStyle="{
|
||||
background: '#03050C',
|
||||
overflow: isScale ? 'hidden' : 'auto',
|
||||
}"
|
||||
:wrapperStyle="wrapperStyle"
|
||||
:autoScale="isScale"
|
||||
>
|
||||
<div class="content_wrap">
|
||||
<Headers />
|
||||
<ScreenIndex />
|
||||
<MessageContent />
|
||||
</div>
|
||||
</scale-screen>
|
||||
<Setting />
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.content_wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 16px 16px 16px 16px;
|
||||
box-sizing: border-box;
|
||||
background-image: url("/src/views/common/screen-vue3/assets/img/pageBg.png");
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
}
|
||||
</style>
|
127
src/views/common/screen-vue3/views/header.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive } from "vue";
|
||||
import dayjs from 'dayjs';
|
||||
import type {DateDataType} from "./index.d"
|
||||
import {useSettingStore} from "/@/views/common/screen-vue3/stores/index"
|
||||
|
||||
const dateData = reactive<DateDataType>({
|
||||
dateDay: "",
|
||||
dateYear: "",
|
||||
dateWeek: "",
|
||||
timing:null
|
||||
});
|
||||
|
||||
const { setSettingShow} =useSettingStore()
|
||||
const weekday= ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
|
||||
const timeFn = () => {
|
||||
dateData.timing = setInterval(() => {
|
||||
dateData.dateDay = dayjs().format("YYYY-MM-DD hh : mm : ss");
|
||||
dateData.dateWeek = weekday[dayjs().day()];
|
||||
}, 1000);
|
||||
};
|
||||
timeFn()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="d-flex jc-center title_wrap">
|
||||
<div class="zuojuxing"></div>
|
||||
<div class="youjuxing"></div>
|
||||
<div class="guang"></div>
|
||||
<div class="d-flex jc-center">
|
||||
<div class="title">
|
||||
<span class="title-text">互联网设备可视化平台</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timers">
|
||||
{{ dateData.dateYear }} {{ dateData.dateWeek }} {{ dateData.dateDay }}
|
||||
|
||||
<div class="setting_icon" @click="setSettingShow(true)">
|
||||
<img src="/src/views/common/screen-vue3/assets/img/headers/setting.png" alt="设置">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.title_wrap {
|
||||
height: 60px;
|
||||
background-image: url("src/views/common/screen-vue3/assets/img/top.png");
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
position: relative;
|
||||
margin-bottom: 4px;
|
||||
|
||||
.guang {
|
||||
position: absolute;
|
||||
bottom: -26px;
|
||||
background-image: url("src/views/common/screen-vue3/assets/img/guang.png");
|
||||
background-position: 80px center;
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.zuojuxing,
|
||||
.youjuxing {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
width: 140px;
|
||||
height: 6px;
|
||||
background-image: url("src/views/common/screen-vue3/assets/img/headers/juxing1.png");
|
||||
}
|
||||
|
||||
.zuojuxing {
|
||||
left: 11%;
|
||||
}
|
||||
|
||||
.youjuxing {
|
||||
right: 11%;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.timers {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 30px;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.setting_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
margin-left: 12px;
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.title {
|
||||
position: relative;
|
||||
// width: 500px;
|
||||
text-align: center;
|
||||
background-size: cover;
|
||||
color: transparent;
|
||||
height: 60px;
|
||||
line-height: 46px;
|
||||
|
||||
.title-text {
|
||||
font-size: 38px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 6px;
|
||||
width: 100%;
|
||||
background: linear-gradient(
|
||||
92deg,
|
||||
#0072ff 0%,
|
||||
#00eaff 48.8525390625%,
|
||||
#01aaff 100%
|
||||
);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
</style>
|
27
src/views/common/screen-vue3/views/index.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
export interface DateDataType {
|
||||
dateDay: string,
|
||||
dateYear: string,
|
||||
dateWeek: string,
|
||||
timing: NodeJS.Timer
|
||||
}
|
||||
|
||||
interface CountUpOptions {
|
||||
startVal?: number; // number to start at (0)
|
||||
decimalPlaces?: number; // number of decimal places (0)
|
||||
duration?: number; // animation duration in seconds (2)
|
||||
useGrouping?: boolean; // example: 1,000 vs 1000 (true)
|
||||
useEasing?: boolean; // ease animation (true)
|
||||
smartEasingThreshold?: number; // smooth easing for large numbers above this if useEasing (999)
|
||||
smartEasingAmount?: number; // amount to be eased for numbers above threshold (333)
|
||||
separator?: string; // grouping separator (',')
|
||||
decimal?: string; // decimal ('.')
|
||||
// easingFn: easing function for animation (easeOutExpo)
|
||||
easingFn?: (t: number, b: number, c: number, d: number) => number;
|
||||
formattingFn?: (n: number) => string; // this function formats result
|
||||
prefix?: string; // text prepended to result
|
||||
suffix?: string; // text appended to result
|
||||
numerals?: string[]; // numeral glyph substitution
|
||||
enableScrollSpy?: boolean; // start animation when target is in view
|
||||
scrollSpyDelay?: number; // delay (ms) after target comes into view
|
||||
scrollSpyOnce?: boolean; // run only once
|
||||
}
|
158
src/views/common/screen-vue3/views/index/center-bottom.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, nextTick } from "vue";
|
||||
import { installationPlan } from "/@/views/common/screen-vue3/api";
|
||||
import { graphic } from "echarts/core";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const option = ref({});
|
||||
const getData = () => {
|
||||
installationPlan()
|
||||
.then((res) => {
|
||||
console.log("中下--安装计划", res);
|
||||
if (res.success) {
|
||||
setOption(res.data);
|
||||
} else {
|
||||
ElMessage({
|
||||
message: res.msg,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
};
|
||||
const setOption = async (newData: any) => {
|
||||
option.value = {
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
backgroundColor: "rgba(0,0,0,.6)",
|
||||
borderColor: "rgba(147, 235, 248, .8)",
|
||||
textStyle: {
|
||||
color: "#FFF",
|
||||
},
|
||||
formatter: function (params: any) {
|
||||
// 添加单位
|
||||
var result = params[0].name + "<br>";
|
||||
params.forEach(function (item: any) {
|
||||
if (item.value) {
|
||||
if (item.seriesName == "安装率") {
|
||||
result += item.marker + " " + item.seriesName + " : " + item.value + "%</br>";
|
||||
} else {
|
||||
result += item.marker + " " + item.seriesName + " : " + item.value + "个</br>";
|
||||
}
|
||||
} else {
|
||||
result += item.marker + " " + item.seriesName + " : - </br>";
|
||||
}
|
||||
});
|
||||
return result;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ["已安装", "计划安装", "安装率"],
|
||||
textStyle: {
|
||||
color: "#B4B4B4",
|
||||
},
|
||||
top: "0",
|
||||
},
|
||||
grid: {
|
||||
left: "50px",
|
||||
right: "40px",
|
||||
bottom: "30px",
|
||||
top: "20px",
|
||||
},
|
||||
xAxis: {
|
||||
data: newData.category,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#B4B4B4",
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
splitLine: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#B4B4B4",
|
||||
},
|
||||
},
|
||||
|
||||
axisLabel: {
|
||||
formatter: "{value}",
|
||||
},
|
||||
},
|
||||
{
|
||||
splitLine: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#B4B4B4",
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: "{value}% ",
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "已安装",
|
||||
type: "bar",
|
||||
barWidth: 10,
|
||||
itemStyle: {
|
||||
borderRadius: 5,
|
||||
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "#956FD4" },
|
||||
{ offset: 1, color: "#3EACE5" },
|
||||
]),
|
||||
},
|
||||
data: newData.barData,
|
||||
},
|
||||
{
|
||||
name: "计划安装",
|
||||
type: "bar",
|
||||
barGap: "-100%",
|
||||
barWidth: 10,
|
||||
itemStyle: {
|
||||
borderRadius: 5,
|
||||
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(156,107,211,0.8)" },
|
||||
{ offset: 0.2, color: "rgba(156,107,211,0.5)" },
|
||||
{ offset: 1, color: "rgba(156,107,211,0.2)" },
|
||||
]),
|
||||
},
|
||||
z: -12,
|
||||
data: newData.lineData,
|
||||
},
|
||||
{
|
||||
name: "安装率",
|
||||
type: "line",
|
||||
smooth: true,
|
||||
showAllSymbol: true,
|
||||
symbol: "emptyCircle",
|
||||
symbolSize: 8,
|
||||
yAxisIndex: 1,
|
||||
itemStyle: {
|
||||
color: "#F02FC2",
|
||||
},
|
||||
data: newData.rateData,
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
onMounted(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-chart class="chart" :option="option" v-if="JSON.stringify(option) != '{}'" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
</style>
|
177
src/views/common/screen-vue3/views/index/center-map.vue
Normal file
@ -0,0 +1,177 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, nextTick } from "vue";
|
||||
import { centerMap, GETNOBASE } from "/@/views/common/screen-vue3/api";
|
||||
import { registerMap, getMap } from "echarts/core";
|
||||
import { optionHandle, regionCodes } from "./center.map";
|
||||
import BorderBox13 from "/@/views/common/screen-vue3/components/datav/border-box-13";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
import type { MapdataType } from "./center.map";
|
||||
|
||||
const option = ref({});
|
||||
const code = ref("china"); //china 代表中国 其他地市是行政编码
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
// 结束数值
|
||||
title: number | string;
|
||||
}>(),
|
||||
{
|
||||
title: "地图",
|
||||
}
|
||||
);
|
||||
|
||||
const dataSetHandle = async (regionCode: string, list: object[]) => {
|
||||
const geojson: any = await getGeojson(regionCode);
|
||||
let cityCenter: any = {};
|
||||
let mapData: MapdataType[] = [];
|
||||
//获取当前地图每块行政区中心点
|
||||
geojson.features.forEach((element: any) => {
|
||||
cityCenter[element.properties.name] = element.properties.centroid || element.properties.center;
|
||||
});
|
||||
//当前中心点如果有此条数据中心点则赋值x,y当然这个x,y也可以后端返回进行大点,前端省去多行代码
|
||||
list.forEach((item: any) => {
|
||||
if (cityCenter[item.name]) {
|
||||
mapData.push({
|
||||
name: item.name,
|
||||
value: cityCenter[item.name].concat(item.value),
|
||||
});
|
||||
}
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
option.value = optionHandle(regionCode, list, mapData);
|
||||
};
|
||||
|
||||
const getData = async (regionCode: string) => {
|
||||
centerMap({ regionCode: regionCode })
|
||||
.then((res) => {
|
||||
console.log("中上--设备分布", res);
|
||||
if (res.success) {
|
||||
dataSetHandle(res.data.regionCode, res.data.dataList);
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
};
|
||||
const getGeojson = (regionCode: string) => {
|
||||
return new Promise<boolean>(async (resolve) => {
|
||||
let mapjson = getMap(regionCode);
|
||||
if (mapjson) {
|
||||
mapjson = mapjson.geoJSON;
|
||||
resolve(mapjson);
|
||||
} else {
|
||||
mapjson = await GETNOBASE(`./map-geojson/${regionCode}.json`).then((data) => data);
|
||||
code.value = regionCode;
|
||||
registerMap(regionCode, {
|
||||
geoJSON: mapjson as any,
|
||||
specialAreas: {},
|
||||
});
|
||||
resolve(mapjson);
|
||||
}
|
||||
});
|
||||
};
|
||||
getData(code.value);
|
||||
|
||||
const mapClick = (params: any) => {
|
||||
// console.log(params);
|
||||
let xzqData = regionCodes[params.name];
|
||||
if (xzqData) {
|
||||
getData(xzqData.adcode);
|
||||
} else {
|
||||
ElMessage.warning('暂无下级地市');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="centermap">
|
||||
<div class="maptitle">
|
||||
<div class="zuo"></div>
|
||||
<span class="titletext">{{ title }}</span>
|
||||
<div class="you"></div>
|
||||
</div>
|
||||
<div class="mapwrap">
|
||||
<BorderBox13>
|
||||
<div class="quanguo" @click="getData('china')" v-if="code !== 'china'">中国</div>
|
||||
<v-chart
|
||||
class="chart"
|
||||
:option="option"
|
||||
ref="centerMapRef"
|
||||
@click="mapClick"
|
||||
v-if="JSON.stringify(option) != '{}'"
|
||||
/>
|
||||
</BorderBox13>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.centermap {
|
||||
margin-bottom: 30px;
|
||||
|
||||
.maptitle {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 10px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.titletext {
|
||||
font-size: 28px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 6px;
|
||||
background: linear-gradient(92deg, #0072ff 0%, #00eaff 48.8525390625%, #01aaff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.zuo,
|
||||
.you {
|
||||
background-size: 100% 100%;
|
||||
width: 29px;
|
||||
height: 20px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.zuo {
|
||||
background: url("/src/views/common/screen-vue3/assets/img/xiezuo.png") no-repeat;
|
||||
}
|
||||
|
||||
.you {
|
||||
background: url("/src/views/common/screen-vue3/assets/img/xieyou.png") no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
.mapwrap {
|
||||
height: 580px;
|
||||
width: 100%;
|
||||
// padding: 0 0 10px 0;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
.quanguo {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: -46px;
|
||||
width: 80px;
|
||||
height: 28px;
|
||||
border: 1px solid #00eded;
|
||||
border-radius: 10px;
|
||||
color: #00f7f6;
|
||||
text-align: center;
|
||||
line-height: 26px;
|
||||
letter-spacing: 6px;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 4px rgba(0, 237, 237, 0.5), 0 0 6px rgba(0, 237, 237, 0.4);
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
399
src/views/common/screen-vue3/views/index/center.map.ts
Normal file
@ -0,0 +1,399 @@
|
||||
|
||||
|
||||
//mapData数据结构
|
||||
export interface MapdataType {
|
||||
name: string;
|
||||
value: [number, number, number]; //x,y,value 第一个x 第二个y 第三个value
|
||||
}
|
||||
export const optionHandle = (regionCode: string,
|
||||
list: object[],
|
||||
mapData: MapdataType[]) => {
|
||||
let top = 45;
|
||||
let zoom = ["china"].includes(regionCode) ? 1.05 : 1;
|
||||
return {
|
||||
backgroundColor: "rgba(0,0,0,0)",
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
visualMap: {
|
||||
seriesIndex:0,
|
||||
left: 20,
|
||||
bottom: 20,
|
||||
pieces: [
|
||||
{ gte: 1000, label: "1000个以上" }, // 不指定 max,表示 max 为无限大(Infinity)。
|
||||
{ gte: 600, lte: 999, label: "600-999个" },
|
||||
{ gte: 200, lte: 599, label: "200-599个" },
|
||||
{ gte: 50, lte: 199, label: "49-199个" },
|
||||
{ gte: 10, lte: 49, label: "10-49个" },
|
||||
{ lte: 9, label: "1-9个" }, // 不指定 min,表示 min 为无限大(-Infinity)。
|
||||
],
|
||||
inRange: {
|
||||
// 渐变颜色,从小到大
|
||||
// FFFFFF,EDF7FD,DBF0FA,C9E8F8,B7E1F6,A5D9F3,93D2F1,81CAEF,6FC2EC,5DBBEA,4AB3E8,38ACE5,26A4E3,1C9AD9,1A8DC7,
|
||||
// 1781B5,
|
||||
// 1573A2,136790,105A7E,0E4D6C,0C405A,093348,072636,051A24,020D12
|
||||
color: [
|
||||
// "#EDF7FD",
|
||||
"rgba(237,247,253,.8)",
|
||||
// "#B7E1F6",
|
||||
"rgba(183,225,246,.9)",
|
||||
// "#81CAEF",
|
||||
"rgba(129,202,239,.9)",
|
||||
// "#38ACE5",
|
||||
"rgba(56,172,229,.9)",
|
||||
// "#1781B5",
|
||||
"rgba(23,129,181,.9)",
|
||||
// "#105A7E",
|
||||
"rgba(16,90,126,0.9)"
|
||||
],
|
||||
},
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
geo: {
|
||||
map: regionCode,
|
||||
roam: false,
|
||||
selectedMode: false, //是否允许选中多个区域
|
||||
zoom: zoom,
|
||||
top: top,
|
||||
// aspectScale: 0.78,
|
||||
show: false,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "MAP",
|
||||
type: "map",
|
||||
map: regionCode,
|
||||
// aspectScale: 0.78,
|
||||
data: list,
|
||||
// data: [1,100],
|
||||
selectedMode: false, //是否允许选中多个区域
|
||||
zoom: zoom,
|
||||
geoIndex: 1,
|
||||
top: top,
|
||||
tooltip: {
|
||||
show: true,
|
||||
formatter: function (params: any) {
|
||||
if (params.data) {
|
||||
return params.name + ":" + params.data["value"];
|
||||
} else {
|
||||
return params.name;
|
||||
}
|
||||
},
|
||||
backgroundColor: "rgba(0,0,0,.6)",
|
||||
borderColor: "rgba(147, 235, 248, .8)",
|
||||
textStyle: {
|
||||
color: "#FFF",
|
||||
},
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
color: "#000",
|
||||
// position: [-10, 0],
|
||||
formatter: function (val: any) {
|
||||
// console.log(val)
|
||||
if (val.data !== undefined) {
|
||||
return val.name.slice(0, 2);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
rich: {},
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
// areaColor: "rgba(56,155,183,.7)",
|
||||
areaColor:{
|
||||
type: "radial",
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
r: 0.8,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(56,155,183, .8)", // 100% 处的颜色
|
||||
},
|
||||
],
|
||||
globalCoord: false, // 缺为 false
|
||||
},
|
||||
borderWidth: 1,
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
borderColor: "rgba(147, 235, 248, .8)",
|
||||
borderWidth: 1,
|
||||
areaColor: {
|
||||
type: "radial",
|
||||
x: 0.5,
|
||||
y: 0.5,
|
||||
r: 0.8,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(147, 235, 248, .2)", // 100% 处的颜色
|
||||
},
|
||||
],
|
||||
globalCoord: false, // 缺为 false
|
||||
},
|
||||
shadowColor: "rgba(128, 217, 248, .3)",
|
||||
shadowOffsetX: -2,
|
||||
shadowOffsetY: 2,
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
data: mapData,
|
||||
type: "effectScatter",
|
||||
coordinateSystem: "geo",
|
||||
symbolSize: function (val: any) {
|
||||
return 4;
|
||||
// return val[2] / 50;
|
||||
},
|
||||
legendHoverLink: true,
|
||||
showEffectOn: "render",
|
||||
rippleEffect: {
|
||||
// period: 4,
|
||||
scale: 6,
|
||||
color: "rgba(255,255,255, 1)",
|
||||
brushType: "fill",
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
formatter: function (params: any) {
|
||||
if (params.data) {
|
||||
return params.name + ":" + params.data["value"][2];
|
||||
} else {
|
||||
return params.name;
|
||||
}
|
||||
},
|
||||
backgroundColor: "rgba(0,0,0,.6)",
|
||||
borderColor: "rgba(147, 235, 248, .8)",
|
||||
textStyle: {
|
||||
color: "#FFF",
|
||||
},
|
||||
},
|
||||
label: {
|
||||
formatter: (param: any) => {
|
||||
return param.name.slice(0, 2);
|
||||
},
|
||||
|
||||
fontSize: 11,
|
||||
offset: [0, 2],
|
||||
position: "bottom",
|
||||
textBorderColor: "#fff",
|
||||
textShadowColor: "#000",
|
||||
textShadowBlur: 10,
|
||||
textBorderWidth: 0,
|
||||
color: "#FFF",
|
||||
show: true,
|
||||
},
|
||||
// colorBy: "data",
|
||||
itemStyle: {
|
||||
color: "rgba(255,255,255,1)",
|
||||
borderColor: "rgba(2255,255,255,2)",
|
||||
borderWidth: 4,
|
||||
shadowColor: "#000",
|
||||
shadowBlur: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
//动画效果
|
||||
// animationDuration: 1000,
|
||||
// animationEasing: 'linear',
|
||||
// animationDurationUpdate: 1000
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export const regionCodes: any = {
|
||||
"中国": {
|
||||
"adcode": "100000",
|
||||
"level": "country",
|
||||
"name": "中华人民共和国"
|
||||
},
|
||||
"新疆维吾尔自治区": {
|
||||
"adcode": "650000",
|
||||
"level": "province",
|
||||
"name": "新疆维吾尔自治区"
|
||||
},
|
||||
"湖北省": {
|
||||
"adcode": "420000",
|
||||
"level": "province",
|
||||
"name": "湖北省"
|
||||
},
|
||||
"辽宁省": {
|
||||
"adcode": "210000",
|
||||
"level": "province",
|
||||
"name": "辽宁省"
|
||||
},
|
||||
"广东省": {
|
||||
"adcode": "440000",
|
||||
"level": "province",
|
||||
"name": "广东省"
|
||||
},
|
||||
"内蒙古自治区": {
|
||||
"adcode": "150000",
|
||||
"level": "province",
|
||||
"name": "内蒙古自治区"
|
||||
},
|
||||
"黑龙江省": {
|
||||
"adcode": "230000",
|
||||
"level": "province",
|
||||
"name": "黑龙江省"
|
||||
},
|
||||
"河南省": {
|
||||
"adcode": "410000",
|
||||
"level": "province",
|
||||
"name": "河南省"
|
||||
},
|
||||
"山东省": {
|
||||
"adcode": "370000",
|
||||
"level": "province",
|
||||
"name": "山东省"
|
||||
},
|
||||
"陕西省": {
|
||||
"adcode": "610000",
|
||||
"level": "province",
|
||||
"name": "陕西省"
|
||||
},
|
||||
"贵州省": {
|
||||
"adcode": "520000",
|
||||
"level": "province",
|
||||
"name": "贵州省"
|
||||
},
|
||||
"上海市": {
|
||||
"adcode": "310000",
|
||||
"level": "province",
|
||||
"name": "上海市"
|
||||
},
|
||||
"重庆市": {
|
||||
"adcode": "500000",
|
||||
"level": "province",
|
||||
"name": "重庆市"
|
||||
},
|
||||
"西藏自治区": {
|
||||
"adcode": "540000",
|
||||
"level": "province",
|
||||
"name": "西藏自治区"
|
||||
},
|
||||
"安徽省": {
|
||||
"adcode": "340000",
|
||||
"level": "province",
|
||||
"name": "安徽省"
|
||||
},
|
||||
"福建省": {
|
||||
"adcode": "350000",
|
||||
"level": "province",
|
||||
"name": "福建省"
|
||||
},
|
||||
"湖南省": {
|
||||
"adcode": "430000",
|
||||
"level": "province",
|
||||
"name": "湖南省"
|
||||
},
|
||||
"海南省": {
|
||||
"adcode": "460000",
|
||||
"level": "province",
|
||||
"name": "海南省"
|
||||
},
|
||||
"江苏省": {
|
||||
"adcode": "320000",
|
||||
"level": "province",
|
||||
"name": "江苏省"
|
||||
},
|
||||
"青海省": {
|
||||
"adcode": "630000",
|
||||
"level": "province",
|
||||
"name": "青海省"
|
||||
},
|
||||
"广西壮族自治区": {
|
||||
"adcode": "450000",
|
||||
"level": "province",
|
||||
"name": "广西壮族自治区"
|
||||
},
|
||||
"宁夏回族自治区": {
|
||||
"adcode": "640000",
|
||||
"level": "province",
|
||||
"name": "宁夏回族自治区"
|
||||
},
|
||||
"浙江省": {
|
||||
"adcode": "330000",
|
||||
"level": "province",
|
||||
"name": "浙江省"
|
||||
},
|
||||
"河北省": {
|
||||
"adcode": "130000",
|
||||
"level": "province",
|
||||
"name": "河北省"
|
||||
},
|
||||
"香港特别行政区": {
|
||||
"adcode": "810000",
|
||||
"level": "province",
|
||||
"name": "香港特别行政区"
|
||||
},
|
||||
"台湾省": {
|
||||
"adcode": "710000",
|
||||
"level": "province",
|
||||
"name": "台湾省"
|
||||
},
|
||||
"澳门特别行政区": {
|
||||
"adcode": "820000",
|
||||
"level": "province",
|
||||
"name": "澳门特别行政区"
|
||||
},
|
||||
"甘肃省": {
|
||||
"adcode": "620000",
|
||||
"level": "province",
|
||||
"name": "甘肃省"
|
||||
},
|
||||
"四川省": {
|
||||
"adcode": "510000",
|
||||
"level": "province",
|
||||
"name": "四川省"
|
||||
},
|
||||
"天津市": {
|
||||
"adcode": "120000",
|
||||
"level": "province",
|
||||
"name": "天津市"
|
||||
},
|
||||
"江西省": {
|
||||
"adcode": "360000",
|
||||
"level": "province",
|
||||
"name": "江西省"
|
||||
},
|
||||
"云南省": {
|
||||
"adcode": "530000",
|
||||
"level": "province",
|
||||
"name": "云南省"
|
||||
},
|
||||
"山西省": {
|
||||
"adcode": "140000",
|
||||
"level": "province",
|
||||
"name": "山西省"
|
||||
},
|
||||
"北京市": {
|
||||
"adcode": "110000",
|
||||
"level": "province",
|
||||
"name": "北京市"
|
||||
},
|
||||
"吉林省": {
|
||||
"adcode": "220000",
|
||||
"level": "province",
|
||||
"name": "吉林省"
|
||||
}
|
||||
}
|
93
src/views/common/screen-vue3/views/index/index.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<script setup lang="ts">
|
||||
import ItemWrap from "/@/views/common/screen-vue3/components/item-wrap";
|
||||
import LeftTop from "./left-top.vue";
|
||||
import LeftCenter from "./left-center.vue";
|
||||
import LeftBottom from "./left-bottom.vue";
|
||||
import CenterMap from "./center-map.vue";
|
||||
import CenterBottom from "./center-bottom.vue";
|
||||
import RightTop from "./right-top.vue";
|
||||
import RightCenter from "./right-center.vue";
|
||||
import RightBottom from "./right-bottom.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="index-box">
|
||||
<div class="contetn_left">
|
||||
<div class="pagetab">
|
||||
<div class="item">实时监测</div>
|
||||
<div class="item">统计分析</div>
|
||||
</div>
|
||||
<ItemWrap class="contetn_left-top contetn_lr-item" title="设备总览">
|
||||
<LeftTop />
|
||||
</ItemWrap>
|
||||
<ItemWrap class="contetn_left-center contetn_lr-item" title="用户总览">
|
||||
<LeftCenter />
|
||||
</ItemWrap>
|
||||
<ItemWrap
|
||||
class="contetn_left-bottom contetn_lr-item"
|
||||
title="设备提醒"
|
||||
style="padding: 0 10px 16px 10px"
|
||||
>
|
||||
<LeftBottom />
|
||||
</ItemWrap>
|
||||
</div>
|
||||
<div class="contetn_center">
|
||||
<CenterMap class="contetn_center_top" title="设备分布图" />
|
||||
<ItemWrap class="contetn_center-bottom" title="安装计划">
|
||||
<CenterBottom />
|
||||
</ItemWrap>
|
||||
</div>
|
||||
<div class="contetn_right">
|
||||
<ItemWrap class="contetn_left-bottom contetn_lr-item" title="报警次数">
|
||||
<RightTop />
|
||||
</ItemWrap>
|
||||
<ItemWrap
|
||||
class="contetn_left-bottom contetn_lr-item"
|
||||
title="报警排名(TOP8)"
|
||||
style="padding: 0 10px 16px 10px"
|
||||
>
|
||||
<RightCenter />
|
||||
</ItemWrap>
|
||||
<ItemWrap class="contetn_left-bottom contetn_lr-item" title="数据统计图 ">
|
||||
<RightBottom />
|
||||
</ItemWrap>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.index-box {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
min-height: calc(100% - 64px);
|
||||
justify-content: space-between;
|
||||
}
|
||||
//左边 右边 结构一样
|
||||
.contetn_left,
|
||||
.contetn_right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
position: relative;
|
||||
width: 540px;
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.contetn_center {
|
||||
flex: 1;
|
||||
margin: 0 54px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
.contetn_center-bottom {
|
||||
height: 315px;
|
||||
}
|
||||
}
|
||||
|
||||
.contetn_lr-item {
|
||||
height: 310px;
|
||||
}
|
||||
</style>
|
231
src/views/common/screen-vue3/views/index/left-bottom.vue
Normal file
@ -0,0 +1,231 @@
|
||||
<script setup lang="ts">
|
||||
import { leftBottom } from "/@/views/common/screen-vue3/api";
|
||||
import SeamlessScroll from "/@/views/common/screen-vue3/components/seamless-scroll";
|
||||
import { computed, onMounted, reactive } from "vue";
|
||||
import { useSettingStore } from "/@/views/common/screen-vue3/stores";
|
||||
import { storeToRefs } from "pinia";
|
||||
import EmptyCom from "/@/views/common/screen-vue3/components/empty-com";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const { defaultOption, indexConfig } = storeToRefs(settingStore);
|
||||
const state = reactive<any>({
|
||||
list: [],
|
||||
defaultOption: {
|
||||
...defaultOption.value,
|
||||
singleHeight: 256,
|
||||
limitScrollNum: 4,
|
||||
},
|
||||
scroll: true,
|
||||
});
|
||||
|
||||
const getData = () => {
|
||||
leftBottom( { limitNum: 20 })
|
||||
.then((res) => {
|
||||
console.log("左下--设备提醒", res);
|
||||
if (res.success) {
|
||||
state.list = res.data.list;
|
||||
} else {
|
||||
ElMessage({
|
||||
message: res.msg,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
};
|
||||
const addressHandle = (item: any) => {
|
||||
let name = item.provinceName;
|
||||
if (item.cityName) {
|
||||
name += "/" + item.cityName;
|
||||
if (item.countyName) {
|
||||
name += "/" + item.countyName;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
};
|
||||
const comName = computed(() => {
|
||||
if (indexConfig.value.leftBottomSwiper) {
|
||||
return SeamlessScroll;
|
||||
} else {
|
||||
return EmptyCom;
|
||||
}
|
||||
});
|
||||
onMounted(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="left_boottom_wrap beautify-scroll-def" :class="{ 'overflow-y-auto': !indexConfig.leftBottomSwiper }">
|
||||
<component
|
||||
:is="comName"
|
||||
:list="state.list"
|
||||
v-model="state.scroll"
|
||||
:singleHeight="state.defaultOption.singleHeight"
|
||||
:step="state.defaultOption.step"
|
||||
:limitScrollNum="state.defaultOption.limitScrollNum"
|
||||
:hover="state.defaultOption.hover"
|
||||
:singleWaitTime="state.defaultOption.singleWaitTime"
|
||||
:wheel="state.defaultOption.wheel"
|
||||
>
|
||||
<ul class="left_boottom">
|
||||
<li class="left_boottom_item" v-for="(item, i) in state.list" :key="i">
|
||||
<span class="orderNum doudong">{{ i + 1 }}</span>
|
||||
<div class="inner_right">
|
||||
<div class="dibu"></div>
|
||||
<div class="flex">
|
||||
<div class="info">
|
||||
<span class="labels">设备ID:</span>
|
||||
<span class="text-content zhuyao doudong wangguan"> {{ item.gatewayno }}</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="labels">时间:</span>
|
||||
<span class="text-content" style="font-size: 12px"> {{ item.createTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="types doudong"
|
||||
:class="{
|
||||
typeRed: item.onlineState == 0,
|
||||
typeGreen: item.onlineState == 1,
|
||||
}"
|
||||
>{{ item.onlineState == 1 ? "上线" : "下线" }}</span
|
||||
>
|
||||
|
||||
<div class="info addresswrap">
|
||||
<span class="labels">地址:</span>
|
||||
<span class="text-content ciyao" style="font-size: 12px"> {{ addressHandle(item) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
|
||||
.left_boottom_wrap {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.doudong {
|
||||
overflow: hidden;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.overflow-y-auto {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.left_boottom {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.left_boottom_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
margin: 10px 0;
|
||||
.orderNum {
|
||||
margin: 0 16px 0 -20px;
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
|
||||
.labels {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.zhuyao {
|
||||
color: #1890ff;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.ciyao {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: #e6a23c;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.inner_right {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 380px;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
.dibu {
|
||||
position: absolute;
|
||||
height: 2px;
|
||||
width: 104%;
|
||||
background-image: url("/src/views/common/screen-vue3/assets/img/zuo_xuxian.png");
|
||||
bottom: -10px;
|
||||
left: -2%;
|
||||
background-size: cover;
|
||||
}
|
||||
.addresswrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.wangguan {
|
||||
color: #1890ff;
|
||||
font-weight: 900;
|
||||
font-size: 15px;
|
||||
width: 80px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
// color: rgba(211, 210, 210,.8);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.address {
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
// @include text-overflow(1);
|
||||
}
|
||||
|
||||
.types {
|
||||
width: 30px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.typeRed {
|
||||
color: #fc1a1a;
|
||||
}
|
||||
|
||||
.typeGreen {
|
||||
color: #29fc29;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
161
src/views/common/screen-vue3/views/index/left-center.vue
Normal file
@ -0,0 +1,161 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue";
|
||||
import { graphic } from "echarts/core";
|
||||
import { countUserNum } from "/@/views/common/screen-vue3/api";
|
||||
import {ElMessage} from "element-plus"
|
||||
|
||||
let colors = ["#0BFC7F", "#A0A0A0", "#F48C02", "#F4023C"];
|
||||
const option = ref({});
|
||||
const state = reactive({
|
||||
lockNum: 0,
|
||||
offlineNum: 0,
|
||||
onlineNum: 0,
|
||||
alarmNum: 0,
|
||||
totalNum: 0,
|
||||
});
|
||||
const echartsGraphic = (colors: string[]) => {
|
||||
return new graphic.LinearGradient(1, 0, 0, 0, [
|
||||
{ offset: 0, color: colors[0] },
|
||||
{ offset: 1, color: colors[1] },
|
||||
]);
|
||||
};
|
||||
const getData = () => {
|
||||
countUserNum().then((res) => {
|
||||
console.log("左中--用户总览",res);
|
||||
if (res.success) {
|
||||
state.lockNum = res.data.lockNum;
|
||||
state.offlineNum = res.data.offlineNum;
|
||||
state.onlineNum = res.data.onlineNum;
|
||||
state.totalNum = res.data.totalNum;
|
||||
state.alarmNum = res.data.alarmNum;
|
||||
setOption();
|
||||
}else{
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
}).catch(err=>{
|
||||
ElMessage.error(err)
|
||||
});
|
||||
};
|
||||
getData();
|
||||
const setOption = () => {
|
||||
option.value = {
|
||||
title: {
|
||||
top: "center",
|
||||
left: "center",
|
||||
text: [`{value|${state.totalNum}}`, "{name|总数}"].join("\n"),
|
||||
textStyle: {
|
||||
rich: {
|
||||
value: {
|
||||
color: "#ffffff",
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
lineHeight: 20,
|
||||
padding:[4,0,4,0]
|
||||
},
|
||||
name: {
|
||||
color: "#ffffff",
|
||||
lineHeight: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
backgroundColor: "rgba(0,0,0,.6)",
|
||||
borderColor: "rgba(147, 235, 248, .8)",
|
||||
textStyle: {
|
||||
color: "#FFF",
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "用户总览",
|
||||
type: "pie",
|
||||
radius: ["40%", "70%"],
|
||||
// avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 6,
|
||||
borderColor: "rgba(255,255,255,0)",
|
||||
borderWidth: 2,
|
||||
},
|
||||
color: colors,
|
||||
label: {
|
||||
show: true,
|
||||
formatter: " {b|{b}} \n {c|{c}个} {per|{d}%} ",
|
||||
// position: "outside",
|
||||
rich: {
|
||||
b: {
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
lineHeight: 26,
|
||||
},
|
||||
c: {
|
||||
color: "#31ABE3",
|
||||
fontSize: 14,
|
||||
},
|
||||
per: {
|
||||
color: "#31ABE3",
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
},
|
||||
emphasis: {
|
||||
show: false,
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: { show: true },
|
||||
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 20, // 第一段线 长度
|
||||
length2: 36, // 第二段线 长度
|
||||
smooth: 0.2,
|
||||
lineStyle: {},
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: state.onlineNum,
|
||||
name: "在线",
|
||||
itemStyle: {
|
||||
color: echartsGraphic(["#0BFC7F", "#A3FDE0"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
value: state.offlineNum,
|
||||
name: "离线",
|
||||
itemStyle: {
|
||||
color: echartsGraphic(["#A0A0A0", "#DBDFDD"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
value: state.lockNum,
|
||||
name: "锁定",
|
||||
itemStyle: {
|
||||
color: echartsGraphic(["#F48C02", "#FDDB7D"]),
|
||||
},
|
||||
},
|
||||
{
|
||||
value: state.alarmNum,
|
||||
name: "异常",
|
||||
itemStyle: {
|
||||
color: echartsGraphic(["#F4023C", "#FB6CB7"]),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-chart class="chart" :option="option" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
</style>
|
131
src/views/common/screen-vue3/views/index/left-top.vue
Normal file
@ -0,0 +1,131 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from "vue";
|
||||
import { countDeviceNum } from "/@/views/common/screen-vue3/api";
|
||||
import CountUp from "/@/views/common/screen-vue3/components/count-up";
|
||||
import {ElMessage} from "element-plus"
|
||||
|
||||
const duration = ref(2);
|
||||
const state = reactive({
|
||||
alarmNum: 0,
|
||||
offlineNum: 0,
|
||||
onlineNum: 0,
|
||||
totalNum: 0,
|
||||
});
|
||||
|
||||
|
||||
const getData = () => {
|
||||
countDeviceNum().then((res) => {
|
||||
console.log("左上--设备总览",res);
|
||||
if (res.success) {
|
||||
state.alarmNum = res.data.alarmNum;
|
||||
state.offlineNum = res.data.offlineNum;
|
||||
state.onlineNum = res.data.onlineNum;
|
||||
state.totalNum = res.data.totalNum;
|
||||
}else{
|
||||
ElMessage.error(res.msg)
|
||||
}
|
||||
}).catch(err=>{
|
||||
ElMessage.error(err)
|
||||
});;
|
||||
};
|
||||
getData();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul class="user_Overview flex">
|
||||
<li class="user_Overview-item" style="color: #00fdfa">
|
||||
<div class="user_Overview_nums allnum">
|
||||
<CountUp :endVal="state.totalNum" :duration="duration" />
|
||||
</div>
|
||||
<p>总设备数</p>
|
||||
</li>
|
||||
<li class="user_Overview-item" style="color: #07f7a8">
|
||||
<div class="user_Overview_nums online">
|
||||
<CountUp :endVal="state.onlineNum" :duration="duration" />
|
||||
</div>
|
||||
<p>在线数</p>
|
||||
</li>
|
||||
<li class="user_Overview-item" style="color: #e3b337">
|
||||
<div class="user_Overview_nums offline">
|
||||
<CountUp :endVal="state.offlineNum" :duration="duration" />
|
||||
</div>
|
||||
<p>掉线数</p>
|
||||
</li>
|
||||
<li class="user_Overview-item" style="color: #f5023d">
|
||||
<div class="user_Overview_nums laramnum">
|
||||
<CountUp :endVal="state.alarmNum" :duration="duration" />
|
||||
</div>
|
||||
<p>告警次数</p>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.left-top {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.user_Overview {
|
||||
li {
|
||||
flex: 1;
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
height: 16px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.user_Overview_nums {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
font-size: 22px;
|
||||
margin: 50px auto 30px;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&.bgdonghua::before {
|
||||
animation: rotating 14s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.allnum {
|
||||
&::before {
|
||||
background-image: url("/@/views/common/screen-vue3/assets/img/left_top_lan.png");
|
||||
}
|
||||
}
|
||||
|
||||
.online {
|
||||
&::before {
|
||||
background-image: url("/@/views/common/screen-vue3/assets/img/left_top_lv.png");
|
||||
}
|
||||
}
|
||||
|
||||
.offline {
|
||||
&::before {
|
||||
background-image: url("/@/views/common/screen-vue3/assets/img/left_top_huang.png");
|
||||
}
|
||||
}
|
||||
|
||||
.laramnum {
|
||||
&::before {
|
||||
background-image: url("/@/views/common/screen-vue3/assets/img/left_top_hong.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
195
src/views/common/screen-vue3/views/index/right-bottom.vue
Normal file
@ -0,0 +1,195 @@
|
||||
<script setup lang="ts">
|
||||
import { rightBottom } from "/@/views/common/screen-vue3/api";
|
||||
import SeamlessScroll from "/@/views/common/screen-vue3/components/seamless-scroll";
|
||||
import { computed, onMounted, reactive } from "vue";
|
||||
import { useSettingStore } from "/@/views/common/screen-vue3/stores";
|
||||
import { storeToRefs } from "pinia";
|
||||
import EmptyCom from "/@/views/common/screen-vue3/components/empty-com";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const { defaultOption, indexConfig } = storeToRefs(settingStore);
|
||||
const state = reactive<any>({
|
||||
list: [],
|
||||
defaultOption: {
|
||||
...defaultOption.value,
|
||||
singleHeight: 252,
|
||||
limitScrollNum: 3,
|
||||
// step:3
|
||||
},
|
||||
scroll: true,
|
||||
});
|
||||
|
||||
const getData = () => {
|
||||
rightBottom({ limitNum: 20 })
|
||||
.then((res) => {
|
||||
console.log("右下", res);
|
||||
if (res.success) {
|
||||
state.list = res.data.list;
|
||||
} else {
|
||||
ElMessage({
|
||||
message: res.msg,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
const comName = computed(() => {
|
||||
if (indexConfig.value.rightBottomSwiper) {
|
||||
return SeamlessScroll;
|
||||
} else {
|
||||
return EmptyCom;
|
||||
}
|
||||
});
|
||||
function montionFilter(val: any) {
|
||||
// console.log(val);
|
||||
return val ? Number(val).toFixed(2) : "--";
|
||||
}
|
||||
const handleAddress = (item: any) => {
|
||||
return `${item.provinceName}/${item.cityName}/${item.countyName}`;
|
||||
};
|
||||
onMounted(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="right_bottom_wrap beautify-scroll-def" :class="{ 'overflow-y-auto': !indexConfig.rightBottomSwiper }">
|
||||
<component
|
||||
:is="comName"
|
||||
:list="state.list"
|
||||
v-model="state.scroll"
|
||||
:singleHeight="state.defaultOption.singleHeight"
|
||||
:step="state.defaultOption.step"
|
||||
:limitScrollNum="state.defaultOption.limitScrollNum"
|
||||
:hover="state.defaultOption.hover"
|
||||
:singleWaitTime="state.defaultOption.singleWaitTime"
|
||||
:wheel="state.defaultOption.wheel"
|
||||
>
|
||||
<ul class="right_bottom">
|
||||
<li class="right_center_item" v-for="(item, i) in state.list" :key="i">
|
||||
<span class="orderNum">{{ i + 1 }}</span>
|
||||
<div class="inner_right">
|
||||
<div class="dibu"></div>
|
||||
<div class="flex">
|
||||
<div class="info">
|
||||
<span class="labels">设备ID:</span>
|
||||
<span class="text-content zhuyao"> {{ item.gatewayno }}</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="labels">型号:</span>
|
||||
<span class="text-content"> {{ item.terminalno }}</span>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="labels">告警值:</span>
|
||||
<span class="text-content warning"> {{ montionFilter(item.alertvalue) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<div class="info">
|
||||
<span class="labels shrink-0"> 地址:</span>
|
||||
<span class="ciyao truncate" style="font-size: 12px; width: 220px" :title="handleAddress(item)">
|
||||
{{ handleAddress(item) }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="info time shrink-0">
|
||||
<span class="labels">时间:</span>
|
||||
<span class="text-content" style="font-size: 12px"> {{ item.createtime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="info">
|
||||
<span class="labels">报警内容:</span>
|
||||
<span class="text-content ciyao" :class="{ warning: item.alertdetail }">
|
||||
{{ item.alertdetail || "无" }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.right_bottom {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.right_center_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: auto;
|
||||
padding: 10px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
|
||||
.orderNum {
|
||||
margin: 0 20px 0 -20px;
|
||||
}
|
||||
|
||||
.inner_right {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 400px;
|
||||
flex-shrink: 0;
|
||||
line-height: 1.5;
|
||||
|
||||
.dibu {
|
||||
position: absolute;
|
||||
height: 2px;
|
||||
width: 104%;
|
||||
background-image: url("/src/views/common/screen-vue3/assets/img/zuo_xuxian.png");
|
||||
bottom: -12px;
|
||||
left: -2%;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.labels {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
.zhuyao {
|
||||
color: #1890ff;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.ciyao {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: #e6a23c;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right_bottom_wrap {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 252px;
|
||||
}
|
||||
|
||||
.overflow-y-auto {
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
46
src/views/common/screen-vue3/views/index/right-center.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from "vue";
|
||||
import CapsuleChart from "/@/views/common/screen-vue3/components/datav/capsule-chart";
|
||||
import { ranking } from "/@/views/common/screen-vue3/api";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const config = ref({
|
||||
showValue: true,
|
||||
unit: "次",
|
||||
});
|
||||
const data = ref([]);
|
||||
const getData = () => {
|
||||
ranking()
|
||||
.then((res) => {
|
||||
console.log("右中--报警排名", res);
|
||||
if (res.success) {
|
||||
data.value = res.data;
|
||||
} else {
|
||||
ElMessage({
|
||||
message: res.msg,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
};
|
||||
getData();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="right_bottom">
|
||||
<CapsuleChart :config="config" style="width: 100%; height: 260px" :data="data" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.right_bottom {
|
||||
box-sizing: border-box;
|
||||
padding: 0 16px;
|
||||
}
|
||||
</style>
|
236
src/views/common/screen-vue3/views/index/right-top.vue
Normal file
@ -0,0 +1,236 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { alarmNum } from "/@/views/common/screen-vue3/api";
|
||||
import { graphic } from "echarts/core";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const option = ref({});
|
||||
const getData = () => {
|
||||
alarmNum()
|
||||
.then((res) => {
|
||||
console.log("右上--报警次数 ", res);
|
||||
if (res.success) {
|
||||
setOption(res.data.dateList, res.data.numList, res.data.numList2);
|
||||
} else {
|
||||
ElMessage({
|
||||
message: res.msg,
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
ElMessage.error(err);
|
||||
});
|
||||
};
|
||||
const setOption = async (xData: any[], yData: any[], yData2: any[]) => {
|
||||
option.value = {
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: xData,
|
||||
boundaryGap: false, // 不留白,从原点开始
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "rgba(31,99,163,.2)",
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
// show:false,
|
||||
lineStyle: {
|
||||
color: "rgba(31,99,163,.1)",
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#7EB7FD",
|
||||
fontWeight: "500",
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "rgba(31,99,163,.2)",
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "rgba(31,99,163,.1)",
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#7EB7FD",
|
||||
fontWeight: "500",
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
backgroundColor: "rgba(0,0,0,.6)",
|
||||
borderColor: "rgba(147, 235, 248, .8)",
|
||||
textStyle: {
|
||||
color: "#FFF",
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
//布局
|
||||
show: true,
|
||||
left: "10px",
|
||||
right: "30px",
|
||||
bottom: "10px",
|
||||
top: "32px",
|
||||
containLabel: true,
|
||||
borderColor: "#1F63A3",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
type: "line",
|
||||
smooth: true,
|
||||
symbol: "none", //去除点
|
||||
name: "报警1次数",
|
||||
color: "rgba(252,144,16,.7)",
|
||||
areaStyle: {
|
||||
//右,下,左,上
|
||||
color: new graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: "rgba(252,144,16,.7)",
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(252,144,16,.0)",
|
||||
},
|
||||
],
|
||||
false
|
||||
),
|
||||
},
|
||||
markPoint: {
|
||||
data: [
|
||||
{
|
||||
name: "最大值",
|
||||
type: "max",
|
||||
valueDim: "y",
|
||||
symbol: "rect",
|
||||
symbolSize: [60, 26],
|
||||
symbolOffset: [0, -20],
|
||||
itemStyle: {
|
||||
color: "rgba(0,0,0,0)",
|
||||
},
|
||||
label: {
|
||||
color: "#FC9010",
|
||||
backgroundColor: "rgba(252,144,16,0.1)",
|
||||
borderRadius: 6,
|
||||
padding: [7, 14],
|
||||
borderWidth: 0.5,
|
||||
borderColor: "rgba(252,144,16,.5)",
|
||||
formatter: "报警1:{c}",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "最大值",
|
||||
type: "max",
|
||||
valueDim: "y",
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
itemStyle: {
|
||||
color: "#FC9010",
|
||||
shadowColor: "#FC9010",
|
||||
shadowBlur: 8,
|
||||
},
|
||||
label: {
|
||||
formatter: "",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: yData2,
|
||||
type: "line",
|
||||
smooth: true,
|
||||
symbol: "none", //去除点
|
||||
name: "报警2次数",
|
||||
color: "rgba(9,202,243,.7)",
|
||||
areaStyle: {
|
||||
//右,下,左,上
|
||||
color: new graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: "rgba(9,202,243,.7)",
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "rgba(9,202,243,.0)",
|
||||
},
|
||||
],
|
||||
false
|
||||
),
|
||||
},
|
||||
markPoint: {
|
||||
data: [
|
||||
{
|
||||
name: "最大值",
|
||||
type: "max",
|
||||
valueDim: "y",
|
||||
symbol: "rect",
|
||||
symbolSize: [60, 26],
|
||||
symbolOffset: [0, -20],
|
||||
itemStyle: {
|
||||
color: "rgba(0,0,0,0)",
|
||||
},
|
||||
label: {
|
||||
color: "#09CAF3",
|
||||
backgroundColor: "rgba(9,202,243,0.1)",
|
||||
|
||||
borderRadius: 6,
|
||||
borderColor: "rgba(9,202,243,.5)",
|
||||
padding: [7, 14],
|
||||
formatter: "报警2:{c}",
|
||||
borderWidth: 0.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "最大值",
|
||||
type: "max",
|
||||
valueDim: "y",
|
||||
symbol: "circle",
|
||||
symbolSize: 6,
|
||||
itemStyle: {
|
||||
color: "#09CAF3",
|
||||
shadowColor: "#09CAF3",
|
||||
shadowBlur: 8,
|
||||
},
|
||||
label: {
|
||||
formatter: "",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
onMounted(() => {
|
||||
getData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-chart class="chart" :option="option" v-if="JSON.stringify(option) != '{}'" />
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@import '/src/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/src/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
</style>
|
141
src/views/common/screen-vue3/views/setting.vue
Normal file
@ -0,0 +1,141 @@
|
||||
<script setup lang="ts">
|
||||
import { useSettingStore } from "/@/views/common/screen-vue3/stores/index";
|
||||
import { ref } from "vue";
|
||||
import {storeToRefs} from "pinia"
|
||||
const isScaleRadio = ref(false);
|
||||
const leftBottomRadio=ref(true)
|
||||
const rightBottomRadio=ref(true)
|
||||
const settingStore = useSettingStore();
|
||||
const {indexConfig}=storeToRefs(settingStore)
|
||||
|
||||
const init = () => {
|
||||
settingStore.initSetting();
|
||||
isScaleRadio.value = settingStore.isScale;
|
||||
|
||||
leftBottomRadio.value=indexConfig.value.leftBottomSwiper
|
||||
rightBottomRadio.value=indexConfig.value.rightBottomSwiper
|
||||
|
||||
};
|
||||
init();
|
||||
const handleClose = () => {};
|
||||
|
||||
const cancelClick = () => {
|
||||
settingStore.setSettingShow(false);
|
||||
};
|
||||
|
||||
const confirmClick = () => {};
|
||||
const isScaleChange = (flag: boolean) => {
|
||||
settingStore.setIsScale(flag);
|
||||
};
|
||||
const radiochange = (blag: boolean) => {
|
||||
settingStore.setIsScale(blag);
|
||||
// this.$store.commit('setting/updateSwiper', { val, type })
|
||||
};
|
||||
const indexRadioChange=(flag: boolean)=>{
|
||||
settingStore.setIndexConfig({
|
||||
leftBottomSwiper: leftBottomRadio.value,//左轮播
|
||||
rightBottomSwiper:rightBottomRadio.value,//右下轮播
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-drawer v-model="settingStore.settingShow" direction="rtl" size="360px">
|
||||
<template #header>
|
||||
<h2 class="setting-title">设置</h2>
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="left_shu">全局设置</div>
|
||||
<div class="setting_item">
|
||||
<span class="setting_label">
|
||||
是否进行自动适配<span class="setting_label_tip"
|
||||
>(默认分辨率1920*1080)</span
|
||||
>:
|
||||
</span>
|
||||
<div class="setting_content">
|
||||
<el-radio-group v-model="isScaleRadio" @change="(flag)=>isScaleChange(flag as boolean)">
|
||||
<el-radio :label="true">是</el-radio>
|
||||
<el-radio :label="false">否</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="left_shu">实时监测</div>
|
||||
<div class="setting_item">
|
||||
<span class="setting_label">
|
||||
设备提醒自动轮询: <span class="setting_label_tip"></span>
|
||||
</span>
|
||||
<div class="setting_content">
|
||||
<el-radio-group
|
||||
v-model="leftBottomRadio"
|
||||
@change="(flag)=>indexRadioChange(flag as boolean)"
|
||||
>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
<el-radio :label="false">否</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting_item">
|
||||
<span class="setting_label"> 实时预警轮播: </span>
|
||||
<div class="setting_content">
|
||||
<el-radio-group
|
||||
v-model="rightBottomRadio"
|
||||
@change="(flag)=>indexRadioChange(flag as boolean)"
|
||||
>
|
||||
<el-radio :label="true">是</el-radio>
|
||||
<el-radio :label="false">否</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- <template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button @click="cancelClick">取消</el-button>
|
||||
<el-button type="primary" @click="confirmClick">确定</el-button>
|
||||
</div>
|
||||
</template> -->
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@import '/@/views/common/screen-vue3/assets/css/main.scss';
|
||||
@import '/@/views/common/screen-vue3/assets/css/tailwind.css';
|
||||
.setting-title {
|
||||
font-size: 20px;
|
||||
color: #000;
|
||||
font-weight: 900;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
.left_shu {
|
||||
color: #000;
|
||||
font-weight: 900;
|
||||
position: relative;
|
||||
text-indent: 10px;
|
||||
padding: 16px 0 10px 0;
|
||||
line-height: 1;
|
||||
&::before {
|
||||
display: block;
|
||||
content: " ";
|
||||
height: 16px;
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
background: #0072ff;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
}
|
||||
}
|
||||
.setting_item {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
|
||||
// display: flex;
|
||||
.setting_label {
|
||||
color: #555454;
|
||||
}
|
||||
.setting_label_tip {
|
||||
font-size: 12px;
|
||||
color: #838282;
|
||||
}
|
||||
}
|
||||
</style>
|
14
tailwind.config.js
Normal file
@ -0,0 +1,14 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./index.html', './src/views/common/screen-vue3/**/*.{vue,js,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
// fontFamily: {
|
||||
// sans: ['"Inter var"', ...defaultTheme.fontFamily.sans],
|
||||
// },
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
|