@@ -1,343 +0,0 @@ | |||
[ | |||
{ | |||
"id": 1100, | |||
"parentId": 0, | |||
"name": "首页", | |||
"icon": "HomeOutlined", | |||
"type":0, | |||
"path": "/dashboard", | |||
"component": "/dashboard/index.tsx", | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1200, | |||
"parentId": 0, | |||
"name": "定制选品", | |||
"icon": "BgColorsOutlined", | |||
"type":0, | |||
"path": "/custom", | |||
"component": "", | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1210, | |||
"parentId": 1200, | |||
"name": "定制商品", | |||
"icon": "", | |||
"type":2, | |||
"path": "/product", | |||
"component": "", | |||
"orderNumber": 2, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1211, | |||
"parentId": 1210, | |||
"name": "样机", | |||
"icon": "", | |||
"type":0, | |||
"path": "/sample", | |||
"component": "/custom/product/sample/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1212, | |||
"parentId": 1210, | |||
"name": "素材", | |||
"icon": "", | |||
"type":0, | |||
"path": "/material", | |||
"component": "/custom/product/material/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1213, | |||
"parentId": 1210, | |||
"name": "款式", | |||
"icon": "", | |||
"type":0, | |||
"path": "/shape", | |||
"component": "/custom/product/shape/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1214, | |||
"parentId": 1210, | |||
"name": "成品", | |||
"icon": "", | |||
"type":0, | |||
"path": "/finished", | |||
"component": "/custom/product/finished/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1220, | |||
"parentId": 1200, | |||
"name": "模板配置", | |||
"icon": "", | |||
"type":2, | |||
"path": "/template", | |||
"component": "", | |||
"orderNumber": 2, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1221, | |||
"parentId": 1220, | |||
"name": "数据字典", | |||
"icon": "", | |||
"type":0, | |||
"path": "/dict", | |||
"component": "/custom/template/dict/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1222, | |||
"parentId": 1220, | |||
"name": "虾皮模板", | |||
"icon": "", | |||
"type":0, | |||
"path": "/xiapi", | |||
"component": "/custom/template/xiapi/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id":1223, | |||
"parentId": 1220, | |||
"name": "规则引擎", | |||
"icon": "", | |||
"type":0, | |||
"path": "/rules", | |||
"component": "/custom/template/rules/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1230, | |||
"parentId": 1200, | |||
"name": "平台商品", | |||
"icon": "", | |||
"type":2, | |||
"path": "/platform-product", | |||
"component": "", | |||
"orderNumber": 2, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1231, | |||
"parentId": 1230, | |||
"name": "虾皮", | |||
"icon": "", | |||
"type":0, | |||
"path": "/xiapi", | |||
"component": "/custom/platform-product/xiapi/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1232, | |||
"parentId": 1230, | |||
"name": "亚马逊", | |||
"icon": "", | |||
"type":0, | |||
"path": "/amazone", | |||
"component": "/custom/platform-product/amazone/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1240, | |||
"parentId": 1200, | |||
"name": "SDS商品", | |||
"icon": "", | |||
"type":2, | |||
"path": "/sds", | |||
"component": "", | |||
"orderNumber": 2, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1241, | |||
"parentId": 1240, | |||
"name": "成品库", | |||
"icon": "", | |||
"type":0, | |||
"path": "/finished-product-warehouse", | |||
"component": "/custom/sds/finished-product-warehouse/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1242, | |||
"parentId": 1240, | |||
"name": "款式", | |||
"icon": "", | |||
"type":0, | |||
"path": "/sds-shape", | |||
"component": "/custom/sds/sds-shape/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1243, | |||
"parentId": 1240, | |||
"name": "图案素材", | |||
"icon": "", | |||
"type":0, | |||
"path": "/pattern-material", | |||
"component": "/custom/sds/pattern-material/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1300, | |||
"parentId": 0, | |||
"name": "AI应用", | |||
"icon": "HighlightOutlined", | |||
"type":0, | |||
"path": "/ai", | |||
"component": "", | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1310, | |||
"parentId": 1300, | |||
"name": "AI 作图", | |||
"icon": "", | |||
"type":0, | |||
"path": "/makeup", | |||
"component": "/ai/makeup/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id":1320, | |||
"parentId": 1300, | |||
"name": "AI 画背景", | |||
"icon": "", | |||
"type":0, | |||
"path": "/background", | |||
"component": "/ai/background/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1330, | |||
"parentId": 1300, | |||
"name": "图片裂变", | |||
"icon": "", | |||
"type":0, | |||
"path": "/fission", | |||
"component": "/ai/fission/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1340, | |||
"parentId": 1300, | |||
"name": "轮廓出图", | |||
"icon": "", | |||
"type":0, | |||
"path": "/outline", | |||
"component": "/ai/outline/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1350, | |||
"parentId": 1300, | |||
"name": "一键白底", | |||
"icon": "", | |||
"type":0, | |||
"path": "/white-background", | |||
"component": "/ai/white-background/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1360, | |||
"parentId": 1300, | |||
"name": "AI P图", | |||
"icon": "", | |||
"type":0, | |||
"path": "/ps", | |||
"component": "/ai/ps/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1370, | |||
"parentId": 1300, | |||
"name": "AI 试装", | |||
"icon": "", | |||
"type":0, | |||
"path": "/try", | |||
"component": "/ai/try/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1380, | |||
"parentId": 1300, | |||
"name": "AI 作图2", | |||
"icon": "", | |||
"type":0, | |||
"path": "/makeup2", | |||
"component": "/ai/makeup2/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
}, | |||
{ | |||
"id": 1390, | |||
"parentId": 1300, | |||
"name": "旺嘉智库", | |||
"icon": "", | |||
"type":0, | |||
"path": "/smart-libs", | |||
"component": "/ai/smart-libs/index.tsx", | |||
"orderNumber": 3, | |||
"keepAlive": false, | |||
"visible":true | |||
} | |||
] |
@@ -17,7 +17,7 @@ import TabsLayout from './tabs-layout'; | |||
import Content from './content'; | |||
import userService from '@/request/service/user'; | |||
import { useRequest } from "@/hooks/use-request"; | |||
import menuData from '../../mock/menu.json' | |||
// import menuData from '../../mock/menu.json' | |||
const BasicLayout: React.FC = () => { | |||
@@ -76,25 +76,7 @@ const BasicLayout: React.FC = () => { | |||
useEffect(() => { | |||
if (!currentUserProfile || !menuList?.data) return; | |||
const menus:Array<Menu> = menuData as Array<Menu> ; | |||
const menuGroup = menus.reduce<Record<string, Menu[]>>((prev, menu) => { | |||
if (!menu.parentId) { | |||
return prev; | |||
} | |||
if (!prev[menu.parentId]) { | |||
prev[menu.parentId] = []; | |||
} | |||
prev[menu.parentId].push(menu); | |||
return prev; | |||
}, {}); | |||
const routes: Menu[] = []; | |||
const formatedMenus = formatMenus(menus.filter(o => !o.parentId), menuGroup, routes); | |||
console.log(formatedMenus); | |||
console.log(menuList.data); | |||
const fixAndPushMenu = (item: Menu) => { | |||
@@ -105,18 +87,23 @@ const BasicLayout: React.FC = () => { | |||
if(!item.path.startsWith('/')) { | |||
item.path = `/${item.path}` | |||
} | |||
item.path = [...item.parentPaths, item.path].join('') | |||
item.component = `${item.path}/index.tsx` | |||
const parentPath = item.parentPaths.join('') | |||
if(!item.path.startsWith(parentPath)) { | |||
item.path = [...item.parentPaths, item.path].join('') | |||
} | |||
item.component = item.component ? (item.path.endsWith('/index.tsx') ? item.path : `${item.path}/index.tsx`) : item.component | |||
routes.push(item) | |||
if(item.children && item.children.length > 0) { | |||
const parentPaths= item.path.replace('/index.tsx', '').split("/").filter(it => it!== '').map(it => `/${it}`) | |||
item.children.forEach(it => { | |||
it.parentPaths = [...item.parentPaths||[], item.path] | |||
it.parentPaths = parentPaths | |||
fixAndPushMenu(it) | |||
}) | |||
} | |||
} | |||
menuList.data.forEach(item => fixAndPushMenu(item)) | |||
setMenus([...formatedMenus, ...menuList.data]); | |||
setMenus(menuList.data) //([...formatedMenus, ...menuList.data]); | |||
console.log('components', components); | |||
replaceRoutes('*', [ | |||
...routes.map(menu => ({ | |||
@@ -283,10 +283,9 @@ const SlideMenu = () => { | |||
} | |||
const treeMenuData = useCallback((menus: MenuType[]): ItemType[] => { | |||
return (menus) | |||
.map((menu: MenuType) => { | |||
return (menus).map((menu: MenuType) => { | |||
const children = menu?.children?.filter(menu => menu.visible) || []; | |||
const type = menu.type === 2 ? "group": (menu.type === 3 ? "divider" : "") | |||
const type = (children.length > 0 && (menu.parentPaths?.length??0 > 0)) ? 'group': '' | |||
return { | |||
type: type, | |||
key: menu.path, | |||
@@ -173,7 +173,7 @@ const MenuListPage: React.FC = () => { | |||
<div className='flex justify-normal items-center'> | |||
<Form layout='inline' form={searchFrom}> | |||
<Form.Item name="name" label="菜单名称"> | |||
<Input className='ml-[10px]' placeholder='请输入名称' allowClear/> | |||
<Input placeholder='请输入名称' allowClear/> | |||
</Form.Item> | |||
<Form.Item className='ml-2 w-[130px]' name="status" label="状态"> | |||
<Select placeholder="请选择" allowClear > | |||
@@ -1,13 +1,12 @@ | |||
import React, { lazy, useEffect, useState } from 'react' | |||
import { TreeSelect, Form, Input, InputNumber, Radio, Modal, Switch, Popover, Button, Space, List } from 'antd'; | |||
import { ProList } from '@ant-design/pro-components'; | |||
import menuService from '@/request/service/menu'; | |||
import { useRequest } from '@/hooks/use-request'; | |||
import type { DefaultOptionType } from 'antd/es/select'; | |||
import type { Menu } from '@/models' | |||
import { antdUtils } from '@/utils/antd'; | |||
import * as Icon from "@ant-design/icons"; | |||
// 编写生成ReactNode的方法 | |||
const icon2Element = (name: string) => { | |||
return <React.Suspense fallback={<></>}> | |||
{React.createElement((Icon as any)[name], { | |||
@@ -28,9 +27,9 @@ const MenuIcon: React.FC<MenuIconProps> = ({ value = '', onChange }) => { | |||
if (i != 'default') icons.push(i) | |||
} | |||
const girdItems = icons.filter(i => i.endsWith('Outlined')) | |||
if (value === '' || girdItems.indexOf(value) < 0) { | |||
value = 'MenuUnfoldOutlined' | |||
} | |||
// if (value === '' || girdItems.indexOf(value) < 0) { | |||
// value = 'MenuUnfoldOutlined' | |||
// } | |||
const triggerChange = (changedValue: string) => { | |||
onChange?.(changedValue); | |||
setHovered(false) | |||
@@ -53,13 +52,18 @@ const MenuIcon: React.FC<MenuIconProps> = ({ value = '', onChange }) => { | |||
/>) | |||
} | |||
return <Popover placement="bottom" | |||
content={renderIcons} | |||
const handleOpenChange = (isOpen: boolean) => { | |||
setHovered(isOpen) | |||
} | |||
return <Popover placement="bottom" | |||
content={renderIcons} | |||
open={hovered} | |||
onOpenChange={handleOpenChange} | |||
trigger="click"> | |||
<Space> | |||
<Input value={value} /> | |||
{icon2Element(value)} | |||
{(value && girdItems.indexOf(value) >= 0) ? icon2Element(value) : <></>} | |||
</Space> | |||
</Popover> | |||
}; | |||
@@ -186,14 +190,14 @@ const MenuEditor: React.FC<MenuEditorProps> = (props) => { | |||
<Radio.Group options={[ | |||
{ value: 1, label: "目录" }, | |||
{ value: 2, label: "菜单" }, | |||
{ value: 3, label: "按钮" } | |||
{ value: 3, label: "按钮" }, | |||
{ value: 4, label: "菜单组" } | |||
]} optionType="button"> | |||
</Radio.Group> | |||
</Form.Item> | |||
<Form.Item name="icon" label="菜单图标" > | |||
<MenuIcon /> | |||
</Form.Item> | |||
<Form.Item name="path" label="路由地址" | |||
@@ -207,39 +211,34 @@ const MenuEditor: React.FC<MenuEditorProps> = (props) => { | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="component" label="组件地址" > | |||
<Input /> | |||
<Form.Item | |||
noStyle | |||
shouldUpdate={(prevValues, currentValues) => prevValues.type !== currentValues.type} | |||
> | |||
{({ getFieldValue }) => | |||
getFieldValue('type') === 2 ? ( | |||
<Form.Item name="component" label="组件地址" > | |||
<Input /> | |||
</Form.Item> | |||
) : null | |||
} | |||
</Form.Item> | |||
<Form.Item name="sort" label="显示排序" > | |||
<InputNumber min={1} max={100} /> | |||
</Form.Item> | |||
<Form.Item name="status" label="菜单状态" | |||
// getValueProps={(value: number) => { | |||
// const checked = value !== 0; | |||
// console.log(checked) | |||
// return { checked } | |||
// }} | |||
valuePropName="checked" | |||
// normalize={(value: boolean) => { | |||
// // prevValues.status = value ? 0 : 1 | |||
// return value ? 0 : 1 | |||
// }} | |||
> | |||
<Switch checkedChildren="开启" unCheckedChildren="关闭" /> | |||
<Form.Item name="status" label="菜单状态"> | |||
<Radio.Group options={[ | |||
{ value: 0, label: "开启" }, | |||
{ value: 1, label: "关闭" } | |||
]} optionType="default"> | |||
</Radio.Group> | |||
</Form.Item> | |||
<Form.Item name="visible" label="显示状态" valuePropName="checked"> | |||
<Switch checkedChildren="显示" unCheckedChildren="隐藏" /> | |||
</Form.Item> | |||
{/* <Form.Item | |||
name="cache" | |||
label="缓存状态" | |||
> | |||
<Switch /> | |||
</Form.Item> */} | |||
</Form> | |||
</Modal> | |||
</> | |||