feat: wire market batch submission flow
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { buildMarketCsv } from "./csv-exporter";
|
||||
import { createBatchPayload, type BatchPayload } from "./batch-payload";
|
||||
import {
|
||||
applyRowOrder,
|
||||
applyRowVisibility,
|
||||
@@ -16,6 +17,11 @@ import {
|
||||
setToolbarExportStatus
|
||||
} from "./plugin-toolbar";
|
||||
import { createMarketResultStore } from "./result-store";
|
||||
import {
|
||||
isAuthResponseMessage,
|
||||
type AuthStateValue
|
||||
} from "../../shared/auth-messages";
|
||||
import { createBatchSubmitClient } from "../../shared/batch-submit-client";
|
||||
import type {
|
||||
MarketApiResult,
|
||||
MarketFilterState,
|
||||
@@ -33,24 +39,38 @@ interface MutationObserverLike {
|
||||
export interface CreateMarketControllerOptions {
|
||||
buildCsv?: (records: MarketRecord[]) => string;
|
||||
document: Document;
|
||||
getAuthState?: () => Promise<AuthStateValue>;
|
||||
loadAuthorMetrics?: (authorId: string) => Promise<MarketApiResult>;
|
||||
mutationObserverFactory?: (
|
||||
callback: MutationCallback
|
||||
) => MutationObserverLike;
|
||||
onCsvReady?: (csv: string) => void;
|
||||
promptBatchName?: () => string | null;
|
||||
resultStore?: ReturnType<typeof createMarketResultStore>;
|
||||
submitBatch?: (payload: BatchPayload) => Promise<unknown>;
|
||||
window: Window;
|
||||
}
|
||||
|
||||
export function createMarketController(options: CreateMarketControllerOptions) {
|
||||
const marketApiClient = createMarketApiClient();
|
||||
const sendRuntimeMessage = createRuntimeMessageSender();
|
||||
const resultStore = options.resultStore ?? createMarketResultStore();
|
||||
const loadAuthorMetrics =
|
||||
options.loadAuthorMetrics ?? marketApiClient.loadAuthorAseInfo;
|
||||
const buildCsv = options.buildCsv ?? buildMarketCsv;
|
||||
const getAuthState = options.getAuthState ?? (() => readAuthState(sendRuntimeMessage));
|
||||
const mutationObserverFactory =
|
||||
options.mutationObserverFactory ??
|
||||
((callback: MutationCallback) => new MutationObserver(callback));
|
||||
const promptBatchName =
|
||||
options.promptBatchName ??
|
||||
(() => options.window.prompt("请输入批次名称"));
|
||||
const submitBatch =
|
||||
options.submitBatch ??
|
||||
createBatchSubmitClient({
|
||||
baseUrl: "http://127.0.0.1:4319",
|
||||
sendMessage: sendRuntimeMessage
|
||||
}).submitBatch;
|
||||
const exportRangeController = createExportRangeController({
|
||||
document: options.document,
|
||||
onProgress: ({ currentPage, totalPages }) => {
|
||||
@@ -119,7 +139,46 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
||||
}
|
||||
},
|
||||
onSubmitBatch: async () => {
|
||||
setToolbarExportStatus(toolbar, "批次提交功能开发中");
|
||||
const exportTarget = readToolbarExportTarget(toolbar);
|
||||
if (!exportTarget.target) {
|
||||
setToolbarExportStatus(toolbar, exportTarget.error ?? "导出配置无效");
|
||||
return;
|
||||
}
|
||||
|
||||
const batchName = promptBatchName();
|
||||
if (batchName === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!batchName.trim()) {
|
||||
setToolbarExportStatus(toolbar, "请输入批次名称");
|
||||
return;
|
||||
}
|
||||
|
||||
setToolbarBusyState(toolbar, true);
|
||||
try {
|
||||
const records = await exportRecords(exportTarget.target, "提交中");
|
||||
const authState = await getAuthState();
|
||||
if (!authState.isAuthenticated) {
|
||||
throw new Error("请先登录插件");
|
||||
}
|
||||
|
||||
const payload = createBatchPayload({
|
||||
authState,
|
||||
batchName,
|
||||
createdAt: new Date().toISOString(),
|
||||
records
|
||||
});
|
||||
await submitBatch(payload);
|
||||
setToolbarExportStatus(toolbar, "批次提交成功");
|
||||
} catch (error) {
|
||||
setToolbarExportStatus(
|
||||
toolbar,
|
||||
error instanceof Error ? error.message : "批次提交失败,请稍后重试"
|
||||
);
|
||||
} finally {
|
||||
setToolbarBusyState(toolbar, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -228,9 +287,12 @@ export function createMarketController(options: CreateMarketControllerOptions) {
|
||||
});
|
||||
}
|
||||
|
||||
async function exportRecords(target: MarketExportTarget): Promise<MarketRecord[]> {
|
||||
async function exportRecords(
|
||||
target: MarketExportTarget,
|
||||
inProgressLabel = "导出中"
|
||||
): Promise<MarketRecord[]> {
|
||||
if (target.mode === "count" && target.pageCount <= 1) {
|
||||
setToolbarExportStatus(toolbar, "导出中...");
|
||||
setToolbarExportStatus(toolbar, `${inProgressLabel}...`);
|
||||
await prepareCurrentPageForExport();
|
||||
return getVisibleOrderedRecords();
|
||||
}
|
||||
@@ -556,6 +618,32 @@ function mergeFieldMap<T extends Record<string, string | undefined>>(
|
||||
return merged as T;
|
||||
}
|
||||
|
||||
function createRuntimeMessageSender(): (message: unknown) => Promise<unknown> {
|
||||
return (message: unknown) =>
|
||||
Promise.resolve(
|
||||
(
|
||||
globalThis as typeof globalThis & {
|
||||
chrome?: {
|
||||
runtime?: {
|
||||
sendMessage?: (payload: unknown) => Promise<unknown>;
|
||||
};
|
||||
};
|
||||
}
|
||||
).chrome?.runtime?.sendMessage?.(message)
|
||||
);
|
||||
}
|
||||
|
||||
async function readAuthState(
|
||||
sendMessage: (message: unknown) => Promise<unknown>
|
||||
): Promise<AuthStateValue> {
|
||||
const response = await sendMessage({ type: "auth:get-state" });
|
||||
if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:state") {
|
||||
throw new Error("请先登录插件");
|
||||
}
|
||||
|
||||
return response.value;
|
||||
}
|
||||
|
||||
function mergeStringValue(
|
||||
current: string | undefined,
|
||||
incoming: string | undefined
|
||||
|
||||
Reference in New Issue
Block a user