mirror of https://github.com/fantasticit/think.git
Merge pull request #139 from fantasticit/fix/13x
fix paste html, notify user who is mentioned
This commit is contained in:
commit
ac81cc8e31
|
@ -1,4 +1,5 @@
|
|||
import type { IPagination, IUser } from '@think/domains';
|
||||
import { IAuth, IUser, OrganizationApiDefinition } from '@think/domains';
|
||||
import Router from 'next/router';
|
||||
|
||||
import { HttpClient } from './http-client';
|
||||
|
||||
|
@ -9,3 +10,14 @@ export const register = (data: Partial<IUser>): Promise<IUser> => {
|
|||
export const getUsers = (): Promise<IUser[]> => {
|
||||
return HttpClient.get('/user');
|
||||
};
|
||||
|
||||
export const getMentionUser = (): Promise<{ data: Array<{ auth: IAuth; user: IUser }>; total: number }> => {
|
||||
const { organizationId } = Router.query;
|
||||
return HttpClient.request({
|
||||
method: OrganizationApiDefinition.getMembers.method,
|
||||
url: OrganizationApiDefinition.getMembers.client(organizationId as string),
|
||||
params: {
|
||||
pageSize: 10000,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import BulitInMention from '@tiptap/extension-mention';
|
||||
import { ReactRenderer } from '@tiptap/react';
|
||||
import { getUsers } from 'services/user';
|
||||
import { getMentionUser } from 'services/user';
|
||||
import tippy from 'tippy.js';
|
||||
import { MentionList } from 'tiptap/core/wrappers/mention-list';
|
||||
import { getDatasetAttribute } from 'tiptap/prose-utils';
|
||||
|
||||
const suggestion = {
|
||||
items: async ({ query }) => {
|
||||
const res = await getUsers();
|
||||
const data = res.map((item) => item.name);
|
||||
const res = await getMentionUser();
|
||||
const data = (res.data || []).map((item) => item.user.name);
|
||||
return data.filter((item) => item.toLowerCase().startsWith(query.toLowerCase()));
|
||||
},
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ interface IPasteOptions {
|
|||
|
||||
/**
|
||||
* 将 markdown 转换为 prosemirror 节点
|
||||
* FIXME: prosemirror 节点的类型是什么?
|
||||
*/
|
||||
markdownToProsemirror: (arg: { schema: Schema; content: string; needTitle: boolean }) => Node;
|
||||
|
||||
|
@ -111,8 +110,8 @@ export const Paste = Extension.create<IPasteOptions>({
|
|||
return true;
|
||||
}
|
||||
|
||||
// 新增:office 套件内容处理
|
||||
if (html?.includes('urn:schemas-microsoft-com:office')) {
|
||||
// FIXME:各家 office 套件标准不一样,是否需要做成用户自行选择粘贴 html 或者 图片?
|
||||
if (html?.length) {
|
||||
const doc = htmlToProsemirror({
|
||||
schema: editor.schema,
|
||||
html,
|
||||
|
|
|
@ -46,6 +46,7 @@ export const CollaborationEditor = forwardRef((props: ICollaborationEditorProps,
|
|||
targetId: documentId,
|
||||
userId: user && user.id,
|
||||
docType: type,
|
||||
editable,
|
||||
},
|
||||
maxAttempts: 1,
|
||||
onAwarenessUpdate: throttle(({ states }) => {
|
||||
|
@ -67,7 +68,7 @@ export const CollaborationEditor = forwardRef((props: ICollaborationEditorProps,
|
|||
setStatus(status);
|
||||
},
|
||||
} as any);
|
||||
}, [documentId, user, type, onAwarenessUpdate, toggleLoading]);
|
||||
}, [documentId, user, type, editable, onAwarenessUpdate, toggleLoading]);
|
||||
|
||||
useImperativeHandle(
|
||||
ref,
|
||||
|
|
|
@ -10,6 +10,25 @@ import { DocumentStatus, IUser } from '@think/domains';
|
|||
import * as lodash from 'lodash';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
export const findMentions = (content) => {
|
||||
const queue = [content];
|
||||
const res = [];
|
||||
|
||||
while (queue.length) {
|
||||
const node = queue.shift();
|
||||
|
||||
if (node.type === 'mention') {
|
||||
res.push(node.attrs.id);
|
||||
}
|
||||
|
||||
if (node.content && node.content.length) {
|
||||
queue.push(...node.content);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class CollaborationService {
|
||||
server: typeof Server;
|
||||
|
@ -244,6 +263,7 @@ export class CollaborationService {
|
|||
const targetId = requestParameters.get('targetId');
|
||||
const docType = requestParameters.get('docType');
|
||||
const userId = requestParameters.get('userId');
|
||||
const editable = requestParameters.get('editable');
|
||||
|
||||
if (docType === 'document') {
|
||||
const data = await this.documentService.findById(targetId);
|
||||
|
@ -252,6 +272,14 @@ export class CollaborationService {
|
|||
title: '未命名文档',
|
||||
});
|
||||
}
|
||||
|
||||
if (editable) {
|
||||
const content = data.content;
|
||||
const json = JSON.parse(content).default;
|
||||
const mentionUsers = findMentions(json);
|
||||
this.documentService.notifyMentionUsers(targetId, mentionUsers);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -727,4 +727,33 @@ export class DocumentService {
|
|||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知文档中 @ 的用户
|
||||
* @param documentId
|
||||
* @param mentionUsers
|
||||
* @returns
|
||||
*/
|
||||
public async notifyMentionUsers(documentId, mentionUsers) {
|
||||
const doc = await this.documentRepo.findOne(documentId);
|
||||
if (!doc) return;
|
||||
|
||||
await Promise.all(
|
||||
mentionUsers
|
||||
.map(async (userName) => {
|
||||
const user = await this.userService.findOne({ name: userName });
|
||||
if (!user) return null;
|
||||
return await this.messageService.notify(user.id, {
|
||||
title: `文档「${doc.title}」提及了您`,
|
||||
message: `文档「${doc.title}」提及了您,快去看看吧!`,
|
||||
url: buildMessageURL('toDocument')({
|
||||
organizationId: doc.organizationId,
|
||||
wikiId: doc.wikiId,
|
||||
documentId: doc.id,
|
||||
}),
|
||||
});
|
||||
})
|
||||
.filter(Boolean)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,14 @@ export class MessageService {
|
|||
*/
|
||||
async notify(userId: IUser['id'], msg) {
|
||||
const data = { userId, ...msg };
|
||||
const mayBeNotified = await this.messageRepo.findOne(data);
|
||||
|
||||
if (mayBeNotified) {
|
||||
if (!mayBeNotified.read) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const res = await this.messageRepo.create(data);
|
||||
const ret = await this.messageRepo.save(res);
|
||||
return ret;
|
||||
|
|
Loading…
Reference in New Issue