feat: crud2 移动端卡片模式支持固定新增按钮以及顶部搜索

This commit is contained in:
jinye 2024-10-25 20:09:52 +08:00 committed by lmaomaoz
parent cf7de4cb6e
commit 20b969fe2c
2 changed files with 133 additions and 9 deletions

View File

@ -174,15 +174,28 @@
}
&-actions {
padding-top: var(--sizes-base-4);
padding-bottom: var(--sizes-base-4);
gap: var(--sizes-base-5);
justify-content: flex-end;
flex-wrap: wrap;
&-wrapper {
padding-left: var(--gap-md);
padding-right: var(--gap-md);
}
& > a {
height: var(--sizes-base-12);
line-height: var(--sizes-base-12);
margin-top: var(--sizes-size-4);
margin-bottom: var(--sizes-size-4);
line-height: var(--sizes-base-14);
background: var(--colors-link-10);
border-radius: var(--sizes-base-7);
font-size: var(--fontSizeBase);
color: var(--colors-link-5);
flex-grow: 0;
text-align: center;
padding: 0 var(--sizes-base-10);
&.text-danger {
background-color: var(--colors-error-10);
color: var(--colors-error-5);
}
}
}
@ -242,6 +255,51 @@
}
}
}
.#{$ns}Button.is-fixed-right-bottom {
position: fixed;
right: 12px;
bottom: 70px;
z-index: 1300;
width: 46px;
height: 46px;
border-radius: 50%;
background: #528eff;
box-shadow: 0 2px 12px 0 rgba(22, 27, 67, 0.2);
border: 0 !important;
.#{$ns}Button-icon {
width: 18px;
height: 18px;
}
}
.is-fixed-right-bottom-wrapper {
flex: 0 !important;
& + div {
position: sticky !important;
top: 0;
margin-top: 0;
.#{$ns}SearchBox {
margin-left: 0;
}
}
}
.#{$ns}Crud2-header-toolbar.is-sticky {
position: sticky;
top: 0;
z-index: 1300;
background-color: #fff;
padding: 5px 16px;
margin-top: calc(-1 * var(--Page-body-padding));
margin-left: calc(-1 * var(--Page-body-padding));
margin-right: calc(-1 * var(--Page-body-padding));
.#{$ns}SearchBox {
background: #f7f7f9;
border-radius: 4px;
border-bottom: 0;
}
}
}
}

View File

@ -1416,6 +1416,52 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
};
}
// headerToolbar 移动端适配,如果只有新增按钮,则将新增按钮固定到屏幕右下
transMobileHeaderToolbar(toolbar: any, fixedHeader: () => void) {
let buttonCount = 0;
let addButton: any = {};
let addButtonParent: any = {};
let searchBox: any = {};
function traverse(node: any, parentObj?: any) {
if (Array.isArray(node)) {
node.forEach((item: any) => traverse(item, parentObj));
} else if (node && typeof node === 'object') {
if (node.type === 'button') {
buttonCount++;
if (node.label === '新增') {
addButton = node;
addButtonParent = parentObj;
}
} else if (node.type === 'search-box') {
searchBox = node;
}
Object.values(node).forEach((item: any) => traverse(item, node));
}
}
toolbar.forEach((item: any) => {
traverse(item);
});
if (buttonCount === 1 && addButton) {
addButton.label = '';
addButton.icon = 'plus';
if (!addButton.className) {
addButton.className = '';
}
addButton.className += ' is-fixed-right-bottom';
if (addButtonParent) {
if (!addButtonParent.className) {
addButtonParent.className = '';
}
addButtonParent.className += ' is-fixed-right-bottom-wrapper';
}
if (searchBox) {
fixedHeader();
}
}
}
render() {
const {
columns,
@ -1464,8 +1510,8 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
} = this.props;
let pullRefresh: any;
let mobileModeProps: any = {};
let stickyHeader = false;
let mobileModeProps: any = null;
if (mobileMode && mobileUI && mode.includes('table')) {
const cardsSchema = this.transformTable2cards();
if (typeof mobileMode === 'string' && mobileMode === 'cards') {
@ -1482,6 +1528,11 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
}
};
}
if (mobileModeProps) {
this.transMobileHeaderToolbar(headerToolbar, () => {
stickyHeader = true;
});
}
// 移动端模式,默认开启上拉刷新
if (mobileModeProps && !_pullRefresh?.disabled) {
pullRefresh = {
@ -1557,7 +1608,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
'is-loading': store.loading,
'is-mobile': mobileUI,
'is-mobile-cards':
mobileMode === 'cards' || mobileModeProps.type === 'cards'
mobileMode === 'cards' || mobileModeProps?.type === 'cards'
})}
style={style}
data-id={id}
@ -1570,7 +1621,16 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
{this.renderFilter(filterSchema)}
</div>
<div className={cx('Crud2-toolbar', headerToolbarClassName)}>
<div
className={cx(
'Crud2-toolbar',
'Crud2-header-toolbar',
headerToolbarClassName,
{
'is-sticky': stickyHeader
}
)}
>
{this.renderToolbar('headerToolbar', headerToolbar)}
</div>
@ -1597,7 +1657,13 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
) : (
<>
{body}
<div className={cx('Crud2-toolbar', footerToolbarClassName)}>
<div
className={cx(
'Crud2-toolbar',
'Crud2-footer-toolbar',
footerToolbarClassName
)}
>
{this.renderToolbar('footerToolbar', footerToolbar)}
</div>
</>