Compare commits

..

No commits in common. '0a3b114ebee7cfb52cd02f5aee02f2c0092899ef' and 'cf3d489d9d1b36eaeafec489d54401cea0d2cd52' have entirely different histories.

  1. 1
      package.json
  2. 16
      src/App.vue
  3. 6
      src/apis/login.js
  4. 9
      src/apis/personal.js
  5. 18
      src/layout/components/PageHeader.vue
  6. 1
      src/main.js
  7. 103
      src/mock/data.js
  8. 52
      src/mock/index.js
  9. 54
      src/mock/modules/login.js
  10. 66
      src/mock/modules/personal.js
  11. 4
      src/request/config.js
  12. 8
      src/request/index.js
  13. 11
      src/router/index.js
  14. 27
      src/store/index.js
  15. 38
      src/store/modules/user.js
  16. 31
      src/views/login/index.vue
  17. 12
      yarn.lock

@ -13,7 +13,6 @@
"@types/node": "^20.8.7", "@types/node": "^20.8.7",
"axios": "^1.5.1", "axios": "^1.5.1",
"element-plus": "^2.4.1", "element-plus": "^2.4.1",
"mockjs": "^1.1.0",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-i18n": "^9.4.1", "vue-i18n": "^9.4.1",

@ -15,15 +15,17 @@ locale.value = localStorage.getItem('locale') || 'zh-cn';
<style> <style>
html,
body { body {
height: 100%; height: 100%;
} }
#app { #app {
height: 100%; font-family: Avenir, Helvetica, Arial, sans-serif;
align-items: center; -webkit-font-smoothing: antialiased;
justify-content: center; -moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
} }
.flex-center { .flex-center {
@ -35,10 +37,4 @@ body {
.cursor { .cursor {
cursor: pointer; cursor: pointer;
} }
.txt-c {
text-align: center;
}
.w100p {
width: 100%;
}
</style> </style>

@ -1,4 +1,4 @@
import request from "@/request"; import request from "@/request/index.js";
// 登录 // 登录
export const login = (data) => { export const login = (data) => {
@ -6,5 +6,5 @@ export const login = (data) => {
url: 'login', url: 'login',
method: 'post', method: 'post',
data, data,
}); })
}; };

@ -1,9 +0,0 @@
import request from "@/request/index.js"
export const userInfo = (data) => {
return request({
url: '/personal/userinfo',
method: 'get',
data,
})
}

