wjx 4 недель назад
Родитель
Сommit
4f696758bc

+ 1 - 1
config/config.ts

@@ -93,7 +93,7 @@ export default defineConfig({
    * @name layout 插件
    * @doc https://umijs.org/docs/max/layout-menu
    */
-  title: '趣程系统中控台',
+  title: '趣程集团数智中台',
   layout: {
     locale: true,
     ...defaultSettings,

+ 1 - 1
config/defaultSettings.ts

@@ -15,7 +15,7 @@ const Settings: ProLayoutProps & {
   fixedHeader: true,
   fixSiderbar: true,
   colorWeak: false,
-  title: '趣程系统中控台',
+  title: '趣程集团数智中台',
   pwa: true,
   logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
   iconfontUrl: '',

+ 37 - 5
src/access.ts

@@ -1,11 +1,43 @@
+import { getMyMenu } from "./utils/menu";
+
 /**
  * @see https://umijs.org/docs/max/access#access
  * */
-export default function access(
-  initialState: { currentUser?: API.CurrentUser } | undefined,
-) {
-  const { currentUser } = initialState ?? {};
+export default function access(initialState: { currentUser?: API.CurrentUser, menu?: any } | undefined) {
+  const { currentUser, menu } = initialState ?? {};
+
+  const obj: {[x: string]: any} = {}
+
+  const btnMap = (btns: any) => {//按钮级权限
+    btns?.map((btn:any)=>{
+      Object.keys(btn).forEach((key: string) => {
+        if(key === 'name'){
+          obj[btn[key]] = true
+        }
+      })
+    })
+  }
+
+  const nameMap = (menu: any[]) => {//路由权限
+    menu?.forEach((item: any) => {
+      const arr = item?.path?.split('/')//分割path路径为数组
+      if (Array.isArray(arr)) {
+        obj[arr[arr?.length - 1]] = item?.roles?.indexOf(currentUser?.access) !== -1 //将路径的最后一个字段作为权限名称,值为查找当前路由的roles的值是否存在个人信息权限中,不存在就是false不展示
+      }
+      if (item.routes) {//假如item有子路由重新执行函数
+        nameMap(item.routes)
+      }
+      if (item?.routes?.length >0 && !item?.routes[0].path) {//假如item有按钮路由执行按钮权限判断
+        btnMap(item.routes)
+      }
+    })
+  }
+
+  if (menu) {
+    const data = getMyMenu(menu)
+    nameMap(data)//后端菜单列表
+  }
   return {
-    canAdmin: currentUser && currentUser.access === 'admin',
+    ...obj
   };
 }

+ 0 - 1
src/app.tsx

@@ -42,7 +42,6 @@ export async function getInitialState(): Promise<{
     try {
       sessionStorage.removeItem('IS_MES')
       const currentUser = await fetchUserInfo();
-      console.log('currentUser', currentUser)
       if (currentUser) {
         const { companyRelationInfo, userInfo: { powerLevel, nickname, userId, phone, sex }, onlineCompanyId } = currentUser
         const companyInfo = companyRelationInfo?.filter((item: { companyId: number }) => item.companyId !== 4 && item.companyId !== 3)

BIN
src/assets/image/qucheng.png


+ 4 - 2
src/components/RightContent/AvatarDropdown.tsx

@@ -127,8 +127,10 @@ export const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ children }) =
   const setCompanyHandle = (companyId: number) => {
     selectCompany.run(companyId).then((res: any) => {
       setSwitchOpen(false)
-      sessionStorage.setItem('Admin-Token', res?.data?.token)
-      window.location.reload()
+      if (res?.token) {
+        localStorage.setItem('Admin-Token', res?.token)
+        window.location.reload()
+      }
     })
   }
   return (

+ 1 - 1
src/mocks/systemData.ts

@@ -82,7 +82,7 @@ export const SYSTEMS_DATA: BusinessSystem[] = [
     icon: 'system',
     iconBackColor: '#5981B9',
     iconColor: '#FFFFFF',
-    url: `https://erp.zanxiangnet.com/#/login?token=${localStorage.getItem('Admin-Token')}`
+    url: `https://erp.zanxiangnet.com/#/login?token=${encodeURIComponent(localStorage.getItem('Admin-Token') || '')}`
   },
   {
     id: 'gameManage',

+ 6 - 5
src/pages/Welcome.tsx

@@ -64,10 +64,10 @@ const Welcome: React.FC = () => {
 				<div className="flex justify-between items-center h-16">
 					<div className="flex items-center">
 						<div className="flex-shrink-0 flex items-center">
-							<div className="w-8 h-8 rounded-lg flex items-center justify-center text-white mr-2">
-								<img src={logo} alt="" />
+							<div className="h-8 rounded-lg flex items-center justify-center text-white mr-2">
+								<img src={logo} style={{height: '100%'}} alt="" />
 							</div>
-							<span className="font-semibold text-gray-900 dark:text-white" style={{ fontSize: 18 }}>趣程系统中控台</span>
+							{/* <span className="font-semibold text-gray-900 dark:text-white" style={{ fontSize: 18 }}>趣程集团数智中台</span> */}
 						</div>
 					</div>
 
@@ -92,7 +92,8 @@ const Welcome: React.FC = () => {
 			{/* 欢迎信息 */}
 			<div className="mb-8">
 				<h1 className="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-gray-900 dark:text-white">
-					欢迎回来,{initialState?.currentUser?.name || '用户'}
+					欢迎回来
+					{/* ,{initialState?.currentUser?.name || '用户'} */}
 				</h1>
 				<p className="text-gray-600 dark:text-gray-400 mt-1">
 					这里是所有趣程内部系统的入口,选择您需要访问的系统
@@ -212,7 +213,7 @@ const Welcome: React.FC = () => {
 			<div className="container mx-auto px-4 sm:px-6 lg:px-8">
 				<div className="flex flex-col md:flex-row justify-between items-center">
 					<p className="text-sm text-gray-500 dark:text-gray-400">
-						© 2025 趣程内部系统中控台. 保留所有权利.
+						© 2025 趣程集团数智中台. 保留所有权利.
 					</p>
 				</div>
 			</div>

+ 0 - 2
src/pages/user/login/index.tsx

@@ -20,7 +20,6 @@ import Settings from '../../../../config/defaultSettings';
 import { api } from '@/services/env';
 import SelectCompany from './selectCompany';
 import { getCode } from '@/services/user/login';
-import logo from '@/assets/image/qucheng.png';
 
 const useStyles = createStyles(({ token }) => {
   return {
@@ -182,7 +181,6 @@ const Login: React.FC = () => {
             minWidth: 280,
             maxWidth: '75vw',
           }}
-          logo={logo}
           title={Settings.title}
           subTitle={'趣程数字业务指挥中心(整合公众号/企微/广告投放)'}
           onFinish={async (values) => {

+ 73 - 0
src/utils/index.ts

@@ -0,0 +1,73 @@
+import moment from 'moment';
+/**
+ * 返回是否为移动端
+ * @returns 
+ */
+export const isMobile = (): boolean => {
+    const u = navigator.userAgent
+    const isPhone = !!u.match(/AppleWebKit.*Mobile.*/) || u.indexOf('iPad') > -1
+    return isPhone
+}
+
+/**
+ * 下载Excel
+ * @param data 
+ * @param type 
+ * @param fileName 
+ */
+export const downloadFile = (data: BlobPart, type: any, fileName: string) => {
+    const blob = new Blob([data], { type: `application/${type};` });
+    const downloadElement = document.createElement('a');
+    const href = window.URL.createObjectURL(blob);
+    downloadElement.href = href;
+    downloadElement.download = fileName;
+    document.body.appendChild(downloadElement);
+    downloadElement.click();
+    document.body.removeChild(downloadElement);
+    window.URL.revokeObjectURL(href);
+}
+type Type = "day" | "week" | "month" | "year" | "years" | "y" | "months" | "M" | "weeks" | "w" | "days" | "d" | "hour" | "hours" | "h" | "minute"
+type Format = 'YYYY-MM-DD' | 'YYYY-MM-DD HH' | 'YYYY-MM-DD HH:mm' | 'YYYY-MM-DD HH:mm:ss'
+export const useAddTime = (num: number, type: Type, format?: Format, date?: Date | string): string => {
+    return moment(date || new Date()).add(num, type).format(format || 'YYYY-MM-DD')
+}
+
+/**
+ * 返回localStorage中的查询参数
+ * @param param0 
+ * @returns 
+ */
+export const getLocalStoragePage = ({
+    isSelectPitcherIds,
+    isSelctChannelIds,
+    isSelectBookNames,
+    isDataSelectChannelDisabledPitcher,
+    isCostTime,
+    isDay1
+}: { isSelectPitcherIds?: boolean, isSelctChannelIds?: boolean, isSelectBookNames?: boolean, isDataSelectChannelDisabledPitcher?: boolean, isDay1?: boolean, isCostTime?: boolean }) => {
+    const { pitcher_ids, channel_ids, book_names, day1 } = JSON.parse(localStorage.getItem('QUERYFORMNOVEL') || '{}')
+    const params: { [x: string]: any } = {}
+    if (isSelectPitcherIds && pitcher_ids?.length) {
+        params.pitcher_ids = pitcher_ids
+    }
+    if (isSelctChannelIds && channel_ids?.length) {
+        params.channel_ids = channel_ids
+        if (isDataSelectChannelDisabledPitcher) {
+            delete params?.pitcher_ids
+        }
+    }
+    if (isSelectBookNames && book_names?.length) {
+        params.book_names = book_names
+    }
+
+    if (isDay1 && day1?.[0]) {
+        if (!isCostTime) {
+            params.start = day1[0]
+            params.end = day1[1]
+        } else {
+            params.cost_time_start = day1[0]
+            params.cost_time_end = day1[1]
+        }
+    }
+    return params
+}

+ 112 - 0
src/utils/menu.ts

@@ -0,0 +1,112 @@
+
+interface ButtonItem {
+    meta: {
+        title: string
+    }
+    menuId?: string
+}
+
+interface ProcessedButton {
+    name: string
+    key?: string
+}
+
+const btnFun = (items: { childrenBtn?: ButtonItem[] }): ProcessedButton[] => {
+    return items.childrenBtn?.map(btn => ({
+        name: btn.meta.title,
+        key: btn.menuId
+    })) ?? []
+}
+
+
+interface RouteItem {
+    path: string
+    meta: {
+        title: string
+        icon?: string
+    }
+    component: any
+    children?: RouteItem[]
+    childrenBtn?: any[]
+    menuId?: string
+}
+
+interface ProcessedRoute {
+  path: string;
+  name: string;
+  component: any;
+  icon?: string;
+  key?: string;
+  routes?: (ProcessedRoute | ProcessedButton)[];
+}
+
+const routeFun = (items: RouteItem): ProcessedRoute[] => {
+    return items.children?.map((route: RouteItem) => {
+        const baseRoute = {
+            path: route.path,
+            name: route.meta.title,
+            component: route.component,
+            icon: route.meta.icon || items.meta.icon,
+            key: route.menuId
+        }
+
+        if (route.children?.length) {
+            return {
+                ...baseRoute,
+                routes: routeFun(route)
+            }
+        }
+
+        if (route.childrenBtn?.length) {
+            return {
+                ...baseRoute,
+                routes: btnFun(route)
+            }
+        }
+
+        return baseRoute
+    }) ?? []
+}
+
+
+export const getMyMenu = (data: Record<string, any[]>) => {
+    // 提取有效菜单项并排序
+    const sortedItems = Object.keys(data)
+        .reverse()
+        .flatMap(key => Array.isArray(data[key]) && data[key]?.length ? [data[key][0]] : [])
+        .sort((a, b) => a.orderNum - b.orderNum)
+
+    // 转换菜单结构
+    const processedData = sortedItems.map(items => {
+        if (!items?.children?.length) {
+            return {
+                path: items.children[0].path,
+                name: items.meta.title,
+                icon: items.meta.icon,
+                component: items.children[0].component,
+                key: items.menuId
+            }
+        }
+        return {
+            path: items.path,
+            name: items.meta.title,
+            icon: items.meta.icon,
+            routes: routeFun(items),
+            key: items.menuId
+        }
+    })
+
+    // 过滤企业微信菜单
+    const wechatIndex = processedData.findIndex(i => i.path === '/enterpriseWeChat')
+    if (wechatIndex !== -1) {
+        const filteredRoutes = processedData[wechatIndex].routes?.filter(item =>
+            ["企微信息", "企微客户联系成员", "企微客服", "企微客服消息", "投诉信息"]
+                .includes(item.name)
+        )
+        filteredRoutes?.length
+            ? processedData[wechatIndex].routes = filteredRoutes
+            : processedData.splice(wechatIndex, 1)
+    }
+
+    return processedData
+}