Commit 4298a4c4 authored by nick zheng's avatar nick zheng

feat: 模拟用户密码登录(非正式版)及调整布局

parent e874823d
import { request } from '@/utils/request'
export function fetchLogin<T>(payload: { loginChannel: string; account: string; password: string }) {
return request.post<T>(`/bizMemberInfoRest/doLogin.json`, payload)
}
export const BASE_URLS: Record<'DEV' | 'PROD', string> = { export const BASE_URLS: Record<'DEV' | 'PROD', string> = {
DEV: '', DEV: 'https://poc-sit.gsstcloud.com',
PROD: '', PROD: 'https://poc.gsstcloud.com',
}
export const INDEX_URLS: Record<'DEV' | 'PROD', string> = {
DEV: 'https://poc-sit.gsstcloud.com/fe#/',
PROD: 'https://poc.gsstcloud.com/fe#/',
} }
<script setup lang="ts">
import { useUserStore } from '@/store/modules/user'
import { readonly } from 'vue'
import { useRouter } from 'vue-router'
const defaultAvatar = 'https://mkp-dev.oss-cn-shenzhen.aliyuncs.com/game-template/20221018/1666079174947.png'
const userStore = useUserStore()
const router = useRouter()
const avatarOptions = readonly([
{
label: '退出登录',
key: 1,
},
])
function handleDropdownSelect(key: number) {
if (key === 1) {
userStore.logout().then(() => {
router.push({ name: 'Login' })
})
}
}
</script>
<template>
<div class="flex select-none items-center justify-between bg-white px-4 shadow-[inset_0_-1px_#e8e9eb]">
<div class="flex">APPBuilder</div>
<div class="flex cursor-pointer items-center px-2">
<NDropdown trigger="click" :options="avatarOptions" @select="handleDropdownSelect">
<div class="flex h-full items-center">
<NAvatar round :size="30" object-fit="cover" :src="userStore.userInfo.avatar || defaultAvatar" />
</div>
</NDropdown>
</div>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import { h, readonly, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { sidebarMenus } from '@/router/index' import { sidebarMenus } from '@/router/index'
import { type MenuOption } from '@/router/utils' import { type MenuOption } from '@/router/utils'
import { useRoute, useRouter } from 'vue-router'
import { ref, watch } from 'vue'
import CustomIcon from '@/components/custom-icon/custom-icon.vue' import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { useUserStore } from '@/store/modules/user'
const currentRoute = useRoute() const currentRoute = useRoute()
const router = useRouter() const router = useRouter()
const userStore = useUserStore()
const menuValue = ref(currentRoute.meta.belong) const menuValue = ref(currentRoute.meta.belong)
const defaultAvatar = 'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png'
const avatarOptions = readonly([
// {
// label: '我的',
// key: 'My',
// icon: () => h(CustomIcon, { icon: 'bx:user' }),
// },
{
label: '退出登录',
key: 'logout',
icon: () => h(CustomIcon, { icon: 'teenyicons:logout-solid' }),
},
])
watch( watch(
() => currentRoute.fullPath, () => currentRoute.fullPath,
() => { () => {
...@@ -24,27 +42,75 @@ function handleUpdateValue(_key: string, menuItemOption: MenuOption) { ...@@ -24,27 +42,75 @@ function handleUpdateValue(_key: string, menuItemOption: MenuOption) {
// function handleToPersonAppSettingPage() { // function handleToPersonAppSettingPage() {
// router.push({ name: 'PersonalAppSetting' }) // router.push({ name: 'PersonalAppSetting' })
// } // }
function handleDropdownSelect(key: string) {
if (key === 'logout') {
userStore.logout().then(() => {
router.push({ name: 'Login' })
})
return
}
router.replace({ name: key })
}
</script> </script>
<template> <template>
<!-- <button <div class="flex h-full flex-col justify-between px-3">
class="mx-2 mb-[14px] flex h-[32px] w-[188px] items-center justify-center rounded-md bg-gradient-to-r from-[#005aff] to-[#60e0fd] text-white outline-none hover:opacity-80" <div>
@click="handleToPersonAppSettingPage" <div
> class="mx-auto my-[14px] flex h-[23px] w-[90px] bg-[url('@/assets/images/page-logo.png')] bg-contain bg-center bg-no-repeat"
<CustomIcon icon="zondicons:add-solid" class="mr-1.5" /> />
<span>创建应用</span>
</button> --> <!-- <div class="py-5">
<button
<ul> class="bg-theme-color flex h-[40px] w-[203px] items-center justify-center rounded-md text-white outline-none hover:opacity-80"
<li @click="handleToPersonAppSettingPage"
v-for="sidebarMenuItem in sidebarMenus" >
:key="sidebarMenuItem.key" <CustomIcon icon="ic:outline-add" class="mr-1 h-[18px] w-[18px]" />
class="my-1 flex h-10 cursor-pointer items-center rounded-md pl-3 hover:bg-[#f2f5f9]" <span>创建应用</span>
:class="[menuValue === sidebarMenuItem.routeName ? 'bg-[#f2f5f9] text-[#151b26]' : 'text-[#5c5f66]']" </button>
@click="handleUpdateValue(sidebarMenuItem.routeName, sidebarMenuItem)" </div> -->
>
<CustomIcon :icon="sidebarMenuItem.icon" class="mr-2 text-base" /> <ul>
<span class="line-clamp-1 max-w-[150px]">{{ sidebarMenuItem.label }}</span> <li
</li> v-for="sidebarMenuItem in sidebarMenus"
</ul> :key="sidebarMenuItem.key"
class="my-1 flex h-10 cursor-pointer items-center rounded-md pl-3 hover:bg-[#f2f5f9]"
:class="[menuValue === sidebarMenuItem.routeName ? 'bg-[#f2f5f9] text-[#151b26]' : 'text-[#5c5f66]']"
@click="handleUpdateValue(sidebarMenuItem.routeName, sidebarMenuItem)"
>
<CustomIcon :icon="sidebarMenuItem.icon" class="mr-2 text-base" />
<span class="line-clamp-1 max-w-[150px]">{{ sidebarMenuItem.label }}</span>
</li>
</ul>
</div>
<div class="mb-7">
<NDropdown trigger="click" placement="top-start" :options="avatarOptions" @select="handleDropdownSelect">
<div class="flex h-full cursor-pointer items-center">
<NAvatar round :size="40" object-fit="cover" :src="userStore.userInfo.avatarUrl || defaultAvatar" />
<div class="ml-3 line-clamp-1 max-w-[140px] select-none break-all text-base">
{{ userStore.userInfo.nickName || '未登录' }}
</div>
</div>
</NDropdown>
</div>
</div>
</template> </template>
<style lang="scss">
.v-binder-follower-container {
.n-dropdown-menu {
--n-border-radius: 10px !important;
--n-box-shadow: -3px 3px 4px 0px #f2f2f2 !important;
padding: 6px 0 !important;
}
.n-dropdown-menu .n-dropdown-option-body {
padding: 0 10px;
}
}
</style>
<script setup lang="ts"> <script setup lang="ts">
import Sidebar from './components/sidebar/sidebar.vue' import Sidebar from './components/sidebar/sidebar.vue'
import NavBar from './components/navbar/navbar.vue'
const layoutSideWidth = 221 const layoutSideWidth = 243
</script> </script>
<template> <template>
<NLayout content-class="layout-content" position="absolute"> <NLayout has-sider class="h-full">
<NLayoutHeader class="box-border h-[56px] flex-none"> <NLayoutSider
<NavBar class="h-full" /> class="border-r border-[#e8e9eb] px-2"
</NLayoutHeader> collapse-mode="width"
:collapsed-width="64"
<NLayout has-sider class="h-[calc(100%-56px)]"> :width="layoutSideWidth"
<NLayoutSider >
class="border-r border-[#e8e9eb] px-2 pt-4" <Sidebar />
collapse-mode="width" </NLayoutSider>
:collapsed-width="64"
:width="layoutSideWidth" <NLayoutContent class="bg-[#f3f6f9]! flex-1">
> <main class="box-border h-full px-6 py-4">
<Sidebar /> <RouterView v-slot="{ Component }">
</NLayoutSider> <Transition appear name="fade-slide" mode="out-in">
<Component :is="Component" />
<NLayoutContent class="bg-[#f3f6f9]! flex-1"> </Transition>
<main class="box-border h-full px-6 py-4"> </RouterView>
<RouterView v-slot="{ Component }"> </main>
<Transition appear name="fade-slide" mode="out-in"> </NLayoutContent>
<Component :is="Component" />
</Transition>
</RouterView>
</main>
</NLayoutContent>
</NLayout>
</NLayout> </NLayout>
</template> </template>
......
...@@ -34,7 +34,7 @@ const modules: Record<string, any> = import.meta.glob(['./modules/**/*.ts', '!./ ...@@ -34,7 +34,7 @@ const modules: Record<string, any> = import.meta.glob(['./modules/**/*.ts', '!./
export const sidebarMenus: any[] = menuFilterSort([...routes]) export const sidebarMenus: any[] = menuFilterSort([...routes])
const router = createRouter({ export const router = createRouter({
history: getHistoryMode(import.meta.env.VITE_ROUTER_MODE), history: getHistoryMode(import.meta.env.VITE_ROUTER_MODE),
routes: [...routes, ...baseRoutes], routes: [...routes, ...baseRoutes],
strict: true, strict: true,
......
...@@ -5,12 +5,10 @@ import type { UserState, UserInfo } from '../types/user' ...@@ -5,12 +5,10 @@ import type { UserState, UserInfo } from '../types/user'
function getDefaultUserInfo(): UserInfo { function getDefaultUserInfo(): UserInfo {
return { return {
account: '', memberId: 0,
userAccount: '', nickName: '',
userId: null, mobilePhone: '',
userName: '用户', avatarUrl: 'https://gsst-poe-sit.gz.bcebos.com/data/20240910/1725952917468.png',
createdTime: '',
avatar: '',
} }
} }
......
export interface UserInfo { export interface UserInfo {
account: string memberId: number
userAccount: string nickName: string
userId: null | number avatarUrl: string
userName: string mobilePhone: string
createdTime: string
avatar: string
} }
export interface UserState { export interface UserState {
......
...@@ -2,6 +2,7 @@ import axios, { type AxiosRequestConfig, type AxiosResponse } from 'axios' ...@@ -2,6 +2,7 @@ import axios, { type AxiosRequestConfig, type AxiosResponse } from 'axios'
import { BASE_URLS } from '@/config/base-url' import { BASE_URLS } from '@/config/base-url'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { router } from '@/router'
interface PagingInfoParams { interface PagingInfoParams {
pageNo: number pageNo: number
...@@ -18,15 +19,14 @@ export interface Response<T> { ...@@ -18,15 +19,14 @@ export interface Response<T> {
const ENV = import.meta.env.VITE_APP_ENV const ENV = import.meta.env.VITE_APP_ENV
function handleLogout() { function handleLogout() {
const router = useRouter()
const currentRoute = router.currentRoute.value const currentRoute = router.currentRoute.value
router.replace({ name: 'Login', query: { redirect: encodeURIComponent(currentRoute.fullPath) } }) router.replace({ name: 'Login', query: { redirect: encodeURIComponent(currentRoute.fullPath) } })
window.$message.warning('身份已过期,请重新登录') window.$message.warning('身份已过期,请重新登录')
} }
const service = axios.create({ const service = axios.create({
baseURL: `${BASE_URLS[ENV]}/api`, baseURL: `${BASE_URLS[ENV]}/api/rest`,
timeout: 7000, timeout: 7000,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...@@ -81,7 +81,7 @@ function http<T>( ...@@ -81,7 +81,7 @@ function http<T>(
handleLogout() handleLogout()
} }
if (res.message) { if (res.code === -1 && res.message) {
const msg = res.message.match(/\[(?<msg>[\s\S]+)\]/)?.groups?.msg const msg = res.message.match(/\[(?<msg>[\s\S]+)\]/)?.groups?.msg
window.$message.error(msg || res.message) window.$message.error(msg || res.message)
} }
......
...@@ -3,9 +3,8 @@ import { ref } from 'vue' ...@@ -3,9 +3,8 @@ import { ref } from 'vue'
import { appConfig } from '@/config/app-config' import { appConfig } from '@/config/app-config'
import CustomIcon from '@/components/custom-icon/custom-icon.vue' import CustomIcon from '@/components/custom-icon/custom-icon.vue'
import { FormInst } from 'naive-ui' import { FormInst } from 'naive-ui'
// import { fetchLogin } from '@/apis/user' import { fetchLogin } from '@/apis/user'
import { useUserStore } from '@/store/modules/user' import { useUserStore } from '@/store/modules/user'
// import type { UserInfo } from '@/store/types/user'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const userStore = useUserStore() const userStore = useUserStore()
...@@ -26,73 +25,42 @@ const loginFormRules = { ...@@ -26,73 +25,42 @@ const loginFormRules = {
function handleLogin(e: MouseEvent) { function handleLogin(e: MouseEvent) {
e.preventDefault() e.preventDefault()
loginFormRef.value?.validate((errors) => { loginFormRef.value?.validate(async (errors) => {
if (!errors) { if (!errors) {
// loginBtnLoading.value = true loginBtnLoading.value = true
userStore.updateIsLogin(true) const res = await fetchLogin<{
userStore.updateToken('') token: string
const userInfoRes = { memberId: number
account: 'account', nickName: string
userAccount: 'userAccount', avatarUrl: string
userId: 134, mobilePhone: string
userName: 'userName', }>({
createdTime: 'createdTime', loginChannel: 'MEMBER_PLATFOMR_PW',
} account: '15816736768',
userStore.updateUserInfo({ password: '123456',
account: userInfoRes.account, }).finally(() => (loginBtnLoading.value = false))
userAccount: userInfoRes.userAccount,
userId: userInfoRes.userId,
userName: userInfoRes.userName,
createdTime: userInfoRes.createdTime,
avatar: '',
})
const currentRoute = router.currentRoute.value
const redirectUrl = decodeURIComponent((currentRoute.query.redirect as string) || '')
if (redirectUrl) {
router.replace({ path: redirectUrl })
return
}
router.replace({ name: 'Root' }) if (res.code === 0) {
userStore.updateIsLogin(true)
userStore.updateToken(res.data.token)
userStore.updateUserInfo({
avatarUrl: res.data.avatarUrl,
memberId: res.data.memberId,
mobilePhone: res.data.mobilePhone,
nickName: res.data.nickName,
})
// fetchLogin<{ token: string; user: UserInfo }>(loginForm.value) const currentRoute = router.currentRoute.value
// .then((res) => { const redirectUrl = decodeURIComponent((currentRoute.query.redirect as string) || '')
// if (res.code !== null && res.code !== 0) {
// window.$message.error(res.message || '登录失败请重试')
// return
// }
// userStore.updateIsLogin(true) if (redirectUrl) {
// userStore.updateToken(res.data.token) router.replace({ path: redirectUrl })
// const userInfoRes = res.data.user || {} return
// userStore.updateUserInfo({ }
// account: userInfoRes.account,
// userAccount: userInfoRes.userAccount,
// userId: userInfoRes.userId,
// userName: userInfoRes.userName,
// createdTime: userInfoRes.createdTime,
// avatar: '',
// })
// const currentRoute = router.currentRoute.value router.replace({ name: 'Root' })
// const redirectUrl = decodeURIComponent((currentRoute.query.redirect as string) || '') }
// if (redirectUrl) {
// router.replace({ path: redirectUrl })
// return
// }
// router.replace({ name: 'Root' })
// })
// .catch((err) => {
// console.log(err)
// })
// .finally(() => {
// loginBtnLoading.value = false
// })
} }
}) })
} }
......
...@@ -18,5 +18,9 @@ export default defineConfig({ ...@@ -18,5 +18,9 @@ export default defineConfig({
colors: { colors: {
'theme-color': '#2468f2', 'theme-color': '#2468f2',
}, },
height: {
navbar: '56px',
content: 'calc(100% - 56px)',
},
}, },
}) })
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment