登录页面

pull/1/head
pnoker 6 years ago
parent d43368aa8a
commit a48cc614d4

@ -18,7 +18,10 @@
"vue": "^2.6.11",
"vue-axios": "^2.1.5",
"vue-router": "^3.1.3",
"vuex": "^3.1.2"
"vuex": "^3.1.2",
"nprogress": "latest",
"js-base64": "latest",
"js-cookie": "latest"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.1.2",

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@ -9,7 +9,7 @@
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="chrome=1"/>
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>IOT | DC3</title>
<title>DC3 Web UI</title>
<style>
html,
body,

@ -0,0 +1,12 @@
import request from '@/config/axios'
export const generateToken = (user) => request({
url: '/api/auth/token',
method: 'post',
data: user
});
export const checkTokenValid = (token) => request({
url: '/auth/token/' + token,
method: 'post'
});

@ -0,0 +1,185 @@
.login-container {
display: flex;
align-items: center;
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
margin: 0 auto;
background: radial-gradient(circle, #fff, #1296DB);
}
.login-weaper {
margin: 0 auto;
width: 1000px;
border-radius: 5px;
box-shadow: -4px 5px 10px rgba(0, 0, 0, 0.4);
.el-input-group__append {
border: none;
}
}
.login-left,
.login-border {
position: relative;
min-height: 500px;
align-items: center;
display: flex;
}
.login-left {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
justify-content: center;
flex-direction: column;
background-color: #1296DB;
color: #fff;
float: left;
width: 50%;
position: relative;
}
.login-left .img {
width: 350px;
}
.login-time {
position: absolute;
left: 25px;
top: 25px;
width: 100%;
color: #fff;
font-weight: 200;
opacity: 0.9;
font-size: 18px;
overflow: hidden;
}
.login-left .title {
margin-top: 60px;
text-align: center;
color: #fff;
font-weight: 300;
letter-spacing: 2px;
font-size: 25px;
}
.login-border {
z-index: 1;
border-left: 5px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
color: #fff;
background-color: #fff;
width: 50%;
float: left;
box-sizing: border-box;
}
.login-main {
margin: 0 auto;
width: 65%;
box-sizing: border-box;
}
.login-main > h3 {
margin-bottom: 20px;
}
.login-main > p {
color: #76838f;
}
.login-title {
color: #333;
margin-bottom: 40px;
font-weight: 500;
font-size: 22px;
text-align: center;
letter-spacing: 4px;
}
.login-menu {
margin-top: 40px;
width: 100%;
text-align: center;
a {
color: #999;
font-size: 12px;
margin: 0px 8px;
}
}
.login-submit {
width: 100%;
height: 45px;
background: none;
font-size: 18px;
letter-spacing: 2px;
font-weight: 300;
color: #1296DB;
cursor: pointer;
margin-top: 30px;
transition: 0.25s;
}
.login-form {
margin: 10px 0;
i {
color: #333;
}
.el-form-item__content {
width: 100%;
}
.el-form-item {
margin-bottom: 12px;
}
.el-input {
input {
padding-bottom: 10px;
text-indent: 5px;
background: transparent;
border: none;
border-radius: 0;
color: #333;
border-bottom: 1px solid rgb(235, 237, 242);
}
.el-input__prefix {
i {
padding: 0 5px;
font-size: 16px !important;
}
}
}
}
.login-code {
display: flex;
align-items: center;
justify-content: space-around;
margin: 0 0 0 10px;
}
.login-code-img {
margin-top: 2px;
width: 100px;
height: 38px;
background-color: #fdfdfd;
border: 1px solid #f0f0f0;
color: #333;
font-size: 14px;
font-weight: bold;
letter-spacing: 5px;
line-height: 38px;
text-indent: 5px;
text-align: center;
}

@ -1,7 +1,7 @@
<template>
<div class="error">
<div class="img"
style=" background-image: url('/img/error/403.svg');">
style=" background-image: url('/images/error/403.svg');">
</div>
<div class="content">
<h1>403</h1>

@ -1,7 +1,7 @@
<template>
<div class="error">
<div class="img"
style=" background-image: url('/img/error/404.svg');">
style=" background-image: url('/images/error/404.svg');">
</div>
<div class="content">
<h1>404</h1>

@ -1,7 +1,7 @@
<template>
<div class="error">
<div class="img"
style=" background-image: url('/img/error/500.svg');">
style=" background-image: url('/images/error/500.svg');">
</div>
<div class="content">
<h1>500</h1>

@ -1,5 +1,4 @@
.error {
margin-top: 45px;
height: 100%;
display: flex;
flex-direction: column;

@ -0,0 +1,465 @@
<template>
<div class="waves">
<slot/>
</div>
</template>
<script>
class ShaderProgram {
constructor(holder, options = {}) {
options = Object.assign(
{
antialias: false,
depthTest: false,
mousemove: false,
autosize: true,
side: "front",
vertex: `
precision highp float;
attribute vec4 a_position;
attribute vec4 a_color;
uniform float u_time;
uniform vec2 u_resolution;
uniform vec2 u_mousemove;
uniform mat4 u_projection;
varying vec4 v_color;
void main() {
gl_Position = u_projection * a_position;
gl_PointSize = (10.0 / gl_Position.w) * 100.0;
v_color = a_color;
}`,
fragment: `
precision highp float;
uniform sampler2D u_texture;
uniform int u_hasTexture;
varying vec4 v_color;
void main() {
if ( u_hasTexture == 1 ) {
gl_FragColor = v_color * texture2D(u_texture, gl_PointCoord);
} else {
gl_FragColor = v_color;
}
}`,
onUpdate: () => {
},
onResize: () => {
}
},
options
);
const uniforms = Object.assign(
{
time: {
type: "float",
value: 0
},
hasTexture: {
type: "int",
value: 0
},
resolution: {
type: "vec2",
value: [0, 0]
},
projection: {
type: "mat4",
value: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
}
},
options.uniforms
);
const buffers = Object.assign(
{
position: {
size: 3,
data: []
},
color: {
size: 4,
data: []
}
},
options.buffers
);
const camera = Object.assign(
{
fov: 60,
near: 1,
far: 10000,
aspect: 1,
z: 100,
perspective: true
},
options.camera
);
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl", {
antialias: options.antialias
});
if (!gl) return false;
this.count = 0;
this.gl = gl;
this.canvas = canvas;
this.camera = camera;
this.holder = holder;
this.onUpdate = options.onUpdate;
this.onResize = options.onResize;
this.data = {};
holder.appendChild(canvas);
this.createProgram(options.vertex, options.fragment);
this.createBuffers(buffers);
this.createUniforms(uniforms);
this.updateUniforms();
this.createTexture(options.texture);
gl.enable(gl.BLEND);
gl.enable(gl.CULL_FACE);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
gl[options.depthTest ? "enable" : "disable"](gl.DEPTH_TEST);
if (options.autosize)
window.addEventListener("resize", () => this.resize(), false);
this.resize();
this.update = this.update.bind(this);
this.time = {
start: performance.now(),
old: performance.now()
};
this.update();
}
resize() {
const holder = this.holder;
const canvas = this.canvas;
const gl = this.gl;
const width = (this.width = holder.offsetWidth);
const height = (this.height = holder.offsetHeight);
const aspect = (this.aspect = width / height);
const dpi = (this.dpi = devicePixelRatio);
canvas.width = width * dpi;
canvas.height = height * dpi;
canvas.style.width = 100 + "%";
canvas.style.height = 100 + "%";
gl.viewport(0, 0, width * dpi, height * dpi);
this.uniforms.resolution = [width, height];
this.uniforms.projection = this.setProjection(aspect);
this.onResize(width, height, dpi);
}
setProjection(aspect) {
const camera = this.camera;
if (camera.perspective) {
camera.aspect = aspect;
const fovRad = camera.fov * (Math.PI / 180);
const f = Math.tan(Math.PI * 0.5 - 0.5 * fovRad);
const rangeInv = 1.0 / (camera.near - camera.far);
const matrix = [
f / camera.aspect,
0,
0,
0,
0,
f,
0,
0,
0,
0,
(camera.near + camera.far) * rangeInv,
-1,
0,
0,
camera.near * camera.far * rangeInv * 2,
0
];
matrix[14] += camera.z;
matrix[15] += camera.z;
return matrix;
} else {
return [
2 / this.width,
0,
0,
0,
0,
-2 / this.height,
0,
0,
0,
0,
1,
0,
-1,
1,
0,
1
];
}
}
createShader(type, source) {
const gl = this.gl;
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
return shader;
} else {
gl.deleteShader(shader);
}
}
createProgram(vertex, fragment) {
const gl = this.gl;
const vertexShader = this.createShader(gl.VERTEX_SHADER, vertex);
const fragmentShader = this.createShader(gl.FRAGMENT_SHADER, fragment);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
gl.useProgram(program);
this.program = program;
} else {
gl.deleteProgram(program);
}
}
createUniforms(data) {
const gl = this.gl;
const uniforms = (this.data.uniforms = data);
const values = (this.uniforms = {});
Object.keys(uniforms).forEach(name => {
const uniform = uniforms[name];
uniform.location = gl.getUniformLocation(this.program, "u_" + name);
Object.defineProperty(values, name, {
set: value => {
uniforms[name].value = value;
this.setUniform(name, value);
},
get: () => uniforms[name].value
});
});
}
setUniform(name, value) {
const gl = this.gl;
const uniform = this.data.uniforms[name];
uniform.value = value;
switch (uniform.type) {
case "int": {
gl.uniform1i(uniform.location, value);
break;
}
case "float": {
gl.uniform1f(uniform.location, value);
break;
}
case "vec2": {
gl.uniform2f(uniform.location, ...value);
break;
}
case "vec3": {
gl.uniform3f(uniform.location, ...value);
break;
}
case "vec4": {
gl.uniform4f(uniform.location, ...value);
break;
}
case "mat2": {
gl.uniformMatrix2fv(uniform.location, false, value);
break;
}
case "mat3": {
gl.uniformMatrix3fv(uniform.location, false, value);
break;
}
case "mat4": {
gl.uniformMatrix4fv(uniform.location, false, value);
break;
}
}
}
updateUniforms() {
const uniforms = this.data.uniforms;
Object.keys(uniforms).forEach(name => {
const uniform = uniforms[name];
this.uniforms[name] = uniform.value;
});
}
createBuffers(data) {
const buffers = (this.data.buffers = data);
const values = (this.buffers = {});
Object.keys(buffers).forEach(name => {
const buffer = buffers[name];
buffer.buffer = this.createBuffer("a_" + name, buffer.size);
Object.defineProperty(values, name, {
set: data => {
buffers[name].data = data;
this.setBuffer(name, data);
if (name === "position") this.count = buffers.position.data.length / 3;
},
get: () => buffers[name].data
});
});
}
createBuffer(name, size) {
const gl = this.gl;
const program = this.program;
const index = gl.getAttribLocation(program, name);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(index);
gl.vertexAttribPointer(index, size, gl.FLOAT, false, 0, 0);
return buffer;
}
setBuffer(name, data) {
const gl = this.gl;
const buffers = this.data.buffers;
if (name == null && !gl.bindBuffer(gl.ARRAY_BUFFER, null)) return;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers[name].buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
}
createTexture(src) {
const gl = this.gl;
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
1,
1,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
new Uint8Array([0, 0, 0, 0])
);
this.texture = texture;
if (src) {
this.uniforms.hasTexture = 1;
this.loadTexture(src);
}
}
loadTexture(src) {
const gl = this.gl;
const texture = this.texture;
const textureImage = new Image();
textureImage.onload = () => {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
textureImage
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
};
textureImage.src = src;
}
update() {
const gl = this.gl;
const now = performance.now();
const elapsed = (now - this.time.start) / 5000;
this.time.old = now;
this.uniforms.time = elapsed;
if (this.count > 0) {
gl.drawArrays(gl.POINTS, 0, this.count);
}
this.onUpdate();
requestAnimationFrame(this.update);
}
}
export default {
name: "BgAnimation",
data() {
return {};
},
mounted() {
const pointSize = 1.5;
new ShaderProgram(
document.querySelector(".waves"), {
texture: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAb1BMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8v0wLRAAAAJHRSTlMAC/goGvDhmwcExrVjWzrm29TRqqSKenRXVklANSIUE8mRkGpv+HOfAAABCElEQVQ4y4VT13LDMAwLrUHteO+R9f/fWMfO6dLaPeKVEECRxOULWsEGpS9nULDwia2Y+ALqUNbAWeg775zv+sA4/FFRMxt8U2FZFCVWjR/YrH4/H9sarclSKdPMWKzb8VsEeHB3m0shkhVCyNzeXeAQ9Xl4opEieX2QCGnwGbj6GMyjw9t1K0fK9YZunPXeAGsfJtYjwzxaBnozGGorYz0ypK2HzQSYx1y8DgSRo2ewOiyh2QWOEk1Y9OrQV0a8TiBM1a8eMHWYnRMy7CZ4t1CmyRkhSUvP3gRXyHOCLBxNoC3IJv//ZrJ/kxxUHPUB+6jJZZHrpg6GOjnqaOmzp4NDR48OLxn/H27SRQ08S0ZJAAAAAElFTkSuQmCC",
uniforms: {
size: {type: "float", value: pointSize},
field: {type: "vec3", value: [0, 0, 0]},
speed: {type: "float", value: 5}
},
vertex: `
#define M_PI 3.1415926535897932384626433832795
precision highp float;
attribute vec4 a_position;
attribute vec4 a_color;
uniform float u_time;
uniform float u_size;
uniform float u_speed;
uniform vec3 u_field;
uniform mat4 u_projection;
varying vec4 v_color;
void main() {
vec3 pos = a_position.xyz;
pos.y += (
cos(pos.x / u_field.x * M_PI * 8.0 + u_time * u_speed) +
sin(pos.z / u_field.z * M_PI * 8.0 + u_time * u_speed)
) * u_field.y;
gl_Position = u_projection * vec4( pos.xyz, a_position.w );
gl_PointSize = ( u_size / gl_Position.w ) * 100.0;
v_color = a_color;
}`,
fragment: `
precision highp float;
uniform sampler2D u_texture;
varying vec4 v_color;
void main() {
gl_FragColor = v_color * texture2D(u_texture, gl_PointCoord);
}`,
onResize(w, h, dpi) {
const position = [], color = [];
const width = 400 * (w / h), depth = 500, height = 3, distance = 3;
for (let x = 0; x < width; x += distance) {
for (let z = 0; z < depth; z += distance) {
position.push(-width / 2 + x, -30, -depth / 2 + z);
color.push(
1,
//1 - (x / width),
1,
1,
//0.5 + (x / width) * 0.5,
z / depth
);
}
}
this.uniforms.field = [width, height, depth];
this.buffers.position = position;
this.buffers.color = color;
this.uniforms.size = (h / 400) * pointSize * dpi;
}
});
}
};
</script>
<style scoped>
canvas {
display: block;
}
.waves {
position: absolute;
left: 0px;
top: 0;
right: 0;
bottom: 0;
}
</style>

