koishi-plugin-smmcat-eazyfeedback 0.0.1

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.
@@ -0,0 +1,63 @@
1
+ /**
2
+ * 内容发送模块(Markdown 优先 + 纯文本降级)
3
+ *
4
+ * 功能定位:
5
+ * - 统一封装向 QQ 平台发送消息:优先走 QQ 官方 Markdown 接口(useMd=true),
6
+ * 失败或非 QQ 平台时降级为纯文本 fallbackText。
7
+ *
8
+ * 核心算法(msg_seq 递增):
9
+ * - QQ 平台限制同一 msg_id 的被动回复次数;本模块以 msg_id 为键维护计数,
10
+ * 连续发送时递增 msg_seq;超过 5 次后尝试切换到 middleware 捕获的最新
11
+ * messageId,仍不可用则直接降级发纯文本。
12
+ *
13
+ * 注意事项:
14
+ * - 私聊场景会先移除 <qqbot-at-user> 标签(私聊不支持 @)。
15
+ * - chache/messageIdTemp 为有界内存缓存(分别 40/150 条,FIFO 淘汰)。
16
+ * - 调用方应同时提供 Markdown 内容与等价纯文本,保证降级后信息不丢失。
17
+ */
18
+ import { Context, Session } from "koishi";
19
+ import { Config } from ".";
20
+ import { QQKeyboard } from "./keyboards";
21
+ type PassiveSource = {
22
+ type: 'msg_id';
23
+ id: string;
24
+ payload: {
25
+ msg_id: string;
26
+ };
27
+ } | {
28
+ type: 'event_id';
29
+ id: string;
30
+ payload: {
31
+ event_id: string;
32
+ };
33
+ };
34
+ /** 内容发送模块 */
35
+ export declare const Chat: {
36
+ config: Config;
37
+ ctx: Context;
38
+ chache: Record<string, number>;
39
+ messageIdTemp: Record<string, string>;
40
+ buttonEventIdTemp: Record<string, string>;
41
+ init(config: Config, ctx: Context): Promise<void>;
42
+ /**
43
+ * 发送消息(Markdown 优先,失败自动降级)。
44
+ */
45
+ send(session: Session, content: string, keyboard?: QQKeyboard): Promise<any>;
46
+ isUseMd(session: Session): boolean;
47
+ /** 优先取当前 session 的 msg_id;如果是按钮事件,则取 event_id */
48
+ getCurrentPassiveSource(session: Session): PassiveSource | null;
49
+ /**
50
+ * 超过被动 MD 上限时:
51
+ * 1. 优先找 message 事件中缓存的新 msg_id
52
+ * 2. 没有新 msg_id,再找按钮事件缓存的 event_id
53
+ */
54
+ getNextPassiveSource(userId: string, current: PassiveSource): PassiveSource | null;
55
+ getCacheKey(source: PassiveSource): string;
56
+ /** 清除一条 msg_id/event_id 计数记录 */
57
+ clearChache(): void;
58
+ /** 清除一条 messageId 缓存 */
59
+ clearMessageIdTemp(): void;
60
+ /** 清除一条按钮 event_id 缓存 */
61
+ clearButtonEventIdTemp(): void;
62
+ };
63
+ export {};
package/lib/index.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Context, Schema } from 'koishi';
2
+ export declare const name = "smmcat-eazyfeedback";
3
+ export interface Config {
4
+ deBug: boolean;
5
+ useMd: boolean;
6
+ mid: number;
7
+ picAutoWidth: number;
8
+ title: string;
9
+ titlePic: string;
10
+ replyList: string[];
11
+ masterList: string[];
12
+ }
13
+ export declare const usage = "\n\u3010\u6CE8\u610F\u3011\u95EE\u5377\u8C03\u67E5/\u53CD\u9988 \u7684 title \u914D\u7F6E\u9879\u4E2D\uFF0C\u82E5\u9700\u8981\u6587\u5B57\u6362\u884C\u8BF7\u7528 \\<br\\> \u800C\u4E0D\u662F \\n\n";
14
+ export declare const inject: string[];
15
+ export declare const Config: Schema<Config>;
16
+ type EazyFeedbackGuildLog = {
17
+ id?: number;
18
+ guildId: string;
19
+ msgId: number;
20
+ timer: string;
21
+ };
22
+ type EazyFeedbackData = {
23
+ id?: number;
24
+ name: string;
25
+ title: string;
26
+ userId: string;
27
+ mid: number;
28
+ message: string;
29
+ avatar: string;
30
+ timer: string;
31
+ };
32
+ type EazyFeedbackTitleData = {
33
+ id?: number;
34
+ mid: number;
35
+ title: string;
36
+ replyList: string[];
37
+ };
38
+ declare module 'koishi' {
39
+ interface Tables {
40
+ smm_eazy_feedback_guild_log: EazyFeedbackGuildLog;
41
+ smm_eazy_feedback_log: EazyFeedbackData;
42
+ smmcat_eazy_feedback_title: EazyFeedbackTitleData;
43
+ }
44
+ }
45
+ export type CanvasData = {
46
+ naturalHeight: number;
47
+ height: number;
48
+ naturalWidth: number;
49
+ width: number;
50
+ };
51
+ export declare function apply(ctx: Context, config: Config): void;
52
+ export {};
package/lib/index.js ADDED
@@ -0,0 +1,588 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __export = (target, all) => {
7
+ for (var name2 in all)
8
+ __defProp(target, name2, { get: all[name2], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ Config: () => Config,
24
+ apply: () => apply,
25
+ inject: () => inject,
26
+ name: () => name,
27
+ usage: () => usage
28
+ });
29
+ module.exports = __toCommonJS(src_exports);
30
+ var import_koishi = require("koishi");
31
+
32
+ // src/chatSend.ts
33
+ var Chat = {
34
+ config: {},
35
+ ctx: {},
36
+ chache: {},
37
+ // message 事件缓存:userId -> msg_id
38
+ messageIdTemp: {},
39
+ // 按钮事件缓存:userId -> event_id
40
+ buttonEventIdTemp: {},
41
+ async init(config, ctx) {
42
+ Chat.config = config;
43
+ Chat.ctx = ctx;
44
+ ctx.on("message", (session) => {
45
+ if (!session.userId || !session.messageId) return;
46
+ Chat.messageIdTemp[session.userId] = session.messageId;
47
+ Chat.clearMessageIdTemp();
48
+ }, true);
49
+ ctx.on("interaction/button", (session) => {
50
+ const eventId = session.event?._data?.id;
51
+ if (!session.userId || !eventId) {
52
+ Chat.config.deBug && console.log("[Chat] button interaction has no event_id:", session.event?._data);
53
+ return;
54
+ }
55
+ Chat.buttonEventIdTemp[session.userId] = eventId;
56
+ Chat.clearButtonEventIdTemp();
57
+ Chat.config.deBug && console.log("[Chat] cached button event_id:", eventId);
58
+ });
59
+ },
60
+ /**
61
+ * 发送消息(Markdown 优先,失败自动降级)。
62
+ */
63
+ async send(session, content, keyboard2) {
64
+ const fallbackText = content;
65
+ if (session.platform !== "qq") {
66
+ await session.send(fallbackText);
67
+ return { sent: true, mode: "text" };
68
+ }
69
+ if (!Chat.config.useMd) {
70
+ await session.send(fallbackText);
71
+ return { sent: true, mode: "text" };
72
+ }
73
+ const userId = session.userId;
74
+ let source = Chat.getCurrentPassiveSource(session);
75
+ if (!source) {
76
+ Chat.config.deBug && console.log("[Chat.send] no msg_id/event_id, fallback to text");
77
+ await session.send(fallbackText);
78
+ return { sent: true, mode: "text" };
79
+ }
80
+ const cacheKey = Chat.getCacheKey(source);
81
+ if (Chat.chache[cacheKey] == void 0) {
82
+ Chat.chache[cacheKey] = 0;
83
+ }
84
+ let seq = ++Chat.chache[cacheKey];
85
+ let msgSeq = seq === 1 ? 0 : seq;
86
+ if (seq > 1) {
87
+ Chat.config.deBug && console.log(`检测到 MD 连续发送,尝试递增 msg_seq;当前第 ${seq} 次。`);
88
+ }
89
+ if (seq > 5) {
90
+ const nextSource = Chat.getNextPassiveSource(userId, source);
91
+ if (nextSource) {
92
+ source = nextSource;
93
+ const nextCacheKey = Chat.getCacheKey(source);
94
+ if (Chat.chache[nextCacheKey] == void 0) {
95
+ Chat.chache[nextCacheKey] = 0;
96
+ }
97
+ const nextSeq = ++Chat.chache[nextCacheKey];
98
+ msgSeq = nextSeq === 1 ? 0 : nextSeq;
99
+ Chat.config.deBug && console.log(`[Chat.send] 被动 MD 超过上限,切换到 ${source.type}: ${source.id}`);
100
+ } else {
101
+ await session.send(fallbackText);
102
+ Chat.clearChache();
103
+ return { sent: true, mode: "text" };
104
+ }
105
+ }
106
+ const mdContent = {
107
+ ...source.payload,
108
+ msg_type: 2,
109
+ msg_seq: msgSeq,
110
+ markdown: {
111
+ content
112
+ },
113
+ ...keyboard2 ? { keyboard: keyboard2 } : {}
114
+ };
115
+ try {
116
+ if (session.guildId) {
117
+ await session.bot.internal.sendMessage(session.channelId, mdContent);
118
+ } else {
119
+ mdContent.markdown.content = mdContent.markdown.content.replace(/<qqbot-at-user[^>]*\/>/g, "");
120
+ await session.bot.internal.sendPrivateMessage(session.userId, mdContent);
121
+ }
122
+ Chat.clearChache();
123
+ return { sent: true, mode: "markdown" };
124
+ } catch (error) {
125
+ Chat.config.deBug && console.log("[Chat.send] Markdown 发送失败,回退普通文本", error);
126
+ try {
127
+ await session.send(fallbackText);
128
+ Chat.clearChache();
129
+ return { sent: true, mode: "text" };
130
+ } catch {
131
+ Chat.clearChache();
132
+ throw new Error("消息发送失败");
133
+ }
134
+ }
135
+ },
136
+ // 当前 session 是否可以使用 MD
137
+ isUseMd(session) {
138
+ if (session.platform !== "qq") return false;
139
+ const source = Chat.getCurrentPassiveSource(session);
140
+ if (!source) return false;
141
+ const cacheKey = Chat.getCacheKey(source);
142
+ if (Chat.chache[cacheKey] == void 0) return true;
143
+ return Chat.chache[cacheKey] <= 5;
144
+ },
145
+ /** 优先取当前 session 的 msg_id;如果是按钮事件,则取 event_id */
146
+ getCurrentPassiveSource(session) {
147
+ if (session.messageId) {
148
+ return {
149
+ type: "msg_id",
150
+ id: session.messageId,
151
+ payload: {
152
+ msg_id: session.messageId
153
+ }
154
+ };
155
+ }
156
+ const eventId = session.event?._data?.id;
157
+ if (eventId) {
158
+ return {
159
+ type: "event_id",
160
+ id: eventId,
161
+ payload: {
162
+ event_id: eventId
163
+ }
164
+ };
165
+ }
166
+ return null;
167
+ },
168
+ /**
169
+ * 超过被动 MD 上限时:
170
+ * 1. 优先找 message 事件中缓存的新 msg_id
171
+ * 2. 没有新 msg_id,再找按钮事件缓存的 event_id
172
+ */
173
+ getNextPassiveSource(userId, current) {
174
+ const cachedMessageId = Chat.messageIdTemp[userId];
175
+ if (cachedMessageId && !(current.type === "msg_id" && current.id === cachedMessageId)) {
176
+ return {
177
+ type: "msg_id",
178
+ id: cachedMessageId,
179
+ payload: {
180
+ msg_id: cachedMessageId
181
+ }
182
+ };
183
+ }
184
+ const cachedButtonEventId = Chat.buttonEventIdTemp[userId];
185
+ if (cachedButtonEventId && !(current.type === "event_id" && current.id === cachedButtonEventId)) {
186
+ return {
187
+ type: "event_id",
188
+ id: cachedButtonEventId,
189
+ payload: {
190
+ event_id: cachedButtonEventId
191
+ }
192
+ };
193
+ }
194
+ return null;
195
+ },
196
+ getCacheKey(source) {
197
+ return `${source.type}:${source.id}`;
198
+ },
199
+ /** 清除一条 msg_id/event_id 计数记录 */
200
+ clearChache() {
201
+ const chache = Object.keys(Chat.chache);
202
+ if (chache.length >= 40) {
203
+ delete Chat.chache[chache[0]];
204
+ }
205
+ },
206
+ /** 清除一条 messageId 缓存 */
207
+ clearMessageIdTemp() {
208
+ const messageIdTempList = Object.keys(Chat.messageIdTemp);
209
+ if (messageIdTempList.length > 150) {
210
+ delete Chat.messageIdTemp[messageIdTempList[0]];
211
+ }
212
+ },
213
+ /** 清除一条按钮 event_id 缓存 */
214
+ clearButtonEventIdTemp() {
215
+ const buttonEventIdTempList = Object.keys(Chat.buttonEventIdTemp);
216
+ if (buttonEventIdTempList.length > 150) {
217
+ delete Chat.buttonEventIdTemp[buttonEventIdTempList[0]];
218
+ }
219
+ }
220
+ };
221
+
222
+ // src/keyboards.ts
223
+ var UNSUPPORT_TIPS = "请升级QQ版本";
224
+ function cmdButton(label, data, style = 0, permission = { type: 2 }, visitedLabel = label, enter = true) {
225
+ return {
226
+ render_data: { label, visited_label: visitedLabel, style },
227
+ action: { type: 2, permission, data, enter, unsupport_tips: UNSUPPORT_TIPS }
228
+ };
229
+ }
230
+ __name(cmdButton, "cmdButton");
231
+ function keyboard(...rows) {
232
+ return { content: { rows: rows.map((buttons) => ({ buttons })) } };
233
+ }
234
+ __name(keyboard, "keyboard");
235
+
236
+ // src/index.ts
237
+ var name = "smmcat-eazyfeedback";
238
+ var usage = `
239
+ 【注意】问卷调查/反馈 的 title 配置项中,若需要文字换行请用 \\<br\\> 而不是 \\n
240
+ `;
241
+ var inject = ["canvas", "database"];
242
+ var Config = import_koishi.Schema.object({
243
+ deBug: import_koishi.Schema.boolean().default(false).description("日志查看更多信息"),
244
+ useMd: import_koishi.Schema.boolean().default(true).description("使用qqmd发送"),
245
+ picAutoWidth: import_koishi.Schema.number().default(300).description("自适应图片展示的宽度"),
246
+ mid: import_koishi.Schema.number().default(1).disabled().description("模板索引id,更新模板后差异对比自递增,无需手动改动"),
247
+ title: import_koishi.Schema.string().default("").description("问卷调查/反馈 文案的标题(支持md)"),
248
+ titlePic: import_koishi.Schema.string().default("").description("问卷调查/反馈 标题配图(需要公网图床)"),
249
+ replyList: import_koishi.Schema.array(String).role("table").default([]).description("反馈的默认回复模板列表(建议字和选项均不要太多)"),
250
+ masterList: import_koishi.Schema.array(String).role("table").default([]).description("主人 userId")
251
+ });
252
+ function apply(ctx, config) {
253
+ let rootFoot = null;
254
+ const eazyFeedback = {
255
+ /** 发送邮箱反馈信息 */
256
+ sendEmail(title, res) {
257
+ },
258
+ /** 发送给主人反馈信息(需开通主动发言) */
259
+ sendUser(title, res) {
260
+ },
261
+ init() {
262
+ ctx.database.extend(
263
+ "smm_eazy_feedback_log",
264
+ {
265
+ id: "integer",
266
+ message: "string",
267
+ name: "string",
268
+ userId: "string",
269
+ title: "string",
270
+ timer: "string",
271
+ avatar: "string",
272
+ mid: "integer"
273
+ },
274
+ {
275
+ autoInc: true,
276
+ primary: "id"
277
+ }
278
+ );
279
+ ctx.database.extend(
280
+ "smm_eazy_feedback_guild_log",
281
+ {
282
+ id: "integer",
283
+ guildId: "string",
284
+ msgId: "integer",
285
+ timer: "string"
286
+ },
287
+ {
288
+ autoInc: true,
289
+ primary: "id"
290
+ }
291
+ );
292
+ ctx.database.extend(
293
+ "smmcat_eazy_feedback_title",
294
+ {
295
+ id: "integer",
296
+ mid: "integer",
297
+ title: "string",
298
+ replyList: "array"
299
+ },
300
+ {
301
+ autoInc: true,
302
+ primary: "id"
303
+ }
304
+ );
305
+ eazyFeedback.difference();
306
+ },
307
+ /** 为指定主题反馈 */
308
+ async createFeedback(session, data, fn) {
309
+ const { guildId, userId } = session;
310
+ console.log(guildId, userId);
311
+ if (!(data.mid && data.msg)) return;
312
+ if (!guildId) return;
313
+ const [temp_data] = await ctx.database.get("smm_eazy_feedback_log", { mid: data.mid, userId });
314
+ if (temp_data) {
315
+ fn && await fn("该 问卷调查/反馈 你已经参与过了!");
316
+ return;
317
+ }
318
+ const [feedbackData] = await ctx.database.get("smmcat_eazy_feedback_title", { mid: data.mid });
319
+ if (!feedbackData) return;
320
+ const temp = {
321
+ mid: data.mid,
322
+ name: session.event.user.name,
323
+ avatar: session.event.user?.avatar || `http://q.qlogo.cn/qqapp/${session.event._data?.d?.application_id}/${session.userId}/640`,
324
+ userId,
325
+ title: feedbackData.title,
326
+ message: data.msg,
327
+ timer: (/* @__PURE__ */ new Date()).toLocaleString()
328
+ };
329
+ await ctx.database.create("smm_eazy_feedback_log", temp);
330
+ await Chat.send(session, `<@${userId}> 反馈成功!`);
331
+ },
332
+ /** 对比差异 */
333
+ async difference() {
334
+ if (!config.title?.trim()) return;
335
+ const [data] = await ctx.database.get("smmcat_eazy_feedback_title", { mid: config.mid });
336
+ if (!data) {
337
+ await eazyFeedback.updateDatabaseFeedbackData();
338
+ return;
339
+ }
340
+ if (data.title !== config.title) {
341
+ await eazyFeedback.updateDatabaseFeedbackData();
342
+ return;
343
+ }
344
+ let isOk = false;
345
+ isOk = config.replyList.length !== data.replyList.length;
346
+ isOk = isOk || config.replyList.some((item, index) => {
347
+ return item !== data.replyList[index];
348
+ });
349
+ if (isOk) {
350
+ await eazyFeedback.updateDatabaseFeedbackData();
351
+ }
352
+ },
353
+ /** 更新数据库标题信息 */
354
+ async updateDatabaseFeedbackData() {
355
+ config.mid++;
356
+ await ctx.database.create("smmcat_eazy_feedback_title", {
357
+ mid: config.mid,
358
+ title: config.title,
359
+ replyList: config.replyList
360
+ });
361
+ eazyFeedback.updateFeedBackMid();
362
+ },
363
+ // 更新插件配置项
364
+ updateFeedBackMid() {
365
+ config.deBug && console.log("自增本地数据");
366
+ rootFoot.scope.update(ctx.config, true);
367
+ },
368
+ /** 检查是否存在最新反馈或者通知 */
369
+ async pushDetection(session) {
370
+ const { guildId, userId } = session;
371
+ if (!guildId) return;
372
+ const [data] = await ctx.database.get("smm_eazy_feedback_guild_log", { msgId: config.mid, guildId });
373
+ if (!data) {
374
+ const temp = {
375
+ msgId: config.mid,
376
+ guildId,
377
+ timer: (/* @__PURE__ */ new Date()).toLocaleString()
378
+ };
379
+ await eazyFeedback.sendMdFormatMsg(session, config.mid);
380
+ await ctx.database.create("smm_eazy_feedback_guild_log", temp);
381
+ }
382
+ },
383
+ /** 以md方式发送反馈 */
384
+ async sendMdFormatMsg(session, mid) {
385
+ const [data] = await ctx.database.get("smmcat_eazy_feedback_title", { mid });
386
+ if (!data) return;
387
+ data.title = data.title.replaceAll("<br>", "\n");
388
+ const md = `
389
+ ##问卷调查
390
+
391
+ ${config.titlePic ? `![pic #${config.picAutoWidth}px #${(await utils.getImageReduceSize(config.titlePic)).h}px](${config.titlePic})
392
+
393
+ ` : ""}
394
+ ${data.title}
395
+
396
+ `;
397
+ const btn = [];
398
+ let index = 0;
399
+ let arrIndex = 0;
400
+ const maxRow = 2;
401
+ for (const item of data.replyList) {
402
+ if (index && !(index % maxRow)) arrIndex++;
403
+ if (!btn[arrIndex]) {
404
+ btn[arrIndex] = [];
405
+ }
406
+ btn[arrIndex].push({
407
+ id: "smm-eazy-feedback-" + index,
408
+ render_data: {
409
+ label: item,
410
+ visited_label: "选择成功",
411
+ style: 1
412
+ },
413
+ action: {
414
+ type: 1,
415
+ permission: {
416
+ type: 2
417
+ },
418
+ data: JSON.stringify({ mid, msg: item })
419
+ }
420
+ });
421
+ index++;
422
+ }
423
+ if (index && !(index % maxRow)) arrIndex++;
424
+ if (!btn[arrIndex]) {
425
+ btn[arrIndex] = [];
426
+ }
427
+ btn[arrIndex].push(cmdButton("其他回复", `/反馈更多 ${mid} 在这填写你的回复`));
428
+ await Chat.send(session, md, keyboard(...btn));
429
+ }
430
+ };
431
+ const utils = {
432
+ /** 获取图片缩小后的尺寸 */
433
+ async getImageReduceSize(url, size = config.picAutoWidth) {
434
+ const useImg = await ctx.canvas.loadImage(url);
435
+ const h2 = useImg.naturalHeight || useImg.height || 0;
436
+ const w = useImg.naturalWidth || useImg.width || 0;
437
+ return {
438
+ w: size,
439
+ h: Math.ceil(size / w * h2)
440
+ };
441
+ }
442
+ };
443
+ ctx.command("问卷反馈");
444
+ ctx.command("问卷反馈/反馈更多 <mid:posint> <msg:text>").action(async ({ session }, mid, msg) => {
445
+ const [data] = await ctx.database.get("smmcat_eazy_feedback_title", { mid });
446
+ if (!data) {
447
+ await Chat.send(session, `<@${session.userId}> 没有找到你要反馈 mid 下的 问卷调查/反馈。反馈失败...`);
448
+ return;
449
+ }
450
+ const text = import_koishi.h.select(msg, "text")[0]?.attrs?.content?.trim() || "";
451
+ if (!text) {
452
+ await Chat.send(session, `<@${session.userId}> 反馈的内容为空,反馈失败...`);
453
+ return;
454
+ }
455
+ await eazyFeedback.createFeedback(session, { mid, msg }, async (err) => {
456
+ await Chat.send(session, `<@${session.userId}> ${err}`);
457
+ });
458
+ });
459
+ ctx.command("问卷反馈/问卷查询").action(async ({ session }) => {
460
+ const _data = (await ctx.database.get("smmcat_eazy_feedback_title", {})).reverse();
461
+ if (!_data.length) return `当前还没有创建任何问卷`;
462
+ const maxLen = Math.ceil(_data.length / 10);
463
+ let currentIndex = 0;
464
+ let pageSize = 10;
465
+ while (true) {
466
+ const data = _data.slice(pageSize * currentIndex, (currentIndex + 1) * pageSize);
467
+ const msg = [`<@${session.userId}> 获取成功,一共 ${data.length} 条数据!当前页数 (${currentIndex + 1}/${maxLen})
468
+ `, "|mid|问题|参与人数|操作|\n|:-:|:--|:-:|:-:|"];
469
+ for (const item of data) {
470
+ const feedbackData = await ctx.database.get("smm_eazy_feedback_log", { mid: item.mid });
471
+ msg.push(`|${item.mid}|${item.title.length > 10 ? item.title.slice(0, 10) + "..." : item.title + ""}|${feedbackData.length}|<qqbot-cmd-input text="/查询回复 ${item.mid}" show="查询回复" reference="false"/>`);
472
+ }
473
+ msg.push(
474
+ `
475
+ 操作选项:<qqbot-cmd-input text="上一页" show="【上一页】" reference="false"/> <qqbot-cmd-input text="下一页" show="【下一页】" reference="false"/> <qqbot-cmd-input text="退出" show="【退出】" reference="false"/>`
476
+ );
477
+ Chat.send(session, msg.join("\n"));
478
+ let type = await session.prompt(6e4);
479
+ if (type === void 0) {
480
+ await Chat.send(session, `<@${session.userId}> 长时间未操作,已结束展示`);
481
+ break;
482
+ }
483
+ type = type.trim();
484
+ if (type == "退出") {
485
+ await Chat.send(session, `<@${session.userId}> 已主动退出!`);
486
+ break;
487
+ }
488
+ if (type == "下一页") {
489
+ if (currentIndex + 1 < maxLen) {
490
+ currentIndex++;
491
+ }
492
+ continue;
493
+ }
494
+ if (type == "上一页") {
495
+ if (currentIndex > 0) {
496
+ currentIndex--;
497
+ }
498
+ continue;
499
+ }
500
+ if (type.includes("查询回复")) {
501
+ session.execute(type.replace("/", ""));
502
+ break;
503
+ }
504
+ }
505
+ });
506
+ ctx.command("查询回复 <mid:posint>").action(async ({ session }, mid) => {
507
+ const _data = (await ctx.database.get("smm_eazy_feedback_log", { mid })).reverse();
508
+ if (!_data.length) return `当前该 快捷问卷/反馈 还没有任何回复`;
509
+ const maxLen = Math.ceil(_data.length / 10);
510
+ let currentIndex = 0;
511
+ let pageSize = 10;
512
+ while (true) {
513
+ const data = _data.slice(pageSize * currentIndex, (currentIndex + 1) * pageSize);
514
+ console.log(data);
515
+ const msg = [
516
+ `<@${session.userId}> 获取成功,一共 ${data.length} 条数据!当前页数 (${currentIndex + 1}/${maxLen})
517
+ `,
518
+ `
519
+ \`\`\` 问卷标题
520
+ ${data[0].title}
521
+ \`\`\`
522
+
523
+ 回复内容
524
+
525
+
526
+ `,
527
+ "|头像|昵称(如果有)|回复|\n|:-:|:--|:-:|"
528
+ ];
529
+ for (const item of data) {
530
+ msg.push(`|${item.avatar ? `![pic #50px #${(await utils.getImageReduceSize(item.avatar, 50)).h}px](${item.avatar})` : ""}|${item.name ? item.name : "未知昵称"}|${item.message}`);
531
+ }
532
+ msg.push(
533
+ `
534
+ 操作选项:<qqbot-cmd-input text="上一页" show="【上一页】" reference="false"/> <qqbot-cmd-input text="下一页" show="【下一页】" reference="false"/> <qqbot-cmd-input text="退出" show="【退出】" reference="false"/>`
535
+ );
536
+ Chat.send(session, msg.join("\n"));
537
+ let type = await session.prompt(6e4);
538
+ if (type === void 0) {
539
+ await Chat.send(session, `<@${session.userId}> 长时间未操作,已结束展示`);
540
+ break;
541
+ }
542
+ type = type.trim();
543
+ if (type == "退出") {
544
+ await Chat.send(session, `<@${session.userId}> 已主动退出!`);
545
+ break;
546
+ }
547
+ if (type == "下一页") {
548
+ if (currentIndex + 1 < maxLen) {
549
+ currentIndex++;
550
+ }
551
+ continue;
552
+ }
553
+ if (type == "上一页") {
554
+ if (currentIndex > 0) {
555
+ currentIndex--;
556
+ }
557
+ continue;
558
+ }
559
+ }
560
+ });
561
+ ctx.on("ready", () => {
562
+ rootFoot = ctx;
563
+ Chat.init(config, ctx);
564
+ eazyFeedback.init();
565
+ });
566
+ ctx.middleware(async (session, next) => {
567
+ eazyFeedback.pushDetection(session);
568
+ return await next();
569
+ }, true);
570
+ ctx.on("interaction/button", async (session) => {
571
+ console.log(session);
572
+ const callBtn = session.event?.button;
573
+ if (callBtn?.id && callBtn.id.includes("smm-eazy-feedback")) {
574
+ const { guildId, userId } = session;
575
+ config.deBug && console.log(callBtn);
576
+ eazyFeedback.createFeedback(session, JSON.parse(callBtn.data));
577
+ }
578
+ });
579
+ }
580
+ __name(apply, "apply");
581
+ // Annotate the CommonJS export names for ESM import in node:
582
+ 0 && (module.exports = {
583
+ Config,
584
+ apply,
585
+ inject,
586
+ name,
587
+ usage
588
+ });
@@ -0,0 +1,46 @@
1
+ /**
2
+ * QQ Markdown 下挂按钮(keyboard)组件
3
+ *
4
+ * 结构、样式与交互规范来自 robloxmdbutton.md / QQ_MARKDOWN_BUTTON_GUIDE.md:
5
+ * - action.type:0 链接 / 1 回调 / 2 指令
6
+ * - render_data.style:0 灰线框 / 1 蓝线框 / 2 蓝底 / 3 红色警示 / 4 主操作
7
+ * - permission.type:0 指定用户 / 1 管理者 / 2 所有人
8
+ * - 每行最多 4 个按钮,最多 5 行
9
+ */
10
+ export interface QQButtonRenderData {
11
+ label: string;
12
+ visited_label?: string;
13
+ style: 0 | 1 | 2 | 3 | 4;
14
+ }
15
+ export interface QQButtonPermission {
16
+ type: 0 | 1 | 2;
17
+ specify_user_ids?: string[];
18
+ }
19
+ export interface QQButtonAction {
20
+ type: 0 | 1 | 2;
21
+ permission: QQButtonPermission;
22
+ data: string;
23
+ enter?: boolean;
24
+ reply?: boolean;
25
+ unsupport_tips?: string;
26
+ }
27
+ export interface QQButton {
28
+ id?: string;
29
+ render_data: QQButtonRenderData;
30
+ action: QQButtonAction;
31
+ }
32
+ export interface QQKeyboardRow {
33
+ buttons: QQButton[];
34
+ }
35
+ export interface QQKeyboard {
36
+ content: {
37
+ rows: QQKeyboardRow[];
38
+ };
39
+ }
40
+ /** 指令按钮(action.type=2):以点击者身份发送指令 */
41
+ export declare function cmdButton(label: string, data: string, style?: QQButtonRenderData['style'], permission?: QQButtonPermission, visitedLabel?: string, enter?: boolean): QQButton;
42
+ /** 回调按钮(action.type=1):触发 interaction/button 事件 */
43
+ export declare function callbackButton(label: string, data: string, style?: QQButtonRenderData['style'], permission?: QQButtonPermission, visitedLabel?: string, id?: string): QQButton;
44
+ /** 链接按钮(action.type=0) */
45
+ export declare function linkButton(label: string, url: string, style?: QQButtonRenderData['style']): QQButton;
46
+ export declare function keyboard(...rows: QQButton[][]): QQKeyboard;
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "koishi-plugin-smmcat-eazyfeedback",
3
+ "description": "更容易让用户反馈的反馈功能",
4
+ "version": "0.0.1",
5
+ "main": "lib/index.js",
6
+ "typings": "lib/index.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "dist"
10
+ ],
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "chatbot",
14
+ "koishi",
15
+ "plugin"
16
+ ],
17
+ "peerDependencies": {
18
+ "koishi": "^4.18.7"
19
+ }
20
+ }
package/readme.md ADDED
@@ -0,0 +1,5 @@
1
+ # koishi-plugin-smmcat-eazyfeedback
2
+
3
+ [![npm](https://img.shields.io/npm/v/koishi-plugin-smmcat-eazyfeedback?style=flat-square)](https://www.npmjs.com/package/koishi-plugin-smmcat-eazyfeedback)
4
+
5
+ 更容易让用户反馈的反馈功能