pull/121/head
fantasticit 2022-07-06 09:28:00 +08:00
parent 4161d5fd2d
commit 1626e1764a
5 changed files with 75 additions and 61 deletions

View File

@ -0,0 +1,41 @@
import { Spin, Typography } from '@douyinfe/semi-ui';
import { Empty } from 'illustrations/empty';
import React, { useMemo } from 'react';
const { Text } = Typography;
export const defaultLoading = <Spin />;
export const defaultRenderError = (error) => {
return <Text>{(error && error.message) || '未知错误'}</Text>;
};
export const defaultEmpty = (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
}}
>
<div>
<Empty />
</div>
<Text type="tertiary"></Text>
</div>
);
export const Render: React.FC<{ fn: ((arg: unknown) => React.ReactNode) | React.ReactNode; args?: unknown[] }> = ({
fn,
args = [],
}) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
const content = useMemo(() => (typeof fn === 'function' ? fn.apply(null, ...args) : fn), [args]);
return <>{content}</>;
};

View File

@ -1,7 +1,6 @@
import { Spin, Typography } from '@douyinfe/semi-ui';
import { Empty } from 'illustrations/empty';
import React from 'react';
import { defaultEmpty, defaultLoading, defaultRenderError, Render } from './constant';
import { LoadingWrap } from './loading';
type RenderProps = React.ReactNode | (() => React.ReactNode);
@ -16,40 +15,6 @@ interface IProps {
normalContent: RenderProps;
}
const { Text } = Typography;
const defaultLoading = () => {
return <Spin />;
};
const defaultRenderError = (error) => {
return <Text>{(error && error.message) || '未知错误'}</Text>;
};
const defaultEmpty = () => {
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
position: 'relative',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
}}
>
<div>
<Empty />
</div>
<Text type="tertiary"></Text>
</div>
);
};
const runRender = (fn, ...args) => (typeof fn === 'function' ? fn(...args) : fn);
export const DataRender: React.FC<IProps> = ({
loading,
error,
@ -60,19 +25,14 @@ export const DataRender: React.FC<IProps> = ({
normalContent,
}) => {
if (error) {
return runRender(errorContent, error);
return <Render fn={errorContent} args={[error]} />;
}
if (empty) {
return runRender(emptyContent);
return <Render fn={emptyContent} />;
}
return (
<LoadingWrap
loading={loading}
runRender={runRender}
loadingContent={loadingContent}
normalContent={loading ? null : normalContent}
/>
<LoadingWrap loading={loading} loadingContent={loadingContent} normalContent={loading ? null : normalContent} />
);
};

View File

@ -1,15 +1,9 @@
import { useToggle } from 'hooks/use-toggle';
import React, { useEffect, useRef } from 'react';
// interface IProps {
// loading: boolean;
// delay?: number;
// runRender
// loadingContent: React.ReactElement;
// normalContent: React.ReactElement;
// }
import { Render } from './constant';
export const LoadingWrap = ({ loading, delay = 200, runRender, loadingContent, normalContent }) => {
export const LoadingWrap = ({ loading, delay = 200, loadingContent, normalContent }) => {
const timer = useRef<ReturnType<typeof setTimeout>>(null);
const [showLoading, toggleShowLoading] = useToggle(false);
@ -32,8 +26,8 @@ export const LoadingWrap = ({ loading, delay = 200, runRender, loadingContent, n
}, [delay, loading, toggleShowLoading]);
if (loading) {
return showLoading ? runRender(loadingContent) : null;
return showLoading ? <Render fn={loadingContent} /> : null;
}
return runRender(normalContent);
return <Render fn={normalContent} />;
};

View File

@ -122,13 +122,25 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
{isMobile && <div className={styles.mobileToolbar}>{actions}</div>}
</header>
<main className={styles.contentWrap}>
{docAuthError && (
<div style={{ margin: '10vh', textAlign: 'center' }}>
<SecureDocumentIllustration />
</div>
)}
{document && <Seo title={document.title} />}
<Editor user={user} documentId={documentId} authority={authority} />
<DataRender
loading={docAuthLoading}
error={docAuthError}
errorContent={() => {
return (
<div style={{ margin: '10vh', textAlign: 'center' }}>
<SecureDocumentIllustration />
</div>
);
}}
normalContent={() => {
return (
<>
{document && <Seo title={document.title} />}
{user && <Editor user={user} documentId={documentId} authority={authority} />}
</>
);
}}
/>
</main>
</div>
);

View File

@ -90,6 +90,8 @@ export class CollaborationService {
async onAuthenticate({ connection, token, requestParameters }: onAuthenticatePayload) {
const targetId = requestParameters.get('targetId');
const docType = requestParameters.get('docType');
const userId = requestParameters.get('userId');
const user = token ? await this.userService.decodeToken(token) : null;
switch (docType) {
@ -99,8 +101,13 @@ export class CollaborationService {
if (!document || document.status !== DocumentStatus.public) {
throw new HttpException('您无权查看此文档', HttpStatus.FORBIDDEN);
}
connection.readOnly = true;
return { user: { name: '匿名用户' } };
} else {
if (user.id !== userId) {
throw new HttpException('用户信息不匹配', HttpStatus.FORBIDDEN);
}
const authority = await this.documentService.getDocumentUserAuth(user.id, targetId);
if (!authority.readable) {