@ -0,0 +1,54 @@
import axios from 'axios'
import router from '@/router/router'
import store from '@/store/store';
import {Message} from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {getToken} from '@/util/auth'
//返回其他状态码
axios.defaults.validateStatus = function (status) {
return status >= 200 && status <= 500; // 默认的
};
//跨域请求允许保存cookie
axios.defaults.withCredentials = true;
//NProgress Configuration
NProgress.configure({
showSpinner: false
});
//HTTP Request拦截
axios.interceptors.request.use(config => {
NProgress.start();
config.headers['Content-Type'] = 'application/json';
config.headers['Auth-Token'] = getToken();
return config;
}, error => {
return Promise.reject(error)
});
//HTTP Response拦截
axios.interceptors.response.use(res => {
NProgress.done();
const ok = res.data.ok || false;
const status = res.data.code || 200;
const message = res.data.message || '未知错误';
//如果是401则跳转到登录页面
if (status === 401) store.dispatch('FedLogOut').then(() => router.push({path: '/login'}));
// 如果请求为 !ok 默认统一处理
if (!ok) {
Message({
type: 'error',
showClose: true,
message: message
});
return Promise.reject(new Error(message));
}
return res;
}, error => {
NProgress.done();
return Promise.reject(new Error(error));
});
export default axios