@ -55,13 +55,10 @@
import {Message} from '@element-plus/icons-vue' import {Message} from '@element-plus/icons-vue'
import {useI18n} from "vue-i18n"; import {useI18n} from "vue-i18n";
import {ref} from 'vue'; import {ref} from 'vue';
import {useRouter} from "vue-router"; import {useRoute} from "vue-router";
import router from "@/router/index.js"; import router from "@/router/index.js";
import store from "@/store/index.js";
import user from "@/store/modules/user.js";
// import {useStore} from "vuex";
const route = useRouter(); const route = useRoute();
const {locale, t} = useI18n(); const {locale, t} = useI18n();
function changeLanguage(lang) { function changeLanguage(lang) {
@ -69,13 +66,10 @@ function changeLanguage(lang) {
localStorage.setItem('locale', lang) localStorage.setItem('locale', lang)
} }
// const store = useStore(); const isLogin = ref(false);
const isLogin = computed(() => store.getters['user/isLogin']); const username = ref('admin');
const userInfo = computed(() => store.state.user.userInfo) const unReadCount = ref(2);
const username = computed(() => userInfo.value?.name); isLogin.value = true;
const unReadCount = computed(() => userInfo.value?.unReadCount);
store.dispatch('user/refreshInfo');
const commands = { const commands = {
toPersonal: () => { toPersonal: () => {

@ -5,7 +5,6 @@ import store from "./store/index.js";
import i18n from "./i18n/index.js"; import i18n from "./i18n/index.js";
import * as ElIcons from "@element-plus/icons-vue"; import * as ElIcons from "@element-plus/icons-vue";
import 'normalize.css/normalize.css' import 'normalize.css/normalize.css'
import "./mock"
const app = createApp(App); const app = createApp(App);

@ -1,103 +0,0 @@
export const users = [
{
name: "visitor",
roleId: 'visitor',
password: "visitor",
},
{
name: "master",
roleId: "master",
password: "master",
},
{
name: "admin",
roleId: "admin",
password: "admin",
},
];
export const menuTreeData = [
{
id: 1,
parentId: 0,
name: 'App',
path: "/app",
icon: "el-icon-menu",
children: [
{
id: 11,
parentId: 1,
name: 'AppUser',
path: "/app/user",
icon: "user",
},
{
id: 12,
parentId: 1,
name: 'AppDept',
path: "/app/dept",
icon: "office-building",
},
{
id: 13,
parentId: 1,
name: 'AppRole',
path: "/app/role",
icon: "avatar",
},
{
id: 14,
parentId: 1,
name: 'AppResource',
path: "/app/resource",
icon: "management",
},
],
},
{
id: 2,
parentId: 0,
name: 'Sys',
path: "/sys",
icon: "setting",
children: [
{
id: 21,
parentId: 2,
name: 'SysUser',
path: "/sys/user",
icon: "user-filled",
},
{
id: 22,
parentId: 2,
name: 'SysNotice',
path: "/sys/notice",
icon: "chat-dot-round",
},
],
},
{
id: 3,
parentId: 0,
name: 'Logs',
path: "/logs",
icon: "document",
children: [
{
id: 31,
parentId: 3,
name: 'LogsVisit',
path: "/logs/visit",
icon: "tickets",
},
{
id: 32,
parentId: 3,
name: 'LogsOperation',
path: "/logs/operation",
icon: "operation",
},
],
},
];

@ -1,52 +0,0 @@
import Mock from "mockjs";
import config from "@/request/config";
import * as login from "./modules/login";
import * as personal from "./modules/personal";
const { baseURL } = config;
// 1. 开启/关闭所有模块拦截, 通过openMock开关设置.
// 2. 开启/关闭单个模块拦截, 通过调用mock方法isOpen参数设置.
// 3. 开启/关闭模块中某个请求拦截, 通过函数返回对象中的isOpen属性设置.
const openMock = true;
// 模拟所有模块
// mockAll([login], openMock);
// function mockAll(modules, isOpen = true) {
// for (const k in modules) {
// mock(modules[k], isOpen);
// }
// }
// 模拟单个模块
mock(login, openMock)
mock(personal, openMock)
/**
* 创建mock模拟数据
* @param {*} mod 模块
* @param {*} isOpen 是否开启?
*/
function mock(mod, isOpen = true) {
if (isOpen) {
for (var key in mod) {
((res) => {
if (res.isOpen !== false) {
let url = baseURL;
if (!url.endsWith("/")) {
url = url + "/";
}
url = url + res.url;
Mock.mock(new RegExp(url), res.method, (opts) => {
opts.data = opts.body ? JSON.parse(opts.body) : null;
const resData = Mock.mock(
typeof res.response === "function"
? res.response(opts)
: res.response
);
console.log("%cmock拦截, 请求: ", "color:blue", opts);
console.log("%cmock拦截, 响应: ", "color:blue", resData);
return resData;
});
}
})(mod[key]() || {});
}
}
}

@ -1,54 +0,0 @@
/*
* 系统登录模块
*/
import { users } from "../data";
// 登录
export function login() {
return {
url: "login",
method: "post",
response: (opts) => {
const name = opts.data.account;
if (
users.find((v) => v.name === name && v.password === opts.data.password)
) {
return {
code: 200,
msg: "",
data: {
token: name + "@eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImV4cC",
name,
},
};
}
return {
code: -1,
msg: "用户名或密码错误",
};
},
};
}
// export function login() {
// return {
// url: "login",
// method: "post",
// response: () => {
// return {
// code: -1,
// msg: "用户名或密码不正确!",
// };
// },
// };
// }
// 登出接口
export function logout() {
return {
url: "logout",
method: "get",
response: {
code: 200,
msg: null,
data: {},
},
};
}

@ -1,66 +0,0 @@
import { users, menuTreeData } from "../data";
export function userInfo() {
return {
url: "personal/userinfo",
method: "get",
response: () => {
const token = localStorage.getItem('pm_token');
if (token) {
const uinfo = {...users.find((v) => v.name === token.split('@')[0])}
delete uinfo.password;
return {
code: 200,
data: {
...uinfo,
'unReadCount|0-10': 0
}
};
} else {
return {
code: -2,
msg: '请先登录!'
}
}
},
};
}
export function menuTree() {
return {
url: "personal/menuTree",
method: "get",
response: () => {
const token = localStorage.getItem('pm_token');
if (!token) {
return {
code: 200,
msg: ''
}
}
const name = token.split('@')[0]
const info = users.find(v => v.name === name)
const role = info.roleId;
let treeData = [menuTreeData[2]];
switch (role) {
case "admin":
treeData = menuTreeData;
break;
case "master":
treeData = [menuTreeData[0], menuTreeData[2]];
break;
case "visitor":
treeData = [menuTreeData[2]];
break;
default:
break;
}
return {
code: 200,
data: treeData,
};
},
};
}

@ -1,10 +1,10 @@
export default { export default {
method: 'get', method: 'get',
baseURL: 'http://localhost:8001', baseURL: 'http://localhost:8001',
headers: { header: {
'Content-Type': 'application/json;charset=UTF-8' 'Content-Type': 'application/json;charset=UTF-8'
}, },
timeout: 10000, timeout: 10000,
withCredentials: true, withCredentials: true,
responseType: 'json', responseType: 'json',
} }

@ -1,7 +1,7 @@
import axios from "axios"; import axios from "axios";
import config from "@/request/config.js"; import config from "@/request/config.js";
import router from "@/router"; import router from "@/router/index.js";
import { ElMessage } from 'element-plus'; import ElMessage from 'element-plus';
export default function request(options) { export default function request(options) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -12,11 +12,9 @@ export default function request(options) {
let token = localStorage.getItem('pm_token'); let token = localStorage.getItem('pm_token');
if (token) { if (token) {
config.headers.token = token; config.headers.token = token;
} else { } else {
router.push('/login') router.push('/login')
} }
return config;
}, },
(error) => { (error) => {
console.log("request:", error); console.log("request:", error);
@ -108,4 +106,4 @@ export default function request(options) {
} }
) )
}) })
} }

