feat(portal/t53): 進站完成安裝清單(leo 07-25:金鑰與 daemon 要在站內做,不然安裝沒完成)——常駐三項清單(下載小幫手/下載 config.json 站內生成/貼 Gemini 金鑰即時啟用)+新端點 POST /portal/admin/chat-key(改寫 tenant rag_chat 的 x-goog-api-key,admin 閘、金鑰不落 log)+session 回 email 供 config 生成

This commit is contained in:
uncle6me-web
2026-07-25 23:26:44 +08:00
parent 11ffd42899
commit a8d246ebe9
2 changed files with 129 additions and 21 deletions
+86 -21
View File
@@ -590,27 +590,10 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
$('v-firstsetup').classList.remove('on');
$('shell').classList.add('on');
$('tabbar').classList.add('on');
// t49 一次性歡迎引導(首次設定完成那一刻才出現;關掉就不再出現):
// 下一步只有兩件——裝同步小幫手(資料自動進來)、想問答就設金鑰。連去 installer /setup。
try {
if (localStorage.getItem('arcrun_onboarding') === '1' && !document.getElementById('onboard-card')) {
var setupUrl = (window.ARCRUN_CONFIG && window.ARCRUN_CONFIG.installerBase
? String(window.ARCRUN_CONFIG.installerBase).replace(/\/+$/, '')
: 'https://arcrun-installer.youlin-hsieh-dev.workers.dev') + '/setup';
var el = document.createElement('div');
el.id = 'onboard-card';
el.style.cssText = 'position:fixed;left:50%;bottom:24px;transform:translateX(-50%);z-index:60;max-width:560px;width:calc(100% - 32px);padding:18px 20px;border-radius:14px;background:rgba(var(--amber-rgb),.10);border:1px solid rgba(var(--amber-rgb),.45);backdrop-filter:blur(6px);font-size:14.5px;line-height:1.7';
el.innerHTML = '<b>🎉 你的知識庫開張了!</b>接下來只有一件事:'
+ '<a href="' + setupUrl + '" target="_blank" rel="noopener">下載同步小幫手設定</a>'
+ '——把你的資料夾連上來,檔案就會自動變成可搜尋的知識(想用 AI 問答,金鑰也在同一頁設定)。'
+ '<button id="onboard-close" style="margin-left:10px;border:none;background:none;color:inherit;cursor:pointer;font-size:13px;text-decoration:underline">知道了</button>';
document.body.appendChild(el);
document.getElementById('onboard-close').addEventListener('click', function () {
try { localStorage.removeItem('arcrun_onboarding'); } catch (e) { /* noop */ }
el.remove();
});
}
} catch (e) { /* 引導卡失敗不擋主流程 */ }
// t53(leo 07-25:「進站要做的事——給金鑰、下載 daemon——不然這個安裝沒完成」):
// 常駐「完成安裝」清單卡,三件做完才消失(localStorage 記進度;admin 才看得到——
// 金鑰與 daemon 設定是裝機者的事,同事帳號不顯示)。
try { renderSetupChecklist(); } catch (e) { /* 清單卡失敗不擋主流程 */ }
var p = S.profile || {};
$('side-foot').innerHTML = esc(p.display_name || '') + '<br>' + esc(location.host);
$('nav-workflows').classList.toggle('hide', !p.workflows_visible);
@@ -678,6 +661,88 @@ function taipeiMonthDay(ms) { var d = new Date(ms + TAIPEI_OFFSET_MS); return {
dropSession();
});
// ── t53 完成安裝清單(進站必見,三件做完才消失)─────────────────────────────
function setupSteps() {
try { return JSON.parse(localStorage.getItem('arcrun_setup_steps') || '{}'); } catch (e) { return {}; }
}
function markStep(k) {
var s = setupSteps(); s[k] = 1;
try { localStorage.setItem('arcrun_setup_steps', JSON.stringify(s)); } catch (e) { /* noop */ }
renderSetupChecklist();
}
function renderSetupChecklist() {
var old = document.getElementById('setup-checklist');
if (old) old.remove();
var p = S.profile || {};
if (p.role !== 'admin') return;
var s = setupSteps();
if (s.daemon && s.config && s.key) return; // 三件齊=安裝真的完成,不再打擾
var cfg = window.ARCRUN_CONFIG || {};
var daemonUrl = cfg.daemonDownload || 'https://raw.githubusercontent.com/youlinhsieh/arcrun-rag-bundles/main/daemon/ArcrunRAG-mac-unsigned.zip';
var row = function (done, id, html) {
return '<div style="display:flex;gap:10px;align-items:baseline;margin-top:10px">'
+ '<span>' + (done ? '✅' : '⬜') + '</span><div style="flex:1">' + html + '</div></div>';
};
var el = document.createElement('div');
el.id = 'setup-checklist';
el.style.cssText = 'position:fixed;right:20px;bottom:20px;z-index:60;max-width:400px;width:calc(100% - 40px);padding:18px 20px;border-radius:14px;background:rgba(var(--amber-rgb),.10);border:1px solid rgba(var(--amber-rgb),.45);backdrop-filter:blur(8px);font-size:14px;line-height:1.65';
el.innerHTML = '<b>還差 ' + (3 - (s.daemon?1:0) - (s.config?1:0) - (s.key?1:0)) + ' 步,安裝就真的完成了</b>'
+ row(s.daemon, 'daemon',
'<b>下載同步小幫手</b>(把資料夾變成知識庫)<br>'
+ '<a href="' + esc(daemonUrl) + '" id="sc-daemon">下載 Mac 版</a>'
+ '<span class="muted" style="font-size:12.5px">(封測版未簽章,第一次請右鍵→打開)</span>')
+ row(s.config, 'config',
'<b>下載設定檔</b> 放到 <code style="font-size:12px">~/.arcrun-rag/config.json</code><br>'
+ '<a href="#" id="sc-config">下載 config.json</a>')
+ row(s.key, 'key',
'<b>啟用 AI 問答</b><a href="https://aistudio.google.com" target="_blank" rel="noopener">aistudio.google.com</a> 免費申請)<br>'
+ '<input id="sc-key" type="password" placeholder="貼上 Google AI 金鑰" style="width:60%;padding:6px 8px;border-radius:8px;border:1px solid rgba(var(--ink-rgb),.25);background:rgba(var(--ink-rgb),.04);color:var(--ink)"> '
+ '<button class="btn3" id="sc-key-save" style="padding:6px 12px;border-radius:8px;cursor:pointer">啟用</button>'
+ '<div id="sc-key-msg" style="font-size:12.5px;min-height:1.1em"></div>')
+ '<div style="margin-top:10px;text-align:right"><button id="sc-later" style="border:none;background:none;color:inherit;cursor:pointer;font-size:12.5px;text-decoration:underline;opacity:.65">稍後再說</button></div>';
document.body.appendChild(el);
var dl = document.getElementById('sc-daemon');
if (dl) dl.addEventListener('click', function () { markStep('daemon'); });
var cb = document.getElementById('sc-config');
if (cb) cb.addEventListener('click', function (ev) {
ev.preventDefault();
var conf = {
watch_folders: [],
manifest: '~/.arcrun-rag/manifest.json',
cypher_url: cfg.apiBase || '',
namespace: cfg.tenant || '',
library: 'kb',
extractor: 'claude',
email: (S.profile && S.profile.email) || ''
};
var a = document.createElement('a');
a.href = 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(conf, null, 2));
a.download = 'config.json';
document.body.appendChild(a); a.click(); a.remove();
markStep('config');
});
var kb = document.getElementById('sc-key-save');
if (kb) kb.addEventListener('click', function () {
var k = (document.getElementById('sc-key').value || '').trim();
var m = document.getElementById('sc-key-msg');
if (!k) { m.textContent = '請先貼上金鑰'; return; }
kb.disabled = true; m.textContent = '啟用中…';
fetch(API_BASE + '/portal/admin/chat-key', {
method: 'POST',
headers: Object.assign({ 'Content-Type': 'application/json' }, authHeaders()),
body: JSON.stringify({ key: k })
}).then(function (r) { return r.json().then(function (d) { return { ok: r.ok, d: d }; }); })
.then(function (x) {
kb.disabled = false;
if (!x.ok || !x.d.success) { m.textContent = x.d.error || '啟用失敗,請再試一次'; return; }
markStep('key');
})
.catch(function () { kb.disabled = false; m.textContent = '網路好像有問題,請再試一次'; });
});
var later = document.getElementById('sc-later');
if (later) later.addEventListener('click', function () { el.remove(); }); // 只藏本次,下次進站再提醒
}
// ── t49 首次設定(leo 07-25):console/setup → portal/admin/bootstrap → 預設庫登記 → portal/login
// 四發全是既有端點,一顆按鈕做完;用戶感受=「建一組帳密就進來了」。
$('fs-submit').addEventListener('click', doFirstSetup);