dsh-plugin-update 0.5.8 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -4
- package/README.md +23 -8
- package/dist/bilingual.d.ts +4 -4
- package/dist/bilingual.js +300 -1
- package/dist/changelog.d.ts +19 -13
- package/dist/changelog.js +60 -22
- package/dist/diag.d.ts +3 -0
- package/dist/diag.js +32 -20
- package/dist/entry-batch.d.ts +5 -1
- package/dist/entry-batch.js +6 -4
- package/dist/entry.d.ts +26 -1
- package/dist/entry.js +69 -25
- package/dist/host-batch.js +104 -13
- package/dist/http.d.ts +2 -2
- package/dist/http.js +1 -1
- package/dist/panel-batch.d.ts +46 -10
- package/dist/panel-batch.js +484 -150
- package/dist/panel.d.ts +35 -25
- package/dist/panel.js +504 -362
- package/dist/store.d.ts +42 -0
- package/dist/store.js +139 -0
- package/package.json +1 -1
package/dist/host-batch.js
CHANGED
|
@@ -19,10 +19,13 @@ import { createHostUpdate } from "./host.js";
|
|
|
19
19
|
import { defaultHomeDir } from "./reader.js";
|
|
20
20
|
import { compareReleaseVersions } from "./service.js";
|
|
21
21
|
import {
|
|
22
|
-
|
|
22
|
+
createBatchOwnerPorts,
|
|
23
23
|
createSkipDiskPorts,
|
|
24
24
|
createUpdateQueuePorts,
|
|
25
|
-
|
|
25
|
+
emptyBatchInventory,
|
|
26
|
+
isVersionSkipped,
|
|
27
|
+
normalizeBatchInventory,
|
|
28
|
+
normalizeBatchPrefs
|
|
26
29
|
} from "./store.js";
|
|
27
30
|
const DEFAULT_DRAIN_INTERVAL_MS = 5e3;
|
|
28
31
|
const MIN_DRAIN_INTERVAL_MS = 1e3;
|
|
@@ -405,31 +408,56 @@ function createMultiHostUpdate(deps = {}, options) {
|
|
|
405
408
|
return runtime;
|
|
406
409
|
});
|
|
407
410
|
const runtimeByKey = new Map(runtimes.map((rt) => [rt.spec.key, rt]));
|
|
408
|
-
const
|
|
411
|
+
const ownerPorts = batchScope && batchScope.profileDir ? createBatchOwnerPorts(batchScope.homeDir, batchScope.profileDir, prefix) : null;
|
|
409
412
|
let memSession = null;
|
|
413
|
+
let memInventory = null;
|
|
414
|
+
let memPrefs = {};
|
|
410
415
|
let driveActive = false;
|
|
411
416
|
let liveSession = null;
|
|
412
417
|
let lastRun = null;
|
|
413
418
|
let drainTimer = null;
|
|
414
419
|
let disposed = false;
|
|
415
420
|
async function readSession() {
|
|
416
|
-
if (
|
|
421
|
+
if (ownerPorts) return await ownerPorts.readBatch();
|
|
417
422
|
return memSession ?? emptyBatchSession();
|
|
418
423
|
}
|
|
419
424
|
async function saveSession(session) {
|
|
420
|
-
if (
|
|
421
|
-
await
|
|
425
|
+
if (ownerPorts) {
|
|
426
|
+
await ownerPorts.writeBatch(session);
|
|
422
427
|
return;
|
|
423
428
|
}
|
|
424
429
|
memSession = session;
|
|
425
430
|
}
|
|
426
431
|
async function clearSession() {
|
|
427
|
-
if (
|
|
428
|
-
await
|
|
432
|
+
if (ownerPorts) {
|
|
433
|
+
await ownerPorts.clearBatch();
|
|
429
434
|
return;
|
|
430
435
|
}
|
|
431
436
|
memSession = emptyBatchSession();
|
|
432
437
|
}
|
|
438
|
+
async function readInventory() {
|
|
439
|
+
if (ownerPorts) return await ownerPorts.readInventory();
|
|
440
|
+
return memInventory ?? emptyBatchInventory();
|
|
441
|
+
}
|
|
442
|
+
async function writeInventory(inventory) {
|
|
443
|
+
if (ownerPorts) {
|
|
444
|
+
await ownerPorts.writeInventory(inventory);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
memInventory = inventory;
|
|
448
|
+
}
|
|
449
|
+
async function readPrefs() {
|
|
450
|
+
if (ownerPorts) return await ownerPorts.readPrefs();
|
|
451
|
+
return memPrefs;
|
|
452
|
+
}
|
|
453
|
+
async function writePrefs(prefs) {
|
|
454
|
+
const normalized = normalizeBatchPrefs(prefs);
|
|
455
|
+
if (ownerPorts) {
|
|
456
|
+
await ownerPorts.writePrefs(normalized);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
memPrefs = normalized;
|
|
460
|
+
}
|
|
433
461
|
function newSessionId() {
|
|
434
462
|
const suffix = String(randomId() ?? "").replace(/[^A-Za-z0-9._~-]/g, "").slice(0, 24);
|
|
435
463
|
return now().toString(36) + "-" + (suffix || hash8(String(now())));
|
|
@@ -499,7 +527,19 @@ function createMultiHostUpdate(deps = {}, options) {
|
|
|
499
527
|
}
|
|
500
528
|
async function table(session, refresh = true) {
|
|
501
529
|
const built = await buildRows(session, refresh);
|
|
502
|
-
|
|
530
|
+
let inventory = emptyBatchInventory();
|
|
531
|
+
let prefs = {};
|
|
532
|
+
try {
|
|
533
|
+
inventory = await readInventory();
|
|
534
|
+
} catch {
|
|
535
|
+
inventory = emptyBatchInventory();
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
prefs = await readPrefs();
|
|
539
|
+
} catch {
|
|
540
|
+
prefs = {};
|
|
541
|
+
}
|
|
542
|
+
return { ok: true, session: built.session, rows: built.rows, progress: progressOf(built.session), inventory, prefs };
|
|
503
543
|
}
|
|
504
544
|
function denied() {
|
|
505
545
|
if (!scopeError) return null;
|
|
@@ -609,14 +649,42 @@ function createMultiHostUpdate(deps = {}, options) {
|
|
|
609
649
|
if (refuse) return refuse;
|
|
610
650
|
const session = await readSession();
|
|
611
651
|
if (!driveActive) {
|
|
652
|
+
const at = now();
|
|
653
|
+
let prev = emptyBatchInventory();
|
|
654
|
+
try {
|
|
655
|
+
prev = await readInventory();
|
|
656
|
+
} catch {
|
|
657
|
+
prev = emptyBatchInventory();
|
|
658
|
+
}
|
|
659
|
+
const entries = { ...prev.entries };
|
|
612
660
|
for (const rt of runtimes) {
|
|
613
661
|
try {
|
|
614
662
|
const outcome = await rt.check(rt.spec.key, rt.spec);
|
|
615
663
|
rt.cache = { ...rt.cache, error: outcome.kind === "failed" ? outcome.error : null };
|
|
664
|
+
const snapshot = asRecord(rt.cache.snapshot);
|
|
665
|
+
const installed = firstText(snapshot["installedVersion"], snapshot["runningVersion"]);
|
|
666
|
+
const canInstallRaw = snapshot["canInstall"];
|
|
667
|
+
const canInstall = typeof canInstallRaw === "boolean" ? canInstallRaw : null;
|
|
668
|
+
if (outcome.kind === "update") {
|
|
669
|
+
entries[rt.spec.key] = { lastCheckedAt: at, installedVersion: installed, latestVersion: outcome.version, canInstall, error: null };
|
|
670
|
+
} else if (outcome.kind === "current") {
|
|
671
|
+
entries[rt.spec.key] = { lastCheckedAt: at, installedVersion: installed, latestVersion: installed, canInstall: false, error: null };
|
|
672
|
+
} else if (outcome.kind === "skipped") {
|
|
673
|
+
entries[rt.spec.key] = { lastCheckedAt: at, installedVersion: installed, latestVersion: outcome.version, canInstall: false, error: null };
|
|
674
|
+
} else {
|
|
675
|
+
entries[rt.spec.key] = { lastCheckedAt: at, installedVersion: installed, latestVersion: firstText(snapshot["latestVersion"]), canInstall, error: outcome.error };
|
|
676
|
+
}
|
|
616
677
|
} catch (error) {
|
|
617
|
-
|
|
678
|
+
const code = errorPayloadOf(error).error;
|
|
679
|
+
rt.cache = { ...rt.cache, error: code };
|
|
680
|
+
const snapshot = asRecord(rt.cache.snapshot);
|
|
681
|
+
entries[rt.spec.key] = { lastCheckedAt: at, installedVersion: firstText(snapshot["installedVersion"], snapshot["runningVersion"]), latestVersion: firstText(snapshot["latestVersion"]), canInstall: typeof snapshot["canInstall"] === "boolean" ? snapshot["canInstall"] : null, error: code };
|
|
618
682
|
}
|
|
619
683
|
}
|
|
684
|
+
try {
|
|
685
|
+
await writeInventory(normalizeBatchInventory({ version: 1, updatedAt: at, entries }, at));
|
|
686
|
+
} catch {
|
|
687
|
+
}
|
|
620
688
|
}
|
|
621
689
|
return await table(session, false);
|
|
622
690
|
}
|
|
@@ -682,11 +750,12 @@ function createMultiHostUpdate(deps = {}, options) {
|
|
|
682
750
|
if (refuse) return refuse;
|
|
683
751
|
if (driveActive) return { ok: false, error: "update-busy", errorKind: "update-busy" };
|
|
684
752
|
const disk = await readSession();
|
|
685
|
-
|
|
753
|
+
const hadUnfinished = disk.entries.length > 0 && !isBatchFinished(disk);
|
|
754
|
+
if (!hadUnfinished) return { ...await table(disk), resumed: false };
|
|
686
755
|
const resumed = resumeBatchSession(disk, now());
|
|
687
756
|
if (resumed !== disk) await saveSession(resumed);
|
|
688
757
|
try {
|
|
689
|
-
return await table(await drive(resumed, null, Number.POSITIVE_INFINITY));
|
|
758
|
+
return { ...await table(await drive(resumed, null, Number.POSITIVE_INFINITY)), resumed: true };
|
|
690
759
|
} catch (error) {
|
|
691
760
|
return { ok: false, ...errorPayloadOf(error) };
|
|
692
761
|
}
|
|
@@ -727,12 +796,32 @@ function createMultiHostUpdate(deps = {}, options) {
|
|
|
727
796
|
void tickDrain();
|
|
728
797
|
}, drainIntervalMs);
|
|
729
798
|
}
|
|
799
|
+
async function prefsPhone() {
|
|
800
|
+
const refuse = denied();
|
|
801
|
+
if (refuse) return refuse;
|
|
802
|
+
return { ok: true, prefs: await readPrefs() };
|
|
803
|
+
}
|
|
804
|
+
async function prefsSavePhone(args) {
|
|
805
|
+
const refuse = denied();
|
|
806
|
+
if (refuse) return refuse;
|
|
807
|
+
const current = await readPrefs();
|
|
808
|
+
const next = { ...current };
|
|
809
|
+
if ("checkOnOpen" in args) {
|
|
810
|
+
const v = args["checkOnOpen"];
|
|
811
|
+
if (typeof v !== "boolean") return { ok: false, error: "check-failed", errorKind: "check-failed" };
|
|
812
|
+
next.checkOnOpen = v;
|
|
813
|
+
}
|
|
814
|
+
await writePrefs(next);
|
|
815
|
+
return { ok: true, prefs: next };
|
|
816
|
+
}
|
|
730
817
|
const phoneNames = {
|
|
731
818
|
status: prefix + ".batchStatus",
|
|
732
819
|
check: prefix + ".batchCheck",
|
|
733
820
|
install: prefix + ".batchInstall",
|
|
734
821
|
resume: prefix + ".batchResume",
|
|
735
|
-
cancel: prefix + ".batchCancel"
|
|
822
|
+
cancel: prefix + ".batchCancel",
|
|
823
|
+
prefs: prefix + ".batchPrefs",
|
|
824
|
+
prefsSave: prefix + ".batchPrefsSave"
|
|
736
825
|
};
|
|
737
826
|
function phone(fn) {
|
|
738
827
|
return async (args) => {
|
|
@@ -749,6 +838,8 @@ function createMultiHostUpdate(deps = {}, options) {
|
|
|
749
838
|
handlers[phoneNames.install] = phone((args) => installPhone(args));
|
|
750
839
|
handlers[phoneNames.resume] = phone(() => resumePhone());
|
|
751
840
|
handlers[phoneNames.cancel] = phone(() => cancelPhone());
|
|
841
|
+
handlers[phoneNames.prefs] = phone(() => prefsPhone());
|
|
842
|
+
handlers[phoneNames.prefsSave] = phone((args) => prefsSavePhone(args));
|
|
752
843
|
for (const rt of runtimes) {
|
|
753
844
|
for (const name of Object.keys(rt.host.handlers)) {
|
|
754
845
|
const handler = rt.host.handlers[name];
|
package/dist/http.d.ts
CHANGED
|
@@ -11,8 +11,8 @@ export declare const DEFAULT_HTTP_STATUS_TIMEOUT_MS = 15000;
|
|
|
11
11
|
/** 单插件电话动作名(旧三电话与 src/config.ts PHONE_ACTIONS 同字面,不另起字面;#38 加 updateChangelog)。 */
|
|
12
12
|
export declare const HTTP_PHONE_ACTIONS: readonly ["updateStatus", "updateCheck", "updateInstall", "updateChangelog"];
|
|
13
13
|
export type HttpPhoneAction = (typeof HTTP_PHONE_ACTIONS)[number];
|
|
14
|
-
/**
|
|
15
|
-
export declare const HTTP_BATCH_ACTIONS: readonly ["batchStatus", "batchCheck", "batchInstall", "batchResume", "batchCancel"];
|
|
14
|
+
/** 批量七电话动作名(与 src/panel-batch.ts buildBatchPhoneNames 同字面,不另起字面;同一内核)。 */
|
|
15
|
+
export declare const HTTP_BATCH_ACTIONS: readonly ["batchStatus", "batchCheck", "batchInstall", "batchResume", "batchCancel", "batchPrefs", "batchPrefsSave"];
|
|
16
16
|
export type HttpBatchAction = (typeof HTTP_BATCH_ACTIONS)[number];
|
|
17
17
|
/** 逐电话覆写表:键为全电话名(prefix.动作)或短动作名;未知键拒绝。 */
|
|
18
18
|
export type HttpRoutes = Record<string, string>;
|
package/dist/http.js
CHANGED
|
@@ -11,7 +11,7 @@ const DEFAULT_HTTP_CHECK_TIMEOUT_MS = 15e3;
|
|
|
11
11
|
const DEFAULT_HTTP_INSTALL_TIMEOUT_MS = 16 * 6e4;
|
|
12
12
|
const DEFAULT_HTTP_STATUS_TIMEOUT_MS = 15e3;
|
|
13
13
|
const HTTP_PHONE_ACTIONS = ["updateStatus", "updateCheck", "updateInstall", "updateChangelog"];
|
|
14
|
-
const HTTP_BATCH_ACTIONS = ["batchStatus", "batchCheck", "batchInstall", "batchResume", "batchCancel"];
|
|
14
|
+
const HTTP_BATCH_ACTIONS = ["batchStatus", "batchCheck", "batchInstall", "batchResume", "batchCancel", "batchPrefs", "batchPrefsSave"];
|
|
15
15
|
function isAbsoluteUrl(value) {
|
|
16
16
|
return /^https?:\/\//i.test(value);
|
|
17
17
|
}
|
package/dist/panel-batch.d.ts
CHANGED
|
@@ -55,13 +55,22 @@ export interface BatchPanelOptions {
|
|
|
55
55
|
*/
|
|
56
56
|
onCloseRequested?: () => void | Promise<void>;
|
|
57
57
|
/**
|
|
58
|
-
* 语言覆盖(#
|
|
58
|
+
* 语言覆盖(#59 起消费:新文案走集中字典单语渲染;既有散落文案保持基线不变)。
|
|
59
59
|
* 形态与入口件一致:'zh' | 'en' | { getActive(): string; subscribe?(cb): () => void }。
|
|
60
60
|
*/
|
|
61
61
|
locale?: unknown;
|
|
62
|
+
/**
|
|
63
|
+
* 打开面板自动查(#59 D3):缺省 true。false 即手动挡(行为回今天,只修文案)。
|
|
64
|
+
* 优先级:用户偏好(prefs.json)> 本选项 > 缺省。
|
|
65
|
+
*/
|
|
66
|
+
checkOnOpen?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* 自动继续未终态轮次(#59 Q3:与显式按钮并存,常开)。false 可关(测试与特殊集成用)。
|
|
69
|
+
*/
|
|
70
|
+
autoResume?: boolean;
|
|
62
71
|
}
|
|
63
72
|
/** 面板可点的动作(HTML 上 data-act 一一对应;测试走同一条路)。 */
|
|
64
|
-
export type BatchPanelActionKind = 'check' | 'install' | 'resume' | 'cancel' | 'row-install' | 'row-skip' | 'row-resume-skip' | 'row-cancel-queue' | 'row-copy-manual' | 'row-copy-diag' | 'toggle-details' | 'restart' | 'close';
|
|
73
|
+
export type BatchPanelActionKind = 'check' | 'install' | 'resume' | 'cancel' | 'row-install' | 'row-skip' | 'row-resume-skip' | 'row-cancel-queue' | 'row-copy-manual' | 'row-copy-diag' | 'toggle-details' | 'restart' | 'close' | 'toggle-check-on-open';
|
|
65
74
|
/** 挂载点:只要有 innerHTML 的容器即可(浏览器元素或测试替身都行)。 */
|
|
66
75
|
export interface BatchPanelContainer {
|
|
67
76
|
innerHTML: string;
|
|
@@ -76,20 +85,22 @@ export interface BatchPanelController {
|
|
|
76
85
|
setMode(mode: BatchPanelMode): void;
|
|
77
86
|
unmount(): void;
|
|
78
87
|
}
|
|
79
|
-
/**
|
|
88
|
+
/** 批量七个电话名(与宿主侧 MultiHostUpdate.phoneNames 同一形状)。 */
|
|
80
89
|
export interface BatchPhoneNames {
|
|
81
90
|
status: string;
|
|
82
91
|
check: string;
|
|
83
92
|
install: string;
|
|
84
93
|
resume: string;
|
|
85
94
|
cancel: string;
|
|
95
|
+
prefs: string;
|
|
96
|
+
prefsSave: string;
|
|
86
97
|
}
|
|
87
98
|
/** 批量面板轮询口径(默认 1.5 秒、下限 250 毫秒,与单插件面板同一套下限)。 */
|
|
88
99
|
export declare const BATCH_PANEL_POLL: {
|
|
89
100
|
readonly defaultMs: 1500;
|
|
90
101
|
readonly minMs: 250;
|
|
91
102
|
};
|
|
92
|
-
/** 批量电话名拼法:前缀 +
|
|
103
|
+
/** 批量电话名拼法:前缀 + 七个固定动作名(前缀形状校验与单插件面板同一套)。 */
|
|
93
104
|
export declare function buildBatchPhoneNames(prefix: string): BatchPhoneNames;
|
|
94
105
|
export interface BatchLedgerCounts {
|
|
95
106
|
/** phase=ready:有新版、还没安装。 */
|
|
@@ -114,20 +125,37 @@ export interface BatchLedgerCounts {
|
|
|
114
125
|
* 宿主忙时先写占位再回 update-busy,面板把它翻回「可更新」,免得总账把它报成失败。
|
|
115
126
|
*/
|
|
116
127
|
export declare function batchLedgerCounts(rows: readonly BatchRowView[]): BatchLedgerCounts;
|
|
117
|
-
/** 分类计数 → 一句话总账(只出现非零档,顺序固定:可更新 · 安装中 · 待查 · 待重启 · 失败 · 已跳过 ·
|
|
118
|
-
export declare function batchLedgerText(counts: BatchLedgerCounts): string;
|
|
128
|
+
/** 分类计数 → 一句话总账(只出现非零档,顺序固定:可更新 · 安装中 · 待查 · 待重启 · 失败 · 已跳过 · 已最新;#64 单语:缺省 zh 零回归)。 */
|
|
129
|
+
export declare function batchLedgerText(counts: BatchLedgerCounts, lang?: unknown): string;
|
|
119
130
|
/**
|
|
120
131
|
* 排队中的状态词:只回答「还要等多久」。位置从该行的队列视图来。
|
|
121
132
|
* queue.ts 的 position 是 waiting 顺位(队首为 1、0 = 自己正在装),而正在装的那一家也压在这一家前面,
|
|
122
133
|
* 所以「前方 N 个」= position N(队首那家前方正好 1 个:正在装的拥有者)。
|
|
123
134
|
* 位置取不到(宿主只记了忙、没给占位读数)就说「等前面安装完」,不猜数字。
|
|
124
135
|
*/
|
|
125
|
-
export declare function batchQueuedStatus(position: number | null): string;
|
|
136
|
+
export declare function batchQueuedStatus(position: number | null, lang?: unknown): string;
|
|
137
|
+
/** 知识账本里的一行(只做展示,不参与安装决策)。 */
|
|
138
|
+
export interface BatchKnowledgeEntry {
|
|
139
|
+
lastCheckedAt: number;
|
|
140
|
+
installedVersion: string | null;
|
|
141
|
+
latestVersion: string | null;
|
|
142
|
+
canInstall: boolean | null;
|
|
143
|
+
error: string | null;
|
|
144
|
+
}
|
|
145
|
+
/** 有未终态行(控制区出现条件:盘上有没做完的一轮)。 */
|
|
146
|
+
export declare function hasUnfinishedRows(rows: readonly BatchRowView[], session?: unknown): boolean;
|
|
147
|
+
export declare function unfinishedCount(rows: readonly BatchRowView[], session?: unknown): number;
|
|
126
148
|
/**
|
|
127
149
|
* 一行的状态词:只回答一个问题——这家的**下一步**是什么。
|
|
128
150
|
* 中文可执行,不写相位英文(相位只留在 data-phase 属性上,给人看的这句永远是动作)。
|
|
151
|
+
* (#59 D2:调用方在无轮次 + 有知识时优先用 batchRowKnowledgeText;本函数语义冻结,旧快照不动。)
|
|
152
|
+
*/
|
|
153
|
+
export declare function batchRowStatus(row: BatchRowView, skippedVersion?: string | null, lang?: unknown): string;
|
|
154
|
+
/**
|
|
155
|
+
* 无轮次时的知识行(#59 D2):pending + 有知识即按知识展示;有轮次未做完仍走执行态。
|
|
156
|
+
* 无知识(从没查过)回 null,调用方回退旧 pending 文案。
|
|
129
157
|
*/
|
|
130
|
-
export declare function
|
|
158
|
+
export declare function batchRowKnowledgeText(row: BatchRowView, entry: BatchKnowledgeEntry | null, lang?: unknown): string | null;
|
|
131
159
|
export interface BatchPanelRenderInput {
|
|
132
160
|
rows?: readonly BatchRowView[];
|
|
133
161
|
theme?: UpdatePanelTheme;
|
|
@@ -151,15 +179,23 @@ export interface BatchPanelRenderInput {
|
|
|
151
179
|
noticeKey?: string | null;
|
|
152
180
|
/** 键 -> 该行已取到的日志全文(只传有文本的;取不到与没展开即中性提示,不挡安装)。 */
|
|
153
181
|
changelogs?: Record<string, string | null>;
|
|
182
|
+
/** 轮次会话(有未终态行才画控制区;不传按行相位回退旧口径,兼容旧快照)。 */
|
|
183
|
+
session?: unknown;
|
|
184
|
+
/** 知识账本(无轮次时行按知识展示;只做展示,不参与安装决策)。 */
|
|
185
|
+
inventory?: unknown;
|
|
186
|
+
/** 偏好(底部勾选的受控状态;不传不画勾选)。 */
|
|
187
|
+
prefs?: unknown;
|
|
188
|
+
/** 语言(单语渲染新文案用;不传跟随全局信号)。 */
|
|
189
|
+
lang?: unknown;
|
|
154
190
|
}
|
|
155
191
|
/** 整面板 HTML(含样式;重绘即整体替换 innerHTML,故每次都带 style 也只留一份)。 */
|
|
156
192
|
export declare function renderBatchPanelHTML(input: BatchPanelRenderInput): string;
|
|
157
193
|
export declare const UPDATE_BATCH_PANEL_CSS: string;
|
|
158
194
|
/**
|
|
159
|
-
* 批量面板的
|
|
195
|
+
* 批量面板的 Archive 皮肤(#20 同一套口径:只换颜色/字体/间距,不改顺序、不藏东西)。
|
|
160
196
|
* 卷宗抬头右侧给大印章留 120px(与单插件面板档案头同一处理)。
|
|
161
197
|
*/
|
|
162
|
-
export declare const
|
|
198
|
+
export declare const UPDATE_BATCH_PANEL_ARCHIVE_CSS: string;
|
|
163
199
|
/**
|
|
164
200
|
* 挂批量面板(调用方一行即跑):
|
|
165
201
|
* ```js
|