diff --git a/.umirc.library.ts b/.fatherrc.ts similarity index 100% rename from .umirc.library.ts rename to .fatherrc.ts diff --git a/package.json b/package.json index 05e228996e994a5867bf2e71912cd90453090a53..71d211f01a92968bacafd5fe11fcb72cecdefcf1 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "lint-staged:ts": { "src/**/*.{ts,tsx}": [ "prettier --write", - "tslint --fix", + "tslint --fix" ] } } diff --git a/src/apollo-table/component/Cell.tsx b/src/apollo-table/component/Cell.tsx index b3b6e13cdab6b8d1a915ce53d325ea09b39d9b90..4fb8d357f3975c6d5a270a06423d37a79a87c1fd 100644 --- a/src/apollo-table/component/Cell.tsx +++ b/src/apollo-table/component/Cell.tsx @@ -1,4 +1,4 @@ -import React, { ReactComponentElement } from 'react'; +import React from 'react'; import { message, Popover, Modal } from 'antd'; import { getComponent } from './base'; diff --git a/src/apollo-table/component/Table.less b/src/apollo-table/component/Table.less index 672bf5f356bf22618094bd12fbacb92390d70ed6..8090b6db78b1d655a300bf5e2aaaa2fcf40401b9 100644 --- a/src/apollo-table/component/Table.less +++ b/src/apollo-table/component/Table.less @@ -1,7 +1,8 @@ +@import '../../common'; + .tableCell { - //padding: 0 !important; &.sortCol { - background: rgba(92, 153, 255, 0.2); + background: @hoverColor; } } @@ -18,23 +19,13 @@ :global(.ant-table-thead > tr > th) { padding: 0; - //margin-bottom: 1px; - //text-align: center; } - //:global(.ant-table-thead > tr > th:first-child) { - // border-right: none; - //} - :global(.ant-table-tbody > tr > td) { padding: 0; height: 40px; } - //:global(.ant-table-tbody > tr > td:first-child) { - // border-right: none; - //} - :global(.ant-table-tbody > tr > td:last-child) { text-align: left; } @@ -48,13 +39,6 @@ background: white; } - //:global(.ant-table-bordered.ant-table-fixed-header - // .ant-table-header - // + .ant-table-body - // > table) { - // border-top: 0px solid #e8e8e8; - //} - :global(.ant-table-row-hover) { .unchecked { display: block; @@ -80,7 +64,7 @@ box-sizing: border-box; &.disabled { - background: #f9f9f9; + background: @disabledColor; &:hover { box-shadow: none; @@ -88,7 +72,7 @@ } &:hover { - box-shadow: inset 0 0 0 1px #85b6ff; + box-shadow: inset 0 0 0 1px @operateColor; .showFormBtn { visibility: visible; @@ -106,9 +90,11 @@ .cellNo { display: flex; align-items: center; + min-width: 50px; } .cellContent { + flex: 1; overflow: hidden; height: 100%; @@ -143,6 +129,11 @@ display: flex; flex-direction: row; background: #fff; + .LeftSideContainer{ + box-shadow: 6px 0 6px -4px rgba(0, 0, 0, 0.15); + position: absolute; + z-index: 1; + } } .GridColumn { @@ -157,7 +148,6 @@ z-index: 10; background: #fff; border-left: 1px solid #e8e8e8; - box-shadow: 6px 0 6px -4px rgba(0, 0, 0, 0.15); } .LeftSideGrid { @@ -181,7 +171,7 @@ box-sizing: border-box; .cellNo { - margin-right: 5px; + min-width: 50px; } .cellContent { @@ -206,7 +196,7 @@ justify-content: center; align-items: center; text-align: center; - padding: 0 0.5em; + padding: 0 .5em; } .headerCell, diff --git a/src/apollo-table/component/Table.tsx b/src/apollo-table/component/Table.tsx index cfd1500a7606646fce6b7f9b9acfda836db7f617..45c1b36109e2ba0d832c85a6b20c2599fb074a6a 100644 --- a/src/apollo-table/component/Table.tsx +++ b/src/apollo-table/component/Table.tsx @@ -8,6 +8,7 @@ import styles from './Table.less'; import { TableProps, TableState } from './interface'; import Column from './Column'; import Cell from './Cell'; +import extendIcon from '../assets/extend.png'; export default class AirTable extends Component { static getDerivedStateFromProps(nextProps: TableProps, prevState: TableState) { @@ -26,10 +27,11 @@ export default class AirTable extends Component { } constructor(props: TableProps) { super(props); - const { columns, dataSource, tableId } = props; + const { columns, dataSource, tableId, checked = [] } = props; this.state = { columns, dataSource, + checked, tableId, prevProps: props, height: document.body.clientHeight - 193, @@ -43,12 +45,24 @@ export default class AirTable extends Component { }; this.memoizeLeftCount = memoizeOne(this.getLeftCount); this.memoizeData = memoizeOne(this.filterData); + this.indexCount = {}; + } + componentDidMount() { + window.addEventListener('resize', this.resize, false); } + //重置窗口高度 + resize = () => { + this.setState({ + height: document.body.clientHeight - 193, + }); + }; //获取左侧固定列数量 getLeftCount = (columns: []) => { let len = 0; columns.map((item: any) => { - item.fixed && len++; + if (item.fixed) { + len += 1; + } }); return len; }; @@ -61,31 +75,104 @@ export default class AirTable extends Component { let i = 0; this.indexCount = {}; cloneData.map((item1: any) => { - item1.rowData = item1.rowData.filter((item2: any) => + const itemData = item1; + itemData.rowData = itemData.rowData.filter((item2: any) => columns.some((temp: any) => temp.columnName === item2.colName), ); - if (item1.groupId) { - if (this.indexCount[item1.groupId]) { - this.indexCount[item1.groupId].push(item1.id); + if (itemData.groupId) { + if (this.indexCount[itemData.groupId]) { + this.indexCount[itemData.groupId].push(itemData.id); } else { - i++; - this.indexCount[item1.groupId] = [item1.id]; + i += 1; + this.indexCount[itemData.groupId] = [itemData.id]; } - item1.index = i; + itemData.index = i; } - return item1; + return itemData; }); return cloneData; }; - //下拉加载 + // 复选框选择 + changeCheckbox = (record: any, flag: boolean) => { + const { changeChecked, hasGroup } = this.props; + const { checked, dataSource } = this.state; + let temp = checked.slice(); + if (flag) { + if (hasGroup) { + const selected = dataSource.filter((item: any) => { + return item.groupId === record.groupId; + }); + temp = temp.concat(selected); + } else { + temp.push(record); + } + } else { + if (hasGroup) { + temp = temp.filter((item: any) => { + return item.groupId !== record.groupId; + }); + } + const index = temp.findIndex((item: any) => { + return item.id === record.id; + }); + temp.splice(index, 1); + } + if (typeof changeChecked === 'function') { + changeChecked({ checked: temp }); + } + }; + // 检测当前分组是否全部选中 + getCheckedAll = () => { + const { checked, dataSource } = this.state; + const temp = checked.slice(); + const result = temp.filter((v: any) => { + return dataSource.some((item: any) => { + return item.id === v.id; + }); + }); + return result.length === dataSource.length && result.length !== 0; + }; + // 全选/反选 + changeCheckboxAll = () => { + const { checked, dataSource } = this.state; + const { changeChecked } = this.props; + const temp = checked.slice(); + const flag = this.getCheckedAll(); + let result = []; + if (flag) { + result = temp.concat(dataSource).filter((v:any) => { + return ( + temp.some((item: any) => { + return item.id === v.id; + }) && + !dataSource.some((item: any) => { + return item.id === v.id; + }) + ); + }); + } else { + result = temp.concat( + dataSource.filter((v: any) => { + return !temp.some((item: any) => { + return item.id === v.id; + }); + }), + ); + } + if (typeof changeChecked === 'function') { + changeChecked({ checked: result }); + } + }; + // 下拉加载 onScrollRow = ({ clientHeight, scrollTop }: any) => { const height = clientHeight + scrollTop || 0; const { dataSource = [], rowHeight = 40 } = this.state; + const { onScroll } = this.props; const offset = 100; if (dataSource.length === 0) return; - if (height + offset >= dataSource.length * rowHeight) { - this.props.onScroll && this.props.onScroll(); - } else return; + if (height + offset >= dataSource.length * rowHeight && typeof onScroll === 'function') { + onScroll(); + } }; //渲染表头 renderHeaderCell = ({ columnIndex, key, rowIndex, style }: any) => { @@ -96,7 +183,7 @@ export default class AirTable extends Component { return (
- +
@@ -110,18 +197,93 @@ export default class AirTable extends Component {
); }; + // 渲染首列复选框 + renderCheckbox = (record: any, rowIndex: number) => { + const { checked } = this.state; + const { hasGroup } = this.props; + const flag = checked.some((item: any) => { + return item.id === record.id; + }); + let checkbox = flag ? ( + + ) : ( + <> + +
{record.index || rowIndex + 1}
+ + ); + if (hasGroup) { + if ( + this.indexCount[record.groupId][Math.floor((this.indexCount[record.groupId].length - 1) / 2)] !== + record.id + ) { + // 填充透明的复选框使样式保持一致 + checkbox = ; + } + } + return checkbox; + }; + //渲染数据 renderBodyCell = (data: [], { columnIndex, key, rowIndex, style }: any) => { - const { columns } = this.state; + const { columns, dataSource } = this.state; + const { + updateData, + hasGroup, + showForm=()=>{}, + delData, + getData, + extraMenu, + noAdd, + noEdit, + noDel, + tableId, + flush, + } = this.props; if (columns.length === 0 || data.length === 0) { return; } - const rowData: any = data[rowIndex] || {}; - const columnData: any = (rowData.rowData && rowData.rowData[columnIndex]) || {}; - const cellData: [] = columnData.cellValueList || []; - let columnConfig = columns[columnIndex]; + const filterRowData: any = data[rowIndex]; // 过滤掉隐藏项并追加行号的行数据,只在渲染逻辑中使用 + const rowData: any = dataSource[rowIndex]; // 原始行数据,真实使用的数据 + const columnConfig: any = columns[columnIndex]; // 列属性 + const columnData: any = rowData.rowData[columnIndex]; // 列数据 + const cellData: any = columnData.cellValueList; // 列数据 let className = styles.indexCell; - + // 只读列不可编辑样式 + if (columnConfig.readOnlyFlag || rowData.isLocked || noEdit) { + className += ` ${styles.disabled}`; + } + let extraIndexCellStyle = {}; + let extraCellContentStyle = {}; + if (hasGroup) { + if (columnConfig.splitFlag) { + // 正常列额外样式 + extraIndexCellStyle = { + borderTop: + this.indexCount[rowData.groupId][0] !== rowData.id ? '1px solid #F7F7F7' : '1px solid #e8e8e8', + borderBottom: rowIndex + 1 < data.length ? 0 : '1px solid #e8e8e8', + }; + } else { + // 不可拆分列额外样式 + extraIndexCellStyle = { + borderTop: this.indexCount[rowData.groupId][0] !== rowData.id ? 0 : '1px solid #e8e8e8', + borderBottom: rowIndex + 1 < data.length ? 0 : '1px solid #e8e8e8', + }; + // 不可拆分列数据样式 + extraCellContentStyle = { + display: + this.indexCount[rowData.groupId][ + Math.floor((this.indexCount[rowData.groupId].length - 1) / 2) + ] !== rowData.id + ? 'none' + : 'auto', + }; + } + } if (columnIndex === 0) { return (
{ className={className} style={{ ...style, + ...extraIndexCellStyle, }} > -
- +
+ {this.renderCheckbox(filterRowData, rowIndex)} + edit +
+
+
); @@ -143,10 +331,27 @@ export default class AirTable extends Component { className={className} style={{ ...style, + ...extraIndexCellStyle, }} > -
- +
+
); @@ -154,6 +359,8 @@ export default class AirTable extends Component { render() { const { columns, dataSource, checked } = this.state; + const { changeChecked, operateConfig = {}, hasGroup } = this.props; + const { groupConfig } = operateConfig; const { overscanColumnCount, overscanRowCount, columnWidth, rowHeight } = this.config; let { height } = this.state; if (dataSource.length * rowHeight < height) { @@ -171,61 +378,72 @@ export default class AirTable extends Component { {({ onScroll, scrollLeft, scrollTop }: any) => { return (
- { - //左侧表头 -
- -
- } - { - //左侧固定列 -
- -
- } +
+ { + //左侧表头 +
+ +
+ } + { + //左侧固定列 +
+ +
+ } +
{({ width }: any) => ( @@ -284,6 +502,7 @@ export default class AirTable extends Component { cellRenderer={this.renderBodyCell.bind(this, data)} columns={columns} checked={checked} + hasGroup={hasGroup} />
} diff --git a/src/common.less b/src/common.less new file mode 100644 index 0000000000000000000000000000000000000000..9a762135a75b086ed0480d13b457acd714d606f1 --- /dev/null +++ b/src/common.less @@ -0,0 +1,40 @@ +//全局布局 +@secondSliderBg: #F8FAFA; //二级菜单背景 +@contentBg: #F5F5F5; //内容区背景 +//全局color +@primaryColor: #04B4AD; //主题色 --关键行动点,操作状态、重要信息高亮,图形化等场 +@textPrimaryColor: #2C3F53; //重要文字颜色 --用于重要级文字信息、内页标题信息(label) +@textGeneralColor: #5A6876; //普通文字颜色 --用于普通级段落信息、内标题信息(如详情段落标题信息)(value) +@textSupplyColor: #848F9B; //辅助文字颜色 --用于辅助、次要文字信息、普通按钮描边 +@textHolderColor: #AEB4BA; // --用于表格输入框文字提示、缺省图下方文案 +@borderColor: #ECECEC; // --分割线及边框颜色 +@tableHoverBgColor: #F9FBFF; // --用于表格的选中底色 +@disabledColor: #F9F9F9; //禁用颜色 +@errorColor: #FF5363; //错误提示颜色 +@hoverColor: #04B4AD; //鼠标悬停颜色 +@operateColor: #04B4AD; //表格操作按钮颜色 + +// 菜单颜色 +@sliderWidth: 70px; //一级菜单宽度 +@secondSliderWidth: 180px; //二级菜单宽度 +@headerHeight: 60px; //三级标题菜单高度 +//全局字号 +@textFontLgX: 18px; //标题 +@textFontLg: 16px; //小标题&需醒目区别的正文 +@textFontGen: 14px; //正文 +@textFontSm: 12px; //正文和辅助文字 + +//全局间距 +@marginLgX: 24px; +@marginLg: 16px; +@marginGen: 10px; +@marginSm: 8px; +@marginSmX: 5px; +@paddingLgX: 24px; +@paddingLg: 16px; +@paddingGen: 10px; +@paddingSm: 8px; +@paddingSmX: 5px; + +//全局圆角 +@borderRadius: 4px; diff --git a/src/index.mdx b/src/index.mdx index e3de9c6444b44cb56a5a167b3f09efe9b2391136..d60463d8bddd6830a349b65643d2475931bbfd49 100644 --- a/src/index.mdx +++ b/src/index.mdx @@ -11,4 +11,6 @@ import ApolloTable from './apollo-table'; ## Normal ApolloTable +
Hi +