@lark-apaas/coding-template-nestjs-react-fullstack 0.1.55-alpha.20261030035108 → 0.1.55-alpha.20261030085054
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/client/src/components/business-ui/README.md +1 -1
- package/template/client/src/components/business-ui/comment/README.md +4 -34
- package/template/client/src/components/business-ui/comment/comment-input.tsx +7 -8
- package/template/client/src/components/business-ui/comment/content.ts +1 -3
- package/template/client/src/components/business-ui/comment/editor.tsx +337 -414
- package/template/client/src/components/business-ui/comment/entity-mention.ts +276 -0
- package/template/client/src/components/business-ui/comment/mention-appearance.ts +1 -1
- package/template/client/src/components/business-ui/comment/types.ts +1 -37
- package/template/package-lock.json +540 -0
- package/template/package.json +11 -1
- package/template/client/src/components/business-ui/comment/dom-editor.ts +0 -581
- package/template/client/src/components/business-ui/comment/image-attachments.tsx +0 -374
package/package.json
CHANGED
|
@@ -522,7 +522,7 @@ function BasicExample() {
|
|
|
522
522
|
|
|
523
523
|
`comment/comment-content.tsx` 提供不依赖 Tiptap 的只读展示,配合 `comment/mention-provider.tsx` 批量补全人员和文档信息。
|
|
524
524
|
|
|
525
|
-
评论输入框已内置。从 `@/components/business-ui/comment/comment-input` 直接导入 `CommentInput`,组件提供 getContent/clear/setEditable/focus ref API 和 onSubmitRequest
|
|
525
|
+
评论输入框已内置。从 `@/components/business-ui/comment/comment-input` 直接导入 `CommentInput`,组件提供 getContent/clear/setEditable/focus ref API 和 onSubmitRequest 快捷键回调,发送、取消按钮及请求状态由页面组合,首次激活时动态加载最小 Tiptap 编辑器。只读 `CommentContent` 不依赖编辑器。作者、时间、线程与接口调用由消费页面组合。
|
|
526
526
|
|
|
527
527
|
数据源和真实服务的接入要求见 [CommentInput 使用说明](./comment/README.md)。输入与只读列表应共享同一 CommentProvider;CCM 的 Lark ID 与模板的 apaas ID 不能混用。
|
|
528
528
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
面向 AI 生成的多维表格评论界面,只提供两个基础组件:
|
|
4
4
|
|
|
5
5
|
- `CommentContent`:直接渲染 `reply.content`,内部补全人员与文档信息。
|
|
6
|
-
- `CommentInput
|
|
6
|
+
- `CommentInput`:编辑文字、@人员与文档,暴露 ref API。按钮、请求、loading 和发送错误由页面组合。
|
|
7
7
|
|
|
8
8
|
作者、时间、评论线程、回复、分页和解决状态均由业务页面处理。组件不包含这些业务包装。
|
|
9
9
|
|
|
@@ -20,7 +20,7 @@ type CommentApiContent =
|
|
|
20
20
|
|
|
21
21
|
userID 是妙搭用户 ID,与 UserDisplay 一致。缺失 userID 的历史 mention 显示“引用信息缺失”,读取时仍原样返回,是否提交由页面决定。数字 ID 不得静默舍入。
|
|
22
22
|
|
|
23
|
-
文档通过 link(url) 提交,内部 token、类型、标题和图标不进入接口数据。识别出的飞书文档 URL 可按 token 补全元数据;其他 URL
|
|
23
|
+
文档通过 link(url) 提交,内部 token、类型、标题和图标不进入接口数据。识别出的飞书文档 URL 可按 token 补全元数据;其他 URL 显示为普通链接。图片和旧 CCM `<at>` 内容格式不在组件范围内。
|
|
24
24
|
|
|
25
25
|
## 使用
|
|
26
26
|
|
|
@@ -73,13 +73,11 @@ export function CommentExample({ save }: { save: (body: CommentSubmitPayload) =>
|
|
|
73
73
|
|
|
74
74
|
- `getContent()`:读取最新接口 content,不做发送状态校验;编辑器尚未加载时也可读取草稿。
|
|
75
75
|
- `clear()`:普通的正文清空操作,保留撤销历史,不重建编辑会话。
|
|
76
|
-
- `
|
|
77
|
-
- `clearImages()`:删除全部附件并取消/忽略上传,释放本地预览地址。附件独立于正文撤销历史。
|
|
78
|
-
- `setEditable(boolean)`:控制正文、上传按钮及附件删除/重试;disabled prop 是外部硬禁用。
|
|
76
|
+
- `setEditable(boolean)`:控制编辑;disabled prop 是外部硬禁用。
|
|
79
77
|
- `focus()`:聚焦输入框,必要时加载编辑器。
|
|
80
78
|
- `onSubmitRequest`:Enter(或 submitMode="mod-enter")通知页面;输入法确认和 @候选选择优先处理,未配置时 Enter 换行。
|
|
81
79
|
|
|
82
|
-
入口动态 import
|
|
80
|
+
入口动态 import 最小 Tiptap 3.20.0,首次激活时挂载编辑器;只读组件不导入 Tiptap。加载失败可重试。popover 挂在 Dialog/Sheet 时可传 portalContainer。
|
|
83
81
|
|
|
84
82
|
## 搜索与回显
|
|
85
83
|
|
|
@@ -109,31 +107,3 @@ const documents = createCcmDocumentSource({
|
|
|
109
107
|
CommentContent 的 onMentionClick(ref, anchor) 仅透出人员点击,由消费页面复用 UserProfile。元数据加载前也可点击,回显更新保持锚点 DOM 稳定。
|
|
110
108
|
|
|
111
109
|
在生成应用中运行 `npm run type:check:client` 和 `npm run build:client`;浏览器中另行验证中文输入法、键盘候选操作、撤销、回填和弹层位置。类型检查与构建不代表真实接口鉴权或视觉验收完成。
|
|
112
|
-
|
|
113
|
-
## 图片附件与权限意图
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
<CommentInput
|
|
117
|
-
ref={inputRef}
|
|
118
|
-
documentKey="new"
|
|
119
|
-
value={value}
|
|
120
|
-
onChange={setValue}
|
|
121
|
-
enableDocuments
|
|
122
|
-
enableImages
|
|
123
|
-
onImagesChange={setImages}
|
|
124
|
-
grantMentionAccess={grantMentionAccess}
|
|
125
|
-
onGrantMentionAccessChange={setGrantMentionAccess}
|
|
126
|
-
/>
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
图片区按参考图排列在正文下方,64px 缩略图、圆角与右上角删除按钮;点击缩略图可预览。选择文件、粘贴或拖入正文均追加到附件区,不占正文光标位置。支持 PNG/JPEG/WebP/GIF/AVIF/BMP;默认最多 9 张、单张 10 MiB,通过 maxImages/maxImageSize 调整。最多 3 个并发上传,上传中显示加载状态,失败可重试。
|
|
130
|
-
|
|
131
|
-
默认延迟导入模板已有的 api/files/service 上传到妙搭存储。可通过 uploadImage(file, { signal }) 注入自定义服务,返回 `{ id, url, filePath?, bucketId? }`。删除、clearImages、切换 documentKey、切换数据源作用域和卸载都会取消或忽略迟到的上传结果;默认 SDK 不支持真正取消网络请求。删除和卸载时释放 Object URL;失败文件仅保留到重试或删除。
|
|
132
|
-
|
|
133
|
-
getImages 返回 `{ id, name, size, previewUrl, status, result?, error? }[]`:id 是本地附件 ID,result.id 才是服务端文件 ID;previewUrl 是临时 Blob URL,不能提交或持久化。页面通过 onImagesChange 判断是否仍有 uploading/error 状态,自行控制发送按钮,并把 result 映射到真实接口。当前未确认多维表格图片提交协议,因此 getContent 继续只返回 text/mention/link,CommentContent 继续只渲染正文。
|
|
134
|
-
|
|
135
|
-
如需在发送成功后重置整个输入区,依次调用 clear() 与 clearImages()。这两个方法不执行发送校验,也不处理发送失败;失败时是否保留内容由页面决定。切换 documentKey 表示新会话,正文撤销和附件都重置。
|
|
136
|
-
|
|
137
|
-
“授予提及的人阅读权限”仅在传入 onGrantMentionAccessChange 时显示,属于受控的业务意图,组件不直接调用文档授权接口。消费页面负责结合勾选值执行真实授权。
|
|
138
|
-
|
|
139
|
-
正文使用统一的自有撤销历史,覆盖文字、引用插入/删除、粘贴和 clear。连续文字合并为一组,输入法组合输入作为一组;元数据回显不产生编辑历史,外部替换 value 会重置正文历史。保留旧结构转换函数供已有调用方过渡,新实现不使用它们。
|
|
@@ -18,7 +18,11 @@ import type {
|
|
|
18
18
|
CommentInputHandle,
|
|
19
19
|
CommentEditorProps,
|
|
20
20
|
} from './types';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
emptyComment,
|
|
23
|
+
normalizeValue,
|
|
24
|
+
readApiContent,
|
|
25
|
+
} from './content';
|
|
22
26
|
|
|
23
27
|
let modulePromise: Promise<typeof import('./editor')> | undefined;
|
|
24
28
|
function loadEditor() {
|
|
@@ -32,7 +36,7 @@ export function preloadCommentEditor() {
|
|
|
32
36
|
void loadEditor().catch(() => {});
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
/** Public entry
|
|
39
|
+
/** Public entry contains no static import of Tiptap. A session change resets all work. */
|
|
36
40
|
export function CommentInput(props: CommentInputProps) {
|
|
37
41
|
const { store } = useMentionContext();
|
|
38
42
|
try {
|
|
@@ -108,11 +112,6 @@ function InputSession(props: CommentInputProps) {
|
|
|
108
112
|
() => ({
|
|
109
113
|
getContent: () =>
|
|
110
114
|
editorRef.current?.getContent() ?? readApiContent(latest.current.value),
|
|
111
|
-
getImages: () => editorRef.current?.getImages() ?? [],
|
|
112
|
-
clearImages() {
|
|
113
|
-
if (!alive.current) return;
|
|
114
|
-
editorRef.current?.clearImages();
|
|
115
|
-
},
|
|
116
115
|
clear() {
|
|
117
116
|
if (!alive.current) return;
|
|
118
117
|
if (editorRef.current) editorRef.current.clear();
|
|
@@ -125,7 +124,7 @@ function InputSession(props: CommentInputProps) {
|
|
|
125
124
|
setEditable(next) {
|
|
126
125
|
if (!alive.current) return;
|
|
127
126
|
editable.current = next;
|
|
128
|
-
editorRef.current?.setEditable(next);
|
|
127
|
+
editorRef.current?.setEditable(next && !latest.current.disabled);
|
|
129
128
|
setEnabled(next);
|
|
130
129
|
},
|
|
131
130
|
focus() {
|
|
@@ -155,7 +155,7 @@ export function mentionLabel(
|
|
|
155
155
|
return (!strict && label) || (ref.kind === 'user' ? '用户' : '文档');
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
/**
|
|
158
|
+
/** Deliberately structural: these utilities have no runtime or type import from Tiptap. */
|
|
159
159
|
export interface EditorDocument {
|
|
160
160
|
type?: string;
|
|
161
161
|
text?: string;
|
|
@@ -163,7 +163,6 @@ export interface EditorDocument {
|
|
|
163
163
|
content?: EditorDocument[];
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
/** @deprecated Retained for existing consumers; new code uses CommentValue directly. */
|
|
167
166
|
export function toEditorDocument(value: CommentValue): EditorDocument {
|
|
168
167
|
return {
|
|
169
168
|
type: 'doc',
|
|
@@ -195,7 +194,6 @@ export function toEditorDocument(value: CommentValue): EditorDocument {
|
|
|
195
194
|
};
|
|
196
195
|
}
|
|
197
196
|
|
|
198
|
-
/** @deprecated Retained for existing consumers; new code uses CommentValue directly. */
|
|
199
197
|
export function fromEditorDocument(doc: EditorDocument): CommentValue {
|
|
200
198
|
if (doc.type !== 'doc') throw new Error('无效的评论编辑文档');
|
|
201
199
|
const content: CommentPart[] = [];
|