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 |
After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
@ -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;
|
||||||
|
}
|
@ -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,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();
|
||||||
|
});
|
@ -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,43 +1,86 @@
|
|||||||
export default [
|
import Index from '@/views/index/index'
|
||||||
/*{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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',
|
name: 'template',
|
||||||
component: () => import('@/components/error/403'),
|
path: '/template',
|
||||||
name: '403',
|
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: true,
|
isAuth: true
|
||||||
isTab: false,
|
},
|
||||||
isAuth: false
|
component: () => import('@/views/Template')
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
path: '/500',
|
name: 'now',
|
||||||
component: () => import('@/components/error/500'),
|
path: '/now',
|
||||||
name: '500',
|
|
||||||
meta: {
|
meta: {
|
||||||
keepAlive: true,
|
isAuth: true
|
||||||
isTab: false,
|
},
|
||||||
isAuth: false
|
component: () => import('@/views/Now')
|
||||||
}
|
}, {
|
||||||
|
name: 'history',
|
||||||
|
path: '/history',
|
||||||
|
meta: {
|
||||||
|
isAuth: true
|
||||||
|
},
|
||||||
|
component: () => import('@/views/History')
|
||||||
}, {
|
}, {
|
||||||
path: '*',
|
name: 'alarm',
|
||||||
redirect: '/404'
|
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 = {
|
const getters = {
|
||||||
currentNav: state => state.common.currentNav
|
token: state => state.user.token,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default getters
|
export default getters
|
@ -1,20 +1,10 @@
|
|||||||
import website from '../../config/website'
|
import website from '@/config/website'
|
||||||
import {getStore, setStore} from '../../util/store'
|
|
||||||
|
|
||||||
const common = {
|
const common = {
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
website: website,
|
website: website,
|
||||||
currentNav: getStore({name: 'currentNav'}) || '/',
|
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {}
|
||||||
SET_CURRENT_PATH: (state, currentNav) => {
|
|
||||||
state.currentNav = currentNav;
|
|
||||||
setStore({
|
|
||||||
name: 'currentNav',
|
|
||||||
content: state.currentNav,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export default common
|
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
|
@ -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 '';
|
||||||
|
}
|
@ -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()
|
||||||
|
}
|
||||||
|
};
|
@ -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 = {
|
module.exports = {
|
||||||
publicPath: './',
|
publicPath: './',
|
||||||
lintOnSave: true,
|
lintOnSave: true,
|
||||||
productionSourceMap: false
|
productionSourceMap: false,
|
||||||
}
|
devServer: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:8400',
|
||||||
|
changeOrigin: true,
|
||||||
|
ws: true,
|
||||||
|
pathRewrite: {
|
||||||
|
'^/api': ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|