登录页面init
This commit is contained in:
@@ -1,3 +1,2 @@
|
||||
NODE_ENV='development'
|
||||
VITE_TITLE=""
|
||||
VITE_URL="http://localhost:8081"
|
||||
@@ -1,3 +1,2 @@
|
||||
NODE_ENV='production'
|
||||
VITE_TITLE=""
|
||||
VITE_URL="http://www.test.com"
|
||||
@@ -15,6 +15,7 @@
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
"axios": "^1.7.3",
|
||||
"crypto-js": "^4.2.0",
|
||||
"element-plus": "^2.7.8",
|
||||
"pinia": "^2.2.1",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
@@ -33,6 +34,7 @@
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"npm-run-all2": "^6.2.0",
|
||||
"postcss": "^8.4.41",
|
||||
"sass": "^1.77.8",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.3.1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utils/http'
|
||||
import createAxios from '@/utils/http'
|
||||
import { useUserInfoStore } from '@/stores/user'
|
||||
import { sm3Digest } from '@/assets/commjs/sm3.js'
|
||||
import { sm2, encrypt } from '@/assets/commjs/sm2.js'
|
||||
@@ -11,7 +11,7 @@ export const publicKey = (params?: any) => {
|
||||
loginName: encrypt(userInfo.loginName),
|
||||
}
|
||||
}
|
||||
return request({
|
||||
return createAxios({
|
||||
url: '/user/generateSm2Key',
|
||||
method: 'get',
|
||||
params,
|
||||
@@ -30,7 +30,7 @@ export const pwdSm3 = async (pwd: any, loginName?: string) => {
|
||||
export const login = async (params: any) => {
|
||||
params.password = await pwdSm3(params.password, params.username)
|
||||
params.username = encrypt(params.username)
|
||||
return request({
|
||||
return createAxios({
|
||||
url: '/pqs-auth/oauth/token',
|
||||
method: 'post',
|
||||
params,
|
||||
@@ -40,7 +40,7 @@ export const login = async (params: any) => {
|
||||
//获取用户信息
|
||||
export const getUserById = () => {
|
||||
const userInfo = useUserInfoStore()
|
||||
return request({
|
||||
return createAxios({
|
||||
url: '/user-boot/user/getUserById?id=' + userInfo.userIndex,
|
||||
method: 'get',
|
||||
})
|
||||
|
||||
BIN
frontend/src/assets/font/DongFangDaKai-Regular.woff
Normal file
BIN
frontend/src/assets/font/DongFangDaKai-Regular.woff
Normal file
Binary file not shown.
BIN
frontend/src/assets/font/DongFangDaKai-Regular.woff2
Normal file
BIN
frontend/src/assets/font/DongFangDaKai-Regular.woff2
Normal file
Binary file not shown.
BIN
frontend/src/assets/font/MFBanHei.ttf
Normal file
BIN
frontend/src/assets/font/MFBanHei.ttf
Normal file
Binary file not shown.
BIN
frontend/src/assets/images/login/background.png
Normal file
BIN
frontend/src/assets/images/login/background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 300 KiB |
@@ -1,3 +1,19 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
/* 申明字体为东方大楷 */
|
||||
@font-face {
|
||||
font-family: 'DongFangDaKai';
|
||||
src: url('@/assets/font/DongFangDaKai-Regular.woff') format('woff'),
|
||||
url('@/assets/font/DongFangDaKai-Regular.woff2') format('woff2');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "MFBanHei"; /* Project id 1513211 */
|
||||
src: url('@/assets/font/MFBanHei.ttf?t=1643094287456') format('truetype');
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/*文件说明:本文件用来定义一些本地缓存的key*/
|
||||
6
frontend/src/constants/user.ts
Normal file
6
frontend/src/constants/user.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* 用户相关的一些常量
|
||||
*/
|
||||
|
||||
// 请求头token拼接的前缀
|
||||
export const TOKEN_PREFIX = 'bearer '
|
||||
@@ -1,15 +1,14 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
// element-plus
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
// 使用pinia
|
||||
import pinia from '@/stores'
|
||||
|
||||
import App from './App.vue'
|
||||
// 导入路由
|
||||
import Router from './router/index'
|
||||
|
||||
// 引入tailwindcss
|
||||
// 引入项目主CSS
|
||||
import '@/assets/styles/tailMain.css'
|
||||
|
||||
// 导入全局注册的组件
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
// 变量名对应含义请在 /stores/* 里边找
|
||||
import type { RouteRecordRaw, RouteLocationNormalized } from 'vue-router'
|
||||
|
||||
export interface Layout {
|
||||
showDrawer: boolean
|
||||
shrink: boolean
|
||||
layoutMode: string
|
||||
mainAnimation: string
|
||||
isDark: boolean
|
||||
menuWidth: number
|
||||
menuDefaultIcon: string
|
||||
menuCollapse: boolean
|
||||
menuUniqueOpened: boolean
|
||||
menuShowTopBar: boolean
|
||||
elementUiPrimary: string[]
|
||||
tableHeaderBackground: string[]
|
||||
tableHeaderColor: string[]
|
||||
tableCurrent: string[]
|
||||
menuBackground: string[]
|
||||
menuColor: string[]
|
||||
menuActiveBackground: string[]
|
||||
menuActiveColor: string[]
|
||||
menuTopBarBackground: string[]
|
||||
headerBarTabColor: string[]
|
||||
headerBarBackground: string[]
|
||||
headerBarHoverBackground: string[]
|
||||
headerBarTabActiveBackground: string[]
|
||||
headerBarTabActiveColor: string[]
|
||||
}
|
||||
|
||||
export interface NavTabs {
|
||||
activeIndex: number
|
||||
activeRoute: RouteLocationNormalized | null
|
||||
tabsView: RouteLocationNormalized[]
|
||||
tabFullScreen: boolean
|
||||
tabsViewRoutes: RouteRecordRaw[]
|
||||
authNode: Map<string, string[]>
|
||||
}
|
||||
|
||||
// 用户信息
|
||||
export interface UserInfo {
|
||||
access_token: string
|
||||
token_type: string
|
||||
refresh_token: string
|
||||
expires_in: number
|
||||
scope: string
|
||||
nickname: string
|
||||
userType: number
|
||||
deptIndex: string
|
||||
userIndex: string
|
||||
client_id: string
|
||||
headSculpture: any
|
||||
jti: string
|
||||
name: string
|
||||
deptId: string
|
||||
phone: string
|
||||
email: string
|
||||
limitIpStart: string
|
||||
limitIpEnd: string
|
||||
limitTime: string
|
||||
casualUser: number
|
||||
type: number
|
||||
smsNotice: number
|
||||
emailNotice: number
|
||||
role: string[]
|
||||
devCode: any
|
||||
id: string
|
||||
loginName: string
|
||||
state: number
|
||||
registerTime: string
|
||||
loginTime: string
|
||||
deptName: string
|
||||
areaId: string
|
||||
areaName: string
|
||||
deptLevel: number
|
||||
roleList: string[]
|
||||
roleCode: string[]
|
||||
}
|
||||
|
||||
// 字典数据
|
||||
export interface DictData {
|
||||
basic: BasicDictData[]
|
||||
area: BasicDictData[]
|
||||
areaTree: BasicDictData[]
|
||||
userList: string[]
|
||||
}
|
||||
|
||||
export interface BasicDictData {
|
||||
name: string
|
||||
id: string
|
||||
code: string
|
||||
value: null
|
||||
sort: number | null
|
||||
children?: BasicDictData[]
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { USER_INFO } from '@/stores/constant/cacheKey'
|
||||
import type { UserInfo } from '@/stores/interface'
|
||||
import { USER_INFO } from '@/constants/storeKey'
|
||||
import { TOKEN_PREFIX } from '@/constants/user'
|
||||
import type { UserInfo } from '@/types/user'
|
||||
import { getUserById } from '@/api/user'
|
||||
import { createPersistedState } from 'pinia-plugin-persistedstate'
|
||||
|
||||
export const useUserInfoStore = defineStore('userInfo', {
|
||||
// 行为
|
||||
@@ -8,6 +11,9 @@ export const useUserInfoStore = defineStore('userInfo', {
|
||||
dataFill(state: UserInfo) {
|
||||
this.$state = { ...this.$state, ...state }
|
||||
},
|
||||
async initUserInfo() {
|
||||
this.dataFill(await getUserById())
|
||||
},
|
||||
removeToken() {
|
||||
this.access_token = ''
|
||||
this.refresh_token = ''
|
||||
@@ -18,8 +24,8 @@ export const useUserInfoStore = defineStore('userInfo', {
|
||||
},
|
||||
getToken(type: 'auth' | 'refresh' = 'auth') {
|
||||
if (type === 'auth') {
|
||||
if (this.token_type && this.access_token) {
|
||||
return this.token_type + ' ' + this.access_token
|
||||
if (this.access_token) {
|
||||
return `${TOKEN_PREFIX}${this.access_token}`
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
@@ -32,7 +38,6 @@ export const useUserInfoStore = defineStore('userInfo', {
|
||||
state: (): UserInfo => {
|
||||
return {
|
||||
access_token: '',
|
||||
token_type: '',
|
||||
refresh_token: '',
|
||||
expires_in: 0,
|
||||
scope: '',
|
||||
@@ -69,7 +74,10 @@ export const useUserInfoStore = defineStore('userInfo', {
|
||||
roleCode: [],
|
||||
}
|
||||
},
|
||||
persist: {
|
||||
key: USER_INFO,
|
||||
},
|
||||
plugins: [
|
||||
createPersistedState({
|
||||
key: USER_INFO,
|
||||
storage: window.localStorage
|
||||
}),
|
||||
],
|
||||
})
|
||||
16
frontend/src/types/dict/index.ts
Normal file
16
frontend/src/types/dict/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// 字典数据
|
||||
export interface DictData {
|
||||
basic: BasicDictData[]
|
||||
area: BasicDictData[]
|
||||
areaTree: BasicDictData[]
|
||||
userList: string[]
|
||||
}
|
||||
|
||||
export interface BasicDictData {
|
||||
name: string
|
||||
id: string
|
||||
code: string
|
||||
value: null
|
||||
sort: number | null
|
||||
children?: BasicDictData[]
|
||||
}
|
||||
39
frontend/src/types/user/index.ts
Normal file
39
frontend/src/types/user/index.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
// 用户信息
|
||||
export interface UserInfo {
|
||||
access_token: string
|
||||
refresh_token: string
|
||||
expires_in: number
|
||||
scope: string
|
||||
nickname: string
|
||||
userType: number
|
||||
deptIndex: string
|
||||
userIndex: string
|
||||
client_id: string
|
||||
headSculpture: any
|
||||
jti: string
|
||||
name: string
|
||||
deptId: string
|
||||
phone: string
|
||||
email: string
|
||||
limitIpStart: string
|
||||
limitIpEnd: string
|
||||
limitTime: string
|
||||
casualUser: number
|
||||
type: number
|
||||
smsNotice: number
|
||||
emailNotice: number
|
||||
role: string[]
|
||||
devCode: any
|
||||
id: string
|
||||
loginName: string
|
||||
state: number
|
||||
registerTime: string
|
||||
loginTime: string
|
||||
deptName: string
|
||||
areaId: string
|
||||
areaName: string
|
||||
deptLevel: number
|
||||
roleList: string[]
|
||||
roleCode: string[]
|
||||
}
|
||||
@@ -27,7 +27,7 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
|
||||
const userInfo = useUserInfoStore()
|
||||
|
||||
const Axios = axios.create({
|
||||
baseURL: import.meta.env.VITE_URL,
|
||||
baseURL: '/api',
|
||||
timeout: 1000 * 60 * 5,
|
||||
headers: {},
|
||||
responseType: 'json',
|
||||
|
||||
9
frontend/src/utils/logout/index.ts
Normal file
9
frontend/src/utils/logout/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { useUserInfoStore } from '@/stores/user'
|
||||
import { USER_INFO } from '@/constants/storeKey'
|
||||
|
||||
export function clearUserInfo() {
|
||||
const userInfo = useUserInfoStore()
|
||||
userInfo.$reset()
|
||||
// 清除用户信息缓存
|
||||
localStorage.removeItem(USER_INFO)
|
||||
}
|
||||
@@ -1,26 +1,119 @@
|
||||
<template>
|
||||
<div ref="loginContent" class="text-xl text-red-600">
|
||||
<h1 ref="loginTitle">123</h1>
|
||||
<svg-icon name="wind" color="#fff" size="100" spin > </svg-icon>
|
||||
<div ref="loginContent" class="login">
|
||||
<div class="login_form">
|
||||
<div class="login_form_title">自动检测平台</div>
|
||||
<el-form :model="LoginForm" :rules="rules" ref="formRef">
|
||||
<el-form-item label="" prop="loginUserName">
|
||||
<el-input
|
||||
v-model="LoginForm.loginUserName"
|
||||
:prefix-icon="Avatar"
|
||||
placeholder="请输入账户"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="" prop="loginUserPassword">
|
||||
<el-input
|
||||
v-model="LoginForm.loginUserPassword"
|
||||
:prefix-icon="Lock"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
show-password
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleLogin"
|
||||
style="width: 100%"
|
||||
:loading="loginLoading"
|
||||
>登 录</el-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
defineOptions(
|
||||
{
|
||||
name: "CustomLogin"
|
||||
}
|
||||
)
|
||||
import {ref, onMounted} from 'vue'
|
||||
let loginContent = ref()
|
||||
let loginTitle = ref()
|
||||
|
||||
onMounted(() => {
|
||||
console.log(loginTitle.value);
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "CustomLogin",
|
||||
});
|
||||
import { ref, onMounted } from "vue";
|
||||
const router = useRouter();
|
||||
import { useRouter } from "vue-router";
|
||||
import { Avatar, Lock } from "@element-plus/icons-vue";
|
||||
import { useUserInfoStore } from "@/stores/user";
|
||||
const userInfoStore = useUserInfoStore();
|
||||
|
||||
|
||||
const rules = {
|
||||
loginUserName: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
||||
loginUserPassword: [
|
||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||
],
|
||||
};
|
||||
const loginLoading = ref(false);
|
||||
const LoginForm = ref({
|
||||
loginUserName: "",
|
||||
loginUserPassword: "",
|
||||
});
|
||||
let loginContent = ref();
|
||||
const formRef = ref();
|
||||
const handleLogin = () => {
|
||||
formRef.value.validate((validate: any) => {
|
||||
if (validate) {
|
||||
loginLoading.value = true;
|
||||
if (LoginForm.value.loginUserName && LoginForm.value.loginUserPassword) {
|
||||
setTimeout(() => {
|
||||
// router.push({
|
||||
// path: "/admin",
|
||||
// query: {
|
||||
// name: LoginForm.value.loginUserName,
|
||||
// },
|
||||
// });
|
||||
userInfoStore.dataFill({ loginName: LoginForm.value.loginUserName });
|
||||
console.log(userInfoStore.loginName)
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
|
||||
.login {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-right: 10%;
|
||||
background: #0b47a1 url("../assets/images/login/background.png") no-repeat left center;
|
||||
background-size: auto;
|
||||
.login_form {
|
||||
width: 30rem;
|
||||
height: 27rem;
|
||||
cursor: pointer;
|
||||
border-radius: 12px;
|
||||
box-shadow: 6px 6px 10px #000;
|
||||
background-color: #fff;
|
||||
border: 1px solid #eee;
|
||||
padding: 10px 20px 10px;
|
||||
.login_form_title {
|
||||
width: 100%;
|
||||
height: 4rem;
|
||||
font-size: 32px;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
font-family: "DongFangDaKai";
|
||||
letter-spacing: 4px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.el-button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:deep(.el-input){
|
||||
outline: none !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
9
frontend/vite-env.d.ts
vendored
Normal file
9
frontend/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
interface ImportMetaEnv {
|
||||
readonly NODE_ENV: string;
|
||||
readonly VITE_TITLE: string;
|
||||
// ... 其他环境变量
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
@@ -4,12 +4,7 @@ import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig((config) => {
|
||||
// 根据当前工作目录中的 `mode` 加载 .env 文件
|
||||
// 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
|
||||
const {command, mode} = config
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
return {
|
||||
plugins: [
|
||||
vue(),
|
||||
@@ -52,5 +47,16 @@ export default defineConfig((config) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
open: false,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://192.168.1.125:18092', //hsw
|
||||
changeOrigin: true,
|
||||
rewrite: path => path.replace(/^\/api/, '') //路径重写,把'/api'替换为''
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user