完成管理页面的结构

This commit is contained in:
LittleBoy 2022-12-06 15:29:26 +08:00
parent bd903154ab
commit 07230156e6
13 changed files with 222 additions and 68 deletions

View File

@ -1,19 +1,22 @@
<template>
<div>
<button @click="showMessage">显示消息</button>
<router-view/>
</div>
</template>
<script lang="ts">
//
import message from "./components/message";
import {useUserStore} from "./service/store";
export default {
name: "App",
setup() {
useUserStore().updateInfo();
// TODO
return {
// login->index->
showMessage() {
message.toast('test display')
}

View File

@ -1,5 +1,44 @@
:root {
--primary-color: #fff;
--primary-color: #1890ff;
--primary-color-hover: #40a9ff;
--primary-color-active: #096dd9;
--primary-color-outline: rgba(24, 144, 255, .2);
--primary-1: #e6f7ff;
--primary-2: #bae7ff;
--primary-3: #91d5ff;
--primary-4: #69c0ff;
--primary-5: #40a9ff;
--primary-6: #1890ff;
--primary-7: #096dd9;
--primary-color-deprecated-l-35: #cbe6ff;
--primary-color-deprecated-l-20: #7ec1ff;
--primary-color-deprecated-t-20: #46a6ff;
--primary-color-deprecated-t-50: #8cc8ff;
--primary-color-deprecated-f-12: rgba(24, 144, 255, .12);
--primary-color-active-deprecated-f-30: rgba(230, 247, 255, .3);
--primary-color-active-deprecated-d-02: #dcf4ff;
--success-color: #52c41a;
--success-color-hover: #73d13d;
--success-color-active: #389e0d;
--success-color-outline: rgba(82, 196, 26, .2);
--success-color-deprecated-bg: #f6ffed;
--success-color-deprecated-border: #b7eb8f;
--error-color: #ff4d4f;
--error-color-hover: #ff7875;
--error-color-active: #d9363e;
--error-color-outline: rgba(255, 77, 79, .2);
--error-color-deprecated-bg: #fff2f0;
--error-color-deprecated-border: #ffccc7;
--warning-color: #faad14;
--warning-color-hover: #ffc53d;
--warning-color-active: #d48806;
--warning-color-outline: rgba(250, 173, 20, .2);
--warning-color-deprecated-bg: #fffbe6;
--warning-color-deprecated-border: #ffe58f;
--info-color: #1890ff;
--info-color-deprecated-bg: #e6f7ff;
--info-color-deprecated-border: #91d5ff;
--primary-color-text: #333;
--font-size: 14px;
--font-size-small: calc(var(--font-size) - 2px);
@ -8,12 +47,16 @@
--border-radius: 1px;
--border-radius-middle: calc(var(--border-radius) + 2px);
--border-radius-large: calc(var(--border-radius) + 3px);
--header-height: 80px;
--left-menu-width: 200px;
}
* {
margin: 0;
padding: 0;
}
*, *:before, *:after {
box-sizing: border-box;
}
@ -21,10 +64,12 @@
input[type=text], input[type=password], input[type=number], textarea {
-webkit-appearance: none;
}
[class^=p-]::-ms-clear, [class*=p-]::-ms-clear, [class^=p-] input::-ms-clear,
[class*=p-] input::-ms-clear, [class^=p-] input::-ms-reveal, [class*=p-] input::-ms-reveal {
display: none
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 'Source Han Sans SC', 'Microsoft YaHei', 'Microsoft YaHei UI', "Helvetica Neue", sans-serif;
scroll-behavior: smooth;
@ -70,6 +115,7 @@ body {
.icon-svg {
}
.pointer-cursor {
cursor: pointer;
}

View File

@ -0,0 +1,3 @@
import PInput from './input.vue'
export default PInput

View File

@ -12,4 +12,5 @@ const app = createApp(App)
// 使用路由
app.use(router)
app.use(createPinia());
// 将应用实例挂载到 模板中
app.mount('#vue-root-app')

View File

@ -3,15 +3,22 @@ import Home from '../views/admin/Home.vue'
import Login from '../views/Login.vue'
import NotFound from '../views/NotFound.vue'
import Test from '../views/Test.vue'
import AdminLayout from '../views/layout/AdminLayout.vue'
const routes: RouteRecordRaw[] = [
{
path: '/',
component: Test
component: AdminLayout,
children: [
{
path: 'home',
component: Home
},
{
path: '/home',
component: Home
path: 'test',
component: Test
}
]
},
{
path: '/login',

View File

@ -16,7 +16,8 @@ export const useTestStore = defineStore('test-store', {
},
actions: {}
})
// 保存数据的key
const TOKEN_KEY = "user-login-token";
export const useUserStore = defineStore('user-store', () => {
const userinfo = ref<AdminLoginModel>()
@ -25,11 +26,16 @@ export const useUserStore = defineStore('user-store', () => {
userinfo.value = data
}
function token() {
if (userinfo.value && userinfo.value.token) return userinfo.value.token;
return localStorage.getItem(TOKEN_KEY)
}
async function login(params: any) {
try {
const data = await http.post<AdminLoginModel>('/admin/user/login', params)
userinfo.value = data
localStorage.setItem("user-login-token", data.token)
localStorage.setItem(TOKEN_KEY, data.token)
} catch (e) {
message.toast('登录失败:' + e.message)
throw e;
@ -38,10 +44,10 @@ export const useUserStore = defineStore('user-store', () => {
async function logout() {
const data = await http.get<AdminLoginModel>('/admin/user/info')
localStorage.removeItem('user-login-token')
localStorage.removeItem(TOKEN_KEY)
userinfo.value = null
}
return {userinfo, login, logout}
return {userinfo, login, logout, updateInfo, token}
})

View File

@ -1,4 +1,6 @@
import {toast} from "../components/message";
import {useUserStore} from "../service/store";
import {useRoute, useRouter} from "vue-router";
export type HttpMethod = 'get' | 'post' | 'delete' | 'put'
@ -69,12 +71,16 @@ class Http {
}
}
const headers: any = {
'Content-Type': contentType
}
const token = useUserStore().token();
if (token) headers.token = token
const r = useRoute(), router = useRouter();
fetch(httpConfig.baseURL + url, {
method,
body: data,
headers: {
'Content-Type': contentType
}
headers,
})
.then(res => res.json()) // 只要json的响应数据
.then((res: ResponseModel<T>) => {
@ -84,6 +90,9 @@ class Http {
// 需要统一处理数据
if (code === 403) {
toast("登录凭证无效或者已过期")
if (r.fullPath != '/login') {
router.replace('/login');
}
return;
} else if (err) {
toast(httpConfig.globalErrorHandler[code])

View File

@ -2,10 +2,10 @@
<div class="login-wrapper">
<form @submit="onLogin">
<p>
<input placeholder="请输入账号" type="text" v-model="data.account">
<PInput placeholder="请输入密码" type="text" v-model="data.account"/>
</p>
<p>
<input placeholder="请输入密码" type="text" v-model="data.password">
<PInput placeholder="请输入密码" type="password" v-model="data.password"/>
</p>
<button :disabled="loading" :type="loading?'button':'submit'">{{ loading ? '正在登录' : '登录' }}</button>
</form>
@ -14,12 +14,13 @@
<script lang="ts">
import {reactive, ref} from "vue";
import http from "../util/http";
import PInput from './../components/input'
import {useUserStore} from "../service/store";
import {useRouter} from "vue-router";
export default {
name: "User",
components: {PInput},
setup() {
// vue ()
// vue2 Object.definedProperty
@ -58,7 +59,9 @@ export default {
.error {
color: red;
}
p{
margin: 10px 0;
}
.login-wrapper {
width: 500px;
margin: 50px auto;

View File

@ -20,7 +20,7 @@
</template>
<script lang="ts" setup>
import PInput from "../components/input/index.vue";
import PInput from "../components/input";
import {reactive} from "vue";
const data = reactive({

View File

@ -1,5 +1,9 @@
<template>
<h1>Home</h1>
<h1> Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home</h1>
<h1> Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home</h1>
<h1> Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home</h1>
<h1> Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home</h1>
<h1> Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home Home</h1>
<router-link to="/user">User</router-link>
</template>

View File

@ -0,0 +1,71 @@
<template>
<div class="app-admin-layout">
<div class="header">
<!-- 头部 -->
<div class="user-info">
<span>
{{ userStore.userinfo?.account }}
</span>
</div>
</div>
<div class="main">
<div class="left-menu">左侧的菜单
<div>
<router-link to="/test">TEST</router-link>
</div>
<div>
<router-link to="/home">HOME</router-link>
</div>
</div>
<div class="content-wrapper">
<!-- 内容区域-->
<router-view/>
</div>
</div>
</div>
</template>
<script setup>
import {useUserStore} from "../../service/store";
const userStore = useUserStore();
</script>
<style lang="less">
.app-admin-layout {
min-height: 100vh;
}
.header {
background-color: var(--primary-color);
color: white;
line-height: 80px;
padding: 0 20px;
text-align: right;
position: fixed;
height: 80px;
left: 0;
right: 0;
top: 0;
}
.main {
background-color: #eee;
padding-top: var(--header-height);
padding-left: var(--left-menu-width);
.left-menu {
width: 200px;
background-color: black;
color: white;
padding: 20px;
position: fixed;
left: 0;
top: 0;
bottom: 0;
}
.content-wrapper {
}
}
</style>

View File

@ -2,6 +2,7 @@ import vue from '@vitejs/plugin-vue'
import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
export default {
// 开发服务信息
server: {
host:'::'
},