Commit 381c4ada authored by 前端-许佳敏's avatar 前端-许佳敏

修改树形菜单

parent 09168d12
......@@ -36,7 +36,7 @@
"@umijs/test": "^3.2.0",
"bizcharts": "^4.0.7",
"copy-to-clipboard": "^3.3.1",
"god": "0.1.20",
"god": "0.1.21",
"lint-staged": "^10.0.7",
"mobx": "^5.15.4",
"mobx-react": "^6.2.2",
......
import React, { useState, useEffect } from 'react'
import { Select } from 'antd';
import { useDebounceFn } from '@umijs/hooks';
import { ISchemaFieldComponentProps, FormPath, useFormEffects, createFormActions, createAsyncFormActions } from '@formily/antd'
// 自定义搜索型下拉框
const SearchSelect = (props: ISchemaFieldComponentProps) => {
const { schema, form, path } = props
// 可选参数 fetchSearch, select为search
const { fetchSearch, fetchParams = 'name', fetchFormat, ...resetProps } = schema.getExtendsComponentProps()
const [dataSource, setDataSource] = useState<any[]>([])
const [loading, setLoading] = useState(false)
console.log(dataSource)
const dispatchSearch = (searchValue: string) => {
if (fetchSearch) {
fetchSearch({
[fetchParams]: searchValue
}).then(({data = []}) => {
const formatData = fetchFormat ? fetchFormat(data) : data.map(v => ({
label: v.name,
value: v.id
}))
setDataSource(formatData)
}).finally(() => {
setLoading(false)
})
}
// 触发自定义事件
form.notify('onSearchSelect', {
...props,
searchValue
})
}
const { run } = useDebounceFn(dispatchSearch, 1000)
return (
<Select
showSearch
onChange={e => console.log(e)}
onSearch={value => {
console.log(value)
setLoading(true)
run(value)
}
}
loading={loading}
options={dataSource}
{...resetProps}
>
</Select>
)
}
SearchSelect.defaultProps = {}
SearchSelect.isFieldComponent = true;
export default SearchSelect
\ No newline at end of file
......@@ -20,6 +20,7 @@ import Children from './components/Children';
import CircleBox from './components/CircleBox';
import Phone from './components/Phone';
import CustomRadio from './components/CustomRadio';
import SearchSelect from './components/SearchSelect';
import './index.less'
import { Checkbox } from '@formily/antd-components';
......@@ -113,6 +114,7 @@ const NiceForm: React.FC<NiceFormProps> = props => {
SchemaFormButtonGroup,
FlexBox,
Phone,
SearchSelect,
};
const defineComponents = Object.assign(customComponents, components);
......
import React, {
useState,
ReactText,
useImperativeHandle,
useEffect,
useRef,
} from 'react';
import { Tree, Space, Tooltip, Button } from 'antd';
import { findItemAndDelete, findTreeKeys } from '@/utils';
import './index.less';
import deepClone from 'clone';
import { TreeProps } from 'antd/lib/tree';
import {
PlusOutlined,
DeleteOutlined,
PlusCircleOutlined,
} from '@ant-design/icons';
import cx from 'classnames';
import { EventDataNode } from 'rc-tree/lib/interface';
import { useSelections } from '@umijs/hooks';
import React, { useState, ReactText, useImperativeHandle, useEffect, useRef } from 'react'
import { Tree, Space, Tooltip, Button } from 'antd'
import { findItemAndDelete, findTreeKeys, treeReduction, getParentTreeTitles } from '@/utils'
import './index.less'
import deepClone from 'clone'
import { TreeProps } from 'antd/lib/tree'
import { PlusOutlined, DeleteOutlined, PlusCircleOutlined } from '@ant-design/icons'
import cx from 'classnames'
import { EventDataNode } from 'rc-tree/lib/interface'
import { useSelections } from '@umijs/hooks'
export interface TabTreeActions {
selected: ReactText[];
......@@ -27,6 +17,8 @@ export interface TabTreeActions {
setExpandedKeys: (keys: ReactText[]) => void;
setSelectKey: (key: ReactText) => void;
setSelectKeys: (keys: ReactText[]) => void;
getParentPath: (id: ReactText) => string
getParent: (id) => any
}
export interface toolsRenderProps {
......@@ -77,11 +69,11 @@ export const createTreeActions = () => {
getSelectKeys() {
return [];
},
setSelectKey() {
console.log(222);
},
setSelectKey() {},
setSelectKeys() {},
setExpandedKeys() {},
getParentPath(id){return ''},
getParent(id){return null}
};
return actions;
};
......@@ -194,7 +186,7 @@ function transformSingleTitle(
// 使选中样式受控
data[item].className = cx(
'god-tabtree-select',
nowKey === data[item].key ? 'show' : 'hide',
Number(nowKey) === Number(data[item].key) ? 'show' : 'hide',
);
if (disabled) {
data[item].disableCheckbox = disabled;
......@@ -223,7 +215,7 @@ const TabTree: React.FC<TabTreeProps> = props => {
handleSubmit,
} = props;
// const selfActions = useTreeActions(actions)
const selfActions = useTreeActions(actions)
// 需展开的key
const [expandkeys, setExpandkeys] = useState<ReactText[]>([]);
......@@ -267,23 +259,38 @@ const TabTree: React.FC<TabTreeProps> = props => {
}
};
if (actions) {
actions.getExpandedKeys = () => expandkeys;
actions.getSelectKey = () => selectKey;
actions.getSelectKeys = () => selected;
actions.selected = selected;
actions.setSelectKeys = (keys: ReactText[]) => {
if (selfActions) {
selfActions.getExpandedKeys = () => expandkeys;
selfActions.getSelectKey = () => selectKey;
selfActions.getSelectKeys = () => selected;
selfActions.selected = selected;
selfActions.setSelectKeys = (keys: ReactText[]) => {
setSelected(keys);
};
actions.setExpandedKeys = (keys: ReactText[]) => {
selfActions.setExpandedKeys = (keys: ReactText[]) => {
setExpandkeys(keys);
};
actions.setSelectKey = (key: ReactText) => {
selfActions.setSelectKey = (key: ReactText) => {
setSelectKey(key);
};
selfActions.getParentPath = (id: ReactText) => {
return getParentTreeTitles(treeData, id)
}
selfActions.getParent = (id) => {
const reductData = treeReduction(treeData)
const targetInfo = reductData[id]
const parentInfo = reductData[targetInfo.parentId]
return parentInfo || null
}
}
const batchSelect = (items: any[]) => {
items.forEach(v => select(v));
const batchSelect = (items: any) => {
if (items.checked) {
// 更改为严格模式
items.checked.forEach(v => select(v))
} else {
items.forEach(v => select(v))
}
};
return (
......
export interface MemberType {
id: number;
typeName: string;
}
export interface BusinessType {
id: number;
typeName: string;
}
export interface UseType {
memberType: MemberType[];
businessType: BusinessType[];
}
export interface UserRegister {
useType: UseType;
}
export interface ShopInfo {
id: number;
name: string;
type: number;
environment: number;
logoUrl: string;
describe: string;
state: number;
url: string;
}
export interface Web {
shopInfo: ShopInfo[];
}
export interface PayConfig {
paymemberConfig?: any;
}
export interface CountryList {
name: string;
key: string;
icon: string;
}
export interface Global {
siteId: number;
siteUrl: string;
logo: string;
countryList: CountryList[];
}
export interface RootObject {
userRegister: UserRegister;
web: Web;
payConfig: PayConfig;
global: Global;
}
\ No newline at end of file
import { useMap } from '@umijs/hooks'
import { useState, useEffect } from 'react'
import React, { useState, useEffect } from 'react'
import { Modal } from 'antd'
import { TabTreeActions } from '@/components/TabTree'
import { ISchemaFormActions } from '@formily/antd'
import { isObject } from '@/utils'
export enum FormState {
FREE, // 空闲状态
......@@ -12,11 +15,20 @@ export interface useTreeTabOptions {
selectCallback?(selectKey?, node?),
fetchMenuData?(),
fetchItemDetailData?(id),
// 重置右侧详情
resetDetail?(),
// 对树形工具栏做render扩展
extendsToolsRender?: any,
// 树形的实例操作方法
treeActions?: TabTreeActions
// 右侧表单的实例操作方法
formActions?: ISchemaFormActions
// 删除菜单时调用的API
deleteMenu?: any
}
export const useTreeTabs = (options: useTreeTabOptions = {}) => {
const { selectCallback, fetchMenuData, fetchItemDetailData, resetDetail } = options
const { selectCallback, fetchMenuData, fetchItemDetailData, resetDetail, treeActions, formActions, extendsToolsRender, deleteMenu } = options
const [ treeExtraMaps, { set, get } ] = useMap<any, any>()
const [ treeData, setTreeData ] = useState<any[]>([])
const [ treeStatus, setTreeStatus ] = useState<FormState>(FormState.FREE)
......@@ -86,6 +98,45 @@ export const useTreeTabs = (options: useTreeTabOptions = {}) => {
set(id, data)
})
}
const handleDeleteMenu = (id) => {
deleteMenu({
id: isObject(id) ? nodeRecord.key : id
}).then(() => {
setTreeStatus(FormState.FREE)
setNodeRecord(undefined)
resetMenu()
})
}
// 新增整合树形操作菜单
// 树形工具栏
const toolsRender = {
addNode(node) {
const activeParentId = treeActions && treeActions.getParent(node.key || node.id)?.id
setNodeRecord({
...node,
parentId: activeParentId, // 添加同级的时候 使用上一级的id作为parentId
})
formActions && formActions.reset({ validate: false })
setTreeStatus(FormState.ADD)
},
addChildNode(node) {
setNodeRecord({
...node,
parentId: node.key || node.id
})
formActions && formActions.reset({ validate: false })
set(node.key || node.id, null)
setTreeStatus(FormState.ADD)
},
deleteNode(node) {
const id = node.key || node.id
handleDeleteMenu(id)
},
...extendsToolsRender
}
return {
handleSelect,
treeStatus,
......@@ -99,6 +150,8 @@ export const useTreeTabs = (options: useTreeTabOptions = {}) => {
treeExtraMaps,
setTreeMaps: set,
getTreeMaps: get,
resetMenu
resetMenu,
toolsRender,
handleDeleteMenu
}
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ import { classSchema } from './schema'
import { PublicApi } from '@/services/api';
import { useTreeTabs } from '@/hooks/useTreeTabs';
import NiceForm from '@/components/NiceForm';
import { action } from 'mobx';
import { isObject } from '@antv/util';
const { ON_FORM_INPUT_CHANGE } = LifeCycleTypes
......@@ -51,36 +51,15 @@ const ClassProperty: React.FC<{}> = () => {
getTreeMaps,
setTreeMaps,
resetMenu,
toolsRender,
handleDeleteMenu
} = useTreeTabs({
deleteMenu: PublicApi.postProductCustomerDeleteCustomerCategory,
fetchMenuData: fetchClassTreeData,
fetchItemDetailData: PublicApi.getProductCustomerGetCustomerCategory
})
const formInitValue = nodeRecord ? getTreeMaps(nodeRecord.key) : {}
// 树形工具栏
const toolsRender = {
addNode(node) {
formActions.reset({ validate: false })
setTreeStatus(FormState.ADD)
},
addChildNode(node) {
formActions.reset({ validate: false })
setNodeRecord({
...node,
parentId: node.id, // 添加子级的时候 使用上一级的id作为parentId
})
setTreeMaps(node.id, null)
setTreeStatus(FormState.ADD)
},
deleteNode(node) {
PublicApi.postProductCustomerDeleteCustomerCategory({
id: node.id
}).then(() => {
resetMenu()
})
}
}
const formInitValue = (nodeRecord && treeStatus === FormState.EDIT) ? getTreeMaps(nodeRecord.key) : {}
/* 关联平台后台品类树 */
const {
......@@ -107,17 +86,6 @@ const ClassProperty: React.FC<{}> = () => {
})
}
const handleDeleteMenu = () => {
if (nodeRecord) {
PublicApi.postProductCustomerDeleteCustomerCategory({
id: nodeRecord.id
}).then(() => {
setNodeRecord(undefined)
resetMenu()
})
}
}
const handleSelectOk = () => {
setPlateformVisible(false)
console.log(plateformSelectNode, 'plateformSelectNode')
......
......@@ -190,6 +190,9 @@ const Repositories: React.FC<{}> = () => {
'search',
FORM_FILTER_PATH,
);
// 填充下拉框
// useAsyncInitSelect(['category'])
// useAsyncInitSelect(['brand'])
}}
schema={repositSchema}
/>
......
......@@ -2,6 +2,7 @@ import React from 'react'
import { ISchema } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { GlobalConfig } from '@/global/config';
import { PublicApi } from '@/services/api';
export const repositSchema: ISchema = {
type: 'object',
......@@ -71,15 +72,24 @@ export const repositSchema: ISchema = {
},
category: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '请选择品类'
fetchSearch: PublicApi.getProductSelectGetSelectCategory,
placeholder: '请选择品类',
style: {
minWidth: 120
}
},
enum: []
},
brand: {
type: 'string',
"x-component": 'SearchSelect',
"x-component-props": {
placeholder: '请选择品牌'
placeholder: '请选择品牌',
style: {
minWidth: 120
}
},
enum: []
},
......
......@@ -9,7 +9,7 @@ function isArray(arr: any) {
return Array.isArray(arr)
}
function isObject(obj: any) {
export function isObject(obj: any) {
return Object.prototype.toString.call(obj) === '[object Object]'
}
......@@ -331,6 +331,44 @@ export const getFieldType = (field) => {
}
}
// 树形结构降为一维对象处理
export const treeReduction = (data: any[]) => {
const hashMaps = {}
const selfData: any[] = deepClone(data)
while (selfData.length > 0) {
const useItem = selfData.shift()
// 存在子集
if (useItem.children && useItem.children.length > 0) {
useItem.children = useItem.children.map(v => {
v.parentId = useItem.id
return v
})
selfData.push(...useItem.children)
}
hashMaps[useItem.id] = useItem
}
return hashMaps
}
// 获取某一节点的title路径
export const getParentTreeTitles = (dataSouce, key) => {
const hashMaps = treeReduction(dataSouce)
let targetKey = key
let targetPath = ''
while (targetKey !== '') {
if (!hashMaps[targetKey]) {
break
}
const title = hashMaps[targetKey].title
targetPath = targetPath === '' ? title : `${title}-${targetPath}`
targetKey = hashMaps[targetKey].parentId || ''
}
return targetPath
}
export const getQueryStringParams = (url?: string) => {
const nowUrl = url || window.location.href
const firstIndex = nowUrl.indexOf('?')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment