Repository navigation
Expand file tree
/
Copy pathpopup.js
More file actions
149 lines (134 loc) · 5.12 KB
/
Copy pathpopup.js
File metadata and controls
149 lines (134 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
(function initializePopup() {
"use strict";
const csvFile = document.getElementById("csvFile");
const fileMeta = document.getElementById("fileMeta");
const status = document.getElementById("status");
const issues = document.getElementById("issues");
const preview = document.getElementById("preview");
const previewCount = document.getElementById("previewCount");
const previewBody = document.getElementById("previewBody");
const startBtn = document.getElementById("startBtn");
let readyRecords = [];
function setStatus(message, tone = "neutral") {
status.textContent = message;
status.dataset.tone = tone;
}
function formatBytes(bytes) {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
function issueText(issue) {
const prefix = issue.row ? `第 ${issue.row} 行` : "文件";
return `${prefix}:${issue.message}`;
}
function renderIssues(errors, warnings) {
issues.replaceChildren();
const combined = [
...errors.map((item) => ({ ...item, kind: "错误" })),
...warnings.map((item) => ({ ...item, kind: "提醒" })),
];
if (combined.length === 0) {
issues.hidden = true;
return;
}
combined.slice(0, 6).forEach((item) => {
const line = document.createElement("p");
line.textContent = `${item.kind}:${issueText(item)}`;
issues.appendChild(line);
});
if (combined.length > 6) {
const more = document.createElement("p");
more.textContent = `另有 ${combined.length - 6} 条未显示`;
issues.appendChild(more);
}
issues.hidden = false;
}
function renderPreview(records) {
previewBody.replaceChildren();
records.slice(0, 3).forEach((record) => {
const row = document.createElement("tr");
[record.file_name, record.title, record.keywords].forEach((value) => {
const cell = document.createElement("td");
cell.textContent = value;
cell.title = value;
row.appendChild(cell);
});
previewBody.appendChild(row);
});
previewCount.textContent = records.length > 3 ? `显示 3 / ${records.length}` : `${records.length} 条`;
preview.hidden = records.length === 0;
}
function resetData() {
readyRecords = [];
startBtn.disabled = true;
preview.hidden = true;
issues.hidden = true;
fileMeta.hidden = true;
}
async function loadCSV(file) {
resetData();
if (!file) {
setStatus("等待选择文件");
return;
}
if (file.size > 5 * 1024 * 1024) {
setStatus("文件超过 5 MB,请拆分后重试", "error");
return;
}
fileMeta.textContent = `${file.name},${formatBytes(file.size)}`;
fileMeta.hidden = false;
setStatus("正在读取并校验 CSV", "working");
try {
const decoded = window.VCGCSV.decodeCSVBuffer(await file.arrayBuffer());
const parsed = window.VCGCSV.csvToRecords(decoded.text);
const result = window.VCGCSV.validateRecords(parsed);
renderIssues(result.errors, result.warnings);
renderPreview(result.validRecords);
if (result.errors.length > 0) {
setStatus(`发现 ${result.errors.length} 个错误,请修正 CSV`, "error");
return;
}
readyRecords = result.validRecords;
startBtn.disabled = false;
const warningText = result.warnings.length > 0 ? `,${result.warnings.length} 条提醒` : "";
setStatus(`已读取 ${readyRecords.length} 条,编码 ${decoded.encoding}${warningText}`, "success");
} catch (error) {
console.error(error);
setStatus(error instanceof Error ? error.message : "CSV 读取失败", "error");
}
}
function queryActiveTab() {
return new Promise((resolve, reject) => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (chrome.runtime.lastError) return reject(new Error(chrome.runtime.lastError.message));
const tab = tabs[0];
if (!tab?.id) return reject(new Error("无法获取当前标签页"));
resolve(tab);
});
});
}
function sendToTab(tabId, message) {
return new Promise((resolve, reject) => {
chrome.tabs.sendMessage(tabId, message, (response) => {
if (chrome.runtime.lastError) return reject(new Error("请打开 VCG 草稿页面并刷新后重试"));
resolve(response);
});
});
}
csvFile.addEventListener("change", () => loadCSV(csvFile.files?.[0]));
startBtn.addEventListener("click", async () => {
if (readyRecords.length === 0) return;
startBtn.disabled = true;
setStatus("正在连接当前 VCG 页面", "working");
try {
const tab = await queryActiveTab();
const response = await sendToTab(tab.id, { action: "vcg:start", version: 1, records: readyRecords });
if (!response?.ok) throw new Error(response?.message || "任务未能启动");
setStatus("任务已启动,请使用网页右上角控制台", "success");
} catch (error) {
setStatus(error instanceof Error ? error.message : "任务启动失败", "error");
startBtn.disabled = false;
}
});
})();