微件:Excel2Page

来自卡厄思梦境WIKI
跳转到导航 跳转到搜索

模板:Path

准备中...

生成结果(0 个页面)

0 待处理
0 处理中
0 成功
0 失败
0 跳过
' : ''; return '' + '
' + '
' + '' + esc(item.page) + '' + ' {{' + esc(item.temple) + '}}' + ' ' + '
' + '
' + esc(item.wikitext) + '
' + statusHtml + '
'; } function bindItemEvents(div, item) { var toggleBtn = div.querySelector('.e2p-item-toggle'); if (toggleBtn) { toggleBtn.addEventListener('click', function (e) { e.stopPropagation(); var expanded = div.classList.toggle('expanded'); toggleBtn.textContent = expanded ? '收起' : '展开'; }); } var cb = div.querySelector('.e2p-result-checkbox'); if (cb) { cb.addEventListener('change', function () { item.checked = cb.checked; updateSubmitBtn(); }); } } function refreshItemEl(item) { var div = $('e2p-item-' + item.idx); if (!div) return; var wasExpanded = div.classList.contains('expanded'); div.className = 'e2p-result-item status-' + item.status + (wasExpanded ? ' expanded' : ''); div.innerHTML = buildItemHtml(item); bindItemEvents(div, item); if (wasExpanded) { var tb = div.querySelector('.e2p-item-toggle'); if (tb) tb.textContent = '收起'; } } /* ═══════════════════════════════════════════ 统计 ═══════════════════════════════════════════ */ function updateStats() { var s = { pending: 0, running: 0, success: 0, error: 0, skipped: 0 }; state.items.forEach(function (it) { s[it.status] = (s[it.status] || 0) + 1; }); state.stats = s; $('e2p-stat-pending').textContent = s.pending + ' 待处理'; $('e2p-stat-running').textContent = s.running + ' 处理中'; $('e2p-stat-success').textContent = s.success + ' 成功'; $('e2p-stat-error').textContent = s.error + ' 失败'; $('e2p-stat-skipped').textContent = s.skipped + ' 跳过'; } function updateSubmitBtn() { var n = state.items.filter(function (it) { return it.checked && it.status === 'pending'; }).length; submitBtn.disabled = (n === 0) || state.isRunning; submitBtn.textContent = '提交选中页面(' + n + ')'; } /* ═══════════════════════════════════════════ 全选 / 取消全选 ═══════════════════════════════════════════ */ selectAllBtn.addEventListener('click', function () { state.items.forEach(function (item) { if (item.status !== 'pending') return; item.checked = true; var cb = document.querySelector('#e2p-item-' + item.idx + ' .e2p-result-checkbox'); if (cb) cb.checked = true; }); updateSubmitBtn(); }); deselectAllBtn.addEventListener('click', function () { state.items.forEach(function (item) { if (item.status !== 'pending') return; item.checked = false; var cb = document.querySelector('#e2p-item-' + item.idx + ' .e2p-result-checkbox'); if (cb) cb.checked = false; }); updateSubmitBtn(); }); /* ═══════════════════════════════════════════ 展开 / 折叠全部 ═══════════════════════════════════════════ */ toggleAllBtn.addEventListener('click', function () { state.allExpanded = !state.allExpanded; toggleAllBtn.textContent = state.allExpanded ? '折叠全部' : '展开全部'; resultList.querySelectorAll('.e2p-result-item').forEach(function (div) { div.classList.toggle('expanded', state.allExpanded); var btn = div.querySelector('.e2p-item-toggle'); if (btn) btn.textContent = state.allExpanded ? '收起' : '展开'; }); }); /* ═══════════════════════════════════════════ 返回 / 重置 ═══════════════════════════════════════════ */ backBtn.addEventListener('click', function () { if (state.isRunning) return; showStep('input'); }); resetBtn.addEventListener('click', function () { if (state.isRunning) { if (!confirm('当前正在运行中,确定要停止并重置吗?')) return; state.stopFlag = true; } pasteArea.value = ''; previewSection.style.display = 'none'; parseHint.textContent = ''; parseHint.style.color = ''; state.parsed = null; state.items = []; resultList.innerHTML = ''; progressWrap.style.display = 'none'; showStep('input'); updateStats(); updateSubmitBtn(); }); /* ═══════════════════════════════════════════ MediaWiki API ═══════════════════════════════════════════ */ function getToken() { return new mw.Api().getToken('csrf'); } function pageExists(title) { return new mw.Api().get({ action: 'query', titles: title, formatversion: 2 }).then(function (data) { var pages = data.query.pages; return pages && pages.length > 0 && pages[0].pageid > 0; }); } function editPage(token, title, content, summary, append) { var params = { action: 'edit', title: title, summary: summary, token: token, formatversion: 2 }; if (append) { params.appendtext = content; } else { params.text = content; } return new mw.Api().post(params); } /* ═══════════════════════════════════════════ 提交流程 ═══════════════════════════════════════════ */ submitBtn.addEventListener('click', function () { if (state.isRunning) return; var toProcess = state.items.filter(function (it) { return it.checked && it.status === 'pending'; }); if (toProcess.length === 0) return; /* 仅预览模式 */ if (optPreviewOnly.checked) { toProcess.forEach(function (item) { var div = $('e2p-item-' + item.idx); if (!div) return; div.classList.add('expanded'); var btn = div.querySelector('.e2p-item-toggle'); if (btn) btn.textContent = '收起'; }); alert('预览模式:已展开 ' + toProcess.length + ' 个条目的 Wikitext,未实际提交。'); return; } if (!confirm('将提交 ' + toProcess.length + ' 个页面,确认吗?')) return; /* 启动 */ state.isRunning = true; state.stopFlag = false; submitBtn.style.display = 'none'; stopBtn.style.display = ''; selectAllBtn.style.display = 'none'; deselectAllBtn.style.display = 'none'; backBtn.disabled = true; progressWrap.style.display = ''; progressBar.style.width = '0%'; progressText.textContent = '正在获取 Token...'; var summary = summaryInput.value || '通过 Excel2Page 批量创建'; var skipExist = optSkipExist.checked; var appendMode = optAppend.checked; getToken().then(function (token) { return processItems(toProcess, token, summary, skipExist, appendMode); }).then(function () { finishRun(); }).catch(function (err) { progressText.textContent = '发生错误:' + String(err); finishRun(); }); }); stopBtn.addEventListener('click', function () { state.stopFlag = true; progressText.textContent = '正在停止...'; }); function finishRun() { state.isRunning = false; stopBtn.style.display = 'none'; submitBtn.style.display = ''; selectAllBtn.style.display = ''; deselectAllBtn.style.display = ''; backBtn.disabled = false; updateSubmitBtn(); } /** 顺序处理,避免并发限流 */ function processItems(items, token, summary, skipExist, appendMode) { var total = items.length; var done = 0; function next(idx) { if (idx >= items.length) { updateStats(); return Promise.resolve(); } /* 停止标志 */ if (state.stopFlag) { for (var k = idx; k < items.length; k++) { items[k].status = 'skipped'; items[k].statusMsg = '已停止'; refreshItemEl(items[k]); } updateStats(); return Promise.resolve(); } var item = items[idx]; item.status = 'running'; item.statusMsg = '处理中...'; refreshItemEl(item); updateStats(); progressBar.style.width = Math.round(done / total * 100) + '%'; progressText.textContent = '处理中 ' + (done + 1) + ' / ' + total + ':' + item.page; var p; if (skipExist) { p = pageExists(item.page).then(function (exists) { if (exists) { item.status = 'skipped'; item.statusMsg = '页面已存在,已跳过'; refreshItemEl(item); done++; updateStats(); return next(idx + 1); } return doEdit(item, token, summary, appendMode).then(function () { done++; updateStats(); return next(idx + 1); }); }); } else { p = doEdit(item, token, summary, appendMode).then(function () { done++; updateStats(); return next(idx + 1); }); } return p.catch(function (err) { item.status = 'error'; item.statusMsg = '错误:' + String(err); refreshItemEl(item); done++; updateStats(); return next(idx + 1); }); } return next(0).then(function () { progressBar.style.width = '100%'; var s = state.stats; progressText.textContent = '完成!成功 ' + s.success + ',跳过 ' + s.skipped + ',失败 ' + s.error; }); } function doEdit(item, token, summary, appendMode) { return editPage(token, item.page, item.wikitext, summary, appendMode) .then(function (data) { if (data && data.edit && (data.edit.result === 'Success' || data.edit.nochange !== undefined)) { item.status = 'success'; item.statusMsg = data.edit.nochange !== undefined ? '内容未变化(已跳过)' : '提交成功'; } else { item.status = 'error'; item.statusMsg = '提交失败:' + JSON.stringify(data); } refreshItemEl(item); }) .catch(function (err) { item.status = 'error'; item.statusMsg = 'API 错误:' + String(err); refreshItemEl(item); throw err; }); } /* ═══════════════════════════════════════════ 初始化 ═══════════════════════════════════════════ */ showStep('input'); updateStats(); updateSubmitBtn(); }());