diff --git a/cli/src/commands/declaration.ts b/cli/src/commands/declaration.ts index f10cb529..1482e245 100644 --- a/cli/src/commands/declaration.ts +++ b/cli/src/commands/declaration.ts @@ -44,13 +44,12 @@ export const declarationCommand: CommandModule = { content = "declare module '@capital/common';\ndeclare module '@capital/component';\n"; } else if (source === 'github') { - const spinner = ora('正在从 Github 下载插件类型声明').start(); + const url = + 'https://raw.githubusercontent.com/msgbyte/tailchat/master/client/web/tailchat.d.ts'; - content = await got - .get( - 'https://raw.githubusercontent.com/msgbyte/tailchat/master/client/web/tailchat.d.ts' - ) - .then((res) => res.body); + const spinner = ora(`正在从 Github 下载插件类型声明: ${url}`).start(); + + content = await got.get(url).then((res) => res.body); spinner.succeed('声明文件下载完毕'); } diff --git a/client/web/src/components/Panel/group/Wrapper.tsx b/client/web/src/components/Panel/group/Wrapper.tsx index 75eef4a2..3259fc15 100644 --- a/client/web/src/components/Panel/group/Wrapper.tsx +++ b/client/web/src/components/Panel/group/Wrapper.tsx @@ -1,4 +1,4 @@ -import React, { PropsWithChildren, useEffect } from 'react'; +import React, { PropsWithChildren, useEffect, useMemo } from 'react'; import { t, useGroupPanelInfo } from 'tailchat-shared'; import _isNil from 'lodash/isNil'; import { MembersPanel } from './MembersPanel'; @@ -46,26 +46,35 @@ export const GroupPanelWrapper: React.FC = React.memo( const panelInfo = useGroupPanelInfo(props.groupId, props.panelId); useRecordGroupPanel(props.groupId, props.panelId); + const { hasOpenedPanel, openPanelWindow, closePanelWindow } = + usePanelWindow(`/panel/group/${props.groupId}/${props.panelId}`); + + const groupPanelContextValue = useMemo( + () => ({ + groupId: props.groupId, + panelId: props.panelId, + }), + [props.groupId, props.panelId] + ); + if (_isNil(panelInfo)) { return null; } - const { hasOpenedPanel, openPanelWindow, closePanelWindow } = - usePanelWindow(`/panel/group/${props.groupId}/${props.panelId}`); if (hasOpenedPanel) { return ; } if (!props.showHeader) { return ( - + {props.children} ); } return ( - + [ diff --git a/client/web/src/plugin/component/index.tsx b/client/web/src/plugin/component/index.tsx index 60293832..91d78b4d 100644 --- a/client/web/src/plugin/component/index.tsx +++ b/client/web/src/plugin/component/index.tsx @@ -11,6 +11,7 @@ export { Switch, Tooltip, notification, + Empty, } from 'antd'; export { Avatar, SensitiveText } from 'tailchat-design'; export const TextArea = Input.TextArea; diff --git a/client/web/tailchat.d.ts b/client/web/tailchat.d.ts index 51d3e874..8fbeaea4 100644 --- a/client/web/tailchat.d.ts +++ b/client/web/tailchat.d.ts @@ -252,6 +252,8 @@ declare module '@capital/component' { */ export const notification: any; + export const Empty: any; + export const Avatar: any; export const SensitiveText: React.FC<{ className?: string; text: string }>; diff --git a/server/plugins/com.msgbyte.topic/models/topic.ts b/server/plugins/com.msgbyte.topic/models/topic.ts index 46161718..4e7f8172 100644 --- a/server/plugins/com.msgbyte.topic/models/topic.ts +++ b/server/plugins/com.msgbyte.topic/models/topic.ts @@ -1,5 +1,5 @@ import { db } from 'tailchat-server-sdk'; -const { getModelForClass, prop, TimeStamps } = db; +const { getModelForClass, prop, TimeStamps, modelOptions } = db; import type { Types } from 'mongoose'; import { nanoid } from 'nanoid'; @@ -22,6 +22,11 @@ class GroupTopicComment { replyCommentId?: string; } +@modelOptions({ + options: { + customName: 'p_topic', + }, +}) export class GroupTopic extends TimeStamps implements db.Base { _id: Types.ObjectId; id: string; diff --git a/server/plugins/com.msgbyte.topic/services/topic.service.ts b/server/plugins/com.msgbyte.topic/services/topic.service.ts index 65822e49..74ae939e 100644 --- a/server/plugins/com.msgbyte.topic/services/topic.service.ts +++ b/server/plugins/com.msgbyte.topic/services/topic.service.ts @@ -8,7 +8,6 @@ import { call, } from 'tailchat-server-sdk'; import type { GroupTopicDocument, GroupTopicModel } from '../models/topic'; -const { Types } = db; /** * 群组话题 @@ -24,6 +23,14 @@ class GroupTopicService extends TcService { onInit(): void { this.registerLocalDb(require('../models/topic').default); + this.registerAction('list', this.list, { + params: { + groupId: 'string', + panelId: 'string', + page: { type: 'number', optional: true }, + size: { type: 'number', optional: true }, + }, + }); this.registerAction('create', this.create, { params: { groupId: 'string', @@ -33,6 +40,42 @@ class GroupTopicService extends TcService { }); } + /** + * 获取所有Topic + */ + async list( + ctx: TcContext<{ + groupId: string; + panelId: string; + page?: number; + size?: number; + }> + ) { + const { groupId, panelId, page = 1, size = 20 } = ctx.params; + const userId = ctx.meta.userId; + const t = ctx.meta.t; + + // 鉴权 + const group = await call(ctx).getGroupInfo(groupId); + const isMember = group.members.some((member) => member.userId === userId); + if (!isMember) { + throw new Error(t('不是该群组成员')); + } + + const topic = await this.adapter.model + .find({ + groupId, + panelId, + }) + .limit(size) + .skip((page - 1) * 20) + .exec(); + + const json = await this.transformDocuments(ctx, {}, topic); + + return json; + } + /** * 创建一条Topic */ @@ -59,18 +102,12 @@ class GroupTopicService extends TcService { if (!targetPanel) { throw new Error(t('面板不存在')); } - const isPanelValid = - targetPanel.type === GroupPanelType.TEXT && - _.get(targetPanel, ['meta', 'variant']) === 'topic'; - if (!isPanelValid) { - throw new Error(t('面板类型不合法')); - } const topic = await this.adapter.model.create({ - groupId: new Types.ObjectId(groupId), + groupId, panelId, content, - author: new Types.ObjectId(userId), + author: userId, comment: [], }); diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx index 2aa9a4fc..dbb3ffae 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/group/GroupTopicPanelRender.tsx @@ -1,13 +1,39 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { TopicCard } from '../components/TopicCard'; +import { useAsyncRequest, useGroupPanelContext } from '@capital/common'; +import { Empty } from '@capital/component'; +import { request } from '../request'; import './GroupTopicPanelRender.less'; const GroupTopicPanelRender: React.FC = React.memo(() => { + const panelInfo = useGroupPanelContext(); + + const [{ value: list = [] }, fetch] = useAsyncRequest(async () => { + if (!panelInfo) { + return []; + } + + const { data } = await request.get('list', { + params: { + groupId: panelInfo.groupId, + panelId: panelInfo.panelId, + }, + }); + + return data; + }, [panelInfo]); + + useEffect(() => { + fetch(); + }, [fetch]); + return (
- {Array.from({ length: 20 }).map((_, i) => ( - - ))} + {Array.isArray(list) && list.length > 0 ? ( + list.map((_, i) => ) + ) : ( + + )}
); }); diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/request.ts b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/request.ts new file mode 100644 index 00000000..bca9c425 --- /dev/null +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/src/request.ts @@ -0,0 +1,3 @@ +import { createPluginRequest } from '@capital/common'; + +export const request = createPluginRequest('com.msgbyte.topic'); diff --git a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts index c59324aa..0ea783da 100644 --- a/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts +++ b/server/plugins/com.msgbyte.topic/web/plugins/com.msgbyte.topic/types/tailchat.d.ts @@ -1,5 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +/// + /** * 该文件由 Tailchat 自动生成 * 用于插件的类型声明 @@ -66,7 +68,7 @@ declare module '@capital/common' { export const appendUrlSearch: any; - export const useGroupIdContext: any; + export const getServiceWorkerRegistration: any; export const getServiceUrl: () => string; @@ -84,7 +86,14 @@ declare module '@capital/common' { export const getCachedConverseInfo: any; - export const localTrans: any; + /** + * 本地翻译 + * @example + * localTrans({'zh-CN': '你好', 'en-US': 'Hello'}); + * + * @param trans 翻译对象 + */ + export const localTrans: (trans: Record<'zh-CN' | 'en-US', string>) => string; export const getLanguage: any; @@ -114,7 +123,7 @@ declare module '@capital/common' { export const useLocation: any; - export const useHistory: any; + export const useNavigate: any; export const createFastFormSchema: any; @@ -205,6 +214,15 @@ declare module '@capital/common' { */ required?: string[]; }) => void; + + export const useGroupIdContext: () => string; + + export const useGroupPanelContext: () => { + groupId: string; + panelId: string; + } | null; + + export const useSocketContext: any; } /** @@ -215,6 +233,8 @@ declare module '@capital/component' { export const Checkbox: any; + export const Empty: any; + export const Input: any; export const Divider: any; @@ -301,4 +321,6 @@ declare module '@capital/component' { userId: string; className?: string; }>; + + export const Markdown: any; }