@ -0,0 +1,36 @@
import router from '@/router/router'
import store from '@/store/store'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {getToken} from '@/util/auth'
router.beforeEach((to, from, next) => {
NProgress.start();
const meta = to.meta || {};
if (getToken()) {
if (to.path === '/login') { //如果登录成功访问登录页跳转到主页
next({path: '/'})
} else {
//如果用户信息为空则获取用户信息,获取用户信息失败,跳转到登录页
console.log(store.getters.token);
if (store.getters.token.length === 0) {
store.dispatch('FedLogOut').then(() => {
next({path: '/login'})
})
} else {
next()
}
}
} else {
//判断是否需要认证,没有登录访问去登录页
if (meta.isAuth === false) {
next()
} else {
next('/login')
}
}
});
router.afterEach(() => {
NProgress.done();
});

@ -2,6 +2,5 @@
* 全局配置文件
*/
export default {
key: 'dc3',
nav: '/'
key: 'dc3'
}

@ -1,16 +1,13 @@
import Vue from 'vue'
import axios from './config/axios'
import VueAxios from 'vue-axios'
import App from './App'
import router from './router/router'
import store from './store/store'
import baseCard from './components/card/base-card'
//Element UI
import './plugins/element/element.js'
//Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
import './config/permission';
Vue.use(VueAxios, axios);
Vue.component('base-card', baseCard);
Vue.config.productionTip = false;
new Vue({

@ -5,4 +5,7 @@ import locale from 'element-ui/lib/locale/lang/zh-CN'
import 'element-ui/lib/theme-chalk/index.css';
import './element-variables.scss'
Vue.use(Element, {locale})
import baseCard from '@/components/card/base-card'
Vue.use(Element, {locale});
Vue.component('base-card', baseCard);

@ -0,0 +1,42 @@
export default [
{
name: 'login',
path: '/login',
meta: {
isAuth: false
},
component: () => import('@/views/login/index')
}, {
name: 'index',
path: '/',
redirect: '/home',
meta: {
isAuth: true
}
}, {
name: '404',
path: '/404',
meta: {
isAuth: false
},
component: () => import('@/components/error/404')
}, {
name: '403',
path: '/403',
meta: {
isAuth: false
},
component: () => import('@/components/error/403')
}, {
name: '500',
path: '/500',
meta: {
isAuth: false
},
component: () => import('@/components/error/500')
}, {
path: '*',
redirect: '/404'
}
]

@ -1,72 +1,9 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import ViewsRouter from './views/'
import PageRouter from './page/index'
import ViewsRouter from './views/index'
import Home from '../views/Home'
import Things from '../views/Things'
import Template from '../views/Template'
import Now from '../views/Now'
import History from '../views/History'
import Alarm from '../views/Alarm'
import Label from '../views/Label'
import Picture from '../views/Picture'
import Video from '../views/Video'
import About from '../views/About'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/things',
name: 'things',
component: Things
},
{
path: '/template',
name: 'template',
component: Template
},
{
path: '/now',
name: 'now',
component: Now
},
{
path: '/history',
name: 'history',
component: History
},
{
path: '/alarm',
name: 'alarm',
component: Alarm
},
{
path: '/label',
name: 'label',
component: Label
},
{
path: '/picture',
name: 'picture',
component: Picture
},
{
path: '/video',
name: 'video',
component: Video
},
{
path: '/about',
name: 'about',
component: About
}
];
Vue.use(VueRouter);
const router = new VueRouter({
scrollBehavior(to, from, savedPosition) {
@ -82,9 +19,9 @@ const router = new VueRouter({
}
}
},
routes: routes
routes: []
});
router.addRoutes([...ViewsRouter]);
router.addRoutes([...PageRouter, ...ViewsRouter]);
export default router

