@lark-apaas/coding-template-nestjs-react-fullstack 0.1.60-alpha.20261105142153 → 0.1.60-beta.0

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.
Files changed (33) hide show
  1. package/package.json +1 -1
  2. package/template/client/src/components/business-ui/README.md +0 -2
  3. package/template/package-lock.json +30 -546
  4. package/template/package.json +3 -14
  5. package/template/scripts/build.sh +39 -22
  6. package/template/scripts/prune-smart.js +20 -1
  7. package/template/client/src/components/business-ui/comments/README.md +0 -101
  8. package/template/client/src/components/business-ui/comments/comments.tsx +0 -670
  9. package/template/client/src/components/business-ui/comments/contracts.ts +0 -256
  10. package/template/client/src/components/business-ui/comments/index.ts +0 -20
  11. package/template/client/src/components/business-ui/comments/use-comments.ts +0 -492
  12. package/template/client/src/components/business-ui/record-comments/README.md +0 -141
  13. package/template/client/src/components/business-ui/record-comments/app-source.ts +0 -93
  14. package/template/client/src/components/business-ui/record-comments/assets/reaction-sprite.png +0 -0
  15. package/template/client/src/components/business-ui/record-comments/comment-panel.contract.ts +0 -240
  16. package/template/client/src/components/business-ui/record-comments/comment-panel.tsx +0 -231
  17. package/template/client/src/components/business-ui/record-comments/extensions.ts +0 -130
  18. package/template/client/src/components/business-ui/record-comments/index.ts +0 -9
  19. package/template/client/src/components/business-ui/record-comments/internal/composer.tsx +0 -531
  20. package/template/client/src/components/business-ui/record-comments/internal/content.tsx +0 -213
  21. package/template/client/src/components/business-ui/record-comments/internal/discussion.tsx +0 -523
  22. package/template/client/src/components/business-ui/record-comments/internal/editor.tsx +0 -681
  23. package/template/client/src/components/business-ui/record-comments/internal/icons.tsx +0 -148
  24. package/template/client/src/components/business-ui/record-comments/internal/images.tsx +0 -155
  25. package/template/client/src/components/business-ui/record-comments/internal/mentions.tsx +0 -163
  26. package/template/client/src/components/business-ui/record-comments/internal/model.ts +0 -581
  27. package/template/client/src/components/business-ui/record-comments/internal/mutations.ts +0 -198
  28. package/template/client/src/components/business-ui/record-comments/internal/reaction-catalog.ts +0 -196
  29. package/template/client/src/components/business-ui/record-comments/internal/reactions.tsx +0 -683
  30. package/template/client/src/components/business-ui/record-comments/internal/styles.css +0 -1109
  31. package/template/client/src/components/business-ui/record-comments/internal/suggestions.tsx +0 -456
  32. package/template/client/src/components/business-ui/record-comments/internal/view-types.ts +0 -91
  33. package/template/client/src/components/business-ui/record-comments/types.ts +0 -121
