From db12e1ff52090074d54396fef90e11e1d59bba5b Mon Sep 17 00:00:00 2001 From: G Date: Mon, 11 Dec 2023 15:58:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20:sparkles:=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=A1=A8=E6=A0=BC=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/gbeata/src/GAction/index.tsx | 4 +- .../gbeata/src/GDialogForm/g-dialog-form.d.ts | 7 +- packages/gbeata/src/GField/index.d.ts | 4 +- packages/gbeata/src/GField/index.tsx | 4 +- packages/gbeata/src/GForm/GFormList.tsx | 6 +- packages/gbeata/src/GForm/g-form.d.ts | 6 +- packages/gbeata/src/GForm/index.tsx | 46 +- packages/gbeata/src/GList/context.ts | 2 +- packages/gbeata/src/GSearch/g-search.d.ts | 4 +- .../context.ts | 10 +- .../g-search-table.d.ts} | 30 +- packages/gbeata/src/GSearchTable/index.d.ts | 9 + packages/gbeata/src/GSearchTable/index.md | 1180 +++++++++++++++++ .../{MwSearchTable => GSearchTable}/index.tsx | 82 +- .../mw-search-table.less | 0 .../use/useExtraBtn.tsx | 14 +- .../src/GSearchTable/use/useSelection.tsx | 263 ++++ packages/gbeata/src/GTable/EditableTable.tsx | 4 +- packages/gbeata/src/GTable/core.tsx | 12 +- packages/gbeata/src/GTable/g-table.d.ts | 16 +- packages/gbeata/src/GTable/index.d.ts | 21 +- packages/gbeata/src/GTable/index.tsx | 16 +- .../src/MwSearchList/Selection/index.tsx | 45 +- .../src/MwSearchList/SelectionAll/index.tsx | 55 +- ...mw-search-list.d.ts => g-search-list.d.ts} | 20 +- packages/gbeata/src/MwSearchList/index.d.ts | 18 +- packages/gbeata/src/MwSearchList/index.tsx | 74 +- packages/gbeata/src/MwSearchTable/index.d.ts | 7 - .../src/MwSearchTable/use/useSelection.tsx | 237 ---- packages/gbeata/src/index.ts | 26 +- packages/gbeata/src/less/variable.less | 40 + 31 files changed, 1781 insertions(+), 481 deletions(-) rename packages/gbeata/src/{MwSearchTable => GSearchTable}/context.ts (76%) rename packages/gbeata/src/{MwSearchTable/mw-search-table.d.ts => GSearchTable/g-search-table.d.ts} (87%) create mode 100644 packages/gbeata/src/GSearchTable/index.d.ts create mode 100644 packages/gbeata/src/GSearchTable/index.md rename packages/gbeata/src/{MwSearchTable => GSearchTable}/index.tsx (87%) rename packages/gbeata/src/{MwSearchTable => GSearchTable}/mw-search-table.less (100%) rename packages/gbeata/src/{MwSearchTable => GSearchTable}/use/useExtraBtn.tsx (96%) create mode 100644 packages/gbeata/src/GSearchTable/use/useSelection.tsx rename packages/gbeata/src/MwSearchList/{mw-search-list.d.ts => g-search-list.d.ts} (87%) delete mode 100644 packages/gbeata/src/MwSearchTable/index.d.ts delete mode 100644 packages/gbeata/src/MwSearchTable/use/useSelection.tsx create mode 100755 packages/gbeata/src/less/variable.less diff --git a/packages/gbeata/src/GAction/index.tsx b/packages/gbeata/src/GAction/index.tsx index 156dd59e..6764b3bb 100644 --- a/packages/gbeata/src/GAction/index.tsx +++ b/packages/gbeata/src/GAction/index.tsx @@ -7,8 +7,8 @@ import { Modal } from 'antd'; import React, { useContext, useState } from 'react'; import GButton from '../GButton'; import { info, success } from '../GMessage'; +import { GSearchTableContext } from '../GSearchTable/context'; import { EditableContext } from '../GTable/context'; -import { MwSearchTableContext } from '../MwSearchTable/context'; import locale from '../locale'; import { AnyKeyProps } from '../types/AnyKeyProps'; import { getKey, getRowKey } from '../utils'; @@ -371,7 +371,7 @@ export const getActionProps = ( }; export default function MwAction(props: GActionProps) { - const searchTable: any = useContext(MwSearchTableContext); + const searchTable: any = useContext(GSearchTableContext); const form = useContext(EditableContext); const actionProps = getActionProps(props, searchTable, form); return ; diff --git a/packages/gbeata/src/GDialogForm/g-dialog-form.d.ts b/packages/gbeata/src/GDialogForm/g-dialog-form.d.ts index 9304a353..31de8479 100644 --- a/packages/gbeata/src/GDialogForm/g-dialog-form.d.ts +++ b/packages/gbeata/src/GDialogForm/g-dialog-form.d.ts @@ -1,10 +1,7 @@ import { ModalProps } from 'antd/lib/modal'; import { ReactNode } from 'react'; import { Field } from '../GForm/g-form'; -import { - ExtendField, - MwSearchTableField, -} from '../MwSearchTable/mw-search-table'; +import { ExtendField, GSearchTableField } from '../GSearchTable/g-search-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; declare type ModeType = 'add' | 'update' | 'view' | 'custom' | string; @@ -15,7 +12,7 @@ export interface GDialogFormProps extends ModalProps { /** 用抽屉来展示 */ drawer?: boolean; /** 表单项 */ - fields?: Array; + fields?: Array; /** form 的 span */ span?: number; /** 新增 api */ diff --git a/packages/gbeata/src/GField/index.d.ts b/packages/gbeata/src/GField/index.d.ts index 238eb644..6d786cd6 100644 --- a/packages/gbeata/src/GField/index.d.ts +++ b/packages/gbeata/src/GField/index.d.ts @@ -1,8 +1,8 @@ import { GFormField } from '../GForm/g-form'; -import { MwSearchTableField } from '../MwSearchTable/mw-search-table'; +import { GSearchTableField } from '../GSearchTable/g-search-table'; declare const GField: React.ForwardRefExoticComponent< - (MwSearchTableField | GFormField) & React.RefAttributes + (GSearchTableField | GFormField) & React.RefAttributes >; export default GField; diff --git a/packages/gbeata/src/GField/index.tsx b/packages/gbeata/src/GField/index.tsx index e9c66f43..17d93f3d 100644 --- a/packages/gbeata/src/GField/index.tsx +++ b/packages/gbeata/src/GField/index.tsx @@ -1,6 +1,6 @@ import { GFormField } from '../GForm/g-form'; -import { MwSearchTableField } from '../MwSearchTable/mw-search-table'; +import { GSearchTableField } from '../GSearchTable/g-search-table'; -export default function GField(_: GFormField | MwSearchTableField) { +export default function GField(_: GFormField | GSearchTableField) { return null; } diff --git a/packages/gbeata/src/GForm/GFormList.tsx b/packages/gbeata/src/GForm/GFormList.tsx index 81b5da18..a7940ad8 100644 --- a/packages/gbeata/src/GForm/GFormList.tsx +++ b/packages/gbeata/src/GForm/GFormList.tsx @@ -1,7 +1,7 @@ import { CopyOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Form, Space, Tooltip } from 'antd'; import React, { useEffect, useState } from 'react'; -import { MwSearchTableField } from '../MwSearchTable/mw-search-table'; +import { GSearchTableField } from '../GSearchTable/g-search-table'; import { FORM_TYPE_DATE, FORM_TYPE_DATE_RANGE, @@ -17,7 +17,7 @@ interface AyFormListProps { formInstant: AnyKeyProps; ayFormProps: GFormProps; getFormItem: ( - fields: Array, + fields: Array, formInstans: AnyKeyProps, props: GFormProps, childrenType?: 'group' | 'card' | 'input-group' | 'list', @@ -115,7 +115,7 @@ export default function GFormList(props: AyFormListProps) { } } return newField; - }) as Array, + }) as Array, formInstant, ayFormProps, FORM_TYPE_LIST, diff --git a/packages/gbeata/src/GForm/g-form.d.ts b/packages/gbeata/src/GForm/g-form.d.ts index 4a7883cd..19554fe7 100644 --- a/packages/gbeata/src/GForm/g-form.d.ts +++ b/packages/gbeata/src/GForm/g-form.d.ts @@ -1,5 +1,5 @@ import { CSSProperties, ReactNode } from 'react'; -import { MwSearchTableField } from '../MwSearchTable/mw-search-table'; +import { GSearchTableField } from '../GSearchTable/g-search-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; import { FormValues } from '../types/FormValues'; @@ -14,7 +14,7 @@ export interface ColSize { export interface GFormProps { /** 配置项 */ - fields?: Array; + fields?: Array; /** form 名称 */ name?: string; /** 子元素 */ @@ -220,5 +220,5 @@ export interface GFormField extends Field { */ export type FieldListener = ( value: any, - field: GFormField | MwSearchTableField, + field: GFormField | GSearchTableField, ) => void; diff --git a/packages/gbeata/src/GForm/index.tsx b/packages/gbeata/src/GForm/index.tsx index d8978f6b..73a2d199 100644 --- a/packages/gbeata/src/GForm/index.tsx +++ b/packages/gbeata/src/GForm/index.tsx @@ -14,9 +14,9 @@ import React, { useState, } from 'react'; import { convertChildrenToField } from '../GFields/convertFields'; -import { MwSearchField } from '../GSearch/g-search'; +import { GSearchField } from '../GSearch/g-search'; +import { GSearchTableField } from '../GSearchTable/g-search-table'; import MwCard from '../MwCard'; -import { MwSearchTableField } from '../MwSearchTable/mw-search-table'; import { theme } from '../Theme'; import { FORM_TYPE_CARD, @@ -73,8 +73,8 @@ install(registerField); * @param field 配置项 */ const getNoVisibleField = ( - field: GFormField | MwSearchTableField, -): GFormField | MwSearchTableField => { + field: GFormField | GSearchTableField, +): GFormField | GSearchTableField => { return { ...field, title: '', @@ -86,7 +86,7 @@ const getNoVisibleField = ( * 生成 placeholder * @param field 配置项 */ -const getPlaceholder = (field: GFormField | MwSearchTableField): string => { +const getPlaceholder = (field: GFormField | GSearchTableField): string => { const defaultProps = field.props; if (defaultProps && defaultProps.placeholder) { @@ -136,10 +136,10 @@ const getPlaceholder = (field: GFormField | MwSearchTableField): string => { * @param fields 配置列表 */ export const getDefaultValue = ( - fields: Array, + fields: Array, ) => { let form: AnyKeyProps = {}; - fields.forEach((field: GFormField | MwSearchField | MwSearchTableField) => { + fields.forEach((field: GFormField | GSearchField | GSearchTableField) => { if ( [FORM_TYPE_CARD, FORM_TYPE_GROUP, FORM_TYPE_INPUT_GROUP].includes( field.type || '', @@ -201,7 +201,7 @@ export const getDefaultValue = ( export const getFieldDefaultValue = ( key: string, - fields: Array, + fields: Array, ) => { if (!key) { return ''; @@ -274,8 +274,8 @@ const usedKeys = [ * @param field 配置项 */ const getTag = ( - field: GFormField | MwSearchTableField, - fields: Array, + field: GFormField | GSearchTableField, + fields: Array, formInstans: AnyKeyProps, readonly?: boolean, childrenType?: string, @@ -320,7 +320,7 @@ const getTag = ( * @param childrenType 子类型 */ const getFormItem = ( - fields: Array, + fields: Array, formInstans: AnyKeyProps, props: GFormProps, childrenType?: 'group' | 'card' | 'input-group' | 'list', @@ -328,7 +328,7 @@ const getFormItem = ( const { span, readonly, formLayout, gutter } = props; const ayFormProps: GFormProps = props; - return fields.map((field: GFormField | MwSearchTableField, index: number) => { + return fields.map((field: GFormField | GSearchTableField, index: number) => { // 把其它属性 添加到 props 里面 field = { ...field, @@ -346,7 +346,7 @@ const getFormItem = ( children = [children]; } let content = getFormItem( - children as Array, + children as Array, formInstans, ayFormProps, FORM_TYPE_CARD, @@ -476,7 +476,7 @@ const getFormItem = ( tag = ( {getFormItem( - field.children as Array, + field.children as Array, formInstans, ayFormProps, FORM_TYPE_GROUP, @@ -489,7 +489,7 @@ const getFormItem = ( tag = ( {getFormItem( - field.children as Array, + field.children as Array, formInstans, ayFormProps, FORM_TYPE_INPUT_GROUP, @@ -541,11 +541,11 @@ const getFormItem = ( const getField = ( key: string, - fields: Array, + fields: Array, ) => { - let field: GFormField | MwSearchTableField | null = null; + let field: GFormField | GSearchTableField | null = null; - const loop = (fields: Array) => { + const loop = (fields: Array) => { for (let i = 0; i < fields.length; i++) { let item = fields[i]; if (item.key === key) { @@ -569,7 +569,7 @@ const getField = ( */ const formatValues = ( values: AnyKeyProps, - fields: Array, + fields: Array, ): AnyKeyProps => { let result: AnyKeyProps = {}; for (let key in values) { @@ -635,7 +635,7 @@ const formatValues = ( */ const handleConfirm = ( values: AnyKeyProps, - fields: Array, + fields: Array, onConfirm?: (values: FormValues) => void, onFinish?: (values: FormValues) => void, onSubmit?: (values: FormValues) => void, @@ -662,7 +662,7 @@ const handleConfirm = ( const handleChange = ( changedValues: AnyKeyProps, allValues: AnyKeyProps, - fields: Array, + fields: Array, setFieldsValue: (params: AnyKeyProps) => void, ) => { for (let key in changedValues) { @@ -841,11 +841,11 @@ export default forwardRef(function GForm(props: GFormProps, ref: Ref) { * @returns object */ const getValues = ( - fields: GFormField | MwSearchTableField, + fields: GFormField | GSearchTableField, readonly?: boolean, ) => { let result: AnyKeyProps = {}; - fields?.forEach((field: GFormField | MwSearchTableField) => { + fields?.forEach((field: GFormField | GSearchTableField) => { if (!field.key) { return; } diff --git a/packages/gbeata/src/GList/context.ts b/packages/gbeata/src/GList/context.ts index 30a581b7..98435bf4 100644 --- a/packages/gbeata/src/GList/context.ts +++ b/packages/gbeata/src/GList/context.ts @@ -1,7 +1,7 @@ import { createContext } from 'react'; import { AnyKeyProps } from '../types/AnyKeyProps'; -export const MwListContext = createContext({ +export const GListContext = createContext({ // 当前列表的数据 data: [], // 已经禁用的 row 组成的 key diff --git a/packages/gbeata/src/GSearch/g-search.d.ts b/packages/gbeata/src/GSearch/g-search.d.ts index 4d7ec6c8..f9a5aee8 100644 --- a/packages/gbeata/src/GSearch/g-search.d.ts +++ b/packages/gbeata/src/GSearch/g-search.d.ts @@ -1,9 +1,9 @@ import { GFormField } from '../GForm/g-form'; -import { ExtendField } from '../MwSearchTable/mw-search-table'; +import { ExtendField } from '../GSearchTable/g-search-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; export interface GSearchProps { - fields: Array; + fields: Array; onConfirm?(values: AnyKeyProps): void; onReset?(): void; formExtend?: AnyKeyProps; diff --git a/packages/gbeata/src/MwSearchTable/context.ts b/packages/gbeata/src/GSearchTable/context.ts similarity index 76% rename from packages/gbeata/src/MwSearchTable/context.ts rename to packages/gbeata/src/GSearchTable/context.ts index ecf8e40f..c6aa863d 100644 --- a/packages/gbeata/src/MwSearchTable/context.ts +++ b/packages/gbeata/src/GSearchTable/context.ts @@ -1,7 +1,7 @@ -import { AnyKeyProps } from '../types/AnyKeyProps' -import { createContext } from 'react' +import { createContext } from 'react'; +import { AnyKeyProps } from '../types/AnyKeyProps'; -export const MwSearchTableContext = createContext({ +export const GSearchTableContext = createContext({ // 查询区域表单控制 formRef: { current: undefined }, // 表格控制 @@ -23,5 +23,5 @@ export const MwSearchTableContext = createContext({ // 当前查询表格控制 searchTableRef: { current: undefined }, // 所有编辑表格的数据 - setEditTableRow: (ary: any[]) => {} -}) + setEditTableRow: (ary: any[]) => {}, +}); diff --git a/packages/gbeata/src/MwSearchTable/mw-search-table.d.ts b/packages/gbeata/src/GSearchTable/g-search-table.d.ts similarity index 87% rename from packages/gbeata/src/MwSearchTable/mw-search-table.d.ts rename to packages/gbeata/src/GSearchTable/g-search-table.d.ts index a2315881..5d62f1ba 100644 --- a/packages/gbeata/src/MwSearchTable/mw-search-table.d.ts +++ b/packages/gbeata/src/GSearchTable/g-search-table.d.ts @@ -1,12 +1,12 @@ import { SizeType } from 'antd/lib/config-provider/SizeContext'; import { ReactNode } from 'react'; -import { Field, GFormField } from '../GForm/g-form'; -import { MwTableCtrlField, MwTableField } from '../GTable/mw-table'; import { + GDialogFormField, + GDialogFormProps, ModeType, - MwDialogFormField, - MwDialogFormProps, -} from '../MwDialogForm/g-dialog-form'; +} from '../GDialogForm/g-dialog-form'; +import { Field, GFormField } from '../GForm/g-form'; +import { GTableCtrlField, GTableField } from '../GTable/g-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; import { FormValues } from '../types/FormValues'; import { Record } from '../types/Record'; @@ -26,11 +26,11 @@ export interface SearchTableInitConfig extends AnyKeyProps { extraFullscreenVisible?: boolean; } -export interface MwSearchTableProps extends SearchTableInitConfig { +export interface GSearchTableProps extends SearchTableInitConfig { /** 标题 */ title?: string | ReactNode; /** 配置项 */ - fields?: Array; + fields?: Array; /** 子元素 */ children?: Array | ReactNode; /** 请求列表接口 */ @@ -40,7 +40,7 @@ export interface MwSearchTableProps extends SearchTableInitConfig { /** 表格数据(当不需要 api,由自己控制时使用) */ data?: Array; /** 表格操作列(写法跟正常的 filed 一致) */ - ctrl?: MwTableCtrlField; + ctrl?: GTableCtrlField; /** 为空时表示没有选框 */ selectionType?: 'checkbox' | 'radio'; /** 选项改变事件 */ @@ -50,9 +50,9 @@ export interface MwSearchTableProps extends SearchTableInitConfig { /** 选择时列表展示的 key */ selectShowKey?: string; /** dialog form 的配置 */ - dialogFormExtend?: MwDialogFormProps; + dialogFormExtend?: GDialogFormProps; /** 弹窗表单的配置项 */ - formField?: Array; + formField?: Array; /** 滚动的 X 轴数值 */ scrollX?: number; /** 表格高度 */ @@ -122,13 +122,13 @@ export interface ExtendField extends Omit { hiddenMode?: Array; } -export interface MwSearchTableField extends Field, MwTableField { - /** MwSearch 需要的扩展参数,里面的属性比外面的属性优先级更高 */ +export interface GSearchTableField extends Field, GTableField { + /** GSearch 需要的扩展参数,里面的属性比外面的属性优先级更高 */ search?: ExtendField | boolean; - /** MwDialogForm 需要的扩展参数,里面的属性比外面的属性优先级更高 */ + /** GDialogForm 需要的扩展参数,里面的属性比外面的属性优先级更高 */ dialog?: ExtendField | boolean; - /** MwTable 需要的扩展参数,里面的属性比外面的属性优先级更高 */ - table?: MwTableField | boolean; + /** GTable 需要的扩展参数,里面的属性比外面的属性优先级更高 */ + table?: GTableField | boolean; [key: string]: any; } diff --git a/packages/gbeata/src/GSearchTable/index.d.ts b/packages/gbeata/src/GSearchTable/index.d.ts new file mode 100644 index 00000000..0ea4266d --- /dev/null +++ b/packages/gbeata/src/GSearchTable/index.d.ts @@ -0,0 +1,9 @@ +import { GSearchTableField, GSearchTableProps } from './g-search-table'; + +export { GSearchTableField }; + +declare const GSearchTable: React.ForwardRefExoticComponent< + GSearchTableProps & React.RefAttributes +>; + +export default GSearchTable; diff --git a/packages/gbeata/src/GSearchTable/index.md b/packages/gbeata/src/GSearchTable/index.md new file mode 100644 index 00000000..dcaf5a8b --- /dev/null +++ b/packages/gbeata/src/GSearchTable/index.md @@ -0,0 +1,1180 @@ +--- +nav: 组件 +group: 表格table +--- + +# GSearchTable 查询表格 + + + +表格顶部使用了 `GSearch`,可以点击[这里](./form/mw-search)看详细介绍。 + +## 基础表格 + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { GSearchTable, GSearchTableField, Record } from 'gbeata'; + +const data: Array = [ + { + id: '1', + cn: 'Multiway', + index: 'R001', + des: '罗德岛公开领导人阿米娅,将与你并肩作战。', + }, + { + id: '2', + cn: '能天使', + index: 'PL03', + des: '企鹅物流职员能天使,将用铳枪为小队扫平前路。', + }, +]; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '编号', + key: 'index', + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ; +} +``` + +少写一个 `dataIndex`,其它的跟原本表格差不多。 + +## JSX / TSX 语法糖 + +```tsx +import React from 'react'; +import { GSearchTable, Record, GFields, GField } from 'gbeata'; + +const data: Array = [ + { + id: '1', + cn: 'Multiway', + index: 'R001', + des: '罗德岛公开领导人阿米娅,将与你并肩作战。', + }, + { + id: '2', + cn: '能天使', + index: 'PL03', + des: '企鹅物流职员能天使,将用铳枪为小队扫平前路。', + }, +]; + +export default function Demo() { + return ( + + + + + + + + ); +} +``` + +```diff +-const fields: Array = [ +- { +- title: '姓名', +- key: 'cn' +- }, +- { +- title: '编号', +- key: 'index' +- }, +- { +- title: '描述', +- key: 'des' +- } +-] + +export default function Demo() { + return ( + ++ ++ ++ ++ ++ + + ) +} +``` + +只是换了另一种风格写 `fields` 而已,请不要用其它元素包裹住 `GFields` 和 `GField`。 + +## 带接口的表格 + +```tsx +/** + * defaultShowCode: true + */ +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '编号', + key: 'index', + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +是不是一下子就干净了很多,不需要自己请求接口,也不需要处理翻页,Multiway 会自己处理。 + +对示例代码里的 listApi 有疑问或者想要自定义? 🤔️ 可以点[这里](../components/global/set-default-search-filter)查看请求提交处理,点[这里](../components/global/set-default-data-filter)查看请求返回处理。 + +如果你的接口不是返回以上的格式,可以创建一个 `gbeata.init.tsx` 文件,提前引入一次就好了,具体请看[这里](../components/%E5%85%A8%E5%B1%80%E6%96%B9%E6%B3%95/set-default-search-filter)。 + +## 查询表格 + +一般表格都会在顶部放一个查询区域,用来筛选表格,让我们把它做出来。 + +```tsx +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + search: true, + }, + { + title: '编号', + key: 'index', + }, + { + title: '职业', + key: 'class', + type: 'select', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + search: true, + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +```diff +// 输入框 +{ + title: '姓名', + key: 'cn', + // 表述顶部出现查询区域,默认为输入框 ++ search: true +} + +// 选择框 +{ + title: '职业', + key: 'class', + // 设定类型为查询框 ++ type: 'select', + // 表格会根据 options 展示 label,选择框会作为选项 ++ options: [ ++ { label: '近卫干员', value: '近卫' }, ++ { label: '狙击干员', value: '狙击' }, ++ { label: '术师重装', value: '术师' }, ++ { label: '医疗干员', value: '医疗' }, ++ { label: '重装干员', value: '重装' }, ++ { label: '辅助干员', value: '辅助' }, ++ { label: '特种干员', value: '特种' }, ++ { label: '先锋干员', value: '先锋' } ++ ], ++ search: true +}, +``` + +## 紧凑型表格 + +设置 `compact`,将会让表格取消边框与背景色,配合 `extraVisible={false}` 隐藏扩展按钮,会得到一个纯的表格。 + +```tsx +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '编号', + key: 'index', + }, + { + title: '职业', + key: 'class', + type: 'select', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +## 紧凑型查询区域 + +设置 `searchExtend={{ inline: true }}`,`searchExtend` 是 [GSearch](./form/mw-search)的[属性](./form/mw-search#props-参数),会让表格的查询区域变成平铺模式,此时查询区域的 label 将会消失,且作为 placeholder 出现。 + +```tsx +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '编号', + key: 'index', + search: true, + }, + { + title: '职业', + key: 'class', + type: 'select', + search: { + style: { + width: 200, + }, + }, + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +## 右侧查询表格 + +如果只有一个查询条件,可以考虑把查询条件放在右侧。 + +```tsx +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + search: { + type: 'search', + position: 'more', + }, + }, + { + title: '编号', + key: 'index', + }, + { + title: '职业', + key: 'class', + type: 'select', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +```diff +{ + title: '姓名', + key: 'cn', + // 这样会带个搜索按钮 + search: { ++ type: 'search', + // 把这个查询条件放到右侧 ++ position: 'more' + } +}, +``` + +## 筛选与排序 + +```tsx +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '编号', + key: 'index', + sort: true, + }, + { + title: '职业', + key: 'class', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + filter: true, + }, + { + title: '描述', + key: 'des', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +```diff +{ + title: '编号', + key: 'index', ++ sort: true +}, +{ + title: '职业', + key: 'class', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' } + ], ++ filter: true +}, +``` + +更详细的筛选于排序使用方法看[这里](./table/sort-filter) + +## 表头合并 + +在 `children` 下嵌套 Field 就可以做到表头合并。 + +```tsx +import React from 'react'; +import { GSearchTable, GSearchTableField } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'names', // 请给予这个地方 key,否则表头的自定义别名会出现意外结果 + children: [ + { + title: '中文名', + key: 'cn', + }, + { + title: '英文名', + key: 'en', + }, + { + title: '日文名', + key: 'jp', + }, + ], + }, + { + title: '初始HP', + key: 'ori-hp', + }, + { + title: '初始攻击', + key: 'ori-atk', + }, +]; + +export default function Demo() { + return ( + + ); +} +``` + +## 多选表格 + +`selectionType="checkbox"` 可以让表格开启多选。 + +不要忘记指定 `rowKey`,作为每一行数据的唯一 key,`selectShowKey` 可以指定悬浮在数字上展示的名称。 + +开启后选中的选项是会被记录的,不管翻页、查询、筛选、排序,是不会清空已选中的选项的,除非主动调用表格的 clearSelection 方法清空,或者用户主动点击清空按钮。 + +```tsx +/** + * title: 关于默认值 + * desc: rowKey 默认值是 id,selectShowKey 默认值是 name。 + */ +import React, { useRef } from 'react'; +import { GSearchTable, GSearchTableField, GButton, Record } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '英文名', + key: 'en', + }, +]; + +export default function Demo() { + const tableRef = useRef(); + + const handleView = () => { + let selection = tableRef.current.getSelection(); + if (selection.length) { + alert( + '你选中了:' + selection.map((record: Record) => record.cn).join('、'), + ); + } + }; + + return ( + + handleView()}> + 打印选项 + + + ); +} +``` + +```html + +``` + +## 单选表格 + +`selectionType="radio"` 可以让表格开启单选。 + +除了只能选中一个,其它特性跟[多选表格](#多选表格)一致。 + +```tsx +import React, { useRef } from 'react'; +import { GSearchTable, GSearchTableField, GButton } from 'gbeata'; +import { listApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + }, + { + title: '英文名', + key: 'en', + }, +]; + +export default function Demo() { + const tableRef = useRef(); + + const handleView = () => { + let selection = tableRef.current.getSelection(); + if (selection.length) { + alert('你选中了:' + selection[0].cn); + } + }; + + return ( + + handleView()}> + 打印选项 + + + ); +} +``` + +```html + +``` + +## 指令按钮 + +### 新增、详情、编辑 + +```tsx +import React from 'react'; +import { + GSearchTable, + GSearchTableField, + GTableCtrlField, + GAction, + Record, + GCtrl, +} from 'gbeata'; +import { listApi, addApi, updateApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + search: true, + dialog: { + required: true, + }, + }, + { + title: '编号', + key: 'index', + sort: true, + search: true, + dialog: { + required: true, + }, + }, + { + title: '职业', + key: 'class', + type: 'select', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + filter: true, + dialog: true, + }, + { + title: '描述', + key: 'des', + type: 'textarea', + dialog: true, + }, +]; + +const ctrl: GTableCtrlField = { + render: (_, record: Record) => ( + + + 详情 + + + 编辑 + + + ), +}; + +export default function Demo() { + return ( + + 新增 + + ); +} +``` + +```diff +const fields: Array = [ + { + title: '姓名', + key: 'cn', + search: true, ++ dialog: { ++ required: true ++ } + }, + { + title: '编号', + key: 'index', + sort: true + search: true, ++ dialog: { ++ required: true ++ } + }, + { + title: '职业', + key: 'class', + type: 'select', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' } + ], + filter: true ++ dialog: true + }, + { + title: '描述', + key: 'des', ++ type: 'textarea', ++ dialog: true + } +] + ++const ctrl: GTableCtrlField = { ++ render: (_, record: Record) => ( ++ ++ 详情 ++ 编辑 ++ ++ ) ++} + + ++ 新增 + +``` + +:::info +此例子 addApi、updateApi 都是模拟接口,实际场景推荐使用 axios +::: + +```js +/** + * 模拟新增 + * @param params 保存参数 + */ +export const addApi = (params: AnyKeyProps) => { + return new Promise((resolve) => { + data.unshift({ + id: Date.now(), + sort_id: Date.now(), + ...params, + }); + resolve({ + msg: '请求成功', + data: Date.now(), + }); + }); +}; + +/** + * 模拟修改 + * @param params 保存参数 + */ +export const updateApi = (params: AnyKeyProps) => { + return new Promise((resolve) => { + let index: number = data.findIndex((row) => row.id === params.id); + if (index >= 0 && data[index]) { + data[index] = { + ...data[index], + ...params, + }; + } + resolve({ + msg: '请求成功', + data: data[index], + }); + }); +}; +``` + +大概只增加了 20 行代码就能实现了 新增、详情、编辑,好用吧~ + +### 删除、批量删除 + +```tsx +import React from 'react'; +import { + GSearchTable, + GSearchTableField, + GTableCtrlField, + GAction, + Record, + GCtrl, +} from 'gbeata'; +import { listApi, addApi, updateApi, deleteApi } from '../api'; + +const fields: Array = [ + { + title: '姓名', + key: 'cn', + search: true, + dialog: { + required: true, + }, + }, + { + title: '编号', + key: 'index', + sort: true, + search: true, + dialog: { + required: true, + }, + }, + { + title: '职业', + key: 'class', + type: 'select', + options: [ + { label: '近卫干员', value: '近卫' }, + { label: '狙击干员', value: '狙击' }, + { label: '术师重装', value: '术师' }, + { label: '医疗干员', value: '医疗' }, + { label: '重装干员', value: '重装' }, + { label: '辅助干员', value: '辅助' }, + { label: '特种干员', value: '特种' }, + { label: '先锋干员', value: '先锋' }, + ], + filter: true, + dialog: true, + }, + { + title: '描述', + key: 'des', + type: 'textarea', + dialog: true, + }, +]; + +const ctrl: GTableCtrlField = { + render: (_, record: Record) => ( + + + 详情 + + + 编辑 + + + 删除 + + + ), +}; + +export default function Demo() { + return ( + + 新增 + 批量删除 + + ); +} +``` + +```diff + +const ctrl: GTableCtrlField = { + render: (_, record: Record) => ( + + 详情 + 编辑 ++ 删除 + + ) +} + + + 新增 ++ 批量删除 + +``` + +同样也很简单,只需要 5 行代码,实现删除 & 批量删除。 + +:::warning +此例子 deleteApi 都是模拟接口,deleteApi 是支持批量删除的,实际场景推荐使用 axios +::: + +```js +/** + * 模拟删除 + * @param params 删除的 id + */ +export const deleteApi = (params: AnyKeyProps) => { + return new Promise((resolve) => { + data = data.filter((row) => { + return !params.includes(row.sort_id); + }); + resolve({ + msg: '删除成功', + data: null, + }); + }); +}; +``` + +更详细的指令按钮介绍,请看[这里](../button/mw-action) + +## 增删改查 + + + +对示例代码里的 listApi 有疑问或者想要自定义? 🤔️ 可以点[这里](./global/set-default-search-filter)查看请求提交处理,点[这里](./global/set-default-data-filter)查看请求返回处理。 + +## 参数 + +| 参数名 | 说明 | 参数类型 | 默认值 | 版本 | +| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------ | ------ | +| title | 表格标题,显示在表格左上角的标题文字。 | string \| ReactNode | '' | - | +| fields | 配置项,可决定表格、查询项、弹窗表单的配置。 | Array<[GSearchTableField][mwsearchtablefield]> | [] | - | +| selectionType | 是否开启勾选,checkbox:多选、radio:单选,单选表格的使用可以请看[这里][单选表格],开启后需要指定 rowKey。 | 'checkbox' \| 'radio' | - | - | +| children | 子元素会被放在表格右上角。 | ReactNode | - | - | +| api | 列表分页接口,会传递分页和参数参数,发现跟接口风格不一致,点[这里][自定义请求]查看自定义方式。 | Promise | - | - | +| deleteApi | 批量删除接口。 | Promise | - | - | +| data | 表格静态数据,不希望表格做请求,自己定义数据。 | Array | - | - | +| ctrl | 列表每一行后面数据跟着的按钮渲染。 | GSearchTableField | - | - | +| rowKey | 列表每一行的唯一标志。 | string \| (record: Record) => string | 'id' | - | +| selectShowKey | 批量删除,勾选时,在表格顶部会有数字,点击数字可以看到选项的名称。 | string | 'name' | - | +| dialogFormExtend | [GDialogForm][aydialogform] 的扩展配置。 | GDialogFormProps | {} | - | +| scrollX | 滚动的 X 轴数值。 | number | - | - | +| height | 表格滚动高度。 | number | - | - | +| filterData | 列表数据过滤。 | (data: Object) => Array | - | - | +| beforeSearch | 提交前过滤,希望请求前改变参数可使用此方法。 | (data: Object) => Object | - | - | +| pagination | 分页参数。 | antd 分页一致 | - | - | +| center | 把元素插入到查询和表格之间。 | ReactNode | - | - | +| listHeader | GSearchList 在列表头部插入元素。 | ReactNode | - | - | +| tableHeader | GSearchTable 在列表头部插入元素。 | ReactNode | - | - | +| searchVisible | 查询区域是否展示。 | boolean | true | - | +| tableExtend | table 的扩展配置。 | Object | {} | - | +| extendSearchParams | 请求时额外携带的参数。 | Object | {} | - | +| after | 在表格底部插入元素。 | ReactNode | - | - | +| before | 在顶部插入元素。 | boolean | true | 0.55.0 | +| autoload | 表格渲染时是否自动发起请求。 | booelan | true | - | +| rowSelection | 表格选项设置,可以用来设置表格是否[禁用][禁用表格选项],请不要设置 type、selectedRowKeys、onSelect、onSelectAll 方法,这会影响到原本的设置。 | - | - | - | +| compact | 紧凑型表格样式,会取消表格包裹的边框与样式。 | boolean | false | 0.52.0 | +| useOriginPagination | 是否使用 Table 自带的 pagination,设置 false 后,在跨行(rowSpan)时会不受 Table 自动分页的影响。 | boolean | true | 0.55.0 | +| onExpand | 展开事件。 | (expanded: boolean, record: Record) => void | - | - | +| onLoad | 表格查询完成监听。 | (records: Array, data: any) => void | - | - | +| onParamsChange | 查询参数变化事件,包括分页。 | (searchPamras: Object) => void | - | - | +| onSelectionChange | 选项改变事件。 | (selection: Array): void | - | - | + +extra 右侧扩展按钮配置参考[这里][1]。 + +## GSearchTableField + +最为常见的 Field,是每个列表页面都会用到的参数。 + +| 参数名 | 说明 | 参数类型 | 默认值 | 版本 | +| -------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------- | ------ | ------ | +| title | 标题。 | string | - | - | +| key | 唯一 key,dataIndex 默认会跟这个值一样。 | string | - | - | +| options | 可选项,展示会根据这个值变化。 | Array<[Option][option]> | - | - | +| hidden | 是否隐藏这一列。 | boolean \| () => boolean | - | 0.45.0 | +| render | 自定义展示列。 | (text: ReactNode, record: AnyKeyProps, index: number) => ReactNode | - | 0.45.0 | +| renderType | 美化展示列,扩展方法看[这里][rendertype]。 | string | - | 0.45.0 | +| filter | 设置 true 会以 options 作为筛选项出现在表头。 | boolean | - | 0.45.0 | +| filterMultiple | 筛选是否支持多选,需要先设置 `filter: true`。 | boolean | false | 0.45.0 | +| sort | 排序。 | boolean | - | 0.45.0 | +| sortOrder | 排序权重,越大越重,不设置则表示不需要多列筛选,需要先设置 `sort: true`。 | number | - | 0.45.0 | +| editable | 表格是否可以编辑,具体示例看[这里][可编辑表格]。 | boolean | - | 0.45.0 | +| before | (仅 `editable` 可用), 渲染前置元素,[使用案例][可编辑表格] | ({ record: Record, field: Field, refreshRow: Function }) => ReactNode | - | 0.45.0 | +| after | (仅 `editable` 可用), 渲染后置元素,[使用案例][可编辑表格] | ({ record: Record, field: Field, refreshRow: Function }) => ReactNode | - | 0.45.0 | +| children | 嵌套表格时使用。 | Array<[GTableField][aytablefield]> | - | 0.45.0 | +| search | GSearch 需要的扩展参数,里面的属性比外面的属性优先级更高,为 true 则在查询区域展示输入框。 | [GFormField][mwformfield] \| boolean | - | - | +| dialog | GDialogForm 需要的扩展参数,里面的属性比外面的属性优先级更高,为 true 则在弹窗展示输入框。 | [GFormField][mwformfield] \| boolean | - | - | +| table | GTable 需要的扩展参数,里面的属性比外面的属性优先级更高,为 false 则不在表格展示。 | [GTableField][aytablefield] \| boolean | - | - | + +```typescript +// 示例 +const fields: Array = [ + { + title: '', // 表格、查询、编辑 的标题 + key: '', // 表格、查询、编辑 的 key + type: '', // 查询、编辑 的 FormType + options: [], // 表格、查询、编辑 的 选项 + // 表示查询区域内出现该元素,默认是输入框 + search: true, + // 表示弹窗内出现该元素,默认是输入框 + dialog: true, + }, +]; +``` + +## GTableField + +| 参数名 | 说明 | 参数类型 | 默认值 | +| -------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------- | -------- | --- | +| title | 标题。 | string | - | +| key | 唯一 key,dataIndex 默认会跟这个值一样。 | string | - | +| options | 可选项,展示会根据这个值变化。 | Array<[Option][option]> | - | +| hidden | 是否隐藏这一列。 | boolean \| () => boolean | - | +| render | 自定义展示列。 | (text: ReactNode, record: AnyKeyProps, index: number) => ReactNode | - | +| renderType | 美化展示列,扩展方法看[这里][rendertype]。 | string | 'string' | - | +| filter | 设置 true 会以 options 作为筛选项出现在表头。 | boolean | - | +| filterMultiple | 筛选是否支持多选,需要先设置 `filter: true`。 | boolean | false | +| sort | 排序。 | boolean | - | +| sortOrder | 排序权重,越大越重,不设置则表示不需要多列筛选,需要先设置 `sort: true`。 | number | - | +| editable | 表格是否可以编辑,具体示例看[这里][可编辑表格]。 | boolean | - | +| before | (仅 `editable` 可用), 渲染前置元素,[使用案例][可编辑表格] | ({ record: Record, field: Field, refreshRow: Function }) => ReactNode | - | +| after | (仅 `editable` 可用), 渲染后置元素,[使用案例][可编辑表格] | ({ record: Record, field: Field, refreshRow: Function }) => ReactNode | - | +| children | 嵌套表格时使用。 | Array<[GTableField][aytablefield]> | - | + +## Option 参数 + +| 参数名 | 说明 | 参数类型 | 默认值 | +| -------- | -------- | ----------------------- | ------ | +| label | 显示选项 | string \| number | - | +| value | 值 | any | - | +| disabled | 是否禁用 | boolean | - | +| children | 子元素 | Array<[Option][option]> | - | + +## Method 方法 + +| 方法名 | 说明 | 返回值 | +| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------- | +| refresh() | 重新发起请求。 | - | +| reset() | 回到第一页,重新发起请求。 | - | +| doLayout() | 重新布局表格。 | - | +| clearFilters(keys: Array) | 可以不传参数,不传则清空全部;传了则清空相同 key 的过滤值,即设置 filter 之后的值。 | - | +| clearSorts(keys: Array) | 可以不传参数,不传则清空全部;传了则清空相同 key 的排序值,即设置 sort 之后的值。 | - | +| getSelection() | 获取所有勾选的行。 | Array | +| setSelection(selection: Array) | 设置选中行。 | - | +| addSelection(selection: Array) | 添加选中行。 | - | +| clearSelection() | 清空所有选中行。 | - | +| getTableData() | 获取表格当前数据。 | Array | +| setTableData(data: Array) | 设置表格当前数据。 | - | +| getApiParams() | 获取表格请求前数据,不会发起请求,会经过 defaultSearchFilter、beforeSearch 方法过滤,即接口将要请求时的数据。 | { pagination, filters, sorts, search } | +| setSortsValue(
Array<{ key: string, order: 'ascend' \| 'descend' }>
) | 设置排序值,设置后会影响,并覆盖现有的排序值,可用 `getApiParams()` 中的 `sorts` 来获得现有排序值。 | - | +| setFiltersValue({ key: value }) | 设置筛选值。 | - | + +[1]: ./global/set-search-table-default-value +[option]: ./table#option-参数 +[formtype]: ./form#formtype +[mwsearchtablefield]: ./table#GSearchTableField +[rendertype]: ./table/custom-render#已全局注册 +[mwformfield]: ./form#GFormField-参数 +[aytablefield]: ./table#aytablefield +[aydialogform]: ./form/mw-dialog-form +[禁用表格选项]: ./table/disabled-row +[单选表格]: ./table/radio-table +[可编辑表格]: ./table/edit-table +[自定义请求]: ./global/set-default-search-filter diff --git a/packages/gbeata/src/MwSearchTable/index.tsx b/packages/gbeata/src/GSearchTable/index.tsx similarity index 87% rename from packages/gbeata/src/MwSearchTable/index.tsx rename to packages/gbeata/src/GSearchTable/index.tsx index 9ba243a3..7aa85613 100644 --- a/packages/gbeata/src/MwSearchTable/index.tsx +++ b/packages/gbeata/src/GSearchTable/index.tsx @@ -11,27 +11,27 @@ import React, { useRef, useState, } from 'react'; +import { getActionProps } from '../GAction'; +import GButton from '../GButton'; +import GDialogForm from '../GDialogForm'; +import { GDialogFormRef } from '../GDialogForm/g-dialog-form'; import { convertChildrenToField } from '../GFields/convertFields'; import GForm, { getDefaultValue } from '../GForm'; -import MwTable from '../GTable'; -import { LoadParams, MwTableField } from '../GTable/mw-table'; -import { getActionProps } from '../MwAction'; -import MwButton from '../MwButton'; -import MwDialogForm from '../MwDialogForm'; -import { MwDialogFormRef } from '../MwDialogForm/g-dialog-form'; -import MwSearch from '../MwSearch'; -import { MwSearchField } from '../MwSearch/mw-search'; +import GSearch from '../GSearch'; +import { GSearchField } from '../GSearch/g-search'; +import GTable from '../GTable'; +import { GTableField, LoadParams } from '../GTable/g-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; import { Record } from '../types/Record'; import { isObj, omitObj, optionObj } from '../utils'; -import { MwSearchTableContext } from './context'; +import { GSearchTableContext } from './context'; import { - MwSearchTableField, - MwSearchTableProps, + GSearchTableField, + GSearchTableProps, SearchTableInitConfig, SortItem, TableRefProps, -} from './mw-search-table'; +} from './g-search-table'; import './mw-search-table.less'; import useExtraBtn, { setSearchTableExtraDefaultValue, @@ -42,14 +42,14 @@ import useSelection from './use/useSelection'; * 转化并过滤成 mw-search 能用的 fields * @param fields 查询表格的 fields */ -const getSearchFields = (fields: Array) => { - let searchFields: Array = []; - let moreSearchFields: Array = []; +const getSearchFields = (fields: Array) => { + let searchFields: Array = []; + let moreSearchFields: Array = []; fields - .filter((field: MwSearchTableField) => { + .filter((field: GSearchTableField) => { return isObj(field.search) || field.search === true; }) - .forEach((field: MwSearchTableField) => { + .forEach((field: GSearchTableField) => { let search = typeof field.search === 'boolean' ? {} : field.search; if (!search) { return { @@ -58,7 +58,7 @@ const getSearchFields = (fields: Array) => { type: 'input', }; } - let searchField: MwSearchField = { + let searchField: GSearchField = { title: field.title, key: search.key || field.key || '', type: field.type || 'input', @@ -93,9 +93,9 @@ const getSearchFields = (fields: Array) => { * @param fields 配置项 */ const getTableFields = ( - fields: Array, -): Array => { - return fields.map((field: MwSearchTableField) => { + fields: Array, +): Array => { + return fields.map((field: GSearchTableField) => { let table = typeof field.table === 'boolean' ? {} : field.table; // false 表示表格隐藏 @@ -105,7 +105,7 @@ const getTableFields = ( }; } - let tableField: MwTableField = { + let tableField: GTableField = { ...omitObj(field, 'table'), title: field.title, key: field.key, @@ -121,7 +121,7 @@ const getTableFields = ( * @param fields 当前的表格配置项 * @returns AnyKeyProps */ -const getFiltersDefaultValue = (fields: Array) => { +const getFiltersDefaultValue = (fields: Array) => { let filtersValue: AnyKeyProps = {}; fields.forEach((field) => { if ( @@ -140,7 +140,7 @@ const getFiltersDefaultValue = (fields: Array) => { * @param fields 当前的表格配置项 * @returns Array<{ key: string, order: 'ascend' | 'descend' }> */ -const getSortsDefaultValue = (fields: Array) => { +const getSortsDefaultValue = (fields: Array) => { let sorts: Array = []; // 排序是否带了先后顺序 let hasSortOrder = false; @@ -176,7 +176,7 @@ const getSortsDefaultValue = (fields: Array) => { /** * 判断该节点是否只出现在底部 - * @param node MwAction 按钮 + * @param node GAction 按钮 */ const isFooterActionOnly = (node: any) => { if (!node || !node.props) { @@ -187,8 +187,8 @@ const isFooterActionOnly = (node: any) => { }; /** - * 获取表格底部以及右侧 MwAction 按钮 - * @param node MwAction 按钮 + * 获取表格底部以及右侧 GAction 按钮 + * @param node GAction 按钮 */ const getTableActionBtns = ( children: ReactNode, @@ -224,8 +224,8 @@ export const setSearchTableDefaultValue = (config: SearchTableInitConfig) => { setSearchTableExtraDefaultValue(config); }; -export default forwardRef(function MwSearchTable( - props: MwSearchTableProps, +export default forwardRef(function GSearchTable( + props: GSearchTableProps, ref: Ref, ) { const { @@ -273,8 +273,8 @@ export default forwardRef(function MwSearchTable( }, [originFields, children]); /** form 控制 */ - const formRef: MutableRefObject = - useRef() as MutableRefObject; + const formRef: MutableRefObject = + useRef() as MutableRefObject; /** table 控制 */ const tableRef: MutableRefObject = useRef() as MutableRefObject; @@ -287,7 +287,7 @@ export default forwardRef(function MwSearchTable( /** 查询项 */ const { searchFields, moreSearchFields } = getSearchFields(fields); /** 列表项 */ - const [tableFields, setTableFields] = useState>( + const [tableFields, setTableFields] = useState>( getTableFields(fields), ); /** 使用勾选 */ @@ -517,10 +517,10 @@ export default forwardRef(function MwSearchTable( fields={moreSearchFields} onConfirm={onConfirm} > - + >
, ); } @@ -547,7 +547,7 @@ export default forwardRef(function MwSearchTable( compact && 'compact', )} > - {before} {searchVisible !== false && searchFields.length > 0 ? ( - + {children} - + ) : null} - + {tableChildren} - + {selection.length && footerActions.length ? (
{message} @@ -590,7 +590,7 @@ export default forwardRef(function MwSearchTable(
) : null} {after} -
+ ); }); diff --git a/packages/gbeata/src/MwSearchTable/mw-search-table.less b/packages/gbeata/src/GSearchTable/mw-search-table.less similarity index 100% rename from packages/gbeata/src/MwSearchTable/mw-search-table.less rename to packages/gbeata/src/GSearchTable/mw-search-table.less diff --git a/packages/gbeata/src/MwSearchTable/use/useExtraBtn.tsx b/packages/gbeata/src/GSearchTable/use/useExtraBtn.tsx similarity index 96% rename from packages/gbeata/src/MwSearchTable/use/useExtraBtn.tsx rename to packages/gbeata/src/GSearchTable/use/useExtraBtn.tsx index 4c6f8bac..10d95dbd 100644 --- a/packages/gbeata/src/MwSearchTable/use/useExtraBtn.tsx +++ b/packages/gbeata/src/GSearchTable/use/useExtraBtn.tsx @@ -12,9 +12,9 @@ import { SizeType } from 'antd/lib/config-provider/SizeContext'; import React, { ChangeEvent, Dispatch, useEffect, useState } from 'react'; import GButton from '../../GButton'; import MwDialog from '../../GDialog'; -import { MwTableField } from '../../GTable/g-table'; +import { GTableField } from '../../GTable/g-table'; import locale from '../../locale'; -import { MwSearchTableProps, SearchTableInitConfig } from '../mw-search-table'; +import { GSearchTableProps, SearchTableInitConfig } from '../g-search-table'; /** 表格扩展按钮-是否显示 */ let defaultConfig: SearchTableInitConfig = { @@ -53,8 +53,8 @@ export const setSearchTableExtraDefaultValue = ( }; const useFieldsEdit = ( - tableFields: Array, - setTableFields: Dispatch>, + tableFields: Array, + setTableFields: Dispatch>, defaultExtra: string[], ) => { const [visible, setVisible] = useState(false); @@ -240,9 +240,9 @@ const useFieldsEdit = ( export default function useExtraBtn( tableRef: any, searchRef: any, - tableFields: Array, - setTableFields: Dispatch>, - props: MwSearchTableProps, + tableFields: Array, + setTableFields: Dispatch>, + props: GSearchTableProps, ) { // 合并配置 const config = Object.assign({}, defaultConfig, props); diff --git a/packages/gbeata/src/GSearchTable/use/useSelection.tsx b/packages/gbeata/src/GSearchTable/use/useSelection.tsx new file mode 100644 index 00000000..60dbc7b6 --- /dev/null +++ b/packages/gbeata/src/GSearchTable/use/useSelection.tsx @@ -0,0 +1,263 @@ +import { Alert, Popover, Tag } from 'antd'; +import React, { ReactNode, ReactText, useEffect, useState } from 'react'; +import GAction from '../../GAction'; +import locale from '../../locale'; +import { AnyKeyProps } from '../../types/AnyKeyProps'; +import { getKey } from '../../utils'; + +type Row = AnyKeyProps; + +interface UseSelectionProps { + /** 表格 rowKey */ + rowKey?: ((record: AnyKeyProps) => string) | string; + /** ☑️表格选择框类型 */ + selectionType?: 'checkbox' | 'radio'; + /** 📢表格选择改变触发事件 */ + onSelectionChange?( + selection: Array, + selectionKeys: Array, + ): void; + /** 选中显示的名称 */ + selectShowKey?: string; + /** 选择功能的配置 */ + rowSelection?: AnyKeyProps; +} + +interface UseSelectionReturns { + /** 头部元素 */ + header: ReactNode; + /** 只有消息部分 */ + message: ReactNode; + /** 生成的 antd rowSelection */ + tableRowSelection: AnyKeyProps | undefined; + /** ☑️已选中的选项 */ + selection: Array; + /** 清空所有选项 */ + clearSelection(): void; + /** 设置选中的项 */ + setSelection(selection: Array): void; + /** 添加选中的项 */ + addSelection(selection: Array): void; + /** 移除选项 */ + removeSelection?(i: number | null, record?: AnyKeyProps): void; +} + +export default function useSelection( + _props: UseSelectionProps, +): UseSelectionReturns { + const { + rowKey, + selectionType, + onSelectionChange, + selectShowKey, + rowSelection, + } = _props; + const [selectionKeys, setSelectionKeys] = useState>([]); + const [selection, setSelection] = useState>([]); + + let tableRowSelection: AnyKeyProps | undefined; + + if (selectionType) { + tableRowSelection = { + ...rowSelection, + type: selectionType, + selectedRowKeys: selectionKeys, + onSelect: (record: Row, selected: boolean) => { + if (selectionType === 'radio') { + changeRadioSelection(record); + } else { + selected ? addSelection(record) : removeSelection(null, record); + } + }, + onSelectAll: ( + selected: boolean, + selectedRows: Array, + changeRows: Array, + ) => { + selected + ? addSelectionArray(selectedRows) + : removeSelectionArray(changeRows); + }, + }; + } + + /** + * 清空所有选项 + */ + const clearSelection = () => { + setSelectionKeys([]); + setSelection([]); + }; + + /** + * 设置选中的行 + */ + const setDefaultSelection = (selection: AnyKeyProps[]) => { + setSelection(selection); + setSelectionKeys(selection.map((row) => getKey(row, rowKey))); + }; + + /** + * 添加选项 + */ + const addDefaultSelection = (addSelection: AnyKeyProps[]) => { + // @ts-ignore + let newSelection = [...selection]; + addSelection.forEach((row) => { + if (!selectionKeys.includes(getKey(row, rowKey))) { + newSelection.push(row); + } + }); + + setSelection(newSelection); + setSelectionKeys(newSelection.map((row) => getKey(row, rowKey))); + }; + + const changeRadioSelection = (row: AnyKeyProps) => { + let newKeys = []; + let newSelection = []; + + newKeys.push(getKey(row, rowKey)); + newSelection.push(row); + + setSelectionKeys(newKeys); + setSelection(newSelection); + }; + + /** + * 添加选项(单个) + * @param row 某一条选项 + */ + const addSelection = (row: AnyKeyProps) => { + // @ts-ignore + let newKeys = [...selectionKeys]; + let newSelection = [...selection]; + + newKeys.push(getKey(row, rowKey)); + newSelection.push(row); + + setSelectionKeys(newKeys); + setSelection(newSelection); + }; + + /** + * 添加选项(数组) + * @param rows 项目列表 + */ + const addSelectionArray = (rows: Array) => { + let newKeys = [...selectionKeys]; + let newSelection = [...selection]; + + rows.forEach((row) => { + if (!row) { + return; + } + let key = getKey(row, rowKey); + if (!newKeys.includes(key)) { + newKeys.push(key); + newSelection.push(row); + } + }); + + setSelectionKeys(newKeys); + setSelection(newSelection); + }; + + /** + * 移除某个选项 + * @param i 移除选项的 index + */ + const removeSelection = (i: number | null, record?: AnyKeyProps) => { + let newKeys = [...selectionKeys]; + let newSelection = [...selection]; + + if (i === null && record) { + i = newKeys.findIndex((key) => key === getKey(record, rowKey)); + } + + if (typeof i === 'number') { + newKeys.splice(i, 1); + newSelection.splice(i, 1); + } + + setSelectionKeys(newKeys); + setSelection(newSelection); + }; + + /** + * 移除一组选项 + * @param rows 移除选项 + */ + const removeSelectionArray = (rows: Array) => { + let newKeys = [...selectionKeys]; + let newSelection = [...selection]; + + rows.forEach((row) => { + let index = newKeys.findIndex((item) => item === getKey(row, rowKey)); + if (index >= 0) { + newKeys.splice(index, 1); + newSelection.splice(index, 1); + } + }); + + setSelectionKeys(newKeys); + setSelection(newSelection); + }; + + /** Popover 弹窗的提示 */ + const popContent = ( +
+ {selection.map((row, i) => { + return ( + removeSelection(i)} + > + {row[selectShowKey || 'name']} + + ); + })} +
+ ); + + const message = ( +
+ + {locale.table.selectedBefore} + + {selection.length} + +  {locale.table.selectedAfter} + + + {locale.table.selectedClear} + +
+ ); + + /** 头部已选中的提示 */ + const header = selectionKeys.length ? ( + + ) : ( + '' + ); + + useEffect(() => { + if (onSelectionChange) { + onSelectionChange(selection, selectionKeys); + } + }, [onSelectionChange, selection]); + + return { + header, + message, + tableRowSelection, + selection, + clearSelection, + removeSelection, + setSelection: setDefaultSelection, + addSelection: addDefaultSelection, + }; +} diff --git a/packages/gbeata/src/GTable/EditableTable.tsx b/packages/gbeata/src/GTable/EditableTable.tsx index 3b4fcbbc..680fd152 100644 --- a/packages/gbeata/src/GTable/EditableTable.tsx +++ b/packages/gbeata/src/GTable/EditableTable.tsx @@ -9,7 +9,7 @@ import { } from 'antd'; import classnames from 'classnames'; import React, { ReactNode, useContext, useEffect, useState } from 'react'; -import { MwSearchTableContext } from '../MwSearchTable/context'; +import { GSearchTableContext } from '../GSearchTable/context'; import { AnyKeyProps } from '../types/AnyKeyProps'; import { getKey } from '../utils'; import { EditableContext } from './context'; @@ -18,7 +18,7 @@ const { Text } = Typography; export function EditableRow({ index, ...props }: AnyKeyProps) { const [form] = Form.useForm(); - const searchTable: any = useContext(MwSearchTableContext); + const searchTable: any = useContext(GSearchTableContext); useEffect(() => { searchTable.setEditTableRow([{ index, form }]); }, []); diff --git a/packages/gbeata/src/GTable/core.tsx b/packages/gbeata/src/GTable/core.tsx index a17b997f..2eec9d92 100644 --- a/packages/gbeata/src/GTable/core.tsx +++ b/packages/gbeata/src/GTable/core.tsx @@ -3,8 +3,8 @@ import { Tooltip } from 'antd'; import React, { Dispatch, ReactNode, SetStateAction } from 'react'; import { TABLE_CTRL_KEY } from '../constant'; import { AnyKeyProps } from '../types/AnyKeyProps'; -import { MwTableField } from './g-table'; -import './mw-table.less'; +import { GTableField } from './g-table'; +import './g-table.less'; export const install = (renderMap: AnyKeyProps) => { /** @@ -145,9 +145,9 @@ export const install = (renderMap: AnyKeyProps) => { params: AnyKeyProps, tableData: Array, setTableData: Dispatch>>, - ctrl?: MwTableField, + ctrl?: GTableField, props?: AnyKeyProps, - ): Array => { + ): Array => { let tableFields = fields .filter((field) => { if (field.__extraTouched) { @@ -175,13 +175,13 @@ export const install = (renderMap: AnyKeyProps) => { tableFields.push(ctrl); } // 排序 - tableFields = tableFields.sort((a: MwTableField, b: MwTableField) => { + tableFields = tableFields.sort((a: GTableField, b: GTableField) => { return a.order - b.order; }); // 二次排序 if (tableFields.some((field) => field.__extraTouched)) { - tableFields = tableFields.sort((a: MwTableField, b: MwTableField) => { + tableFields = tableFields.sort((a: GTableField, b: GTableField) => { return (a.__order || 0) - (b?.__order || 0); }); } diff --git a/packages/gbeata/src/GTable/g-table.d.ts b/packages/gbeata/src/GTable/g-table.d.ts index 80e413cd..d51ad372 100644 --- a/packages/gbeata/src/GTable/g-table.d.ts +++ b/packages/gbeata/src/GTable/g-table.d.ts @@ -4,18 +4,18 @@ import { ReactNode } from 'react'; import { Option } from '../GForm/g-form'; import { AnyKeyProps } from '../types/AnyKeyProps'; -export interface MwListProps { +export interface GListProps { title?: string | ReactNode; children?: ReactNode; header?: ReactNode; size?: SizeType; api?(params: AnyKeyProps): Promise; /** 列表项 */ - fields: Array; + fields: Array; /** 列表数据 */ data?: Array; /** 操作列 */ - ctrl?: MwTableField; + ctrl?: GTableField; /** 列表前面的 selection */ rowSelection?: TableRowSelection; /** 列表查询完成监听 */ @@ -52,7 +52,7 @@ export interface MwListProps { /** 提示文本 */ tooltip?: string; } -export interface MwTableProps { +export interface GTableProps { title?: string | ReactNode; children?: ReactNode; header?: ReactNode; @@ -60,11 +60,11 @@ export interface MwTableProps { size?: SizeType; api?(params: AnyKeyProps): Promise; /** 列表项 */ - fields: Array; + fields: Array; /** 列表数据 */ data?: Array; /** 操作列 */ - ctrl?: MwTableField; + ctrl?: GTableField; /** 表格前面的 selection */ rowSelection?: TableRowSelection; /** 表格查询完成监听 */ @@ -115,7 +115,7 @@ export interface MwTableProps { resizableHeader?: boolean; } -export interface MwTableField { +export interface GTableField { /** 标题 */ title?: ReactNode | string; /** 唯一 key,dataIndex 默认会跟此值一样 */ @@ -142,7 +142,7 @@ export interface MwTableField { [key: string]: any; } -export interface MwTableCtrlField extends MwTableField { +export interface GTableCtrlField extends GTableField { /** render 函数 */ render(text: ReactNode, record: AnyKeyProps, index: number): ReactNode; } diff --git a/packages/gbeata/src/GTable/index.d.ts b/packages/gbeata/src/GTable/index.d.ts index 77c40f12..3bbc81df 100644 --- a/packages/gbeata/src/GTable/index.d.ts +++ b/packages/gbeata/src/GTable/index.d.ts @@ -1,24 +1,31 @@ -import { MwTableProps } from './mw-table' -import { AnyKeyProps } from '../types/AnyKeyProps' +import { AnyKeyProps } from '../types/AnyKeyProps'; +import { GTableProps } from './g-table'; /** * 自定义查询前过滤 * @param params 查询参数 */ -export declare function setDefaultSearchFilter(params: AnyKeyProps): AnyKeyProps +export declare function setDefaultSearchFilter( + params: AnyKeyProps, +): AnyKeyProps; /** * 自定义查询后过滤 * @param params 查询参数 */ -export declare function setDefaultDataFilter(params: AnyKeyProps): AnyKeyProps +export declare function setDefaultDataFilter(params: AnyKeyProps): AnyKeyProps; /** * 自定义表格渲染 * @param params 渲染参数 */ -export declare function registerTableRender(key: string, params: AnyKeyProps): void +export declare function registerTableRender( + key: string, + params: AnyKeyProps, +): void; -declare const MwTable: React.ForwardRefExoticComponent> +declare const MwTable: React.ForwardRefExoticComponent< + GTableProps & React.RefAttributes +>; -export default MwTable +export default MwTable; diff --git a/packages/gbeata/src/GTable/index.tsx b/packages/gbeata/src/GTable/index.tsx index b850da61..1cf36476 100644 --- a/packages/gbeata/src/GTable/index.tsx +++ b/packages/gbeata/src/GTable/index.tsx @@ -10,8 +10,8 @@ import React, { useRef, useState, } from 'react'; -import { MwListContext } from '../GList/context'; -import { SortItem } from '../MwSearchTable/mw-search-table'; +import { GListContext } from '../GList/context'; +import { SortItem } from '../GSearchTable/g-search-table'; import { TABLE_DEFAULT_ROW_KEY, TABLE_PAGESIZE, @@ -23,8 +23,8 @@ import { clearEmpty, getKey } from '../utils'; import { getComponents } from './EditableTable'; import RenderMapInit from './RenderMapInit'; import core from './core'; -import { LoadParams, MwTableField, MwTableProps, RenderProps } from './g-table'; -import './mw-table.less'; +import { GTableField, GTableProps, LoadParams, RenderProps } from './g-table'; +import './g-table.less'; /** 默认请求前列表过滤 */ export let defaultSearchFilter = (params: AnyKeyProps) => { @@ -75,7 +75,7 @@ export const setTableDefaultProps = (props: AnyKeyProps) => { tableDefaultProps = props; }; -export default forwardRef(function MwTable(props: MwTableProps, ref) { +export default forwardRef(function MwTable(props: GTableProps, ref) { const { className, rowClassName, @@ -124,7 +124,7 @@ export default forwardRef(function MwTable(props: MwTableProps, ref) { /** 表格数据 */ const [tableData, setTableData] = useState>(data || []); /** 表格配置 */ - const ayTableFields: Array = useMemo(() => { + const ayTableFields: Array = useMemo(() => { return getAyTableFields( fields, loadParams, @@ -499,7 +499,7 @@ export default forwardRef(function MwTable(props: MwTableProps, ref) { }; return ( - - + ); }); diff --git a/packages/gbeata/src/MwSearchList/Selection/index.tsx b/packages/gbeata/src/MwSearchList/Selection/index.tsx index 293fbe0d..56dd75b7 100644 --- a/packages/gbeata/src/MwSearchList/Selection/index.tsx +++ b/packages/gbeata/src/MwSearchList/Selection/index.tsx @@ -1,45 +1,50 @@ -import { Record } from '../../types/Record' -import { getKey } from '../../utils' -import { Checkbox } from 'antd' -import React, { useContext, useEffect } from 'react' -import { MwSearchTableContext } from '../../MwSearchTable/context' -import { MwListContext } from '../../MwList/context' -import { MwSelectionProps } from '../mw-search-list' +import { Checkbox } from 'antd'; +import React, { useContext, useEffect } from 'react'; +import { GListContext } from '../../GList/context'; +import { GSearchTableContext } from '../../GSearchTable/context'; +import { Record } from '../../types/Record'; +import { getKey } from '../../utils'; +import { GSelectionProps } from '../g-search-list'; -export default function Selection(props: MwSelectionProps) { - const { selection, rowKey, addSelection, removeSelection } = useContext(MwSearchTableContext) - const { disabledKeys, setDisabledKeys } = useContext(MwListContext) - const { record, disabled, ...extendProps } = props +export default function Selection(props: GSelectionProps) { + const { selection, rowKey, addSelection, removeSelection } = + useContext(GSearchTableContext); + const { disabledKeys, setDisabledKeys } = useContext(GListContext); + const { record, disabled, ...extendProps } = props; - const isChecked = selection.some((row: Record) => getKey(record, rowKey) === getKey(row, rowKey)) + const isChecked = selection.some( + (row: Record) => getKey(record, rowKey) === getKey(row, rowKey), + ); const toggleChecked = (checked: boolean) => { if (checked) { - addSelection([record]) + addSelection([record]); } else { - removeSelection(null, record) + removeSelection(null, record); } - } + }; useEffect(() => { if (disabled) { // 如果禁用了,没有注册过就补一个 if (!disabledKeys.includes(getKey(record, rowKey))) { - setDisabledKeys([...disabledKeys, getKey(record, rowKey)]) + setDisabledKeys([...disabledKeys, getKey(record, rowKey)]); } } else { // 如果没有禁用,注册过就删掉 if (disabledKeys.includes(getKey(record, rowKey))) { - setDisabledKeys(disabledKeys.filter((key: string) => key !== getKey(record, rowKey))) + setDisabledKeys( + disabledKeys.filter((key: string) => key !== getKey(record, rowKey)), + ); } } - }, [disabled, disabledKeys]) + }, [disabled, disabledKeys]); return ( toggleChecked(e.target.checked)} + onChange={(e) => toggleChecked(e.target.checked)} /> - ) + ); } diff --git a/packages/gbeata/src/MwSearchList/SelectionAll/index.tsx b/packages/gbeata/src/MwSearchList/SelectionAll/index.tsx index 954cba81..d6b03c67 100644 --- a/packages/gbeata/src/MwSearchList/SelectionAll/index.tsx +++ b/packages/gbeata/src/MwSearchList/SelectionAll/index.tsx @@ -1,42 +1,59 @@ -import { AnyKeyProps } from '../../types/AnyKeyProps' -import { Record } from '../../types/Record' -import { Checkbox } from 'antd' -import React, { useContext } from 'react' -import { MwSearchTableContext } from '../../MwSearchTable/context' -import { MwListContext } from '../../MwList/context' -import { getKey } from '../../utils' +import { Checkbox } from 'antd'; +import React, { useContext } from 'react'; +import { GListContext } from '../../GList/context'; +import { GSearchTableContext } from '../../GSearchTable/context'; +import { AnyKeyProps } from '../../types/AnyKeyProps'; +import { Record } from '../../types/Record'; +import { getKey } from '../../utils'; export default function Selection(props: AnyKeyProps) { - const { selection, rowKey, addSelection, setSelection } = useContext(MwSearchTableContext) - const { data, disabledKeys } = useContext(MwListContext) + const { selection, rowKey, addSelection, setSelection } = + useContext(GSearchTableContext); + const { data, disabledKeys } = useContext(GListContext); // 获取到已选中的行组成的 keys - let keys = selection.map((row: Record) => getKey(row, rowKey)) + let keys = selection.map((row: Record) => getKey(row, rowKey)); // 获取到没有被禁用的列 - let noDisabledData = data.filter((row: Record) => !disabledKeys.includes(getKey(row, rowKey))) + let noDisabledData = data.filter( + (row: Record) => !disabledKeys.includes(getKey(row, rowKey)), + ); // 是否全选 const isAllChekced = - noDisabledData.every((row: Record) => keys.includes(getKey(row, rowKey))) && noDisabledData.length > 0 + noDisabledData.every((row: Record) => keys.includes(getKey(row, rowKey))) && + noDisabledData.length > 0; // 是否半选 const isIndeterminate = noDisabledData.some((row: Record) => keys.includes(getKey(row, rowKey))) && !isAllChekced && - noDisabledData.length > 0 + noDisabledData.length > 0; // 切换选中 const toggleChecked = () => { // 去选取消所有选项 if (isAllChekced) { // 当前列表数据组成的 keys - let dataKeys = data.map((row: Record) => getKey(row, rowKey)) + let dataKeys = data.map((row: Record) => getKey(row, rowKey)); // 过滤掉当前页面所有的 keys 剩下的选项 - let newSelection = selection.filter((row: Record) => !dataKeys.includes(getKey(row, rowKey))) + let newSelection = selection.filter( + (row: Record) => !dataKeys.includes(getKey(row, rowKey)), + ); // 设置新的选项 - setSelection(newSelection) + setSelection(newSelection); } else { // 添加新选项,是个数组 - addSelection(noDisabledData.filter((row: Record) => !keys.includes(getKey(row, rowKey)))) + addSelection( + noDisabledData.filter( + (row: Record) => !keys.includes(getKey(row, rowKey)), + ), + ); } - } - return toggleChecked()} /> + }; + return ( + toggleChecked()} + /> + ); } diff --git a/packages/gbeata/src/MwSearchList/mw-search-list.d.ts b/packages/gbeata/src/MwSearchList/g-search-list.d.ts similarity index 87% rename from packages/gbeata/src/MwSearchList/mw-search-list.d.ts rename to packages/gbeata/src/MwSearchList/g-search-list.d.ts index 2617c2a7..cbc1c8f6 100644 --- a/packages/gbeata/src/MwSearchList/mw-search-list.d.ts +++ b/packages/gbeata/src/MwSearchList/g-search-list.d.ts @@ -1,10 +1,10 @@ import { SizeType } from 'antd/lib/config-provider/SizeContext'; import { ReactNode } from 'react'; import { - MwDialogFormField, - MwDialogFormProps, -} from '../MwDialogForm/g-dialog-form'; -import { MwTableCtrlField } from '../MwTable/mw-table'; + GDialogFormField, + GDialogFormProps, +} from '../GDialogForm/g-dialog-form'; +import { GTableCtrlField } from '../GTable/g-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; export interface SearchListInitConfig extends AnyKeyProps { @@ -22,11 +22,11 @@ export interface SearchListInitConfig extends AnyKeyProps { extraFullscreenVisible?: boolean; } -export interface MwSearchListProps extends SearchListInitConfig { +export interface GSearchListProps extends SearchListInitConfig { /** 标题 */ title?: string | ReactNode; /** 配置项 */ - fields?: Array; + fields?: Array; /** 子元素 */ children?: Array | ReactNode; /** 请求列表接口 */ @@ -36,7 +36,7 @@ export interface MwSearchListProps extends SearchListInitConfig { /** 表格数据(当不需要 api,由自己控制时使用) */ data?: Array; /** 表格操作列(写法跟正常的 filed 一致) */ - ctrl?: MwTableCtrlField; + ctrl?: GTableCtrlField; /** 为空时表示没有选框 */ selectionType?: 'checkbox' | 'radio'; /** 选项改变事件 */ @@ -46,9 +46,9 @@ export interface MwSearchListProps extends SearchListInitConfig { /** 选择时列表展示的 key */ selectShowKey?: string; /** dialog form 的配置 */ - dialogFormExtend?: MwDialogFormProps; + dialogFormExtend?: GDialogFormProps; /** 弹窗表单的配置项 */ - formField?: Array; + formField?: Array; /** 滚动的 X 轴数值 */ scrollX?: number; /** 表格高度 */ @@ -85,7 +85,7 @@ export interface MwSearchListProps extends SearchListInitConfig { searchExtend?: AnyKeyProps; } -export interface MwSelectionProps { +export interface GSelectionProps { record: AnyKeyProps; disabled?: boolean; } diff --git a/packages/gbeata/src/MwSearchList/index.d.ts b/packages/gbeata/src/MwSearchList/index.d.ts index 5c3a9e00..8a800d57 100644 --- a/packages/gbeata/src/MwSearchList/index.d.ts +++ b/packages/gbeata/src/MwSearchList/index.d.ts @@ -1,10 +1,12 @@ -import { MwSearchListProps } from './mw-search-list' -import Selection from './Selection' -import SelectionAll from './SelectionAll' +import { GSearchListProps } from './g-search-list'; +import Selection from './Selection'; +import SelectionAll from './SelectionAll'; -declare const MwSearchList: React.ForwardRefExoticComponent> & { - Selection?: typeof Selection - SelectionAll?: typeof SelectionAll -} +declare const MwSearchList: React.ForwardRefExoticComponent< + GSearchListProps & React.RefAttributes +> & { + Selection?: typeof Selection; + SelectionAll?: typeof SelectionAll; +}; -export default MwSearchList +export default MwSearchList; diff --git a/packages/gbeata/src/MwSearchList/index.tsx b/packages/gbeata/src/MwSearchList/index.tsx index 8c31a274..69249ef8 100644 --- a/packages/gbeata/src/MwSearchList/index.tsx +++ b/packages/gbeata/src/MwSearchList/index.tsx @@ -9,29 +9,29 @@ import React, { useRef, useState, } from 'react'; +import { getActionProps } from '../GAction'; +import GButton from '../GButton'; +import GDialogForm from '../GDialogForm'; +import { GDialogFormRef } from '../GDialogForm/g-dialog-form'; import { convertChildrenToField } from '../GFields/convertFields'; import GForm, { getDefaultValue } from '../GForm'; -import { getActionProps } from '../MwAction'; -import MwButton from '../MwButton'; -import MwDialogForm from '../MwDialogForm'; -import { MwDialogFormRef } from '../MwDialogForm/g-dialog-form'; -import MwList from '../MwList'; -import MwSearch from '../MwSearch'; -import { MwSearchField } from '../MwSearch/mw-search'; -import { MwSearchTableContext } from '../MwSearchTable/context'; +import GList from '../GList'; +import GSearch from '../GSearch'; +import { GSearchField } from '../GSearch/g-search'; +import { GSearchTableContext } from '../GSearchTable/context'; import { - MwSearchTableField, + GSearchTableField, SortItem, TableRefProps, -} from '../MwSearchTable/mw-search-table'; -import useExtraBtn from '../MwSearchTable/use/useExtraBtn'; -import useSelection from '../MwSearchTable/use/useSelection'; -import { MwTableField } from '../MwTable/mw-table'; +} from '../GSearchTable/g-search-table'; +import useExtraBtn from '../GSearchTable/use/useExtraBtn'; +import useSelection from '../GSearchTable/use/useSelection'; +import { GTableField } from '../GTable/g-table'; import { AnyKeyProps } from '../types/AnyKeyProps'; import { isObj } from '../utils'; import Selection from './Selection'; import SelectionAll from './SelectionAll'; -import { MwSearchListProps } from './mw-search-list'; +import { GSearchListProps } from './g-search-list'; import './mw-search-list.less'; @@ -41,14 +41,14 @@ export { Selection, SelectionAll }; * 转化并过滤成 mw-search 能用的 fields * @param fields 查询表格的 fields */ -const getSearchFields = (fields: Array) => { - let searchFields: Array = []; - let moreSearchFields: Array = []; +const getSearchFields = (fields: Array) => { + let searchFields: Array = []; + let moreSearchFields: Array = []; fields - .filter((field: MwSearchTableField) => { + .filter((field: GSearchTableField) => { return isObj(field.search) || field.search === true; }) - .forEach((field: MwSearchTableField) => { + .forEach((field: GSearchTableField) => { let search = typeof field.search === 'boolean' ? {} : field.search; if (!search) { return { @@ -57,7 +57,7 @@ const getSearchFields = (fields: Array) => { type: 'input', }; } - let searchField: MwSearchField = { + let searchField: GSearchField = { title: field.title, key: search.key || field.key || '', type: field.type || 'input', @@ -81,7 +81,7 @@ const getSearchFields = (fields: Array) => { /** * 判断该节点是否只出现在底部 - * @param node MwAction 按钮 + * @param node GAction 按钮 */ const isFooterActionOnly = (node: any) => { if (!node || !node.props) { @@ -92,8 +92,8 @@ const isFooterActionOnly = (node: any) => { }; /** - * 获取表格底部以及右侧 MwAction 按钮 - * @param node MwAction 按钮 + * 获取表格底部以及右侧 GAction 按钮 + * @param node GAction 按钮 */ const getTableActionBtns = ( children: ReactNode, @@ -123,7 +123,7 @@ const getTableActionBtns = ( }; }; -function MwSearchList(props: MwSearchListProps, ref: Ref) { +function GSearchList(props: GSearchListProps, ref: Ref) { const { fields: originFields, api, @@ -165,8 +165,8 @@ function MwSearchList(props: MwSearchListProps, ref: Ref) { }, [originFields, children]); /** form 控制 */ - const formRef: MutableRefObject = - useRef() as MutableRefObject; + const formRef: MutableRefObject = + useRef() as MutableRefObject; /** table 控制 */ const tableRef: MutableRefObject = useRef() as MutableRefObject; @@ -179,7 +179,7 @@ function MwSearchList(props: MwSearchListProps, ref: Ref) { /** 查询项 */ const { searchFields, moreSearchFields } = getSearchFields(fields); /** 列表项 */ - const [tableFields, setTableFields] = useState>([]); + const [tableFields, setTableFields] = useState>([]); /** 使用勾选 */ const { header, @@ -349,10 +349,10 @@ function MwSearchList(props: MwSearchListProps, ref: Ref) { fields={moreSearchFields} onConfirm={onConfirm} > - + > , ); } @@ -371,7 +371,7 @@ function MwSearchList(props: MwSearchListProps, ref: Ref) { return (
- ) { > {before} {searchVisible !== false && searchFields.length > 0 ? ( - ) { ) : null} {center} {dialogFormExtend ? ( - + {children} - + ) : null} - {tableChildren} - + {selection.length && footerActions.length ? (
{message} @@ -415,12 +415,12 @@ function MwSearchList(props: MwSearchListProps, ref: Ref) {
) : null} {after} -
+
); } -let component = forwardRef(MwSearchList); +let component = forwardRef(GSearchList); // @ts-ignore component.Selection = Selection; diff --git a/packages/gbeata/src/MwSearchTable/index.d.ts b/packages/gbeata/src/MwSearchTable/index.d.ts deleted file mode 100644 index 849ee21c..00000000 --- a/packages/gbeata/src/MwSearchTable/index.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { MwSearchTableProps, MwSearchTableField } from './mw-search-table' - -export { MwSearchTableField } - -declare const MwSearchTable: React.ForwardRefExoticComponent> - -export default MwSearchTable diff --git a/packages/gbeata/src/MwSearchTable/use/useSelection.tsx b/packages/gbeata/src/MwSearchTable/use/useSelection.tsx deleted file mode 100644 index 6411e1ab..00000000 --- a/packages/gbeata/src/MwSearchTable/use/useSelection.tsx +++ /dev/null @@ -1,237 +0,0 @@ -import React, { ReactNode, useState, ReactText, useEffect } from 'react' -import { Tag, Popover, Alert } from 'antd' -import MwAction from '../../MwAction' -import { AnyKeyProps } from '../../types/AnyKeyProps' -import { getKey } from '../../utils' -import locale from '../../locale' - -interface Row extends AnyKeyProps {} - -interface UseSelectionProps { - /** 表格 rowKey */ - rowKey?: ((record: AnyKeyProps) => string) | string - /** ☑️表格选择框类型 */ - selectionType?: 'checkbox' | 'radio' - /** 📢表格选择改变触发事件 */ - onSelectionChange?(selection: Array, selectionKeys: Array): void - /** 选中显示的名称 */ - selectShowKey?: string - /** 选择功能的配置 */ - rowSelection?: AnyKeyProps -} - -interface UseSelectionReturns { - /** 头部元素 */ - header: ReactNode - /** 只有消息部分 */ - message: ReactNode - /** 生成的 antd rowSelection */ - tableRowSelection: AnyKeyProps | undefined - /** ☑️已选中的选项 */ - selection: Array - /** 清空所有选项 */ - clearSelection(): void - /** 设置选中的项 */ - setSelection(selection: Array): void - /** 添加选中的项 */ - addSelection(selection: Array): void - /** 移除选项 */ - removeSelection?(i: number | null, record?: AnyKeyProps): void -} - -export default function useSelection(_props: UseSelectionProps): UseSelectionReturns { - const { rowKey, selectionType, onSelectionChange, selectShowKey, rowSelection } = _props - const [selectionKeys, setSelectionKeys] = useState>([]) - const [selection, setSelection] = useState>([]) - - let tableRowSelection: AnyKeyProps | undefined - - if (selectionType) { - tableRowSelection = { - ...rowSelection, - type: selectionType, - selectedRowKeys: selectionKeys, - onSelect: (record: Row, selected: boolean) => { - if (selectionType === 'radio') { - changeRadioSelection(record) - } else { - selected ? addSelection(record) : removeSelection(null, record) - } - }, - onSelectAll: (selected: boolean, selectedRows: Array, changeRows: Array) => { - selected ? addSelectionArray(selectedRows) : removeSelectionArray(changeRows) - } - } - } - - /** - * 清空所有选项 - */ - const clearSelection = () => { - setSelectionKeys([]) - setSelection([]) - } - - /** - * 设置选中的行 - */ - const setDefaultSelection = (selection: AnyKeyProps[]) => { - setSelection(selection) - setSelectionKeys(selection.map(row => getKey(row, rowKey))) - } - - /** - * 添加选项 - */ - const addDefaultSelection = (addSelection: AnyKeyProps[]) => { - // @ts-ignore - let newSelection = [...selection] - addSelection.forEach(row => { - if (!selectionKeys.includes(getKey(row, rowKey))) { - newSelection.push(row) - } - }) - - setSelection(newSelection) - setSelectionKeys(newSelection.map(row => getKey(row, rowKey))) - } - - const changeRadioSelection = (row: AnyKeyProps) => { - let newKeys = [] - let newSelection = [] - - newKeys.push(getKey(row, rowKey)) - newSelection.push(row) - - setSelectionKeys(newKeys) - setSelection(newSelection) - } - - /** - * 添加选项(单个) - * @param row 某一条选项 - */ - const addSelection = (row: AnyKeyProps) => { - // @ts-ignore - let newKeys = [...selectionKeys] - let newSelection = [...selection] - - newKeys.push(getKey(row, rowKey)) - newSelection.push(row) - - setSelectionKeys(newKeys) - setSelection(newSelection) - } - - /** - * 添加选项(数组) - * @param rows 项目列表 - */ - const addSelectionArray = (rows: Array) => { - let newKeys = [...selectionKeys] - let newSelection = [...selection] - - rows.forEach(row => { - if (!row) { - return - } - let key = getKey(row, rowKey) - if (!newKeys.includes(key)) { - newKeys.push(key) - newSelection.push(row) - } - }) - - setSelectionKeys(newKeys) - setSelection(newSelection) - } - - /** - * 移除某个选项 - * @param i 移除选项的 index - */ - const removeSelection = (i: number | null, record?: AnyKeyProps) => { - let newKeys = [...selectionKeys] - let newSelection = [...selection] - - if (i === null && record) { - i = newKeys.findIndex(key => key === getKey(record, rowKey)) - } - - if (typeof i === 'number') { - newKeys.splice(i, 1) - newSelection.splice(i, 1) - } - - setSelectionKeys(newKeys) - setSelection(newSelection) - } - - /** - * 移除一组选项 - * @param rows 移除选项 - */ - const removeSelectionArray = (rows: Array) => { - let newKeys = [...selectionKeys] - let newSelection = [...selection] - - rows.forEach(row => { - let index = newKeys.findIndex(item => item === getKey(row, rowKey)) - if (index >= 0) { - newKeys.splice(index, 1) - newSelection.splice(index, 1) - } - }) - - setSelectionKeys(newKeys) - setSelection(newSelection) - } - - /** Popover 弹窗的提示 */ - const popContent = ( -
- {selection.map((row, i) => { - return ( - removeSelection(i)}> - {row[selectShowKey || 'name']} - - ) - })} -
- ) - - const message = ( -
- - {locale.table.selectedBefore} - - {selection.length} - -  {locale.table.selectedAfter} - - - {locale.table.selectedClear} - -
- ) - - /** 头部已选中的提示 */ - const header = selectionKeys.length ? : '' - - useEffect(() => { - if (onSelectionChange) { - onSelectionChange(selection, selectionKeys) - } - }, [onSelectionChange, selection]) - - return { - header, - message, - tableRowSelection, - selection, - clearSelection, - removeSelection, - setSelection: setDefaultSelection, - addSelection: addDefaultSelection - } -} diff --git a/packages/gbeata/src/index.ts b/packages/gbeata/src/index.ts index eee75c1f..9c26d4cc 100644 --- a/packages/gbeata/src/index.ts +++ b/packages/gbeata/src/index.ts @@ -1,13 +1,21 @@ import GButton, { setPermissionList } from './GButton'; import GCardGroup from './GCardGroup'; +import MwDialog, { setGlobalDialogField } from './GDialog'; import GDialogForm from './GDialogForm'; import GField from './GField'; import GFields from './GFields'; import GForm, { registerField } from './GForm'; import { error, info, success, warning } from './GMessage'; import GSearch, { setSearchDefaultVisibleRow } from './GSearch'; +import GSearchTable, { setSearchTableDefaultValue } from './GSearchTable'; +import GSelect from './GSelect'; +import GTable, { + registerTableRender, + setDefaultDataFilter, + setDefaultSearchFilter, + setTableDefaultProps, +} from './GTable'; import { default as GTagGroup } from './GTagGroup'; -import MwDialog, { setGlobalDialogField } from './MwDialog'; export { GButton, GCardGroup, @@ -16,13 +24,21 @@ export { GFields, GForm, GSearch, + GSearchTable, + GSelect, + GTable, GTagGroup, MwDialog, error, info, + registerTableRender, + setDefaultDataFilter, + setDefaultSearchFilter, setGlobalDialogField, setPermissionList, setSearchDefaultVisibleRow, + setSearchTableDefaultValue, + setTableDefaultProps, success, warning, }; @@ -45,4 +61,12 @@ export default { GSearch, setSearchDefaultVisibleRow, GCardGroup, + GSearchTable, + setSearchTableDefaultValue, + GSelect, + GTable, + setDefaultDataFilter, + setDefaultSearchFilter, + registerTableRender, + setTableDefaultProps, }; diff --git a/packages/gbeata/src/less/variable.less b/packages/gbeata/src/less/variable.less new file mode 100755 index 00000000..7310bad0 --- /dev/null +++ b/packages/gbeata/src/less/variable.less @@ -0,0 +1,40 @@ +@space: 10px; +@gap: (@space / 2); +@space2: @space * 2; +@space3: @space * 3; +@space4: @space * 4; + +@primary: #4091f1; +@bg-gray: #fbfbfb; + +:root { + --ay-primary-color: #1890ff; + --ay-primary-bg-color: #e6f7ff; + --ay-primary-border-color: #69c0ff; + --ay-border-color: #d9d9d9; + --ay-disabled-bg-color: #f5f5f5; + --ay-disabled-font-color: rgba(0, 0, 0, 0.25); + --ay-sub-color: rgba(0, 0, 0, 0.45); +} + +.flex () { + display: flex; + justify-content: center; + align-items: center; +} + +.fr { + float: right; +} + +.ml { + margin-left: @space; +} + +.mb { + margin-bottom: @space; +} + +.gap { + margin-left: 4px; +}