fix(mobile-client): fix multiple bugs and do some improvement (#2072)
This commit is contained in:
parent
6254fceb04
commit
b80aaacb38
@ -42,7 +42,5 @@
|
||||
}
|
||||
|
||||
html body {
|
||||
--adm-font-family: -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Hiragino Sans GB,
|
||||
Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji,
|
||||
Segoe UI Symbol;
|
||||
--adm-font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||
}
|
||||
|
@ -2,45 +2,36 @@ import { css } from '@emotion/css';
|
||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||
import { TabPaneProps, Tabs as AntdTabs, TabsProps } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import React, { useMemo } from 'react';
|
||||
import React from 'react';
|
||||
import { Icon } from '../../../icon';
|
||||
import { useSchemaInitializer } from '../../../schema-initializer';
|
||||
import { DndContext, SortableItem } from '../../common';
|
||||
import { useDesigner } from '../../hooks/useDesigner';
|
||||
import { TabsContextProvider, useTabsContext } from './context';
|
||||
import { useTabsContext } from './context';
|
||||
import { TabsDesigner } from './Tabs.Designer';
|
||||
import { useDesignable } from '../../hooks';
|
||||
|
||||
export const Tabs: any = observer(
|
||||
(props: TabsProps) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
|
||||
const { designable } = useDesignable();
|
||||
const contextProps = useTabsContext();
|
||||
|
||||
const PaneProvider = useMemo(() => {
|
||||
if (contextProps.deep === false) {
|
||||
return TabsContextProvider;
|
||||
}
|
||||
return React.Fragment;
|
||||
}, [contextProps.deep]);
|
||||
const { PaneRoot = React.Fragment as React.FC<any> } = contextProps;
|
||||
|
||||
return (
|
||||
<DndContext>
|
||||
<AntdTabs
|
||||
{...contextProps}
|
||||
style={props.style}
|
||||
tabBarExtraContent={{
|
||||
right: render(),
|
||||
}}
|
||||
>
|
||||
<AntdTabs {...contextProps} style={props.style}>
|
||||
{fieldSchema.mapProperties((schema, key) => {
|
||||
return (
|
||||
<AntdTabs.TabPane tab={<RecursionField name={key} schema={schema} onlyRenderSelf />} key={key}>
|
||||
<PaneProvider>
|
||||
<PaneRoot active={key === contextProps.activeKey}>
|
||||
<RecursionField name={key} schema={schema} onlyRenderProperties />
|
||||
</PaneProvider>
|
||||
</PaneRoot>
|
||||
</AntdTabs.TabPane>
|
||||
);
|
||||
})}
|
||||
{designable && <AntdTabs.TabPane tab={render()} />}
|
||||
</AntdTabs>
|
||||
</DndContext>
|
||||
);
|
||||
|
@ -2,7 +2,7 @@ import { TabsProps } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
interface TabsContextProps extends TabsProps {
|
||||
deep?: boolean;
|
||||
PaneRoot?: React.FC<any>;
|
||||
}
|
||||
const TabsContext = React.createContext<TabsContextProps>({});
|
||||
|
||||
|
@ -3,12 +3,13 @@ interface InvokeFunction {
|
||||
(params: { action: 'moveTaskToBack' }, cb?: () => void): void;
|
||||
}
|
||||
|
||||
const JsBridge = (window as any).JsBridge as {
|
||||
invoke: InvokeFunction;
|
||||
};
|
||||
const getJsBridge = () =>
|
||||
(window as any).JsBridge as {
|
||||
invoke: InvokeFunction;
|
||||
};
|
||||
|
||||
export const invoke: InvokeFunction = (params, cb) => {
|
||||
JsBridge.invoke(params, cb);
|
||||
return getJsBridge().invoke(params, cb);
|
||||
};
|
||||
|
||||
export const isJSBridge = !!JsBridge;
|
||||
export const isJSBridge = () => !!getJsBridge();
|
||||
|
@ -6,6 +6,7 @@ import React from 'react';
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from '../../../../locale';
|
||||
import { useSchemaPatch } from '../../hooks';
|
||||
import { menuItemSchema } from './schema';
|
||||
|
||||
interface MMenuItemProps extends ListItemProps {
|
||||
name: string;
|
||||
@ -56,24 +57,7 @@ const MenuItemDesigner: React.FC = () => {
|
||||
<SchemaSettings.ModalItem
|
||||
title={t('Edit menu info')}
|
||||
initialValues={field.componentProps}
|
||||
schema={{
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
title: t('Menu name'),
|
||||
required: true,
|
||||
'x-component': 'Input',
|
||||
'x-decorator': 'FormItem',
|
||||
},
|
||||
icon: {
|
||||
required: true,
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'IconPicker',
|
||||
title: t('Icon'),
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
}}
|
||||
schema={menuItemSchema}
|
||||
onSubmit={onUpdateComponentProps}
|
||||
/>
|
||||
<SchemaSettings.Remove
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { generateNTemplate } from '../../../../locale';
|
||||
|
||||
export const menuItemSchema = {
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
title: `{{t('Menu name')}}`,
|
||||
title: generateNTemplate('Menu name'),
|
||||
required: true,
|
||||
'x-component': 'Input',
|
||||
'x-decorator': 'FormItem',
|
||||
@ -10,7 +12,7 @@ export const menuItemSchema = {
|
||||
icon: {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'IconPicker',
|
||||
title: `{{t('Icon')}}`,
|
||||
title: generateNTemplate('Icon'),
|
||||
'x-component-props': {},
|
||||
},
|
||||
},
|
||||
|
@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
|
||||
import { RecursionField, useFieldSchema } from '@formily/react';
|
||||
import { ActionBarProvider, SortableItem, TabsContextProvider, useDesigner } from '@nocobase/client';
|
||||
import { TabsProps } from 'antd';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { countGridCol } from '../../helpers';
|
||||
import { PageDesigner } from './Page.Designer';
|
||||
@ -28,90 +28,113 @@ const InternalPage: React.FC = (props) => {
|
||||
// Only support globalActions in page
|
||||
const onlyInPage = fieldSchema.root === fieldSchema.parent;
|
||||
let hasGlobalActions = false;
|
||||
if (!tabsSchema) {
|
||||
if (!tabsSchema && fieldSchema.properties) {
|
||||
hasGlobalActions = countGridCol(fieldSchema.properties['grid'], 2) === 1;
|
||||
} else if (searchParams.has('tab') && tabsSchema.properties?.[searchParams.get('tab')]) {
|
||||
} else if (searchParams.has('tab') && tabsSchema?.properties?.[searchParams.get('tab')]) {
|
||||
hasGlobalActions = countGridCol(tabsSchema.properties[searchParams.get('tab')]?.properties?.['grid'], 2) === 1;
|
||||
} else if (tabsSchema.properties) {
|
||||
} else if (tabsSchema?.properties) {
|
||||
const schema = Object.values(tabsSchema.properties).sort((t1, t2) => t1['x-index'] - t2['x-index'])[0];
|
||||
if (schema) {
|
||||
setTimeout(() => {
|
||||
setSearchParams([['tab', schema.name.toString()]]);
|
||||
setSearchParams([['tab', schema.name.toString()]], {
|
||||
replace: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const onTabsChange = useCallback<TabsProps['onChange']>(
|
||||
(key) => {
|
||||
setSearchParams([['tab', key]]);
|
||||
setSearchParams([['tab', key]], {
|
||||
replace: true,
|
||||
});
|
||||
},
|
||||
[setSearchParams],
|
||||
);
|
||||
|
||||
const GlobalActionProvider = useMemo(() => {
|
||||
if (hasGlobalActions) {
|
||||
return ActionBarProvider;
|
||||
}
|
||||
return (props) => <>{props.children}</>;
|
||||
}, [hasGlobalActions]);
|
||||
const GlobalActionProvider = useCallback(
|
||||
(props) => {
|
||||
if (hasGlobalActions) {
|
||||
return (
|
||||
<TabsContextProvider>
|
||||
<ActionBarProvider
|
||||
container={
|
||||
(typeof props.active !== 'undefined' ? props.active : true) && onlyInPage
|
||||
? document.getElementById('nb-position-container')
|
||||
: null
|
||||
}
|
||||
forceProps={{
|
||||
layout: 'one-column',
|
||||
className: globalActionCSS,
|
||||
}}
|
||||
>
|
||||
{props.children}
|
||||
</ActionBarProvider>
|
||||
</TabsContextProvider>
|
||||
);
|
||||
}
|
||||
return <>{props.children}</>;
|
||||
},
|
||||
[hasGlobalActions, onlyInPage],
|
||||
);
|
||||
|
||||
return (
|
||||
<GlobalActionProvider
|
||||
container={hasGlobalActions && onlyInPage ? document.getElementById('nb-position-container') : null}
|
||||
forceProps={{
|
||||
layout: 'one-column',
|
||||
className: globalActionCSS,
|
||||
}}
|
||||
<SortableItem
|
||||
eid="nb-mobile-scroll-wrapper"
|
||||
className={cx(
|
||||
'nb-mobile-page',
|
||||
css`
|
||||
background: #f0f2f5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-bottom: var(--nb-spacing);
|
||||
`,
|
||||
)}
|
||||
>
|
||||
<SortableItem
|
||||
eid="nb-mobile-scroll-wrapper"
|
||||
<Designer {...fieldSchema?.['x-designer-props']}></Designer>
|
||||
<div
|
||||
style={{
|
||||
paddingBottom: tabsSchema ? null : 'var(--nb-spacing)',
|
||||
}}
|
||||
className={cx(
|
||||
'nb-mobile-page',
|
||||
'nb-mobile-page-header',
|
||||
css`
|
||||
background: #f0f2f5;
|
||||
& > .ant-tabs > .ant-tabs-nav {
|
||||
.ant-tabs-tab {
|
||||
margin: 0 !important;
|
||||
padding: 0 16px !important;
|
||||
}
|
||||
background: #fff;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-bottom: var(--nb-spacing);
|
||||
`,
|
||||
)}
|
||||
>
|
||||
<Designer {...fieldSchema?.['x-designer-props']}></Designer>
|
||||
<div
|
||||
style={{
|
||||
paddingBottom: tabsSchema ? null : 'var(--nb-spacing)',
|
||||
<RecursionField
|
||||
schema={fieldSchema}
|
||||
filterProperties={(s) => {
|
||||
return 'MHeader' === s['x-component'];
|
||||
}}
|
||||
className={cx(
|
||||
'nb-mobile-page-header',
|
||||
css`
|
||||
& > .ant-tabs > .ant-tabs-nav {
|
||||
background: #fff;
|
||||
padding: 0 var(--nb-spacing);
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`,
|
||||
)}
|
||||
></RecursionField>
|
||||
<TabsContextProvider
|
||||
PaneRoot={GlobalActionProvider}
|
||||
activeKey={searchParams.get('tab')}
|
||||
onChange={onTabsChange}
|
||||
>
|
||||
<RecursionField
|
||||
schema={fieldSchema}
|
||||
filterProperties={(s) => {
|
||||
return 'MHeader' === s['x-component'];
|
||||
return 'Tabs' === s['x-component'];
|
||||
}}
|
||||
></RecursionField>
|
||||
<TabsContextProvider deep={false} activeKey={searchParams.get('tab')} onChange={onTabsChange}>
|
||||
<RecursionField
|
||||
schema={fieldSchema}
|
||||
filterProperties={(s) => {
|
||||
return 'Tabs' === s['x-component'];
|
||||
}}
|
||||
></RecursionField>
|
||||
</TabsContextProvider>
|
||||
</div>
|
||||
|
||||
</TabsContextProvider>
|
||||
</div>
|
||||
<GlobalActionProvider>
|
||||
{!tabsSchema && (
|
||||
<RecursionField
|
||||
schema={fieldSchema}
|
||||
@ -120,8 +143,8 @@ const InternalPage: React.FC = (props) => {
|
||||
}}
|
||||
></RecursionField>
|
||||
)}
|
||||
</SortableItem>
|
||||
</GlobalActionProvider>
|
||||
</GlobalActionProvider>
|
||||
</SortableItem>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -115,6 +115,7 @@ const MApplication: React.FC = (props) => {
|
||||
{props.children}
|
||||
</RemoteSchemaComponent>
|
||||
)}
|
||||
{/* Global action will insert here */}
|
||||
<div id="nb-position-container"></div>
|
||||
</div>
|
||||
</ActionContextProvider>
|
||||
|
@ -10,7 +10,7 @@ export const RouterSwitchProvider = (props) => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
useEffect(() => {
|
||||
if (isJSBridge) {
|
||||
if (isJSBridge()) {
|
||||
if (location.pathname.includes('/admin')) {
|
||||
navigate('/mobile');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user