@@ -1,198 +0,0 @@
1
- import type { MentionRef } from '../types';
2
- import type { DiscussionDraft, DiscussionImage, DiscussionReply, DiscussionThread } from './view-types';
3
- import type { CommentIDs, DeleteCommentResult, CommentMutationFailure } from '../comment-panel.contract';
4
- import { commentFailureMessage, normalizeValue, mentionKey } from './model';
5
-
6
- export interface LocalCommentMutation {
7
- id: string;
8
- kind: 'add' | 'edit' | 'delete';
9
- phase: 'sending' | 'failed' | 'uncertain' | 'confirmed';
10
- message?: string;
11
- }
12
- interface Operation extends LocalCommentMutation {
13
- thread: DiscussionThread;
14
- commentID: string;
15
- replyID: string;
16
- draft?: DiscussionDraft;
17
- author?: MentionRef;
18
- operationId?: string;
19
- createTime: number;
20
- wholeThread?: boolean;
21
- deletionUnknown?: boolean;
22
- authoritativeReply?: DiscussionReply;
23
- execute: () => Promise<CommentIDs | DeleteCommentResult>;
24
- }
25
- const contentKey = (reply: Pick<DiscussionReply, 'value'>) => JSON.stringify(normalizeValue(reply.value).content.map(part =>
26
- part.type === 'mention' ? part.ref.kind === 'document' && part.href ? ['link', part.href] : ['mention', mentionKey(part.ref)]
27
- : part.type === 'link' ? ['link', part.url] : part.type === 'text' ? ['text', part.text] : [part.type]));
28
- const imageKey = (images: readonly DiscussionImage[]) => JSON.stringify(images.map(({ id, url }) => [id, url]));
29
- const uncertain = (message: string) => Object.assign(new Error(message), { outcome: 'unknown' as const });
30
-
31
- /** Component-local overlay. Never writes the host's data or performs a request itself. */
32
- export class CommentMutations {
33
- private readonly options: { opaqueIDs?: boolean; unknownDeletion?: boolean; unknownErrors?: boolean; removePending?: boolean };
34
- constructor(options: { opaqueIDs?: boolean; unknownDeletion?: boolean; unknownErrors?: boolean; removePending?: boolean } = {}) { this.options = options; }
35
- private validID(id: unknown): id is string { return typeof id === 'string' && (this.options.opaqueIDs ? id.trim().length > 0 : /^\d+$/.test(id)); }
36
- private operations: Operation[] = [];
37
- private listeners = new Set<() => void>();
38
- private version = 0;
39
- private active = true;
40
- subscribe = (listener: () => void) => { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; };
41
- getVersion = () => this.version;
42
- private changed() { if (this.active) { this.version++; this.listeners.forEach((listener) => listener()); } }
43
- activate() { this.active = true; }
44
- private release(operation: Operation) {
45
- for (const image of operation.draft?.images ?? [])
46
- if (image.file && image.url.startsWith('blob:')) URL.revokeObjectURL(image.url);
47
- }
48
- dispose() {
49
- this.active = false;
50
- this.operations.forEach((operation) => this.release(operation));
51
- this.operations = [];
52
- }
53
- replyID(id: string) { return this.operations.find((operation) => operation.id === id)?.replyID ?? id; }
54
- private assertAvailable(commentID: string, replyID?: string) {
55
- if (!this.active) throw new Error('评论会话已关闭');
56
- if (this.operations.some((operation) => operation.commentID === commentID &&
57
- (operation.wholeThread || (operation.kind === 'add' && !operation.draft?.commentID) || operation.replyID === replyID)))
58
- throw new Error('该评论仍在处理中,请先完成同步或处理失败提示');
59
- }
60
- private start(operation: Operation) {
61
- this.operations.push(operation); this.changed();
62
- void this.run(operation);
63
- return operation.id;
64
- }
65
- add(thread: DiscussionThread | undefined, draft: DiscussionDraft, author: MentionRef | undefined, execute: () => Promise<CommentIDs>, operationId?: string) {
66
- if (thread) this.assertAvailable(thread.commentID);
67
- else if (!this.active) throw new Error('评论会话已关闭');
68
- const id = `local:${crypto.randomUUID()}`;
69
- const createTime = Math.floor(Date.now() / 1000);
70
- const commentID = thread?.commentID ?? `local:thread:${crypto.randomUUID()}`;
71
- return this.start({ id, operationId, kind: 'add', phase: 'sending', commentID, replyID: id,
72
- thread: thread ?? { commentID, creator: author ?? null, createTime, isSolved: false, replies: [] },
73
- draft: { ...draft, commentID: thread?.commentID, value: normalizeValue(draft.value), images: [...draft.images] }, author, createTime, execute });
74
- }
75
- edit(thread: DiscussionThread, replyID: string, draft: DiscussionDraft, execute: () => Promise<CommentIDs>) {
76
- this.assertAvailable(thread.commentID, replyID);
77
- return this.start({ id: `local:${crypto.randomUUID()}`, kind: 'edit', phase: 'sending',
78
- thread, commentID: thread.commentID, replyID, createTime: Math.floor(Date.now() / 1000),
79
- draft: { ...draft, value: normalizeValue(draft.value), images: [...draft.images] }, execute });
80
- }
81
- delete(thread: DiscussionThread, replyID: string, execute: () => Promise<DeleteCommentResult>) {
82
- // The UI always deletes one selected message, including the current body.
83
- const wholeThread = false;
84
- this.assertAvailable(thread.commentID, replyID);
85
- return this.start({ id: `local:${crypto.randomUUID()}`, kind: 'delete', phase: 'sending',
86
- thread, commentID: thread.commentID, replyID, wholeThread, createTime: Math.floor(Date.now() / 1000), execute });
87
- }
88
- private async run(operation: Operation) {
89
- operation.phase = 'sending'; operation.message = undefined; this.changed();
90
- try {
91
- const result = await operation.execute();
92
- if (!this.active) return;
93
- if (!this.validID(result.commentID)) throw uncertain('提交结果缺少有效评论 ID');
94
- if (operation.kind !== 'add' || operation.draft?.commentID !== undefined) {
95
- if (result.commentID !== operation.commentID) throw uncertain('提交结果与目标讨论不一致');
96
- }
97
- if (operation.kind === 'delete') {
98
- if (!('commentDeleted' in result) || typeof result.commentDeleted !== 'boolean') {
99
- if (!this.options.unknownDeletion) throw uncertain('删除结果未确认');
100
- operation.deletionUnknown = true;
101
- } else operation.wholeThread = result.commentDeleted;
102
- } else {
103
- if (!('replyID' in result) || !this.validID(result.replyID)) throw uncertain('提交结果缺少有效回复 ID');
104
- if (operation.kind === 'edit' && result.replyID !== operation.replyID) throw uncertain('编辑结果与目标回复不一致');
105
- operation.replyID = result.replyID;
106
- }
107
- if ('authoritativeReply' in result && result.authoritativeReply) operation.authoritativeReply = result.authoritativeReply as DiscussionReply;
108
- operation.commentID = result.commentID;
109
- operation.phase = 'confirmed';
110
- } catch (cause) {
111
- if (!this.active) return;
112
- const outcome = (cause as CommentMutationFailure | null)?.outcome;
113
- operation.phase = outcome === 'unknown' || (this.options.unknownErrors && outcome !== 'not-applied') ? 'uncertain' : 'failed';
114
- operation.message = commentFailureMessage(cause, '操作失败,请重试');
115
- }
116
- this.changed();
117
- }
118
- retry(id: string) {
119
- const operation = this.operations.find((item) => item.id === id);
120
- if (!operation || operation.phase !== 'failed' || !this.active) return;
121
- void this.run(operation);
122
- }
123
- dismiss(id: string) {
124
- const operation = this.operations.find((item) => item.id === id);
125
- if (!operation || !['failed', 'uncertain'].includes(operation.phase)) return;
126
- this.operations = this.operations.filter((item) => item !== operation);
127
- this.release(operation); this.changed();
128
- }
129
- private acknowledged(operation: Operation, base: readonly DiscussionThread[]) {
130
- // Only a server-echoed operation ID can correlate a write whose response was lost.
131
- if (operation.kind === 'add' && operation.operationId) {
132
- const matches = base.flatMap(thread => thread.replies.filter(reply =>
133
- reply.clientOperationId === operation.operationId &&
134
- (!operation.draft?.commentID || thread.commentID === operation.draft.commentID) &&
135
- (!operation.author || (reply.author && mentionKey(reply.author) === mentionKey(operation.author)))
136
- ).map(reply => ({ thread, reply })));
137
- if (matches.length === 1) {
138
- operation.commentID = matches[0].thread.commentID;
139
- operation.replyID = matches[0].reply.replyID;
140
- return true;
141
- }
142
- }
143
- const thread = base.find((item) => item.commentID === operation.commentID);
144
- const reply = thread?.replies.find((item) => item.replyID === operation.replyID);
145
- if (operation.kind === 'delete') return operation.wholeThread ? !thread : !reply;
146
- if (!reply) return false;
147
- if (operation.kind === 'add') return true;
148
- const before = operation.thread.replies.find((item) => item.replyID === operation.replyID)!;
149
- // A later authoritative edit wins even when another editor changed the text.
150
- // Compare server revisions, never the optimistic client wall clock.
151
- if (operation.phase === 'confirmed' && reply.updateTime !== undefined &&
152
- reply.updateTime > (before.updateTime ?? before.createTime)) return true;
153
- if (contentKey(reply) !== contentKey(operation.authoritativeReply ?? { value: operation.draft!.value })) return false;
154
- const images = operation.draft!.images;
155
- if (imageKey(images) === imageKey(before.images)) return true;
156
- return images.some((image) => image.file)
157
- ? reply.images.length === images.length && imageKey(reply.images) !== imageKey(before.images)
158
- : imageKey(reply.images) === imageKey(images);
159
- }
160
- reconcile(base: readonly DiscussionThread[]) {
161
- const finished = this.operations.filter((operation) => (operation.phase === 'confirmed' ||
162
- (operation.phase === 'uncertain' && (operation.kind !== 'add' || Boolean(operation.operationId)))) && this.acknowledged(operation, base));
163
- if (!finished.length) return;
164
- this.operations = this.operations.filter((operation) => !finished.includes(operation));
165
- finished.forEach((operation) => this.release(operation)); this.changed();
166
- }
167
- view(base: readonly DiscussionThread[]): DiscussionThread[] {
168
- let threads = base.map((thread) => ({ ...thread, replies: [...thread.replies] }));
169
- for (const operation of this.operations) {
170
- let thread = threads.find((item) => item.commentID === operation.commentID);
171
- if (operation.kind === 'delete' && (operation.phase === 'confirmed' || (this.options.removePending && operation.phase === 'sending'))) {
172
- if (operation.wholeThread) threads = threads.filter((item) => item !== thread);
173
- else if (thread) {
174
- thread.replies = thread.replies.filter((reply) => reply.replyID !== operation.replyID);
175
- if (!thread.replies.length && (operation.deletionUnknown || operation.phase === 'sending')) thread.verificationPending = true;
176
- }
177
- continue;
178
- }
179
- if (!thread) {
180
- thread = { ...operation.thread, commentID: operation.commentID, replies: [...operation.thread.replies] };
181
- threads.push(thread);
182
- }
183
- const index = thread.replies.findIndex((item) => item.replyID === operation.replyID);
184
- const before = thread.replies[index] ?? operation.thread.replies.find((item) => item.replyID === operation.replyID);
185
- const mutation: LocalCommentMutation = { id: operation.id, kind: operation.kind, phase: operation.phase, message: operation.message };
186
- const reply: DiscussionReply = operation.authoritativeReply ? {...operation.authoritativeReply, mutation} : operation.kind === 'add'
187
- ? { replyID: operation.replyID, author: operation.author ?? null, createTime: operation.createTime,
188
- value: operation.draft!.value, images: operation.draft!.images, reactions: [], mutation }
189
- : { ...before!, ...(operation.draft ? { value: operation.draft.value, images: operation.draft.images,
190
- edited: before?.edited || operation.phase === 'confirmed',
191
- updateTime: operation.phase === 'confirmed' ? operation.createTime : before?.updateTime } : {}), mutation };
192
- if (index < 0) thread.replies.push(reply); else thread.replies[index] = reply;
193
- if ((operation.kind === 'delete' && operation.wholeThread) || (operation.kind === 'add' && !operation.draft?.commentID))
194
- thread.replies = thread.replies.map((item) => ({ ...item, mutationBlocked: true }));
195
- }
196
- return threads.filter((thread) => thread.replies.length > 0 || thread.verificationPending || thread.listFooter);
197
- }
198
- }
@@ -1,196 +0,0 @@
1
-
2
-
3
- /** UD biz-react 6.11.4 Emoji: original zh-CN labels, order and sprite coordinates. */
4
- export const REACTION_SPRITE_SIZE = [1741, 1632] as const;
5
- export const DEFAULT_USED_REACTIONS = [
6
- 'MUSCLE',
7
- 'APPLAUSE',
8
- 'OK',
9
- 'THUMBSUP',
10
- 'HEART',
11
- 'JIAYI',
12
- 'DONE',
13
- 'BLUSH',
14
- 'FACEPALM',
15
- ];
16
- export const REACTION_CATALOG: ReadonlyArray<
17
- readonly [
18
- key: string,
19
- label: string,
20
- x: number,
21
- y: number,
22
- width: number,
23
- height: number,
24
- ]
25
- > = [
26
- ['OK', 'OK', 208, 576, 104, 96],
27
- ['THUMBSUP', '赞', 96, 1536, 96, 96],
28
- ['THANKS', '双手合十', 1549, 1248, 96, 96],
29
- ['MUSCLE', '加油', 288, 1056, 96, 96],
30
- ['FINGERHEART', '比心', 384, 1056, 96, 96],
31
- ['APPLAUSE', '鼓掌', 579, 768, 96, 96],
32
- ['FISTBUMP', '碰拳', 768, 1056, 96, 96],
33
- ['JIAYI', '+1', 1453, 672, 96, 96],
34
- ['DONE', '完成', 1069, 96, 96, 96],
35
- ['SMILE', '微笑', 1248, 1440, 96, 96],
36
- ['Delighted', '愉快', 864, 960, 96, 96],
37
- ['BeamingFace', '笑容满面', 877, 192, 96, 96],
38
- ['BLUSH', '呲牙', 0, 1152, 96, 96],
39
- ['LAUGH', '大笑', 1056, 1152, 96, 96],
40
- ['SMIRK', '坏笑', 194, 768, 97, 96],
41
- ['LOL', '笑哭', 0, 480, 108, 96],
42
- ['FACEPALM', '捂脸', 192, 1056, 96, 96],
43
- ['LOVE', '送心', 192, 1248, 96, 96],
44
- ['WINK', '调皮', 1440, 1536, 96, 96],
45
- ['PROUD', '得意', 1453, 864, 96, 96],
46
- ['WITTY', '灵光一闪', 512, 672, 102, 96],
47
- ['SMART', '机智', 1152, 1440, 96, 96],
48
- ['SCOWL', '惊呆', 0, 1440, 96, 96],
49
- ['THINKING', '思考', 1549, 1440, 96, 96],
50
- ['SOB', '流泪', 1549, 0, 96, 96],
51
- ['CRY', '泣不成声', 973, 480, 96, 96],
52
- ['ERROR', '黑线', 0, 1056, 96, 96],
53
- ['NOSEPICK', '抠鼻', 1453, 96, 96, 96],
54
- ['HAUGHTY', '烦躁', 768, 1152, 96, 96],
55
- ['SLAP', '打脸', 864, 1440, 96, 96],
56
- ['SPITBLOOD', '吐血', 410, 672, 102, 96],
57
- ['TOASTED', '衰', 192, 1536, 96, 96],
58
- ['ColdSweat', '冷汗', 973, 96, 96, 96],
59
- ['BLACKFACE', '新月脸', 877, 576, 96, 96],
60
- ['FullMoonFace', '满月脸', 1056, 1056, 96, 96],
61
- ['GLANCE', '看', 1165, 864, 96, 96],
62
- ['DULL', '呆无辜', 1069, 480, 96, 96],
63
- ['ROSE', '玫瑰', 1453, 1248, 96, 96],
64
- ['HEART', '爱心', 192, 1152, 96, 96],
65
- ['PARTY', '撒花', 1453, 288, 96, 96],
66
- ['INNOCENTSMILE', '无辜笑', 672, 1152, 96, 96],
67
- ['SHY', '害羞', 384, 1440, 96, 96],
68
- ['CHUCKLE', '偷笑', 672, 864, 96, 96],
69
- ['JOYFUL', '笑', 864, 1152, 96, 96],
70
- ['WOW', '惊喜', 1536, 1536, 96, 96],
71
- ['TRICK', '嬉笑', 384, 1536, 96, 96],
72
- ['YEAH', '耶', 614, 672, 102, 96],
73
- ['ENOUGH', '我想静静', 557, 384, 108, 96],
74
- ['TEARS', '泪奔', 1549, 960, 96, 96],
75
- ['EMBARRASSED', '尬笑', 1069, 960, 96, 96],
76
- ['KISS', '亲亲', 960, 1152, 96, 96],
77
- ['SMOOCH', '飞吻', 777, 192, 100, 96],
78
- ['DROOL', '爱慕', 1069, 192, 96, 96],
79
- ['OBSESSED', '心心脸', 384, 1152, 96, 96],
80
- ['MONEY', '财迷', 1248, 1344, 96, 96],
81
- ['TEASE', '做鬼脸', 1549, 1056, 96, 96],
82
- ['SHOWOFF', '酷', 288, 1440, 96, 96],
83
- ['COMFORT', '摸头', 973, 192, 96, 96],
84
- ['CLAP', '欢呼', 206, 672, 102, 96],
85
- ['PRAISE', '强', 0, 672, 103, 96],
86
- ['STRIVE', '奋斗', 1549, 864, 96, 96],
87
- ['XBLUSH', '脸红', 877, 768, 96, 96],
88
- ['SILENT', '闭嘴', 672, 1440, 96, 96],
89
- ['WAVE', '再见', 777, 384, 99, 96],
90
- ['WHAT', '什么?', 520, 576, 104, 96],
91
- ['FROWN', '皱眉', 960, 1056, 96, 96],
92
- ['DIZZY', '晕', 1069, 0, 96, 96],
93
- ['LOOKDOWN', '鄙视', 0, 1248, 96, 96],
94
- ['WAIL', '大哭', 447, 384, 110, 96],
95
- ['CRAZY', '抓狂', 973, 288, 96, 96],
96
- ['WHIMPER', '可怜', 1344, 1536, 96, 96],
97
- ['HUG', '求抱抱', 338, 288, 132, 96],
98
- ['BLUBBER', '快哭了', 877, 672, 96, 96],
99
- ['WRONGED', '委屈', 1645, 0, 96, 96],
100
- ['HUSKY', '翻白眼', 576, 1152, 96, 96],
101
- ['SHHH', '嘘', 192, 1440, 96, 96],
102
- ['SMUG', '撇嘴', 1344, 1440, 96, 96],
103
- ['ANGRY', '发怒', 483, 768, 96, 96],
104
- ['HAMMER', '敲打', 96, 1152, 96, 96],
105
- ['SHOCKED', '震惊', 324, 480, 107, 96],
106
- ['TERROR', '惊恐', 1549, 1152, 96, 96],
107
- ['PETRIFIED', '石化', 1453, 480, 96, 96],
108
- ['SKULL', '骷髅', 768, 1440, 96, 96],
109
- ['SWEAT', '汗', 777, 288, 100, 96],
110
- ['SPEECHLESS', '无语', 103, 672, 103, 96],
111
- ['SLEEP', '鼾睡', 960, 1440, 96, 96],
112
- ['DROWSY', '困', 1069, 288, 96, 96],
113
- ['YAWN', '哈欠', 1645, 288, 96, 96],
114
- ['SICK', '戴口罩', 480, 1440, 96, 96],
115
- ['PUKE', '吐', 1453, 960, 96, 96],
116
- ['BETRAYED', '背叛', 877, 384, 96, 96],
117
- ['HEADSET', '听歌', 431, 480, 106, 96],
118
- ['EatingFood', '吃饭', 1069, 768, 96, 96],
119
- ['Typing', '敲键盘', 864, 1536, 96, 96],
120
- ['Lemon', '柠檬', 1152, 1152, 96, 96],
121
- ['Get', '了解', 1165, 672, 96, 96],
122
- ['LGTM', '我看行', 0, 768, 97, 96],
123
- ['OnIt', '在做了', 337, 384, 110, 96],
124
- ['OneSecond', '稍等', 216, 480, 108, 96],
125
- ['Sigh', '叹气', 576, 1440, 96, 96],
126
- ['MeMeMe', '举手', 108, 480, 108, 96],
127
- ['VRHeadset', 'VR', 1056, 1536, 96, 96],
128
- ['GoGoGo', '冲!', 671, 96, 105, 96],
129
- ['Partying', '派对', 416, 576, 104, 96],
130
- ['ThanksFace', '感谢', 1549, 1344, 96, 96],
131
- ['SaluteFace', '致敬', 671, 192, 105, 96],
132
- ['Shrug', '耸肩摊手', 777, 96, 100, 96],
133
- ['YouAreTheBest', '送你小红花', 1645, 384, 96, 96],
134
- ['SALUTE', '抱拳', 1453, 1344, 96, 96],
135
- ['SHAKE', '握手', 96, 1440, 96, 96],
136
- ['HIGHFIVE', '击掌', 480, 1152, 96, 96],
137
- ['WavingHand', '挥手', 1152, 1536, 96, 96],
138
- ['UPPERLEFT', '点击', 864, 864, 96, 96],
139
- ['ThumbsDown', '踩', 0, 1536, 96, 96],
140
- ['ClownFace', '小丑脸', 973, 0, 96, 96],
141
- ['SLIGHT', '白眼', 1056, 1440, 96, 96],
142
- ['TONGUE', '吐舌', 288, 1536, 96, 96],
143
- ['EYESCLOSED', '不看', 96, 1056, 96, 96],
144
- ['BEAR', '啊?', 117, 384, 110, 96],
145
- ['BULL', '公牛', 192, 864, 96, 96],
146
- ['CALF', '小牛', 384, 864, 96, 96],
147
- ['LIPS', '嘴唇', 1261, 1152, 96, 96],
148
- ['BEER', '啤酒', 877, 288, 96, 96],
149
- ['CAKE', '蛋糕', 288, 864, 96, 96],
150
- ['GIFT', '礼物', 1165, 768, 96, 96],
151
- ['CUCUMBER', '胡瓜', 973, 576, 96, 96],
152
- ['Drumstick', '鸡腿', 1069, 384, 96, 96],
153
- ['Pepper', '辣椒', 1453, 384, 96, 96],
154
- ['CANDIEDHAWS', '冰糖葫芦', 480, 864, 96, 96],
155
- ['BubbleTea', '奶茶', 96, 864, 96, 96],
156
- ['Coffee', '咖啡', 671, 384, 104, 96],
157
- ['Yes', 'Yes', 624, 576, 104, 96],
158
- ['No', 'No', 104, 576, 104, 96],
159
- ['OKR', 'OKR', 312, 576, 104, 96],
160
- ['CheckMark', '勾号', 576, 864, 96, 96],
161
- ['CrossMark', '叉号', 973, 384, 96, 96],
162
- ['MinusOne', '-1', 1152, 1344, 96, 96],
163
- ['Hundred', '100分', 0, 576, 104, 96],
164
- ['AWESOMEN', '牛', 771, 768, 96, 96],
165
- ['Pin', '图钉', 1453, 576, 96, 96],
166
- ['Alarm', '闹钟', 387, 768, 96, 96],
167
- ['Loudspeaker', '喇叭', 96, 1248, 96, 96],
168
- ['Trophy', '奖杯', 480, 1536, 96, 96],
169
- ['Fire', '火', 480, 1056, 96, 96],
170
- ['RAINBOWPUKE', '彩虹', 1453, 1056, 96, 96],
171
- ['Music', '音乐', 1453, 0, 96, 96],
172
- ['TV', '电视', 576, 1536, 96, 96],
173
- ['Movie', '电影', 1344, 1344, 96, 96],
174
- ['Pumpkin', '南瓜灯', 777, 0, 100, 96],
175
- ['XmasTree', '圣诞树', 1645, 192, 96, 96],
176
- ['Snowman', '雪人', 1440, 1440, 96, 96],
177
- ['XmasHat', '圣诞帽', 1645, 96, 96, 96],
178
- ['FIREWORKS', '烟花', 672, 1056, 96, 96],
179
- ['2023', '2023', 291, 768, 96, 96],
180
- ['JubilantRabbit', '欢兔喝彩', 227, 384, 110, 96],
181
- ['REDPACKET', '红包', 1453, 1152, 96, 96],
182
- ['FORTUNE', '发', 864, 1056, 96, 96],
183
- ['LUCK', '福', 288, 1248, 96, 96],
184
- ['FIRECRACKER', '爆竹', 576, 1056, 96, 96],
185
- ['StickyRiceBalls', '元宵', 671, 0, 106, 96],
186
- ['Mooncake', '月饼', 97, 768, 97, 96],
187
- ['MoonRabbit', '玉兔', 537, 480, 106, 96],
188
- ['HEARTBROKEN', '心碎', 288, 1152, 96, 96],
189
- ['BOMB', '炸弹', 0, 864, 96, 96],
190
- ['POOP', '便便', 1453, 768, 96, 96],
191
- ['18X', '18禁', 1069, 864, 96, 96],
192
- ['CLEAVER', '刀', 768, 864, 96, 96],
193
- ['Basketball', '篮球', 877, 96, 96, 96],
194
- ['Soccer', '足球', 1549, 96, 96, 96],
195
- ['GeneralDoNotDisturb', '请勿打扰', 1165, 192, 96, 96],
196
- ];