@ -1,43 +1,86 @@
export default [
/*{
path: '/login',
name: '登录页',
component: () => import('@/page/login/index'),
meta: {
keepAlive: true,
isTab: false,
isAuth: false
}
},*/ {
path: '/404',
component: () => import('@/components/error/404'),
name: '404',
meta: {
keepAlive: true,
isTab: false,
isAuth: false
}
import Index from '@/views/index/index'
export default [
{
path: '/',
redirect: '/home',
meta: {
isAuth: true
},
component: Index,
children: [
{
name: 'home',
path: '/home',
meta: {
isAuth: true
},
component: () => import('@/views/Home')
},
{
name: 'things',
path: '/things',
meta: {
isAuth: true
},
component: () => import('@/views/Things')
}, {
path: '/403',
component: () => import('@/components/error/403'),
name: '403',
name: 'template',
path: '/template',
meta: {
keepAlive: true,
isTab: false,
isAuth: false
}
isAuth: true
},
component: () => import('@/views/Template')
}, {
path: '/500',
component: () => import('@/components/error/500'),
name: '500',
name: 'now',
path: '/now',
meta: {
keepAlive: true,
isTab: false,
isAuth: false
}
isAuth: true
},
component: () => import('@/views/Now')
}, {
name: 'history',
path: '/history',
meta: {
isAuth: true
},
component: () => import('@/views/History')
}, {
path: '*',
redirect: '/404'
name: 'alarm',
path: '/alarm',
meta: {
isAuth: true
},
component: () => import('@/views/Alarm')
}, {
name: 'label',
path: '/label',
meta: {
isAuth: true
},
component: () => import('@/views/Label')
}, {
name: 'picture',
path: '/picture',
meta: {
isAuth: true
},
component: () => import('@/views/Picture')
}, {
name: 'video',
path: '/video',
meta: {
isAuth: true
},
component: () => import('@/views/Video')
}, {
name: 'about',
path: '/about',
meta: {
isAuth: true
},
component: () => import('@/views/About')
}
]
}
]

