@@ -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 Content from './content'; | ||||
import userService from '@/request/service/user'; | import userService from '@/request/service/user'; | ||||
import { useRequest } from "@/hooks/use-request"; | import { useRequest } from "@/hooks/use-request"; | ||||
import menuData from '../../mock/menu.json' | |||||
// import menuData from '../../mock/menu.json' | |||||
const BasicLayout: React.FC = () => { | const BasicLayout: React.FC = () => { | ||||
@@ -76,25 +76,7 @@ const BasicLayout: React.FC = () => { | |||||
useEffect(() => { | useEffect(() => { | ||||
if (!currentUserProfile || !menuList?.data) return; | 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 routes: Menu[] = []; | ||||
const formatedMenus = formatMenus(menus.filter(o => !o.parentId), menuGroup, routes); | |||||
console.log(formatedMenus); | |||||
console.log(menuList.data); | console.log(menuList.data); | ||||
const fixAndPushMenu = (item: Menu) => { | const fixAndPushMenu = (item: Menu) => { | ||||
@@ -105,18 +87,23 @@ const BasicLayout: React.FC = () => { | |||||
if(!item.path.startsWith('/')) { | if(!item.path.startsWith('/')) { | ||||
item.path = `/${item.path}` | 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) | routes.push(item) | ||||
if(item.children && item.children.length > 0) { | 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 => { | item.children.forEach(it => { | ||||
it.parentPaths = [...item.parentPaths||[], item.path] | |||||
it.parentPaths = parentPaths | |||||
fixAndPushMenu(it) | fixAndPushMenu(it) | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
menuList.data.forEach(item => fixAndPushMenu(item)) | menuList.data.forEach(item => fixAndPushMenu(item)) | ||||
setMenus([...formatedMenus, ...menuList.data]); | |||||
setMenus(menuList.data) //([...formatedMenus, ...menuList.data]); | |||||
console.log('components', components); | console.log('components', components); | ||||
replaceRoutes('*', [ | replaceRoutes('*', [ | ||||
...routes.map(menu => ({ | ...routes.map(menu => ({ | ||||
@@ -283,10 +283,9 @@ const SlideMenu = () => { | |||||
} | } | ||||
const treeMenuData = useCallback((menus: MenuType[]): ItemType[] => { | 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 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 { | return { | ||||
type: type, | type: type, | ||||
key: menu.path, | key: menu.path, | ||||
@@ -173,7 +173,7 @@ const MenuListPage: React.FC = () => { | |||||
<div className='flex justify-normal items-center'> | <div className='flex justify-normal items-center'> | ||||
<Form layout='inline' form={searchFrom}> | <Form layout='inline' form={searchFrom}> | ||||
<Form.Item name="name" label="菜单名称"> | <Form.Item name="name" label="菜单名称"> | ||||
<Input className='ml-[10px]' placeholder='请输入名称' allowClear/> | |||||
<Input placeholder='请输入名称' allowClear/> | |||||
</Form.Item> | </Form.Item> | ||||
<Form.Item className='ml-2 w-[130px]' name="status" label="状态"> | <Form.Item className='ml-2 w-[130px]' name="status" label="状态"> | ||||
<Select placeholder="请选择" allowClear > | <Select placeholder="请选择" allowClear > | ||||
@@ -1,13 +1,12 @@ | |||||
import React, { lazy, useEffect, useState } from 'react' | import React, { lazy, useEffect, useState } from 'react' | ||||
import { TreeSelect, Form, Input, InputNumber, Radio, Modal, Switch, Popover, Button, Space, List } from 'antd'; | 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 menuService from '@/request/service/menu'; | ||||
import { useRequest } from '@/hooks/use-request'; | import { useRequest } from '@/hooks/use-request'; | ||||
import type { DefaultOptionType } from 'antd/es/select'; | import type { DefaultOptionType } from 'antd/es/select'; | ||||
import type { Menu } from '@/models' | import type { Menu } from '@/models' | ||||
import { antdUtils } from '@/utils/antd'; | import { antdUtils } from '@/utils/antd'; | ||||
import * as Icon from "@ant-design/icons"; | import * as Icon from "@ant-design/icons"; | ||||
// 编写生成ReactNode的方法 | |||||
const icon2Element = (name: string) => { | const icon2Element = (name: string) => { | ||||
return <React.Suspense fallback={<></>}> | return <React.Suspense fallback={<></>}> | ||||
{React.createElement((Icon as any)[name], { | {React.createElement((Icon as any)[name], { | ||||
@@ -28,9 +27,9 @@ const MenuIcon: React.FC<MenuIconProps> = ({ value = '', onChange }) => { | |||||
if (i != 'default') icons.push(i) | if (i != 'default') icons.push(i) | ||||
} | } | ||||
const girdItems = icons.filter(i => i.endsWith('Outlined')) | 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) => { | const triggerChange = (changedValue: string) => { | ||||
onChange?.(changedValue); | onChange?.(changedValue); | ||||
setHovered(false) | 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} | open={hovered} | ||||
onOpenChange={handleOpenChange} | |||||
trigger="click"> | trigger="click"> | ||||
<Space> | <Space> | ||||
<Input value={value} /> | <Input value={value} /> | ||||
{icon2Element(value)} | |||||
{(value && girdItems.indexOf(value) >= 0) ? icon2Element(value) : <></>} | |||||
</Space> | </Space> | ||||
</Popover> | </Popover> | ||||
}; | }; | ||||
@@ -186,14 +190,14 @@ const MenuEditor: React.FC<MenuEditorProps> = (props) => { | |||||
<Radio.Group options={[ | <Radio.Group options={[ | ||||
{ value: 1, label: "目录" }, | { value: 1, label: "目录" }, | ||||
{ value: 2, label: "菜单" }, | { value: 2, label: "菜单" }, | ||||
{ value: 3, label: "按钮" } | |||||
{ value: 3, label: "按钮" }, | |||||
{ value: 4, label: "菜单组" } | |||||
]} optionType="button"> | ]} optionType="button"> | ||||
</Radio.Group> | </Radio.Group> | ||||
</Form.Item> | </Form.Item> | ||||
<Form.Item name="icon" label="菜单图标" > | <Form.Item name="icon" label="菜单图标" > | ||||
<MenuIcon /> | <MenuIcon /> | ||||
</Form.Item> | </Form.Item> | ||||
<Form.Item name="path" label="路由地址" | <Form.Item name="path" label="路由地址" | ||||
@@ -207,39 +211,34 @@ const MenuEditor: React.FC<MenuEditorProps> = (props) => { | |||||
<Input /> | <Input /> | ||||
</Form.Item> | </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> | ||||
<Form.Item name="sort" label="显示排序" > | <Form.Item name="sort" label="显示排序" > | ||||
<InputNumber min={1} max={100} /> | <InputNumber min={1} max={100} /> | ||||
</Form.Item> | </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> | ||||
<Form.Item name="visible" label="显示状态" valuePropName="checked"> | <Form.Item name="visible" label="显示状态" valuePropName="checked"> | ||||
<Switch checkedChildren="显示" unCheckedChildren="隐藏" /> | <Switch checkedChildren="显示" unCheckedChildren="隐藏" /> | ||||
</Form.Item> | </Form.Item> | ||||
{/* <Form.Item | |||||
name="cache" | |||||
label="缓存状态" | |||||
> | |||||
<Switch /> | |||||
</Form.Item> */} | |||||
</Form> | </Form> | ||||
</Modal> | </Modal> | ||||
</> | </> | ||||