@ -50,16 +50,7 @@ const routes = [
name: "404", name: "404",
redirect: "/404" redirect: "/404"
} }
]; ]
const router = createRouter({history: createWebHashHistory(), routes}) const router = createRouter({history: createWebHashHistory(), routes})
router.beforeEach((to) => {
const token = localStorage.getItem("pm_token");
if (to.meta.requireAuth && !token) {
return {name: 'Login'}
}
return true;
});
export default router export default router

@ -1,27 +1,12 @@
import {createStore} from "vuex"; import {createStore} from "vuex";
import user from "./modules/user.js"
export default createStore({ export default createStore({
modules: {
user
},
state: { state: {
routeLoaded: false, // 菜单和路由是否已经加载 count: 0,
firstRoute: null, // 第一个路由,用于设置进入主页 的redirect
menuTree: null, // 菜单树
}, },
mutations: { mutations: {
// 改变菜单和路由的加载状态 increase (state, count) {
setRouteLoaded(state, loaded) { state.count += count;
state.routeLoaded = loaded; }
}, }
setFirstRoute(state, route) { })
state.firstRoute = route;
},
setMenuTree(state, data) {
state.menuTree = data
},
},
actions: {},
})

@ -1,38 +0,0 @@
import {userInfo} from "@/apis/personal.js"
import {info} from "sass";
export default {
namespaced: true,
state: {
token: '',
userInfo: {} // 用户基本信息
},
getters: {
isLogin(state) {
return !!state.token || !!localStorage.getItem("pm_token");
}
},
mutations: {
setToken(state, token) {
localStorage.setItem('pm_token', token);
state.token = token;
},
clearToken(state) {
state.token = '';
localStorage.removeItem('pm_token');
},
setUserInfo(state, info) {
state.userInfo = info || {};
},
clearUserInfo(state) {
state.userInfo = {}
}
},
actions: {
refreshInfo({commit}) {
userInfo().then(res => {
commit('setUserInfo', res.data)
})
}
}
}