@ -1,5 +1,5 @@
const getters = {
currentNav: state => state.common.currentNav
token: state => state.user.token,
};
export default getters

@ -1,20 +1,10 @@
import website from '../../config/website'
import {getStore, setStore} from '../../util/store'
import website from '@/config/website'
const common = {
state: {
website: website,
currentNav: getStore({name: 'currentNav'}) || '/',
},
mutations: {
SET_CURRENT_PATH: (state, currentNav) => {
state.currentNav = currentNav;
setStore({
name: 'currentNav',
content: state.currentNav,
})
}
}
mutations: {}
};
export default common

@ -0,0 +1,51 @@
import {getStore, setStore} from '@/util/store'
import {setToken} from '@/util/auth'
import {checkTokenValid, generateToken} from '@/api/user'
const user = {
state: {
userInfo: getStore({name: 'userInfo'}) || [],
token: getStore({name: 'token'}) || '',
},
actions: {
GenerateToken({commit}, user) {
return new Promise((resolve, reject) => {
generateToken(user).then(res => {
const data = res.data;
if (data.ok) {
commit('SET_USER', user);
commit('SET_TOKEN', data.message);
resolve();
}
}).catch(error => {
reject(error);
})
})
},
CheckTokenValid(body) {
return new Promise((resolve, reject) => {
checkTokenValid(body).then(res => {
const data = res.data;
if (data.ok) {
resolve();
}
}).catch(error => {
reject(error)
})
})
}
},
mutations: {
SET_TOKEN: (state, token) => {
setToken(token);
state.token = token;
setStore({name: 'token', content: state.token, type: 'session'})
},
SET_USER: (state, userInfo) => {
state.userInfo = userInfo;
setStore({name: 'userInfo', content: state.userInfo})
}
}
};
export default user

@ -1,5 +1,6 @@
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import common from './modules/common'
import getters from './getters'
@ -7,7 +8,7 @@ Vue.use(Vuex);
const store = new Vuex.Store({
modules: {
common
common, user
},
getters
});

@ -0,0 +1,16 @@
import Cookies from 'js-cookie'
const TokenKey = 'x-access-token';
const inFifteenMinutes = new Date(new Date().getTime() + 120 * 60 * 1000);
export function getToken() {
return Cookies.get(TokenKey);
}
export function setToken(token) {
return Cookies.set(TokenKey, token, {expires: inFifteenMinutes});
}
export function removeToken() {
return Cookies.remove(TokenKey);
}

@ -0,0 +1,59 @@
/**
*
* @param date1
* @param date2
* @returns {{leave1: number, hours: number, seconds: number, leave2: number, leave3: number, minutes: number, days: number}}
*/
export const calcDate = (date1, date2) => {
let date3 = date2 - date1;
let days = Math.floor(date3 / (24 * 3600 * 1000));
let leave1 = date3 % (24 * 3600 * 1000);//计算天数后剩余的毫秒数
let hours = Math.floor(leave1 / (3600 * 1000));
let leave2 = leave1 % (3600 * 1000);//计算小时数后剩余的毫秒数
let minutes = Math.floor(leave2 / (60 * 1000));
let leave3 = leave2 % (60 * 1000);//计算分钟数后剩余的毫秒数
let seconds = Math.round(date3 / 1000);
return {
leave1,
leave2,
leave3,
days: days,
hours: hours,
minutes: minutes,
seconds: seconds,
}
};
/**
* 日期格式化
*
* @param date
* @returns {string}
*/
export function dateFormat(date) {
let format = 'yyyy-MM-dd hh:mm:ss';
if (date !== 'Invalid Date') {
let o = {
"M+": date.getMonth() + 1, //month
"d+": date.getDate(), //day
"h+": date.getHours(), //hour
"m+": date.getMinutes(), //minute
"s+": date.getSeconds(), //second
"q+": Math.floor((date.getMonth() + 3) / 3), //quarter
"S": date.getMilliseconds() //millisecond
};
if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
(date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (let k in o)
if (new RegExp("(" + k + ")").test(format))
format = format.replace(RegExp.$1,
RegExp.$1.length === 1 ? o[k] :
("00" + o[k]).substr(("" + o[k]).length));
return format;
}
return '';
}

@ -1,5 +1,5 @@
import {isNull} from './validate';
import website from '../config/website'
import website from '@/config/website'
const keyName = website.key + '-';

@ -0,0 +1,345 @@
import {isNull} from './validate'
/**
* 表单序列化
*
* @param data
* @returns {string}
*/
export const serialize = data => {
let list = [];
Object.keys(data).forEach(ele => {
list.push(`${ele}=${data[ele]}`)
});
return list.join('&');
};
/**
* 获取对象类型
*
* @param obj
* @returns {string|*}
*/
export const getObjType = obj => {
let toString = Object.prototype.toString;
let map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object'
};
if (obj instanceof Element) {
return 'element';
}
return map[toString.call(obj)];
};
/**
* 对象深拷贝
*
* @param data
* @returns {{}|*}
*/
export const deepClone = data => {
let type = getObjType(data);
let obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
//不再具有下一层次
return data;
}
if (type === 'array') {
for (let i = 0, len = data.length; i < len; i++) {
obj.push(deepClone(data[i]));
}
} else if (type === 'object') {
for (let key in data) {
obj[key] = deepClone(data[key]);
}
}
return obj;
};
/**
* 设置灰度模式
*
* @param status
*/
export const toggleGrayMode = (status) => {
if (status) {
document.body.className = document.body.className + ' grayMode';
} else {
document.body.className = document.body.className.replace(' grayMode', '');
}
};
/**
* 设置主题
*
* @param name
*/
export const setTheme = (name) => {
document.body.className = name;
};
/**
* 加密处理
*
* @param params
* @returns {any}
*/
export const encryption = (params) => {
let {
data,
type,
param,
key
} = params;
let result = JSON.parse(JSON.stringify(data));
if (type === 'Base64') {
param.forEach(ele => {
result[ele] = btoa(result[ele]);
})
} else if (type === 'Aes') {
param.forEach(ele => {
result[ele] = window.CryptoJS.AES.encrypt(result[ele], key).toString();
})
}
return result;
};
/**
* 递归寻找子类的父类
*
* @param menu
* @param id
* @returns {undefined|*}
*/
export const findParent = (menu, id) => {
for (let i = 0; i < menu.length; i++) {
if (menu[i].children.length !== 0) {
for (let j = 0; j < menu[i].children.length; j++) {
if (menu[i].children[j].id === id) {
return menu[i];
} else {
if (menu[i].children[j].children.length !== 0) {
return findParent(menu[i].children[j].children, id);
}
}
}
}
}
};
/**
* 动态插入css
*
* @param url
*/
export const loadStyle = url => {
const link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.href = url;
const head = document.getElementsByTagName('head')[0];
head.appendChild(link);
};
/**
* 判断2个对象属性和值是否相等
*
* @param obj1
* @param obj2
* @returns {boolean}
*/
export const diff = (obj1, obj2) => {
delete obj1.close;
let o1 = obj1 instanceof Object;
let o2 = obj2 instanceof Object;
if (!o1 || !o2) {
return obj1 === obj2;
}
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
return false;
}
for (let attr in obj1) {
let t1 = obj1[attr] instanceof Object;
let t2 = obj2[attr] instanceof Object;
if (t1 && t2) {
return diff(obj1[attr], obj2[attr]);
} else if (obj1[attr] !== obj2[attr]) {
return false;
}
}
return true;
};
/**
* 根据字典的value显示label
*
* @param dic
* @param value
* @returns {string|*}
*/
export const findDicLabel = (dic, value) => {
let result = '';
if (isNull(dic)) return value;
if (typeof (value) == 'string' || typeof (value) == 'number' || typeof (value) == 'boolean') {
let index = 0;
index = findDicIndex(dic, value);
if (index !== -1) {
result = dic[index].label;
} else {
result = value;
}
} else if (value instanceof Array) {
result = [];
let index = 0;
value.forEach(ele => {
index = findDicIndex(dic, ele);
if (index !== -1) {
result.push(dic[index].label);
} else {
result.push(value);
}
});
result = result.toString();
}
return result;
};
/**
* 根据字典的value查找对应的index
*
* @param dic
* @param value
* @returns {number}
*/
export const findDicIndex = (dic, value) => {
for (let i = 0; i < dic.length; i++) {
if (dic[i].value === value) {
return i;
}
}
return -1;
};
/**
* 生成随机len位数字
*
* @param len
* @param date
* @returns {string}
*/
export const randomLenNum = (len, date) => {
let random = '';
random = Math.ceil(Math.random() * 100000000000000).toString().substr(0, len ? len : 4);
if (date) random = random + Date.now();
return random;
};
/**
* 打开全屏/关闭全屏
*/
export const triggerFullscreen = () => {
if (fullscreenEnable()) {
exitFullScreen();
} else {
reqFullScreen();
}
};
/**
* esc监听全屏
*
* @param callback
*/
export const listenFullscreen = (callback) => {
function listen() {
callback()
}
document.addEventListener("fullscreenchange", function () {
listen();
});
document.addEventListener("mozfullscreenchange", function () {
listen();
});
document.addEventListener("webkitfullscreenchange", function () {
listen();
});
document.addEventListener("msfullscreenchange", function () {
listen();
});
};
/**
* 浏览器判断是否全屏
*/
export const fullscreenEnable = () => {
return document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen;
};
/**
* 浏览器全屏
*/
export const reqFullScreen = () => {
if (document.documentElement.requestFullScreen) {
document.documentElement.requestFullScreen();
} else if (document.documentElement.webkitRequestFullScreen) {
document.documentElement.webkitRequestFullScreen();
} else if (document.documentElement.mozRequestFullScreen) {
document.documentElement.mozRequestFullScreen();
}
};
/**
* 浏览器退出全屏
*/
export const exitFullScreen = () => {
if (document.documentElement.requestFullScreen) {
document.exitFullScreen();
} else if (document.documentElement.webkitRequestFullScreen) {
document.webkitCancelFullScreen();
} else if (document.documentElement.mozRequestFullScreen) {
document.mozCancelFullScreen();
}
};
/**
* 打开小窗口
*
* @param url
* @param title
* @param w
* @param h
*/
export const openWindow = (url, title, w, h) => {
// Fixes dual-screen position Most browsers Firefox
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left;
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : screen.top;
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
const left = ((width / 2) - (w / 2)) + dualScreenLeft;
const top = ((height / 2) - (h / 2)) + dualScreenTop;
const newWindow = window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
// Puts focus on the newWindow
if (window.focus) {
newWindow.focus()
}
};

@ -4,8 +4,7 @@
* @returns {boolean}
*/
export function isUrl(url) {
const urlregex = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return urlregex.test(url)
return /^http[s]?:\/\/.*/.test(url);
}
/**
@ -14,8 +13,7 @@ export function isUrl(url) {
* @returns {boolean}
*/
export function isEmail(email) {
const re = /^(([^<>()\\[\]\\.,;:\s@"]+(\.[^<>()\\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return re.test(email)
return /^([a-zA-Z0-9_\\.\\-])+\\@(([a-zA-Z0-9\\-])+\\.)+([a-zA-Z0-9]{2,4})+$/.test(email);
}
/**
@ -24,7 +22,7 @@ export function isEmail(email) {
* @returns {boolean}
*/
export function isPhone(phone) {
return /^1[0-9]{10}$/.test(phone)
return /^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$/.test(phone);
}
/**

@ -0,0 +1,164 @@
<template>
<div class="container">
<div class="header">
<el-col :span="4" class="header_item">
<img class="logo" src="/images/logo/logo.png">
</el-col>
<el-col :span="16" class="header_item">
<el-menu class="menu"
:default-active="this.$route.path"
mode="horizontal"
:router=true>
<el-menu-item index="/home"><span class="el-icon-menu"/>首页</el-menu-item>
<el-menu-item index="/things">物联</el-menu-item>
<el-menu-item index="/template">模板</el-menu-item>
<el-menu-item index="/now">实时</el-menu-item>
<el-menu-item index="/history">历史</el-menu-item>
<el-menu-item index="/alarm">报警</el-menu-item>
<el-menu-item index="/label">标签</el-menu-item>
<el-menu-item index="/picture">图片</el-menu-item>
<el-menu-item index="/video">视频</el-menu-item>
<el-menu-item index="/setting">设置</el-menu-item>
<el-menu-item index="/help">帮助</el-menu-item>
<el-menu-item index="/about">关于</el-menu-item>
</el-menu>
</el-col>
<el-col :span="2" class="header_item">
<el-badge :value="12" :max="99" class="badge_item" type="primary">
<span class="span_small" @click="handleMessage"></span>
</el-badge>
</el-col>
<el-col :span="2" class="header_item">
<el-dropdown class="avatar_item" @command="handleCommand">
<span class="el-dropdown-link">
<el-avatar>
<img src="/images/common/avatar.png">
</el-avatar>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="profile">个人信息</el-dropdown-item>
<el-dropdown-item command="setting" divided>设置</el-dropdown-item>
<el-dropdown-item command="about">关于</el-dropdown-item>
<el-dropdown-item command="logout" divided>退出登录</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span class="span_small avatar">管理员</span>
</el-col>
</div>
<div class="body">
<el-scrollbar style="height: 100%;">
<router-view/>
</el-scrollbar>
</div>
</div>
</template>
<script>
export default {
data() {
return {};
},
created() {
},
methods: {
handleMessage() {
this.$message('click on message');
},
handleCommand(command) {
this.$message('click on item ' + command);
}
}
}
</script>
<style lang="scss">
body {
margin: 0;
min-width: 1366px;
min-height: 768px;
}
.container {
color: #2c3e50;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-family: 'Avenir', Helvetica, Arial, sans-serif;
}
.header {
top: 0px;
width: 100%;
height: 60px;
border-bottom: 1px solid #dcdfe6;
}
.header_item {
height: 100%;
}
.logo {
height: 60px;
margin-left: 10px;
}
.menu {
display: flex;
justify-content: center;
border-bottom: none !important;
}
.menu .el-menu-item {
font-size: 15px;
}
.badge_item {
top: 25px;
cursor: pointer;
margin-right: 40px;
}
.span_small {
color: #909399;
font-size: 14px;
}
.span_small.avatar {
margin: 20px 10px;
}
.avatar_item {
top: 10px;
cursor: pointer;
}
.body {
top: 65px;
bottom: 5px;
width: 100%;
position: absolute;
.el-scrollbar__wrap {
overflow-x: hidden;
}
}
.view {
top: 1px;
bottom: 0px;
width: 100%;
position: absolute;
}
.operator {
text-align: center;
margin: 5px 0px;
}
.page {
right: 1px;
bottom: 1px;
position: absolute !important;
}
</style>

@ -0,0 +1,105 @@
<template>
<div class="login-container">
<div class="login-weaper animated bounceInDown">
<div class="login-left">
<img class="img" src="/images/logo/logo-white.png">
</div>
<div class="login-border">
<div class="login-main">
<h4 class="login-title">
登录 DC3 Web UI
</h4>
<el-form class="login-form"
status-icon
:rules="loginRules"
ref="loginForm"
:model="loginForm"
label-width="0">
<el-form-item prop="name">
<el-input size="small"
@keyup.enter.native="handleLogin"
v-model="loginForm.name"
auto-complete="off"
placeholder="请输入用户名">
<i slot="prefix" class="el-icon-user"/>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input size="small"
@keyup.enter.native="handleLogin"
:type="passwordType"
v-model="loginForm.password"
auto-complete="off"
placeholder="请输入密码">
<i class="el-icon-view el-input__icon" slot="suffix" @click="showPassword"/>
<i slot="prefix" class="el-icon-lock"/>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary"
size="small"
@click.native.prevent="handleLogin"
class="login-submit">登录
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</div>
<particles></particles>
</div>
</template>
<script>
import particles from "@/components/particles/particles";
export default {
name: "login",
components: {particles},
data() {
return {
loginForm: {
name: "pnoker",
password: "dc3dc3dc3"
},
loginRules: {
name: [
{required: true, message: "请输入用户名", trigger: "blur"}
],
password: [
{required: true, message: "请输入密码", trigger: "blur"},
{min: 1, message: "密码长度最少为6位", trigger: "blur"}
]
},
passwordType: "password"
};
},
methods: {
showPassword() {
this.passwordType === ""
? (this.passwordType = "password")
: (this.passwordType = "");
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
const loading = this.$loading({
lock: true,
text: '登录中,请稍后。。。',
spinner: "el-icon-loading"
});
this.$store.dispatch("GenerateToken", this.loginForm).then(() => {
this.$router.push({path: '/'});
loading.close();
}).catch(() => {
loading.close()
});
}
});
}
}
};
</script>
<style lang="scss">
@import "~@/assets/styles/login.scss";
</style>

@ -1,5 +1,17 @@
module.exports = {
publicPath: './',
lintOnSave: true,
productionSourceMap: false
productionSourceMap: false,
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8400',
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
Loading…
Cancel
Save