Commit 2875b3a8 by 陈鑫伟

update

parents
> 1%
last 2 versions
not IE <= 11
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
BASE_URL=/
ENTRY=./src/main.ts
VUE_APP_ROUTE_BASE=/
VUE_APP_APP_NAME=roms-cnc
VUE_APP_APP_THEME=theme_light
VUE_APP_BASE_URL=https://www.machplat.com/roms-server-cnc
VUE_APP_ROUTE_MODE=history
# 测试用url
VUE_APP_TEST_BASE_URL=https://www.machplat.com/roms-server-cnc
#VUE_APP_TEST_BASE_URL=http://192.168.0.105:10100/roms-server-cnc
VUE_APP_HTML_TITLE=LKT-ROMS
VUE_APP_LOGIN_TITLE1=设备运维管理云平台
VUE_APP_LOGIN_TITLE2=LKT-ROMS
VUE_APP_TITLE_LG=https://roms-cnc.oss-cn-hangzhou.aliyuncs.com/logos/logow1.png
VUE_APP_LOGIN_LG=https://roms-cnc.oss-cn-hangzhou.aliyuncs.com/logos/lkt_logo2.png
VUE_APP_LOGIN_SCHEMA=cnc
NODE_ENV=production
ENTRY=./src/main.ts
BASE_URL=./
VUE_APP_ROUTE_BASE=/
VUE_APP_APP_NAME=roms-cnc
VUE_APP_APP_THEME=theme_light
VUE_APP_BASE_URL=https://www.machplat.com/roms-server-cnc
VUE_APP_ROUTE_MODE=hash
VUE_APP_DEPLOY_MODE=normal
VUE_APP_HTML_TITLE=LKT-ROMS
VUE_APP_LOGIN_TITLE1=设备运维管理云平台
VUE_APP_LOGIN_TITLE2=LKT-ROMS
VUE_APP_TITLE_LG=https://roms-cnc.oss-cn-hangzhou.aliyuncs.com/logos/logow1.png
VUE_APP_LOGIN_LG=https://roms-cnc.oss-cn-hangzhou.aliyuncs.com/logos/lkt_logo2.png
VUE_APP_LOGIN_SCHEMA=cnc
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
weekly.*
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
package-lock.json
.history
安装:yarn
代码整齐:yarn lint
运行dev:yarn dev.demo
更新web-toolkit: yarn core
module.exports = {
presets: [
'@vue/app'
]
}
{
"name": "roms_web",
"version": "2.0.0",
"private": true,
"scripts": {
"dev.demo": "vue-cli-service serve --mode dev.demo",
"build.demo": "vue-cli-service build --modern --mode pro.demo",
"lint": "vue-cli-service lint",
"rm_cache": "rm -rf ./node_modules/.cache",
"core": "yarn add git+https://github.com/mizuki1412/web-toolkit.git",
"upgrade-dep": "yarn upgrade-interactive --latest"
},
"lint-staged": {
"*.ts": [
"vue-cli-service lint",
"git add"
]
},
"dependencies": {
"echarts": "^4.8.0",
"element-ui": "^2.13.2",
"web-toolkit": "git+https://github.com/mizuki1412/web-toolkit.git"
},
"devDependencies": {
"@babel/core": "7.10.4",
"@babel/helper-call-delegate": "^7.10.4",
"@types/echarts": "^4.6.3",
"@types/qs": "^6.9.3",
"@vue/babel-preset-app": "^4.4.6",
"@vue/cli-plugin-babel": "^4.4.6",
"@vue/cli-plugin-typescript": "^4.4.6",
"@vue/cli-service": "^4.4.6",
"babel-loader": "^8.1.0",
"core-js": "^3.6.5",
"node-sass": "^4.14.1",
"sass-loader": "^9.0.2",
"typescript": "^3.9.6",
"vue-template-compiler": "^2.6.11"
}
}
module.exports = {
plugins: {
autoprefixer: {}
}
}
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566177859925" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1464" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M532.1 918.9c-9.1 11-25.5 12.6-36.5 3.4-1.2-1-2.4-2.2-3.4-3.4-154.6-186.6-245.7-319-273.2-397.3-12-34.3-18.2-70.4-18.1-106.7 0-174.9 139.4-316.7 311.3-316.7S823.4 240 823.4 414.9c0 37.7-6.5 73.9-18.4 107.4-27.5 78.1-118.6 210.3-272.9 396.6z m-20-398.4c57.3 0 103.8-47.3 103.8-105.6s-46.4-105.5-103.8-105.5-103.8 47.2-103.8 105.5 46.5 105.6 103.8 105.6z" p-id="1465" fill="#515151"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566177859925" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1464" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M532.1 918.9c-9.1 11-25.5 12.6-36.5 3.4-1.2-1-2.4-2.2-3.4-3.4-154.6-186.6-245.7-319-273.2-397.3-12-34.3-18.2-70.4-18.1-106.7 0-174.9 139.4-316.7 311.3-316.7S823.4 240 823.4 414.9c0 37.7-6.5 73.9-18.4 107.4-27.5 78.1-118.6 210.3-272.9 396.6z m-20-398.4c57.3 0 103.8-47.3 103.8-105.6s-46.4-105.5-103.8-105.5-103.8 47.2-103.8 105.5 46.5 105.6 103.8 105.6z" p-id="1465" fill="#d81e06"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566177859925" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1464" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M532.1 918.9c-9.1 11-25.5 12.6-36.5 3.4-1.2-1-2.4-2.2-3.4-3.4-154.6-186.6-245.7-319-273.2-397.3-12-34.3-18.2-70.4-18.1-106.7 0-174.9 139.4-316.7 311.3-316.7S823.4 240 823.4 414.9c0 37.7-6.5 73.9-18.4 107.4-27.5 78.1-118.6 210.3-272.9 396.6z m-20-398.4c57.3 0 103.8-47.3 103.8-105.6s-46.4-105.5-103.8-105.5-103.8 47.2-103.8 105.5 46.5 105.6 103.8 105.6z" p-id="1465" fill="#515151"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576662003743" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2223" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M514.878 89.234c-177.908 0-322.133 142.358-322.133 317.969s322.133 522.38 322.133 522.38 322.133-346.77 322.133-522.38-144.225-317.969-322.133-317.969zM514.878 565.431c-85.087 0-154.064-68.977-154.064-154.064s68.978-154.064 154.064-154.064 154.064 68.977 154.064 154.064c0 85.087-68.978 154.064-154.064 154.064z" p-id="2224" fill="#09dc17"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577968201688" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4489" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M514.878 89.234c-177.908 0-322.133 142.358-322.133 317.969s322.133 522.38 322.133 522.38 322.133-346.77 322.133-522.38-144.225-317.969-322.133-317.969zM514.878 565.431c-85.087 0-154.064-68.977-154.064-154.064s68.978-154.064 154.064-154.064 154.064 68.977 154.064 154.064c0 85.087-68.978 154.064-154.064 154.064z" p-id="4490" fill="#f78105"></path></svg>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
<title><%= process.env.VUE_APP_HTML_TITLE %></title>
<script>
if (!!window.ActiveXObject || "ActiveXObject" in window) {
alert("当前浏览器不支持,请使用360浏览器极速模式或谷歌浏览器等现代浏览器");
}
</script>
<script src="https://webapi.amap.com/maps?v=1.4.15&key=00e717e8ef5d85403d95f8fade2920bd&plugin=AMap.Geocoder,AMap.DistrictSearch,AMap.Weather"></script>
<link rel="stylesheet" href="https://at.alicdn.com/t/font_248093_unlsz3fwy.css
"/>
</head>
<body>
<div id="app"></div>
</body>
</html>
<template>
<router-view/>
</template>
<script>
export default {
name: 'app',
};
</script>
<template>
<div class="flex">
<div v-for="(item, index) in addrArray" class="el-input el-input--small" :key="index"
:class="setWrap()" style="display:flex; min-width: 60px;"
onpaste="return false">
<input
class="el-input__inner"
v-model="addrArray[index]" :key="index" style="text-align: center;"
maxlength="3"
:class="setGroup()"
:disabled="!available"
@blur="blur1($event, index)"
@keypress="$event.returnValue=limitCharacter($event, index)"
@keydown="lastFocus($event, index)"
@keyup="nextFocus($event, index)"/>
<div class="point" v-if="index<3">&bull;</div>
</div>
</div>
</template>
<script lang="ts">
import {ref, onMounted, watch} from '@vue/composition-api';
import {isNil} from 'web-toolkit/src/utils';
export default {
name: 'IPInput',
props: {
value: {
type: String,
default: null,
},
available: {
type: Boolean,
default: true,
},
},
setup(props: Record<string, any>, ctx: any) {
const addrArray = ref<any>(isNil(props.value) ? ['', '', '', ''] : props.value.split('.'));
const addrResult = ref<any>('');
// 独立性区分groupId --- 根据毫秒时间
const groupId = ref<any>(guid());
watch(() => props.value, () => {
addrArray.value = isNil(props.value) ? ['', '', '', ''] : props.value.split('.');
});
// 禁止输入不是数字的字符
const limitCharacter = (event: any, index: number) => {
return !event.key.match(/[^0-9]/);
};
const nextFocus = (event: any, index: number) => {
const dom = document.getElementsByClassName(`${groupId.value}`);
const currInput: any = dom[index];
const nextInput: any = dom[index + 1];
// 输入长度为3聚焦到下一个输入框
if (!(event.keyCode === 46 || event.keyCode === 8) && ![37, 38, 39, 40].includes(event.keyCode)) {
addrArray.value[index] = addrArray.value[index].replace(/[^0-9]/g, '');
event.target.value = addrArray.value[index];
if (currInput.value.length === 3 && nextInput && nextInput.value.length < 3) {
nextInput.focus();
}
}
// 输入为'.'聚焦到下一个输入框
if (event.key === '.' && nextInput) {
nextInput.focus();
}
// 输入大于255自动转为255
if (event.target.value > 255) {
addrArray.value[index] = '255';
event.target.value = '255';
}
// 将ip转为字符串并更新
addrResult.value = addrArray.value.join('.');
ctx.emit('input', addrResult.value);
};
// backspace | delete 删除整个输入框聚焦到上一个输入框
const lastFocus = (event: any, index: number) => {
const dom = document.getElementsByClassName(`${groupId.value}`);
const currInput: any = dom[index];
const lastInput: any = dom[index - 1];
if (event.keyCode === 46 || event.keyCode === 8) {
if (currInput.value.length === 0 && lastInput) {
lastInput.focus();
}
}
};
const blur1 = (event: any, index: number) => {
addrArray.value[index] = addrArray.value[index].replace(/[^0-9]/g, '');
event.target.value = addrArray.value[index];
addrResult.value = addrArray.value.join('.');
ctx.emit('input', addrResult.value);
};
const setWrap = () => {
const obj: any = {};
obj['is-disabled'] = !props.available;
return obj;
};
function guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
const setGroup = () => {
const obj: any = {};
obj[`${groupId.value}`] = true;
return obj;
};
return {
addrArray,
limitCharacter,
nextFocus, lastFocus,
blur1,
setWrap, setGroup,
};
},
};
</script>
<style scoped lang="scss">
.point {
text-align: center;
width: 10px;
}
.is-valid {
border-color: #F56C6C;
-webkit-animation: mymove 2s infinite; /* Chrome, Safari, Opera */
animation: mymove 2s infinite;
}
/* Chrome, Safari, Opera */
@-webkit-keyframes chcolor {
50% {
border-color: #F56C6C;
}
}
/* Standard syntax */
@keyframes chcolor {
50% {
border-color: #F56C6C;
}
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button{
-webkit-appearance: none !important;
margin: 0;
}
</style>
<template>
<div class="out">
<i class="iconfont icon-404"></i>
<div class="info">{{ $route.params.msg === undefined?'当前页面找不到':$route.params.msg }}</div>
<br />
<el-button type="primary" @click="$router.back()">返 回</el-button>
<el-button type="primary" @click="logout()" style="margin-left: 10px">返回至登录页</el-button>
</div>
</template>
<script>
export default {
name: 'page404',
methods: {
logout() {
this.$store.commit('removeToken');
this.$router.push({name: 'login'});
},
},
};
</script>
<style scoped lang="scss">
.out{
text-align: center;
padding: 70px 0;
}
img{
height: 200px;
margin-bottom: 10px;
}
i{
color: $active-text;
font-size: 16rem;
}
.info{
color: $active-text;
margin-bottom: 10px;
font-size: 1.5rem;
}
</style>
import {postService} from 'web-toolkit/src/case-main/index';
import {Province} from '@/types/beans';
import {postService} from 'web-toolkit/src/case-main/index';
export const Login = async (param: any) => {
// const { data } = await postService('/rest/user/login', param);
// 无接口时的模拟数据
const data = {
user: {
id: 1,
username: 'test',
name: 'test',
role: {
id: 1,
department: {
id: 1,
},
},
phone: '',
extend: {},
},
token: 'test',
};
return data;
};
// export const LoginOut = async () => {
// await postService(urlMap.logout.url);
// };
//
// export const UserUpdatePwd = async (params: any) => {
// await postService(urlMap.pwd_update.url, params);
// };
//
// export const UserUpdateInfo = async (params: any) => {
// await postService(urlMap.user_update_info.url, params);
// };
import Vue from 'vue';
import App from './App.vue';
// 加载所用组件,含core
import './plugin';
import { axiosIntercept, routeIntercept, buildMenu} from 'web-toolkit/src/case-main';
// 主菜单
export const mainMenuTitles = [
// 如果没有子导航,直接在这指定CName一样的值
'首页', 'icon-monitor',
'实时监控', 'icon-dashboard',
'报警提醒', 'icon-dashboard',
];
export const loginTitle1 = process.env.VUE_APP_LOGIN_TITLE1;
export const loginTitle2 = process.env.VUE_APP_LOGIN_TITLE2;
export const loginLogo = process.env.VUE_APP_LOGIN_LG;
export const titleLogo = process.env.VUE_APP_TITLE_LG;
export const schema = process.env.VUE_APP_LOGIN_SCHEMA;
import './scss/common.scss';
import { routes } from './router/routes';
import { genRouter } from 'web-toolkit/src/case-main/router';
export const router = genRouter(routes);
buildMenu(routes, mainMenuTitles);
routeIntercept(router);
axiosIntercept(router);
const vm = new Vue({
router,
render: (h) => h(App),
});
// 可用于延迟加载
vm.$mount('#app');
import 'echarts/lib/chart/bar';
import 'echarts/lib/chart/pie';
import 'echarts/lib/chart/custom';
import 'echarts/lib/chart/line';
import 'echarts/lib/chart/scatter';
import 'echarts/lib/component/title';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/dataZoom';
import 'echarts/lib/component/toolbox';
import 'echarts/lib/component/legend';
import 'echarts/lib/component/visualMap';
// import 'echarts/lib/component/markLine';
// import 'echarts/lib/component/markPoint';
// 注意放第一个
import './web-toolkit';
import './echarts';
import Vue from 'vue';
// scss
import 'web-toolkit/src/scss/common.scss';
import 'web-toolkit/src/scss/vivify.scss';
// 注意加载顺序
import 'web-toolkit/src/plugins';
import 'web-toolkit/src/case-main';
import 'web-toolkit/src/filter/date-time';
// components
import lktTable from 'web-toolkit/src/components/kit-table.vue';
Vue.component('lkt-table', lktTable);
import LktDatePicker from 'web-toolkit/src/components/kit-date-picker.vue';
Vue.component('lkt-date-picker', LktDatePicker);
import KitDialogSimple from 'web-toolkit/src/components/kit-dialog-simple.vue';
Vue.component('kit-dialog-simple', KitDialogSimple);
import KitErrChannel from 'web-toolkit/src/components/kit-err-channel.vue';
Vue.component('kit-err-channel', KitErrChannel);
import { PRIVILEGE } from '@/types/privilege';
const home = {
path: '/home',
name: 'index-page',
component: () => import('../views/home/home.vue'),
meta: {
// privileges: [PRIVILEGE.USER_MNG, PRIVILEGE.USER_LIST],
CName: '首页',
},
};
const MonitorState = {
path: '/MonitorState',
name: 'MonitorState',
component: () => import('../views/MonitorState/MonitorState.vue'),
meta: {
CName: '监控状态',
parentCName: '实时监控',
},
};
const detail = {
path: '/detail',
name: 'detail',
component: () => import('../views/detail/detail.vue'),
meta: {
CName: '参数详情',
parentCName: '实时监控',
},
};
const AlarmRecord = {
path: '/AlarmRecord',
name: 'AlarmRecord',
component: () => import('../views/AlarmRecord/AlarmRecord.vue'),
meta: {
CName: '报警记录',
parentCName: '报警提醒',
},
};
const alarm = {
path: '/alarm',
name: 'alarm',
component: () => import('../views/alarm/alarm.vue'),
meta: {
CName: '巡检提醒',
parentCName: '报警提醒',
},
};
const delay = {
path: '/delay',
name: 'delay',
component: () => import('../views/delay/delay.vue'),
meta: {
CName: '巡检延误提醒',
parentCName: '报警提醒',
},
};
// 按顺序 用于菜单的排列
const indexChildren = [
home,
MonitorState,
detail,
AlarmRecord,
alarm,
delay,
];
export const routes = [
{
path: '/login',
name: 'login',
component: () => import('../views/login.vue'),
meta: { authDisabled: true },
},
{
path: '/',
name: 'index',
redirect: 'index-page',
component: () => import('../views/main/index.vue'),
children: [
...indexChildren,
{
path: '*',
name: '404_child',
component: () => import('../component/page404.vue'),
meta: { authDisabled: true },
},
],
},
{
path: '*',
name: '404',
component: () => import('../component/page404.vue'),
meta: { authDisabled: true },
},
];
.router-link {
color: #0ae;
text-decoration: none;
font-size: 1rem;
&:hover {
text-decoration: underline;
}
}
.full-screen {
position: fixed;
z-index: 2000;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.card {
box-shadow: 0 0 5px 0 rgba(0,0,0,.2);
border: 1px solid #EBEEF5;
background-color: #fff;
border-radius: 5px;
color: #303133;
&.card__transition {
transition: .3s;
}
}
.card-header {
padding: 10px 20px;
line-height: 1;
font-size: 1.1rem;
}
.card-body {
padding: 10px 20px;
}
.no-data {
width: 100%;
margin-top: 10rem;
color: #b0bebf;
font-weight: bold;
font-size: 3rem;
text-align: center;
}
.lkt-select--all {
padding: 5px 20px;
}
.main {
height: 100%;
box-sizing: border-box;
}
.el-card__header {
padding: 5px 20px;
}
.el-button + .el-button {
margin-left: 0;
}
.little-space > * {
margin: 5px!important;
&:first-child:not(.align) {
margin-left: 0 !important;
}
}
.el-table {
//border: 1px solid #d9d9d9;
color: rgba(0,0,0,.65);
thead{
color: rgba(0,0,0,.68);
}
}
.lkt-message {
padding: 15px 30px;
i {
font-size: 1.7rem;
}
> * {
font-size: 1.2rem;
}
}
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
declare module '*.vue' {
global {
class QWebChannel {
[index: string]: any;
constructor(transport: any, cb: (channel: QWebChannel) => any);
}
namespace qt {
const webChannelTransport: any;
}
// const bridge: any;
namespace AMap {
function plugin(name: string, cb: () => any): void;
type Status = 'complete' | 'no_data';
class EventEmitter {
on(event: string, handler: (e: any) => any): void;
}
class Map extends EventEmitter {
constructor(id: string, opts?: {
resizeEnable?: boolean;
zoom?: number;
center?: LngLat;
});
add(elm: any): void;
remove(elm: any): void;
getZoom(): number;
getCenter(): LngLat;
setFitView(elm: any): void;
setFeatures(features: string[]): void;
}
class Geocoder {
constructor(opts?: {
city?: string;
radius?: number;
});
getAddress(
lngLat: LngLat,
cb: (status: Status, result: any) => any,
): void;
getLocation(
address: string,
cb: (status: Status, result: any) => any,
): void;
}
export class DistrictSearch {
constructor(opts?: {
subdistrict?: number;
extensions?: string;
level?: string;
});
setLevel(level: string): void;
search(value: string, cb: (status: Status, result: any) => any): void;
}
export namespace DistrictLayer {
class Province {
constructor(opts: {
zIndex?: number;
adcode?: number[];
depth?: number;
styles?: {
'fill'?: string;
'province-stroke'?: string;
'city-stroke'?: string;
'county-stroke'?: string;
};
});
setMap(map: Map | null): void;
}
}
type LngLat = [number, number];
type Anchor = 'top-left' | 'top-center' | 'top-right' | 'middle-left' | 'center' | 'middle-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
class InfoWindow {
constructor(opts: {
content?: string | HTMLElement;
anchor?: Anchor;
offset?: Pixel;
position?: LngLat;
});
getIsOpen(): boolean;
open(map: Map, position?: LngLat): void;
close(): void;
setAnchor(anchor: Anchor): void;
setContent(content: string | HTMLElement): void;
setOffset(offset: Pixel): void;
setPosition(position: LngLat): void;
setSize(size: number[]): void;
}
interface LiveWeatherData {
city: string;
weather: string;
temperature: string; // 温度
windDirection: string; // 风向
windPower: string; // 风力
humidity: string; // 湿度
reportTime: string; // 发布时间
}
class Weather {
getLive(district: string, cb: (err: Error | null, data: LiveWeatherData) => void): void;
}
class Polygon {
constructor(opts: {
strokeWeight?: number;
path?: number[];
fillOpacity?: number;
fillColor?: string;
strokeColor?: string;
});
}
class Pixel {
x: number;
y: number;
constructor(x: number, y: number);
}
class Marker extends EventEmitter {
constructor(opts?: {
map?: Map;
icon?: string | Icon;
position?: LngLat;
offset?: Pixel;
anchor?: Anchor;
});
setPosition(lngLat: LngLat): void;
setMap(map: Map): void;
setOffset(offset: Pixel): void;
setAnchor(anchor: Anchor): void;
setContent(content: string | HTMLElement): void;
}
class Size {
constructor(width: number, height: number);
}
class Icon {
constructor(opts?: {
image: string;
size?: Size;
imageOffset?: Pixel;
imageSize?: Size;
});
}
}
}
import Vue from 'vue';
export default Vue;
}
import { IDepartment, IRole, IUser } from 'web-toolkit/src/case-main/types/beans';
export * from 'web-toolkit/src/case-main/types/beans';
export interface IAlarmMsg {
id: string;
deviceType: string;
type: string;
msg: string;
}
export interface IAlarmNoticeUser {
id: number;
name: string;
phone: string;
off: boolean;
createDt: string;
extend: Record<string, any>;
}
export interface IAlarmRule {
id: string;
title: string;
type: string;
description: string;
rules: object;
noticeUserIds: number[];
noticeUsers: IAlarmNoticeUser[];
off: boolean;
}
export interface IBaseClock {
device: IDevice;
part: IProductPart;
clock: number;
extend: Record<string, any>;
createDt: string;
}
export interface ICallRecord {
id: number;
fromUser: IUser;
toUser: IUser;
type: ICallType;
extend: Record<string, any>;
status: number;
createDt: string;
}
export interface ICallType {
id: number;
name: string;
extend: Record<string, any>;
}
export interface IClockAnalysisDaily {
deviceId: string;
device: IDevice;
data: object;
dt: string;
startDt: string;
endDt: string;
createDt: string;
}
export interface IClockRecord {
id: number;
device: IDevice;
dt: string;
duration: number;
durationWork: number;
extend: Record<string, any>;
createDt: string;
}
export interface ICollector {
id: number;
ip: string;
no: string;
mac: string;
pwd: string;
createDt: string;
off: boolean;
extend: Record<string, any>;
}
export interface ICollectorWarn {
id: number;
collector: ICollector;
info: string;
createDt: string;
}
export interface IDepartmentRelation {
department: IDepartment;
users: number[];
products: number[];
callUsers: number[];
userList: IUser[];
productList: IProduct[];
callUserList: IUser[];
}
export interface IDevice {
id: string;
collector: ICollector;
name: string;
type: string;
createDt: string;
off: boolean;
extend: Record<string, any>;
deviceType: IDeviceType;
}
export interface IDeviceAlarmRecord {
id: number;
device: IDevice;
createDt: string;
type: string;
no: string;
msg: string;
duration: number;
extend: Record<string, any>;
deviceId: string;
category: string;
}
export interface IDeviceMaintenance {
id: number;
device: IDevice;
operator: string;
description: string;
position: string;
reason: string;
occurDt: string;
treatment: string;
restorationDt: string;
extend: Record<string, any>;
createDt: string;
}
export interface IDeviceType {
id: string;
name: string;
img: string;
extend: Record<string, any>;
}
export interface IDeviceValue {
id: number;
device: IDevice;
createDt: string;
dt: string;
type: string;
data: object;
}
export interface IDeviceValueAlarmsDTO {
id: number;
alarms: object[];
createDt: string;
}
export interface IDeviceWorkStatusRecord {
id: number;
device: IDevice;
dt: string;
status: string;
duration: number;
extend: Record<string, any>;
createDt: string;
}
export interface IEmpAttendance {
id: number;
employee: IUser;
dt: string;
extend: Record<string, any>;
}
export interface IFactorySetting {
id: number;
name: string;
workshopName: string;
workshopImg: string;
workshopImgApp: string;
company: object;
}
export interface ILine {
id: string;
name: string;
createDt: string;
extend: Record<string, any>;
off: boolean;
}
export interface ILineDeviceConfig {
device: IDevice;
line: ILine;
stageId: number;
stageName: string;
}
export interface ILineProductRecord {
id: number;
no: string;
line: ILine;
product: IProduct;
startDt: string;
endDt: string;
extend: Record<string, any>;
createDt: string;
}
export interface ILineRelation {
line: ILine;
users: number[];
products: object[];
callUsers: number[];
shifts: number[];
userList: IUser[];
shiftList: IShiftSetting[];
callUserList: IUser[];
}
export interface ILineStatusRecord {
id: number;
line: ILine;
dt: string;
status: string;
duration: number;
extend: Record<string, any>;
createDt: string;
}
export interface ILineWorkOrder {
id: number;
plan: IProductionPlan;
no: string;
product: IProduct;
line: ILine;
shift: IShiftSetting;
startDt: string;
endDt: string;
status: number;
extend: Record<string, any>;
createDt: string;
}
export interface ILogisticsRecord {
id: number;
product: IProduct;
device: IDevice;
no: string;
plan: IProductionPlan;
operator: IUser;
address: string;
extend: Record<string, any>;
createDt: string;
}
export interface IMaterial {
id: number;
no: string;
name: string;
content: string;
extend: Record<string, any>;
off: boolean;
createDt: string;
}
export interface IMaterialForm {
id: number;
plan: IProductionPlan;
no: string;
name: string;
extend: Record<string, any>;
off: boolean;
createDt: string;
materialList: IMaterial[];
}
export interface IMonitorGraph {
id: number;
type: string;
device: IDevice;
style: object;
}
export interface IParamConfig {
available: boolean;
id: number;
key: string;
keyFull: string;
modify: boolean;
remoteId: string;
nameSimple: string;
nameFull: string;
ruleMap: object;
showAnalysis: boolean;
showTogether: string[];
unit: string;
influxEx: boolean;
freq: number;
benchmarkMin: number;
benchmarkMax: number;
value: string;
}
export interface IPartDeviceRelation {
device: IDevice;
part: IProductPart;
extend: Record<string, any>;
}
export interface IPartOptRecord {
id: number;
no: string;
part: IProductPart;
product: IProduct;
device: IDevice;
plan: IProductionPlan;
operator: IUser;
startDt: string;
endDt: string;
duration: number;
extend: Record<string, any>;
createDt: string;
}
export interface IProduceSetting {
id: number;
startTimeInDay: string;
endTimeInDay: string;
shifts: string;
shiftsList: string[][];
}
export interface IProduct {
id: number;
no: string;
name: string;
description: string;
process: IProductProcess;
extend: Record<string, any>;
off: boolean;
createDt: string;
}
export interface IProductionPlan {
id: number;
product: IProduct;
no: string;
name: string;
startDt: string;
endDt: string;
status: number;
extend: Record<string, any>;
off: boolean;
createDt: string;
}
export interface IProductOrder {
id: number;
no: string;
name: string;
content: string;
startDt: string;
endDt: string;
status: number;
target: object;
extend: Record<string, any>;
createDt: string;
off: number;
}
export interface IProductPart {
id: number;
process: IProductProcess;
no: string;
name: string;
content: string;
sort: number;
extend: Record<string, any>;
off: boolean;
createDt: string;
deviceList: IDevice[];
}
export interface IProductProcess {
id: number;
no: string;
name: string;
content: string;
extend: Record<string, any>;
off: boolean;
createDt: string;
partList: IProductPart[];
}
export interface IProductWasteReason {
id: number;
name: string;
off: boolean;
extend: Record<string, any>;
}
export interface IProductWasteReasonGroup {
id: number;
name: string;
reasons: number[];
products: number[];
reasonList: IUser[];
productList: IProduct[];
extend: Record<string, any>;
}
export interface IQualityManualRecord {
id: number;
no: string;
plan: IProductionPlan;
product: IProduct;
device: IDevice;
part: IProductPart;
operator: IUser;
dt: string;
createDt: string;
extend: Record<string, any>;
line: ILine;
startDt: string;
endDt: string;
}
export interface IQualityRecord {
id: number;
device: IDevice;
product: IProduct;
operator: IUser;
category: string;
reason: string;
dt: string;
extend: Record<string, any>;
line: ILine;
}
export interface IShiftSetting {
id: number;
name: string;
startTime: string;
endTime: string;
start: string;
end: string;
}
export interface IStationConfig {
id: string;
name: string;
mac: string;
config: Record<string, any>;
dt: string;
}
export interface Administration {
code: string;
name: string;
}
export interface Province extends Administration {
cities: Administration[];
}
export interface IROMSCustomer {
id: number;
name: string;
tel: string;
province: Province;
city: Administration;
area: Administration;
address: string;
extend: Record<string, any>;
createDt: string;
off: boolean;
}
export interface IStaffAreaRelation {
id: number;
staff: IUser;
province: Province;
city: Administration;
area: Administration;
}
export interface IROMSMaintenOrderResult {
id: number;
name: string;
}
export interface IROMSMaintenMaterial {
id: number;
no: string;
name: string;
usage?: string;
}
export interface IROMSMaintenOrder {
id: number;
no: string;
customer: IROMSCustomer;
devices: string[];
staff: IUser;
content: string;
address: string;
dt: string | Date;
startDt: string | Date;
completeDt: string | Date;
feedback: string;
materials: IROMSMaintenMaterial[];
pics: string[];
result: string;
score: number;
scoreContent: string;
createDt: string;
off: boolean;
extend: Record<string, any>;
deviceList: IDevice[];
}
import Vue from 'vue';
interface Result { valid: boolean; message: string; }
export interface Filter extends Vue {
conditions: Record<string, string>;
validate(): Result;
load(): Promise<void>;
selectDevice(deviceId: string, customerId?: number): void;
}
export const PRIVILEGE = {
USER_LIST : 'userList',
USER_MNG : 'userMng',
ROLE_MNG : 'roleMng',
DEVICE_MONITOR : 'deviceMonitor',
PRODUCT_LIST : 'productList',
PRODUCT_MNG : 'productMng',
PLAN_LIST : 'planList',
PLAN_MNG : 'planMng',
QUALITY_LIST : 'qualityList',
QUALITY_ADD : 'qualityAdd',
QUALITY_MNG : 'qualityMng',
CALL_RECORD_LIST : 'callRecordList',
CALL_MNG : 'callMng',
// 质保提醒管理
QUALITY_DT_MNG: 'qualityDtMng',
// 远程协助-参数
// REMOTE_PARAM: 'remoteParam',
// 远程协助-程序
// REMOTE_PROGRAM: 'remoteProgram',
REMOTE: 'remote',
// 派单查询
MAINTENT_ORDER_LIST: 'maintenOrderList',
// 派单管理
MAINTENT_ORDER_MNG: 'maintenOrderMng',
// 采集参数配置
COLLECT_PARAMS_MNG: 'collectParamsMng',
// 维护人员管理
MAINTENT_STAFF_MNG: 'maintenStaffMng',
// 消耗物料管理
MAINTENT_MATERIAL_MNG: 'maintenMaterialMng',
// 派单结果管理
MAINTENT_ORDER_RESULT_MNG: 'maintenOrderResultMng',
// 客户资料管理
CUSTOMER_MNG: 'customerMng',
DEVICE_LIST : 'deviceList',
DEVICE_MNG : 'deviceMng',
// 边缘网关配置
ADAPTER_DEVICE_MNG: 'AdapterDeviceMng',
EMP_LIST : 'empList',
EMP_MNG : 'empMng',
PART_OPT_RECORD_LIST : 'partOptRecordList',
PART_OPT_RECORD_MNG : 'partOptRecordMng',
DEVICE_ANALYSIS : 'deviceAnalysis',
DEPARTMENT_MNG : 'departmentMng',
PRODUCE_SETTING : 'produceSetting',
ANALYSIS_SETTING : 'analysisSetting',
ALARM_RULE_SETTING : 'alarmRuleSetting',
EMP_REPORT_WORK : 'empReportWork',
STATION_SETTING : 'stationSetting',
DEV : 'dev',
// 临时权限: 工单模式
MODE_ORDER: 'mode_order',
MODE_DEVICE: 'mode_device',
};
export default PRIVILEGE;
import {debounce, isNil, deepClone} from 'web-toolkit/src/utils';
export const isProvinceZoom = (zoom: number) => {
return zoom > 3 && zoom < 8;
};
export const isCityZoom = (zoom: number) => {
return zoom >= 8 && zoom < 11;
};
export const getDistrictLevel = (zoom: number) => {
if (zoom < 8) {
return 'province';
} else if (zoom >= 8 && zoom < 9) {
return 'city';
} else {
return 'district';
}
};
let infoWindow: AMap.InfoWindow;
export function setInfoWindow(opts: {
map: AMap.Map;
content: string | HTMLElement;
anchor?: AMap.Anchor;
offset?: AMap.Pixel;
position?: AMap.LngLat;
}) {
if (!infoWindow) {
infoWindow = new AMap.InfoWindow(opts);
} else {
infoWindow.setContent(opts.content);
opts.anchor && infoWindow.setAnchor(opts.anchor);
opts.offset && infoWindow.setOffset(opts.offset);
opts.position && infoWindow.setPosition(opts.position);
}
infoWindow.open(opts.map);
}
const weather = new AMap.Weather();
export const getLiveWeather = async (district: string) => {
return new Promise((resolve) => {
weather.getLive(district, (err, data) => {
resolve(err ? undefined : data);
});
});
};
let marker: AMap.Marker;
export const mark = async (lnglat: AMap.LngLat, map: AMap.Map) => {
if (!marker) {
marker = new AMap.Marker();
}
marker.setPosition(lnglat);
marker.setMap(map);
};
const geocoder = new AMap.Geocoder();
export const getAddress = async (lnglat: AMap.LngLat) => {
return new Promise<any>((resolve) => {
geocoder.getAddress(lnglat, (status, result) => {
if (status === 'complete' && result.regeocode) {
resolve(result.regeocode);
} else {
resolve();
}
});
});
};
export const getLocation = async (address: string) => {
return new Promise<any>((resolve) => {
geocoder.getLocation(address, (status, result) => {
if (status === 'complete' && result.geocodes.length) {
resolve(result.geocodes);
} else {
resolve();
}
});
});
};
const districtSearch = new AMap.DistrictSearch({
level: 'province',
extensions: 'all',
subdistrict: 0,
});
export const getDistrictBounds = (level: 'province' | 'city' | 'district', value: string) => {
return new Promise<{ bounds: number[][], name: string }>((resolve) => {
districtSearch.setLevel(level);
districtSearch.search(value, (status, result) => {
if (status === 'complete' && result.districtList && result.districtList[0]) {
resolve({
bounds: result.districtList[0].boundaries,
name: result.districtList[0].name,
});
} else {
resolve({
bounds: [],
name: '',
});
}
});
});
};
let polygons: AMap.Polygon[];
let districtName: string;
export const highLightDistrict = (name: string, bounds: number[][], map: AMap.Map) => {
if (districtName === name) {
return;
}
districtName = name;
if (polygons) {
map.remove(polygons);
}
polygons = bounds.map((bound) => new AMap.Polygon({
strokeWeight: 1,
path: bound,
fillOpacity: 0.4,
fillColor: '#80d8ff',
strokeColor: '#0091ea',
}));
map.add(polygons);
};
import {IDevice} from '@/types/beans';
export const changeXY = (deviceList: IDevice[]) => {
let x = 0;
let y = 0;
deviceList.sort( function( a: IDevice, b: IDevice) {
if (isNil(a.extend.lon) || isNil(b.extend.lon)) { return 0; }
return (a.extend.lon - b.extend.lon);
});
for (const device of deviceList) {
if (isNil(device.extend.lon) || isNil(device.extend.lat)) { continue; }
if (device.extend.lon === x && device.extend.lat === y) {
device.extend.lon = parseFloat((0.0005 * Math.random()).toFixed(6)) + device.extend.lon;
device.extend.lat = parseFloat((0.0005 * Math.random()).toFixed(6)) + device.extend.lat;
} else {
x = device.extend.lon;
y = device.extend.lat;
}
}
return deviceList;
};
interface StatusMap {
[key: string]: {
arrName: string;
color: string;
tag: string;
};
}
const $statusMap: StatusMap = {
mdc_offline: {
arrName: 'MDC离线',
color: '#ff4949',
tag: 'danger',
},
offline: {
arrName: '离线',
color: '#3d3d3d',
tag: 'info',
},
close: {
arrName: '关机',
color: '#8e8e8e',
tag: 'info',
},
idle: {
arrName: '空闲',
color: '#d7d400',
tag: 'warning',
},
working: {
arrName: '运行',
color: '#26b229',
tag: 'success',
},
run_gap: {
arrName: '加工间隔',
color: '#9add6f',
tag: 'success',
},
editing: {
arrName: '设置',
color: '#1082ff',
tag: 'primary',
},
emergency: {
arrName: '急停',
color: '#ff4949',
tag: 'danger',
},
pause: {
arrName: '暂停',
color: '#00b9ff',
tag: 'success',
},
overhaul: {
arrName: '维护',
color: '#ff9b00',
tag: 'warning',
},
collect_err: {
arrName: '采集异常',
color: '#ff4949',
tag: 'danger',
},
debug: {
arrName: '手动',
color: '#00b9ff',
tag: 'primary',
},
};
/**
* 一个map对象, 根据status获取对应的arrName, color, tag
* @example statusMap(some_status)
*/
export const statusMap = (status: string) => {
const obj = $statusMap[status];
return obj || $statusMap.offline;
};
/**
* 判断一个状态是否属于正常的状态
* @param status
*/
export function isNormal(status: string) {
const normalStatus = ['working', 'run_gap', 'pause', 'debug', 'idle', 'editing'];
return normalStatus.includes(status);
}
/**
* 判断一个状态是否属于不正常的状态
* @param status
*/
export function isAbnormal(status: string) {
const abnormalStatus = ['emergency', 'collect_err'];
return abnormalStatus.includes(status);
}
/**
* 判断一个状态是否属于离线状态
* @param status
*/
export function isOffline(status: string) {
const offlineStatus = ['close', 'offline', 'overhaul'];
return offlineStatus.includes(status);
}
/**
* 将提供的时间数据填充进日期对象
* @param dt 日期对象
* @param base 填充的时间数据
*/
export function fillBaseTime(dt: Date, base: any = {
hh: 0,
mm: 0,
ss: 0,
}) {
dt.setHours(base.hh);
dt.setMinutes(base.mm);
dt.setSeconds(base.ss);
dt.setMilliseconds(0);
}
/**
* 用于默认的时间范围, 若提供的开始时间晚于当前时间则将开始日期提前一天
*/
export function getDefaultDatetimePickerRanger(startTime?: any) {
const startBase = new Date();
fillBaseTime(startBase, startTime);
let ret: Date[] = [];
const end = new Date();
const start = new Date();
if (start.getTime() < startBase.getTime()) {
start.setDate(start.getDate() - 1);
}
fillBaseTime(start, startTime);
ret = [start, end];
return ret;
}
/**
* 根据oee返回对应的状态
* @param num oee数值
*/
export function oeeProgressStatus(num: number) {
if (num > 80) {
return 'success';
} else if (num < 40) {
return 'exception';
} else {
return undefined;
}
}
/**
* 根据oee返回对应的颜色值
* @param num oee数值
*/
export function oeeProgressColor(num: number) {
if (num > 80) {
return '#26b229';
} else if (num < 40) {
return '#FF4949';
} else {
return '#00afff';
}
}
/**
* 一个对象, 用于获取全局的echart样式
* todo 用echarts-helper中的getColor
*/
export const echartStyle = {
titleColor: '#ffffff',
textColor: 'white',
contentColor: '#3398DB',
};
export type AnyFunction = (...args: any[]) => any;
export const debounce = (fn: AnyFunction, freq: number = 300): AnyFunction => {
let timer = 0;
const dFn: () => void = function(this: any) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, [...arguments]);
}, freq);
};
return dFn;
};
export const offsetWindow = (elm: HTMLElement) => {
const offsetParent = elm.offsetParent;
let offsetLeft = elm.offsetLeft;
let offsetTop = elm.offsetTop;
if (offsetParent) {
const offset = offsetWindow(offsetParent as HTMLElement);
offsetLeft += offset.left;
offsetTop += offset.top;
}
return {
left: offsetLeft,
top: offsetTop,
};
};
export const transformMiiliseconds = (milliseconds: number) => {
const oneHour = 3600000;
const oneMinute = 60000;
const oneSecond = 1000;
const hours = Math.floor(milliseconds / oneHour);
milliseconds %= oneHour;
const minutes = Math.floor(milliseconds / oneMinute);
milliseconds %= oneMinute;
const seconds = Math.floor(milliseconds / oneSecond);
return `${hours}:${minutes}:${seconds}`;
};
<template>
<div v-loading="loading">
<el-container>
<el-header>
<el-row class="row-bg" :gutter="35">
<el-col :span="4">
<div class="grid-content bg-blue">设备总数</div>
<div class="grid-content bg-blue big">4545台</div>
</el-col>
<el-col :span="4">
<div class="grid-content bg-green">正常</div>
<div class="grid-content bg-green big">3621台</div>
</el-col>
<el-col :span="4">
<div class="grid-content bg-orange">报警</div>
<div class="grid-content bg-orange big">273台</div>
</el-col>
<el-col :span="4">
<div class="grid-content bg-red">故障</div>
<div class="grid-content bg-red big">432台</div>
</el-col>
<el-col :span="4">
<div class="grid-content bg-grey">通讯中断</div>
<div class="grid-content bg-grey big">422台</div>
</el-col>
</el-row>
</el-header>
<el-main class="list">
<div class="list-first">
<el-row :gutter="20">
<el-col :span="6">
<div class="grid-content1">设备列表</div>
</el-col>
<el-col :span="6" :offset="12">
<div class="grid-content1">
<el-input placeholder="请输入内容/编号" suffix-icon="el-icon-search" v-model="search" ></el-input>
</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<div class="grid-content2">
设备状态:
<el-select size="mini" v-model="value1" multiple placeholder="请选择">
<el-option
v-for="item in states"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="grid-content2">
设备型号:
<el-select size="mini" v-model="value2" multiple placeholder="请选择">
<el-option
v-for="item in models"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="grid-content2">
设备选择:
<el-select size="mini" v-model="value3" multiple placeholder="请选择">
<el-option
v-for="item in equipments"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="grid-content2">
<el-button type="primary" class="bu" size="mini">搜索</el-button>
<el-button size="mini">重置</el-button>
</div>
</el-col>
</el-row>
<el-row>
<el-table
ref="multipleTable"
:data="tableData.filter(data => !search || data.state.toLowerCase().includes(search.toLowerCase())||data.number.toLowerCase().includes(search.toLowerCase()))"
tooltip-effect="dark"
style="width: 100% "
@selection-change="handleSelectionChange"
>
<el-table-column align="center" type="selection" width="50"></el-table-column>
<el-table-column align="center" label="设备状态" width="200">
<template slot-scope="scope">
<div v-if="scope.row.state==='正常'">
<el-tag :type="'success'">{{scope.row.state}}</el-tag>
</div>
<div v-else-if="scope.row.state=='报警'">
<el-tag :type="'warning'">{{scope.row.state}}</el-tag>
</div>
<div v-else-if="scope.row.state=='故障'">
<el-tag :type="'danger'">{{scope.row.state}}</el-tag>
</div>
<div v-else>
<el-tag :type="'info'">{{scope.row.state}}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column align="center" label="设备编号" width="200">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column align="center" label="设备型号" width="200">
<template slot-scope="scope">{{ scope.row.model }}</template>
</el-table-column>
<el-table-column align="center" label="设备位置" width="200">
<template slot-scope="scope">{{ scope.row.location }}</template>
</el-table-column>
<el-table-column align="center" label="检测区域" width="200">
<template slot-scope="scope">{{ scope.row.area }}</template>
</el-table-column>
<el-table-column align="center" label="操作" width="150">
<template slot-scope="scope">
<el-button @click="detail(scope.row)" type="text" size="small">参数详情</el-button>
</template>
</el-table-column>
</el-table>
</el-row>
</div>
</el-main>
</el-container>
</div>
</template>
<script lang="ts">
import { ref, onMounted } from "@vue/composition-api";
import { router } from "../../main";
export default {
setup() {
const tableData=[
{
state: "正常",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "正常",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "故障",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "正常",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "通讯中断",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "正常",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "正常",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
},
{
state: "报警",
number: "DLQ423",
model: "LTY-1",
location: "杭州市西湖区",
area: "杭州市西湖区古荡湾",
collector: "LKT001"
}
]
const equipments=[
{
value: "选项1",
label: "断路器1"
},
{
value: "选项2",
label: "断路器2"
},
{
value: "选项3",
label: "断路器3"
},
{
value: "选项4",
label: "断路器4"
}
]
const models= [
{
value: "选项1",
label: "型号1"
},
{
value: "选项2",
label: "型号2"
},
{
value: "选项3",
label: "型号3"
},
{
value: "选项4",
label: "型号4"
}
]
const states=[
{
value: "选项1",
label: "正常"
},
{
value: "选项2",
label: "报警"
},
{
value: "选项3",
label: "故障"
},
{
value: "选项4",
label: "通讯中断"
}
]
function detail() {
router.push({ name: "demo3" });
}
const loading = ref<boolean>(false);
const value1 = ref<any>([]);
const value2= ref<any>([]);
const value3= ref<any>([]);
const multipleSelection= ref<any>([]);
return {
loading,
search: "",
tableData,
detail,
states,
value1,
models,
value2,
equipments,
value3,
multipleSelection
};
}
};
</script>
<style lang="scss">
.bu {
margin-right: 10px;
margin-left: 50px;
}
.grid-content {
text-align: center;
line-height: 30px;
}
.grid-content1 {
font-weight: bolder;
font-size: medium;
line-height: center;
}
.bg-blue {
color: blue;
}
.el-row {
margin-bottom: 10px;
}
.bg-green {
color: green;
}
.bg-orange {
color: orange;
}
.bg-red {
color: red;
}
.bg-grey {
color: grey;
}
.big {
font-size: large;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.list {
background: white;
margin-top: 3%;
}
</style>
<template>
<div v-loading="loading">
<el-container>
<el-header style="margin-bottom:3%;background:white">
<div class="list-first" style="background:white">
<el-row :gutter="20">
<el-col :span="6">
<div class="content">巡检提醒列表</div>
</el-col>
<el-col :span="6" :offset="12">
<div class="content">
<el-input placeholder="请输入内容/编号" suffix-icon="el-icon-search" v-model="search" ></el-input>
</div>
</el-col>
</el-row>
<el-row >
<el-col :span="3"><div class="content1">提前提醒时间:</div></el-col>
<el-col :span="5" ><div >
<el-input-number v-model="num" @change="handleChange" :min="1" label="天">
</el-input-number><span class="content2"></span></div></el-col>
<el-col :span="2"><div class="content3"><el-button @click="see(scope.row)" type="primary" size="small">查询</el-button></div></el-col>
</el-row>
</div>
</el-header>
<el-main>
<el-table
ref="multipleTable"
:data="tableData.filter(data => !search || data.frequency.toLowerCase().includes(search.toLowerCase())||data.number.toLowerCase().includes(search.toLowerCase()))"
tooltip-effect="dark"
style="width: 100% "
>
<el-table-column align="center" label="设备编号" width="160">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column align="center" label="设备型号" width="160">
<template slot-scope="scope">{{ scope.row.model }}</template>
</el-table-column>
<el-table-column align="center" label="开始时间" width="160">
<template slot-scope="scope">{{ scope.row.start }}</template>
</el-table-column>
<el-table-column align="center" label="结束时间" width="160">
<template slot-scope="scope">{{ scope.row.end }}</template>
</el-table-column>
<el-table-column align="center" label="巡检频率" width="160">
<template slot-scope="scope">{{ scope.row.frequency }}</template>
</el-table-column>
<el-table-column align="center" label="下次巡检时间" width="160">
<template slot-scope="scope">{{ scope.row.next }}</template>
</el-table-column>
<el-table-column align="center" label="巡检员" width="160">
<template slot-scope="scope">{{ scope.row.person }}</template>
</el-table-column>
<el-table-column align="center" label="操作" width="140">
<template slot-scope="scope">
<el-button @click="sure(scope.row)" type="success" size="small">确认/不再提醒</el-button>
</template>
</el-table-column>
</el-table>
</el-main>
<el-footer style="margin:0 auto">
<el-row >
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage1"
:page-sizes="[5, 10, 15, 20]"
:page-size="5"
:total="100"
layout="prev, pager, next,sizes,jumper"
>
</el-pagination>
</el-row>
</el-footer>
</el-container>
</div>
</template>
<script lang="ts">
import { ref, onMounted } from '@vue/composition-api';
export default {
setup() {
function handleCurrentChange(val) {
console.log(`当前页: ${val}`);
}
const tableData=[
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "天",
next:"2019-10-09",
person:"王邹"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "天",
next:"2019-10-09",
person:"王邹"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "年",
next:"2019-10-09",
person:"王邹"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "天",
next:"2019-10-09",
person:"王邹"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "月",
next:"2019-10-09",
person:"王邹"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "年",
next:"2019-10-09",
person:"王邹"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "月",
next:"2019-10-09",
person:"王邹"
},
]
const loading = ref<boolean>(false);
return{
loading,
search: '',
tableData,
currentPage1:1,
handleCurrentChange,
num:1
};
},
};
</script>
<style lang="scss">
.content{font-weight: bold;
font-size: medium;
line-height: center;
padding: 10px}
.content1{ padding: 10px}
.content2{
padding: 20px}
</style>
</style>
\ No newline at end of file
<template>
<div v-loading="loading">
<el-container>
<el-header style="background:white">
<div class="list-first" style="background:white">
<el-row :gutter="20">
<el-col :span="6">
<div class="content">延误巡检列表</div>
</el-col>
<el-col :span="6" :offset="12">
<div class="content">
<el-input
placeholder="请输入内容/编号"
suffix-icon="el-icon-search"
v-model="search"
></el-input>
</div>
</el-col>
</el-row>
</div>
</el-header>
<el-main>
<el-row style="margin-bottom:2%">
<el-col :span="8">
<div class="grid-content2">
选择日期:
<el-date-picker
size="mini"
v-model="value1"
type="daterange"
unlink-panels
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="pickerOptions"
>
</el-date-picker>
</div>
</el-col>
<el-col :span="5">
<div class="grid-content2">
巡检频率:
<el-select
size="mini"
v-model="value2"
multiple
placeholder="请选择"
>
<el-option
v-for="item in frequencys"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</el-col>
<el-col :span="5">
<div class="grid-content2">
巡检员:
<el-select
size="mini"
v-model="value3"
multiple
placeholder="请选择"
>
<el-option
v-for="item in persons"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</div>
</el-col>
<el-col :span="6">
<div class="grid-content2">
<el-button type="primary" class="bu" size="mini">搜索</el-button>
<el-button size="mini">重置</el-button>
</div>
</el-col>
</el-row>
<el-row>
<el-table
ref="multipleTable"
:data="
tableData.filter(
data =>
!search ||
data.frequency.toLowerCase().includes(search.toLowerCase()) ||
data.number.toLowerCase().includes(search.toLowerCase())
)
"
tooltip-effect="dark"
style="width: 100% "
>
<el-table-column align="center" label="设备编号" width="140">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column align="center" label="设备型号" width="140">
<template slot-scope="scope">{{ scope.row.model }}</template>
</el-table-column>
<el-table-column align="center" label="开始时间" width="140">
<template slot-scope="scope">{{ scope.row.start }}</template>
</el-table-column>
<el-table-column align="center" label="结束时间" width="140">
<template slot-scope="scope">{{ scope.row.end }}</template>
</el-table-column>
<el-table-column align="center" label="巡检频率" width="140">
<template slot-scope="scope">{{ scope.row.frequency }}</template>
</el-table-column>
<el-table-column align="center" label="下次巡检时间" width="140">
<template slot-scope="scope">{{ scope.row.next }}</template>
</el-table-column>
<el-table-column align="center" label="巡检员" width="140">
<template slot-scope="scope">{{ scope.row.person }}</template>
</el-table-column>
<el-table-column align="center" label="状态" width="140">
<template slot-scope="scope">
<div v-if="scope.row.state === '正常'">
<el-tag :type="'success'">{{ scope.row.state }}</el-tag>
</div>
<div v-else>
<el-tag :type="'danger'">{{ scope.row.state }}</el-tag>
</div>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="110">
<template slot-scope="scope">
<el-button @click="sure(scope.row)" type="success" size="small"
>查看</el-button
>
</template>
</el-table-column>
</el-table>
</el-row>
</el-main>
<el-footer style="margin:0 auto">
<el-row>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage1"
:page-sizes="[5, 10, 15, 20]"
:page-size="5"
:total="100"
layout="prev, pager, next,sizes,jumper"
>
</el-pagination>
</el-row>
</el-footer>
</el-container>
</div>
</template>
<script lang="ts">
import { ref, onMounted } from "@vue/composition-api";
export default {
setup() {
function handleCurrentChange(val) {
console.log(`当前页: ${val}`);
}
const value1 = ref<any>([]);
const value2 = ref<any>([]);
const value3 = ref<any>([]);
const multipleSelection = ref<any>([]);
const frequencys = [
{
value: "选项1",
label: "天"
},
{
value: "选项2",
label: "周"
},
{
value: "选项3",
label: "月"
},
{
value: "选项4",
label: "年"
}
];
const persons = [
{
value: "选项1",
label: "张三"
},
{
value: "选项2",
label: "李四"
},
{
value: "选项3",
label: "教授"
},
{
value: "选项4",
label: "万正"
}
];
const tableData = [
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "天",
next: "2019-10-09",
person: "王邹",
state: "正常"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "天",
next: "2019-10-09",
person: "王邹",
state: "已延误12天"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "年",
next: "2019-10-09",
person: "王邹",
state: "已延误10天"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "天",
next: "2019-10-09",
person: "王邹",
state: "已延误2天"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "月",
next: "2019-10-09",
person: "王邹",
state: "正常"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "年",
next: "2019-10-09",
person: "王邹",
state: "正常"
},
{
number: "LKT15456",
model: "DL01",
start: "2017-10-10",
end: "2018-07-12",
frequency: "月",
next: "2019-10-09",
person: "王邹",
state: "正常"
}
];
const loading = ref<boolean>(false);
const pickerOptions = {
shortcuts: [
{
text: "最近一周",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近一个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
picker.$emit("pick", [start, end]);
}
},
{
text: "最近三个月",
onClick(picker) {
const end = new Date();
const start = new Date();
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
picker.$emit("pick", [start, end]);
}
}
]
};
return {
loading,
search: "",
tableData,
currentPage1: 1,
handleCurrentChange,
num: 1,
frequencys,
persons,
pickerOptions,
value2,
value1,
value3
};
}
};
</script>
<style lang="scss">
.bu {
margin-right: 10px;
margin-left: 50px;
}
</style>
<template>
<div v-loading="loading">
<el-row>
<el-button type="primary" size="mini">返回</el-button>
</el-row>
<el-container>
<el-aside style="background:white; ;margin-right:15px;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<div style="margin-top:10px;margin-left:10px">
<el-row style="text-align:center;margin-bottom:5% ;font-weight:bold" >BOT0016</el-row>
<el-row >
<el-col :span="10"><div ><img src="../../assets/device.png" alt="" class="device"></div></el-col>
<el-col :span="7" :offset="3"><div>设备型号:</div><div>12</div><div style="margin-top:10px">采集器编号:</div><div>12</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="10"><div>客户地址:</div></el-col>
<el-col :span="10" :offset="2"><div>杭州市江干区</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="10"><div>联系人:</div></el-col>
<el-col :span="10" :offset="2"><div>张三</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="10"><div>联系方式:</div></el-col>
<el-col :span="10" :offset="2"><div>1283948933</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="10"><div>设备位置:</div></el-col>
<el-col :span="10" :offset="2"><div>北楼一区</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="10"><div>监测区域:</div></el-col>
<el-col :span="10" :offset="2"><div>北楼一区</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="10"><div>开机率:</div></el-col>
<el-col :span="10" :offset="2"><div><el-progress :text-inside="true" :stroke-width="24" :percentage="67" status="success"></el-progress></div></el-col>
</el-row>
<el-row style="background:white;margin-top:50px " justify="center"><el-col :span="3" :offset="7"><el-button type="primary" size="mini">运行参数查看</el-button></el-col></el-row>
<el-row style="background:white;margin-top:10px " justify="center"><el-col :span="3" :offset="7"><el-button type="primary" size="mini">运行时间统计</el-button></el-col></el-row>
</div>
</el-aside>
<el-container>
<el-header style="line-height:60px; height:60px; background:white;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<el-row >运行时间:</el-row>
</el-header>
<el-main style="background:white;margin-top:10px ;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<el-row style="background:white;margin-top:10px " justify="center"><el-col :span="3" :offset="8"><el-button type="primary" size="mini">实时参数列表</el-button></el-col><el-col :span="3" ><el-button size="mini">参数曲线监控</el-button></el-col></el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="5"><div>电流:</div></el-col>
<el-col :span="2" :offset="1"><div class="it">8.342342</div></el-col>
<el-col :span="5"><div>温度:</div ></el-col>
<el-col :span="2" :offset="1"><div class="it">8.342342</div></el-col>
<el-col :span="5"><div>断路器状态:</div></el-col>
<el-col :span="2" :offset="1"><div class="it">8.342342</div></el-col>
</el-row>
<el-row style="background:white;margin-top:5% ">
<el-col :span="5"><div>A相电压:</div></el-col>
<el-col :span="2" :offset="1"><div class="it">8.342342</div></el-col>
<el-col :span="5"><div>B相电压:</div ></el-col>
<el-col :span="2" :offset="1"><div class="it">8.342342</div></el-col>
<el-col :span="5"><div>AB相线电流:</div></el-col>
<el-col :span="2" :offset="1"><div class="it">8.342342</div></el-col>
</el-row>
<el-row justify="center" style="margin-top:300px"><el-col :span="3" :offset="8"><el-button type="primary" size="mini">上一页</el-button></el-col><el-col :span="3" ><el-button size="mini">下一页</el-button></el-col></el-row>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script lang="ts">
import { ref, onMounted } from '@vue/composition-api';
export default {
setup() {
const loading = ref<boolean>(false);
return{
loading,
};
},
};
</script>
<style lang="scss">
.it{
color: blue;
font-weight:bold;
text-size-adjust: medium;
}
.device {
height: 60px;
overflow: hidden;
cursor:pointer;
}
</style>
<template>
<div v-loading="loading">
<el-container>
<el-aside style="background:white;width:75% ;margin-right:2%;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<div style="margin-top:10px;margin-left:10px">
<el-row style="text-align:left;margin-bottom:5% ;font-weight:bold;" >设备状态统计实时监测</el-row>
<el-row class="row-bg" >
<el-col :span="4">
<div class="grid-content bg-blue">设备总数</div>
<div class="grid-content bg-blue big">4545台</div>
</el-col>
<el-col :span="4" :offset="1">
<div class="grid-content bg-green">正常</div>
<div class="grid-content bg-green big">3621台</div>
</el-col>
<el-col :span="4" :offset="1">
<div class="grid-content bg-orange">报警</div>
<div class="grid-content bg-orange big">273台</div>
</el-col>
<el-col :span="4" :offset="1">
<div class="grid-content bg-red">故障</div>
<div class="grid-content bg-red big">432台</div>
</el-col>
<el-col :span="4" :offset="1">
<div class="grid-content bg-grey">通讯中断</div>
<div class="grid-content bg-grey big">422台</div>
</el-col>
</el-row>
<el-row >
<el-col ><div ><img src="../../assets/map.png" alt="" class="map"></div></el-col>
</el-row>
</div>
</el-aside>
<el-container>
<el-header style=" height:280px; margin-bottom:5%;background:white;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<el-row style="text-align:left;margin-bottom:5% ;font-weight:bold;" >巡检通知</el-row>
<el-row ><div v-for="(item,i) in infos" class="info" ><el-col :span="1" style=" margin-top:12px;width: 25px;height: 25px;border: 1px solid #314659;color:white;background:#314659;border-radius:50%;text-align:center;line-height:25px">{{item.id}}</el-col>
<el-col :span="0.3" class="infos">{{item.location}}</el-col>
<el-col :span="0.3" class="infos"> <div ><el-button @click="detail(scope.row)" type="text" size="small"><div >{{item.operation}}</div></el-button></div></el-col>
</div></el-row>
</el-header>
<el-main style=" overflow: hidden;height:280px; background:white;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<el-row style="text-align:left;margin-bottom:5% ;font-weight:bold;" >区域耗能统计</el-row>
<el-row ><v-chart autoresize :options="option" style="width: 100%;"/></el-row>
</el-main>
</el-container>
</el-container>
<el-container style="margin-top:1%">
<el-aside style="width:49% ;margin-right:2% ; overflow: hidden; background:white;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<el-row style="text-align:left;margin-bottom:2% ;font-weight:bold;" >今日能耗实时统计</el-row>
<el-row ><v-chart autoresize :options="option1" style="width: 100%;"/></el-row>
</el-aside>
<el-main style="overflow: hidden; background:white;border-radius: 4px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)">
<el-row style="text-align:left;margin-bottom:2% ;font-weight:bold;" >今日报警次数统计</el-row>
<el-row ><v-chart autoresize :options="option2" style="width: 100%;"/></el-row>
</el-main>
</el-container>
</div>
</template>
<script lang="ts">
import { ref, onMounted } from '@vue/composition-api';
export default {
setup() {
var labelRight = {
position: 'right'
};
const option = {
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
top: 5,
bottom: 5
},
xAxis: {
type: 'value',
position: 'top',
splitLine: {
lineStyle: {
type: 'dashed'
}
}
},
yAxis: {
type: 'category',
axisLine: {show: false},
axisLabel: {show: false},
axisTick: {show: false},
splitLine: {show: false},
max:5,
data: [ '孵化器2幢', '孵化器2幢', '孵化器2幢', '孵化器2幢', '孵化器1幢'],
},
series: [
{
name: '用电',
type: 'bar',
stack: '总量',
label: {
show: true,
formatter: '{b}'
},
data: [
{value: -0.07, label: labelRight},
{value: -0.09, label: labelRight},
0.2, 0.44,
{value: -0.23, label: labelRight},
0.08,
{value: -0.17, label: labelRight},
0.47,
{value: -0.36, label: labelRight},
0.18
]
}
]
};
const option1={
color: ['#3398DB'],
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00','16:00', '17:00', '18:00'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '能耗',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220,435,656,232]
}
]
};
const option2={
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['9:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00','16:00', '17:00', '18:00']
},
yAxis: {
type: 'value'
},
series: [{
name: '次数',
data: [820, 932, 901, 934, 1290, 1330, 1320,2312,5435,2121],
type: 'line',
areaStyle: {}
}]
};
const infos=[{id:'1',
location:'孵化器2幢一层',
operation:'日常巡检'},
{id:'2',
location:'孵化器2幢一层',
operation:'日常巡检'},
{id:'3',
location:'孵化器2幢一层',
operation:'日常巡检'},
{id:'4',
location:'孵化器2幢一层',
operation:'日常巡检'},
{id:'5',
location:'孵化器2幢一层',
operation:'日常巡检'},
]
const loading = ref<boolean>(false);
return{
loading,
infos,
option,
option1,
option2,
labelRight,
};
},
};
</script>
<style lang="scss">
.map{
margin-left: 5%;
width:90%;
overflow: hidden;
cursor:pointer;
}
.grid-content {
text-align: center;
line-height: 30px;
}
.bg-blue {
color: blue;
}
.el-row {
margin-bottom: 10px;
}
.bg-green {
color: green;
}
.bg-orange {
color: orange;
}
.bg-red {
color: red;
}
.bg-grey {
color: grey;
}
.big {
font-size: large;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
}
.info{line-height: 50px;}
.infos{padding:0 25px;}
</style>
<template>
<div class="flex column center login" v-loading="loading">
<div class="login-body vivify popIn flex center column">
<div class="login-head flex column center align-center">
<div class="title1">{{loginTitle1}}</div>
<div v-if="loginTitle2" class="title2">{{loginTitle2}}</div>
</div>
<div class="inner flex center align-center around">
<div class="left">
<img src="../assets/u90.png">
</div>
<div class="flex column right">
<div class="flex center">
<img :src="loginLogo"/>
</div>
<el-form
label-position="left" label-width="70px"
class="flex column around" ref="formRef" :model="form" :rules="rule">
<el-form-item prop="username" label="账户:">
<el-input v-model="form.username" autofocus autocomplete="off" placeholder="用户名" @keyup.enter.native="login($refs.formRef)" />
</el-form-item>
<el-form-item prop="pwd" label="密码:">
<el-input type="password" autocomplete="off" v-model="form.pwd" placeholder="密 码" @keyup.enter.native="login($refs.formRef)" />
</el-form-item>
<kit-err-channel id="login" style="margin-bottom: 5px" />
<el-form-item>
<el-button type="primary" @click="login($refs.formRef)">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
<div class="login-support">技术支持:杭州领克信息科技有限公司</div>
</div>
</template>
<script lang="ts">
import { ref, Ref, onMounted } from '@vue/composition-api';
import { ElForm } from 'element-ui/types/form';
import { useLoading } from 'web-toolkit/src/service';
import { postService, storeUserInfo, updateStoreUserInfo, submitErrChanel, pushMsgErr } from 'web-toolkit/src/case-main';
import {loginTitle1, loginTitle2, loginLogo, schema} from '@/main';
import {router} from '@/main';
import { Route } from 'vue-router';
import {assert} from 'web-toolkit/src/utils/index';
import {Login} from '@/dao/userDao';
export default {
setup() {
const loading = ref(false);
const form = ref({ username: '', pwd: '' });
const formRef: Ref<ElForm|null> = ref(null);
const rule = {
username: {
required: true,
message: '请填写用户名',
trigger: 'none',
},
pwd: [{
required: true,
message: '请填写密码',
trigger: 'none',
}, {
type: 'string',
min: 6,
message: '密码长度不能小于6位',
trigger: 'none',
}],
};
async function login() {
const valid = await (formRef.value as ElForm).validate();
assert(valid);
submitErrChanel('login');
const data = await Login({
...form.value,
schema,
});
updateStoreUserInfo(data as any);
// 设置登录后回到登录前页面
// @ts-ignore
const redirect: Route = {
name: 'index',
query: {},
};
if (
storeUserInfo.redirect &&
storeUserInfo.redirect.name &&
storeUserInfo.redirect.name !== 'notFound' &&
storeUserInfo.redirect.name !== 'login'
) {
redirect.name = storeUserInfo.redirect.name;
redirect.query = storeUserInfo.redirect.query;
}
// @ts-ignore
storeUserInfo.redirect = redirect;
router.push(redirect as any);
}
return {
formRef, loginTitle1, loginTitle2, loginLogo,
loading, form, rule, login: useLoading(loading, login),
};
},
};
</script>
<style lang="scss" scoped>
.login{
background: url("../assets/bg.jpg") no-repeat;
background-size: 100% 100%;
width: 100vw;
height: 100vh;
min-height: 600px;
}
.login-body {
width: 90vw;
height: 90vh;
min-height: 400px;
.login-head{
color: white;
.title1{
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 10px;
}
.title2{
font-size: 1.8rem;
margin-bottom: 2rem;
}
}
.inner{
width: 100%;
max-height: 600px;
max-width: 1000px;
background: white;
padding: 2rem 2rem;
box-shadow: 3px 3px 10px rgba($color: #000, $alpha: .5);
border-radius: 10px;
font-size: 1rem;
.left{
img{
height: 40vh;
}
}
.right{
width: 300px;
img{
height: 3.8rem;
width: auto;
margin-bottom: 3rem;
}
.el-input{
width: 230px;
}
.el-button{
width: 230px;
font-weight: 600;
margin: 0 auto;
}
}
}
}
.login-support{
/*margin-top: 3vh;*/
color: #fff;
width: 100%;
font-weight: 700;
font-size: 1.1rem;
text-align: center;
}
</style>
<template>
<el-menu
activeTextColor="#00d0FF"
textColor="white"
:unique-opened="true"
:backgroundColor="bgColor"
mode="vertical"
:default-active="active"
@select="routeTo">
<template v-for="(item, index) of storePageMenu">
<el-menu-item
v-if="item.name && contains(item.privileges)"
:key="index"
:index="item.name">
<i :class="'iconfont ' + item.icon"/>
<span class="title">{{ item.title }}</span>
</el-menu-item>
<el-submenu
v-if="!item.name && item.children && item.children.length > 0 && contains(item.privileges)"
popper-class="my-el-menu-popper"
:key="index"
:index="item.title">
<template slot="title">
<i :class="'iconfont '+item.icon"/>
<span class="title">{{ item.title }}</span>
</template>
<el-menu-item
class="item"
v-for="(child, i) of menuItemFilter(item.children)"
:key="i"
:index="child.name"
v-text="child.cTitle"/>
</el-submenu>
</template>
</el-menu>
</template>
<script lang="ts">
import { ref, onMounted, computed, watch } from '@vue/composition-api';
import {checkPrivilege, storePageMenu, storeUserInfo, storeCurrentRoute} from 'web-toolkit/src/case-main';
import {router} from '@/main';
export default {
props: {
bgColor: {
type: String,
default: 'center',
},
},
setup() {
const active = computed(() => {
if (storeCurrentRoute.meta) {
return (storeCurrentRoute.meta as any).parentName || storeCurrentRoute.name;
} else if (storeCurrentRoute.name) {
return storeCurrentRoute.name;
}
return undefined;
});
function menuItemFilter(itemChildren: any[]) {
return itemChildren.filter((child) => contains(child.privileges));
}
function routeTo(name: string) {
router.push({ name });
}
function contains(privileges: any[]) {
if (!storeUserInfo.user) { return false; }
const all = storeUserInfo.user.role.privileges;
return checkPrivilege(all, privileges);
}
return{
storePageMenu, storeCurrentRoute,
menuItemFilter,
routeTo,
contains,
active,
};
},
};
</script>
<style scoped lang="scss">
.el-menu {
border-right: 0;
height: 100%;
i{
margin-right: 10px;
}
}
</style>
<template>
<div class="header theme flex between">
<div class="brand flex align-center center" style="color: white">
<!-- <img :src="titleLogo" style="height: 20px; margin-right: 5px" /> -->
<span>{{loginTitle2}}</span>
<!-- <span>设备运维管理云平台</span> -->
</div>
<div class="header-menu-wrapper flex center">
</div>
<lkt-header-side class="header-side"/>
</div>
</template>
<script lang="ts">
import LktHeaderSide from './header-side.vue';
import LktMenu from './Menu.vue';
import {loginTitle1, loginTitle2, loginLogo, titleLogo} from '@/main';
export default {
components: {
LktHeaderSide, LktMenu,
},
setup() {
return{
loginTitle2, loginTitle1, loginLogo, titleLogo,
};
},
};
</script>
<style scoped lang="scss">
.brand{
height: 60px;
width: 200px;
color: $header-title-font;
font-weight: 600;
cursor: default;
// background-color: $header-title;
background-color: #23479C;
&.vertical {
border-color: transparent;
}
span{
font-size: 1.2rem;
}
}
.header {
background-color: $background-main;
min-width: 800px;
height: 60px;
&.horizontal > * {
// background-color: $header-title;
background-color: #23479C;
border: none;
}
.header-menu-wrapper{
border-bottom: 1px solid $grey-4;
width: calc(100vw - 200px - 30vw);
background-color: white;
}
.header-side{
width: 30vw;
border-bottom: 1px solid $grey-4;
background-color: white;
}
}
</style>
<template>
<div class="layout">
<lkt-navbar class="header"/>
<lkt-menu class="vertical-menu" bgColor="#23479C"/>
<div class="main">
<el-breadcrumb separator-class="el-icon-arrow-right" class="bread">
<el-breadcrumb-item v-for="(item, index) of path" :key="item.cname">
<span v-if="!item.isLink" :class="index" class="bread-title">{{ item.cname }}</span>
<span v-else-if="index === path.length - 1" class="bread-title bread-title--last">{{ item.cname }}</span>
<router-link v-else class="bread-title bread-title--link" :to="item.route.path">{{ item.cname }}</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
<router-view class="page--inner"/>
</div>
<!-- <div class="page flex" :style="{ height: 'calc(100% - 60px)'}">-->
<!-- <lkt-menu class="vertical-menu" bgColor="#02213F"/>-->
<!-- <div class="main" :style="{ width: 'calc(100% - 200px)'}">-->
<!-- <el-breadcrumb separator-class="el-icon-arrow-right" class="bread">-->
<!-- <el-breadcrumb-item v-for="(item, index) of path" :key="item.cname">-->
<!-- <span v-if="!item.isLink" :class="index" class="bread-title">{{ item.cname }}</span>-->
<!-- <span v-else-if="index === path.length - 1" class="bread-title bread-title&#45;&#45;last">{{ item.cname }}</span>-->
<!-- <router-link v-else class="bread-title bread-title&#45;&#45;link" :to="item.route.path">{{ item.cname }}</router-link>-->
<!-- </el-breadcrumb-item>-->
<!-- </el-breadcrumb>-->
<!-- <lkt-scrollbar class="page&#45;&#45;outer">-->
<!-- <router-view class="page&#45;&#45;inner"/>-->
<!-- </lkt-scrollbar>-->
<!-- </div>-->
<!-- </div>-->
</div>
</template>
<script lang="ts">
import LktMenu from './Menu.vue';
import LktNavbar from './Navbar.vue';
import { ref, Ref } from '@vue/composition-api';
import {router} from '@/main';
import {routes} from '@/router/routes';
export default {
components: { LktMenu, LktNavbar },
setup() {
const getRoute = (cname: string, searchedRoutes: any = routes): any => {
for (const route of searchedRoutes) {
if (route.meta && route.meta.CName === cname) {
return route;
}
if (route.children) {
const target = getRoute(cname, route.children);
if (target) {
return target;
}
}
}
};
const resolveRouteMeta = (cname: string | void): PathItem[] => {
if (!cname) {
return [];
}
const route = getRoute(cname);
return [...resolveRouteMeta(route ? route.meta.parentCName : undefined), {
cname,
isLink: !!(route && !route.children),
route,
}];
};
const path: Ref<PathItem[]> = ref(resolveRouteMeta(router.currentRoute.meta.CName));
router.afterEach((to, from) => {
path.value = resolveRouteMeta(to.meta.CName);
});
return { path };
},
};
interface PathItem {
cname: string;
isLink: boolean;
route?: any;
}
</script>
<style lang="scss" scoped>
.header{
position: fixed;
top: 0;
width: 100vw;
z-index: 2000;
}
.vertical-menu {
/*margin-top: 60px;*/
width: 200px;
height: calc(100% - 60px);
position: fixed;
left: 0;
top: 60px;
bottom: 0;
z-index: 1500;
overflow-y: scroll;
// 滚动条消失
&::-webkit-scrollbar { width: 0 !important }
-ms-overflow-style: none;
overflow: -moz-scrollbars-none;
}
.main {
margin: 60px 0 0 200px;
padding: 10px;
width: calc(100% - 200px);
.bread{
padding-top: 5px;
padding-bottom: 10px;
height: 30px;
.bread-title {
color: $normal-text;
cursor: default;
}
.bread-title--link {
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
.bread-title--last {
color: $active;
}
}
/*> .page--outer {*/
/* height: calc(100% - 30px);*/
/*}*/
}
.layout {
height: calc(100% - 60px);
background-color: $background-main;
}
.page--inner > *:not(*[class^=el-]):not(*[class^=lkt-]) {
min-width: 1040px;
}
html{
height: 100%;
}
</style>
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
// todo
"skipLibCheck": true,
// "importHelpers": true,
"moduleResolution": "node",
"noImplicitAny": false,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"sourceMap": true,
"baseUrl": ".",
"noEmit": true,
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"es5",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules/**",
"src/views/temp/**"
]
}
{
"defaultSeverity": "warning",
"extends": [
"tslint:recommended"
],
"linterOptions": {
"exclude": [
"node_modules/**",
"src/views/temp/**"
],
"include": [
"src/**"
]
},
"rules": {
"quotemark": [true, "single"],
"indent": [true, "spaces", 2],
"object-literal-sort-keys": false,
"radix": false,
"ordered-imports": false,
"only-arrow-function": false,
"max-line-length": false,
"no-namespace": false,
"only-arrow-functions": false,
"member-access": false,
"no-empty": false,
"max-classes-per-file": false,
"interface-name": false,
"arrow-parens": false,
"no-shadowed-variable": false,
"ban-types": false,
"no-unused-expression": false,
"no-bitwise": false
}
}
// 这里是在编译时执行
const theme = process.env.VUE_APP_APP_THEME || 'theme_dark';
const webpackExternals = process.env.NODE_ENV==='production' ? {
'vue': 'Vue',
'element-ui': 'ELEMENT',
'vue-router': 'VueRouter',
'vuex': 'Vuex',
'axios': 'axios',
'qs': 'Qs',
} : {};
module.exports = {
publicPath: process.env.BASE_URL,
productionSourceMap: false,
configureWebpack: {
entry: process.env.ENTRY,
externals: {},
},
devServer:{
port: 8888
},
css: {
loaderOptions: {
sass: {
additionalData: `
@import "node_modules/web-toolkit/src/scss/color.scss";
@import "node_modules/web-toolkit/src/scss/${theme}.scss";
`
}
}
},
// for vue-echarts
transpileDependencies: [
'vue-echarts',
'resize-detector'
],
// web-bundle-analyzer: https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin
pluginOptions: {
// webpackBundleAnalyzer: {
// openAnalyzer: false,
// // server(dev), static(product), disabled。需要时用server
// analyzerMode: 'disabled',
// }
}
// pages:{
// index: 'src/main.js',
// }
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment