From e06044d2db5e57dade2aec6a2ac398129f61d0f2 Mon Sep 17 00:00:00 2001
From: zhongrj <646384940@qq.com>
Date: Mon, 01 Jun 2026 19:00:15 +0800
Subject: [PATCH] feat: 增加登录页面,注释测试监控的播放
---
src/router/page/index.js | 22
src/config/website.js | 43 ++
src/permission.js | 61 +-
src/store/modules/user.js | 274 ++++++++++++++-
vue.config.js | 76 ----
src/api/user.js | 81 ++++
src/views/login/index.vue | 58 +++
src/router/axios.js | 72 ++-
src/styles/login.scss | 157 +++++++++
src/utils/tool.js | 39 +-
src/views/login/userlogin.vue | 82 ++++
src/views/home/index.vue | 2
src/store/getters.js | 19
src/styles/index.scss | 1
14 files changed, 784 insertions(+), 203 deletions(-)
diff --git a/src/api/user.js b/src/api/user.js
new file mode 100644
index 0000000..f9ae61f
--- /dev/null
+++ b/src/api/user.js
@@ -0,0 +1,81 @@
+import request from '@/router/axios';
+import website from "@/config/website";
+
+export const loginByUsername = (tenantId, username, password, type, key, code) => request({
+ url: '/api/blade-auth/oauth/token',
+ method: 'post',
+ headers: {
+ 'Tenant-Id': tenantId,
+ 'Captcha-Key': key,
+ 'Captcha-Code': code,
+ },
+ params: {
+ tenantId,
+ username,
+ password,
+ grant_type: (website.captchaMode ? "captcha" : "password"),
+ scope: "all",
+ type
+ }
+});
+
+export const loginBySocial = (tenantId, source, code, state) => request({
+ url: '/api/blade-auth/oauth/token',
+ method: 'post',
+ headers: {
+ 'Tenant-Id': tenantId
+ },
+ params: {
+ tenantId,
+ source,
+ code,
+ state,
+ grant_type: "social",
+ scope: "all",
+ }
+})
+
+export const refreshToken = (refresh_token, tenantId) => request({
+ url: '/api/blade-auth/oauth/token',
+ method: 'post',
+ headers: {
+ 'Tenant-Id': tenantId
+ },
+ params: {
+ tenantId,
+ refresh_token,
+ grant_type: "refresh_token",
+ scope: "all",
+ }
+});
+
+export const getButtons = () => request({
+ url: '/api/blade-system/menu/buttons',
+ method: 'get'
+});
+
+export const getCaptcha = () => request({
+ url: '/api/blade-auth/oauth/captcha',
+ method: 'get'
+});
+
+export const logout = () => request({
+ url: '/api/blade-auth/oauth/logout',
+ method: 'get'
+});
+
+export const getUserInfo = () => request({
+ url: '/api/blade-auth/oauth/user-info',
+ method: 'get'
+});
+
+export const sendLogs = (list) => request({
+ url: '/api/blade-auth/oauth/logout',
+ method: 'post',
+ data: list
+});
+
+export const clearCache = () => request({
+ url: '/api/blade-auth/oauth/clear-cache',
+ method: 'get'
+});
\ No newline at end of file
diff --git a/src/config/website.js b/src/config/website.js
new file mode 100644
index 0000000..4e011b5
--- /dev/null
+++ b/src/config/website.js
@@ -0,0 +1,43 @@
+/**
+ * 全局配置文件
+ */
+
+var fistPage = {
+ label: "首页",
+ value: "/layout/home",
+ params: {},
+ query: {},
+ meta: {
+ i18n: 'dashboard'
+ },
+ group: [],
+ close: false
+}
+
+export default {
+ title: "保安员考试大屏",
+ logo: "S",
+ key: 'saber',
+ indexTitle: '保安员考试大屏',
+ clientId: 'saber',
+ clientSecret: 'saber_secret',
+ tenantMode: true,
+ tenantId: "000000",
+ captchaMode: false,
+ lockPage: '/lock',
+ tokenTime: 3000,
+ tokenHeader: 'Blade-Auth',
+ statusWhiteList: [],
+ isFirstPage: false,
+ fistPage: fistPage,
+ menu: {
+ iconDefault: 'iconfont icon-caidan',
+ props: {
+ label: 'name',
+ path: 'path',
+ icon: 'source',
+ children: 'children'
+ }
+ },
+ authUrl: 'http://localhost/blade-auth/oauth/render',
+}
diff --git a/src/permission.js b/src/permission.js
index a696a51..8d8cd90 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -1,40 +1,35 @@
-/*
- * @Author: shuishen 1109946754@qq.com
- * @Date: 2022-08-18 16:16:10
- * @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2023-05-04 11:09:35
- * @FilePath: \web\bigScreen\src\permission.js
- * @Description: 路由守卫
- *
- * Copyright (c) 2022 by shuishen 1109946754@qq.com, All Rights Reserved.
- */
import router from "@/router/page/index";
+import store from './store'
import { getToken } from "./utils/auth";
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+
+NProgress.configure({showSpinner: false});
router.beforeEach((to, from, next) => {
- // window._axiosPromiseArr && window._axiosPromiseArr.length && window._axiosPromiseArr.forEach((ele, index) => {
- // ele.cancel()
- // delete window._axiosPromiseArr[index]
- // console.clear()
- // })
-
const meta = to.meta || {};
- next();
- // if (getToken()) {
- // if (to.path === '/login') { // 如果登录成功访问登录页跳转到主页
- // next({
- // path: '/'
- // })
- // } else {
- // next()
- // }
- // } else {
- // // 判断是否需要认证,没有登录访问去登录页
- // if (meta.isAuth === false) {
- // next()
- // } else {
- // window.open('https://sk.hubeishuiyi.cn/business/', "_self")
- // }
- // }
+ if (getToken()) {
+ if (to.path === '/login') {
+ next({ path: '/layout/home' })
+ } else {
+ 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();
+});
\ No newline at end of file
diff --git a/src/router/axios.js b/src/router/axios.js
index 9314419..d57ab12 100644
--- a/src/router/axios.js
+++ b/src/router/axios.js
@@ -1,40 +1,42 @@
-/*
- * @Author: shuishen 1109946754@qq.com
- * @Date: 2022-07-29 15:19:13
- * @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2023-04-21 10:16:58
- * @FilePath: \web\bigScreen\src\router\axios.js
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-/**
- * 全站http配置
- *
- * axios参数说明
- * isSerialize是否开启form表单提交
- * isToken是否需要token
- */
import axios from "axios";
+import store from '@/store/';
+import router from '@/router/page';
+import { getToken } from '@/utils/auth';
+import { MessageBox } from 'element-ui';
+import website from '@/config/website';
+import { Base64 } from 'js-base64';
+import NProgress from 'nprogress';
+import 'nprogress/nprogress.css';
-// 调用后台管理的
const service = axios.create({
- timeout: 600000, // request timeout
+ timeout: 600000,
});
-// 返回其他状态码
service.defaults.validateStatus = function (status) {
return status >= 200 && status <= 500;
};
-// 跨域请求,允许保存cookie
-// service.defaults.withCredentials = true
+service.defaults.withCredentials = true;
-// http request拦截
+NProgress.configure({
+ showSpinner: false
+});
+
service.interceptors.request.use(
(config) => {
- if (config.apiKey) {
- config.headers["apikey"] =
- "F1DBECD719108635189480CF60E6553ADB3109616426BD537F25A430DFC613B491A025C4A51E77FD08C6E5B7CBE05917A461286E7B6D69F1AB1B14F946149D2065B0C675F8FEDF4B9B05C1496881BC5A";
+ NProgress.start();
+ const meta = (config.meta || {});
+ const isToken = meta.isToken === false;
+ config.headers['Authorization'] = `Basic ${Base64.encode(`${website.clientId}:${website.clientSecret}`)}`;
+
+ if (getToken() && !isToken) {
+ config.headers[website.tokenHeader] = 'bearer ' + getToken()
}
+
+ if (config.text === true) {
+ config.headers["Content-Type"] = "text/plain";
+ }
+
config.cancelToken = new axios.CancelToken((cancel) => {
window._axiosPromiseArr.push({ cancel });
});
@@ -46,10 +48,25 @@
}
);
-// http response 拦截
service.interceptors.response.use(
(res) => {
- const code = res.data.code;
+ NProgress.done();
+ const status = res.data.code || res.status;
+ const statusWhiteList = website.statusWhiteList || [];
+ const message = res.data.msg || res.data.error_description || '未知错误';
+
+ if (statusWhiteList.includes(status)) return Promise.reject(res);
+
+ if (status === 401) {
+ store.dispatch('FedLogOut').then(() => {
+ router.push({ path: '/login' });
+ });
+ }
+
+ if (status !== 200 && status !== 201) {
+ MessageBox.alert(message);
+ return Promise.reject(new Error(message))
+ }
if (res.data.resultList && res.data.resultList.length > 0) {
res.data.resultList = res.data.resultList.map((item) => {
@@ -68,8 +85,9 @@
return res;
},
(error) => {
+ NProgress.done();
return Promise.reject(new Error(error));
}
);
-export default service;
+export default service;
\ No newline at end of file
diff --git a/src/router/page/index.js b/src/router/page/index.js
index 68e104c..4ed01e3 100644
--- a/src/router/page/index.js
+++ b/src/router/page/index.js
@@ -1,10 +1,3 @@
-/*
- * @Author: Morpheus
- * @Date: 2021-04-30 14:12:09
- * @Last Modified by: Morpheus
- * @Last Modified time: 2022-07-29 09:15:23
- */
-
import Vue from 'vue'
import VueRouter from 'vue-router'
@@ -14,11 +7,20 @@
const home = () => import('../../views/home/index.vue')
const home_02 = () => import('../../views/home/index_02.vue')
const home_03 = () => import('../../views/home/index_03.vue')
+const login = () => import('../../views/login/index.vue')
const routes = [
{
path: '/',
- redirect: '/layout'
+ redirect: '/login'
+ },
+ {
+ path: '/login',
+ meta: {
+ title: '登录',
+ isAuth: false
+ },
+ component: login,
},
{
path: '/layout',
@@ -52,7 +54,6 @@
}
]
},
-
{
path: '/ssjk',
meta: {
@@ -60,7 +61,6 @@
},
component: () => import('../../views/ywsys/index.vue'),
},
-
{
path: '/csmodel',
meta: {
@@ -75,4 +75,4 @@
routes
})
-export default router
+export default router
\ No newline at end of file
diff --git a/src/store/getters.js b/src/store/getters.js
index e266fa4..c0bfcf0 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -1,16 +1,13 @@
-/*
- * @Author: shuishen 1109946754@qq.com
- * @Date: 2023-03-02 16:36:47
- * @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2023-04-04 10:54:12
- * @FilePath: \srs-police-affairs\src\store\getters.js
- * @Description:
- *
- * Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
- */
const getters = {
examId: (state) => state.user.examId,
isShowVideoDialog: (state) => state.user.isShowVideoDialog,
+ token: (state) => state.user.token,
+ userInfo: (state) => state.user.userInfo,
+ tenantId: (state) => state.user.tenantId,
+ permission: (state) => state.user.permission,
+ roles: (state) => state.user.roles,
+ menu: (state) => state.user.menu,
+ menuAll: (state) => state.user.menuAll,
}
-export default getters
+export default getters
\ No newline at end of file
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index a47c8a6..0941f4a 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -1,31 +1,249 @@
-/*
- * @Author: shuishen 1109946754@qq.com
- * @Date: 2022-12-27 09:33:01
- * @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2023-04-02 12:18:26
- * @FilePath: \srs-police-affairs\src\store\modules\user.js
- * @Description:
- *
- * Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
- */
+import { setToken, setRefreshToken, removeToken, removeRefreshToken } from '@/utils/auth'
+import { Message } from 'element-ui'
+import { setStore, getStore } from '@/utils/store'
+import { isURL, validatenull } from '@/utils/validate'
+import { deepClone } from '@/utils/tool'
+import website from '@/config/website'
+import { loginByUsername, loginBySocial, getUserInfo, logout, refreshToken, getButtons } from '@/api/user'
+import md5 from 'js-md5'
-const user = {
- state: {
- examId: '',
- isShowVideoDialog: ''
- },
- actions: {
-
- },
- mutations: {
- SET_EXAMID: (state, active) => {
- state.examId = active
- },
-
- SET_ISSHOWVIDEODIALOG: (state, active) => {
- state.isShowVideoDialog = active
- },
- }
+function addPath(ele, first) {
+ const menu = website.menu;
+ const propsConfig = menu.props;
+ const propsDefault = {
+ label: propsConfig.label || 'name',
+ path: propsConfig.path || 'path',
+ icon: propsConfig.icon || 'icon',
+ children: propsConfig.children || 'children'
+ }
+ const icon = ele[propsDefault.icon];
+ ele[propsDefault.icon] = validatenull(icon) ? menu.iconDefault : icon;
+ const isChild = ele[propsDefault.children] && ele[propsDefault.children].length !== 0;
+ if (!isChild) ele[propsDefault.children] = [];
+ if (!isChild && first && !isURL(ele[propsDefault.path])) {
+ ele[propsDefault.path] = ele[propsDefault.path] + '/index'
+ } else {
+ ele[propsDefault.children].forEach(child => {
+ addPath(child);
+ })
+ }
}
-export default user
+const user = {
+ state: {
+ tenantId: getStore({ name: 'tenantId' }) || '',
+ userInfo: getStore({ name: 'userInfo' }) || [],
+ permission: getStore({ name: 'permission' }) || {},
+ roles: [],
+ menuId: {},
+ menu: getStore({ name: 'menu' }) || [],
+ menuAll: getStore({ name: 'menuAll' }) || [],
+ token: getStore({ name: 'token' }) || '',
+ refreshToken: getStore({ name: 'refreshToken' }) || '',
+ hideHome: false,
+ examId: '',
+ isShowVideoDialog: ''
+ },
+ actions: {
+ LoginByUsername({ commit }, userInfo) {
+ return new Promise((resolve, reject) => {
+ loginByUsername(userInfo.tenantId, userInfo.username, md5(userInfo.password), userInfo.type, userInfo.key, userInfo.code).then(res => {
+ const data = res.data;
+ if (data.error_description) {
+ Message({
+ message: data.error_description,
+ type: 'error'
+ })
+ } else {
+ commit('SET_TOKEN', data.access_token);
+ commit('SET_REFRESH_TOKEN', data.refresh_token);
+ commit('SET_TENANT_ID', data.tenant_id);
+ commit('SET_USER_INFO', data);
+ commit('DEL_ALL_TAG');
+ commit('CLEAR_LOCK');
+ }
+ resolve(data);
+ }).catch(error => {
+ reject(error);
+ })
+ })
+ },
+ LoginByPhone({ commit }, userInfo) {
+ return new Promise((resolve) => {
+ loginByUsername(userInfo.phone, userInfo.code).then(res => {
+ const data = res.data.data;
+ commit('SET_TOKEN', data);
+ commit('DEL_ALL_TAG');
+ commit('CLEAR_LOCK');
+ resolve();
+ })
+ })
+ },
+ LoginBySocial({ commit }, userInfo) {
+ return new Promise((resolve) => {
+ loginBySocial(userInfo.tenantId, userInfo.source, userInfo.code, userInfo.state).then(res => {
+ const data = res.data;
+ if (data.error_description) {
+ Message({
+ message: data.error_description,
+ type: 'error'
+ })
+ } else {
+ commit('SET_TOKEN', data.access_token);
+ commit('SET_REFRESH_TOKEN', data.refresh_token);
+ commit('SET_USER_INFO', data);
+ commit('DEL_ALL_TAG');
+ commit('CLEAR_LOCK');
+ }
+ resolve();
+ })
+ })
+ },
+ GetUserInfo({ commit }) {
+ return new Promise((resolve, reject) => {
+ getUserInfo().then((res) => {
+ const data = res.data.data;
+ commit('SET_ROLES', data.roles);
+ resolve(data);
+ }).catch(err => {
+ reject(err);
+ })
+ })
+ },
+ refreshToken({ state, commit }) {
+ return new Promise((resolve, reject) => {
+ refreshToken(state.refreshToken, state.tenantId).then(res => {
+ const data = res.data;
+ commit('SET_TOKEN', data.access_token);
+ commit('SET_REFRESH_TOKEN', data.refresh_token);
+ resolve();
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ LogOut({ commit }) {
+ return new Promise((resolve, reject) => {
+ logout().then(() => {
+ commit('SET_TOKEN', '');
+ commit('SET_MENU', []);
+ commit('SET_MENU_ALL_NULL', []);
+ commit('SET_ROLES', []);
+ commit('SET_TAG_LIST', []);
+ commit('DEL_ALL_TAG');
+ commit('CLEAR_LOCK');
+ removeToken();
+ removeRefreshToken();
+ resolve();
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ FedLogOut({ commit }) {
+ return new Promise(resolve => {
+ commit('SET_TOKEN', '');
+ commit('SET_MENU_ALL_NULL', []);
+ commit('SET_MENU', []);
+ commit('SET_ROLES', []);
+ commit('SET_TAG_LIST', []);
+ commit('DEL_ALL_TAG');
+ commit('CLEAR_LOCK');
+ removeToken();
+ removeRefreshToken();
+ resolve();
+ })
+ },
+ GetButtons({ commit }) {
+ return new Promise((resolve) => {
+ getButtons().then(res => {
+ const data = res.data.data;
+ commit('SET_PERMISSION', data);
+ resolve();
+ })
+ })
+ },
+ },
+ mutations: {
+ set_hideHome: (state, val) => {
+ state.hideHome = val;
+ },
+ SET_TOKEN: (state, token) => {
+ setToken(token);
+ state.token = token;
+ setStore({ name: 'token', content: state.token })
+ },
+ SET_MENU_ID(state, menuId) {
+ state.menuId = menuId;
+ },
+ SET_MENU_ALL: (state, menuAll) => {
+ let menu = state.menuAll;
+ menuAll.forEach(ele => {
+ if (!menu.find(item => item.label === ele.label && item.path === ele.path)) {
+ menu.push(ele);
+ }
+ })
+ state.menuAll = menu
+ setStore({ name: 'menuAll', content: state.menuAll })
+ },
+ SET_MENU_ALL_NULL: (state) => {
+ state.menuAll = []
+ setStore({ name: 'menuAll', content: state.menuAll })
+ },
+ SET_MENU: (state, menu) => {
+ state.menu = menu
+ setStore({ name: 'menu', content: state.menu })
+ },
+ SET_REFRESH_TOKEN: (state, refreshToken) => {
+ setRefreshToken(refreshToken)
+ state.refreshToken = refreshToken;
+ setStore({ name: 'refreshToken', content: state.refreshToken })
+ },
+ SET_TENANT_ID: (state, tenantId) => {
+ state.tenantId = tenantId;
+ setStore({ name: 'tenantId', content: state.tenantId })
+ },
+ SET_USER_INFO: (state, userInfo) => {
+ if (validatenull(userInfo.avatar)) {
+ userInfo.avatar = "http://61.131.136.25:2081/zhba/upload/picture/mrtx.png";
+ }
+ state.userInfo = userInfo;
+ setStore({ name: 'userInfo', content: state.userInfo })
+ },
+ SET_ROLES: (state, roles) => {
+ state.roles = roles;
+ },
+ SET_PERMISSION: (state, permission) => {
+ let result = [];
+
+ function getCode(list) {
+ list.forEach(ele => {
+ if (typeof (ele) === 'object') {
+ const chiildren = ele.children;
+ const code = ele.code;
+ if (chiildren) {
+ getCode(chiildren)
+ } else {
+ result.push(code);
+ }
+ }
+ })
+ }
+
+ getCode(permission);
+ state.permission = {};
+ result.forEach(ele => {
+ state.permission[ele] = true;
+ });
+ setStore({ name: 'permission', content: state.permission })
+ },
+ SET_EXAMID: (state, active) => {
+ state.examId = active
+ },
+ SET_ISSHOWVIDEODIALOG: (state, active) => {
+ state.isShowVideoDialog = active
+ },
+ }
+}
+
+export default user
\ No newline at end of file
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 8bcdd61..29e8b7d 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -3,6 +3,7 @@
@import "./icon/index.scss";
@import "./tool/index.scss";
@import "./element-ui/element-ui.scss";
+@import "./login.scss";
@font-face {
font-family: Roboto-Bold;
diff --git a/src/styles/login.scss b/src/styles/login.scss
new file mode 100644
index 0000000..e616f24
--- /dev/null
+++ b/src/styles/login.scss
@@ -0,0 +1,157 @@
+html, body, #app {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+.login-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background-image: url("/images/pro-bg.png");
+ background-size: cover;
+ background-position: center;
+}
+
+.login-weaper {
+ display: flex;
+ width: 800px;
+ box-shadow: -4px 5px 20px rgba(0, 0, 0, 0.3);
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.login-left,
+.login-border {
+ min-height: 450px;
+ display: flex;
+ align-items: center;
+}
+
+.login-left {
+ border-top-left-radius: 8px;
+ border-bottom-left-radius: 8px;
+ justify-content: center;
+ flex-direction: column;
+ background: linear-gradient(135deg, #409eff 0%, #67b8ff 100%);
+ color: #fff;
+ width: 45%;
+ padding: 30px;
+ box-sizing: border-box;
+}
+
+.login-time {
+ position: absolute;
+ top: 30px;
+ left: 30px;
+ color: rgba(255, 255, 255, 0.9);
+ font-weight: 300;
+ font-size: 16px;
+}
+
+.login-left .img {
+ width: 120px;
+ margin-bottom: 20px;
+}
+
+.login-left .title {
+ text-align: center;
+ color: #fff;
+ font-weight: 400;
+ letter-spacing: 3px;
+ font-size: 22px;
+ margin: 0;
+}
+
+.login-border {
+ border-top-right-radius: 8px;
+ border-bottom-right-radius: 8px;
+ background-color: #fff;
+ width: 55%;
+ padding: 40px 30px;
+ box-sizing: border-box;
+}
+
+.login-main {
+ width: 100%;
+}
+
+.login-title {
+ color: #333;
+ margin-bottom: 8px;
+ font-weight: 500;
+ font-size: 20px;
+ text-align: center;
+ letter-spacing: 2px;
+}
+
+.login-title-child {
+ color: #999;
+ margin-bottom: 30px;
+ font-weight: 300;
+ font-size: 12px;
+ text-align: center;
+ letter-spacing: 1px;
+}
+
+.login-form {
+ margin: 0;
+
+ .el-form-item {
+ margin-bottom: 20px;
+ }
+
+ .el-input {
+ input {
+ padding: 12px 15px;
+ border: 1px solid #e4e7ed;
+ border-radius: 6px;
+ font-size: 14px;
+ transition: border-color 0.3s;
+
+ &:focus {
+ border-color: #409eff;
+ outline: none;
+ }
+ }
+
+ .el-input__prefix {
+ i {
+ color: #909399;
+ font-size: 16px;
+ }
+ }
+
+ .el-input__suffix {
+ i {
+ color: #909399;
+ cursor: pointer;
+ }
+ }
+ }
+}
+
+.login-submit {
+ width: 100%;
+ height: 42px;
+ background: linear-gradient(135deg, #409eff 0%, #67b8ff 100%);
+ border: none;
+ border-radius: 6px;
+ font-size: 16px;
+ letter-spacing: 2px;
+ color: #fff;
+ cursor: pointer;
+ margin-top: 10px;
+ transition: opacity 0.3s;
+
+ &:hover {
+ opacity: 0.9;
+ }
+
+ &:active {
+ opacity: 0.8;
+ }
+}
\ No newline at end of file
diff --git a/src/utils/tool.js b/src/utils/tool.js
index 2610f3f..ba4b18a 100644
--- a/src/utils/tool.js
+++ b/src/utils/tool.js
@@ -1,42 +1,45 @@
-/*
- * @Author: shuishen 1109946754@qq.com
- * @Date: 2022-10-17 09:34:19
- * @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2022-10-17 09:45:20
- * @FilePath: \srs-police-affairs\src\utils\tool.js
- * @Description:
- *
- * Copyright (c) 2022 by shuishen 1109946754@qq.com, All Rights Reserved.
- */
function executeFunction (callbackArray, amount) {
return new Promise(function (resolve, reject) {
let index = 0
-
let currentIndex = 1
function execute () {
-
try {
callbackArray[index]()
index++
} catch (e) {
-
return new Error(e)
-
} finally {
-
if (currentIndex == callbackArray.length) {
resolve
}
-
execute()
currentIndex++
}
-
}
-
execute()
})
}
+export function deepClone(obj) {
+ if (obj === null || typeof obj !== 'object') {
+ return obj
+ }
+ if (obj instanceof Date) {
+ return new Date(obj.getTime())
+ }
+ if (obj instanceof Array) {
+ return obj.map(item => deepClone(item))
+ }
+ if (typeof obj === 'object') {
+ const clonedObj = {}
+ for (let key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ clonedObj[key] = deepClone(obj[key])
+ }
+ }
+ return clonedObj
+ }
+}
+
export default executeFunction
\ No newline at end of file
diff --git a/src/views/home/index.vue b/src/views/home/index.vue
index 94ef738..bf51829 100644
--- a/src/views/home/index.vue
+++ b/src/views/home/index.vue
@@ -235,7 +235,7 @@
// 点击播放视频
openVideoPlayer () {
- this.$store.commit("SET_ISSHOWVIDEODIALOG", true)
+ // this.$store.commit("SET_ISSHOWVIDEODIALOG", true)
},
},
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..ac7b1c2
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,58 @@
+<template>
+ <div class="login-container" ref="login" @keyup.enter.native="handleLogin">
+ <div class="login-weaper">
+ <div class="login-left">
+ <div class="login-time">
+ {{ time }}
+ </div>
+ <img class="img" src="/images/logo.png" alt="" />
+ <p class="title">保安员考试大屏</p>
+ </div>
+ <div class="login-border">
+ <div class="login-main">
+ <h4 class="login-title">
+ 系统登录
+ </h4>
+ <h4 class="login-title-child">Security Guard Exam System</h4>
+ <userLogin></userLogin>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+<script>
+import userLogin from "./userlogin";
+import { dateFormat } from "@/utils/date";
+
+export default {
+ name: "login",
+ components: {
+ userLogin,
+ },
+ data() {
+ return {
+ time: "",
+ };
+ },
+ created() {
+ document.title = "保安员考试大屏"
+ this.$store.commit("SET_WEBTITLE", '保安员考试大屏')
+ this.getTime();
+ },
+ mounted() {},
+ props: [],
+ methods: {
+ getTime() {
+ setInterval(() => {
+ this.time = dateFormat(new Date());
+ }, 1000);
+ },
+ handleLogin() {
+ },
+ },
+};
+</script>
+
+<style lang="scss">
+@import "@/styles/login.scss";
+</style>
\ No newline at end of file
diff --git a/src/views/login/userlogin.vue b/src/views/login/userlogin.vue
new file mode 100644
index 0000000..d123477
--- /dev/null
+++ b/src/views/login/userlogin.vue
@@ -0,0 +1,82 @@
+<template>
+ <el-form class="login-form" status-icon :rules="loginRules" ref="loginForm" :model="loginForm" label-width="0">
+ <el-form-item prop="username">
+ <el-input size="small" @keyup.enter.native="handleLogin" v-model="loginForm.username" auto-complete="off"
+ placeholder="请输入用户名">
+ <i slot="prefix" class="fa fa-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="fa fa-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>
+</template>
+
+<script>
+import {Message} from "element-ui";
+
+export default {
+ name: "userlogin",
+ data() {
+ return {
+ loginForm: {
+ tenantId: "000000",
+ username: "",
+ password: "",
+ type: "account",
+ },
+ loginRules: {
+ username: [
+ {required: true, message: "请输入用户名", trigger: "blur"},
+ ],
+ password: [
+ {required: true, message: "请输入密码", trigger: "blur"},
+ {min: 6, message: "密码长度最少为6位", trigger: "blur"},
+ ],
+ },
+ passwordType: "password",
+ }
+ },
+ mounted() {
+ },
+ methods: {
+ showPassword() {
+ this.passwordType = this.passwordType === "password" ? "" : "password"
+ },
+ handleLogin() {
+ this.$refs.loginForm.validate((valid) => {
+ if (valid) {
+ const loading = this.$loading({
+ lock: true,
+ text: "登录中,请稍后...",
+ spinner: "el-icon-loading",
+ })
+ this.$store
+ .dispatch("LoginByUsername", this.loginForm)
+ .then((data) => {
+ if (data.error_description) {
+ loading.close()
+ }else{
+ this.$router.push({path: '/layout/home'})
+ loading.close()
+ }
+ })
+ .catch(() => {
+ loading.close()
+ })
+ }
+ })
+ },
+ },
+}
+</script>
+
+<style></style>
\ No newline at end of file
diff --git a/vue.config.js b/vue.config.js
index 23c92f8..d1a4338 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -29,36 +29,6 @@
scss: {
prependData: `@import "~@/styles/scssFile.scss";`,
},
- // postcss: {
- // plugins: [ //配置px转rem进行适配
- // require('postcss-px2rem')({
- // // 根标签字号大小根据设计稿宽度/flexible.js里的份数得到,这里假定设计稿宽度为3840 3840/24 = 160px
- // remUnit: 80
- // }),
- // ]
- // }
- // postcss: {
- // //给postcss-loader传递选项
- // plugins: [
- // new pxtovw({
- // unitToConvert: 'px', //需要转换的单位,默认为"px";
- // viewportWidth: 1920, //设计稿的视口宽度
- // viewportHeight: 1080, //设计稿的视口宽度
- // unitPrecision: 5, //单位转换后保留的小数位数
- // propList: ['*'], //要进行转换的属性列表,*表示匹配所有,!表示不转换
- // viewportUnit: 'vw', //转换后的视口单位
- // fontViewportUnit: 'vw', //转换后字体使用的视口单位
- // selectorBlackList: [], //不进行转换的css选择器,继续使用原有单位
- // minPixelValue: 1, //设置最小的转换数值
- // mediaQuery: false, //设置媒体查询里的单位是否需要转换单位
- // replace: true, //是否直接更换属性值,而不添加备用属性
- // exclude: [/node_modules/], //忽略某些文件夹下的文件
- // // landscape: true,
- // // landscapeUnit: 'vw',
- // // landscapeWidth: 1920
- // })
- // ]
- // }
},
},
@@ -94,11 +64,6 @@
}
],
])
-
- // config.plugin("define").tap((args) => {
- // args[0]["process"] = { ...args[0]["process.env"] }
- // return args
- // })
},
configureWebpack: {
@@ -125,56 +90,19 @@
maxChunks: 5,
minChunkSize: 100,
}),
- // 提供带 Content-Encoding 编码的压缩版的资源
- // new CompressionPlugin({
- // algorithm: 'gzip',
- // test: /\.js$|\.html$|\.css/, // 匹配文件名
- // // test: /\.(js|css)$/,
- // threshold: 10240, // 对超过10k的数据压缩
- // deleteOriginalAssets: false, // 不删除源文件
- // minRatio: 0.8 // 压缩比
- // })
],
},
devServer: {
- // open: false, // 编译完成是否打开网页
- // host: "0.0.0.0", // 指定使用地址,默认localhost,0.0.0.0代表可以被外界访问
- // // port: 82, // 访问端口
- // https: false, // 编译失败时刷新页面
- // hot: true, // 开启热加载
- // hotOnly: false,
- // proxy: {
- // [process.env.VUE_APP_API]: {//拦截器(拦截链接中有/api)
- // target: process.env.VUE_API_DEV_TARGET,//'http://192.168.1.114:3000', //process.env.VUE_API_DEV_TARGET, //API服务器的地址
- // changeOrigin: true,
- // pathRewrite: {
- // //'^/api': '/'
- // [`^${process.env.VUE_APP_API}`]: '',
- // //[`^${process.env.VUE_APP_API}`]: '/', //配置出来的接口没有 /api
- // }
- // }
- // }
proxy: {
-
- // 中台接口
- "/services": {
- target: "https://sk.hubeishuiyi.cn",
- changeOrigin: true, //开启代理跨域
- // pathRewrite: {
- // "^/services": "/",
- // },
- },
// 业务平台接口
"/api": {
// target用于配置你允许访问数据的计算机名称,即是你的api接口的服务器地址
- target: "http://60.220.177.113:2081",
+ target: "http://124.164.10.118:2081",
// target: "http://192.168.0.102:81",
// ws: true, //启用webSocket6566
changeOrigin: true, //开启代理跨域
- // pathRewrite: {//本地地址没有api需要去掉
- // '^/api': '/'
- // }
+ pathRewrite: {}//后端接口包含/api前缀,不需要重写
},
},
},
--
Gitblit v1.9.3