| | |
| | | "autofit.js": "^3.0.4",
|
| | | "axios": "^1.5.0",
|
| | | "core-js": "^2.6.5",
|
| | | "crypto-js": "^4.2.0",
|
| | | "echarts": "^5.5.0",
|
| | | "element-ui": "^2.15.14",
|
| | | "ezuikit-js": "^7.7.10",
|
| | |
| | | const router = createRouter()
|
| | |
|
| | | // 路由守卫
|
| | | // router.beforeEach((to, from, next) => {
|
| | | // const token = store.state.token
|
| | | // if (!token && to.path != '/') {
|
| | | // // 如果没有 token 并且不是去登录页,重定向到登录页
|
| | | // next('/')
|
| | | // } else if (token && to.path === '/') {
|
| | | // // 如果有 token 并且要去登录页,重定向到首页
|
| | | // next('/home')
|
| | | // } else {
|
| | | // // 清理 localStorage
|
| | | // localStorage.removeItem('registerForm')
|
| | | // next()
|
| | | // }
|
| | | // })
|
| | | router.beforeEach((to, from, next) => {
|
| | | const token = store.state.token
|
| | | if (!token && to.path != '/') {
|
| | | // 如果没有 token 并且不是去登录页,重定向到登录页
|
| | | next('/')
|
| | | } else if (token && to.path === '/') {
|
| | | // 如果有 token 并且要去登录页,重定向到首页
|
| | | next('/home')
|
| | | } else {
|
| | | // 清理 localStorage
|
| | | localStorage.removeItem('registerForm')
|
| | | next()
|
| | | }
|
| | | })
|
| | |
|
| | | export default router
|
| | |
| | | export default new Vuex.Store({
|
| | | state: {
|
| | | token: localStorage.getItem('token') || sessionStorage.getItem('token') || '',
|
| | | userInfo: {}
|
| | | userInfo: localStorage.getItem('userInfo') || {}
|
| | | },
|
| | | mutations: {
|
| | | setToken(state, token) {
|
| | |
| | | },
|
| | | clearToken(state) {
|
| | | state.token = '';
|
| | | state.userInfo = {}
|
| | | localStorage.clear();
|
| | | sessionStorage.clear();
|
| | | },
|
| | | setUserInfo(state, userInfo) {
|
| | | state.userInfo = userInfo;
|
| | | localStorage.setItem('userInfo', userInfo)
|
| | | }
|
| | | },
|
| | | actions: {},
|
| | |
| | | const apiConfig = { |
| | | // 开发环境 |
| | | development: { |
| | | baseURL: "", |
| | | baseURL: "http://192.168.110.85:9000", |
| | | mapKey: "67968c82f27c7e2cb9f40c1a9aa3042b", |
| | | secretKey: "37ce61ae86efa5ad82b649a277f5097c", |
| | | }, |
| | |
| | | import axios from 'axios'
|
| | | import apiConfig from './baseurl'
|
| | | import store from '@/store' // 导入 Vuex store
|
| | | import CryptoJS from 'crypto-js';
|
| | |
|
| | | import {
|
| | | Message
|
| | |
| | | withCredentials: false, // 当跨域请求时发送cookie
|
| | | timeout: 30000, // request timeout
|
| | | })
|
| | | // 对 POST 请求参数进行排序
|
| | | const sortPostParams = (params) => {
|
| | | const keys = Object.keys(params);
|
| | |
|
| | | keys.sort((a, b) => {
|
| | | for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
| | | const asciiA = a.charCodeAt(i);
|
| | | const asciiB = b.charCodeAt(i);
|
| | |
|
| | | if (asciiA !== asciiB) {
|
| | | return asciiA - asciiB;
|
| | | }
|
| | | }
|
| | |
|
| | | // 如果两个字符串长度不同,则较短的字符串排在前面
|
| | | return a.length - b.length;
|
| | | });
|
| | |
|
| | | const sortedParams = {};
|
| | | keys.forEach(key => {
|
| | | sortedParams[key] = params[key];
|
| | | });
|
| | |
|
| | | return sortedParams;
|
| | | }
|
| | | //去除对象中空值的属性
|
| | | const removeEmptyProperties = (obj) => {
|
| | | return Object.fromEntries(Object.entries(obj).filter(([key, value]) => value !== undefined && value !== null && value !== '' && (Array.isArray(value) ? value.length > 0 : true)));
|
| | | };
|
| | | // 将对象转换为字符串用&拼接
|
| | | const objToString = (obj) => {
|
| | | // 使用 Object.keys() 获取对象的 key 数组
|
| | | const keys = Object.keys(obj);
|
| | |
|
| | | // 使用 Array.prototype.map() 将每个 key-value 对转化为字符串
|
| | | const strArray = keys.map(key => {
|
| | |
|
| | | const value = obj[key];
|
| | | if (Array.isArray(value) || typeof value === 'object' && value !== null) {
|
| | | return '';
|
| | | } else {
|
| | | return `${key}=${value}`;
|
| | | }
|
| | | });
|
| | |
|
| | | // 使用 Array.prototype.filter() 过滤掉空字符串
|
| | | const filteredStrArray = strArray.filter(str => str !== '');
|
| | |
|
| | | // 使用 Array.prototype.join() 将字符串数组拼接成一个字符串
|
| | | const str = filteredStrArray.join('&');
|
| | | return str;
|
| | | }
|
| | | // 生成随机字符串
|
| | | const generateRandomString = (length) => {
|
| | | const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| | | const str = [];
|
| | | for (let i = 0; i < length; i++) {
|
| | | const randomIndex = Math.floor(Math.random() * chars.length);
|
| | | str.push(chars[randomIndex]);
|
| | | }
|
| | | return str.join('');
|
| | | }
|
| | | // 对字符串进行 HMAC-SHA1 加密
|
| | | const encryptWithHMACSHA1 = (message, secret) => {
|
| | | return CryptoJS.HmacSHA1(message, secret).toString(CryptoJS.enc.Base64);
|
| | | };
|
| | |
|
| | | // 请求拦截
|
| | | service.interceptors.request.use(
|
| | | config => {
|
| | | config.headers['Authorization'] = 'Bearer ' + store.state.token
|
| | | if (config.method == 'get') {
|
| | | if (!config.params) config.params = {};
|
| | | config.params = {
|
| | | ...config.params,
|
| | | const o = config
|
| | | let { data, method } = o
|
| | | const Authorization = localStorage.getItem('token') || ''
|
| | | if (method == 'post') {
|
| | | let copyData = JSON.parse(JSON.stringify(data))
|
| | | // 对 POST 请求参数进行处理
|
| | | let sortData = sortPostParams(copyData)
|
| | | sortData = removeEmptyProperties(sortData)
|
| | | // 将处理后的 POST 请求参数转换为字符串
|
| | | let strData = objToString(sortData)
|
| | | // 生成随机字符串 用作加密秘钥
|
| | | let nonce_str = generateRandomString(16)
|
| | | // 对字符串进行 HMAC-SHA1 加密 并转化为 Base64
|
| | |
|
| | | let sign = encryptWithHMACSHA1(strData, nonce_str)
|
| | | o.headers = {
|
| | | ...o.headers,
|
| | | timestamp: new Date().getTime(),
|
| | | sign,
|
| | | nonce_str,
|
| | | Authorization,
|
| | | client: localStorage.getItem('client')
|
| | | }
|
| | | } else {
|
| | | o.headers = {
|
| | | timestamp: new Date().getTime(),
|
| | | ...config.headers,
|
| | | Authorization,
|
| | | client: localStorage.getItem('client')
|
| | | }
|
| | | }
|
| | | if (config.method == 'post') {
|
| | | if (!config.data) config.data = {};
|
| | | config.data = {
|
| | | ...config.data,
|
| | | }
|
| | | }
|
| | | return config
|
| | | return { ...o };
|
| | | },
|
| | | error => {
|
| | | return Promise.reject(error)
|
| | |
| | | }
|
| | | return code;
|
| | | }
|
| | | // 生成随机字符串
|
| | | export function generateRandomString(length) {
|
| | | const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| | | const str = [];
|
| | | for (let i = 0; i < length; i++) {
|
| | | const randomIndex = Math.floor(Math.random() * chars.length);
|
| | | str.push(chars[randomIndex]);
|
| | | }
|
| | | return str.join('');
|
| | | };
|
| | |
|
| | | // 导出
|
| | | export const exportExcell = (name, params, url) => {
|
| | |
| | | <div class="mt--20 txt-center py--20 px--20 br--10 box-s1"> |
| | | <div class="fs--20 fw-bold">登陆</div> |
| | | <div class="mt--20"> |
| | | <el-input class="w100" prefix-icon="el-icon-user" placeholder="账号" v-model="account" /> |
| | | <el-input class="w100" prefix-icon="el-icon-user" placeholder="账号" v-model="username" /> |
| | | </div> |
| | | <div class="mt--20"> |
| | | <el-input prefix-icon="el-icon-lock" placeholder="密码" v-model="password" show-password /> |
| | | </div> |
| | | <div class="mt--20 flex a-center code_box"> |
| | | <div class="flex1"> |
| | | <el-input placeholder="请输入验证码" v-model="code" /> |
| | | <el-input placeholder="请输入验证码" v-model="code" /> |
| | | </div> |
| | | <div @click="resetCodeStr" class="fs--18 lh--40 border1 pointer">{{ codeStr }}</div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { generateVerificationCode } from '@/utils/utils'; |
| | | import { generateVerificationCode, generateRandomString } from '@/utils/utils'; |
| | | import { mapMutations } from 'vuex'; |
| | | import { loginPwd } from './service' |
| | | import CryptoJS from 'crypto-js'; |
| | | import { |
| | | Message |
| | | } from 'element-ui' |
| | | export default { |
| | | components: {}, |
| | | props: {}, |
| | | data() { |
| | | return { |
| | | loginLoading: false,//登录loading |
| | | account: '', |
| | | username: '', |
| | | password: '', |
| | | code: '', |
| | | codeStr: '' |
| | |
| | | document.removeEventListener("keydown", this.handleKeyDown); |
| | | }, |
| | | methods: { |
| | | ...mapMutations(['setToken', 'clearToken']), |
| | | ...mapMutations(['setToken', 'clearToken', 'setUserInfo']), |
| | | login() { |
| | | this.loginLoading = false; |
| | | // this.setToken(res.access_token); |
| | | this.$router.push('/home') |
| | | if (!this.rulesLogin()) return |
| | | this.loginLoading = true; |
| | | loginPwd({ |
| | | username: this.username, |
| | | password: CryptoJS.HmacMD5(this.password, 'password').toString( |
| | | CryptoJS.enc.Hex, |
| | | ) |
| | | }).then(res => { |
| | | localStorage.setItem('client', generateRandomString(16)); |
| | | this.loginLoading = false; |
| | | this.setToken(res.token.access_token); |
| | | this.setUserInfo(JSON.stringify(res.info.sysUser)); |
| | | this.$router.push('/home') |
| | | }).catch(() => { |
| | | this.resetCodeStr() |
| | | this.loginLoading = false; |
| | | }) |
| | | }, |
| | | rulesLogin() { |
| | | if (!this.username) { |
| | | Message({ |
| | | message: '请输入账号', |
| | | type: 'warning', |
| | | duration: 2000 |
| | | }) |
| | | return false |
| | | } |
| | | if (!this.password) { |
| | | Message({ |
| | | message: '请输入密码', |
| | | type: 'warning', |
| | | duration: 2000 |
| | | }) |
| | | return false |
| | | } |
| | | if (!this.code) { |
| | | Message({ |
| | | message: '请输入验证码', |
| | | type: 'warning', |
| | | duration: 2000 |
| | | }) |
| | | return false |
| | | } |
| | | if (!this.matchCaseInsensitive(this.codeStr, this.code)) { |
| | | Message({ |
| | | message: "验证码错误", |
| | | type: "warning", |
| | | duration: 1500, |
| | | }); |
| | | this.resetCodeStr() |
| | | return false |
| | | } |
| | | return true |
| | | }, |
| | | handleKeyDown(event) { |
| | | if (event.key === "Enter") { |
| | | this.login() |
| | | } |
| | | }, |
| | | // 校验验证码 |
| | |
| | | |
| | | // 密码登录 |
| | | export const loginPwd = (data) => { |
| | | return axios.post('/auth/companyLogin', data) |
| | | return axios.post('/auth/login', data) |
| | | } |