mirror of https://github.com/fantasticit/think.git
chore: ssr 初步完成
This commit is contained in:
parent
b3c7a375ce
commit
24a9d21b4f
|
@ -10,6 +10,9 @@ client:
|
||||||
seoKeywords: '云策文档,协作,文档,前端面试题,fantasticit,https://github.com/fantasticit/think'
|
seoKeywords: '云策文档,协作,文档,前端面试题,fantasticit,https://github.com/fantasticit/think'
|
||||||
# 预先连接的来源,空格分割(比如图片存储服务器)
|
# 预先连接的来源,空格分割(比如图片存储服务器)
|
||||||
dnsPrefetch: '//wipi.oss-cn-shanghai.aliyuncs.com'
|
dnsPrefetch: '//wipi.oss-cn-shanghai.aliyuncs.com'
|
||||||
|
# 站点地址(如:http://think.codingit.cn/),一定要设置,否则会出现 cookie、跨域等问题
|
||||||
|
siteUrl: 'http://localhost:5001'
|
||||||
|
siteDomain: ''
|
||||||
|
|
||||||
server:
|
server:
|
||||||
prefix: '/api'
|
prefix: '/api'
|
||||||
|
|
|
@ -89,7 +89,6 @@
|
||||||
"react-query": "^3.39.0",
|
"react-query": "^3.39.0",
|
||||||
"react-split-pane": "^0.1.92",
|
"react-split-pane": "^0.1.92",
|
||||||
"scroll-into-view-if-needed": "^2.2.29",
|
"scroll-into-view-if-needed": "^2.2.29",
|
||||||
"swr": "^1.2.0",
|
|
||||||
"timeago.js": "^4.0.2",
|
"timeago.js": "^4.0.2",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
"toggle-selection": "^1.0.6",
|
"toggle-selection": "^1.0.6",
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
} from '@douyinfe/semi-ui';
|
} from '@douyinfe/semi-ui';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { DocumentLinkCopyer } from 'components/document/link';
|
import { DocumentLinkCopyer } from 'components/document/link';
|
||||||
import { useCollaborationDocument } from 'data/document';
|
import { useDoumentMembers } from 'data/document';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { event, JOIN_USER } from 'event';
|
import { event, JOIN_USER } from 'event';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
|
@ -48,7 +48,7 @@ const renderChecked = (onChange, authKey: 'readable' | 'editable') => (checked,
|
||||||
export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId }) => {
|
export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId }) => {
|
||||||
const { user: currentUser } = useUser();
|
const { user: currentUser } = useUser();
|
||||||
const [visible, toggleVisible] = useToggle(false);
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
const { users, loading, error, addUser, updateUser, deleteUser } = useCollaborationDocument(documentId);
|
const { users, loading, error, addUser, updateUser, deleteUser } = useDoumentMembers(documentId);
|
||||||
const [inviteUser, setInviteUser] = useState('');
|
const [inviteUser, setInviteUser] = useState('');
|
||||||
const [collaborationUsers, setCollaborationUsers] = useState([]);
|
const [collaborationUsers, setCollaborationUsers] = useState([]);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { IAuthority, ILoginUser } from '@think/domains';
|
import { IAuthority, ILoginUser } from '@think/domains';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { useCollaborationDocument } from 'data/document';
|
import { useDoumentMembers } from 'data/document';
|
||||||
import { event, triggerChangeDocumentTitle, triggerJoinUser, USE_DOCUMENT_VERSION } from 'event';
|
import { event, triggerChangeDocumentTitle, triggerJoinUser, USE_DOCUMENT_VERSION } from 'event';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
|
@ -22,7 +22,7 @@ interface IProps {
|
||||||
export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, authority, className, style }) => {
|
export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, authority, className, style }) => {
|
||||||
const $hasShowUserSettingModal = useRef(false);
|
const $hasShowUserSettingModal = useRef(false);
|
||||||
const $editor = useRef<ICollaborationRefProps>();
|
const $editor = useRef<ICollaborationRefProps>();
|
||||||
const { users, addUser, updateUser } = useCollaborationDocument(documentId);
|
const { users, addUser, updateUser } = useDoumentMembers(documentId);
|
||||||
const [mentionUsersSettingVisible, toggleMentionUsersSettingVisible] = useToggle(false);
|
const [mentionUsersSettingVisible, toggleMentionUsersSettingVisible] = useToggle(false);
|
||||||
const [mentionUsers, setMentionUsers] = useState([]);
|
const [mentionUsers, setMentionUsers] = useState([]);
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,9 @@ import { LogoImage, LogoText } from 'components/logo';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { Theme } from 'components/theme';
|
import { Theme } from 'components/theme';
|
||||||
import { User } from 'components/user';
|
import { User } from 'components/user';
|
||||||
import { usePublicDocument } from 'data/document';
|
import { usePublicDocumentDetail } from 'data/document';
|
||||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||||
|
import { useMount } from 'hooks/use-mount';
|
||||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import React, { useCallback, useMemo, useRef } from 'react';
|
import React, { useCallback, useMemo, useRef } from 'react';
|
||||||
|
@ -40,7 +41,8 @@ interface IProps {
|
||||||
|
|
||||||
export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo = true }) => {
|
export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo = true }) => {
|
||||||
const $form = useRef<FormApi>();
|
const $form = useRef<FormApi>();
|
||||||
const { data, loading, error, query } = usePublicDocument(documentId);
|
const mounted = useMount()
|
||||||
|
const { data, loading, error, query } = usePublicDocumentDetail(documentId);
|
||||||
const { width, fontSize } = useDocumentStyle();
|
const { width, fontSize } = useDocumentStyle();
|
||||||
const { isMobile } = IsOnMobile.useHook();
|
const { isMobile } = IsOnMobile.useHook();
|
||||||
const editorWrapClassNames = useMemo(() => {
|
const editorWrapClassNames = useMemo(() => {
|
||||||
|
@ -148,14 +150,14 @@ export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo =
|
||||||
style={{ fontSize }}
|
style={{ fontSize }}
|
||||||
>
|
>
|
||||||
<Seo title={data.title} />
|
<Seo title={data.title} />
|
||||||
<CollaborationEditor
|
{mounted && <CollaborationEditor
|
||||||
menubar={false}
|
menubar={false}
|
||||||
editable={false}
|
editable={false}
|
||||||
user={null}
|
user={null}
|
||||||
id={documentId}
|
id={documentId}
|
||||||
type="document"
|
type="document"
|
||||||
renderInEditorPortal={renderAuthor}
|
renderInEditorPortal={renderAuthor}
|
||||||
/>
|
/>}
|
||||||
<ImageViewer containerSelector="#js-share-document-editor-container" />
|
<ImageViewer containerSelector="#js-share-document-editor-container" />
|
||||||
<BackTop
|
<BackTop
|
||||||
style={{ bottom: 65, right: isMobile ? 16 : 100 }}
|
style={{ bottom: 65, right: isMobile ? 16 : 100 }}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { IconStar } from '@douyinfe/semi-icons';
|
import { IconStar } from '@douyinfe/semi-icons';
|
||||||
import { Button, Tooltip } from '@douyinfe/semi-ui';
|
import { Button, Tooltip } from '@douyinfe/semi-ui';
|
||||||
import { useDocumentCollectToggle } from 'data/refactor/collector';
|
import { useDocumentCollectToggle } from 'data/collector';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
|
@ -6,9 +6,10 @@ import { DocumentStyle } from 'components/document/style';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { Theme } from 'components/theme';
|
import { Theme } from 'components/theme';
|
||||||
import { User } from 'components/user';
|
import { User } from 'components/user';
|
||||||
import { useTemplate } from 'data/refactor/template';
|
import { useTemplate } from 'data/template';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||||
|
import { useMount } from 'hooks/use-mount';
|
||||||
import { useWindowSize } from 'hooks/use-window-size';
|
import { useWindowSize } from 'hooks/use-window-size';
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
@ -24,6 +25,7 @@ const { Text } = Typography;
|
||||||
|
|
||||||
export const TemplateEditor: React.FC<IProps> = ({ templateId }) => {
|
export const TemplateEditor: React.FC<IProps> = ({ templateId }) => {
|
||||||
const { user } = useUser();
|
const { user } = useUser();
|
||||||
|
const mounted = useMount();
|
||||||
const { data, loading, error, updateTemplate, deleteTemplate } = useTemplate(templateId);
|
const { data, loading, error, updateTemplate, deleteTemplate } = useTemplate(templateId);
|
||||||
const { width: windowWidth } = useWindowSize();
|
const { width: windowWidth } = useWindowSize();
|
||||||
const [title, setTitle] = useState(data && data.title);
|
const [title, setTitle] = useState(data && data.title);
|
||||||
|
@ -81,7 +83,7 @@ export const TemplateEditor: React.FC<IProps> = ({ templateId }) => {
|
||||||
<Space>
|
<Space>
|
||||||
<DocumentStyle />
|
<DocumentStyle />
|
||||||
<Tooltip position="bottom" content={isPublic ? '公开模板' : '个人模板'}>
|
<Tooltip position="bottom" content={isPublic ? '公开模板' : '个人模板'}>
|
||||||
<Switch onChange={(v) => updateTemplate({ isPublic: v })}></Switch>
|
<Switch checked={isPublic} onChange={(v) => updateTemplate({ isPublic: v })}></Switch>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Popconfirm title="删除模板" content="模板删除后不可恢复,谨慎操作!" onConfirm={handleDelte}>
|
<Popconfirm title="删除模板" content="模板删除后不可恢复,谨慎操作!" onConfirm={handleDelte}>
|
||||||
<Button type="danger">删除</Button>
|
<Button type="danger">删除</Button>
|
||||||
|
@ -95,14 +97,16 @@ export const TemplateEditor: React.FC<IProps> = ({ templateId }) => {
|
||||||
<main className={styles.contentWrap}>
|
<main className={styles.contentWrap}>
|
||||||
<div className={styles.editorWrap}>
|
<div className={styles.editorWrap}>
|
||||||
<div className={cls(styles.contentWrap, editorWrapClassNames)} style={{ fontSize }}>
|
<div className={cls(styles.contentWrap, editorWrapClassNames)} style={{ fontSize }}>
|
||||||
<CollaborationEditor
|
{mounted && (
|
||||||
menubar
|
<CollaborationEditor
|
||||||
editable
|
menubar
|
||||||
user={user}
|
editable
|
||||||
id={data.id}
|
user={user}
|
||||||
type="template"
|
id={data.id}
|
||||||
onTitleUpdate={setTitle}
|
type="template"
|
||||||
/>
|
onTitleUpdate={setTitle}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Avatar, Skeleton, Space, Typography } from '@douyinfe/semi-ui';
|
||||||
import { IconDocument } from 'components/icons/IconDocument';
|
import { IconDocument } from 'components/icons/IconDocument';
|
||||||
import { LocaleTime } from 'components/locale-time';
|
import { LocaleTime } from 'components/locale-time';
|
||||||
import { WikiStar } from 'components/wiki/star';
|
import { WikiStar } from 'components/wiki/star';
|
||||||
import { IWikiWithIsMember } from 'data/refactor/collector';
|
import { IWikiWithIsMember } from 'data/collector';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Form, Modal } from '@douyinfe/semi-ui';
|
import { Form, Modal } from '@douyinfe/semi-ui';
|
||||||
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
||||||
import type { IWiki } from '@think/domains';
|
import type { IWiki } from '@think/domains';
|
||||||
import { ICreateWiki, useOwnWikis } from 'data/refactor/wiki';
|
import { ICreateWiki, useOwnWikis } from 'data/wiki';
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
import { Dispatch, SetStateAction, useRef } from 'react';
|
import { Dispatch, SetStateAction, useRef } from 'react';
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Button, Popconfirm, Table } from '@douyinfe/semi-ui';
|
||||||
import { getWikiUserRoleText } from '@think/domains';
|
import { getWikiUserRoleText } from '@think/domains';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { LocaleTime } from 'components/locale-time';
|
import { LocaleTime } from 'components/locale-time';
|
||||||
import { useWikiUsers } from 'data/wiki';
|
import { useWikiMembers } from 'data/wiki';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const Users: React.FC<IProps> = ({ wikiId }) => {
|
||||||
const [visible, toggleVisible] = useToggle(false);
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
const [editVisible, toggleEditVisible] = useToggle(false);
|
const [editVisible, toggleEditVisible] = useToggle(false);
|
||||||
const [currentUser, setCurrentUser] = useState(null);
|
const [currentUser, setCurrentUser] = useState(null);
|
||||||
const { data: users, loading, error, addUser, updateUser, deleteUser } = useWikiUsers(wikiId);
|
const { users, loading, error, addUser, updateUser, deleteUser } = useWikiMembers(wikiId);
|
||||||
|
|
||||||
const editUser = (user) => {
|
const editUser = (user) => {
|
||||||
setCurrentUser(user);
|
setCurrentUser(user);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { IconStar } from '@douyinfe/semi-icons';
|
import { IconStar } from '@douyinfe/semi-icons';
|
||||||
import { Button, Tooltip } from '@douyinfe/semi-ui';
|
import { Button, Tooltip } from '@douyinfe/semi-ui';
|
||||||
import { useWikiCollectToggle } from 'data/refactor/collector';
|
import { useWikiCollectToggle } from 'data/collector';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CollectorApiDefinition, CollectorApiTypeDefinition, CollectType, IDocument, IWiki } from '@think/domains';
|
import { CollectorApiDefinition, CollectType, IDocument, IWiki } from '@think/domains';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
|
@ -13,9 +13,7 @@ export const getCollectedWikis = (cookie = null): Promise<IWikiWithIsMember[]> =
|
||||||
return HttpClient.request({
|
return HttpClient.request({
|
||||||
method: CollectorApiDefinition.wikis.method,
|
method: CollectorApiDefinition.wikis.method,
|
||||||
url: CollectorApiDefinition.wikis.client(),
|
url: CollectorApiDefinition.wikis.client(),
|
||||||
headers: {
|
cookie,
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,9 +35,7 @@ export const getWikiIsCollected = (wikiId, cookie = null): Promise<boolean> => {
|
||||||
return HttpClient.request({
|
return HttpClient.request({
|
||||||
method: CollectorApiDefinition.check.method,
|
method: CollectorApiDefinition.check.method,
|
||||||
url: CollectorApiDefinition.check.client(),
|
url: CollectorApiDefinition.check.client(),
|
||||||
headers: {
|
cookie,
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
type: CollectType.wiki,
|
type: CollectType.wiki,
|
||||||
targetId: wikiId,
|
targetId: wikiId,
|
||||||
|
@ -56,9 +52,7 @@ export const toggleCollectWiki = (wikiId, cookie = null): Promise<boolean> => {
|
||||||
return HttpClient.request({
|
return HttpClient.request({
|
||||||
method: CollectorApiDefinition.toggle.method,
|
method: CollectorApiDefinition.toggle.method,
|
||||||
url: CollectorApiDefinition.toggle.client(),
|
url: CollectorApiDefinition.toggle.client(),
|
||||||
headers: {
|
cookie,
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
type: CollectType.wiki,
|
type: CollectType.wiki,
|
||||||
targetId: wikiId,
|
targetId: wikiId,
|
||||||
|
@ -92,9 +86,7 @@ export const getCollectedDocuments = (cookie = null): Promise<IDocument[]> => {
|
||||||
return HttpClient.request({
|
return HttpClient.request({
|
||||||
method: CollectorApiDefinition.documents.method,
|
method: CollectorApiDefinition.documents.method,
|
||||||
url: CollectorApiDefinition.documents.client(),
|
url: CollectorApiDefinition.documents.client(),
|
||||||
headers: {
|
cookie,
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -119,9 +111,7 @@ export const getDocumentIsCollected = (documentId, cookie = null): Promise<boole
|
||||||
return HttpClient.request({
|
return HttpClient.request({
|
||||||
method: CollectorApiDefinition.check.method,
|
method: CollectorApiDefinition.check.method,
|
||||||
url: CollectorApiDefinition.check.client(),
|
url: CollectorApiDefinition.check.client(),
|
||||||
headers: {
|
cookie,
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
type: CollectType.document,
|
type: CollectType.document,
|
||||||
targetId: documentId,
|
targetId: documentId,
|
||||||
|
@ -138,9 +128,7 @@ export const toggleCollectDocument = (documentId, cookie = null): Promise<boolea
|
||||||
return HttpClient.request({
|
return HttpClient.request({
|
||||||
method: CollectorApiDefinition.toggle.method,
|
method: CollectorApiDefinition.toggle.method,
|
||||||
url: CollectorApiDefinition.toggle.client(),
|
url: CollectorApiDefinition.toggle.client(),
|
||||||
headers: {
|
cookie,
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
type: CollectType.document,
|
type: CollectType.document,
|
||||||
targetId: documentId,
|
targetId: documentId,
|
|
@ -1,12 +1,29 @@
|
||||||
import type { IComment } from '@think/domains';
|
import { CommentApiDefinition, IComment } from '@think/domains';
|
||||||
import React, { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
import useSWR from 'swr';
|
|
||||||
|
|
||||||
export type CreateCommentDto = Pick<IComment, 'parentCommentId' | 'html' | 'replyUserId'>;
|
export type CreateCommentDto = Pick<IComment, 'parentCommentId' | 'html' | 'replyUserId'>;
|
||||||
|
|
||||||
export type UpdateCommentDto = Pick<IComment, 'id' | 'html'>;
|
export type UpdateCommentDto = Pick<IComment, 'id' | 'html'>;
|
||||||
|
|
||||||
|
export const getComments = (
|
||||||
|
documentId,
|
||||||
|
page = 1,
|
||||||
|
cookie = null
|
||||||
|
): Promise<{
|
||||||
|
data: Array<IComment>;
|
||||||
|
total: number;
|
||||||
|
}> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: CommentApiDefinition.documents.method,
|
||||||
|
url: CommentApiDefinition.documents.client(documentId),
|
||||||
|
cookie,
|
||||||
|
params: {
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文档评论
|
* 文档评论
|
||||||
* @param documentId
|
* @param documentId
|
||||||
|
@ -14,49 +31,61 @@ export type UpdateCommentDto = Pick<IComment, 'id' | 'html'>;
|
||||||
*/
|
*/
|
||||||
export const useComments = (documentId) => {
|
export const useComments = (documentId) => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const { data, error, mutate } = useSWR<{
|
const { data, error, isLoading, refetch } = useQuery(
|
||||||
data: Array<IComment>;
|
[CommentApiDefinition.documents.client(documentId), page],
|
||||||
total: number;
|
() => getComments(documentId, page),
|
||||||
}>(`/comment/document/${documentId}?page=${page}`, (url) => HttpClient.get(url));
|
{ keepPreviousData: true }
|
||||||
const loading = !data && !error;
|
);
|
||||||
|
|
||||||
const addComment = useCallback(
|
const addComment = useCallback(
|
||||||
async (data: CreateCommentDto) => {
|
async (data: CreateCommentDto) => {
|
||||||
const ret = await HttpClient.post(`/comment/add`, {
|
const ret = await HttpClient.request({
|
||||||
documentId,
|
method: CommentApiDefinition.add.method,
|
||||||
...data,
|
url: CommentApiDefinition.add.client(),
|
||||||
|
data: {
|
||||||
|
documentId,
|
||||||
|
...data,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
mutate();
|
refetch();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
[mutate, documentId]
|
[refetch, documentId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateComment = useCallback(
|
const updateComment = useCallback(
|
||||||
async (data: UpdateCommentDto) => {
|
async (data: UpdateCommentDto) => {
|
||||||
const ret = await HttpClient.post(`/comment/update`, {
|
const ret = await HttpClient.request({
|
||||||
documentId,
|
method: CommentApiDefinition.update.method,
|
||||||
...data,
|
url: CommentApiDefinition.update.client(),
|
||||||
|
data: {
|
||||||
|
documentId,
|
||||||
|
...data,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
mutate();
|
refetch();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
[mutate, documentId]
|
[refetch, documentId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteComment = useCallback(
|
const deleteComment = useCallback(
|
||||||
async (comment: IComment) => {
|
async (comment: IComment) => {
|
||||||
const ret = await HttpClient.post(`/comment/delete/${comment.id}`);
|
const ret = await HttpClient.request({
|
||||||
mutate();
|
method: CommentApiDefinition.delete.method,
|
||||||
|
url: CommentApiDefinition.delete.client(comment.id),
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
[mutate]
|
[refetch]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
loading,
|
loading: isLoading,
|
||||||
error,
|
error,
|
||||||
|
page,
|
||||||
setPage,
|
setPage,
|
||||||
addComment,
|
addComment,
|
||||||
updateComment,
|
updateComment,
|
||||||
|
|
|
@ -1,252 +0,0 @@
|
||||||
import type { IAuthority, IDocument, IUser, IWiki } from '@think/domains';
|
|
||||||
import { useAsyncLoading } from 'hooks/use-async-loading';
|
|
||||||
import { string } from 'lib0';
|
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
|
||||||
import { getPublicDocumentDetail } from 'services/document';
|
|
||||||
import { HttpClient } from 'services/http-client';
|
|
||||||
import useSWR from 'swr';
|
|
||||||
|
|
||||||
type ICreateDocument = Partial<Pick<IDocument, 'wikiId' | 'parentDocumentId'>>;
|
|
||||||
type IDocumentWithAuth = { document: IDocument; authority: IAuthority };
|
|
||||||
type IUpdateDocument = Partial<Pick<IDocument, 'title' | 'content'>>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建文档
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useCreateDocument = () => {
|
|
||||||
const [create, loading] = useAsyncLoading((data: ICreateDocument): Promise<IDocument> => {
|
|
||||||
return HttpClient.post('/document/create', data);
|
|
||||||
});
|
|
||||||
return { create, loading };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新文档阅读量
|
|
||||||
* @param id
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const updateDocumentViews = (id: string) => {
|
|
||||||
return HttpClient.get('/document/views/' + id);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除文档
|
|
||||||
* @param id
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useDeleteDocument = (id) => {
|
|
||||||
const [deleteDocument, loading] = useAsyncLoading((): Promise<IDocument> => {
|
|
||||||
return HttpClient.delete('/document/delete/' + id);
|
|
||||||
});
|
|
||||||
return { deleteDocument, loading };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文档详情
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useDocumentDetail = (documentId, options = null) => {
|
|
||||||
const { data, error, mutate } = useSWR<IDocumentWithAuth>(
|
|
||||||
`/document/detail/${documentId}`,
|
|
||||||
(url) => HttpClient.get(url),
|
|
||||||
options
|
|
||||||
);
|
|
||||||
const loading = !data && !error;
|
|
||||||
const update = useCallback(
|
|
||||||
async (data: IUpdateDocument) => {
|
|
||||||
const res = await HttpClient.post('/document/update/' + documentId, data);
|
|
||||||
mutate();
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
[mutate, documentId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const toggleStatus = useCallback(
|
|
||||||
async (data: Partial<Pick<IDocument, 'sharePassword'>>) => {
|
|
||||||
const ret = await HttpClient.post('/document/share/' + documentId, data);
|
|
||||||
mutate();
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
[mutate, documentId]
|
|
||||||
);
|
|
||||||
|
|
||||||
return { data, loading, error, update, toggleStatus };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文档历史版本
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useDocumentVersion = (documentId) => {
|
|
||||||
const { data, error, mutate } = useSWR<Array<{ version: string; data: string }>>(
|
|
||||||
`/document/version/${documentId}`,
|
|
||||||
(url) => HttpClient.get(url),
|
|
||||||
{ errorRetryCount: 0 }
|
|
||||||
);
|
|
||||||
const loading = !data && !error;
|
|
||||||
return { data: data || [], loading, error, refresh: mutate };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识库最近更新的10条文档
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useRecentDocuments = () => {
|
|
||||||
const { data, error, mutate } = useSWR<Array<IDocument & { visitedAt: string }>>('/document/recent', (url) =>
|
|
||||||
HttpClient.get(url)
|
|
||||||
);
|
|
||||||
const loading = !data && !error;
|
|
||||||
return { data, error, loading, refresh: mutate };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 收藏文档
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useDocumentStar = (documentId) => {
|
|
||||||
const { data, error, mutate } = useSWR<boolean>(`/collector/check/${documentId}`, () =>
|
|
||||||
HttpClient.post(`/collector/check`, {
|
|
||||||
type: 'document',
|
|
||||||
targetId: documentId,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const toggleStar = useCallback(async () => {
|
|
||||||
await HttpClient.post('/collector/toggle/', {
|
|
||||||
type: 'document',
|
|
||||||
targetId: documentId,
|
|
||||||
});
|
|
||||||
mutate();
|
|
||||||
}, [mutate, documentId]);
|
|
||||||
|
|
||||||
return { data, error, toggleStar };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户收藏的文档
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useStaredDocuments = () => {
|
|
||||||
const { data, error, mutate } = useSWR<IDocument[]>('/collector/documents', (url) => HttpClient.post(url));
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
return { data, error, loading, refresh: mutate };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取公开文档
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const usePublicDocument = (documentId: string) => {
|
|
||||||
const [fetch] = useAsyncLoading(getPublicDocumentDetail);
|
|
||||||
const [document, setDocument] = useState<(IDocument & { createUse: IUser; wiki: IWiki }) | null>(null);
|
|
||||||
const [error, setError] = useState<(Error & { statusCode?: number }) | null>(null);
|
|
||||||
const loading = !document && !error;
|
|
||||||
|
|
||||||
const queryData = useCallback(
|
|
||||||
(sharePassword = '') => {
|
|
||||||
fetch(documentId, { sharePassword })
|
|
||||||
.then((doc) => {
|
|
||||||
setDocument(doc);
|
|
||||||
setError(null);
|
|
||||||
})
|
|
||||||
.catch(setError);
|
|
||||||
},
|
|
||||||
[fetch, documentId]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
queryData();
|
|
||||||
}, [documentId, queryData]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: document,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
query: queryData,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type DocAuth = {
|
|
||||||
userName: string;
|
|
||||||
readable?: boolean;
|
|
||||||
editable?: boolean;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* 协作文档
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useCollaborationDocument = (documentId) => {
|
|
||||||
const { data, error, mutate } = useSWR<Array<{ user: IUser; auth: IAuthority }>>(
|
|
||||||
`/document/user/${documentId}`,
|
|
||||||
(url) => HttpClient.get(url),
|
|
||||||
{ shouldRetryOnError: false }
|
|
||||||
);
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
const addUser = useCallback(
|
|
||||||
async (userName) => {
|
|
||||||
const ret = await HttpClient.post(`/document/user/${documentId}/add`, {
|
|
||||||
documentId,
|
|
||||||
userName,
|
|
||||||
readable: true,
|
|
||||||
editable: false,
|
|
||||||
});
|
|
||||||
mutate();
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
[mutate, documentId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const updateUser = useCallback(
|
|
||||||
async (docAuth: DocAuth) => {
|
|
||||||
const ret = await HttpClient.post(`/document/user/${documentId}/update`, {
|
|
||||||
documentId,
|
|
||||||
...docAuth,
|
|
||||||
});
|
|
||||||
mutate();
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
[mutate, documentId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const deleteUser = useCallback(
|
|
||||||
async (docAuth: DocAuth) => {
|
|
||||||
const ret = await HttpClient.post(`/document/user/${documentId}/delete`, {
|
|
||||||
documentId,
|
|
||||||
...docAuth,
|
|
||||||
});
|
|
||||||
mutate();
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
[mutate, documentId]
|
|
||||||
);
|
|
||||||
|
|
||||||
return { users: data, loading, error, addUser, updateUser, deleteUser };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取子文档
|
|
||||||
* @param documentId
|
|
||||||
* @param isShare 访问路径
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useChildrenDocument = ({ wikiId, documentId, isShare = false }) => {
|
|
||||||
const { data, error, mutate } = useSWR<Array<IDocument>>(
|
|
||||||
wikiId + '/' + documentId,
|
|
||||||
wikiId || documentId
|
|
||||||
? () =>
|
|
||||||
HttpClient.post(isShare ? '/document/public/children' : `/document/children`, { wikiId, documentId, isShare })
|
|
||||||
: null,
|
|
||||||
{ shouldRetryOnError: false }
|
|
||||||
);
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
return { data, loading, error, refresh: mutate };
|
|
||||||
};
|
|
|
@ -0,0 +1,305 @@
|
||||||
|
import { DocumentApiDefinition, IAuthority, IDocument, IUser, IWiki } from '@think/domains';
|
||||||
|
import { useAsyncLoading } from 'hooks/use-async-loading';
|
||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { HttpClient } from 'services/http-client';
|
||||||
|
|
||||||
|
type IDocumentWithVisitedAt = IDocument & { visitedAt: string };
|
||||||
|
type ICreateDocument = Partial<Pick<IDocument, 'wikiId' | 'parentDocumentId'>>;
|
||||||
|
type IDocumentWithAuth = { document: IDocument; authority: IAuthority };
|
||||||
|
type IUpdateDocument = Partial<Pick<IDocument, 'title' | 'content'>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户最近访问的文档
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getRecentVisitedDocuments = (cookie = null): Promise<IDocumentWithVisitedAt[]> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.recent.method,
|
||||||
|
url: DocumentApiDefinition.recent.client(),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户最近访问的文档
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useRecentDocuments = () => {
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(
|
||||||
|
DocumentApiDefinition.recent.client(),
|
||||||
|
getRecentVisitedDocuments
|
||||||
|
);
|
||||||
|
return { data, error, loading: isLoading, refresh: refetch };
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DocAuth = {
|
||||||
|
userName: string;
|
||||||
|
readable?: boolean;
|
||||||
|
editable?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档成员
|
||||||
|
* @param cookie
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getDocumentMembers = (documentId, cookie = null): Promise<Array<{ user: IUser; auth: IAuthority }>> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.getMemberById.method,
|
||||||
|
url: DocumentApiDefinition.getMemberById.client(documentId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文档成员管理
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useDoumentMembers = (documentId) => {
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(DocumentApiDefinition.getMemberById.client(documentId), () =>
|
||||||
|
getDocumentMembers(documentId)
|
||||||
|
);
|
||||||
|
|
||||||
|
const addUser = useCallback(
|
||||||
|
async (userName) => {
|
||||||
|
const ret = await HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.addMemberById.method,
|
||||||
|
url: DocumentApiDefinition.addMemberById.client(documentId),
|
||||||
|
data: {
|
||||||
|
documentId,
|
||||||
|
userName,
|
||||||
|
readable: true,
|
||||||
|
editable: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
[refetch, documentId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateUser = useCallback(
|
||||||
|
async (docAuth: DocAuth) => {
|
||||||
|
const ret = await HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.updateMemberById.method,
|
||||||
|
url: DocumentApiDefinition.updateMemberById.client(documentId),
|
||||||
|
data: {
|
||||||
|
documentId,
|
||||||
|
...docAuth,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
[refetch, documentId]
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteUser = useCallback(
|
||||||
|
async (docAuth: DocAuth) => {
|
||||||
|
const ret = await HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.deleteMemberById.method,
|
||||||
|
url: DocumentApiDefinition.deleteMemberById.client(documentId),
|
||||||
|
data: {
|
||||||
|
documentId,
|
||||||
|
...docAuth,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
[refetch, documentId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { users: data, loading: isLoading, error, addUser, updateUser, deleteUser };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档详情
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getDocumentDetail = (documentId, cookie = null): Promise<IDocumentWithAuth> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.getDetailById.method,
|
||||||
|
url: DocumentApiDefinition.getDetailById.client(documentId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档详情
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useDocumentDetail = (documentId) => {
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(DocumentApiDefinition.getDetailById.client(documentId), (url) =>
|
||||||
|
getDocumentDetail(documentId)
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新文档
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const update = useCallback(
|
||||||
|
async (data: IUpdateDocument) => {
|
||||||
|
const res = await HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.updateById.method,
|
||||||
|
url: DocumentApiDefinition.updateById.client(documentId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
[refetch, documentId]
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公开或私有文档
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const toggleStatus = useCallback(
|
||||||
|
async (data) => {
|
||||||
|
const res = await HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.shareById.method,
|
||||||
|
url: DocumentApiDefinition.shareById.client(documentId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
[refetch, documentId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { data, loading: isLoading, error, update, toggleStatus };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档版本
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getDocumentVersion = (documentId, cookie = null): Promise<Array<{ version: string; data: string }>> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.getVersionById.method,
|
||||||
|
url: DocumentApiDefinition.getVersionById.client(documentId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档历史版本
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useDocumentVersion = (documentId) => {
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(DocumentApiDefinition.getVersionById.client(documentId), () =>
|
||||||
|
getDocumentVersion(documentId)
|
||||||
|
);
|
||||||
|
return { data: data || [], loading: isLoading, error, refresh: refetch };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文档
|
||||||
|
* @param id
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useDeleteDocument = (documentId) => {
|
||||||
|
const [deleteDocument, loading] = useAsyncLoading((): Promise<IDocument> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.deleteById.method,
|
||||||
|
url: DocumentApiDefinition.deleteById.client(documentId),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return { deleteDocument, loading };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建文档
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useCreateDocument = () => {
|
||||||
|
const [create, loading] = useAsyncLoading((data: ICreateDocument): Promise<IDocument> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.create.method,
|
||||||
|
url: DocumentApiDefinition.create.client(),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return { create, loading };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开文档详情
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getPublicDocumentDetail = (
|
||||||
|
documentId,
|
||||||
|
data,
|
||||||
|
cookie = null
|
||||||
|
): Promise<IDocument & { createUse: IUser; wiki: IWiki }> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: DocumentApiDefinition.getPublicDetailById.method,
|
||||||
|
url: DocumentApiDefinition.getPublicDetailById.client(documentId),
|
||||||
|
cookie,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开文档详情
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const usePublicDocumentDetail = (documentId) => {
|
||||||
|
const [sharePassword, setSharePassword] = useState();
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(
|
||||||
|
DocumentApiDefinition.getPublicDetailById.client(documentId),
|
||||||
|
() => getPublicDocumentDetail(documentId, { sharePassword }),
|
||||||
|
{ retry: 0, refetchOnWindowFocus: true, refetchOnReconnect: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const query = useCallback(
|
||||||
|
(password) => {
|
||||||
|
setSharePassword(password);
|
||||||
|
refetch();
|
||||||
|
},
|
||||||
|
[refetch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
loading: isLoading,
|
||||||
|
error,
|
||||||
|
query,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDocumentChildren = (data, cookie = null): Promise<Array<IDocument>> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: data.isShare ? DocumentApiDefinition.getPublicChildren.method : DocumentApiDefinition.getChildren.method,
|
||||||
|
url: data.isShare ? DocumentApiDefinition.getPublicChildren.client() : DocumentApiDefinition.getChildren.client(),
|
||||||
|
cookie,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取子文档
|
||||||
|
* @param documentId
|
||||||
|
* @param isShare 访问路径
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useChildrenDocument = ({ wikiId, documentId, isShare = false }) => {
|
||||||
|
const { data, error, refetch } = useQuery(
|
||||||
|
isShare ? DocumentApiDefinition.getPublicChildren.client() : DocumentApiDefinition.getChildren.client(),
|
||||||
|
() => getDocumentChildren({ wikiId, documentId, isShare })
|
||||||
|
);
|
||||||
|
const loading = !data && !error;
|
||||||
|
|
||||||
|
return { data, loading, error, refresh: refetch };
|
||||||
|
};
|
|
@ -1,83 +1,87 @@
|
||||||
import type { IMessage } from '@think/domains';
|
import { IMessage, MessageApiDefinition } from '@think/domains';
|
||||||
import React, { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
import useSWR from 'swr';
|
|
||||||
|
|
||||||
/**
|
const getMessagesApi =
|
||||||
* 所有消息
|
(apiKey) =>
|
||||||
* @returns
|
(
|
||||||
*/
|
page = 1,
|
||||||
|
cookie = null
|
||||||
|
): Promise<{
|
||||||
|
data: Array<IMessage>;
|
||||||
|
total: number;
|
||||||
|
}> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: MessageApiDefinition[apiKey].method,
|
||||||
|
url: MessageApiDefinition[apiKey].client(),
|
||||||
|
cookie,
|
||||||
|
params: {
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useAllMessages = () => {
|
export const useAllMessages = () => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const { data, error, mutate } = useSWR<{
|
const { data, error, isLoading } = useQuery(
|
||||||
data: Array<IMessage>;
|
[MessageApiDefinition.getAll.client(), page],
|
||||||
total: number;
|
() => getMessagesApi('getAll')(page),
|
||||||
}>(`/message/all?page=${page}`, (url) => HttpClient.get(url), {
|
{ keepPreviousData: true }
|
||||||
refreshInterval: 200,
|
|
||||||
});
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
page,
|
|
||||||
setPage,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 所有已读消息
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useReadMessages = () => {
|
|
||||||
const [page, setPage] = useState(1);
|
|
||||||
const { data, error, mutate } = useSWR<{
|
|
||||||
data: Array<IMessage>;
|
|
||||||
total: number;
|
|
||||||
}>(`/message/read?page=${page}`, (url) => HttpClient.get(url), {
|
|
||||||
refreshInterval: 200,
|
|
||||||
});
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
page,
|
|
||||||
setPage,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 所有未读消息
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useUnreadMessages = () => {
|
|
||||||
const [page, setPage] = useState(1);
|
|
||||||
const { data, error, mutate } = useSWR<{
|
|
||||||
data: Array<IMessage>;
|
|
||||||
total: number;
|
|
||||||
}>(`/message/unread?page=${page}`, (url) => HttpClient.get(url), {
|
|
||||||
refreshInterval: 200,
|
|
||||||
});
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
const readMessage = useCallback(
|
|
||||||
async (messageId) => {
|
|
||||||
const ret = await HttpClient.post(`/message/read/${messageId}`);
|
|
||||||
mutate();
|
|
||||||
return ret;
|
|
||||||
},
|
|
||||||
[mutate]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
loading,
|
loading: isLoading,
|
||||||
error,
|
error,
|
||||||
page,
|
page,
|
||||||
setPage,
|
setPage,
|
||||||
readMessage,
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useReadMessages = () => {
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const { data, error, isLoading } = useQuery(
|
||||||
|
[MessageApiDefinition.getRead.client(), page],
|
||||||
|
() => getMessagesApi('getRead')(page),
|
||||||
|
{ keepPreviousData: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
loading: isLoading,
|
||||||
|
error,
|
||||||
|
page,
|
||||||
|
setPage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUnreadMessages = () => {
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(
|
||||||
|
[MessageApiDefinition.getUnread.client(), page],
|
||||||
|
() => getMessagesApi('getUnread')(page),
|
||||||
|
{ keepPreviousData: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const readMessage = useCallback(
|
||||||
|
async (messageId) => {
|
||||||
|
const ret = await HttpClient.request({
|
||||||
|
method: MessageApiDefinition.readMessage.method,
|
||||||
|
url: MessageApiDefinition.readMessage.client(messageId),
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return ret;
|
||||||
|
},
|
||||||
|
[refetch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
loading: isLoading,
|
||||||
|
error,
|
||||||
|
readMessage,
|
||||||
|
page,
|
||||||
|
setPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import {
|
|
||||||
CollectorApiDefinition,
|
|
||||||
CollectorApiTypeDefinition,
|
|
||||||
CollectType,
|
|
||||||
DocumentApiDefinition,
|
|
||||||
IDocument,
|
|
||||||
IWiki,
|
|
||||||
WikiApiDefinition,
|
|
||||||
} from '@think/domains';
|
|
||||||
import { useCallback } from 'react';
|
|
||||||
import { useQuery } from 'react-query';
|
|
||||||
import { HttpClient } from 'services/http-client';
|
|
||||||
|
|
||||||
type IDocumentWithVisitedAt = IDocument & { visitedAt: string };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户最近访问的文档
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getRecentVisitedDocuments = (cookie = null): Promise<IDocumentWithVisitedAt[]> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: DocumentApiDefinition.recent.method,
|
|
||||||
url: DocumentApiDefinition.recent.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户最近访问的文档
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useRecentDocuments = () => {
|
|
||||||
const { data, error, isLoading, refetch } = useQuery(
|
|
||||||
DocumentApiDefinition.recent.client(),
|
|
||||||
getRecentVisitedDocuments
|
|
||||||
);
|
|
||||||
return { data, error, loading: isLoading, refresh: refetch };
|
|
||||||
};
|
|
|
@ -1,146 +0,0 @@
|
||||||
import { ITemplate, TemplateApiDefinition } from '@think/domains';
|
|
||||||
import { useCallback, useState } from 'react';
|
|
||||||
import { useQuery } from 'react-query';
|
|
||||||
import { HttpClient } from 'services/http-client';
|
|
||||||
|
|
||||||
export const getPublicTemplates = (
|
|
||||||
page = 1,
|
|
||||||
cookie = null
|
|
||||||
): Promise<{
|
|
||||||
data: Array<ITemplate>;
|
|
||||||
total: number;
|
|
||||||
}> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: TemplateApiDefinition.public.method,
|
|
||||||
url: TemplateApiDefinition.public.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
page,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const usePublicTemplates = () => {
|
|
||||||
const [page, setPage] = useState(1);
|
|
||||||
const { data, error, isLoading } = useQuery(`${TemplateApiDefinition.public.client()}?page=${page}`, () =>
|
|
||||||
getPublicTemplates(page)
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading: isLoading,
|
|
||||||
error,
|
|
||||||
setPage,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getOwnTemplates = (
|
|
||||||
page = 1,
|
|
||||||
cookie = null
|
|
||||||
): Promise<{
|
|
||||||
data: Array<ITemplate>;
|
|
||||||
total: number;
|
|
||||||
}> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: TemplateApiDefinition.own.method,
|
|
||||||
url: TemplateApiDefinition.own.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
page,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 个人模板
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useOwnTemplates = () => {
|
|
||||||
const [page, setPage] = useState(1);
|
|
||||||
const {
|
|
||||||
data,
|
|
||||||
error,
|
|
||||||
isLoading,
|
|
||||||
refetch: mutate,
|
|
||||||
} = useQuery(`${TemplateApiDefinition.own.client()}?page=${page}`, () => getOwnTemplates(page));
|
|
||||||
|
|
||||||
const addTemplate = useCallback(
|
|
||||||
async (data): Promise<ITemplate> => {
|
|
||||||
const ret = await HttpClient.post(TemplateApiDefinition.add.client(), data);
|
|
||||||
mutate();
|
|
||||||
return ret as unknown as ITemplate;
|
|
||||||
},
|
|
||||||
[mutate]
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading: isLoading,
|
|
||||||
error,
|
|
||||||
setPage,
|
|
||||||
addTemplate,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取模板详情
|
|
||||||
* @param templateId
|
|
||||||
* @param cookie
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getTemplateDetail = (templateId, cookie = null): Promise<ITemplate> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: TemplateApiDefinition.getDetailById.method,
|
|
||||||
url: TemplateApiDefinition.getDetailById.client(templateId),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取模板详情
|
|
||||||
* @param templateId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useTemplate = (templateId) => {
|
|
||||||
const { data, error, refetch } = useQuery(TemplateApiDefinition.getDetailById.client(templateId), () =>
|
|
||||||
getTemplateDetail(templateId)
|
|
||||||
);
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
const updateTemplate = useCallback(
|
|
||||||
async (data): Promise<ITemplate> => {
|
|
||||||
const ret = await HttpClient.request({
|
|
||||||
method: TemplateApiDefinition.updateById.method,
|
|
||||||
url: TemplateApiDefinition.updateById.client(templateId),
|
|
||||||
data: {
|
|
||||||
id: templateId,
|
|
||||||
...data,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
return ret as unknown as ITemplate;
|
|
||||||
},
|
|
||||||
[refetch, templateId]
|
|
||||||
);
|
|
||||||
|
|
||||||
const deleteTemplate = useCallback(async () => {
|
|
||||||
await HttpClient.request({
|
|
||||||
method: TemplateApiDefinition.deleteById.method,
|
|
||||||
url: TemplateApiDefinition.deleteById.client(templateId),
|
|
||||||
});
|
|
||||||
}, [templateId]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
updateTemplate,
|
|
||||||
deleteTemplate,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,170 +0,0 @@
|
||||||
import {
|
|
||||||
CollectorApiDefinition,
|
|
||||||
CollectorApiTypeDefinition,
|
|
||||||
CollectType,
|
|
||||||
IUser,
|
|
||||||
IWiki,
|
|
||||||
IWikiUser,
|
|
||||||
WikiApiDefinition,
|
|
||||||
} from '@think/domains';
|
|
||||||
import { useCallback, useState } from 'react';
|
|
||||||
import { useQuery } from 'react-query';
|
|
||||||
import { HttpClient } from 'services/http-client';
|
|
||||||
|
|
||||||
export type ICreateWiki = Pick<IWiki, 'name' | 'description'>;
|
|
||||||
export type IUpdateWiki = Partial<IWiki>;
|
|
||||||
export type IWikiUserOpeateData = {
|
|
||||||
userName: Pick<IUser, 'name'>;
|
|
||||||
userRole: Pick<IWikiUser, 'userRole'>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户所有知识库
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getAllWikis = (cookie = null): Promise<{ data: IWiki[]; total: number }> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: WikiApiDefinition.getAllWikis.method,
|
|
||||||
url: WikiApiDefinition.getAllWikis.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户所有知识库
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useAllWikis = () => {
|
|
||||||
const { data, error, isLoading } = useQuery(WikiApiDefinition.getAllWikis.client(), getAllWikis);
|
|
||||||
const list = (data && data.data) || [];
|
|
||||||
const total = (data && data.total) || 0;
|
|
||||||
return { data: list, total, error, loading: isLoading };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户参与的知识库
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getJoinWikis = (cookie = null): Promise<{ data: IWiki[]; total: number }> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: WikiApiDefinition.getJoinWikis.method,
|
|
||||||
url: WikiApiDefinition.getJoinWikis.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户参与的知识库
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useJoinWikis = () => {
|
|
||||||
const { data, error, isLoading } = useQuery(WikiApiDefinition.getJoinWikis.client(), getJoinWikis);
|
|
||||||
const list = (data && data.data) || [];
|
|
||||||
const total = (data && data.total) || 0;
|
|
||||||
|
|
||||||
return { data: list, total, error, loading: isLoading };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户创建的知识库
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getOwnWikis = (cookie = null): Promise<{ data: IWiki[]; total: number }> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: WikiApiDefinition.getOwnWikis.method,
|
|
||||||
url: WikiApiDefinition.getOwnWikis.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户创建的知识库
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useOwnWikis = () => {
|
|
||||||
const { data, error, refetch } = useQuery(WikiApiDefinition.getOwnWikis.client(), getOwnWikis);
|
|
||||||
|
|
||||||
const createWiki = useCallback(
|
|
||||||
async (data: ICreateWiki) => {
|
|
||||||
const res = await HttpClient.request({
|
|
||||||
method: WikiApiDefinition.add.method,
|
|
||||||
url: WikiApiDefinition.add.client(),
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
[refetch]
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除文档
|
|
||||||
* @param id
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const deletWiki = useCallback(
|
|
||||||
async (id) => {
|
|
||||||
const res = await HttpClient.request({
|
|
||||||
method: WikiApiDefinition.deleteById.method,
|
|
||||||
url: WikiApiDefinition.deleteById.client(id),
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
[refetch]
|
|
||||||
);
|
|
||||||
|
|
||||||
const loading = !data && !error;
|
|
||||||
const list = (data && data.data) || [];
|
|
||||||
const total = (data && data.total) || 0;
|
|
||||||
|
|
||||||
return { data: list, total, error, loading, createWiki, deletWiki };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有公开文档
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const getAllPublicWikis = (
|
|
||||||
page = 1,
|
|
||||||
cookie = null
|
|
||||||
): Promise<{
|
|
||||||
data: Array<IWiki>;
|
|
||||||
total: number;
|
|
||||||
}> => {
|
|
||||||
return HttpClient.request({
|
|
||||||
method: WikiApiDefinition.getPublicWikis.method,
|
|
||||||
url: WikiApiDefinition.getPublicWikis.client(),
|
|
||||||
headers: {
|
|
||||||
cookie,
|
|
||||||
},
|
|
||||||
params: {
|
|
||||||
page,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* 获取所有公开文档
|
|
||||||
* @param documentId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useAllPublicWikis = () => {
|
|
||||||
const [page, setPage] = useState(1);
|
|
||||||
const { data, error, isLoading } = useQuery(`${WikiApiDefinition.getPublicWikis.client()}?page=${page}`, () =>
|
|
||||||
getAllPublicWikis(page)
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
loading: isLoading,
|
|
||||||
error,
|
|
||||||
setPage,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,39 +1,72 @@
|
||||||
import type { ITemplate } from '@think/domains';
|
import { ITemplate, TemplateApiDefinition } from '@think/domains';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
import useSWR from 'swr';
|
|
||||||
|
export const getPublicTemplates = (
|
||||||
|
page = 1,
|
||||||
|
cookie = null
|
||||||
|
): Promise<{
|
||||||
|
data: Array<ITemplate>;
|
||||||
|
total: number;
|
||||||
|
}> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: TemplateApiDefinition.public.method,
|
||||||
|
url: TemplateApiDefinition.public.client(),
|
||||||
|
cookie,
|
||||||
|
params: {
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const usePublicTemplates = () => {
|
export const usePublicTemplates = () => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const { data, error, mutate } = useSWR<{
|
const { data, error, isLoading } = useQuery(`${TemplateApiDefinition.public.client()}?page=${page}`, () =>
|
||||||
data: Array<ITemplate>;
|
getPublicTemplates(page)
|
||||||
total: number;
|
);
|
||||||
}>(`/template/public?page=${page}`, (url) => HttpClient.get(url));
|
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
loading,
|
loading: isLoading,
|
||||||
error,
|
error,
|
||||||
setPage,
|
setPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getOwnTemplates = (
|
||||||
|
page = 1,
|
||||||
|
cookie = null
|
||||||
|
): Promise<{
|
||||||
|
data: Array<ITemplate>;
|
||||||
|
total: number;
|
||||||
|
}> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: TemplateApiDefinition.own.method,
|
||||||
|
url: TemplateApiDefinition.own.client(),
|
||||||
|
cookie,
|
||||||
|
params: {
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 个人模板
|
* 个人模板
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useOwnTemplates = () => {
|
export const useOwnTemplates = () => {
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const { data, error, mutate } = useSWR<{
|
const {
|
||||||
data: Array<ITemplate>;
|
data,
|
||||||
total: number;
|
error,
|
||||||
}>(`/template/own?page=${page}`, (url) => HttpClient.get(url));
|
isLoading,
|
||||||
const loading = !data && !error;
|
refetch: mutate,
|
||||||
|
} = useQuery(`${TemplateApiDefinition.own.client()}?page=${page}`, () => getOwnTemplates(page));
|
||||||
|
|
||||||
const addTemplate = useCallback(
|
const addTemplate = useCallback(
|
||||||
async (data): Promise<ITemplate> => {
|
async (data): Promise<ITemplate> => {
|
||||||
const ret = await HttpClient.post(`/template/add`, data);
|
const ret = await HttpClient.post(TemplateApiDefinition.add.client(), data);
|
||||||
mutate();
|
mutate();
|
||||||
return ret as unknown as ITemplate;
|
return ret as unknown as ITemplate;
|
||||||
},
|
},
|
||||||
|
@ -42,31 +75,59 @@ export const useOwnTemplates = () => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data,
|
data,
|
||||||
loading,
|
loading: isLoading,
|
||||||
error,
|
error,
|
||||||
setPage,
|
setPage,
|
||||||
addTemplate,
|
addTemplate,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板详情
|
||||||
|
* @param templateId
|
||||||
|
* @param cookie
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getTemplateDetail = (templateId, cookie = null): Promise<ITemplate> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: TemplateApiDefinition.getDetailById.method,
|
||||||
|
url: TemplateApiDefinition.getDetailById.client(templateId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模板详情
|
||||||
|
* @param templateId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export const useTemplate = (templateId) => {
|
export const useTemplate = (templateId) => {
|
||||||
const { data, error, mutate } = useSWR<ITemplate>(`/template/detail/${templateId}`, (url) => HttpClient.get(url));
|
const { data, error, refetch } = useQuery(TemplateApiDefinition.getDetailById.client(templateId), () =>
|
||||||
|
getTemplateDetail(templateId)
|
||||||
|
);
|
||||||
const loading = !data && !error;
|
const loading = !data && !error;
|
||||||
|
|
||||||
const updateTemplate = useCallback(
|
const updateTemplate = useCallback(
|
||||||
async (data): Promise<ITemplate> => {
|
async (data): Promise<ITemplate> => {
|
||||||
const ret = await HttpClient.post(`/template/update`, {
|
const ret = await HttpClient.request({
|
||||||
id: templateId,
|
method: TemplateApiDefinition.updateById.method,
|
||||||
...data,
|
url: TemplateApiDefinition.updateById.client(templateId),
|
||||||
|
data: {
|
||||||
|
id: templateId,
|
||||||
|
...data,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
mutate();
|
refetch();
|
||||||
return ret as unknown as ITemplate;
|
return ret as unknown as ITemplate;
|
||||||
},
|
},
|
||||||
[mutate, templateId]
|
[refetch, templateId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteTemplate = useCallback(async () => {
|
const deleteTemplate = useCallback(async () => {
|
||||||
await HttpClient.post(`/template/delete/${templateId}`);
|
await HttpClient.request({
|
||||||
|
method: TemplateApiDefinition.deleteById.method,
|
||||||
|
url: TemplateApiDefinition.deleteById.client(templateId),
|
||||||
|
});
|
||||||
}, [templateId]);
|
}, [templateId]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,45 +1,56 @@
|
||||||
import type { ILoginUser, IUser } from '@think/domains';
|
import { ILoginUser, IUser, UserApiDefinition } from '@think/domains';
|
||||||
import { getStorage, setStorage } from 'helpers/storage';
|
import { getStorage, setStorage } from 'helpers/storage';
|
||||||
import Router, { useRouter } from 'next/router';
|
import Router, { useRouter } from 'next/router';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
import useSWR from 'swr';
|
|
||||||
|
|
||||||
export const useUser = () => {
|
export const useUser = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { data, error, mutate } = useSWR<ILoginUser>('user', getStorage);
|
const { data, error, refetch } = useQuery<ILoginUser>('user', () => {
|
||||||
|
return getStorage('user');
|
||||||
|
});
|
||||||
|
|
||||||
const logout = useCallback(() => {
|
const logout = useCallback(() => {
|
||||||
window.localStorage.removeItem('user');
|
window.localStorage.removeItem('user');
|
||||||
window.localStorage.removeItem('token');
|
window.localStorage.removeItem('token');
|
||||||
mutate(null);
|
refetch();
|
||||||
Router.replace('/login');
|
HttpClient.request({
|
||||||
}, [mutate]);
|
method: UserApiDefinition.logout.method,
|
||||||
|
url: UserApiDefinition.logout.client(),
|
||||||
|
}).then(() => {
|
||||||
|
Router.replace('/login');
|
||||||
|
});
|
||||||
|
}, [refetch]);
|
||||||
|
|
||||||
const login = useCallback(
|
const login = useCallback(
|
||||||
(data) => {
|
(data) => {
|
||||||
return HttpClient.post<IUser>('/user/login', data).then((res) => {
|
return HttpClient.request({
|
||||||
|
method: UserApiDefinition.login.method,
|
||||||
|
url: UserApiDefinition.login.client(),
|
||||||
|
data,
|
||||||
|
}).then((res) => {
|
||||||
const user = res as unknown as ILoginUser;
|
const user = res as unknown as ILoginUser;
|
||||||
mutate(user);
|
refetch();
|
||||||
setStorage('user', JSON.stringify(user));
|
setStorage('user', JSON.stringify(user));
|
||||||
user.token && setStorage('token', user.token);
|
user.token && setStorage('token,', user.token);
|
||||||
const next = router.query?.redirect || '/';
|
const next = router.query?.redirect || '/';
|
||||||
Router.replace(next as string);
|
Router.replace(next as string);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[mutate, router.query?.redirect]
|
[refetch, router.query?.redirect]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateUser = async (patch: Pick<IUser, 'email' | 'avatar'>) => {
|
const updateUser = async (patch: Pick<IUser, 'email' | 'avatar'>) => {
|
||||||
const res = await HttpClient.patch('/user/update', patch);
|
const res = await HttpClient.patch('/user/update', patch);
|
||||||
const ret = { ...data, ...res } as unknown as ILoginUser;
|
const ret = { ...data, ...res } as unknown as ILoginUser;
|
||||||
setStorage('user', JSON.stringify(ret));
|
setStorage('user', JSON.stringify(ret));
|
||||||
mutate(ret);
|
refetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
mutate();
|
refetch();
|
||||||
}, [mutate]);
|
}, [refetch]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user: data,
|
user: data,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { CollectType, IDocument, IUser, IWiki, IWikiUser } from '@think/domains';
|
import { IDocument, IUser, IWiki, IWikiUser, WikiApiDefinition } from '@think/domains';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
import { HttpClient } from 'services/http-client';
|
import { HttpClient } from 'services/http-client';
|
||||||
import useSWR from 'swr';
|
|
||||||
|
|
||||||
export type ICreateWiki = Pick<IWiki, 'name' | 'description'>;
|
export type ICreateWiki = Pick<IWiki, 'name' | 'description'>;
|
||||||
export type IUpdateWiki = Partial<IWiki>;
|
export type IUpdateWiki = Partial<IWiki>;
|
||||||
|
@ -15,14 +15,35 @@ export type IWikiWithIsMember = IWiki & { isMember: boolean };
|
||||||
* 获取用户所有知识库
|
* 获取用户所有知识库
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useAllWikis = () => {
|
export const getAllWikis = (cookie = null): Promise<{ data: IWiki[]; total: number }> => {
|
||||||
const { data, error } = useSWR<{ data: IWiki[]; total: number }>('/wiki/list/all', (url) => HttpClient.get(url));
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getAllWikis.method,
|
||||||
|
url: WikiApiDefinition.getAllWikis.client(),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const loading = !data && !error;
|
/**
|
||||||
|
* 获取用户所有知识库
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useAllWikis = () => {
|
||||||
|
const { data, error, isLoading } = useQuery(WikiApiDefinition.getAllWikis.client(), getAllWikis);
|
||||||
const list = (data && data.data) || [];
|
const list = (data && data.data) || [];
|
||||||
const total = (data && data.total) || 0;
|
const total = (data && data.total) || 0;
|
||||||
|
return { data: list, total, error, loading: isLoading };
|
||||||
|
};
|
||||||
|
|
||||||
return { data: list, total, error, loading };
|
/**
|
||||||
|
* 获取用户参与的知识库
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getJoinWikis = (cookie = null): Promise<{ data: IWiki[]; total: number }> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getJoinWikis.method,
|
||||||
|
url: WikiApiDefinition.getJoinWikis.client(),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,13 +51,23 @@ export const useAllWikis = () => {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useJoinWikis = () => {
|
export const useJoinWikis = () => {
|
||||||
const { data, error } = useSWR<{ data: IWiki[]; total: number }>('/wiki/list/join', (url) => HttpClient.get(url));
|
const { data, error, isLoading } = useQuery(WikiApiDefinition.getJoinWikis.client(), getJoinWikis);
|
||||||
|
|
||||||
const loading = !data && !error;
|
|
||||||
const list = (data && data.data) || [];
|
const list = (data && data.data) || [];
|
||||||
const total = (data && data.total) || 0;
|
const total = (data && data.total) || 0;
|
||||||
|
|
||||||
return { data: list, total, error, loading };
|
return { data: list, total, error, loading: isLoading };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户创建的知识库
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getOwnWikis = (cookie = null): Promise<{ data: IWiki[]; total: number }> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getOwnWikis.method,
|
||||||
|
url: WikiApiDefinition.getOwnWikis.client(),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,17 +75,19 @@ export const useJoinWikis = () => {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useOwnWikis = () => {
|
export const useOwnWikis = () => {
|
||||||
const { data, error, mutate } = useSWR<{ data: IWiki[]; total: number }>('/wiki/list/own', (url) =>
|
const { data, error, refetch } = useQuery(WikiApiDefinition.getOwnWikis.client(), getOwnWikis);
|
||||||
HttpClient.get(url)
|
|
||||||
);
|
|
||||||
|
|
||||||
const createWiki = useCallback(
|
const createWiki = useCallback(
|
||||||
async (data: ICreateWiki) => {
|
async (data: ICreateWiki) => {
|
||||||
const res = await HttpClient.post<IWiki>('/wiki/create', data);
|
const res = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.add.method,
|
||||||
|
url: WikiApiDefinition.add.client(),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[mutate]
|
[refetch]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,11 +97,14 @@ export const useOwnWikis = () => {
|
||||||
*/
|
*/
|
||||||
const deletWiki = useCallback(
|
const deletWiki = useCallback(
|
||||||
async (id) => {
|
async (id) => {
|
||||||
const res = await HttpClient.delete<IWiki>('/wiki/delete/' + id);
|
const res = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.deleteById.method,
|
||||||
|
url: WikiApiDefinition.deleteById.client(id),
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[mutate]
|
[refetch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const loading = !data && !error;
|
const loading = !data && !error;
|
||||||
|
@ -78,50 +114,81 @@ export const useOwnWikis = () => {
|
||||||
return { data: list, total, error, loading, createWiki, deletWiki };
|
return { data: list, total, error, loading, createWiki, deletWiki };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有公开文档
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getAllPublicWikis = (
|
||||||
|
page = 1,
|
||||||
|
cookie = null
|
||||||
|
): Promise<{
|
||||||
|
data: Array<IWiki>;
|
||||||
|
total: number;
|
||||||
|
}> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getPublicWikis.method,
|
||||||
|
url: WikiApiDefinition.getPublicWikis.client(),
|
||||||
|
cookie,
|
||||||
|
params: {
|
||||||
|
page,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有公开文档
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useAllPublicWikis = () => {
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const { data, error, isLoading } = useQuery(`${WikiApiDefinition.getPublicWikis.client()}?page=${page}`, () =>
|
||||||
|
getAllPublicWikis(page)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
loading: isLoading,
|
||||||
|
error,
|
||||||
|
setPage,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取知识库首页文档
|
* 获取知识库首页文档
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useWikiHomeDoc = (wikiId) => {
|
export const getWikiHomeDocument = (wikiId, cookie = null): Promise<IDocument> => {
|
||||||
const { data, error } = useSWR<IDocument>('/wiki/homedoc/' + wikiId, (url) => HttpClient.get(url));
|
return HttpClient.request({
|
||||||
const loading = !data && !error;
|
method: WikiApiDefinition.getHomeDocumentById.method,
|
||||||
return { data, error, loading };
|
url: WikiApiDefinition.getHomeDocumentById.client(wikiId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取知识库文档目录
|
* 获取知识库首页文档
|
||||||
* @param workspaceId
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useWikiTocs = (wikiId) => {
|
export const useWikiHomeDocument = (wikiId) => {
|
||||||
const { data, error, mutate } = useSWR<Array<IDocument & { createUser: IUser }>>(`/wiki/tocs/${wikiId}`, (url) =>
|
const { data, error, isLoading } = useQuery(WikiApiDefinition.getHomeDocumentById.client(wikiId), () =>
|
||||||
wikiId ? HttpClient.get(url) : null
|
getWikiHomeDocument(wikiId)
|
||||||
);
|
);
|
||||||
const loading = !data && !error;
|
return { data, error, loading: isLoading };
|
||||||
|
|
||||||
const update = useCallback(
|
|
||||||
async (relations: Array<{ id: string; parentDocumentId: string }>) => {
|
|
||||||
const res = await HttpClient.post(`/wiki/tocs/${wikiId}/update`, relations);
|
|
||||||
mutate();
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
[mutate, wikiId]
|
|
||||||
);
|
|
||||||
|
|
||||||
return { data, loading, error, refresh: mutate, update };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取知识库文档
|
* 获取知识库详情
|
||||||
* @param workspaceId
|
* @param wikiId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useWikiDocs = (wikiId) => {
|
export const getWikiDetail = (wikiId, cookie = null): Promise<IWiki> => {
|
||||||
const { data, error, mutate } = useSWR<Array<IDocument & { createUser: IUser }>>(`/wiki/docs/${wikiId}`, (url) =>
|
return HttpClient.request({
|
||||||
HttpClient.get(url)
|
method: WikiApiDefinition.getDetailById.method,
|
||||||
);
|
url: WikiApiDefinition.getDetailById.client(wikiId),
|
||||||
const loading = !data && !error;
|
cookie,
|
||||||
return { data, loading, error, refresh: mutate };
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,8 +197,9 @@ export const useWikiDocs = (wikiId) => {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useWikiDetail = (wikiId) => {
|
export const useWikiDetail = (wikiId) => {
|
||||||
const { data, error, mutate } = useSWR<IWiki>(wikiId ? `/wiki/detail/${wikiId}` : null, (url) => HttpClient.get(url));
|
const { data, error, isLoading, refetch } = useQuery(WikiApiDefinition.getDetailById.client(wikiId), () =>
|
||||||
const loading = !data && !error;
|
wikiId ? getWikiDetail(wikiId) : null
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新知识库
|
* 更新知识库
|
||||||
|
@ -140,11 +208,15 @@ export const useWikiDetail = (wikiId) => {
|
||||||
*/
|
*/
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
async (data: IUpdateWiki) => {
|
async (data: IUpdateWiki) => {
|
||||||
const res = await HttpClient.patch('/wiki/update/' + wikiId, data);
|
const res = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.updateById.method,
|
||||||
|
url: WikiApiDefinition.updateById.client(wikiId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[mutate, wikiId]
|
[refetch, wikiId]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,98 +226,161 @@ export const useWikiDetail = (wikiId) => {
|
||||||
*/
|
*/
|
||||||
const toggleStatus = useCallback(
|
const toggleStatus = useCallback(
|
||||||
async (data) => {
|
async (data) => {
|
||||||
const res = await HttpClient.post('/wiki/share/' + wikiId, data);
|
const res = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.shareById.method,
|
||||||
|
url: WikiApiDefinition.shareById.client(wikiId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
[mutate, wikiId]
|
[refetch, wikiId]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { data, loading, error, update, toggleStatus };
|
return { data, loading: isLoading, error, update, toggleStatus };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 知识库成员
|
* 获取知识库文档目录
|
||||||
|
* @param workspaceId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getWikiTocs = (wikiId, cookie = null): Promise<Array<IDocument & { createUser: IUser }>> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getTocsById.method,
|
||||||
|
url: WikiApiDefinition.getTocsById.client(wikiId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库文档目录
|
||||||
|
* @param workspaceId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useWikiTocs = (wikiId) => {
|
||||||
|
const { data, error, refetch } = useQuery(WikiApiDefinition.getTocsById.client(wikiId), () =>
|
||||||
|
wikiId ? getWikiTocs(wikiId) : null
|
||||||
|
);
|
||||||
|
const loading = !data && !error;
|
||||||
|
|
||||||
|
const update = useCallback(
|
||||||
|
async (relations: Array<{ id: string; parentDocumentId: string }>) => {
|
||||||
|
const res = await HttpClient.request({
|
||||||
|
method: WikiApiDefinition.updateTocsById.method,
|
||||||
|
url: WikiApiDefinition.updateTocsById.client(wikiId),
|
||||||
|
data: relations,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
[refetch, wikiId]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { data, loading, error, refresh: refetch, update };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库文档目录
|
||||||
|
* @param workspaceId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getWikiDocuments = (wikiId, cookie = null): Promise<Array<IDocument & { createUser: IUser }>> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getDocumentsById.method,
|
||||||
|
url: WikiApiDefinition.getDocumentsById.client(wikiId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库文档
|
||||||
|
* @param workspaceId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const useWikiDocuments = (wikiId) => {
|
||||||
|
const { data, error, isLoading, refetch } = useQuery(WikiApiDefinition.getDocumentsById.client(wikiId), () =>
|
||||||
|
getWikiDocuments(wikiId)
|
||||||
|
);
|
||||||
|
return { data, loading: isLoading, error, refresh: refetch };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库成员
|
||||||
|
* @param wikiId
|
||||||
|
* @param cookie
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getWikiMembers = (wikiId, cookie = null): Promise<IWikiUser[]> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getMemberById.method,
|
||||||
|
url: WikiApiDefinition.getMemberById.client(wikiId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 知识库成员管理
|
||||||
* @param wikiId
|
* @param wikiId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useWikiUsers = (wikiId) => {
|
export const useWikiMembers = (wikiId) => {
|
||||||
const { data, error, mutate } = useSWR<IWikiUser[]>('/wiki/user/' + wikiId, (url) => HttpClient.get(url));
|
const { data, error, isLoading, refetch } = useQuery(WikiApiDefinition.getMemberById.client(wikiId), () =>
|
||||||
const loading = !data && !error;
|
getWikiMembers(wikiId)
|
||||||
|
);
|
||||||
|
|
||||||
const addUser = useCallback(
|
const addUser = useCallback(
|
||||||
async (data: IWikiUserOpeateData) => {
|
async (data: IWikiUserOpeateData) => {
|
||||||
const ret = await HttpClient.post(`/wiki/user/${wikiId}/add`, data);
|
const ret = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.addMemberById.method,
|
||||||
|
url: WikiApiDefinition.addMemberById.client(wikiId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
[mutate, wikiId]
|
[refetch, wikiId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const updateUser = useCallback(
|
const updateUser = useCallback(
|
||||||
async (data: IWikiUserOpeateData) => {
|
async (data: IWikiUserOpeateData) => {
|
||||||
const ret = await HttpClient.post(`/wiki/user/${wikiId}/update`, data);
|
const ret = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.updateMemberById.method,
|
||||||
|
url: WikiApiDefinition.updateMemberById.client(wikiId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
[mutate, wikiId]
|
[refetch, wikiId]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteUser = useCallback(
|
const deleteUser = useCallback(
|
||||||
async (data: IWikiUserOpeateData) => {
|
async (data: IWikiUserOpeateData) => {
|
||||||
const ret = await HttpClient.post(`/wiki/user/${wikiId}/delete`, data);
|
const ret = await HttpClient.request({
|
||||||
mutate();
|
method: WikiApiDefinition.deleteMemberById.method,
|
||||||
|
url: WikiApiDefinition.deleteMemberById.client(wikiId),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
[mutate, wikiId]
|
[refetch, wikiId]
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return { users: data, loading: isLoading, error, addUser, updateUser, deleteUser };
|
||||||
data,
|
|
||||||
error,
|
|
||||||
loading,
|
|
||||||
refresh: mutate,
|
|
||||||
addUser,
|
|
||||||
updateUser,
|
|
||||||
deleteUser,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 收藏知识库
|
* 获取公开知识库首页文档
|
||||||
* @param wikiId
|
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useWikiStar = (wikiId) => {
|
export const getPublicWikiHomeDocument = (wikiId, cookie = null): Promise<IDocument> => {
|
||||||
const { data, error, mutate } = useSWR<boolean>(`/collector/check/${wikiId}`, () =>
|
return HttpClient.request({
|
||||||
HttpClient.post(`/collector/check`, {
|
method: WikiApiDefinition.getPublicHomeDocumentById.method,
|
||||||
type: CollectType.wiki,
|
url: WikiApiDefinition.getPublicHomeDocumentById.client(wikiId),
|
||||||
targetId: wikiId,
|
cookie,
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const toggleStar = useCallback(async () => {
|
|
||||||
await HttpClient.post('/collector/toggle/', {
|
|
||||||
type: CollectType.wiki,
|
|
||||||
targetId: wikiId,
|
|
||||||
});
|
|
||||||
mutate();
|
|
||||||
}, [mutate, wikiId]);
|
|
||||||
|
|
||||||
return { data, error, toggleStar };
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户收藏的文档
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const useStaredWikis = () => {
|
|
||||||
const { data, error, mutate } = useSWR<IWikiWithIsMember[]>('/collector/wikis', (url) => HttpClient.post(url), {
|
|
||||||
revalidateOnFocus: true,
|
|
||||||
});
|
});
|
||||||
const loading = !data && !error;
|
|
||||||
|
|
||||||
return { data, error, loading, refresh: mutate };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -253,19 +388,38 @@ export const useStaredWikis = () => {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const usePublicWikiHomeDoc = (wikiId) => {
|
export const usePublicWikiHomeDoc = (wikiId) => {
|
||||||
const { data, error } = useSWR<IDocument>('/wiki/public/homedoc/' + wikiId, (url) => HttpClient.get(url));
|
const { data, error } = useQuery(
|
||||||
|
WikiApiDefinition.getPublicHomeDocumentById.client(wikiId),
|
||||||
|
() => getPublicWikiHomeDocument(wikiId),
|
||||||
|
{ retry: 0 }
|
||||||
|
);
|
||||||
const loading = !data && !error;
|
const loading = !data && !error;
|
||||||
return { data, error, loading };
|
return { data, error, loading };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开知识库详情
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getPublicWikiDetail = (wikiId, cookie = null): Promise<IWiki> => {
|
||||||
|
return HttpClient.request({
|
||||||
|
method: WikiApiDefinition.getPublicDetailById.method,
|
||||||
|
url: WikiApiDefinition.getPublicDetailById.client(wikiId),
|
||||||
|
cookie,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取知识库详情
|
* 获取知识库详情
|
||||||
* @param wikiId
|
* @param wikiId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const usePublicWikiDetail = (wikiId) => {
|
export const usePublicWikiDetail = (wikiId) => {
|
||||||
const { data, error, mutate } = useSWR<IWiki>(wikiId ? `/wiki/public/detail/${wikiId}` : null, (url) =>
|
const { data, error } = useQuery(
|
||||||
HttpClient.post(url)
|
WikiApiDefinition.getPublicDetailById.client(wikiId),
|
||||||
|
() => getPublicWikiDetail(wikiId),
|
||||||
|
{ retry: 0 }
|
||||||
);
|
);
|
||||||
const loading = !data && !error;
|
const loading = !data && !error;
|
||||||
return { data, loading, error };
|
return { data, loading, error };
|
||||||
|
@ -276,32 +430,26 @@ export const usePublicWikiDetail = (wikiId) => {
|
||||||
* @param workspaceId
|
* @param workspaceId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const usePublicWikiTocs = (wikiId) => {
|
export const getPublicWikiTocs = (wikiId, cookie = null): Promise<Array<IDocument & { createUser: IUser }>> => {
|
||||||
const { data, error, mutate } = useSWR<Array<IDocument>>(`/wiki/public/tocs/${wikiId}`, (url) =>
|
return HttpClient.request({
|
||||||
HttpClient.post(url)
|
method: WikiApiDefinition.getPublicTocsById.method,
|
||||||
);
|
url: WikiApiDefinition.getPublicTocsById.client(wikiId),
|
||||||
const loading = !data && !error;
|
cookie,
|
||||||
|
});
|
||||||
return { data, loading, error, refresh: mutate };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文档评论
|
* 获取公开知识库文档目录
|
||||||
* @param documentId
|
* @param workspaceId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const useAllPublicWikis = () => {
|
export const usePublicWikiTocs = (wikiId) => {
|
||||||
const [page, setPage] = useState(1);
|
const { data, error, refetch } = useQuery(
|
||||||
const { data, error, mutate } = useSWR<{
|
WikiApiDefinition.getPublicTocsById.client(wikiId),
|
||||||
data: Array<IWiki>;
|
() => getPublicWikiTocs(wikiId),
|
||||||
total: number;
|
{ retry: 0 }
|
||||||
}>(`/wiki/public/wikis?page=${page}`, (url) => HttpClient.get(url));
|
);
|
||||||
const loading = !data && !error;
|
const loading = !data && !error;
|
||||||
|
|
||||||
return {
|
return { data, loading, error, refresh: refetch };
|
||||||
data,
|
|
||||||
loading,
|
|
||||||
error,
|
|
||||||
setPage,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,9 +4,13 @@ export const buildUrl = (url) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWikiShareURL = (wikiId) => {
|
export const getWikiShareURL = (wikiId) => {
|
||||||
return window.location.origin + '/share/wiki/' + wikiId;
|
const url = '/share/wiki/' + wikiId;
|
||||||
|
if (typeof window === 'undefined') return url;
|
||||||
|
return window.location.origin + url;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDocumentShareURL = (documentId) => {
|
export const getDocumentShareURL = (documentId) => {
|
||||||
return window.location.origin + '/share/document/' + documentId;
|
const url = '/share/document/' + documentId;
|
||||||
|
if (typeof window === 'undefined') return url;
|
||||||
|
return window.location.origin + url;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { getStorage, setStorage } from 'helpers/storage';
|
import { getStorage, setStorage } from 'helpers/storage';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import useSWR from 'swr';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
export enum Width {
|
export enum Width {
|
||||||
'standardWidth' = 'standardWidth',
|
'standardWidth' = 'standardWidth',
|
||||||
|
@ -13,7 +13,7 @@ const DEFAULT_WIDTH = Width.standardWidth;
|
||||||
const DEFAULT_FONT_SIZE = 16;
|
const DEFAULT_FONT_SIZE = 16;
|
||||||
|
|
||||||
export const useDocumentStyle = () => {
|
export const useDocumentStyle = () => {
|
||||||
const { data, mutate } = useSWR(`/fe/mock/${WIDTH_KEY}/${FONT_SIZE_KEY}`, () => {
|
const { data, refetch } = useQuery(`/fe/mock/${WIDTH_KEY}/${FONT_SIZE_KEY}`, () => {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
return {
|
return {
|
||||||
width: getStorage(WIDTH_KEY) || DEFAULT_WIDTH,
|
width: getStorage(WIDTH_KEY) || DEFAULT_WIDTH,
|
||||||
|
@ -29,17 +29,17 @@ export const useDocumentStyle = () => {
|
||||||
|
|
||||||
const setWidth = (width: Width) => {
|
const setWidth = (width: Width) => {
|
||||||
setStorage(WIDTH_KEY, width);
|
setStorage(WIDTH_KEY, width);
|
||||||
mutate();
|
refetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setFontSize = (fontSize: number) => {
|
const setFontSize = (fontSize: number) => {
|
||||||
setStorage(FONT_SIZE_KEY, fontSize);
|
setStorage(FONT_SIZE_KEY, fontSize);
|
||||||
mutate();
|
refetch();
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
mutate();
|
refetch();
|
||||||
}, [mutate]);
|
}, [refetch]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: (data && data.width) || DEFAULT_WIDTH,
|
width: (data && data.width) || DEFAULT_WIDTH,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { clamp } from 'helpers/clamp';
|
||||||
import { getStorage, setStorage } from 'helpers/storage';
|
import { getStorage, setStorage } from 'helpers/storage';
|
||||||
import { useWindowSize } from 'hooks/use-window-size';
|
import { useWindowSize } from 'hooks/use-window-size';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import useSWR from 'swr';
|
import { useQuery } from 'react-query';
|
||||||
|
|
||||||
const key = 'dragable-menu-width';
|
const key = 'dragable-menu-width';
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export const useDragableWidth = () => {
|
||||||
const { width: windowWidth } = useWindowSize();
|
const { width: windowWidth } = useWindowSize();
|
||||||
const [minWidth, setMinWidth] = useState(DEFAULT_MOBILE_MIN_WIDTH);
|
const [minWidth, setMinWidth] = useState(DEFAULT_MOBILE_MIN_WIDTH);
|
||||||
const [maxWidth, setMaxWidth] = useState(DEFAULT_MOBILE_MAX_WIDTH);
|
const [maxWidth, setMaxWidth] = useState(DEFAULT_MOBILE_MAX_WIDTH);
|
||||||
const { data: currentWidth, mutate } = useSWR<number>(key, () => {
|
const { data: currentWidth, refetch } = useQuery<number>(key, () => {
|
||||||
const nextWidth = getStorage(key, minWidth);
|
const nextWidth = getStorage(key, minWidth);
|
||||||
|
|
||||||
if (nextWidth <= COLLAPSED_WIDTH) {
|
if (nextWidth <= COLLAPSED_WIDTH) {
|
||||||
|
@ -41,9 +41,9 @@ export const useDragableWidth = () => {
|
||||||
}
|
}
|
||||||
setStorage(key, size);
|
setStorage(key, size);
|
||||||
prevWidthRef.current = size;
|
prevWidthRef.current = size;
|
||||||
mutate();
|
refetch();
|
||||||
},
|
},
|
||||||
[mutate, windowWidth, minWidth, maxWidth]
|
[refetch, windowWidth, minWidth, maxWidth]
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggleCollapsed = useCallback(() => {
|
const toggleCollapsed = useCallback(() => {
|
||||||
|
@ -65,15 +65,15 @@ export const useDragableWidth = () => {
|
||||||
|
|
||||||
setStorage(key, nextWidth);
|
setStorage(key, nextWidth);
|
||||||
}
|
}
|
||||||
mutate();
|
refetch();
|
||||||
}, [mutate, currentWidth, minWidth, maxWidth]);
|
}, [refetch, currentWidth, minWidth, maxWidth]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const min = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MIN_WIDTH : DEFAULT_PC_MIN_WIDTH;
|
const min = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MIN_WIDTH : DEFAULT_PC_MIN_WIDTH;
|
||||||
const max = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MAX_WIDTH : DEFAULT_PC_MAX_WIDTH;
|
const max = windowWidth <= PC_MOBILE_CRITICAL_WIDTH ? DEFAULT_MOBILE_MAX_WIDTH : DEFAULT_PC_MAX_WIDTH;
|
||||||
setMinWidth(min);
|
setMinWidth(min);
|
||||||
setMaxWidth(max);
|
setMaxWidth(max);
|
||||||
}, [windowWidth, mutate, currentWidth]);
|
}, [windowWidth, refetch, currentWidth]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
minWidth,
|
minWidth,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Avatar, Dropdown, Modal, Space, Typography } from '@douyinfe/semi-ui';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { Empty } from 'components/empty';
|
import { Empty } from 'components/empty';
|
||||||
import { WikiStar } from 'components/wiki/star';
|
import { WikiStar } from 'components/wiki/star';
|
||||||
import { useCollectedWikis } from 'data/refactor/collector';
|
import { useCollectedWikis } from 'data/collector';
|
||||||
import { useWikiDetail } from 'data/wiki';
|
import { useWikiDetail } from 'data/wiki';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { DataRender } from 'components/data-render';
|
||||||
import { Empty } from 'components/empty';
|
import { Empty } from 'components/empty';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { WikiCard, WikiCardPlaceholder } from 'components/wiki/card';
|
import { WikiCard, WikiCardPlaceholder } from 'components/wiki/card';
|
||||||
import { getAllPublicWikis, useAllPublicWikis } from 'data/refactor/wiki';
|
import { getAllPublicWikis, useAllPublicWikis } from 'data/wiki';
|
||||||
import { SingleColumnLayout } from 'layouts/single-column';
|
import { SingleColumnLayout } from 'layouts/single-column';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
|
@ -7,8 +7,8 @@ import { LocaleTime } from 'components/locale-time';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { WikiCreator } from 'components/wiki/create';
|
import { WikiCreator } from 'components/wiki/create';
|
||||||
import { WikiPinCard, WikiPinCardPlaceholder } from 'components/wiki/pin-card';
|
import { WikiPinCard, WikiPinCardPlaceholder } from 'components/wiki/pin-card';
|
||||||
import { getCollectedWikis, useCollectedWikis } from 'data/refactor/collector';
|
import { getCollectedWikis, useCollectedWikis } from 'data/collector';
|
||||||
import { getRecentVisitedDocuments, useRecentDocuments } from 'data/refactor/document';
|
import { getRecentVisitedDocuments, useRecentDocuments } from 'data/document';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { SingleColumnLayout } from 'layouts/single-column';
|
import { SingleColumnLayout } from 'layouts/single-column';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { DocumentApiDefinition, IDocument } from '@think/domains';
|
||||||
import { DocumentPublicReader } from 'components/document/reader/public';
|
import { DocumentPublicReader } from 'components/document/reader/public';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { getPublicDocumentDetail } from 'services/document';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
documentId: string;
|
documentId: string;
|
||||||
|
@ -12,7 +15,15 @@ const Page: NextPage<IProps> = ({ documentId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { documentId } = ctx.query;
|
const { documentId } = ctx.query;
|
||||||
return { documentId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: DocumentApiDefinition.getPublicDetailById.client(documentId as IDocument['id']),
|
||||||
|
// 默认无密码公开文档,如果有密码,客户端重新获取
|
||||||
|
action: () => getPublicDocumentDetail(documentId as IDocument['id'], { sharePassword: '' }),
|
||||||
|
ignoreCookie: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, documentId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
import { DocumentApiDefinition, IDocument, IWiki, WikiApiDefinition } from '@think/domains';
|
||||||
import { DocumentPublicReader } from 'components/document/reader/public';
|
import { DocumentPublicReader } from 'components/document/reader/public';
|
||||||
import { WikiPublicTocs } from 'components/wiki/tocs/public';
|
import { WikiPublicTocs } from 'components/wiki/tocs/public';
|
||||||
|
import { getPublicWikiTocs } from 'data/wiki';
|
||||||
import { PublicDoubleColumnLayout } from 'layouts/public-double-column';
|
import { PublicDoubleColumnLayout } from 'layouts/public-double-column';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { getPublicDocumentDetail } from 'services/document';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -20,7 +24,20 @@ const Page: NextPage<IProps> = ({ wikiId, documentId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId, documentId } = ctx.query;
|
const { wikiId, documentId } = ctx.query;
|
||||||
return { wikiId, documentId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getPublicTocsById.client(wikiId as IWiki['id']),
|
||||||
|
action: () => getPublicWikiTocs(wikiId),
|
||||||
|
ignoreCookie: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: DocumentApiDefinition.getPublicDetailById.client(documentId as IDocument['id']),
|
||||||
|
// 默认无密码公开文档,如果有密码,客户端重新获取
|
||||||
|
action: () => getPublicDocumentDetail(documentId as IDocument['id'], { sharePassword: '' }),
|
||||||
|
ignoreCookie: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, wikiId, documentId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
import { IWiki, WikiApiDefinition } from '@think/domains';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { DocumentPublicReader } from 'components/document/reader/public';
|
import { DocumentPublicReader } from 'components/document/reader/public';
|
||||||
import { WikiPublicTocs } from 'components/wiki/tocs/public';
|
import { WikiPublicTocs } from 'components/wiki/tocs/public';
|
||||||
import { usePublicWikiHomeDoc } from 'data/wiki';
|
import { getPublicWikiDetail, getPublicWikiHomeDocument, getPublicWikiTocs, usePublicWikiHomeDoc } from 'data/wiki';
|
||||||
import { PublicDoubleColumnLayout } from 'layouts/public-double-column';
|
import { PublicDoubleColumnLayout } from 'layouts/public-double-column';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -31,7 +33,24 @@ const Page: NextPage<IProps> = ({ wikiId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId } = ctx.query;
|
const { wikiId } = ctx.query;
|
||||||
return { wikiId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getPublicDetailById.client(wikiId as IWiki['id']),
|
||||||
|
action: () => getPublicWikiDetail(wikiId),
|
||||||
|
ignoreCookie: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getPublicHomeDocumentById.client(wikiId as IWiki['id']),
|
||||||
|
action: () => getPublicWikiHomeDocument(wikiId),
|
||||||
|
ignoreCookie: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getPublicTocsById.client(wikiId as IWiki['id']),
|
||||||
|
action: () => getPublicWikiTocs(wikiId),
|
||||||
|
ignoreCookie: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { wikiId, ...res } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -5,12 +5,7 @@ import { DocumentCard, DocumentCardPlaceholder } from 'components/document/card'
|
||||||
import { Empty } from 'components/empty';
|
import { Empty } from 'components/empty';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { WikiCard, WikiCardPlaceholder } from 'components/wiki/card';
|
import { WikiCard, WikiCardPlaceholder } from 'components/wiki/card';
|
||||||
import {
|
import { getCollectedDocuments, getCollectedWikis, useCollectedDocuments, useCollectedWikis } from 'data/collector';
|
||||||
getCollectedDocuments,
|
|
||||||
getCollectedWikis,
|
|
||||||
useCollectedDocuments,
|
|
||||||
useCollectedWikis,
|
|
||||||
} from 'data/refactor/collector';
|
|
||||||
import { SingleColumnLayout } from 'layouts/single-column';
|
import { SingleColumnLayout } from 'layouts/single-column';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import { ITemplate, TemplateApiDefinition } from '@think/domains';
|
||||||
import { TemplateEditor } from 'components/template/editor';
|
import { TemplateEditor } from 'components/template/editor';
|
||||||
|
import { getTemplateDetail } from 'data/template';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
templateId: string;
|
templateId: string;
|
||||||
|
@ -11,7 +14,13 @@ const Page: NextPage<IProps> = ({ templateId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { templateId } = ctx.query;
|
const { templateId } = ctx.query;
|
||||||
return { templateId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: TemplateApiDefinition.getDetailById.client(templateId as ITemplate['id']),
|
||||||
|
action: (cookie) => getTemplateDetail(templateId, cookie),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, templateId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button, TabPane, Tabs, Typography } from '@douyinfe/semi-ui';
|
import { Button, TabPane, Tabs, Typography } from '@douyinfe/semi-ui';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { TemplateList } from 'components/template/list';
|
import { TemplateList } from 'components/template/list';
|
||||||
import { useOwnTemplates, usePublicTemplates } from 'data/refactor/template';
|
import { useOwnTemplates, usePublicTemplates } from 'data/template';
|
||||||
import { SingleColumnLayout } from 'layouts/single-column';
|
import { SingleColumnLayout } from 'layouts/single-column';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
import Router, { useRouter } from 'next/router';
|
import Router, { useRouter } from 'next/router';
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { DocumentApiDefinition, IDocument } from '@think/domains';
|
||||||
import { DocumentEditor } from 'components/document/editor';
|
import { DocumentEditor } from 'components/document/editor';
|
||||||
|
import { getDocumentDetail } from 'data/document';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -13,7 +16,14 @@ const Page: NextPage<IProps> = ({ wikiId, documentId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId, documentId } = ctx.query;
|
const { wikiId, documentId } = ctx.query;
|
||||||
return { wikiId, documentId } as IProps;
|
|
||||||
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: DocumentApiDefinition.getDetailById.client(documentId as IDocument['id']),
|
||||||
|
action: (cookie) => getDocumentDetail(documentId, cookie),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, wikiId, documentId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
import { DocumentApiDefinition, IDocument, IWiki, WikiApiDefinition } from '@think/domains';
|
||||||
import { DocumentReader } from 'components/document/reader';
|
import { DocumentReader } from 'components/document/reader';
|
||||||
import { WikiTocs } from 'components/wiki/tocs';
|
import { WikiTocs } from 'components/wiki/tocs';
|
||||||
|
import { getDocumentDetail } from 'data/document';
|
||||||
|
import { getWikiTocs } from 'data/wiki';
|
||||||
import { DoubleColumnLayout } from 'layouts/double-column';
|
import { DoubleColumnLayout } from 'layouts/double-column';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -20,7 +24,18 @@ const Page: NextPage<IProps> = ({ wikiId, documentId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId, documentId } = ctx.query;
|
const { wikiId, documentId } = ctx.query;
|
||||||
return { wikiId, documentId } as IProps;
|
|
||||||
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getTocsById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiTocs(wikiId, cookie),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: DocumentApiDefinition.getDetailById.client(documentId as IDocument['id']),
|
||||||
|
action: (cookie) => getDocumentDetail(documentId, cookie),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, wikiId, documentId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { List, TabPane, Tabs, Typography } from '@douyinfe/semi-ui';
|
import { List, TabPane, Tabs, Typography } from '@douyinfe/semi-ui';
|
||||||
|
import { IWiki, WikiApiDefinition } from '@think/domains';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { DocumentCard, DocumentCardPlaceholder } from 'components/document/card';
|
import { DocumentCard, DocumentCardPlaceholder } from 'components/document/card';
|
||||||
import { DocumentCreator } from 'components/document-creator';
|
import { DocumentCreator } from 'components/document-creator';
|
||||||
|
@ -7,12 +8,13 @@ import { Seo } from 'components/seo';
|
||||||
import { WikiDocumentsShare } from 'components/wiki/documents-share';
|
import { WikiDocumentsShare } from 'components/wiki/documents-share';
|
||||||
import { WikiTocs } from 'components/wiki/tocs';
|
import { WikiTocs } from 'components/wiki/tocs';
|
||||||
import { WikiTocsManager } from 'components/wiki/tocs/manager';
|
import { WikiTocsManager } from 'components/wiki/tocs/manager';
|
||||||
import { useWikiDocs } from 'data/wiki';
|
import { getWikiTocs, useWikiDocuments } from 'data/wiki';
|
||||||
import { CreateDocumentIllustration } from 'illustrations/create-document';
|
import { CreateDocumentIllustration } from 'illustrations/create-document';
|
||||||
import { DoubleColumnLayout } from 'layouts/double-column';
|
import { DoubleColumnLayout } from 'layouts/double-column';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import Router, { useRouter } from 'next/router';
|
import Router, { useRouter } from 'next/router';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -31,7 +33,7 @@ const grid = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const AllDocs = ({ wikiId }) => {
|
const AllDocs = ({ wikiId }) => {
|
||||||
const { data: docs, loading, error } = useWikiDocs(wikiId);
|
const { data: docs, loading, error } = useWikiDocuments(wikiId);
|
||||||
return (
|
return (
|
||||||
<DataRender
|
<DataRender
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
@ -110,7 +112,13 @@ const Page: NextPage<IProps> = ({ wikiId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId } = ctx.query;
|
const { wikiId } = ctx.query;
|
||||||
return { wikiId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getTocsById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiTocs(wikiId, cookie),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, wikiId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
|
import { IWiki, WikiApiDefinition } from '@think/domains';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { DocumentReader } from 'components/document/reader';
|
import { DocumentReader } from 'components/document/reader';
|
||||||
import { WikiTocs } from 'components/wiki/tocs';
|
import { WikiTocs } from 'components/wiki/tocs';
|
||||||
import { useWikiHomeDoc } from 'data/wiki';
|
import { getWikiDetail, getWikiHomeDocument, getWikiTocs, useWikiHomeDocument } from 'data/wiki';
|
||||||
import { DoubleColumnLayout } from 'layouts/double-column';
|
import { DoubleColumnLayout } from 'layouts/double-column';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Page: NextPage<IProps> = ({ wikiId }) => {
|
const Page: NextPage<IProps> = ({ wikiId }) => {
|
||||||
const { data: doc, loading, error } = useWikiHomeDoc(wikiId);
|
const { data: doc, loading, error } = useWikiHomeDocument(wikiId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DoubleColumnLayout
|
<DoubleColumnLayout
|
||||||
|
@ -29,7 +31,21 @@ const Page: NextPage<IProps> = ({ wikiId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId } = ctx.query;
|
const { wikiId } = ctx.query;
|
||||||
return { wikiId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getHomeDocumentById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiHomeDocument(cookie),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getDetailById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiDetail(wikiId, cookie),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getTocsById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiTocs(wikiId, cookie),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, wikiId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
import { IWiki, WikiApiDefinition } from '@think/domains';
|
||||||
import { WikiSetting } from 'components/wiki/setting';
|
import { WikiSetting } from 'components/wiki/setting';
|
||||||
import { WikiTocs } from 'components/wiki/tocs';
|
import { WikiTocs } from 'components/wiki/tocs';
|
||||||
|
import { getWikiMembers, getWikiTocs } from 'data/wiki';
|
||||||
import { DoubleColumnLayout } from 'layouts/double-column';
|
import { DoubleColumnLayout } from 'layouts/double-column';
|
||||||
import { NextPage } from 'next';
|
import { NextPage } from 'next';
|
||||||
import Router, { useRouter } from 'next/router';
|
import Router, { useRouter } from 'next/router';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
import { serverPrefetcher } from 'services/server-prefetcher';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
wikiId: string;
|
wikiId: string;
|
||||||
|
@ -41,7 +44,16 @@ const Page: NextPage<IProps> = ({ wikiId }) => {
|
||||||
|
|
||||||
Page.getInitialProps = async (ctx) => {
|
Page.getInitialProps = async (ctx) => {
|
||||||
const { wikiId } = ctx.query;
|
const { wikiId } = ctx.query;
|
||||||
return { wikiId } as IProps;
|
const res = await serverPrefetcher(ctx, [
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getTocsById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiTocs(wikiId, cookie),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: WikiApiDefinition.getMemberById.client(wikiId as IWiki['id']),
|
||||||
|
action: (cookie) => getWikiMembers(wikiId, cookie),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
return { ...res, wikiId } as IProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Page;
|
export default Page;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Empty } from 'components/empty';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { WikiCard, WikiCardPlaceholder } from 'components/wiki/card';
|
import { WikiCard, WikiCardPlaceholder } from 'components/wiki/card';
|
||||||
import { WikiCreator } from 'components/wiki-creator';
|
import { WikiCreator } from 'components/wiki-creator';
|
||||||
import { getAllWikis, getJoinWikis, getOwnWikis, useAllWikis, useJoinWikis, useOwnWikis } from 'data/refactor/wiki';
|
import { getAllWikis, getJoinWikis, getOwnWikis, useAllWikis, useJoinWikis, useOwnWikis } from 'data/wiki';
|
||||||
import { CreateWikiIllustration } from 'illustrations/create-wiki';
|
import { CreateWikiIllustration } from 'illustrations/create-wiki';
|
||||||
import { SingleColumnLayout } from 'layouts/single-column';
|
import { SingleColumnLayout } from 'layouts/single-column';
|
||||||
import type { NextPage } from 'next';
|
import type { NextPage } from 'next';
|
||||||
|
|
|
@ -2,8 +2,10 @@ import { Toast } from '@douyinfe/semi-ui';
|
||||||
import axios, { Axios, AxiosRequestConfig, AxiosResponse } from 'axios';
|
import axios, { Axios, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
|
|
||||||
|
type WithCookieAxiosRequestConfig = AxiosRequestConfig & { cookie?: string };
|
||||||
|
|
||||||
interface AxiosInstance extends Axios {
|
interface AxiosInstance extends Axios {
|
||||||
request<T = any, R = AxiosResponse<T>>(config: AxiosRequestConfig): Promise<R>;
|
request<T = any, R = AxiosResponse<T>>(config: WithCookieAxiosRequestConfig): Promise<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HttpClient = axios.create({
|
export const HttpClient = axios.create({
|
||||||
|
@ -15,7 +17,14 @@ export const HttpClient = axios.create({
|
||||||
const isBrowser = typeof window !== 'undefined';
|
const isBrowser = typeof window !== 'undefined';
|
||||||
|
|
||||||
HttpClient.interceptors.request.use(
|
HttpClient.interceptors.request.use(
|
||||||
(config) => {
|
(config: WithCookieAxiosRequestConfig) => {
|
||||||
|
const cookie = config.cookie;
|
||||||
|
if (cookie) {
|
||||||
|
if (typeof window === 'undefined' && !config.headers.cookie) {
|
||||||
|
config.headers.cookie = cookie;
|
||||||
|
}
|
||||||
|
delete config.cookie;
|
||||||
|
}
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -4,12 +4,15 @@ import { dehydrate, QueryClient } from 'react-query';
|
||||||
type PrefetchActions = Array<{
|
type PrefetchActions = Array<{
|
||||||
url: string;
|
url: string;
|
||||||
action: (cookie: string) => void;
|
action: (cookie: string) => void;
|
||||||
|
ignoreCookie?: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export async function serverPrefetcher(ctx: NextPageContext, actions: PrefetchActions) {
|
export async function serverPrefetcher(ctx: NextPageContext, actions: PrefetchActions) {
|
||||||
const cookie = ctx.req?.headers?.cookie;
|
const cookie = ctx.req?.headers?.cookie;
|
||||||
|
|
||||||
if (!cookie) return {};
|
if (!cookie && !actions.filter((action) => action.ignoreCookie === true).length) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,3 @@
|
||||||
import { IDocument, IWiki, CollectType } from '../models';
|
|
||||||
export declare type CollectorApiTypeDefinition = {
|
|
||||||
toggle: {
|
|
||||||
request: {
|
|
||||||
targetId: IDocument['id'] | IWiki['id'];
|
|
||||||
type: CollectType;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
check: {
|
|
||||||
request: {
|
|
||||||
targetId: IDocument['id'] | IWiki['id'];
|
|
||||||
type: CollectType;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export declare const CollectorApiDefinition: {
|
export declare const CollectorApiDefinition: {
|
||||||
/**
|
/**
|
||||||
* 收藏(或取消收藏)
|
* 收藏(或取消收藏)
|
||||||
|
|
|
@ -84,7 +84,7 @@ export declare const DocumentApiDefinition: {
|
||||||
* 获取子文档
|
* 获取子文档
|
||||||
*/
|
*/
|
||||||
getChildren: {
|
getChildren: {
|
||||||
method: "get";
|
method: "post";
|
||||||
server: "children";
|
server: "children";
|
||||||
client: () => string;
|
client: () => string;
|
||||||
};
|
};
|
||||||
|
@ -108,7 +108,7 @@ export declare const DocumentApiDefinition: {
|
||||||
* 获取公开文档详情
|
* 获取公开文档详情
|
||||||
*/
|
*/
|
||||||
getPublicDetailById: {
|
getPublicDetailById: {
|
||||||
method: "get";
|
method: "post";
|
||||||
server: "public/detail/:id";
|
server: "public/detail/:id";
|
||||||
client: (id: IDocument['id']) => string;
|
client: (id: IDocument['id']) => string;
|
||||||
};
|
};
|
||||||
|
@ -116,7 +116,7 @@ export declare const DocumentApiDefinition: {
|
||||||
* 获取公开文档的子文档
|
* 获取公开文档的子文档
|
||||||
*/
|
*/
|
||||||
getPublicChildren: {
|
getPublicChildren: {
|
||||||
method: "get";
|
method: "post";
|
||||||
server: "public/children";
|
server: "public/children";
|
||||||
client: () => string;
|
client: () => string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,7 +86,7 @@ exports.DocumentApiDefinition = {
|
||||||
* 获取子文档
|
* 获取子文档
|
||||||
*/
|
*/
|
||||||
getChildren: {
|
getChildren: {
|
||||||
method: 'get',
|
method: 'post',
|
||||||
server: 'children',
|
server: 'children',
|
||||||
client: function () { return "/document/children"; }
|
client: function () { return "/document/children"; }
|
||||||
},
|
},
|
||||||
|
@ -110,7 +110,7 @@ exports.DocumentApiDefinition = {
|
||||||
* 获取公开文档详情
|
* 获取公开文档详情
|
||||||
*/
|
*/
|
||||||
getPublicDetailById: {
|
getPublicDetailById: {
|
||||||
method: 'get',
|
method: 'post',
|
||||||
server: 'public/detail/:id',
|
server: 'public/detail/:id',
|
||||||
client: function (id) { return "/document/public/detail/".concat(id); }
|
client: function (id) { return "/document/public/detail/".concat(id); }
|
||||||
},
|
},
|
||||||
|
@ -118,7 +118,7 @@ exports.DocumentApiDefinition = {
|
||||||
* 获取公开文档的子文档
|
* 获取公开文档的子文档
|
||||||
*/
|
*/
|
||||||
getPublicChildren: {
|
getPublicChildren: {
|
||||||
method: 'get',
|
method: 'post',
|
||||||
server: 'public/children',
|
server: 'public/children',
|
||||||
client: function () { return "/document/public/children"; }
|
client: function () { return "/document/public/children"; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ export const DocumentApiDefinition = {
|
||||||
* 获取子文档
|
* 获取子文档
|
||||||
*/
|
*/
|
||||||
getChildren: {
|
getChildren: {
|
||||||
method: 'get' as const,
|
method: 'post' as const,
|
||||||
server: 'children' as const,
|
server: 'children' as const,
|
||||||
client: () => `/document/children`,
|
client: () => `/document/children`,
|
||||||
},
|
},
|
||||||
|
@ -122,7 +122,7 @@ export const DocumentApiDefinition = {
|
||||||
* 获取公开文档详情
|
* 获取公开文档详情
|
||||||
*/
|
*/
|
||||||
getPublicDetailById: {
|
getPublicDetailById: {
|
||||||
method: 'get' as const,
|
method: 'post' as const,
|
||||||
server: 'public/detail/:id' as const,
|
server: 'public/detail/:id' as const,
|
||||||
client: (id: IDocument['id']) => `/document/public/detail/${id}`,
|
client: (id: IDocument['id']) => `/document/public/detail/${id}`,
|
||||||
},
|
},
|
||||||
|
@ -131,7 +131,7 @@ export const DocumentApiDefinition = {
|
||||||
* 获取公开文档的子文档
|
* 获取公开文档的子文档
|
||||||
*/
|
*/
|
||||||
getPublicChildren: {
|
getPublicChildren: {
|
||||||
method: 'get' as const,
|
method: 'post' as const,
|
||||||
server: 'public/children' as const,
|
server: 'public/children' as const,
|
||||||
client: () => `/document/public/children`,
|
client: () => `/document/public/children`,
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class CommentController {
|
||||||
@Get(CommentApiDefinition.documents.server)
|
@Get(CommentApiDefinition.documents.server)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getArticleComments(@Param('id') documentId, @Query() qurey) {
|
async getArticleComments(@Param('documentId') documentId, @Query() qurey) {
|
||||||
return this.commentService.getDocumentComments(documentId, qurey);
|
return this.commentService.getDocumentComments(documentId, qurey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,15 +52,21 @@ export class UserController {
|
||||||
@Post(UserApiDefinition.login.server)
|
@Post(UserApiDefinition.login.server)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
async login(@Body() user: LoginUserDto, @Res({ passthrough: true }) response: ExpressResponse) {
|
async login(@Body() user: LoginUserDto, @Res({ passthrough: true }) response: ExpressResponse) {
|
||||||
const { user: data, token } = await this.userService.login(user);
|
const { user: data, token, domain, expiresIn } = await this.userService.login(user);
|
||||||
response.cookie('token', token, { httpOnly: true, secure: true, sameSite: 'lax' });
|
response.cookie('token', token, {
|
||||||
|
domain,
|
||||||
|
expires: new Date(new Date().getTime() + expiresIn),
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
});
|
||||||
return { ...data, token };
|
return { ...data, token };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登出
|
* 登出
|
||||||
*/
|
*/
|
||||||
@Get(UserApiDefinition.logout.server)
|
@Post(UserApiDefinition.logout.server)
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
async logout(@Res({ passthrough: true }) response: ExpressResponse) {
|
async logout(@Res({ passthrough: true }) response: ExpressResponse) {
|
||||||
response.cookie('token', '', { expires: new Date() });
|
response.cookie('token', '', { expires: new Date() });
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -311,7 +311,7 @@ export class WikiController {
|
||||||
*/
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post(WikiApiDefinition.getPublicTocsById.server)
|
@Get(WikiApiDefinition.getPublicTocsById.server)
|
||||||
@CheckWikiStatus(WikiStatus.public)
|
@CheckWikiStatus(WikiStatus.public)
|
||||||
@UseGuards(WikiStatusGuard)
|
@UseGuards(WikiStatusGuard)
|
||||||
async getPublicWikiTocs(@Param('id') wikiId) {
|
async getPublicWikiTocs(@Param('id') wikiId) {
|
||||||
|
@ -324,7 +324,7 @@ export class WikiController {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post(WikiApiDefinition.getPublicDetailById.server)
|
@Get(WikiApiDefinition.getPublicDetailById.server)
|
||||||
@CheckWikiStatus(WikiStatus.public)
|
@CheckWikiStatus(WikiStatus.public)
|
||||||
@UseGuards(WikiStatusGuard)
|
@UseGuards(WikiStatusGuard)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
|
|
@ -36,12 +36,7 @@ export class DocumentStatusGuard implements CanActivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.status !== targetStatus) {
|
if (document.status !== targetStatus) {
|
||||||
throw new HttpException(
|
throw new HttpException('私有文档,无法查看内容', HttpStatus.FORBIDDEN);
|
||||||
targetStatus === DocumentStatus.private
|
|
||||||
? '私有文档,无法查看内容'
|
|
||||||
: '公共文档,无法查看内容,请提 issue 到 GitHub 仓库反馈',
|
|
||||||
HttpStatus.FORBIDDEN
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -27,12 +27,7 @@ export class WikiStatusGuard implements CanActivate {
|
||||||
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (wiki.status !== targetStatus) {
|
if (wiki.status !== targetStatus) {
|
||||||
throw new HttpException(
|
throw new HttpException('私有知识库,无法查看内容', HttpStatus.FORBIDDEN);
|
||||||
targetStatus === WikiStatus.private
|
|
||||||
? '私有知识库,无法查看内容'
|
|
||||||
: '公共知识库,无法查看内容,请提 issue 到 GitHub 仓库反馈',
|
|
||||||
HttpStatus.FORBIDDEN
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13,15 +13,12 @@ import { AppModule } from './app.module';
|
||||||
import { AppClusterService } from './app-cluster.service';
|
import { AppClusterService } from './app-cluster.service';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule, {
|
const app = await NestFactory.create(AppModule);
|
||||||
logger: false,
|
|
||||||
});
|
|
||||||
const config = app.get(ConfigService);
|
const config = app.get(ConfigService);
|
||||||
const port = config.get('server.port') || 5002;
|
const port = config.get('server.port') || 5002;
|
||||||
|
|
||||||
app.enableCors({
|
app.enableCors({
|
||||||
// TODO: fixme
|
origin: config.get('client.siteUrl'),
|
||||||
origin: 'http://localhost:5001',
|
|
||||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
|
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
|
||||||
credentials: true,
|
credentials: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -425,7 +425,7 @@ export class DocumentService {
|
||||||
// 5. 生成响应
|
// 5. 生成响应
|
||||||
const doc = instanceToPlain(document);
|
const doc = instanceToPlain(document);
|
||||||
const createUser = await this.userService.findById(doc.createUserId);
|
const createUser = await this.userService.findById(doc.createUserId);
|
||||||
return { document: { ...doc, views, createUser }, authority };
|
return { document: lodash.omit({ ...doc, views, createUser }, ['state']), authority };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -453,6 +453,7 @@ export class DocumentService {
|
||||||
const newData = await this.documentRepo.merge(document, {
|
const newData = await this.documentRepo.merge(document, {
|
||||||
status: nextStatus,
|
status: nextStatus,
|
||||||
...dto,
|
...dto,
|
||||||
|
sharePassword: dto.sharePassword || '',
|
||||||
});
|
});
|
||||||
const ret = await this.documentRepo.save(newData);
|
const ret = await this.documentRepo.save(newData);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -469,7 +470,7 @@ export class DocumentService {
|
||||||
throw new HttpException('输入密码后查看内容', HttpStatus.BAD_REQUEST);
|
throw new HttpException('输入密码后查看内容', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.sharePassword !== dto.sharePassword) {
|
if (document.sharePassword && document.sharePassword !== dto.sharePassword) {
|
||||||
throw new HttpException('密码错误,请重新输入', HttpStatus.BAD_REQUEST);
|
throw new HttpException('密码错误,请重新输入', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ export class UserService {
|
||||||
* @param user
|
* @param user
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async login(user: LoginUserDto): Promise<{ user: OutUser; token: string }> {
|
async login(user: LoginUserDto): Promise<{ user: OutUser; token: string; domain: string; expiresIn: number }> {
|
||||||
const { name, password } = user;
|
const { name, password } = user;
|
||||||
const existUser = await this.userRepo.findOne({ where: { name } });
|
const existUser = await this.userRepo.findOne({ where: { name } });
|
||||||
|
|
||||||
|
@ -125,7 +125,11 @@ export class UserService {
|
||||||
|
|
||||||
const res = instanceToPlain(existUser) as OutUser;
|
const res = instanceToPlain(existUser) as OutUser;
|
||||||
const token = this.jwtService.sign(res);
|
const token = this.jwtService.sign(res);
|
||||||
return { user: res, token };
|
const domain = this.confifgService.get('client.siteDomain');
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
const expiresIn = this.jwtService.decode(token, { complete: true }).payload.exp;
|
||||||
|
return { user: res, token, domain, expiresIn };
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateUser(user: UserEntity) {
|
async validateUser(user: UserEntity) {
|
||||||
|
|
|
@ -540,6 +540,7 @@ export class WikiService {
|
||||||
documents.sort((a, b) => a.index - b.index);
|
documents.sort((a, b) => a.index - b.index);
|
||||||
|
|
||||||
documents.forEach((doc) => {
|
documents.forEach((doc) => {
|
||||||
|
delete doc.content;
|
||||||
delete doc.state;
|
delete doc.state;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -654,6 +655,7 @@ export class WikiService {
|
||||||
|
|
||||||
docs.forEach((doc) => {
|
docs.forEach((doc) => {
|
||||||
delete doc.state;
|
delete doc.state;
|
||||||
|
delete doc.content;
|
||||||
});
|
});
|
||||||
|
|
||||||
return array2tree(docs);
|
return array2tree(docs);
|
||||||
|
|
|
@ -134,7 +134,6 @@ importers:
|
||||||
react-query: ^3.39.0
|
react-query: ^3.39.0
|
||||||
react-split-pane: ^0.1.92
|
react-split-pane: ^0.1.92
|
||||||
scroll-into-view-if-needed: ^2.2.29
|
scroll-into-view-if-needed: ^2.2.29
|
||||||
swr: ^1.2.0
|
|
||||||
timeago.js: ^4.0.2
|
timeago.js: ^4.0.2
|
||||||
tippy.js: ^6.3.7
|
tippy.js: ^6.3.7
|
||||||
toggle-selection: ^1.0.6
|
toggle-selection: ^1.0.6
|
||||||
|
@ -223,7 +222,6 @@ importers:
|
||||||
react-query: 3.39.0_react-dom@17.0.2+react@17.0.2
|
react-query: 3.39.0_react-dom@17.0.2+react@17.0.2
|
||||||
react-split-pane: 0.1.92_react-dom@17.0.2+react@17.0.2
|
react-split-pane: 0.1.92_react-dom@17.0.2+react@17.0.2
|
||||||
scroll-into-view-if-needed: 2.2.29
|
scroll-into-view-if-needed: 2.2.29
|
||||||
swr: 1.2.0_react@17.0.2
|
|
||||||
timeago.js: 4.0.2
|
timeago.js: 4.0.2
|
||||||
tippy.js: 6.3.7
|
tippy.js: 6.3.7
|
||||||
toggle-selection: 1.0.6
|
toggle-selection: 1.0.6
|
||||||
|
@ -238,7 +236,7 @@ importers:
|
||||||
eslint: 8.14.0
|
eslint: 8.14.0
|
||||||
eslint-config-prettier: 8.5.0_eslint@8.14.0
|
eslint-config-prettier: 8.5.0_eslint@8.14.0
|
||||||
eslint-plugin-import: 2.26.0_eslint@8.14.0
|
eslint-plugin-import: 2.26.0_eslint@8.14.0
|
||||||
eslint-plugin-prettier: 4.0.0_740be41c8168d0cc214a306089357ad0
|
eslint-plugin-prettier: 4.0.0_74ebb802163a9b4fa8f89d76ed02f62a
|
||||||
eslint-plugin-react: 7.29.4_eslint@8.14.0
|
eslint-plugin-react: 7.29.4_eslint@8.14.0
|
||||||
eslint-plugin-react-hooks: 4.5.0_eslint@8.14.0
|
eslint-plugin-react-hooks: 4.5.0_eslint@8.14.0
|
||||||
eslint-plugin-simple-import-sort: 7.0.0_eslint@8.14.0
|
eslint-plugin-simple-import-sort: 7.0.0_eslint@8.14.0
|
||||||
|
@ -5445,6 +5443,22 @@ packages:
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/eslint-plugin-prettier/4.0.0_74ebb802163a9b4fa8f89d76ed02f62a:
|
||||||
|
resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>=7.28.0'
|
||||||
|
eslint-config-prettier: '*'
|
||||||
|
prettier: '>=2.0.0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
eslint-config-prettier:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
eslint: 8.14.0
|
||||||
|
eslint-config-prettier: 8.5.0_eslint@8.14.0
|
||||||
|
prettier-linter-helpers: 1.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-react-hooks/4.5.0_eslint@8.14.0:
|
/eslint-plugin-react-hooks/4.5.0_eslint@8.14.0:
|
||||||
resolution: {integrity: sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==}
|
resolution: {integrity: sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -10390,14 +10404,6 @@ packages:
|
||||||
resolution: {integrity: sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=}
|
resolution: {integrity: sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/swr/1.2.0_react@17.0.2:
|
|
||||||
resolution: {integrity: sha512-C3IXeKOREn0jQ1ewXRENE7ED7jjGbFTakwB64eLACkCqkF/A0N2ckvpCTftcaSYi5yV36PzoehgVCOVRmtECcA==}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
|
||||||
dependencies:
|
|
||||||
react: 17.0.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/symbol-observable/4.0.0:
|
/symbol-observable/4.0.0:
|
||||||
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
|
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
|
|
Loading…
Reference in New Issue