feat: 全局获取userinfo、数据持久化、store处理
This commit is contained in:
24
src/App.vue
24
src/App.vue
@ -6,8 +6,26 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from '@/stores';
|
||||
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(() => {
|
||||
init();
|
||||
// 监听全局未处理错误
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
event.preventDefault();
|
||||
@ -15,10 +33,4 @@ onMounted(() => {
|
||||
console.error(`发现catch报错:${event.reason}`);
|
||||
});
|
||||
});
|
||||
const redTheme = {
|
||||
token: {
|
||||
colorPrimary: '#6d4cfe', // 主色
|
||||
colorLink: '#f5222d', // 链接色
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -77,30 +77,33 @@ export default defineComponent({
|
||||
if (appStore.device === 'desktop') appStore.updateSettings({ menuCollapse: val });
|
||||
};
|
||||
const renderSubMenu = () => {
|
||||
function travel(_route: RouteRecordRaw[], nodes = []) {
|
||||
if (Array.isArray(_route)) {
|
||||
_route.forEach((element) => {
|
||||
// This is demo, modify nodes as needed
|
||||
const icon = element?.meta?.icon ? () => h(element?.meta?.icon as object) : null;
|
||||
const node =
|
||||
element?.children && element?.children.length !== 0 ? (
|
||||
<a-sub-menu
|
||||
key={element?.name}
|
||||
v-slots={{
|
||||
icon,
|
||||
title: () => element?.meta?.locale || '',
|
||||
}}
|
||||
>
|
||||
{travel(element?.children)}
|
||||
</a-sub-menu>
|
||||
) : (
|
||||
<a-menu-item key={element?.name} v-slots={{ icon }} onClick={() => goto(element)}>
|
||||
{element?.meta?.locale || ''}
|
||||
</a-menu-item>
|
||||
);
|
||||
nodes.push(node as never);
|
||||
});
|
||||
}
|
||||
function travel(_route: RouteRecordRaw[] = [], nodes: any[] = []) {
|
||||
if (!Array.isArray(_route)) return nodes;
|
||||
_route.forEach((element) => {
|
||||
// 跳过没有 name 的菜单项,防止 key 报错
|
||||
if (!element?.name) return;
|
||||
|
||||
const icon = element?.meta?.icon ? () => h(element.meta.icon as object) : null;
|
||||
if (element.children && element.children.length > 0) {
|
||||
nodes.push(
|
||||
<a-sub-menu
|
||||
key={String(element.name)}
|
||||
v-slots={{
|
||||
icon,
|
||||
title: () => element.meta?.locale || '',
|
||||
}}
|
||||
>
|
||||
{travel(element.children)}
|
||||
</a-sub-menu>,
|
||||
);
|
||||
} else {
|
||||
nodes.push(
|
||||
<a-menu-item key={String(element.name)} v-slots={{ icon }} onClick={() => goto(element)}>
|
||||
{element.meta?.locale || ''}
|
||||
</a-menu-item>,
|
||||
);
|
||||
}
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
return travel(menuTree.value ?? []);
|
||||
|
||||
@ -32,24 +32,6 @@ const router = createRouter({
|
||||
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',
|
||||
name: 'permission',
|
||||
@ -66,6 +48,15 @@ const router = createRouter({
|
||||
requiresAuth: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
redirect: '/dataEngine/hotTranslation',
|
||||
children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
scrollBehavior() {
|
||||
return { top: 0 };
|
||||
|
||||
@ -15,12 +15,26 @@ interface EnterpriseState {
|
||||
|
||||
export const useEnterpriseStore = defineStore('enterprise', {
|
||||
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: {
|
||||
setEnterpriseInfo(enterpriseInfo: EnterpriseInfo) {
|
||||
console.log('setEnterpriseInfo', enterpriseInfo);
|
||||
this.enterpriseInfo = enterpriseInfo;
|
||||
localStorage.setItem('enterpriseInfo', JSON.stringify(enterpriseInfo));
|
||||
},
|
||||
clearEnterpriseInfo() {
|
||||
this.enterpriseInfo = null;
|
||||
localStorage.removeItem('enterpriseInfo');
|
||||
},
|
||||
setEnterpriseName(name: string) {
|
||||
if (this.enterpriseInfo) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { fetchProfileInfo } from '@/api/all/login';
|
||||
|
||||
interface UserInfo {
|
||||
id: number;
|
||||
@ -19,7 +20,7 @@ interface UserState {
|
||||
token: string;
|
||||
userInfo: UserInfo | null;
|
||||
companyInfo: CompanyInfo | null;
|
||||
isLogin: boolean;
|
||||
// isLogin: boolean;
|
||||
}
|
||||
|
||||
interface UserInfo {
|
||||
@ -33,7 +34,6 @@ export const useUserStore = defineStore('user', {
|
||||
token: localStorage.getItem('accessToken') || '',
|
||||
userInfo: null,
|
||||
companyInfo: null,
|
||||
isLogin: false,
|
||||
}),
|
||||
getters: {
|
||||
isLogin(): boolean {
|
||||
@ -46,6 +46,7 @@ export const useUserStore = defineStore('user', {
|
||||
this.token = `Bearer ${token}`;
|
||||
localStorage.setItem('accessToken', this.token);
|
||||
},
|
||||
|
||||
deleteToken() {
|
||||
this.token = '';
|
||||
localStorage.removeItem('accessToken');
|
||||
@ -62,18 +63,11 @@ export const useUserStore = defineStore('user', {
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
getUserInfo(): UserInfo | null {
|
||||
return this.userInfo;
|
||||
},
|
||||
|
||||
// 设置公司信息
|
||||
setCompanyInfo(companyInfo: CompanyInfo | null) {
|
||||
this.companyInfo = companyInfo;
|
||||
},
|
||||
|
||||
// 获取公司信息
|
||||
getCompanyInfo(): CompanyInfo | null {
|
||||
return this.companyInfo;
|
||||
async fetchUserInfo() {
|
||||
const { code, data } = await fetchProfileInfo();
|
||||
if (code === 200) {
|
||||
this.setUserInfo(data);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import router from '@/router';
|
||||
|
||||
import { useUserStore } from '@/stores';
|
||||
import { useEnterpriseStore } from '@/stores/modules/enterprise';
|
||||
|
||||
// 登录
|
||||
export function goUserLogin(query?: any) {
|
||||
@ -23,7 +24,10 @@ export function handleUserHome() {
|
||||
|
||||
export function handleUserLogout() {
|
||||
const userStore = useUserStore();
|
||||
const store = useEnterpriseStore();
|
||||
|
||||
userStore.deleteToken();
|
||||
store.clearEnterpriseInfo();
|
||||
|
||||
goUserLogin();
|
||||
}
|
||||
|
||||
@ -275,9 +275,9 @@ const getProfileInfo = async () => {
|
||||
let enterprises = data['enterprises'];
|
||||
mobileNumber.value = data['mobile'];
|
||||
accounts.value = enterprises;
|
||||
|
||||
enterpriseStore.setEnterpriseInfo(data);
|
||||
userStore.setUserInfo(data);
|
||||
|
||||
if (enterprises.length > 0) {
|
||||
if (enterprises.length === 1) {
|
||||
await enterpriseStore.updateEnterpriseInfo();
|
||||
|
||||
@ -105,6 +105,8 @@ const okText = computed(() => {
|
||||
});
|
||||
const customerServiceVisible = ref(false);
|
||||
const canAddAccount = computed(() => {
|
||||
if (!enterpriseInfo) return false;
|
||||
|
||||
return enterpriseInfo.sub_account_quota > enterpriseInfo.used_sub_account_count;
|
||||
});
|
||||
|
||||
@ -124,9 +126,11 @@ function handlePageSizeChange(pageSize: number) {
|
||||
|
||||
async function getSubAccount() {
|
||||
const res = await fetchSubAccountPage(params);
|
||||
const { data, total } = res.data;
|
||||
pagination.total = total;
|
||||
data.value = data;
|
||||
const { data, total, code } = res.data;
|
||||
if (code === 200) {
|
||||
pagination.total = total;
|
||||
data.value = data;
|
||||
}
|
||||
}
|
||||
async function handleAddAccount() {
|
||||
if (canAddAccount.value) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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 }">
|
||||
{{ record.name }}
|
||||
</template>
|
||||
@ -11,7 +11,7 @@
|
||||
<Modal v-model:visible="infoVisible" width="480px" title="修改企业名称" :okText="okText" @ok="handleOk">
|
||||
<p class="tips">
|
||||
企业名称只能修改2次,请谨慎操作。<span
|
||||
>(剩余{{ enterpriseInfo.update_name_quota - enterpriseInfo.used_update_name_count }}次)
|
||||
>(剩余{{ enterpriseInfo!.update_name_quota - enterpriseInfo!.used_update_name_count }}次)
|
||||
</span>
|
||||
</p>
|
||||
<a-form
|
||||
@ -54,12 +54,15 @@ const columns = [
|
||||
slotName: 'action',
|
||||
},
|
||||
];
|
||||
const data = ref([enterpriseInfo]);
|
||||
|
||||
const infoVisible = ref(false);
|
||||
const customerServiceVisible = ref(false);
|
||||
|
||||
const dataSource = computed(() => {
|
||||
return enterpriseInfo ? [enterpriseInfo] : [];
|
||||
});
|
||||
const canUpdate = computed(() => {
|
||||
if (!enterpriseInfo) return false;
|
||||
return enterpriseInfo.update_name_quota > enterpriseInfo.used_update_name_count;
|
||||
});
|
||||
|
||||
@ -72,7 +75,7 @@ const okText = computed(() => {
|
||||
|
||||
function handleUpdate() {
|
||||
if (!canUpdate.value) {
|
||||
form.name = enterpriseInfo.name;
|
||||
form.name = enterpriseInfo!.name;
|
||||
}
|
||||
infoVisible.value = true;
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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 }">
|
||||
<div class="pt-3px pb-3px">
|
||||
<a-avatar :image-url="record.head_image" :size="32" />
|
||||
@ -85,7 +85,7 @@ import axios from 'axios';
|
||||
import { useUserStore } from '@/stores';
|
||||
|
||||
const store = useUserStore();
|
||||
const userInfo = store.getUserInfo();
|
||||
const userInfo = store.userInfo;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -97,7 +97,7 @@ const columns = [
|
||||
slotName: 'mobile',
|
||||
},
|
||||
];
|
||||
const data = reactive([userInfo]);
|
||||
|
||||
const infoVisible = ref(false);
|
||||
const imageVisible = ref(false);
|
||||
const mobileVisible = ref(false);
|
||||
@ -108,6 +108,10 @@ const formRef = ref();
|
||||
const isSendCaptcha = ref(false);
|
||||
const uploadInputRef = ref();
|
||||
|
||||
const dataSource = computed(() => {
|
||||
return userInfo ? [userInfo] : [];
|
||||
});
|
||||
|
||||
// 表单校验规则
|
||||
const formRules = {
|
||||
mobile: [
|
||||
|
||||
Reference in New Issue
Block a user