feat: 管理中心路由调整、选择公司逻辑调整

This commit is contained in:
renxiaodong
2025-06-23 05:58:04 -04:00
parent 7b79443980
commit 82dfa3faeb
11 changed files with 134 additions and 86 deletions

View File

@ -1,3 +1,7 @@
/*
* @Author: RenXiaoDong
* @Date: 2025-06-23 03:56:22
*/
import Http from '@/api';
// 导出一个函数,用于获取登录验证码
@ -38,3 +42,8 @@ export const fetchEditPhoneCaptcha = (params = {}) => {
export const fetchBindPhone = (params = {}) => {
return Http.put('/v1/me/mobile', params);
};
// 根据id获取企业信息
export const fetchEnterpriseInfo = (id: number) => {
return Http.get(`/v1/enterprises/${id}`);
};

View File

@ -2,7 +2,7 @@
* @Author: 田鑫
* @Date: 2023-02-17 11:58:44
* @LastEditors: Please set LastEditors
* @LastEditTime: 2025-06-23 03:16:47
* @LastEditTime: 2025-06-23 05:51:32
* @Description:
*/
@ -23,8 +23,6 @@ const HttpStatusCode = {
import { useEnterpriseStore } from '@/stores/modules/enterprise';
import pinia from '@/stores';
const store = useEnterpriseStore(pinia);
const enterprise = store.getEnterpriseInfo();
//* 导出Request类可以用来自定义传递配置来创建实例
export class Request {
@ -44,12 +42,16 @@ export class Request {
this.instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
const store = useEnterpriseStore(pinia);
const enterprise = store.getEnterpriseInfo();
const token = localStorage.getItem('accessToken') as string;
config.headers!.Authorization = token;
if (enterprise) {
config.headers!['enterprise-id'] = enterprise.id;
}
return config;
},
(err: any) => {

View File

@ -78,7 +78,7 @@ export default defineComponent({
};
const renderSubMenu = () => {
function travel(_route: RouteRecordRaw[], nodes = []) {
if (_route) {
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;
@ -103,7 +103,7 @@ export default defineComponent({
}
return nodes;
}
return travel(menuTree.value);
return travel(menuTree.value ?? []);
};
return () => (
<a-menu

View File

@ -1,3 +1,7 @@
/*
* @Author: RenXiaoDong
* @Date: 2025-06-19 01:45:53
*/
import type { RouteRecordRaw, RouteRecordNormalized } from 'vue-router';
import { useAppStore } from '@/stores';

View File

@ -24,14 +24,14 @@ onMounted(() => {
});
const appStore = useAppStore();
function setServerMenu() {
console.log('setServerMenu');
}
const setServerMenu = () => {
router.push('/management/person');
};
const handleSelect = (index: any) => {
if (index === 0) {
router.push('/workplace');
} else {
router.push('/dataEngine/dataEngine/hotTranslation');
router.push('/dataEngine/hotTranslation');
}
};
@ -39,17 +39,17 @@ const handleDopdownClick = (index: any, ind: any) => {
let children = lists.value[index].children;
let indPath = children[ind];
if (indPath.name == '行业热门话题洞察') {
router.push('/dataEngine/dataEngine/hotTranslation');
router.push('/dataEngine/hotTranslation');
} else if (indPath.name == '行业词云') {
router.push('/dataEngine/dataEngine/hotCloud');
router.push('/dataEngine/hotCloud');
} else if (indPath.name == '行业关键词动向') {
router.push('/dataEngine/dataEngine/keyWord');
router.push('/dataEngine/keyWord');
} else if (indPath.name == '用户痛点观察') {
router.push('/dataEngine/dataEngine/userPainPoints');
router.push('/dataEngine/userPainPoints');
} else if (indPath.name == '重点品牌动向') {
router.push('/dataEngine/dataEngine/keyBrandMovement');
router.push('/dataEngine/keyBrandMovement');
} else if (indPath.name == '用户画像') {
router.push('/dataEngine/dataEngine/userPersona');
router.push('/dataEngine/userPersona');
}
};
</script>

View File

@ -13,10 +13,10 @@ export default function setupUserLoginInfoGuard(router: Router) {
NProgress.start();
const userStore = useUserStore();
const requireLogin = to?.meta?.requireLogin || 0;
const requiresAuth = to?.meta?.requiresAuth || false;
const isLogin = !!userStore.isLogin;
if (requireLogin === 1 && !isLogin) {
if (requiresAuth && !isLogin) {
goUserLogin();
next();
return;

View File

@ -11,7 +11,7 @@ import 'nprogress/nprogress.css';
import createRouteGuard from './guard';
NProgress.configure({ showSpinner: false }); // NProgress Configuration
// console.log({ appRoutes });
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
@ -20,7 +20,7 @@ const router = createRouter({
name: 'UserLogin',
component: () => import('@/views/components/login'),
meta: {
requireLogin: 0,
requiresAuth: false,
},
},
{
@ -29,33 +29,33 @@ const router = createRouter({
component: () => import('@/views/components/workplace'),
meta: {
hideSidebar: true,
requireLogin: 1,
requiresAuth: true,
},
},
{
path: '/',
name: 'Home',
redirect: '/dataEngine/dataEngine/hotTranslation',
redirect: '/dataEngine/hotTranslation',
children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
meta: {
requireLogin: 1,
},
},
{
path: '/dataEngine',
name: 'dataEngine',
redirect: '/dataEngine/dataEngine/hotTranslation',
children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
meta: {
requireLogin: 1,
requiresAuth: true,
},
},
// {
// path: '/dataEngine',
// name: 'dataEngine',
// redirect: '/dataEngine/hotTranslation',
// children: [...appRoutes, REDIRECT_MAIN, NOT_FOUND_ROUTE],
// meta: {
// requiresAuth: 1,
// },
// },
{
path: '/permission',
name: 'permission',
component: () => import('@/views/components/permission/choose-enterprise.vue'),
meta: {
requireLogin: 1,
requiresAuth: true,
},
},
{
@ -63,31 +63,7 @@ const router = createRouter({
name: 'auth',
component: () => import('@/views/components/permission/auth.vue'),
meta: {
requireLogin: 0,
},
},
{
path: '/management/person',
name: 'person',
component: () => import('@/views/components/management/person'),
meta: {
requireLogin: 1,
},
},
{
path: '/management/enterprise',
name: 'enterprise',
component: () => import('@/views/components/management/enterprise'),
meta: {
requireLogin: 1,
},
},
{
path: '/management/account',
name: 'account',
component: () => import('@/views/components/management/account'),
meta: {
requireLogin: 1,
requiresAuth: false,
},
},
],

View File

@ -0,0 +1,52 @@
/*
* @Author: RenXiaoDong
* @Date: 2025-06-23 04:29:03
*/
import { IconBookmark } from '@arco-design/web-vue/es/icon';
import type { AppRouteRecordRaw } from '../types';
const COMPONENTS: AppRouteRecordRaw = {
path: 'management',
name: 'management',
meta: {
locale: '管理中心',
icon: IconBookmark,
requiresAuth: true,
roles: ['*'],
requiresSidebar: true,
},
children: [
{
path: 'person',
name: '个人信息',
component: () => import('@/views/components/management/person'),
meta: {
locale: '个人信息',
requiresAuth: true,
roles: ['*'],
},
},
{
path: 'enterprise',
name: '企业信息',
component: () => import('@/views/components/management/enterprise'),
meta: {
locale: '企业信息',
requiresAuth: true,
roles: ['*'],
},
},
{
path: 'account',
name: '账号管理',
component: () => import('@/views/components/management/account'),
meta: {
locale: '账号管理',
requiresAuth: true,
roles: ['*'],
},
},
],
};
export default COMPONENTS;

View File

@ -1,3 +1,5 @@
import { fetchEnterpriseInfo } from '@/api/all/login';
interface EnterpriseInfo {
id: number;
name: string;
@ -13,18 +15,11 @@ interface EnterpriseState {
export const useEnterpriseStore = defineStore('enterprise', {
state: (): EnterpriseState => ({
// todo 暂时写死登录功能完成后记得重置为null哦
enterpriseInfo: {
id: 1,
name: '企业1',
update_name_quota: 2,
used_update_name_count: 1,
sub_account_quota: 2,
used_sub_account_count: 0,
},
enterpriseInfo: null,
}),
actions: {
setEnterpriseInfo(enterpriseInfo: EnterpriseInfo) {
console.log('setEnterpriseInfo', enterpriseInfo);
this.enterpriseInfo = enterpriseInfo;
},
setEnterpriseName(name: string) {
@ -45,5 +40,12 @@ export const useEnterpriseStore = defineStore('enterprise', {
getEnterpriseInfo(): EnterpriseInfo | null {
return this.enterpriseInfo;
},
async updateEnterpriseInfo() {
const res = await fetchEnterpriseInfo(this.enterpriseInfo!.id);
const { code, data } = res;
if (code === 200) {
this.setEnterpriseInfo(data);
}
},
},
});

View File

@ -101,14 +101,14 @@
v-for="(account, index) in accounts"
:key="index"
class="account-item"
:class="{ selected: selectedAccount === index }"
@click="selectAccount(index)"
:class="{ selected: selectedAccountIndex === index }"
@click="selectAccount(account, index)"
>
<a-list-item-meta>
<template #title>
<div style="display: flex; align-items: center; gap: 12px">
<a-checkbox :model-value="selectedAccount === index" />
<a-typography-text>{{ account.name }}</a-typography-text>
<a-checkbox :model-value="selectedAccountIndex === index" />
<a-typography-text>{{ account.name || '-' }}</a-typography-text>
</div>
</template>
</a-list-item-meta>
@ -124,11 +124,13 @@ import PuzzleVerification from './components/PuzzleVerification.vue';
import { fetchLoginCaptCha, fetchAuthorizationsCaptcha, fetchProfileInfo } from '@/api/all/login';
import { ref, reactive, onUnmounted, computed } from 'vue';
import { useUserStore } from '@/stores';
import { useEnterpriseStore } from '@/stores/modules/enterprise';
import { handleUserLogin } from '@/utils/user';
import router from '@/router';
const formRef = ref();
const userStore = useUserStore();
const enterpriseStore = useEnterpriseStore();
const countdown = ref(0);
let timer = ref();
const isLogin = ref(true);
@ -138,7 +140,7 @@ const hasGetCode = ref(false);
const submitting = ref(false);
const hasCheck = ref(false);
const mobileNumber = ref('');
const selectedAccount = ref(0);
const selectedAccountIndex = ref(0);
const accounts = ref([]);
@ -199,8 +201,9 @@ const disabledSubmitBtn = computed(() => {
return !isFormValid.value;
});
const selectAccount = (index: any) => {
selectedAccount.value = index;
const selectAccount = (account: any, index: any) => {
enterpriseStore.setEnterpriseInfo(account);
selectedAccountIndex.value = index;
};
const validateField = (field: string) => {
@ -211,8 +214,10 @@ const clearError = (field: string) => {
formRef.value.clearValidate(field);
};
const handleOk = () => {
const handleOk = async () => {
visible.value = false;
await enterpriseStore.updateEnterpriseInfo();
handleUserLogin();
};
@ -259,15 +264,14 @@ const handleVerificationSubmit = async () => {
const getProfileInfo = async () => {
const { code, data } = await fetchProfileInfo();
if (code === 200) {
enterpriseStore.setEnterpriseInfo(data);
userStore.setUserInfo(data);
let enterprises = data['enterprises'];
mobileNumber.value = data['mobile'];
accounts.value = enterprises;
if (enterprises.length > 0) {
if (enterprises.length == 1) {
// let enterprise = enterprises[0];
// userStore.setCompanyInfo(enterprise);
if (enterprises.length === 1) {
await enterpriseStore.updateEnterpriseInfo();
handleUserLogin();
} else {
// 多个企业时候需要弹窗让用户选择企业

View File

@ -4,7 +4,7 @@
<template #info="{ record }">
<div class="pt-3px pb-3px">
<a-avatar :image-url="record.head_image" :size="32" />
{{ record.name }}
{{ record.name || '-' }}
<icon-edit size="13" class="ml-8px" @click="openEditInfoModal" />
</div>
</template>
@ -170,15 +170,17 @@ async function handleFileChange(event: Event) {
const file = target.files?.[0];
if (file) {
const fileExtension = getFileExtension(file.name);
const res = await fetchImageUploadFile({
const { data } = await fetchImageUploadFile({
suffix: fileExtension,
});
const { upload_url, file_name, file_url } = data;
const blob = new Blob([file], { type: file.type });
await axios.put(res.upload_url, blob, {
await axios.put(upload_url, blob, {
headers: { 'Content-Type': file.type },
});
userInfoForm.head_image = res.file_name;
userInfoForm.file_url = res.file_url;
userInfoForm.head_image = file_name;
userInfoForm.file_url = file_url;
}
}
function openEditImageModal() {
@ -191,8 +193,6 @@ function openEditMobileModal() {
async function handleSubmitUserInfo() {
await updateMyInfo(userInfoForm);
store.setUserName(userInfoForm.name);
store.setUserHeadImage(userInfoForm.file_url);
AMessage.success('修改成功!');
}
@ -235,7 +235,6 @@ async function handleUpdateMobile() {
const res = await formRef.value.validate();
if (res === true || res === undefined) {
await updateMobile(form);
store.setUserMobile(form.mobile);
AMessage.success('修改成功!');
}
}