|
@@ -2,8 +2,10 @@
|
|
|
'use strict';
|
|
'use strict';
|
|
|
|
|
|
|
|
const API_BASE = '';
|
|
const API_BASE = '';
|
|
|
- const ACCOUNTS_KEY = 'qiwei-accounts';
|
|
|
|
|
- const CURRENT_ACCOUNT_KEY = 'qiwei-current-account';
|
|
|
|
|
|
|
+ const LEGACY_ACCOUNTS_KEY = 'qiwei-accounts';
|
|
|
|
|
+ const LEGACY_CURRENT_ACCOUNT_KEY = 'qiwei-current-account';
|
|
|
|
|
+ let ACCOUNTS_KEY = LEGACY_ACCOUNTS_KEY;
|
|
|
|
|
+ let CURRENT_ACCOUNT_KEY = LEGACY_CURRENT_ACCOUNT_KEY;
|
|
|
|
|
|
|
|
const CO_FILTERS_KEY = 'qiwei-co-filters';
|
|
const CO_FILTERS_KEY = 'qiwei-co-filters';
|
|
|
const PT_FILTERS_KEY = 'qiwei-pt-filters';
|
|
const PT_FILTERS_KEY = 'qiwei-pt-filters';
|
|
@@ -43,8 +45,8 @@
|
|
|
|
|
|
|
|
const state = {
|
|
const state = {
|
|
|
page: 'overview',
|
|
page: 'overview',
|
|
|
- accounts: JSON.parse(localStorage.getItem(ACCOUNTS_KEY) || '[]'),
|
|
|
|
|
- currentAccountId: localStorage.getItem(CURRENT_ACCOUNT_KEY) || null,
|
|
|
|
|
|
|
+ accounts: [],
|
|
|
|
|
+ currentAccountId: null,
|
|
|
status: null,
|
|
status: null,
|
|
|
groups: [],
|
|
groups: [],
|
|
|
groupSync: {},
|
|
groupSync: {},
|
|
@@ -61,6 +63,7 @@
|
|
|
loginTimer: null,
|
|
loginTimer: null,
|
|
|
loginPhase: 'idle',
|
|
loginPhase: 'idle',
|
|
|
loginUid: null,
|
|
loginUid: null,
|
|
|
|
|
+ loginPreviousAccountId: null,
|
|
|
autoRecoverAttempted: false,
|
|
autoRecoverAttempted: false,
|
|
|
preRecoveryPage: null,
|
|
preRecoveryPage: null,
|
|
|
selectedGroupIds: new Set(),
|
|
selectedGroupIds: new Set(),
|
|
@@ -143,25 +146,85 @@
|
|
|
localStorage.setItem(CURRENT_ACCOUNT_KEY, state.currentAccountId || '');
|
|
localStorage.setItem(CURRENT_ACCOUNT_KEY, state.currentAccountId || '');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ function parseStoredAccounts(value) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const parsed = JSON.parse(value || '[]');
|
|
|
|
|
+ return Array.isArray(parsed) ? parsed.filter(item => item && typeof item === 'object') : [];
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return [];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async function initializeWorkspaceAccountStorage() {
|
|
|
|
|
+ let workspaceId = '';
|
|
|
|
|
+ let activeAccountUid = '';
|
|
|
|
|
+ try {
|
|
|
|
|
+ const health = await api('GET', '/api/health', undefined, 4000);
|
|
|
|
|
+ workspaceId = String(health.data?.workspaceId || '').trim();
|
|
|
|
|
+ activeAccountUid = String(health.data?.activeAccountUid || '').trim();
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ // 旧版服务端或短暂启动延迟时继续使用原键,避免阻断工作台。
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (workspaceId) {
|
|
|
|
|
+ ACCOUNTS_KEY = `qiwei-${workspaceId}-accounts`;
|
|
|
|
|
+ CURRENT_ACCOUNT_KEY = `qiwei-${workspaceId}-current-account`;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let accounts = parseStoredAccounts(localStorage.getItem(ACCOUNTS_KEY));
|
|
|
|
|
+ let currentId = localStorage.getItem(CURRENT_ACCOUNT_KEY) || null;
|
|
|
|
|
+ if (workspaceId && accounts.length === 0 && activeAccountUid) {
|
|
|
|
|
+ const legacy = parseStoredAccounts(localStorage.getItem(LEGACY_ACCOUNTS_KEY));
|
|
|
|
|
+ const activeLegacy = legacy.find(item => String(item.uid || '').trim() === activeAccountUid);
|
|
|
|
|
+ if (activeLegacy) {
|
|
|
|
|
+ accounts = legacy;
|
|
|
|
|
+ currentId = activeLegacy.id;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!accounts.some(item => item.id === currentId)) currentId = null;
|
|
|
|
|
+ state.accounts = accounts;
|
|
|
|
|
+ state.currentAccountId = currentId;
|
|
|
|
|
+ saveAccounts();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
function isGroupSynced(roomId) {
|
|
function isGroupSynced(roomId) {
|
|
|
return !!(state.groupSync[roomId] && state.groupSync[roomId].lastSyncAt);
|
|
return !!(state.groupSync[roomId] && state.groupSync[roomId].lastSyncAt);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- function addAccount(account) {
|
|
|
|
|
|
|
+ function addAccount(account, options = {}) {
|
|
|
|
|
+ const activate = options.activate !== false;
|
|
|
const existing = state.accounts.find(a =>
|
|
const existing = state.accounts.find(a =>
|
|
|
(account.uid && a.uid === account.uid) ||
|
|
(account.uid && a.uid === account.uid) ||
|
|
|
((account.guid || account.userId) && a.guid === account.guid && a.userId === account.userId)
|
|
((account.guid || account.userId) && a.guid === account.guid && a.userId === account.userId)
|
|
|
);
|
|
);
|
|
|
if (existing) {
|
|
if (existing) {
|
|
|
Object.assign(existing, account, { id: existing.id });
|
|
Object.assign(existing, account, { id: existing.id });
|
|
|
- state.currentAccountId = existing.id;
|
|
|
|
|
|
|
+ if (activate) state.currentAccountId = existing.id;
|
|
|
} else {
|
|
} else {
|
|
|
account.id = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
account.id = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
|
state.accounts.push(account);
|
|
state.accounts.push(account);
|
|
|
- state.currentAccountId = account.id;
|
|
|
|
|
|
|
+ if (activate) state.currentAccountId = account.id;
|
|
|
}
|
|
}
|
|
|
saveAccounts();
|
|
saveAccounts();
|
|
|
updateAccountSwitcher();
|
|
updateAccountSwitcher();
|
|
|
|
|
+ return existing?.id || account.id;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function beginAddAccountLogin() {
|
|
|
|
|
+ state.loginPreviousAccountId = state.currentAccountId;
|
|
|
|
|
+ state.loginUid = createDeviceUid();
|
|
|
|
|
+ state.currentAccountId = null;
|
|
|
|
|
+ saveAccounts();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function restorePreviousAccountSelection() {
|
|
|
|
|
+ const previousId = state.loginPreviousAccountId;
|
|
|
|
|
+ if (previousId && state.accounts.some(item => item.id === previousId)) {
|
|
|
|
|
+ state.currentAccountId = previousId;
|
|
|
|
|
+ saveAccounts();
|
|
|
|
|
+ updateAccountSwitcher();
|
|
|
|
|
+ }
|
|
|
|
|
+ state.loginPreviousAccountId = null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function switchAccount(id, options = {}) {
|
|
async function switchAccount(id, options = {}) {
|
|
@@ -3991,6 +4054,7 @@
|
|
|
|
|
|
|
|
if (statusCode === 4) {
|
|
if (statusCode === 4) {
|
|
|
clearInterval(state.loginTimer);
|
|
clearInterval(state.loginTimer);
|
|
|
|
|
+ restorePreviousAccountSelection();
|
|
|
if (statusText) statusText.textContent = '登录已取消,请重新生成二维码';
|
|
if (statusText) statusText.textContent = '登录已取消,请重新生成二维码';
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -4067,10 +4131,19 @@
|
|
|
toast('登录成功,但未获取到 Fmode 设备标识,请重新扫码', 'error');
|
|
toast('登录成功,但未获取到 Fmode 设备标识,请重新扫码', 'error');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- addAccount(account);
|
|
|
|
|
- const switched = await switchAccount(state.currentAccountId, { silent: true, deferRender: state.bootstrapping });
|
|
|
|
|
- if (!switched) return;
|
|
|
|
|
|
|
+ const previousAccountId = state.loginPreviousAccountId;
|
|
|
|
|
+ const accountId = addAccount(account, { activate: false });
|
|
|
|
|
+ const switched = await switchAccount(accountId, { silent: true, deferRender: state.bootstrapping });
|
|
|
|
|
+ if (!switched) {
|
|
|
|
|
+ state.currentAccountId = previousAccountId && state.accounts.some(item => item.id === previousAccountId)
|
|
|
|
|
+ ? previousAccountId
|
|
|
|
|
+ : null;
|
|
|
|
|
+ saveAccounts();
|
|
|
|
|
+ updateAccountSwitcher();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
state.loginUid = null;
|
|
state.loginUid = null;
|
|
|
|
|
+ state.loginPreviousAccountId = null;
|
|
|
toast(`登录成功:${account.nickname || account.userId}`);
|
|
toast(`登录成功:${account.nickname || account.userId}`);
|
|
|
if (state.preRecoveryPage) {
|
|
if (state.preRecoveryPage) {
|
|
|
location.hash = `#${state.preRecoveryPage}`;
|
|
location.hash = `#${state.preRecoveryPage}`;
|
|
@@ -4131,7 +4204,9 @@
|
|
|
if (res.status === 'needs_verify_code') {
|
|
if (res.status === 'needs_verify_code') {
|
|
|
state.loginPhase = 'verify';
|
|
state.loginPhase = 'verify';
|
|
|
state.preRecoveryPage = location.hash.slice(1) || 'groups';
|
|
state.preRecoveryPage = location.hash.slice(1) || 'groups';
|
|
|
|
|
+ state.loginPreviousAccountId ||= state.currentAccountId;
|
|
|
state.currentAccountId = null;
|
|
state.currentAccountId = null;
|
|
|
|
|
+ saveAccounts();
|
|
|
renderPage();
|
|
renderPage();
|
|
|
setTimeout(() => showVerifyCodeInput(), 100);
|
|
setTimeout(() => showVerifyCodeInput(), 100);
|
|
|
return false;
|
|
return false;
|
|
@@ -4157,6 +4232,7 @@
|
|
|
|
|
|
|
|
async function recoverLogin() {
|
|
async function recoverLogin() {
|
|
|
state.autoRecoverAttempted = true;
|
|
state.autoRecoverAttempted = true;
|
|
|
|
|
+ state.loginPreviousAccountId = state.currentAccountId;
|
|
|
state.loginUid = currentAccount()?.uid || null;
|
|
state.loginUid = currentAccount()?.uid || null;
|
|
|
const recovered = await attemptAutoRecover(false);
|
|
const recovered = await attemptAutoRecover(false);
|
|
|
if (!recovered) {
|
|
if (!recovered) {
|
|
@@ -4292,9 +4368,7 @@
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
page.querySelector('#btn-add-account-page').addEventListener('click', () => {
|
|
page.querySelector('#btn-add-account-page').addEventListener('click', () => {
|
|
|
- state.loginUid = createDeviceUid();
|
|
|
|
|
- state.currentAccountId = null;
|
|
|
|
|
- saveAccounts();
|
|
|
|
|
|
|
+ beginAddAccountLogin();
|
|
|
renderPage();
|
|
renderPage();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
@@ -7375,6 +7449,7 @@
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function init() {
|
|
async function init() {
|
|
|
|
|
+ await initializeWorkspaceAccountStorage();
|
|
|
setActiveNav(location.hash.slice(1) || 'overview');
|
|
setActiveNav(location.hash.slice(1) || 'overview');
|
|
|
updateAccountSwitcher();
|
|
updateAccountSwitcher();
|
|
|
const hadAccountAtStart = Boolean(currentAccount());
|
|
const hadAccountAtStart = Boolean(currentAccount());
|
|
@@ -7392,9 +7467,7 @@
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
document.getElementById('btn-add-account').addEventListener('click', () => {
|
|
document.getElementById('btn-add-account').addEventListener('click', () => {
|
|
|
- state.loginUid = createDeviceUid();
|
|
|
|
|
- state.currentAccountId = null;
|
|
|
|
|
- saveAccounts();
|
|
|
|
|
|
|
+ beginAddAccountLogin();
|
|
|
location.hash = '#groups';
|
|
location.hash = '#groups';
|
|
|
renderPage();
|
|
renderPage();
|
|
|
});
|
|
});
|