@musnows/scriverse 0.5.2 → 0.5.3
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/LICENSE +661 -21
- package/README.en.md +8 -0
- package/README.md +8 -0
- package/dist/ai.js +950 -145
- package/dist/ai.js.map +1 -1
- package/dist/app.js +49 -6
- package/dist/app.js.map +1 -1
- package/dist/database.js +321 -0
- package/dist/database.js.map +1 -1
- package/dist/public/app.js +60 -11
- package/dist/public/display-labels.js +1 -0
- package/dist/public/index.html +13 -7
- package/dist/public/styles.css +17 -0
- package/dist/relationship-search.js +196 -0
- package/dist/relationship-search.js.map +1 -0
- package/dist/store.js +59 -8
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +23 -6
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -2
package/dist/public/app.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
taskScopeLabel,
|
|
32
32
|
timelineStatusLabel,
|
|
33
33
|
characterStateFieldLabel
|
|
34
|
-
} from "/display-labels.js?v=
|
|
34
|
+
} from "/display-labels.js?v=20260726-character-name-variant";
|
|
35
35
|
import { parsePageRoute, serializePageRoute } from "/page-route.js?v=20260723-knowledge-editor-page";
|
|
36
36
|
import { splitRelationshipKeywordInput, splitRelationshipKeywords, uniqueRelationshipKeywords } from "/relationship-keywords.js?v=20260720-relationship-keyword-chips";
|
|
37
37
|
import { tokenizeVisibleSpaces } from "/whitespace-visualization.js?v=20260718-visible-whitespace";
|
|
@@ -147,6 +147,14 @@ function analysisTaskTypeLabel(taskType) {
|
|
|
147
147
|
return analysisTaskTypeLabels.get(String(taskType)) ?? "其他分析";
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
function analysisTaskModelPurpose(taskType) {
|
|
151
|
+
if (taskType === "timeline-analysis") return "timeline-analysis";
|
|
152
|
+
if (taskType === "relationship-analysis") return "relationship-analysis";
|
|
153
|
+
if (taskType === "consistency-check") return "consistency-check";
|
|
154
|
+
if (taskType === "chapter-analysis") return "chapter-analysis";
|
|
155
|
+
return "book-analysis";
|
|
156
|
+
}
|
|
157
|
+
|
|
150
158
|
function analysisTaskStatusLabel(status) {
|
|
151
159
|
return ({
|
|
152
160
|
pending: "待执行",
|
|
@@ -2646,6 +2654,7 @@ async function openMembersDialog(targetWork = state.work) {
|
|
|
2646
2654
|
if (!targetWork) return;
|
|
2647
2655
|
memberDialogWork = targetWork;
|
|
2648
2656
|
const canManage = ["admin", "owner"].includes(String(targetWork.accessRole));
|
|
2657
|
+
$("#members-settings-return").classList.toggle("hidden", $("#settings-hub-view").classList.contains("hidden"));
|
|
2649
2658
|
$("#members-dialog-eyebrow").textContent = `作品权限 · 《${targetWork.title}》`;
|
|
2650
2659
|
$("#members-dialog-title").textContent = "成员模块权限";
|
|
2651
2660
|
$("#members-list").innerHTML = '<p class="empty-state">正在读取成员……</p>';
|
|
@@ -2755,6 +2764,13 @@ async function showSettingsHub() {
|
|
|
2755
2764
|
return true;
|
|
2756
2765
|
}
|
|
2757
2766
|
|
|
2767
|
+
async function returnToSettingsHub(actionSelector, dialogSelector = null) {
|
|
2768
|
+
const dialog = dialogSelector ? $(dialogSelector) : null;
|
|
2769
|
+
if (dialog?.open) dialog.close();
|
|
2770
|
+
if (!(await showSettingsHub())) return;
|
|
2771
|
+
queueMicrotask(() => $(actionSelector)?.focus());
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2758
2774
|
async function returnFromSettings() {
|
|
2759
2775
|
const context = settingsReturnContext ?? { view: "shelf" };
|
|
2760
2776
|
settingsReturnContext = null;
|
|
@@ -3438,9 +3454,11 @@ function openReviewDetailDialog(item) {
|
|
|
3438
3454
|
const evidenceHtml = evidence.length
|
|
3439
3455
|
? `<ul>${evidence.map((entry) => {
|
|
3440
3456
|
if (!entry || typeof entry !== "object") return `<li>${esc(String(entry))}</li>`;
|
|
3441
|
-
const source = entry.chapterTitle || entry.chapterId || "相关证据";
|
|
3457
|
+
const source = entry.sourceTitle || entry.chapterTitle || entry.chapterId || "相关证据";
|
|
3442
3458
|
const quote = entry.quote ? `<blockquote>${esc(entry.quote)}</blockquote>` : "";
|
|
3443
|
-
const supports = entry.
|
|
3459
|
+
const supports = entry.reason
|
|
3460
|
+
? `<small>${esc(entry.reason)}${typeof entry.confidence === "number" ? ` · 置信度 ${Math.round(entry.confidence * 100)}%` : ""}</small>`
|
|
3461
|
+
: entry.supports ? `<small>${esc(entry.supports)}</small>` : "";
|
|
3444
3462
|
return `<li><strong>${esc(source)}</strong>${quote}${supports}</li>`;
|
|
3445
3463
|
}).join("")}</ul>`
|
|
3446
3464
|
: "<p>暂无证据</p>";
|
|
@@ -4031,9 +4049,10 @@ async function renderTasks(page = taskListPage) {
|
|
|
4031
4049
|
</div>
|
|
4032
4050
|
</div>
|
|
4033
4051
|
</section>
|
|
4034
|
-
${tasks.length ? `<table class="table-list task-table"><thead><tr><th>分析类型</th><th>范围</th><th>状态</th><th>进度</th><th>操作</th></tr></thead><tbody>${tasks.map((item) => `
|
|
4052
|
+
${tasks.length ? `<table class="table-list task-table"><thead><tr><th>分析类型</th><th>任务模型</th><th>范围</th><th>状态</th><th>进度</th><th>操作</th></tr></thead><tbody>${tasks.map((item) => `
|
|
4035
4053
|
<tr>
|
|
4036
4054
|
<td>${esc(analysisTaskTypeLabel(item.taskType))}</td>
|
|
4055
|
+
<td>${esc(item.model?.displayName || "运行时使用默认模型")}</td>
|
|
4037
4056
|
<td>${esc(item.scopeSummary || taskScopeLabel(item.scope?.type || "book"))}</td>
|
|
4038
4057
|
<td class="task-status-cell">${renderAnalysisTaskStatus(item)}</td>
|
|
4039
4058
|
<td class="task-progress-cell">${renderAnalysisTaskProgress(item)}</td>
|
|
@@ -4113,7 +4132,7 @@ async function renderTasks(page = taskListPage) {
|
|
|
4113
4132
|
const cancel = button.parentElement.querySelector("[data-cancel-task]");
|
|
4114
4133
|
if (cancel) cancel.textContent = "取消运行";
|
|
4115
4134
|
scheduleTaskProgressRefresh(workId, 1);
|
|
4116
|
-
const completed = await api(`/api/tasks/${button.dataset.runTask}/run`, { method: "POST", body: {
|
|
4135
|
+
const completed = await api(`/api/tasks/${button.dataset.runTask}/run`, { method: "POST", body: {} });
|
|
4117
4136
|
toast(completed.status === "cancelled" ? "分析任务已取消" : completed.status === "expired" ? "正文已变化,本次分析已过期" : "分析已完成");
|
|
4118
4137
|
if (state.module === "tasks" && state.work?.id === workId) await renderTasks();
|
|
4119
4138
|
} catch (error) {
|
|
@@ -4440,6 +4459,7 @@ function openTaskDetailDialog(task, trace) {
|
|
|
4440
4459
|
<section class="task-detail-overview">
|
|
4441
4460
|
<p><strong>任务 ID</strong><br><code>${esc(task.id)}</code><br><small>创建于 ${esc(formatDateTime(task.createdAt))} · 更新于 ${esc(formatDateTime(task.updatedAt))}</small></p>
|
|
4442
4461
|
<p><strong>类型</strong> ${esc(analysisTaskTypeLabel(task.taskType))}</p>
|
|
4462
|
+
<p><strong>任务模型</strong> ${esc(task.model?.displayName || "运行时使用默认模型")}${task.model?.modelId ? ` · <code>${esc(task.model.modelId)}</code>` : ""}</p>
|
|
4443
4463
|
<p><strong>状态</strong> ${esc(analysisTaskStatusLabel(task.status))} · 进度 ${Number(task.progress ?? 0)}%</p>
|
|
4444
4464
|
<p><strong>范围摘要</strong> ${esc(task.scopeSummary || "未指定")}</p>
|
|
4445
4465
|
<div><strong>范围详情</strong><ul>${detailHtml}</ul></div>
|
|
@@ -6401,14 +6421,26 @@ function openReviewDialog() {
|
|
|
6401
6421
|
async function openTaskDialog() {
|
|
6402
6422
|
const chapterOptions = state.work.volumes.flatMap((volume) => volume.chapters.map((chapter) => [chapter.id, `${volume.title} / ${chapter.title}`]));
|
|
6403
6423
|
let relationshipCharacters = [];
|
|
6424
|
+
let taskModels = [];
|
|
6425
|
+
let taskDefaults = [];
|
|
6404
6426
|
try {
|
|
6405
|
-
relationshipCharacters =
|
|
6406
|
-
|
|
6407
|
-
|
|
6427
|
+
[relationshipCharacters, taskModels, taskDefaults] = await Promise.all([
|
|
6428
|
+
canReadModule("characters")
|
|
6429
|
+
? apiAllPages(`/api/works/${state.work.id}/characters`)
|
|
6430
|
+
: Promise.resolve([]),
|
|
6431
|
+
api(`/api/works/${state.work.id}/models`),
|
|
6432
|
+
api(`/api/works/${state.work.id}/task-defaults`)
|
|
6433
|
+
]);
|
|
6408
6434
|
} catch (error) {
|
|
6409
|
-
toast(
|
|
6435
|
+
toast(`分析任务配置加载失败:${error.message}`, "error");
|
|
6410
6436
|
return;
|
|
6411
6437
|
}
|
|
6438
|
+
const defaultModelByTask = new Map(taskDefaults.map((item) => [item.taskType, item.model.id]));
|
|
6439
|
+
const availableTaskModels = taskModels.filter((model) =>
|
|
6440
|
+
model.enabled
|
|
6441
|
+
&& model.providerStatus === "enabled"
|
|
6442
|
+
&& model.providerConnectionStatus === "success"
|
|
6443
|
+
);
|
|
6412
6444
|
const characterOptions = relationshipCharacters.map((character) => [character.id, character.name]);
|
|
6413
6445
|
const relationshipCharacterPicker = `<div class="form-field relationship-character-field">
|
|
6414
6446
|
<span id="relationship-character-label">被分析角色(可多选)</span>
|
|
@@ -6429,6 +6461,11 @@ async function openTaskDialog() {
|
|
|
6429
6461
|
</div>`;
|
|
6430
6462
|
const defaultTaskType = ANALYSIS_TYPES[0].value;
|
|
6431
6463
|
const taskTypeField = `<div class="form-field analysis-type-field"><label>分析类型<select name="taskType" aria-describedby="analysis-type-description">${ANALYSIS_TYPES.map(({ value, label }) => `<option value="${esc(value)}" ${value === defaultTaskType ? "selected" : ""}>${esc(label)}</option>`).join("")}</select></label><p id="analysis-type-description" class="analysis-type-description" aria-live="polite">${esc(analysisTypeDescription(defaultTaskType))}</p></div>`;
|
|
6464
|
+
const defaultModelId = defaultModelByTask.get(analysisTaskModelPurpose(defaultTaskType)) ?? "";
|
|
6465
|
+
const modelField = `<label>任务模型<select name="modelId" required aria-describedby="analysis-task-model-help">
|
|
6466
|
+
<option value="" ${availableTaskModels.some((model) => model.id === defaultModelId) ? "" : "selected"} disabled>${availableTaskModels.length ? "请选择模型" : "没有可用模型"}</option>
|
|
6467
|
+
${availableTaskModels.map((model) => `<option value="${esc(model.id)}" ${model.id === defaultModelId ? "selected" : ""}>${esc(modelOptionLabel(model))}</option>`).join("")}
|
|
6468
|
+
</select><small id="analysis-task-model-help">默认值来自“本书 AI 设置”,只修改当前任务,不会改变全书默认模型。</small></label>`;
|
|
6432
6469
|
const chapterField = `<label class="task-chapter-field">章节<select name="chapterId">${chapterOptions.map(([key, text], index) => `<option value="${esc(key)}" ${index === 0 ? "selected" : ""}>${esc(text)}</option>`).join("")}</select></label>`;
|
|
6433
6470
|
const relationshipFields = `<div class="relationship-analysis-options hidden">
|
|
6434
6471
|
${relationshipCharacterPicker}
|
|
@@ -6439,8 +6476,9 @@ async function openTaskDialog() {
|
|
|
6439
6476
|
</div>
|
|
6440
6477
|
<label>额外分析提示<textarea name="additionalPrompt" maxlength="10000" placeholder="例如:重点识别权力继承、师承变化或隐秘亲缘关系"></textarea><small>将同时追加到证据收集和全局关系归纳提示词,仅影响本次任务。</small></label>
|
|
6441
6478
|
</div>`;
|
|
6442
|
-
openDialog("开始 AI 分析", taskTypeField + field("scopeType", "分析范围", "select", "chapter", [["chapter", "指定章节"], ["book", "全书"]]) + chapterField + relationshipFields, async (form) => {
|
|
6479
|
+
openDialog("开始 AI 分析", taskTypeField + modelField + field("scopeType", "分析范围", "select", "chapter", [["chapter", "指定章节"], ["book", "全书"]]) + chapterField + relationshipFields, async (form) => {
|
|
6443
6480
|
const taskType = String(form.get("taskType"));
|
|
6481
|
+
const modelId = String(form.get("modelId"));
|
|
6444
6482
|
const scopeType = String(form.get("scopeType"));
|
|
6445
6483
|
const includeAllSettings = taskType === "relationship-analysis" && scopeType === "book-with-settings";
|
|
6446
6484
|
const settingsOnly = taskType === "relationship-analysis" && scopeType === "settings";
|
|
@@ -6452,7 +6490,7 @@ async function openTaskDialog() {
|
|
|
6452
6490
|
: taskType === "character-identity-audit" || scopeType === "book" || includeAllSettings
|
|
6453
6491
|
? { type: "book", ...(includeAllSettings ? { includeAllSettings: true } : {}), ...(additionalPrompt ? { additionalPrompt } : {}), ...(characterIds.length ? { characterIds } : {}), ...(replaceExistingRelationships ? { replaceExistingRelationships: true } : {}) }
|
|
6454
6492
|
: { type: "chapter", chapterId: form.get("chapterId"), ...(additionalPrompt ? { additionalPrompt } : {}), ...(characterIds.length ? { characterIds } : {}), ...(replaceExistingRelationships ? { replaceExistingRelationships: true } : {}) };
|
|
6455
|
-
await api(`/api/works/${state.work.id}/tasks`, { method: "POST", body: { taskType, scope } });
|
|
6493
|
+
await api(`/api/works/${state.work.id}/tasks`, { method: "POST", body: { taskType, scope, modelId } });
|
|
6456
6494
|
taskListPage = 1;
|
|
6457
6495
|
toast("分析任务已创建,已进入任务队列");
|
|
6458
6496
|
void renderTasks(1).catch((error) => toast(`任务已创建,但列表刷新失败:${error.message}`, "error"));
|
|
@@ -6463,6 +6501,7 @@ async function openTaskDialog() {
|
|
|
6463
6501
|
errorPrefix: "任务创建失败:"
|
|
6464
6502
|
});
|
|
6465
6503
|
const taskTypeSelect = $("#dialog-fields").querySelector('select[name="taskType"]');
|
|
6504
|
+
const taskModelSelect = $("#dialog-fields").querySelector('select[name="modelId"]');
|
|
6466
6505
|
const scopeTypeSelect = $("#dialog-fields").querySelector('select[name="scopeType"]');
|
|
6467
6506
|
const chapterSelect = $("#dialog-fields").querySelector('select[name="chapterId"]');
|
|
6468
6507
|
const chapterFieldElement = chapterSelect.closest(".task-chapter-field");
|
|
@@ -6544,8 +6583,13 @@ async function openTaskDialog() {
|
|
|
6544
6583
|
filterRelationshipCharacters();
|
|
6545
6584
|
syncChapterField();
|
|
6546
6585
|
};
|
|
6586
|
+
const syncTaskModelDefault = () => {
|
|
6587
|
+
const defaultId = defaultModelByTask.get(analysisTaskModelPurpose(taskTypeSelect.value)) ?? "";
|
|
6588
|
+
taskModelSelect.value = availableTaskModels.some((model) => model.id === defaultId) ? defaultId : "";
|
|
6589
|
+
};
|
|
6547
6590
|
taskTypeSelect.addEventListener("change", () => {
|
|
6548
6591
|
description.textContent = analysisTypeDescription(taskTypeSelect.value);
|
|
6592
|
+
syncTaskModelDefault();
|
|
6549
6593
|
syncRelationshipOptions();
|
|
6550
6594
|
});
|
|
6551
6595
|
relationshipCharacterTrigger.addEventListener("click", () => {
|
|
@@ -7549,6 +7593,7 @@ $("#register-form").addEventListener("submit", async (event) => {
|
|
|
7549
7593
|
});
|
|
7550
7594
|
$("#settings-return").addEventListener("click", () => returnFromSettings().catch((error) => toast(error.message, "error")));
|
|
7551
7595
|
$("#platform-ai-button").addEventListener("click", () => showPlatformAi().catch((error) => toast(error.message, "error")));
|
|
7596
|
+
$("#platform-ai-return").addEventListener("click", () => returnToSettingsHub("#platform-ai-button").catch((error) => toast(error.message, "error")));
|
|
7552
7597
|
$("#user-management-button").addEventListener("click", openUsersDialog);
|
|
7553
7598
|
$("#platform-ui-settings-button").addEventListener("click", openPlatformUiSettingsDialog);
|
|
7554
7599
|
$("#collaboration-button").addEventListener("click", () => openMembersDialog());
|
|
@@ -7558,7 +7603,9 @@ $("#presence-button").addEventListener("click", () => {
|
|
|
7558
7603
|
$("#presence-button").setAttribute("aria-expanded", String(open));
|
|
7559
7604
|
});
|
|
7560
7605
|
$("#users-dialog-close").addEventListener("click", () => $("#users-dialog").close());
|
|
7606
|
+
$("#users-settings-return").addEventListener("click", () => returnToSettingsHub("#user-management-button", "#users-dialog").catch((error) => toast(error.message, "error")));
|
|
7561
7607
|
$("#platform-ui-settings-close").addEventListener("click", () => $("#platform-ui-settings-dialog").close());
|
|
7608
|
+
$("#platform-ui-settings-return").addEventListener("click", () => returnToSettingsHub("#platform-ui-settings-button", "#platform-ui-settings-dialog").catch((error) => toast(error.message, "error")));
|
|
7562
7609
|
$("#platform-ui-settings-cancel").addEventListener("click", () => $("#platform-ui-settings-dialog").close());
|
|
7563
7610
|
$("#platform-ui-settings-form").addEventListener("submit", async (event) => {
|
|
7564
7611
|
event.preventDefault();
|
|
@@ -7588,6 +7635,7 @@ $("#platform-ui-settings-form").addEventListener("submit", async (event) => {
|
|
|
7588
7635
|
}
|
|
7589
7636
|
});
|
|
7590
7637
|
$("#members-dialog-close").addEventListener("click", () => $("#members-dialog").close());
|
|
7638
|
+
$("#members-settings-return").addEventListener("click", () => returnToSettingsHub("#collaboration-button", "#members-dialog").catch((error) => toast(error.message, "error")));
|
|
7591
7639
|
$("#members-dialog").addEventListener("close", () => {
|
|
7592
7640
|
memberDialogWork = null;
|
|
7593
7641
|
memberDialogMembers = [];
|
|
@@ -7657,6 +7705,7 @@ function cleanupExpandedRelationshipMap() {
|
|
|
7657
7705
|
$("#relationship-map-close").addEventListener("click", () => $("#relationship-map-dialog").close());
|
|
7658
7706
|
$("#relationship-map-dialog").addEventListener("close", cleanupExpandedRelationshipMap);
|
|
7659
7707
|
$("#appearance-button").addEventListener("click", openAppearanceDialog);
|
|
7708
|
+
$("#appearance-settings-return").addEventListener("click", () => returnToSettingsHub("#appearance-button", "#appearance-dialog").catch((error) => toast(error.message, "error")));
|
|
7660
7709
|
$("#toggle-whitespace-appearance").addEventListener("click", toggleChapterWhitespaceVisibility);
|
|
7661
7710
|
$("#theme-toggle").addEventListener("click", () => {
|
|
7662
7711
|
const theme = nextTheme(currentColorTheme());
|
|
@@ -37,6 +37,7 @@ export function reviewItemTypeLabel(value) {
|
|
|
37
37
|
return enumLabel({
|
|
38
38
|
consistency: "一致性问题",
|
|
39
39
|
"character-duplicate": "角色重复",
|
|
40
|
+
"character-name-variant": "疑似人物名错字",
|
|
40
41
|
"timeline-conflict": "时间线冲突",
|
|
41
42
|
"setting-conflict": "设定冲突",
|
|
42
43
|
"relationship-conflict": "关系冲突",
|
package/dist/public/index.html
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
<link rel="icon" href="/icon.svg?v=20260712" type="image/svg+xml">
|
|
11
11
|
<link rel="manifest" href="/site.webmanifest">
|
|
12
12
|
<link rel="stylesheet" href="/vendor/vditor/dist/index.css?v=3.11.2">
|
|
13
|
-
<link rel="stylesheet" href="/styles.css?v=20260726-
|
|
13
|
+
<link rel="stylesheet" href="/styles.css?v=20260726-settings-select-spacing-v1">
|
|
14
14
|
</head>
|
|
15
15
|
<body class="auth-pending">
|
|
16
16
|
<section id="auth-view" class="auth-view hidden" aria-labelledby="auth-title">
|
|
@@ -159,7 +159,10 @@
|
|
|
159
159
|
<section id="platform-ai-view" class="shelf-view hidden" aria-labelledby="platform-ai-title">
|
|
160
160
|
<div class="shelf-header">
|
|
161
161
|
<div><span class="eyebrow">平台资源</span><h1 id="platform-ai-title">AI 管理</h1><p>供应商、模型与全局系统提示词对所有作品生效;每本书可在“AI 设置”中追加自己的系统提示词。</p></div>
|
|
162
|
-
<
|
|
162
|
+
<div class="settings-detail-actions">
|
|
163
|
+
<button id="platform-ai-return" class="ghost-button settings-parent-button" type="button">返回设置</button>
|
|
164
|
+
<button id="platform-new-provider" class="primary-button" type="button">新建供应商</button>
|
|
165
|
+
</div>
|
|
163
166
|
</div>
|
|
164
167
|
<div id="platform-ai-content" class="module-content"></div>
|
|
165
168
|
</section>
|
|
@@ -497,7 +500,10 @@
|
|
|
497
500
|
<form id="appearance-form" method="dialog">
|
|
498
501
|
<div class="dialog-header">
|
|
499
502
|
<div><span class="eyebrow">本机偏好</span><h2>显示设置</h2></div>
|
|
500
|
-
<
|
|
503
|
+
<div class="settings-dialog-header-actions">
|
|
504
|
+
<button id="appearance-settings-return" class="ghost-button settings-parent-button" type="button">返回设置</button>
|
|
505
|
+
<button class="dialog-close" value="cancel" aria-label="关闭" type="submit">×</button>
|
|
506
|
+
</div>
|
|
501
507
|
</div>
|
|
502
508
|
<div class="appearance-grid">
|
|
503
509
|
<label>中文字体
|
|
@@ -572,14 +578,14 @@
|
|
|
572
578
|
</dialog>
|
|
573
579
|
|
|
574
580
|
<dialog id="users-dialog" class="dialog wide-dialog" aria-labelledby="users-dialog-title">
|
|
575
|
-
<div class="dialog-header"><div><span class="eyebrow">系统管理员</span><h2 id="users-dialog-title">用户管理</h2></div><button id="users-dialog-close" class="dialog-close" aria-label="关闭" type="button">×</button></div>
|
|
581
|
+
<div class="dialog-header"><div><span class="eyebrow">系统管理员</span><h2 id="users-dialog-title">用户管理</h2></div><div class="settings-dialog-header-actions"><button id="users-settings-return" class="ghost-button settings-parent-button" type="button">返回设置</button><button id="users-dialog-close" class="dialog-close" aria-label="关闭" type="button">×</button></div></div>
|
|
576
582
|
<div class="access-dialog-body">
|
|
577
583
|
<div id="users-list" class="access-list"></div>
|
|
578
584
|
</div>
|
|
579
585
|
</dialog>
|
|
580
586
|
|
|
581
587
|
<dialog id="platform-ui-settings-dialog" class="dialog" aria-labelledby="platform-ui-settings-title">
|
|
582
|
-
<div class="dialog-header"><div><span class="eyebrow">系统管理员</span><h2 id="platform-ui-settings-title">界面与分页</h2></div><button id="platform-ui-settings-close" class="dialog-close" aria-label="关闭" type="button">×</button></div>
|
|
588
|
+
<div class="dialog-header"><div><span class="eyebrow">系统管理员</span><h2 id="platform-ui-settings-title">界面与分页</h2></div><div class="settings-dialog-header-actions"><button id="platform-ui-settings-return" class="ghost-button settings-parent-button" type="button">返回设置</button><button id="platform-ui-settings-close" class="dialog-close" aria-label="关闭" type="button">×</button></div></div>
|
|
583
589
|
<form id="platform-ui-settings-form">
|
|
584
590
|
<div class="dialog-fields">
|
|
585
591
|
<label>Toast 提示位置<select id="toast-position" name="toastPosition" aria-label="Toast 提示位置"><option value="bottom-right">右下角(默认)</option><option value="top-right">右上角</option></select></label>
|
|
@@ -660,7 +666,7 @@
|
|
|
660
666
|
</dialog>
|
|
661
667
|
|
|
662
668
|
<dialog id="members-dialog" class="dialog wide-dialog" aria-labelledby="members-dialog-title">
|
|
663
|
-
<div class="dialog-header"><div><span id="members-dialog-eyebrow" class="eyebrow">作品权限</span><h2 id="members-dialog-title">成员模块权限</h2></div><button id="members-dialog-close" class="dialog-close" aria-label="关闭" type="button">×</button></div>
|
|
669
|
+
<div class="dialog-header"><div><span id="members-dialog-eyebrow" class="eyebrow">作品权限</span><h2 id="members-dialog-title">成员模块权限</h2></div><div class="settings-dialog-header-actions"><button id="members-settings-return" class="ghost-button settings-parent-button hidden" type="button">返回设置</button><button id="members-dialog-close" class="dialog-close" aria-label="关闭" type="button">×</button></div></div>
|
|
664
670
|
<div class="access-dialog-body">
|
|
665
671
|
<form id="member-permission-form" class="member-permission-form">
|
|
666
672
|
<label class="member-person-field">选择成员<select id="member-user-select" required></select><small>先选择已注册用户,再逐项配置模块权限。</small></label>
|
|
@@ -745,6 +751,6 @@
|
|
|
745
751
|
<div id="auth-loading" class="auth-loading" role="status" aria-label="正在载入工作台"></div>
|
|
746
752
|
<script id="vditorIconScript" src="/vendor/vditor/dist/js/icons/ant.js?v=3.11.2"></script>
|
|
747
753
|
<script src="/vendor/vditor/dist/index.min.js?v=3.11.2"></script>
|
|
748
|
-
<script type="module" src="/app.js?v=20260726-relationship-
|
|
754
|
+
<script type="module" src="/app.js?v=20260726-relationship-pinyin-v10"></script>
|
|
749
755
|
</body>
|
|
750
756
|
</html>
|
package/dist/public/styles.css
CHANGED
|
@@ -521,6 +521,9 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
|
|
|
521
521
|
.shelf-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 30px; width: 100%; max-width: 1400px; margin: 0 auto 38px; }
|
|
522
522
|
.shelf-header h1 { margin: 0 0 10px; font-size: clamp(30px, 4vw, 52px); font-weight: 560; letter-spacing: -.04em; }
|
|
523
523
|
.shelf-header p { margin: 0; color: var(--muted); }
|
|
524
|
+
.settings-detail-actions, .settings-dialog-header-actions { display: flex; align-items: center; gap: 10px; }
|
|
525
|
+
.settings-detail-actions { flex: 0 0 auto; }
|
|
526
|
+
.settings-parent-button { white-space: nowrap; }
|
|
524
527
|
.settings-hub-header { align-items: center; }
|
|
525
528
|
.settings-hub-header h1 { font-size: clamp(26px, 3vw, 36px); line-height: 1.15; letter-spacing: -.02em; }
|
|
526
529
|
.settings-hub-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; max-width: 1000px; margin: 0 auto; }
|
|
@@ -620,6 +623,17 @@ body.is-panel-resizing { cursor: col-resize; user-select: none; }
|
|
|
620
623
|
.member-permission-row select { min-height: 34px; padding-block: 6px; font-size: 11px; }
|
|
621
624
|
.member-permission-form .primary-button { justify-self: end; min-height: 38px; white-space: nowrap; }
|
|
622
625
|
.permission-hidden { display: none !important; }
|
|
626
|
+
:is(#users-dialog, #platform-ui-settings-dialog, #members-dialog, #appearance-dialog) select:not([multiple]) {
|
|
627
|
+
appearance: none;
|
|
628
|
+
-webkit-appearance: none;
|
|
629
|
+
padding-inline-end: 40px;
|
|
630
|
+
background-image:
|
|
631
|
+
linear-gradient(45deg, transparent 50%, var(--muted) 50%),
|
|
632
|
+
linear-gradient(135deg, var(--muted) 50%, transparent 50%);
|
|
633
|
+
background-position: right 21px center, right 16px center;
|
|
634
|
+
background-repeat: no-repeat;
|
|
635
|
+
background-size: 5px 5px, 5px 5px;
|
|
636
|
+
}
|
|
623
637
|
.app-shell.ai-hidden-mode:not(.shelf-mode) { grid-template-columns: var(--left-panel-width) minmax(480px, 1fr); }
|
|
624
638
|
.app-shell.prose-hidden-mode:not(.shelf-mode) .left-actions,
|
|
625
639
|
.app-shell.prose-hidden-mode:not(.shelf-mode) .panel-heading,
|
|
@@ -2587,6 +2601,8 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2587
2601
|
.shelf-header, .module-header { align-items: stretch; flex-direction: column; gap: 14px; margin-bottom: 20px; }
|
|
2588
2602
|
.shelf-header h1 { font-size: clamp(24px, 7.5vw, 32px); }
|
|
2589
2603
|
.shelf-header .primary-button { align-self: flex-start; min-width: 150px; min-height: 40px; padding: 10px 18px; }
|
|
2604
|
+
.settings-detail-actions { align-items: stretch; flex-direction: column; }
|
|
2605
|
+
.settings-detail-actions .primary-button, .settings-detail-actions .settings-parent-button { align-self: stretch; width: 100%; }
|
|
2590
2606
|
.module-header-actions { width: 100%; }
|
|
2591
2607
|
.book-shelf { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 14px; }
|
|
2592
2608
|
.book-info { padding-top: 10px; padding-right: 0; }
|
|
@@ -2632,6 +2648,7 @@ select:focus, input:focus, textarea:focus { border-color: #a77768; box-shadow: 0
|
|
|
2632
2648
|
}
|
|
2633
2649
|
.dialog-header { padding: 14px 16px 12px; }
|
|
2634
2650
|
.dialog-header h2 { font-size: 20px; }
|
|
2651
|
+
.settings-dialog-header-actions { gap: 6px; }
|
|
2635
2652
|
.dialog-fields, .appearance-grid, .access-dialog-body, .account-settings-body, .versions-list, .entity-history-list { padding-inline: 16px; }
|
|
2636
2653
|
.task-detail-overview { grid-template-columns: minmax(0, 1fr); padding: 12px; }
|
|
2637
2654
|
.task-detail-overview > * { grid-column: 1 !important; }
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { pinyin } from "pinyin-pro";
|
|
2
|
+
export const RELATIONSHIP_SEARCH_POLICY_VERSION = 1;
|
|
3
|
+
export function normalizeRelationshipSearchText(value) {
|
|
4
|
+
return value.normalize("NFKC").toLocaleLowerCase("zh-CN");
|
|
5
|
+
}
|
|
6
|
+
function encodedCodePoint(value) {
|
|
7
|
+
return [...value].map((character) => character.codePointAt(0).toString(16)).join("x");
|
|
8
|
+
}
|
|
9
|
+
function safePinyinToken(value) {
|
|
10
|
+
const normalized = value.normalize("NFKC").toLocaleLowerCase("zh-CN").replaceAll("ü", "v");
|
|
11
|
+
return /^[a-z0-9]+$/u.test(normalized) ? `p${normalized}` : `u${encodedCodePoint(normalized)}`;
|
|
12
|
+
}
|
|
13
|
+
export function relationshipCharacterTokens(value) {
|
|
14
|
+
return [...normalizeRelationshipSearchText(value)].map((character) => `u${encodedCodePoint(character)}`);
|
|
15
|
+
}
|
|
16
|
+
export function relationshipPinyinSyllables(value) {
|
|
17
|
+
const normalized = normalizeRelationshipSearchText(value);
|
|
18
|
+
return pinyin(normalized, { toneType: "none", type: "array" })
|
|
19
|
+
.map((item) => item.normalize("NFKC").toLocaleLowerCase("zh-CN").replaceAll("ü", "v"));
|
|
20
|
+
}
|
|
21
|
+
export function relationshipPinyinTokens(value) {
|
|
22
|
+
return relationshipPinyinSyllables(value).map(safePinyinToken);
|
|
23
|
+
}
|
|
24
|
+
export function relationshipCharacterTokenText(value) {
|
|
25
|
+
return relationshipCharacterTokens(value).join(" ");
|
|
26
|
+
}
|
|
27
|
+
export function relationshipPinyinTokenText(value) {
|
|
28
|
+
return relationshipPinyinTokens(value).join(" ");
|
|
29
|
+
}
|
|
30
|
+
export function ftsPhrase(tokens) {
|
|
31
|
+
return `"${tokens.join(" ").replaceAll('"', '""')}"`;
|
|
32
|
+
}
|
|
33
|
+
export function damerauLevenshteinDistance(left, right, maximum = Number.POSITIVE_INFINITY) {
|
|
34
|
+
if (Math.abs(left.length - right.length) > maximum)
|
|
35
|
+
return maximum + 1;
|
|
36
|
+
const previousPrevious = new Array(right.length + 1).fill(0);
|
|
37
|
+
let previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
38
|
+
for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
|
|
39
|
+
const current = new Array(right.length + 1).fill(0);
|
|
40
|
+
current[0] = leftIndex;
|
|
41
|
+
let rowMinimum = current[0];
|
|
42
|
+
for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
|
|
43
|
+
const substitutionCost = left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1;
|
|
44
|
+
current[rightIndex] = Math.min(previous[rightIndex] + 1, current[rightIndex - 1] + 1, previous[rightIndex - 1] + substitutionCost);
|
|
45
|
+
if (leftIndex > 1 && rightIndex > 1
|
|
46
|
+
&& left[leftIndex - 1] === right[rightIndex - 2]
|
|
47
|
+
&& left[leftIndex - 2] === right[rightIndex - 1]) {
|
|
48
|
+
current[rightIndex] = Math.min(current[rightIndex], previousPrevious[rightIndex - 2] + 1);
|
|
49
|
+
}
|
|
50
|
+
rowMinimum = Math.min(rowMinimum, current[rightIndex]);
|
|
51
|
+
}
|
|
52
|
+
if (rowMinimum > maximum)
|
|
53
|
+
return maximum + 1;
|
|
54
|
+
for (let index = 0; index < previous.length; index += 1)
|
|
55
|
+
previousPrevious[index] = previous[index];
|
|
56
|
+
previous = current;
|
|
57
|
+
}
|
|
58
|
+
return previous[right.length];
|
|
59
|
+
}
|
|
60
|
+
export class RelationshipApproximateMatchLimitError extends Error {
|
|
61
|
+
maximumCandidates;
|
|
62
|
+
constructor(maximumCandidates) {
|
|
63
|
+
super(`Approximate relationship match candidates exceeded ${maximumCandidates}`);
|
|
64
|
+
this.maximumCandidates = maximumCandidates;
|
|
65
|
+
this.name = "RelationshipApproximateMatchLimitError";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function selectApproximateNameMatches(matches, referenceLength, limit) {
|
|
69
|
+
const ranked = matches.sort((left, right) => Math.min(left.characterDistance, left.pinyinDistance) - Math.min(right.characterDistance, right.pinyinDistance)
|
|
70
|
+
|| Math.abs([...left.observed].length - referenceLength) - Math.abs([...right.observed].length - referenceLength)
|
|
71
|
+
|| left.start - right.start);
|
|
72
|
+
const selected = [];
|
|
73
|
+
for (const match of ranked) {
|
|
74
|
+
if (selected.some((item) => match.start < item.end && match.end > item.start))
|
|
75
|
+
continue;
|
|
76
|
+
selected.push(match);
|
|
77
|
+
if (selected.length >= limit)
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
return selected.sort((left, right) => left.start - right.start);
|
|
81
|
+
}
|
|
82
|
+
export function findApproximateNameMatches(content, reference, limit = 3, excludedObserved = new Set(), maximumCandidates = 256) {
|
|
83
|
+
const normalizedContent = normalizeRelationshipSearchText(content);
|
|
84
|
+
const normalizedReference = normalizeRelationshipSearchText(reference).trim();
|
|
85
|
+
const sourceCharacters = [...normalizedContent];
|
|
86
|
+
const utf16Offsets = new Array(sourceCharacters.length + 1).fill(0);
|
|
87
|
+
for (let index = 0; index < sourceCharacters.length; index += 1) {
|
|
88
|
+
utf16Offsets[index + 1] = utf16Offsets[index] + sourceCharacters[index].length;
|
|
89
|
+
}
|
|
90
|
+
const referenceCharacters = [...normalizedReference];
|
|
91
|
+
if (referenceCharacters.length < 2 || sourceCharacters.length === 0)
|
|
92
|
+
return [];
|
|
93
|
+
const hanReference = referenceCharacters.every((character) => /\p{Script=Han}/u.test(character));
|
|
94
|
+
const normalizedExcluded = new Set([...excludedObserved].map((item) => normalizeRelationshipSearchText(item).trim()));
|
|
95
|
+
const referencePinyin = relationshipPinyinSyllables(normalizedReference);
|
|
96
|
+
const sourcePinyin = relationshipPinyinSyllables(normalizedContent);
|
|
97
|
+
const exactCoverage = new Uint8Array(sourceCharacters.length);
|
|
98
|
+
for (let start = 0; start + referenceCharacters.length <= sourceCharacters.length; start += 1) {
|
|
99
|
+
if (!referenceCharacters.every((character, index) => sourceCharacters[start + index] === character))
|
|
100
|
+
continue;
|
|
101
|
+
exactCoverage.fill(1, start, start + referenceCharacters.length);
|
|
102
|
+
}
|
|
103
|
+
const matches = [];
|
|
104
|
+
const seen = new Set();
|
|
105
|
+
for (const windowLength of [referenceCharacters.length, referenceCharacters.length - 1, referenceCharacters.length + 1]) {
|
|
106
|
+
if (windowLength < 1)
|
|
107
|
+
continue;
|
|
108
|
+
for (let start = 0; start + windowLength <= sourceCharacters.length; start += 1) {
|
|
109
|
+
const observedCharacters = sourceCharacters.slice(start, start + windowLength);
|
|
110
|
+
if (observedCharacters.length < 2)
|
|
111
|
+
continue;
|
|
112
|
+
if (hanReference && !observedCharacters.every((character) => /\p{Script=Han}/u.test(character)))
|
|
113
|
+
continue;
|
|
114
|
+
const observed = observedCharacters.join("");
|
|
115
|
+
if (!observed.trim() || observed === normalizedReference || normalizedExcluded.has(observed))
|
|
116
|
+
continue;
|
|
117
|
+
if (exactCoverage.subarray(start, start + windowLength).some((value) => value === 1))
|
|
118
|
+
continue;
|
|
119
|
+
const characterDistance = damerauLevenshteinDistance(referenceCharacters, observedCharacters, 1);
|
|
120
|
+
const observedPinyin = sourcePinyin.slice(start, start + windowLength);
|
|
121
|
+
const pinyinDistance = damerauLevenshteinDistance(referencePinyin, observedPinyin, 1);
|
|
122
|
+
if (characterDistance > 1 && pinyinDistance > 1)
|
|
123
|
+
continue;
|
|
124
|
+
const key = `${start}:${observed}`;
|
|
125
|
+
if (seen.has(key))
|
|
126
|
+
continue;
|
|
127
|
+
seen.add(key);
|
|
128
|
+
matches.push({
|
|
129
|
+
observed,
|
|
130
|
+
start,
|
|
131
|
+
end: start + windowLength,
|
|
132
|
+
utf16Start: utf16Offsets[start],
|
|
133
|
+
utf16End: utf16Offsets[start + windowLength],
|
|
134
|
+
characterDistance,
|
|
135
|
+
pinyinDistance
|
|
136
|
+
});
|
|
137
|
+
if (matches.length > maximumCandidates)
|
|
138
|
+
throw new RelationshipApproximateMatchLimitError(maximumCandidates);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return selectApproximateNameMatches(matches, referenceCharacters.length, limit);
|
|
142
|
+
}
|
|
143
|
+
export async function findApproximateNameMatchesChunked(content, reference, limit = 3, excludedObserved = new Set(), maximumCandidates = 256, chunkSize = 16_384) {
|
|
144
|
+
const normalizedContent = normalizeRelationshipSearchText(content);
|
|
145
|
+
const referenceLength = [...normalizeRelationshipSearchText(reference).trim()].length;
|
|
146
|
+
if (referenceLength < 2 || !normalizedContent || chunkSize < 1)
|
|
147
|
+
return [];
|
|
148
|
+
const overlapSize = referenceLength + 1;
|
|
149
|
+
const matches = [];
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
let processedCharacters = 0;
|
|
152
|
+
let processedCodeUnits = 0;
|
|
153
|
+
let tail = [];
|
|
154
|
+
let chunk = [];
|
|
155
|
+
const processChunk = async () => {
|
|
156
|
+
if (chunk.length === 0)
|
|
157
|
+
return;
|
|
158
|
+
const prefixLength = tail.length;
|
|
159
|
+
const prefixCodeUnits = tail.reduce((total, character) => total + character.length, 0);
|
|
160
|
+
const combined = [...tail, ...chunk];
|
|
161
|
+
const baseOffset = processedCharacters - prefixLength;
|
|
162
|
+
const baseCodeUnitOffset = processedCodeUnits - prefixCodeUnits;
|
|
163
|
+
const chunkMatches = findApproximateNameMatches(combined.join(""), reference, maximumCandidates + 1, excludedObserved, maximumCandidates);
|
|
164
|
+
for (const match of chunkMatches) {
|
|
165
|
+
if (match.end <= prefixLength)
|
|
166
|
+
continue;
|
|
167
|
+
const adjusted = {
|
|
168
|
+
...match,
|
|
169
|
+
start: match.start + baseOffset,
|
|
170
|
+
end: match.end + baseOffset,
|
|
171
|
+
utf16Start: match.utf16Start + baseCodeUnitOffset,
|
|
172
|
+
utf16End: match.utf16End + baseCodeUnitOffset
|
|
173
|
+
};
|
|
174
|
+
const key = `${adjusted.start}:${adjusted.observed}`;
|
|
175
|
+
if (seen.has(key))
|
|
176
|
+
continue;
|
|
177
|
+
seen.add(key);
|
|
178
|
+
matches.push(adjusted);
|
|
179
|
+
if (matches.length > maximumCandidates)
|
|
180
|
+
throw new RelationshipApproximateMatchLimitError(maximumCandidates);
|
|
181
|
+
}
|
|
182
|
+
processedCharacters += chunk.length;
|
|
183
|
+
processedCodeUnits += chunk.reduce((total, character) => total + character.length, 0);
|
|
184
|
+
tail = combined.slice(-overlapSize);
|
|
185
|
+
chunk = [];
|
|
186
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
187
|
+
};
|
|
188
|
+
for (const character of normalizedContent) {
|
|
189
|
+
chunk.push(character);
|
|
190
|
+
if (chunk.length >= chunkSize)
|
|
191
|
+
await processChunk();
|
|
192
|
+
}
|
|
193
|
+
await processChunk();
|
|
194
|
+
return selectApproximateNameMatches(matches, referenceLength, limit);
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=relationship-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationship-search.js","sourceRoot":"","sources":["../src/relationship-search.ts"],"names":[],"mappings":"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"}
|