()
| 2235 | } |
| 2236 | |
| 2237 | async function loadAccounts() { |
| 2238 | try { |
| 2239 | // 后端 page_size 最大为 100,超限会返回 422。 |
| 2240 | const data = await api.get("/accounts?page=1&page_size=100"); |
| 2241 | const sel = document.getElementById("account-select"); |
| 2242 | if (!sel) return; |
| 2243 | |
| 2244 | sel.innerHTML = '<option value="">-- 请选择账号 --</option>'; |
| 2245 | const allAccounts = Array.isArray(data.accounts) ? data.accounts : []; |
| 2246 | const bindFailCountMap = await fetchBindFailStats(allAccounts.map((acc) => Number(acc?.id || 0))); |
| 2247 | const toPriority = (acc) => { |
| 2248 | const num = Number(acc?.priority || 50); |
| 2249 | return Number.isFinite(num) ? num : 50; |
| 2250 | }; |
| 2251 | const toLastUsedRank = (acc) => { |
| 2252 | const ms = Date.parse(String(acc?.last_used_at || "")); |
| 2253 | if (Number.isNaN(ms)) return -1; |
| 2254 | return ms; |
| 2255 | }; |
| 2256 | const toFailRank = (acc) => { |
| 2257 | const accountId = Number(acc?.id || 0); |
| 2258 | if (Number.isFinite(accountId) && accountId > 0) { |
| 2259 | const count = bindFailCountMap.get(accountId); |
| 2260 | if (Number.isFinite(count)) { |
| 2261 | return count; |
| 2262 | } |
| 2263 | } |
| 2264 | return String(acc?.status || "").trim().toLowerCase() === "failed" ? 1 : 0; |
| 2265 | }; |
| 2266 | |
| 2267 | paymentAccounts = allAccounts |
| 2268 | .filter((acc) => { |
| 2269 | const sub = String(acc?.subscription_type || "").trim().toLowerCase(); |
| 2270 | return sub !== "plus"; |
| 2271 | }) |
| 2272 | .sort((a, b) => { |
| 2273 | const priorityDiff = toPriority(a) - toPriority(b); |
| 2274 | if (priorityDiff !== 0) return priorityDiff; |
| 2275 | |
| 2276 | const lastUsedDiff = toLastUsedRank(a) - toLastUsedRank(b); |
| 2277 | if (lastUsedDiff !== 0) return lastUsedDiff; |
| 2278 | |
| 2279 | const failDiff = toFailRank(a) - toFailRank(b); |
| 2280 | if (failDiff !== 0) return failDiff; |
| 2281 | |
| 2282 | return Number(a?.id || 0) - Number(b?.id || 0); |
| 2283 | }); |
| 2284 | |
| 2285 | paymentAccounts.forEach((acc) => { |
| 2286 | const opt = document.createElement("option"); |
| 2287 | opt.value = acc.id; |
| 2288 | const subText = acc.subscription_type ? ` (${String(acc.subscription_type).toUpperCase()})` : ""; |
| 2289 | opt.textContent = `${acc.email}${subText}`; |
| 2290 | sel.appendChild(opt); |
| 2291 | }); |
| 2292 | updateSelectedAccountEmailLabel(); |
| 2293 | updateSemiAutoActionsVisibility(getBindMode()); |
| 2294 | } catch (e) { |
no test coverage detected