@ -1,10 +1,10 @@
<template> <template>
<div class="page flex-center"> <div class="page flex-center">
<div class="sign-box"> <div class="single-box">
<el-form ref="formRef" :model="form" :rules="rules" label-width="86px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="86px">
<h3 class="title">{{ t('login') }}</h3> <h3 class="title">{{ t('login') }}</h3>
<el-form-item :label="t('form.username')" prop="account"> <el-form-item :label="t('form.username')" prop="account">
<el-input v-model="form.account" :placeholder="t('form.usernameHolder')" prefix-icon="user"></el-input> <el-input v-model="form.account" :placeholder="t('form.accountHolder')" prefix-icon="user"></el-input>
</el-form-item> </el-form-item>
<el-form-item :label="t('form.password')" prop="password"> <el-form-item :label="t('form.password')" prop="password">
<el-input v-model="form.password" type="password" :placeholder="t('form.passwordHolder')" <el-input v-model="form.password" type="password" :placeholder="t('form.passwordHolder')"
@ -27,7 +27,6 @@ import {login} from "@/apis/login.js";
import {useI18n} from "vue-i18n"; import {useI18n} from "vue-i18n";
import {useStore} from "vuex"; import {useStore} from "vuex";
import router from "@/router/index.js"; import router from "@/router/index.js";
import {ref, reactive} from "vue";
const {t} = useI18n(); const {t} = useI18n();
@ -51,13 +50,12 @@ function doLogin() {
// //
if (!valid) return; if (!valid) return;
// //
console.log('登录了');
loading.value = true loading.value = true
login(form).then((res) => { login(form).then((res) => {
store.commit("user/setToken", res.data.token); store.commit("user/setToken", res.data.token);
store.dispatch("user/refreshInfo"); store.dispatch("user/refreshInfo");
store.commit("setRouteLoaded", false); store.commit("setRouteLoaded", false);
// localStorage.setItem("pm_token", res.data.token); localStorage.setItem("pm_token", res.data.token);
router.push("/") router.push("/")
}).finally(() => { }).finally(() => {
loading.value = false; loading.value = false;
@ -67,27 +65,6 @@ function doLogin() {
</script> </script>
<style lang="scss"> <style scoped>
.page {
height: 100%;
background: url(@/assets/bg.jpg) no-repeat;
background-size: cover;
}
.sign-box {
width: 400px;
background: #ffffff;
padding: 30px 50px 20px 30px;
border-radius: 4px;
box-shadow: 0 0 10px #022c44;
}
.title {
text-align: center;
font-size: 20px;
line-height: 20px;
margin-top: 0;
margin-bottom: 10px;
color: #000000;
}
</style> </style>

@ -442,11 +442,6 @@ combined-stream@^1.0.8:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@*:
version "11.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906"
integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==
csstype@^3.1.1: csstype@^3.1.1:
version "3.1.2" version "3.1.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
@ -704,13 +699,6 @@ mlly@^1.2.0, mlly@^1.4.2:
pkg-types "^1.0.3" pkg-types "^1.0.3"
ufo "^1.3.0" ufo "^1.3.0"
mockjs@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mockjs/-/mockjs-1.1.0.tgz#e6a0c378e91906dbaff20911cc0273b3c7d75b06"
integrity sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==
dependencies:
commander "*"
ms@2.1.2: ms@2.1.2:
version "2.1.2" version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"

Loading…
Cancel
Save