@lark-apaas/coding-template-nestjs-react-fullstack 0.1.56 → 0.1.57-alpha.20261103143319
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 +2 -0
- package/template/client/src/components/business-ui/record-comments/README.md +141 -0
- package/template/client/src/components/business-ui/record-comments/app-source.ts +93 -0
- package/template/client/src/components/business-ui/record-comments/assets/reaction-sprite.png +0 -0
- package/template/client/src/components/business-ui/record-comments/comment-panel.contract.ts +240 -0
- package/template/client/src/components/business-ui/record-comments/comment-panel.tsx +231 -0
- package/template/client/src/components/business-ui/record-comments/extensions.ts +129 -0
- package/template/client/src/components/business-ui/record-comments/index.ts +9 -0
- package/template/client/src/components/business-ui/record-comments/internal/composer.tsx +529 -0
- package/template/client/src/components/business-ui/record-comments/internal/content.tsx +213 -0
- package/template/client/src/components/business-ui/record-comments/internal/discussion.tsx +517 -0
- package/template/client/src/components/business-ui/record-comments/internal/editor.tsx +675 -0
- package/template/client/src/components/business-ui/record-comments/internal/icons.tsx +148 -0
- package/template/client/src/components/business-ui/record-comments/internal/images.tsx +155 -0
- package/template/client/src/components/business-ui/record-comments/internal/mentions.tsx +163 -0
- package/template/client/src/components/business-ui/record-comments/internal/model.ts +581 -0
- package/template/client/src/components/business-ui/record-comments/internal/mutations.ts +170 -0
- package/template/client/src/components/business-ui/record-comments/internal/reaction-catalog.ts +196 -0
- package/template/client/src/components/business-ui/record-comments/internal/reactions.tsx +681 -0
- package/template/client/src/components/business-ui/record-comments/internal/styles.css +1109 -0
- package/template/client/src/components/business-ui/record-comments/internal/suggestions.tsx +456 -0
- package/template/client/src/components/business-ui/record-comments/internal/view-types.ts +84 -0
- package/template/client/src/components/business-ui/record-comments/types.ts +118 -0
- package/template/package-lock.json +529 -13
- package/template/package.json +15 -4
|
@@ -0,0 +1,170 @@
|
|
|
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, readApiContent } 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
|
+
createTime: number;
|
|
19
|
+
wholeThread?: boolean;
|
|
20
|
+
execute: () => Promise<CommentIDs | DeleteCommentResult>;
|
|
21
|
+
}
|
|
22
|
+
const contentKey = (reply: Pick<DiscussionReply, 'value'>) => JSON.stringify(readApiContent(reply.value));
|
|
23
|
+
const imageKey = (images: readonly DiscussionImage[]) => JSON.stringify(images.map(({ id, url }) => [id, url]));
|
|
24
|
+
const uncertain = (message: string) => Object.assign(new Error(message), { outcome: 'unknown' as const });
|
|
25
|
+
|
|
26
|
+
/** Component-local overlay. Never writes the host's data or performs a request itself. */
|
|
27
|
+
export class CommentMutations {
|
|
28
|
+
private operations: Operation[] = [];
|
|
29
|
+
private listeners = new Set<() => void>();
|
|
30
|
+
private version = 0;
|
|
31
|
+
private active = true;
|
|
32
|
+
subscribe = (listener: () => void) => { this.listeners.add(listener); return () => { this.listeners.delete(listener); }; };
|
|
33
|
+
getVersion = () => this.version;
|
|
34
|
+
private changed() { if (this.active) { this.version++; this.listeners.forEach((listener) => listener()); } }
|
|
35
|
+
activate() { this.active = true; }
|
|
36
|
+
private release(operation: Operation) {
|
|
37
|
+
for (const image of operation.draft?.images ?? [])
|
|
38
|
+
if (image.file && image.url.startsWith('blob:')) URL.revokeObjectURL(image.url);
|
|
39
|
+
}
|
|
40
|
+
dispose() {
|
|
41
|
+
this.active = false;
|
|
42
|
+
this.operations.forEach((operation) => this.release(operation));
|
|
43
|
+
this.operations = [];
|
|
44
|
+
}
|
|
45
|
+
replyID(id: string) { return this.operations.find((operation) => operation.id === id)?.replyID ?? id; }
|
|
46
|
+
private assertAvailable(commentID: string, replyID?: string) {
|
|
47
|
+
if (!this.active) throw new Error('评论会话已关闭');
|
|
48
|
+
if (this.operations.some((operation) => operation.commentID === commentID &&
|
|
49
|
+
(operation.wholeThread || (operation.kind === 'add' && !operation.draft?.commentID) || operation.replyID === replyID)))
|
|
50
|
+
throw new Error('该评论仍在处理中,请先完成同步或处理失败提示');
|
|
51
|
+
}
|
|
52
|
+
private start(operation: Operation) {
|
|
53
|
+
this.operations.push(operation); this.changed();
|
|
54
|
+
void this.run(operation);
|
|
55
|
+
return operation.id;
|
|
56
|
+
}
|
|
57
|
+
add(thread: DiscussionThread | undefined, draft: DiscussionDraft, author: MentionRef | undefined, execute: () => Promise<CommentIDs>) {
|
|
58
|
+
if (thread) this.assertAvailable(thread.commentID);
|
|
59
|
+
else if (!this.active) throw new Error('评论会话已关闭');
|
|
60
|
+
const id = `local:${crypto.randomUUID()}`;
|
|
61
|
+
const createTime = Math.floor(Date.now() / 1000);
|
|
62
|
+
const commentID = thread?.commentID ?? `local:thread:${crypto.randomUUID()}`;
|
|
63
|
+
return this.start({ id, kind: 'add', phase: 'sending', commentID, replyID: id,
|
|
64
|
+
thread: thread ?? { commentID, creator: author ?? null, createTime, isSolved: false, replies: [] },
|
|
65
|
+
draft: { ...draft, commentID: thread?.commentID, value: normalizeValue(draft.value), images: [...draft.images] }, author, createTime, execute });
|
|
66
|
+
}
|
|
67
|
+
edit(thread: DiscussionThread, replyID: string, draft: DiscussionDraft, execute: () => Promise<CommentIDs>) {
|
|
68
|
+
this.assertAvailable(thread.commentID, replyID);
|
|
69
|
+
return this.start({ id: `local:${crypto.randomUUID()}`, kind: 'edit', phase: 'sending',
|
|
70
|
+
thread, commentID: thread.commentID, replyID, createTime: Math.floor(Date.now() / 1000),
|
|
71
|
+
draft: { ...draft, value: normalizeValue(draft.value), images: [...draft.images] }, execute });
|
|
72
|
+
}
|
|
73
|
+
delete(thread: DiscussionThread, replyID: string, execute: () => Promise<DeleteCommentResult>) {
|
|
74
|
+
// The UI always deletes one selected message, including the current body.
|
|
75
|
+
const wholeThread = false;
|
|
76
|
+
this.assertAvailable(thread.commentID, replyID);
|
|
77
|
+
return this.start({ id: `local:${crypto.randomUUID()}`, kind: 'delete', phase: 'sending',
|
|
78
|
+
thread, commentID: thread.commentID, replyID, wholeThread, createTime: Math.floor(Date.now() / 1000), execute });
|
|
79
|
+
}
|
|
80
|
+
private async run(operation: Operation) {
|
|
81
|
+
operation.phase = 'sending'; operation.message = undefined; this.changed();
|
|
82
|
+
try {
|
|
83
|
+
const result = await operation.execute();
|
|
84
|
+
if (!this.active) return;
|
|
85
|
+
if (!/^\d+$/.test(result.commentID)) throw uncertain('提交结果缺少有效评论 ID');
|
|
86
|
+
if (operation.kind !== 'add' || operation.draft?.commentID !== undefined) {
|
|
87
|
+
if (result.commentID !== operation.commentID) throw uncertain('提交结果与目标讨论不一致');
|
|
88
|
+
}
|
|
89
|
+
if (operation.kind === 'delete') {
|
|
90
|
+
if (!('commentDeleted' in result) || typeof result.commentDeleted !== 'boolean') throw uncertain('删除结果未确认');
|
|
91
|
+
operation.wholeThread = result.commentDeleted;
|
|
92
|
+
} else {
|
|
93
|
+
if (!('replyID' in result) || !/^\d+$/.test(result.replyID)) throw uncertain('提交结果缺少有效回复 ID');
|
|
94
|
+
if (operation.kind === 'edit' && result.replyID !== operation.replyID) throw uncertain('编辑结果与目标回复不一致');
|
|
95
|
+
operation.replyID = result.replyID;
|
|
96
|
+
}
|
|
97
|
+
operation.commentID = result.commentID;
|
|
98
|
+
operation.phase = 'confirmed';
|
|
99
|
+
} catch (cause) {
|
|
100
|
+
if (!this.active) return;
|
|
101
|
+
operation.phase = (cause as CommentMutationFailure | null)?.outcome === 'unknown' ? 'uncertain' : 'failed';
|
|
102
|
+
operation.message = commentFailureMessage(cause, '操作失败,请重试');
|
|
103
|
+
}
|
|
104
|
+
this.changed();
|
|
105
|
+
}
|
|
106
|
+
retry(id: string) {
|
|
107
|
+
const operation = this.operations.find((item) => item.id === id);
|
|
108
|
+
if (!operation || operation.phase !== 'failed' || !this.active) return;
|
|
109
|
+
void this.run(operation);
|
|
110
|
+
}
|
|
111
|
+
dismiss(id: string) {
|
|
112
|
+
const operation = this.operations.find((item) => item.id === id);
|
|
113
|
+
if (!operation || !['failed', 'uncertain'].includes(operation.phase)) return;
|
|
114
|
+
this.operations = this.operations.filter((item) => item !== operation);
|
|
115
|
+
this.release(operation); this.changed();
|
|
116
|
+
}
|
|
117
|
+
private acknowledged(operation: Operation, base: readonly DiscussionThread[]) {
|
|
118
|
+
const thread = base.find((item) => item.commentID === operation.commentID);
|
|
119
|
+
const reply = thread?.replies.find((item) => item.replyID === operation.replyID);
|
|
120
|
+
if (operation.kind === 'delete') return operation.wholeThread ? !thread : !reply;
|
|
121
|
+
if (!reply) return false;
|
|
122
|
+
if (operation.kind === 'add') return true;
|
|
123
|
+
const before = operation.thread.replies.find((item) => item.replyID === operation.replyID)!;
|
|
124
|
+
// A later authoritative edit wins even when another editor changed the text.
|
|
125
|
+
// Compare server revisions, never the optimistic client wall clock.
|
|
126
|
+
if (operation.phase === 'confirmed' && reply.updateTime !== undefined &&
|
|
127
|
+
reply.updateTime > (before.updateTime ?? before.createTime)) return true;
|
|
128
|
+
if (contentKey(reply) !== contentKey({ value: operation.draft!.value })) return false;
|
|
129
|
+
const images = operation.draft!.images;
|
|
130
|
+
if (imageKey(images) === imageKey(before.images)) return true;
|
|
131
|
+
return images.some((image) => image.file)
|
|
132
|
+
? reply.images.length === images.length && imageKey(reply.images) !== imageKey(before.images)
|
|
133
|
+
: imageKey(reply.images) === imageKey(images);
|
|
134
|
+
}
|
|
135
|
+
reconcile(base: readonly DiscussionThread[]) {
|
|
136
|
+
const finished = this.operations.filter((operation) => (operation.phase === 'confirmed' ||
|
|
137
|
+
(operation.phase === 'uncertain' && operation.kind !== 'add')) && this.acknowledged(operation, base));
|
|
138
|
+
if (!finished.length) return;
|
|
139
|
+
this.operations = this.operations.filter((operation) => !finished.includes(operation));
|
|
140
|
+
finished.forEach((operation) => this.release(operation)); this.changed();
|
|
141
|
+
}
|
|
142
|
+
view(base: readonly DiscussionThread[]): DiscussionThread[] {
|
|
143
|
+
let threads = base.map((thread) => ({ ...thread, replies: [...thread.replies] }));
|
|
144
|
+
for (const operation of this.operations) {
|
|
145
|
+
let thread = threads.find((item) => item.commentID === operation.commentID);
|
|
146
|
+
if (operation.kind === 'delete' && operation.phase === 'confirmed') {
|
|
147
|
+
if (operation.wholeThread) threads = threads.filter((item) => item !== thread);
|
|
148
|
+
else if (thread) thread.replies = thread.replies.filter((reply) => reply.replyID !== operation.replyID);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (!thread) {
|
|
152
|
+
thread = { ...operation.thread, commentID: operation.commentID, replies: [...operation.thread.replies] };
|
|
153
|
+
threads.push(thread);
|
|
154
|
+
}
|
|
155
|
+
const index = thread.replies.findIndex((item) => item.replyID === operation.replyID);
|
|
156
|
+
const before = thread.replies[index] ?? operation.thread.replies.find((item) => item.replyID === operation.replyID);
|
|
157
|
+
const mutation: LocalCommentMutation = { id: operation.id, kind: operation.kind, phase: operation.phase, message: operation.message };
|
|
158
|
+
const reply: DiscussionReply = operation.kind === 'add'
|
|
159
|
+
? { replyID: operation.replyID, author: operation.author ?? null, createTime: operation.createTime,
|
|
160
|
+
value: operation.draft!.value, images: operation.draft!.images, reactions: [], mutation }
|
|
161
|
+
: { ...before!, ...(operation.draft ? { value: operation.draft.value, images: operation.draft.images,
|
|
162
|
+
edited: before?.edited || operation.phase === 'confirmed',
|
|
163
|
+
updateTime: operation.phase === 'confirmed' ? operation.createTime : before?.updateTime } : {}), mutation };
|
|
164
|
+
if (index < 0) thread.replies.push(reply); else thread.replies[index] = reply;
|
|
165
|
+
if ((operation.kind === 'delete' && operation.wholeThread) || (operation.kind === 'add' && !operation.draft?.commentID))
|
|
166
|
+
thread.replies = thread.replies.map((item) => ({ ...item, mutationBlocked: true }));
|
|
167
|
+
}
|
|
168
|
+
return threads.filter((thread) => thread.replies.length > 0);
|
|
169
|
+
}
|
|
170
|
+
}
|
package/template/client/src/components/business-ui/record-comments/internal/reaction-catalog.ts
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
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
|
+
];
|