koishi-plugin-chatluna-affinity 0.3.1 → 0.3.2
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/client/AffinityDashboardPage.vue +30 -0
- package/client/components/ui/alert.tsx +50 -0
- package/client/components/ui/avatar.tsx +47 -0
- package/client/components/ui/badge.tsx +35 -0
- package/client/components/ui/button.tsx +53 -0
- package/client/components/ui/card.tsx +57 -0
- package/client/components/ui/chart.tsx +136 -0
- package/client/components/ui/sonner.tsx +23 -0
- package/client/components/ui/table.tsx +77 -0
- package/client/components/ui/tabs.tsx +82 -0
- package/client/dashboard/AffinityDashboard.tsx +1123 -0
- package/client/dashboard/mount.tsx +9 -0
- package/client/dashboard/types.ts +85 -0
- package/client/index.ts +13 -0
- package/client/lib/utils.ts +6 -0
- package/client/style.css +125 -0
- package/dist/index.js +38400 -159
- package/dist/style.css +1 -1
- package/lib/index.d.ts +54 -1
- package/lib/index.js +666 -7
- package/package.json +41 -1
package/lib/index.js
CHANGED
|
@@ -417,6 +417,7 @@ __export(index_exports, {
|
|
|
417
417
|
COMMON_STYLE: () => COMMON_STYLE,
|
|
418
418
|
Config: () => ConfigSchema,
|
|
419
419
|
ConfigSchema: () => ConfigSchema,
|
|
420
|
+
DASHBOARD_SNAPSHOT_MODEL_NAME: () => DASHBOARD_SNAPSHOT_MODEL_NAME,
|
|
420
421
|
DEFAULT_MEMBER_INFO_ITEMS: () => DEFAULT_MEMBER_INFO_ITEMS,
|
|
421
422
|
FETCH_CONSTANTS: () => FETCH_CONSTANTS,
|
|
422
423
|
MIGRATION_MODEL_NAME: () => MIGRATION_MODEL_NAME,
|
|
@@ -430,6 +431,7 @@ __export(index_exports, {
|
|
|
430
431
|
THRESHOLDS: () => THRESHOLDS,
|
|
431
432
|
TIME_CONSTANTS: () => TIME_CONSTANTS,
|
|
432
433
|
TIMING_CONSTANTS: () => TIMING_CONSTANTS,
|
|
434
|
+
USER_AFFINITY_SNAPSHOT_MODEL_NAME: () => USER_AFFINITY_SNAPSHOT_MODEL_NAME,
|
|
433
435
|
USER_ALIAS_MODEL_NAME: () => USER_ALIAS_MODEL_NAME,
|
|
434
436
|
USER_ALIAS_MODEL_NAME_V2: () => USER_ALIAS_MODEL_NAME_V2,
|
|
435
437
|
appendActionEntry: () => appendActionEntry,
|
|
@@ -474,6 +476,7 @@ __export(index_exports, {
|
|
|
474
476
|
escapeHtmlForRender: () => escapeHtmlForRender,
|
|
475
477
|
extendAffinityModel: () => extendAffinityModel,
|
|
476
478
|
extendBlacklistModel: () => extendBlacklistModel,
|
|
479
|
+
extendDashboardSnapshotModel: () => extendDashboardSnapshotModel,
|
|
477
480
|
extendMigrationModel: () => extendMigrationModel,
|
|
478
481
|
extendUserAliasModel: () => extendUserAliasModel,
|
|
479
482
|
fetchGroupMemberIds: () => fetchGroupMemberIds,
|
|
@@ -860,6 +863,7 @@ var VariableSettingsSchema = import_koishi4.Schema.object({
|
|
|
860
863
|
)
|
|
861
864
|
}).description("\u53D8\u91CF\u8BBE\u7F6E");
|
|
862
865
|
var OtherSettingsSchema = import_koishi4.Schema.object({
|
|
866
|
+
enableDashboard: import_koishi4.Schema.boolean().default(true).description("\u5728 Koishi \u63A7\u5236\u53F0\u4FA7\u680F\u663E\u793A\u597D\u611F\u5EA6\u4EEA\u8868\u76D8"),
|
|
863
867
|
rankRenderAsImage: import_koishi4.Schema.boolean().default(false).description("\u5C06\u597D\u611F\u5EA6\u6392\u884C\u6E32\u67D3\u4E3A\u56FE\u7247"),
|
|
864
868
|
blacklistRenderAsImage: import_koishi4.Schema.boolean().default(false).description("\u5C06\u9ED1\u540D\u5355\u6E32\u67D3\u4E3A\u56FE\u7247"),
|
|
865
869
|
shortTermBlacklistRenderAsImage: import_koishi4.Schema.boolean().default(false).description("\u5C06\u4E34\u65F6\u9ED1\u540D\u5355\u6E32\u67D3\u4E3A\u56FE\u7247"),
|
|
@@ -1012,12 +1016,57 @@ function extendMigrationModel(ctx) {
|
|
|
1012
1016
|
);
|
|
1013
1017
|
}
|
|
1014
1018
|
|
|
1019
|
+
// src/models/dashboard-snapshot.ts
|
|
1020
|
+
var DASHBOARD_SNAPSHOT_MODEL_NAME = "chatluna_affinity_dashboard_snapshot";
|
|
1021
|
+
var USER_AFFINITY_SNAPSHOT_MODEL_NAME = "chatluna_affinity_user_snapshot";
|
|
1022
|
+
function extendDashboardSnapshotModel(ctx) {
|
|
1023
|
+
ctx.model.extend(
|
|
1024
|
+
DASHBOARD_SNAPSHOT_MODEL_NAME,
|
|
1025
|
+
{
|
|
1026
|
+
scopeId: { type: "string", length: 32 },
|
|
1027
|
+
date: { type: "string", length: 10 },
|
|
1028
|
+
recordedAt: { type: "timestamp" },
|
|
1029
|
+
generatedBy: { type: "string", length: 32, nullable: true },
|
|
1030
|
+
users: { type: "integer", initial: 0 },
|
|
1031
|
+
affinityTotal: { type: "integer", initial: 0 },
|
|
1032
|
+
longTermAffinityTotal: { type: "integer", initial: 0 },
|
|
1033
|
+
shortTermAffinityTotal: { type: "integer", initial: 0 },
|
|
1034
|
+
chatCount: { type: "integer", initial: 0 },
|
|
1035
|
+
blacklisted: { type: "integer", initial: 0 },
|
|
1036
|
+
permanentBlacklisted: { type: "integer", initial: 0 },
|
|
1037
|
+
temporaryBlacklisted: { type: "integer", initial: 0 },
|
|
1038
|
+
aliases: { type: "integer", initial: 0 },
|
|
1039
|
+
latestInteractionAt: { type: "timestamp", nullable: true }
|
|
1040
|
+
},
|
|
1041
|
+
{ primary: ["scopeId", "date"] }
|
|
1042
|
+
);
|
|
1043
|
+
ctx.model.extend(
|
|
1044
|
+
USER_AFFINITY_SNAPSHOT_MODEL_NAME,
|
|
1045
|
+
{
|
|
1046
|
+
scopeId: { type: "string", length: 32 },
|
|
1047
|
+
userId: { type: "string", length: 64 },
|
|
1048
|
+
date: { type: "string", length: 10 },
|
|
1049
|
+
recordedAt: { type: "timestamp" },
|
|
1050
|
+
nickname: { type: "string", length: 255, nullable: true },
|
|
1051
|
+
affinity: { type: "integer", initial: 0 },
|
|
1052
|
+
longTermAffinity: { type: "integer", initial: 0 },
|
|
1053
|
+
shortTermAffinity: { type: "integer", initial: 0 },
|
|
1054
|
+
chatCount: { type: "integer", initial: 0 },
|
|
1055
|
+
relation: { type: "string", length: 64, nullable: true },
|
|
1056
|
+
specialRelation: { type: "string", length: 64, nullable: true },
|
|
1057
|
+
lastInteractionAt: { type: "timestamp", nullable: true }
|
|
1058
|
+
},
|
|
1059
|
+
{ primary: ["scopeId", "userId", "date"] }
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1015
1063
|
// src/models/index.ts
|
|
1016
1064
|
function registerModels(ctx) {
|
|
1017
1065
|
extendAffinityModel(ctx);
|
|
1018
1066
|
extendBlacklistModel(ctx);
|
|
1019
1067
|
extendUserAliasModel(ctx);
|
|
1020
1068
|
extendMigrationModel(ctx);
|
|
1069
|
+
extendDashboardSnapshotModel(ctx);
|
|
1021
1070
|
}
|
|
1022
1071
|
|
|
1023
1072
|
// src/helpers/logger.ts
|
|
@@ -3834,6 +3883,600 @@ function createMigrationService(options) {
|
|
|
3834
3883
|
return { run };
|
|
3835
3884
|
}
|
|
3836
3885
|
|
|
3886
|
+
// src/services/dashboard/snapshot.ts
|
|
3887
|
+
async function readRecordedDashboardSnapshots(ctx, scopeId) {
|
|
3888
|
+
const dashboardSnapshots = await ctx.database.get(
|
|
3889
|
+
DASHBOARD_SNAPSHOT_MODEL_NAME,
|
|
3890
|
+
{ scopeId }
|
|
3891
|
+
);
|
|
3892
|
+
const userAffinitySnapshots = await ctx.database.get(
|
|
3893
|
+
USER_AFFINITY_SNAPSHOT_MODEL_NAME,
|
|
3894
|
+
{ scopeId }
|
|
3895
|
+
);
|
|
3896
|
+
return { dashboardSnapshots, userAffinitySnapshots };
|
|
3897
|
+
}
|
|
3898
|
+
function formatSnapshotDate(value) {
|
|
3899
|
+
const year = value.getFullYear();
|
|
3900
|
+
const month = String(value.getMonth() + 1).padStart(2, "0");
|
|
3901
|
+
const day = String(value.getDate()).padStart(2, "0");
|
|
3902
|
+
return `${year}-${month}-${day}`;
|
|
3903
|
+
}
|
|
3904
|
+
function parseSnapshotDate(value) {
|
|
3905
|
+
const matched = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
3906
|
+
if (!matched) return null;
|
|
3907
|
+
const year = Number(matched[1]);
|
|
3908
|
+
const month = Number(matched[2]);
|
|
3909
|
+
const day = Number(matched[3]);
|
|
3910
|
+
const date = new Date(year, month - 1, day);
|
|
3911
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
|
|
3912
|
+
return null;
|
|
3913
|
+
}
|
|
3914
|
+
return date;
|
|
3915
|
+
}
|
|
3916
|
+
async function readDashboardSnapshotSource(ctx, scopeId) {
|
|
3917
|
+
const affinityRows = await ctx.database.get(MODEL_NAME_V2, { scopeId });
|
|
3918
|
+
const blacklistRows = await ctx.database.get(BLACKLIST_MODEL_NAME_V2, {
|
|
3919
|
+
scopeId
|
|
3920
|
+
});
|
|
3921
|
+
const aliasRows = await ctx.database.get(USER_ALIAS_MODEL_NAME_V2, {
|
|
3922
|
+
scopeId
|
|
3923
|
+
});
|
|
3924
|
+
return { affinityRows, blacklistRows, aliasRows };
|
|
3925
|
+
}
|
|
3926
|
+
function createDashboardSnapshot(scopeId, now, source, trigger = "backend") {
|
|
3927
|
+
const permanentBlacklisted = source.blacklistRows.filter(
|
|
3928
|
+
(row) => row.mode === "permanent"
|
|
3929
|
+
).length;
|
|
3930
|
+
const temporaryBlacklisted = source.blacklistRows.filter(
|
|
3931
|
+
(row) => row.mode === "temporary"
|
|
3932
|
+
).length;
|
|
3933
|
+
const latestInteractionAt = source.affinityRows.reduce(
|
|
3934
|
+
(latest, row) => {
|
|
3935
|
+
const value = row.lastInteractionAt;
|
|
3936
|
+
if (!value) return latest;
|
|
3937
|
+
if (!latest || value.getTime() > latest.getTime()) return value;
|
|
3938
|
+
return latest;
|
|
3939
|
+
},
|
|
3940
|
+
null
|
|
3941
|
+
);
|
|
3942
|
+
return {
|
|
3943
|
+
scopeId,
|
|
3944
|
+
date: formatSnapshotDate(now),
|
|
3945
|
+
recordedAt: now,
|
|
3946
|
+
generatedBy: trigger,
|
|
3947
|
+
users: source.affinityRows.length,
|
|
3948
|
+
affinityTotal: source.affinityRows.reduce(
|
|
3949
|
+
(total, row) => total + Number(row.affinity || 0),
|
|
3950
|
+
0
|
|
3951
|
+
),
|
|
3952
|
+
longTermAffinityTotal: source.affinityRows.reduce(
|
|
3953
|
+
(total, row) => total + Number(row.longTermAffinity ?? row.affinity ?? 0),
|
|
3954
|
+
0
|
|
3955
|
+
),
|
|
3956
|
+
shortTermAffinityTotal: source.affinityRows.reduce(
|
|
3957
|
+
(total, row) => total + Number(row.shortTermAffinity || 0),
|
|
3958
|
+
0
|
|
3959
|
+
),
|
|
3960
|
+
chatCount: source.affinityRows.reduce(
|
|
3961
|
+
(total, row) => total + Number(row.chatCount || 0),
|
|
3962
|
+
0
|
|
3963
|
+
),
|
|
3964
|
+
blacklisted: source.blacklistRows.length,
|
|
3965
|
+
permanentBlacklisted,
|
|
3966
|
+
temporaryBlacklisted,
|
|
3967
|
+
aliases: source.aliasRows.length,
|
|
3968
|
+
latestInteractionAt
|
|
3969
|
+
};
|
|
3970
|
+
}
|
|
3971
|
+
function createUserAffinitySnapshots(scopeId, now, source, existingSnapshots = []) {
|
|
3972
|
+
const date = formatSnapshotDate(now);
|
|
3973
|
+
const latestSnapshotsByUserId = /* @__PURE__ */ new Map();
|
|
3974
|
+
for (const snapshot of existingSnapshots) {
|
|
3975
|
+
if (snapshot.scopeId !== scopeId || !parseSnapshotDate(snapshot.date)) {
|
|
3976
|
+
continue;
|
|
3977
|
+
}
|
|
3978
|
+
const latest = latestSnapshotsByUserId.get(snapshot.userId);
|
|
3979
|
+
if (!latest || snapshot.date >= latest.date) {
|
|
3980
|
+
latestSnapshotsByUserId.set(snapshot.userId, snapshot);
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
return source.affinityRows.filter((row) => {
|
|
3984
|
+
const latest = latestSnapshotsByUserId.get(row.userId);
|
|
3985
|
+
return !latest || Number(latest.affinity || 0) !== Number(row.affinity || 0) || Number(latest.longTermAffinity || 0) !== Number(row.longTermAffinity ?? row.affinity ?? 0) || Number(latest.chatCount || 0) !== Number(row.chatCount || 0);
|
|
3986
|
+
}).map((row) => ({
|
|
3987
|
+
scopeId,
|
|
3988
|
+
userId: row.userId,
|
|
3989
|
+
date,
|
|
3990
|
+
recordedAt: now,
|
|
3991
|
+
nickname: row.nickname || null,
|
|
3992
|
+
affinity: Number(row.affinity || 0),
|
|
3993
|
+
longTermAffinity: Number(row.longTermAffinity ?? row.affinity ?? 0),
|
|
3994
|
+
shortTermAffinity: Number(row.shortTermAffinity || 0),
|
|
3995
|
+
chatCount: Number(row.chatCount || 0),
|
|
3996
|
+
relation: row.relation || null,
|
|
3997
|
+
specialRelation: row.specialRelation || null,
|
|
3998
|
+
lastInteractionAt: row.lastInteractionAt || null
|
|
3999
|
+
}));
|
|
4000
|
+
}
|
|
4001
|
+
function hasSnapshotSourceData(source) {
|
|
4002
|
+
return source.affinityRows.length > 0 || source.blacklistRows.length > 0 || source.aliasRows.length > 0;
|
|
4003
|
+
}
|
|
4004
|
+
function mergeDashboardSnapshot(rows, snapshot) {
|
|
4005
|
+
return [
|
|
4006
|
+
...rows.filter(
|
|
4007
|
+
(row) => row.scopeId !== snapshot.scopeId || row.date !== snapshot.date
|
|
4008
|
+
),
|
|
4009
|
+
snapshot
|
|
4010
|
+
];
|
|
4011
|
+
}
|
|
4012
|
+
function mergeUserAffinitySnapshots(rows, snapshots) {
|
|
4013
|
+
const snapshotKeys = new Set(
|
|
4014
|
+
snapshots.map(
|
|
4015
|
+
(snapshot) => `${snapshot.scopeId}:${snapshot.userId}:${snapshot.date}`
|
|
4016
|
+
)
|
|
4017
|
+
);
|
|
4018
|
+
return [
|
|
4019
|
+
...rows.filter(
|
|
4020
|
+
(row) => !snapshotKeys.has(`${row.scopeId}:${row.userId}:${row.date}`)
|
|
4021
|
+
),
|
|
4022
|
+
...snapshots
|
|
4023
|
+
];
|
|
4024
|
+
}
|
|
4025
|
+
async function recordDashboardSnapshot(ctx, options) {
|
|
4026
|
+
const scopeId = options.scopeId.trim();
|
|
4027
|
+
if (!scopeId) {
|
|
4028
|
+
return { dashboardSnapshots: [], userAffinitySnapshots: [] };
|
|
4029
|
+
}
|
|
4030
|
+
const now = options.now || /* @__PURE__ */ new Date();
|
|
4031
|
+
const source = options.source || await readDashboardSnapshotSource(ctx, scopeId);
|
|
4032
|
+
const existingSnapshots = options.existingSnapshots || await ctx.database.get(DASHBOARD_SNAPSHOT_MODEL_NAME, { scopeId });
|
|
4033
|
+
const existingUserAffinitySnapshots = options.existingUserAffinitySnapshots || await ctx.database.get(USER_AFFINITY_SNAPSHOT_MODEL_NAME, { scopeId });
|
|
4034
|
+
if (!hasSnapshotSourceData(source) && existingSnapshots.length === 0) {
|
|
4035
|
+
return {
|
|
4036
|
+
dashboardSnapshots: existingSnapshots,
|
|
4037
|
+
userAffinitySnapshots: existingUserAffinitySnapshots
|
|
4038
|
+
};
|
|
4039
|
+
}
|
|
4040
|
+
const snapshot = createDashboardSnapshot(
|
|
4041
|
+
scopeId,
|
|
4042
|
+
now,
|
|
4043
|
+
source,
|
|
4044
|
+
options.trigger
|
|
4045
|
+
);
|
|
4046
|
+
const userSnapshots = createUserAffinitySnapshots(
|
|
4047
|
+
scopeId,
|
|
4048
|
+
now,
|
|
4049
|
+
source,
|
|
4050
|
+
existingUserAffinitySnapshots
|
|
4051
|
+
);
|
|
4052
|
+
await ctx.database.upsert(DASHBOARD_SNAPSHOT_MODEL_NAME, [snapshot]);
|
|
4053
|
+
if (userSnapshots.length > 0) {
|
|
4054
|
+
await ctx.database.upsert(USER_AFFINITY_SNAPSHOT_MODEL_NAME, userSnapshots);
|
|
4055
|
+
}
|
|
4056
|
+
return {
|
|
4057
|
+
dashboardSnapshots: mergeDashboardSnapshot(existingSnapshots, snapshot),
|
|
4058
|
+
userAffinitySnapshots: mergeUserAffinitySnapshots(
|
|
4059
|
+
existingUserAffinitySnapshots,
|
|
4060
|
+
userSnapshots
|
|
4061
|
+
)
|
|
4062
|
+
};
|
|
4063
|
+
}
|
|
4064
|
+
|
|
4065
|
+
// src/services/dashboard/backend.ts
|
|
4066
|
+
var DEFAULT_SNAPSHOT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
4067
|
+
function registerDashboardBackend(options) {
|
|
4068
|
+
const { config, ctx, log } = options;
|
|
4069
|
+
if (config.enableDashboard === false) return;
|
|
4070
|
+
const getNow = options.now || (() => /* @__PURE__ */ new Date());
|
|
4071
|
+
const intervalMs = options.sampleIntervalMs || DEFAULT_SNAPSHOT_INTERVAL_MS;
|
|
4072
|
+
const schedule = options.setInterval || setInterval;
|
|
4073
|
+
const clear = options.clearInterval || clearInterval;
|
|
4074
|
+
let timer = null;
|
|
4075
|
+
let running = false;
|
|
4076
|
+
const record = async () => {
|
|
4077
|
+
if (running) return;
|
|
4078
|
+
running = true;
|
|
4079
|
+
try {
|
|
4080
|
+
await recordDashboardSnapshot(ctx, {
|
|
4081
|
+
scopeId: config.scopeId,
|
|
4082
|
+
now: getNow()
|
|
4083
|
+
});
|
|
4084
|
+
} catch (error) {
|
|
4085
|
+
log("warn", "\u8BB0\u5F55\u4EEA\u8868\u76D8\u540E\u53F0\u5FEB\u7167\u5931\u8D25", error);
|
|
4086
|
+
} finally {
|
|
4087
|
+
running = false;
|
|
4088
|
+
}
|
|
4089
|
+
};
|
|
4090
|
+
ctx.on("ready", () => {
|
|
4091
|
+
if (timer !== null) return;
|
|
4092
|
+
void record();
|
|
4093
|
+
timer = schedule(() => {
|
|
4094
|
+
void record();
|
|
4095
|
+
}, intervalMs);
|
|
4096
|
+
});
|
|
4097
|
+
ctx.on("dispose", () => {
|
|
4098
|
+
if (timer === null) return;
|
|
4099
|
+
clear(timer);
|
|
4100
|
+
timer = null;
|
|
4101
|
+
});
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
// src/services/dashboard/index.ts
|
|
4105
|
+
var DASHBOARD_EVENT = "chatluna-affinity/dashboard";
|
|
4106
|
+
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
4107
|
+
var WEEK_DAYS = 7;
|
|
4108
|
+
var MONTH_DAYS = 30;
|
|
4109
|
+
var HISTORY_POINT_LIMIT = 12;
|
|
4110
|
+
function toIsoString(value) {
|
|
4111
|
+
if (!value) return null;
|
|
4112
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
4113
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
4114
|
+
return date.toISOString();
|
|
4115
|
+
}
|
|
4116
|
+
function toCount(value) {
|
|
4117
|
+
return Number.isFinite(value) ? Number(value) : 0;
|
|
4118
|
+
}
|
|
4119
|
+
function roundAverage(total, count) {
|
|
4120
|
+
if (!count) return 0;
|
|
4121
|
+
return Math.round(total / count * 100) / 100;
|
|
4122
|
+
}
|
|
4123
|
+
function roundPercent(value) {
|
|
4124
|
+
return Math.round(value * 100) / 100;
|
|
4125
|
+
}
|
|
4126
|
+
function snapshotAffinityTotal(snapshot) {
|
|
4127
|
+
return toCount(snapshot.affinityTotal);
|
|
4128
|
+
}
|
|
4129
|
+
function snapshotUsers(snapshot) {
|
|
4130
|
+
return toCount(snapshot.users);
|
|
4131
|
+
}
|
|
4132
|
+
function snapshotChatCount(snapshot) {
|
|
4133
|
+
return toCount(snapshot.chatCount);
|
|
4134
|
+
}
|
|
4135
|
+
function snapshotBlacklisted(snapshot) {
|
|
4136
|
+
return toCount(snapshot.blacklisted);
|
|
4137
|
+
}
|
|
4138
|
+
function snapshotAliases(snapshot) {
|
|
4139
|
+
return toCount(snapshot.aliases);
|
|
4140
|
+
}
|
|
4141
|
+
function createMetricChange(current, previous) {
|
|
4142
|
+
return {
|
|
4143
|
+
current,
|
|
4144
|
+
previous,
|
|
4145
|
+
percent: previous === 0 ? current === 0 ? 0 : null : roundPercent((current - previous) / previous * 100)
|
|
4146
|
+
};
|
|
4147
|
+
}
|
|
4148
|
+
function getDisplayRelation(record) {
|
|
4149
|
+
return record.specialRelation || record.relation || "\u672A\u5206\u7EC4";
|
|
4150
|
+
}
|
|
4151
|
+
function getRelationKind(record) {
|
|
4152
|
+
return record.specialRelation ? "custom" : "preset";
|
|
4153
|
+
}
|
|
4154
|
+
function getRelationTone(record, levels) {
|
|
4155
|
+
if (record.specialRelation) return "custom";
|
|
4156
|
+
const relation = record.relation || "";
|
|
4157
|
+
const orderedLevels = [...levels || []].filter((level) => level.relation).sort((left, right) => left.min - right.min);
|
|
4158
|
+
const index = orderedLevels.findIndex((level) => level.relation === relation);
|
|
4159
|
+
if (index < 0) return "unknown";
|
|
4160
|
+
const ratio = orderedLevels.length > 1 ? index / (orderedLevels.length - 1) : 1;
|
|
4161
|
+
if (ratio <= 0.25) return "low";
|
|
4162
|
+
if (ratio < 0.75) return "medium";
|
|
4163
|
+
return "high";
|
|
4164
|
+
}
|
|
4165
|
+
function getDisplayName(record) {
|
|
4166
|
+
return record.nickname || record.userId;
|
|
4167
|
+
}
|
|
4168
|
+
function getOneBotAvatarUrl(userId) {
|
|
4169
|
+
const numericId = userId.match(/^\d+$/)?.[0];
|
|
4170
|
+
return numericId ? `https://q1.qlogo.cn/g?b=qq&nk=${numericId}&s=640` : null;
|
|
4171
|
+
}
|
|
4172
|
+
function getBlacklistDisplayName(record) {
|
|
4173
|
+
return record.nickname || record.userId;
|
|
4174
|
+
}
|
|
4175
|
+
function formatTrendLabel(date) {
|
|
4176
|
+
return `${date.getMonth() + 1}/${date.getDate()}`;
|
|
4177
|
+
}
|
|
4178
|
+
function startOfLocalDay(value) {
|
|
4179
|
+
return new Date(value.getFullYear(), value.getMonth(), value.getDate());
|
|
4180
|
+
}
|
|
4181
|
+
function createEmptyTrendPoint(date) {
|
|
4182
|
+
return {
|
|
4183
|
+
label: formatTrendLabel(date),
|
|
4184
|
+
users: 0,
|
|
4185
|
+
averageAffinity: 0,
|
|
4186
|
+
chatCount: 0,
|
|
4187
|
+
blacklisted: 0
|
|
4188
|
+
};
|
|
4189
|
+
}
|
|
4190
|
+
function createSnapshotTrendPoint(snapshot) {
|
|
4191
|
+
const date = parseSnapshotDate(snapshot.date);
|
|
4192
|
+
if (!date) return null;
|
|
4193
|
+
return {
|
|
4194
|
+
label: formatTrendLabel(date),
|
|
4195
|
+
users: snapshotUsers(snapshot),
|
|
4196
|
+
averageAffinity: roundAverage(
|
|
4197
|
+
snapshotAffinityTotal(snapshot),
|
|
4198
|
+
snapshotUsers(snapshot)
|
|
4199
|
+
),
|
|
4200
|
+
chatCount: snapshotChatCount(snapshot),
|
|
4201
|
+
blacklisted: snapshotBlacklisted(snapshot)
|
|
4202
|
+
};
|
|
4203
|
+
}
|
|
4204
|
+
function createDailyTrend(snapshots, anchor, days) {
|
|
4205
|
+
const snapshotsByDate = new Map(
|
|
4206
|
+
snapshots.map((snapshot) => [snapshot.date, snapshot])
|
|
4207
|
+
);
|
|
4208
|
+
const end = startOfLocalDay(anchor).getTime() + DAY_MS;
|
|
4209
|
+
const start = new Date(end - days * DAY_MS);
|
|
4210
|
+
return Array.from({ length: days }, (_, index) => {
|
|
4211
|
+
const date = new Date(start.getTime() + index * DAY_MS);
|
|
4212
|
+
const snapshot = snapshotsByDate.get(formatSnapshotDate(date));
|
|
4213
|
+
const point = snapshot ? createSnapshotTrendPoint(snapshot) : null;
|
|
4214
|
+
return point || createEmptyTrendPoint(date);
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
function createAllTrend(snapshots) {
|
|
4218
|
+
const latestByMonth = /* @__PURE__ */ new Map();
|
|
4219
|
+
for (const snapshot of snapshots) {
|
|
4220
|
+
const date = parseSnapshotDate(snapshot.date);
|
|
4221
|
+
if (!date) continue;
|
|
4222
|
+
const key = `${date.getFullYear()}-${date.getMonth()}`;
|
|
4223
|
+
const current = latestByMonth.get(key);
|
|
4224
|
+
if (!current || snapshot.date > current.date) {
|
|
4225
|
+
latestByMonth.set(key, snapshot);
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
return [...latestByMonth.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([, snapshot]) => {
|
|
4229
|
+
const point = createSnapshotTrendPoint(snapshot);
|
|
4230
|
+
const date = parseSnapshotDate(snapshot.date);
|
|
4231
|
+
return {
|
|
4232
|
+
...point || createEmptyTrendPoint(date || /* @__PURE__ */ new Date()),
|
|
4233
|
+
label: date ? `${date.getFullYear()}/${date.getMonth() + 1}` : snapshot.date
|
|
4234
|
+
};
|
|
4235
|
+
});
|
|
4236
|
+
}
|
|
4237
|
+
function getSnapshotTime(snapshot) {
|
|
4238
|
+
return parseSnapshotDate(snapshot.date)?.getTime() ?? null;
|
|
4239
|
+
}
|
|
4240
|
+
function getLatestSnapshotDate(snapshots) {
|
|
4241
|
+
const times = snapshots.map(getSnapshotTime).filter((value) => value !== null);
|
|
4242
|
+
if (!times.length) return null;
|
|
4243
|
+
return new Date(Math.max(...times));
|
|
4244
|
+
}
|
|
4245
|
+
function findLatestSnapshotInWindow(snapshots, start, end) {
|
|
4246
|
+
let latest = null;
|
|
4247
|
+
let latestTime = -Infinity;
|
|
4248
|
+
for (const snapshot of snapshots) {
|
|
4249
|
+
const time = getSnapshotTime(snapshot);
|
|
4250
|
+
if (time === null || time < start || time >= end || time < latestTime) {
|
|
4251
|
+
continue;
|
|
4252
|
+
}
|
|
4253
|
+
latest = snapshot;
|
|
4254
|
+
latestTime = time;
|
|
4255
|
+
}
|
|
4256
|
+
return latest;
|
|
4257
|
+
}
|
|
4258
|
+
function snapshotAverage(snapshot) {
|
|
4259
|
+
if (!snapshot) return 0;
|
|
4260
|
+
return roundAverage(snapshotAffinityTotal(snapshot), snapshotUsers(snapshot));
|
|
4261
|
+
}
|
|
4262
|
+
function createUserHistoryPoints(row, snapshots, trendAnchor) {
|
|
4263
|
+
const points = snapshots.map((snapshot) => {
|
|
4264
|
+
const date = parseSnapshotDate(snapshot.date);
|
|
4265
|
+
if (!date) return null;
|
|
4266
|
+
return {
|
|
4267
|
+
date,
|
|
4268
|
+
point: {
|
|
4269
|
+
label: formatTrendLabel(date),
|
|
4270
|
+
timestamp: toIsoString(snapshot.recordedAt) || toIsoString(date),
|
|
4271
|
+
affinity: toCount(snapshot.affinity),
|
|
4272
|
+
longTermAffinity: toCount(snapshot.longTermAffinity),
|
|
4273
|
+
chatCount: toCount(snapshot.chatCount)
|
|
4274
|
+
}
|
|
4275
|
+
};
|
|
4276
|
+
}).filter(
|
|
4277
|
+
(point) => point !== null
|
|
4278
|
+
).sort((left, right) => left.date.getTime() - right.date.getTime());
|
|
4279
|
+
if (points.length) {
|
|
4280
|
+
const anchorDate = startOfLocalDay(trendAnchor);
|
|
4281
|
+
const latest = points.at(-1);
|
|
4282
|
+
if (latest && latest.date.getTime() < anchorDate.getTime()) {
|
|
4283
|
+
points.push({
|
|
4284
|
+
date: anchorDate,
|
|
4285
|
+
point: {
|
|
4286
|
+
label: formatTrendLabel(anchorDate),
|
|
4287
|
+
timestamp: toIsoString(anchorDate),
|
|
4288
|
+
affinity: latest.point.affinity,
|
|
4289
|
+
longTermAffinity: toCount(row.longTermAffinity ?? row.affinity),
|
|
4290
|
+
chatCount: toCount(row.chatCount)
|
|
4291
|
+
}
|
|
4292
|
+
});
|
|
4293
|
+
}
|
|
4294
|
+
return points.slice(-HISTORY_POINT_LIMIT).map(({ point }) => point);
|
|
4295
|
+
}
|
|
4296
|
+
return [
|
|
4297
|
+
{
|
|
4298
|
+
label: "\u5F53\u524D",
|
|
4299
|
+
timestamp: toIsoString(row.lastInteractionAt),
|
|
4300
|
+
affinity: toCount(row.affinity),
|
|
4301
|
+
longTermAffinity: toCount(row.longTermAffinity ?? row.affinity),
|
|
4302
|
+
chatCount: toCount(row.chatCount)
|
|
4303
|
+
}
|
|
4304
|
+
];
|
|
4305
|
+
}
|
|
4306
|
+
function groupUserSnapshots(snapshots) {
|
|
4307
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4308
|
+
for (const snapshot of snapshots) {
|
|
4309
|
+
const rows = grouped.get(snapshot.userId) || [];
|
|
4310
|
+
rows.push(snapshot);
|
|
4311
|
+
grouped.set(snapshot.userId, rows);
|
|
4312
|
+
}
|
|
4313
|
+
return grouped;
|
|
4314
|
+
}
|
|
4315
|
+
async function getDashboardData(ctx, options) {
|
|
4316
|
+
const scopeId = options.scopeId;
|
|
4317
|
+
const now = options.now || /* @__PURE__ */ new Date();
|
|
4318
|
+
const relationshipAffinityLevels = options.relationshipAffinityLevels || [];
|
|
4319
|
+
const affinityRows = await ctx.database.get(MODEL_NAME_V2, {
|
|
4320
|
+
scopeId
|
|
4321
|
+
});
|
|
4322
|
+
const blacklistRows = await ctx.database.get(BLACKLIST_MODEL_NAME_V2, {
|
|
4323
|
+
scopeId
|
|
4324
|
+
});
|
|
4325
|
+
const aliasRows = await ctx.database.get(USER_ALIAS_MODEL_NAME_V2, {
|
|
4326
|
+
scopeId
|
|
4327
|
+
});
|
|
4328
|
+
const recordedSnapshots = await readRecordedDashboardSnapshots(ctx, scopeId);
|
|
4329
|
+
const snapshotRows = recordedSnapshots.dashboardSnapshots;
|
|
4330
|
+
const userSnapshotRows = recordedSnapshots.userAffinitySnapshots;
|
|
4331
|
+
const trendAnchor = getLatestSnapshotDate(snapshotRows) || now;
|
|
4332
|
+
let chatCount = 0;
|
|
4333
|
+
let affinityTotal = 0;
|
|
4334
|
+
let longTermTotal = 0;
|
|
4335
|
+
let shortTermTotal = 0;
|
|
4336
|
+
let latestInteractionAt = null;
|
|
4337
|
+
const relationCounts = /* @__PURE__ */ new Map();
|
|
4338
|
+
const affinityByUserId = /* @__PURE__ */ new Map();
|
|
4339
|
+
const userSnapshotsByUserId = groupUserSnapshots(userSnapshotRows);
|
|
4340
|
+
for (const row of affinityRows) {
|
|
4341
|
+
chatCount += toCount(row.chatCount);
|
|
4342
|
+
affinityTotal += toCount(row.affinity);
|
|
4343
|
+
longTermTotal += toCount(row.longTermAffinity ?? row.affinity);
|
|
4344
|
+
shortTermTotal += toCount(row.shortTermAffinity);
|
|
4345
|
+
const relation = getDisplayRelation(row);
|
|
4346
|
+
const kind = getRelationKind(row);
|
|
4347
|
+
const relationKey = `${kind}:${relation}`;
|
|
4348
|
+
const currentRelation = relationCounts.get(relationKey) || {
|
|
4349
|
+
relation,
|
|
4350
|
+
kind,
|
|
4351
|
+
count: 0
|
|
4352
|
+
};
|
|
4353
|
+
currentRelation.count += 1;
|
|
4354
|
+
relationCounts.set(relationKey, currentRelation);
|
|
4355
|
+
affinityByUserId.set(row.userId, toCount(row.affinity));
|
|
4356
|
+
const currentInteractionAt = toIsoString(row.lastInteractionAt);
|
|
4357
|
+
if (currentInteractionAt && (!latestInteractionAt || currentInteractionAt > latestInteractionAt)) {
|
|
4358
|
+
latestInteractionAt = currentInteractionAt;
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
const topUsers = [...affinityRows].sort((left, right) => right.affinity - left.affinity).map((row) => ({
|
|
4362
|
+
userId: row.userId,
|
|
4363
|
+
name: getDisplayName(row),
|
|
4364
|
+
avatarUrl: getOneBotAvatarUrl(row.userId),
|
|
4365
|
+
affinity: toCount(row.affinity),
|
|
4366
|
+
longTermAffinity: toCount(row.longTermAffinity ?? row.affinity),
|
|
4367
|
+
relation: getDisplayRelation(row),
|
|
4368
|
+
relationTone: getRelationTone(row, relationshipAffinityLevels),
|
|
4369
|
+
chatCount: toCount(row.chatCount),
|
|
4370
|
+
lastInteractionAt: toIsoString(row.lastInteractionAt),
|
|
4371
|
+
historyPoints: createUserHistoryPoints(
|
|
4372
|
+
row,
|
|
4373
|
+
userSnapshotsByUserId.get(row.userId) || [],
|
|
4374
|
+
trendAnchor
|
|
4375
|
+
)
|
|
4376
|
+
}));
|
|
4377
|
+
const relationStats = [...relationCounts.values()].sort((left, right) => right.count - left.count);
|
|
4378
|
+
const currentWeekEnd = startOfLocalDay(trendAnchor).getTime() + DAY_MS;
|
|
4379
|
+
const currentWeekStart = currentWeekEnd - WEEK_DAYS * DAY_MS;
|
|
4380
|
+
const previousWeekStart = currentWeekStart - WEEK_DAYS * DAY_MS;
|
|
4381
|
+
const currentWeekSnapshot = findLatestSnapshotInWindow(
|
|
4382
|
+
snapshotRows,
|
|
4383
|
+
currentWeekStart,
|
|
4384
|
+
currentWeekEnd
|
|
4385
|
+
);
|
|
4386
|
+
const previousWeekSnapshot = findLatestSnapshotInWindow(
|
|
4387
|
+
snapshotRows,
|
|
4388
|
+
previousWeekStart,
|
|
4389
|
+
currentWeekStart
|
|
4390
|
+
);
|
|
4391
|
+
const blacklistItems = [...blacklistRows].sort((left, right) => {
|
|
4392
|
+
const leftTime = toIsoString(left.blockedAt) || "";
|
|
4393
|
+
const rightTime = toIsoString(right.blockedAt) || "";
|
|
4394
|
+
return rightTime.localeCompare(leftTime);
|
|
4395
|
+
}).map((row) => ({
|
|
4396
|
+
platform: row.platform,
|
|
4397
|
+
userId: row.userId,
|
|
4398
|
+
name: getBlacklistDisplayName(row),
|
|
4399
|
+
avatarUrl: getOneBotAvatarUrl(row.userId),
|
|
4400
|
+
affinity: affinityByUserId.get(row.userId) ?? null,
|
|
4401
|
+
mode: row.mode,
|
|
4402
|
+
blockedAt: toIsoString(row.blockedAt),
|
|
4403
|
+
expiresAt: toIsoString(row.expiresAt),
|
|
4404
|
+
note: row.note || ""
|
|
4405
|
+
}));
|
|
4406
|
+
const permanentBlacklisted = blacklistRows.filter(
|
|
4407
|
+
(row) => row.mode === "permanent"
|
|
4408
|
+
).length;
|
|
4409
|
+
const temporaryBlacklisted = blacklistRows.filter(
|
|
4410
|
+
(row) => row.mode === "temporary"
|
|
4411
|
+
).length;
|
|
4412
|
+
return {
|
|
4413
|
+
scopeId,
|
|
4414
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4415
|
+
totals: {
|
|
4416
|
+
users: affinityRows.length,
|
|
4417
|
+
blacklisted: blacklistRows.length,
|
|
4418
|
+
permanentBlacklisted,
|
|
4419
|
+
temporaryBlacklisted,
|
|
4420
|
+
aliases: aliasRows.length,
|
|
4421
|
+
chatCount
|
|
4422
|
+
},
|
|
4423
|
+
averages: {
|
|
4424
|
+
affinity: roundAverage(affinityTotal, affinityRows.length),
|
|
4425
|
+
longTermAffinity: roundAverage(longTermTotal, affinityRows.length),
|
|
4426
|
+
shortTermAffinity: roundAverage(shortTermTotal, affinityRows.length)
|
|
4427
|
+
},
|
|
4428
|
+
latestInteractionAt,
|
|
4429
|
+
weeklyChanges: {
|
|
4430
|
+
users: createMetricChange(
|
|
4431
|
+
currentWeekSnapshot ? snapshotUsers(currentWeekSnapshot) : 0,
|
|
4432
|
+
previousWeekSnapshot ? snapshotUsers(previousWeekSnapshot) : 0
|
|
4433
|
+
),
|
|
4434
|
+
averageAffinity: createMetricChange(
|
|
4435
|
+
snapshotAverage(currentWeekSnapshot),
|
|
4436
|
+
snapshotAverage(previousWeekSnapshot)
|
|
4437
|
+
),
|
|
4438
|
+
chatCount: createMetricChange(
|
|
4439
|
+
currentWeekSnapshot ? snapshotChatCount(currentWeekSnapshot) : 0,
|
|
4440
|
+
previousWeekSnapshot ? snapshotChatCount(previousWeekSnapshot) : 0
|
|
4441
|
+
),
|
|
4442
|
+
aliases: createMetricChange(
|
|
4443
|
+
currentWeekSnapshot ? snapshotAliases(currentWeekSnapshot) : 0,
|
|
4444
|
+
previousWeekSnapshot ? snapshotAliases(previousWeekSnapshot) : 0
|
|
4445
|
+
)
|
|
4446
|
+
},
|
|
4447
|
+
trends: {
|
|
4448
|
+
week: createDailyTrend(snapshotRows, trendAnchor, WEEK_DAYS),
|
|
4449
|
+
month: createDailyTrend(snapshotRows, trendAnchor, MONTH_DAYS),
|
|
4450
|
+
all: createAllTrend(snapshotRows)
|
|
4451
|
+
},
|
|
4452
|
+
relationStats,
|
|
4453
|
+
blacklistItems,
|
|
4454
|
+
topUsers
|
|
4455
|
+
};
|
|
4456
|
+
}
|
|
4457
|
+
function registerDashboardWebui(options) {
|
|
4458
|
+
const { config, ctx, entry, log } = options;
|
|
4459
|
+
if (config.enableDashboard === false) return;
|
|
4460
|
+
ctx.inject(["console"], (innerCtx) => {
|
|
4461
|
+
const consoleService = innerCtx.console;
|
|
4462
|
+
consoleService.addEntry(entry);
|
|
4463
|
+
consoleService.addListener(
|
|
4464
|
+
DASHBOARD_EVENT,
|
|
4465
|
+
async () => getDashboardData(ctx, {
|
|
4466
|
+
scopeId: config.scopeId,
|
|
4467
|
+
relationshipAffinityLevels: config.relationshipAffinityLevels
|
|
4468
|
+
}),
|
|
4469
|
+
{ authority: 1 }
|
|
4470
|
+
);
|
|
4471
|
+
if (config.debugLogging) {
|
|
4472
|
+
log("debug", "\u5DF2\u6CE8\u518C\u63A7\u5236\u53F0\u4EEA\u8868\u76D8\u9875\u9762\u4E0E\u6570\u636E\u63A5\u53E3", {
|
|
4473
|
+
event: DASHBOARD_EVENT,
|
|
4474
|
+
scopeId: config.scopeId
|
|
4475
|
+
});
|
|
4476
|
+
}
|
|
4477
|
+
});
|
|
4478
|
+
}
|
|
4479
|
+
|
|
3837
4480
|
// src/renders/base.ts
|
|
3838
4481
|
function getPuppeteer(ctx) {
|
|
3839
4482
|
return ctx.puppeteer || null;
|
|
@@ -5211,20 +5854,26 @@ function registerClearAllCommand(deps) {
|
|
|
5211
5854
|
await ctx.database.remove(USER_ALIAS_MODEL_NAME_V2, {
|
|
5212
5855
|
scopeId: config.scopeId
|
|
5213
5856
|
});
|
|
5857
|
+
await ctx.database.remove(DASHBOARD_SNAPSHOT_MODEL_NAME, {
|
|
5858
|
+
scopeId: config.scopeId
|
|
5859
|
+
});
|
|
5860
|
+
await ctx.database.remove(USER_AFFINITY_SNAPSHOT_MODEL_NAME, {
|
|
5861
|
+
scopeId: config.scopeId
|
|
5862
|
+
});
|
|
5214
5863
|
cache.clearAll?.();
|
|
5215
5864
|
log("info", "\u5F53\u524D\u4F5C\u7528\u57DF\u6570\u636E\u5E93\u5DF2\u6E05\u7A7A", {
|
|
5216
5865
|
scopeId: config.scopeId,
|
|
5217
5866
|
operator: session.userId,
|
|
5218
5867
|
platform: session.platform
|
|
5219
5868
|
});
|
|
5220
|
-
return `\u2705 \u5DF2\u6210\u529F\u6E05\u7A7A\u4F5C\u7528\u57DF ${config.scopeId} \u4E0B\u7684\u597D\u611F\u5EA6\u3001\u9ED1\u540D\u5355\
|
|
5869
|
+
return `\u2705 \u5DF2\u6210\u529F\u6E05\u7A7A\u4F5C\u7528\u57DF ${config.scopeId} \u4E0B\u7684\u597D\u611F\u5EA6\u3001\u9ED1\u540D\u5355\u3001\u6635\u79F0\u4E0E\u8D8B\u52BF\u5FEB\u7167\u6570\u636E\u3002`;
|
|
5221
5870
|
} catch (error) {
|
|
5222
5871
|
log("warn", "\u6E05\u7A7A\u6570\u636E\u5E93\u5931\u8D25", error);
|
|
5223
5872
|
return "\u274C \u6E05\u7A7A\u6570\u636E\u5E93\u65F6\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u67E5\u770B\u65E5\u5FD7\u3002";
|
|
5224
5873
|
}
|
|
5225
5874
|
}
|
|
5226
5875
|
pendingClearConfirmations.set(sessionKey, { expiresAt: now + 60 * 1e3 });
|
|
5227
|
-
return `\u26A0\uFE0F \u8B66\u544A\uFF1A\u6B64\u64CD\u4F5C\u5C06\u6C38\u4E45\u5220\u9664\u4F5C\u7528\u57DF ${config.scopeId} \u4E0B\u7684\u597D\u611F\u5EA6\u3001\u9ED1\u540D\u5355\
|
|
5876
|
+
return `\u26A0\uFE0F \u8B66\u544A\uFF1A\u6B64\u64CD\u4F5C\u5C06\u6C38\u4E45\u5220\u9664\u4F5C\u7528\u57DF ${config.scopeId} \u4E0B\u7684\u597D\u611F\u5EA6\u3001\u9ED1\u540D\u5355\u3001\u6635\u79F0\u4E0E\u8D8B\u52BF\u5FEB\u7167\u6570\u636E\uFF0C\u4E14\u65E0\u6CD5\u6062\u590D\uFF01
|
|
5228
5877
|
\u8BF7\u5728 60 \u79D2\u5185\u4F7F\u7528 \`${buildScopedCommandName(config.scopeId, "clearAll")} -y\` \u6216 \`\u6E05\u7A7A\u597D\u611F\u5EA6 -y\` \u786E\u8BA4\u6267\u884C\u3002`;
|
|
5229
5878
|
});
|
|
5230
5879
|
}
|
|
@@ -5302,14 +5951,21 @@ function apply(ctx, config) {
|
|
|
5302
5951
|
config.initialAffinity = Number.isFinite(config.initialAffinity) ? Number(config.initialAffinity) : BASE_AFFINITY_DEFAULTS.initialAffinity;
|
|
5303
5952
|
normalizeToolSettings(config);
|
|
5304
5953
|
registerModels(ctx);
|
|
5305
|
-
ctx
|
|
5306
|
-
|
|
5307
|
-
|
|
5954
|
+
const log = createLogger(ctx, config);
|
|
5955
|
+
registerDashboardBackend({
|
|
5956
|
+
ctx,
|
|
5957
|
+
config,
|
|
5958
|
+
log
|
|
5959
|
+
});
|
|
5960
|
+
registerDashboardWebui({
|
|
5961
|
+
ctx,
|
|
5962
|
+
config,
|
|
5963
|
+
log,
|
|
5964
|
+
entry: {
|
|
5308
5965
|
dev: path.resolve(__dirname, "../client/index.ts"),
|
|
5309
5966
|
prod: path.resolve(__dirname, "../dist")
|
|
5310
|
-
}
|
|
5967
|
+
}
|
|
5311
5968
|
});
|
|
5312
|
-
const log = createLogger(ctx, config);
|
|
5313
5969
|
log("info", runtimeFingerprint);
|
|
5314
5970
|
log(
|
|
5315
5971
|
"warn",
|
|
@@ -5795,6 +6451,7 @@ var usage = `
|
|
|
5795
6451
|
COMMON_STYLE,
|
|
5796
6452
|
Config,
|
|
5797
6453
|
ConfigSchema,
|
|
6454
|
+
DASHBOARD_SNAPSHOT_MODEL_NAME,
|
|
5798
6455
|
DEFAULT_MEMBER_INFO_ITEMS,
|
|
5799
6456
|
FETCH_CONSTANTS,
|
|
5800
6457
|
MIGRATION_MODEL_NAME,
|
|
@@ -5808,6 +6465,7 @@ var usage = `
|
|
|
5808
6465
|
THRESHOLDS,
|
|
5809
6466
|
TIME_CONSTANTS,
|
|
5810
6467
|
TIMING_CONSTANTS,
|
|
6468
|
+
USER_AFFINITY_SNAPSHOT_MODEL_NAME,
|
|
5811
6469
|
USER_ALIAS_MODEL_NAME,
|
|
5812
6470
|
USER_ALIAS_MODEL_NAME_V2,
|
|
5813
6471
|
appendActionEntry,
|
|
@@ -5852,6 +6510,7 @@ var usage = `
|
|
|
5852
6510
|
escapeHtmlForRender,
|
|
5853
6511
|
extendAffinityModel,
|
|
5854
6512
|
extendBlacklistModel,
|
|
6513
|
+
extendDashboardSnapshotModel,
|
|
5855
6514
|
extendMigrationModel,
|
|
5856
6515
|
extendUserAliasModel,
|
|
5857
6516
|
fetchGroupMemberIds,
|