feat: 全局获取userinfo、数据持久化、store处理

This commit is contained in:
renxiaodong
2025-06-23 22:03:57 -04:00
parent 55198613a8
commit 59dac3bb13
10 changed files with 104 additions and 75 deletions

View File

@ -6,8 +6,26 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useUserStore } from '@/stores';
import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn'; import zhCN from '@arco-design/web-vue/es/locale/lang/zh-cn';
const store = useUserStore();
const redTheme = {
token: {
colorPrimary: '#6d4cfe', // 主色
colorLink: '#f5222d', // 链接色
},
};
const init = () => {
const { isLogin, fetchUserInfo } = store;
if (isLogin) {
fetchUserInfo();
}
};
onMounted(() => { onMounted(() => {
init();
// 监听全局未处理错误 // 监听全局未处理错误
window.addEventListener('unhandledrejection', (event) => { window.addEventListener('unhandledrejection', (event) => {
event.preventDefault(); event.preventDefault();
@ -15,10 +33,4 @@ onMounted(() => {
console.error(`发现catch报错${event.reason}`); console.error(`发现catch报错${event.reason}`);
}); });
}); });
const redTheme = {
token: {
colorPrimary: '#6d4cfe', // 主色
colorLink: '#f5222d', // 链接色
},
};
</script> </script>

View File

@ -77,30 +77,33 @@ export default defineComponent({
if (appStore.device === 'desktop') appStore.updateSettings({ menuCollapse: val }); if (appStore.device === 'desktop') appStore.updateSettings({ menuCollapse: val });
}; };
const renderSubMenu = () => { const renderSubMenu = () => {
function travel(_route: RouteRecordRaw[], nodes = []) { function travel(_route: RouteRecordRaw[] = [], nodes: any[] = []) {
if (Array.isArray(_route)) { if (!Array.isArray(_route)) return nodes;
_route.forEach((element) => { _route.forEach((element) => {
// This is demo, modify nodes as needed // 跳过没有 name 的菜单项,防止 key 报错
const icon = element?.meta?.icon ? () => h(element?.meta?.icon as object) : null; if (!element?.name) return;
const node =
element?.children && element?.children.length !== 0 ? ( const icon = element?.meta?.icon ? () => h(element.meta.icon as object) : null;
<a-sub-menu if (element.children && element.children.length > 0) {
key={element?.name} nodes.push(
v-slots={{ <a-sub-menu
icon, key={String(element.name)}
title: () => element?.meta?.locale || '', v-slots={{
}} icon,
> title: () => element.meta?.locale || '',
{travel(element?.children)} }}
</a-sub-menu> >
) : ( {travel(element.children)}
<a-menu-item key={element?.name} v-slots={{ icon }} onClick={() => goto(element)}> </a-sub-menu>,
{element?.meta?.locale || ''} );
</a-menu-item> } else {
); nodes.push(
nodes.push(node as never); <a-menu-item key={String(element.name)} v-slots={{ icon }} onClick={() => goto(element)}>
}); {element.meta?.locale || ''}
} </a-menu-item>,
);
}
});
return nodes; return nodes;
} }
return travel(menuTree.value ?? []); return travel(menuTree.value ?? []);

View File

@ -32,24 +32,6 @@ const router = createRouter({
requiresAuth: true, requiresAuth: true,
}, },
}, },
{
path: '/',
name: 'Home',
redirect: '/dataEngine/hotTranslation',
children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
meta: {
requiresAuth: true,
},
},
// {
// path: '/dataEngine',
// name: 'dataEngine',
// redirect: '/dataEngine/hotTranslation',
// children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
// meta: {
// requiresAuth: 1,
// },
// },
{ {
path: '/permission', path: '/permission',
name: 'permission', name: 'permission',
@ -66,6 +48,15 @@ const router = createRouter({
requiresAuth: false, requiresAuth: false,
}, },
}, },
{
path: '/',
name: 'Home',
redirect: '/dataEngine/hotTranslation',
children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
meta: {
requiresAuth: true,
},
},
], ],
scrollBehavior() { scrollBehavior() {
return { top: 0 }; return { top: 0 };

View File

@ -15,12 +15,26 @@ interface EnterpriseState {
export const useEnterpriseStore = defineStore('enterprise', { export const useEnterpriseStore = defineStore('enterprise', {
state: (): EnterpriseState => ({ state: (): EnterpriseState => ({
enterpriseInfo: null, enterpriseInfo: (() => {
const stored = localStorage.getItem('enterpriseInfo');
if (stored) {
try {
return JSON.parse(stored) as EnterpriseInfo;
} catch {
return null;
}
}
return null;
})(),
}), }),
actions: { actions: {
setEnterpriseInfo(enterpriseInfo: EnterpriseInfo) { setEnterpriseInfo(enterpriseInfo: EnterpriseInfo) {
console.log('setEnterpriseInfo', enterpriseInfo);
this.enterpriseInfo = enterpriseInfo; this.enterpriseInfo = enterpriseInfo;
localStorage.setItem('enterpriseInfo', JSON.stringify(enterpriseInfo));
},
clearEnterpriseInfo() {
this.enterpriseInfo = null;
localStorage.removeItem('enterpriseInfo');
}, },
setEnterpriseName(name: string) { setEnterpriseName(name: string) {
if (this.enterpriseInfo) { if (this.enterpriseInfo) {

View File

@ -1,4 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { fetchProfileInfo } from '@/api/all/login';
interface UserInfo { interface UserInfo {
id: number; id: number;
@ -19,7 +20,7 @@ interface UserState {
token: string; token: string;
userInfo: UserInfo | null; userInfo: UserInfo | null;
companyInfo: CompanyInfo | null; companyInfo: CompanyInfo | null;
isLogin: boolean; // isLogin: boolean;
} }
interface UserInfo { interface UserInfo {
@ -33,7 +34,6 @@ export const useUserStore = defineStore('user', {
token: localStorage.getItem('accessToken') || '', token: localStorage.getItem('accessToken') || '',
userInfo: null, userInfo: null,
companyInfo: null, companyInfo: null,
isLogin: false,
}), }),
getters: { getters: {
isLogin(): boolean { isLogin(): boolean {
@ -46,6 +46,7 @@ export const useUserStore = defineStore('user', {
this.token = `Bearer ${token}`; this.token = `Bearer ${token}`;
localStorage.setItem('accessToken', this.token); localStorage.setItem('accessToken', this.token);
}, },
deleteToken() { deleteToken() {
this.token = ''; this.token = '';
localStorage.removeItem('accessToken'); localStorage.removeItem('accessToken');
@ -62,18 +63,11 @@ export const useUserStore = defineStore('user', {
}, },
// 获取用户信息 // 获取用户信息
getUserInfo(): UserInfo | null { async fetchUserInfo() {
return this.userInfo; const { code, data } = await fetchProfileInfo();
}, if (code === 200) {
this.setUserInfo(data);
// 设置公司信息 }
setCompanyInfo(companyInfo: CompanyInfo | null) {
this.companyInfo = companyInfo;
},
// 获取公司信息
getCompanyInfo(): CompanyInfo | null {
return this.companyInfo;
}, },
}, },
}); });

View File

@ -5,6 +5,7 @@
import router from '@/router'; import router from '@/router';
import { useUserStore } from '@/stores'; import { useUserStore } from '@/stores';
import { useEnterpriseStore } from '@/stores/modules/enterprise';
// 登录 // 登录
export function goUserLogin(query?: any) { export function goUserLogin(query?: any) {
@ -23,7 +24,10 @@ export function handleUserHome() {
export function handleUserLogout() { export function handleUserLogout() {
const userStore = useUserStore(); const userStore = useUserStore();
const store = useEnterpriseStore();
userStore.deleteToken(); userStore.deleteToken();
store.clearEnterpriseInfo();
goUserLogin(); goUserLogin();
} }

View File

@ -275,9 +275,9 @@ const getProfileInfo = async () => {
let enterprises = data['enterprises']; let enterprises = data['enterprises'];
mobileNumber.value = data['mobile']; mobileNumber.value = data['mobile'];
accounts.value = enterprises; accounts.value = enterprises;
enterpriseStore.setEnterpriseInfo(data); enterpriseStore.setEnterpriseInfo(data);
userStore.setUserInfo(data); userStore.setUserInfo(data);
if (enterprises.length > 0) { if (enterprises.length > 0) {
if (enterprises.length === 1) { if (enterprises.length === 1) {
await enterpriseStore.updateEnterpriseInfo(); await enterpriseStore.updateEnterpriseInfo();

View File

@ -105,6 +105,8 @@ const okText = computed(() => {
}); });
const customerServiceVisible = ref(false); const customerServiceVisible = ref(false);
const canAddAccount = computed(() => { const canAddAccount = computed(() => {
if (!enterpriseInfo) return false;
return enterpriseInfo.sub_account_quota > enterpriseInfo.used_sub_account_count; return enterpriseInfo.sub_account_quota > enterpriseInfo.used_sub_account_count;
}); });
@ -124,9 +126,11 @@ function handlePageSizeChange(pageSize: number) {
async function getSubAccount() { async function getSubAccount() {
const res = await fetchSubAccountPage(params); const res = await fetchSubAccountPage(params);
const { data, total } = res.data; const { data, total, code } = res.data;
pagination.total = total; if (code === 200) {
data.value = data; pagination.total = total;
data.value = data;
}
} }
async function handleAddAccount() { async function handleAddAccount() {
if (canAddAccount.value) { if (canAddAccount.value) {

View File

@ -1,6 +1,6 @@
<template> <template>
<Container title="企业信息" class="container mt-24px"> <Container title="企业信息" class="container mt-24px">
<a-table :columns="columns" :data="data" :pagination="false" class="mt-16px"> <a-table :columns="columns" :data="dataSource" :pagination="false" class="mt-16px">
<template #info="{ record }"> <template #info="{ record }">
{{ record.name }} {{ record.name }}
</template> </template>
@ -11,7 +11,7 @@
<Modal v-model:visible="infoVisible" width="480px" title="修改企业名称" :okText="okText" @ok="handleOk"> <Modal v-model:visible="infoVisible" width="480px" title="修改企业名称" :okText="okText" @ok="handleOk">
<p class="tips"> <p class="tips">
企业名称只能修改2次请谨慎操作<span 企业名称只能修改2次请谨慎操作<span
>剩余{{ enterpriseInfo.update_name_quota - enterpriseInfo.used_update_name_count }} >剩余{{ enterpriseInfo!.update_name_quota - enterpriseInfo!.used_update_name_count }}
</span> </span>
</p> </p>
<a-form <a-form
@ -54,12 +54,15 @@ const columns = [
slotName: 'action', slotName: 'action',
}, },
]; ];
const data = ref([enterpriseInfo]);
const infoVisible = ref(false); const infoVisible = ref(false);
const customerServiceVisible = ref(false); const customerServiceVisible = ref(false);
const dataSource = computed(() => {
return enterpriseInfo ? [enterpriseInfo] : [];
});
const canUpdate = computed(() => { const canUpdate = computed(() => {
if (!enterpriseInfo) return false;
return enterpriseInfo.update_name_quota > enterpriseInfo.used_update_name_count; return enterpriseInfo.update_name_quota > enterpriseInfo.used_update_name_count;
}); });
@ -72,7 +75,7 @@ const okText = computed(() => {
function handleUpdate() { function handleUpdate() {
if (!canUpdate.value) { if (!canUpdate.value) {
form.name = enterpriseInfo.name; form.name = enterpriseInfo!.name;
} }
infoVisible.value = true; infoVisible.value = true;
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<Container title="个人信息" class="container mt-24px"> <Container title="个人信息" class="container mt-24px">
<a-table :columns="columns" :data="data" :pagination="false" class="mt-16px"> <a-table :columns="columns" :data="dataSource" :pagination="false" class="mt-16px">
<template #info="{ record }"> <template #info="{ record }">
<div class="pt-3px pb-3px"> <div class="pt-3px pb-3px">
<a-avatar :image-url="record.head_image" :size="32" /> <a-avatar :image-url="record.head_image" :size="32" />
@ -85,7 +85,7 @@ import axios from 'axios';
import { useUserStore } from '@/stores'; import { useUserStore } from '@/stores';
const store = useUserStore(); const store = useUserStore();
const userInfo = store.getUserInfo(); const userInfo = store.userInfo;
const columns = [ const columns = [
{ {
@ -97,7 +97,7 @@ const columns = [
slotName: 'mobile', slotName: 'mobile',
}, },
]; ];
const data = reactive([userInfo]);
const infoVisible = ref(false); const infoVisible = ref(false);
const imageVisible = ref(false); const imageVisible = ref(false);
const mobileVisible = ref(false); const mobileVisible = ref(false);
@ -108,6 +108,10 @@ const formRef = ref();
const isSendCaptcha = ref(false); const isSendCaptcha = ref(false);
const uploadInputRef = ref(); const uploadInputRef = ref();
const dataSource = computed(() => {
return userInfo ? [userInfo] : [];
});
// 表单校验规则 // 表单校验规则
const formRules = { const formRules = {
mobile: [ mobile: [