diff --git a/sidepanel/sidepanel.html b/sidepanel/sidepanel.html
index 65966d4..d3e2af7 100644
--- a/sidepanel/sidepanel.html
+++ b/sidepanel/sidepanel.html
@@ -1558,8 +1558,12 @@
路由计划
-
+
+
+
+
MaDao 价格
diff --git a/sidepanel/sidepanel.js b/sidepanel/sidepanel.js
index fac5b5d..fcd6f84 100644
--- a/sidepanel/sidepanel.js
+++ b/sidepanel/sidepanel.js
@@ -494,7 +494,8 @@ const inputMaDaoBaseUrl = document.getElementById('input-madao-base-url');
const inputMaDaoHttpSecret = document.getElementById('input-madao-http-secret');
const btnToggleMaDaoHttpSecret = document.getElementById('btn-toggle-madao-http-secret');
const selectMaDaoMode = document.getElementById('select-madao-mode');
-const inputMaDaoRoutingPlanId = document.getElementById('input-madao-routing-plan-id');
+const selectMaDaoRoutingPlanId = document.getElementById('select-madao-routing-plan-id');
+const btnMaDaoRefreshRoutingPlans = document.getElementById('btn-madao-refresh-routing-plans');
const inputMaDaoProviderId = document.getElementById('input-madao-provider-id');
const inputMaDaoCountry = document.getElementById('input-madao-country');
const inputMaDaoAutoPickCountry = document.getElementById('input-madao-auto-pick-country');
@@ -689,6 +690,7 @@ const DEFAULT_MADAO_BASE_URL = 'http://127.0.0.1:7822';
const MADAO_MODE_ROUTING_PLAN = 'routing_plan';
const MADAO_MODE_DIRECT = 'direct';
const DEFAULT_MADAO_MODE = MADAO_MODE_ROUTING_PLAN;
+let maDaoRoutingPlanOptions = [];
const PHONE_SMS_PROVIDER_UI_DESCRIPTORS = Object.freeze({
[PHONE_SMS_PROVIDER_HERO]: Object.freeze({
rowKeys: Object.freeze([
@@ -4634,8 +4636,8 @@ function collectSettingsPayload() {
const maDaoModeValue = typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode
? normalizeMaDaoModeSafe(selectMaDaoMode.value || latestState?.madaoMode)
: normalizeMaDaoModeSafe(latestState?.madaoMode);
- const maDaoRoutingPlanIdValue = typeof inputMaDaoRoutingPlanId !== 'undefined' && inputMaDaoRoutingPlanId
- ? normalizeMaDaoIdentifierSafe(inputMaDaoRoutingPlanId.value || '')
+ const maDaoRoutingPlanIdValue = typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId
+ ? normalizeMaDaoIdentifierSafe(selectMaDaoRoutingPlanId.value || '')
: normalizeMaDaoIdentifierSafe(latestState?.madaoRoutingPlanId || '');
const maDaoProviderIdValue = typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId
? normalizeMaDaoProviderIdSafe(inputMaDaoProviderId.value || '')
@@ -5671,6 +5673,10 @@ function normalizeMaDaoIdentifierValue(value = '') {
return String(value || '').trim();
}
+function normalizeMaDaoRoutingPlanIdValue(value = '') {
+ return normalizeMaDaoIdentifierValue(value);
+}
+
function normalizeMaDaoProviderIdValue(value = '') {
return String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
}
@@ -5702,6 +5708,218 @@ function normalizeMaDaoPriceValue(value = '') {
return String(Math.round(numeric * 10000) / 10000);
}
+function createSelectOptionElement(value = '', label = '', title = '') {
+ const option = typeof document !== 'undefined' && typeof document.createElement === 'function'
+ ? document.createElement('option')
+ : { value: '', textContent: '', title: '', selected: false };
+ option.value = String(value || '');
+ option.textContent = String(label || value || '').trim();
+ const normalizedTitle = String(title || '').trim();
+ if (normalizedTitle) {
+ option.title = normalizedTitle;
+ }
+ return option;
+}
+
+function setSelectOptions(selectEl, items = [], options = {}) {
+ if (!selectEl) {
+ return;
+ }
+ const placeholder = String(options.placeholder || '').trim();
+ const includeEmpty = options.includeEmpty !== false;
+ const emptyValue = options.emptyValue !== undefined ? String(options.emptyValue) : '';
+ const selectedValue = String(options.value !== undefined ? options.value : selectEl.value || '').trim();
+ const optionItems = [];
+ if (includeEmpty) {
+ optionItems.push({
+ value: emptyValue,
+ label: placeholder || '请选择',
+ });
+ }
+ (Array.isArray(items) ? items : []).forEach((item) => {
+ const value = String(item?.value ?? '').trim();
+ if (!value) {
+ return;
+ }
+ optionItems.push({
+ value,
+ label: String(item?.label || value).trim(),
+ hint: String(item?.hint || '').trim(),
+ });
+ });
+
+ if (typeof selectEl.replaceChildren === 'function') {
+ selectEl.replaceChildren(...optionItems.map((item) => createSelectOptionElement(item.value, item.label, item.hint)));
+ } else if (typeof selectEl.appendChild === 'function') {
+ selectEl.innerHTML = '';
+ optionItems.forEach((item) => {
+ selectEl.appendChild(createSelectOptionElement(item.value, item.label, item.hint));
+ });
+ } else {
+ selectEl.options = optionItems.map((item) => createSelectOptionElement(item.value, item.label, item.hint));
+ }
+
+ const values = new Set(optionItems.map((item) => item.value));
+ const nextValue = values.has(selectedValue)
+ ? selectedValue
+ : (includeEmpty ? emptyValue : (optionItems[0]?.value || ''));
+ selectEl.value = nextValue;
+ Array.from(selectEl.options || []).forEach((option) => {
+ option.selected = String(option.value || '') === nextValue;
+ });
+}
+
+function buildMaDaoRoutingPlanOptions(items = [], selectedValue = '') {
+ const selectedPlanId = normalizeMaDaoRoutingPlanIdValue(selectedValue);
+ const seen = new Set();
+ const normalizedItems = [];
+ (Array.isArray(items) ? items : []).forEach((item) => {
+ const value = normalizeMaDaoRoutingPlanIdValue(
+ item?.value
+ || item?.id
+ || item?.routing_plan_id
+ || item?.routingPlanId
+ || ''
+ );
+ if (!value || seen.has(value)) {
+ return;
+ }
+ seen.add(value);
+ normalizedItems.push({
+ value,
+ label: String(item?.label || item?.name || value).trim() || value,
+ hint: String(item?.hint || item?.description || '').trim(),
+ service: String(item?.service || '').trim().toLowerCase(),
+ });
+ });
+ if (selectedPlanId && !seen.has(selectedPlanId)) {
+ normalizedItems.unshift({
+ value: selectedPlanId,
+ label: selectedPlanId,
+ hint: '已保存的路由计划',
+ });
+ }
+ return normalizedItems;
+}
+
+function setMaDaoRoutingPlanSelectOptions(selectedValue = latestState?.madaoRoutingPlanId || '') {
+ const normalizedSelected = normalizeMaDaoRoutingPlanIdValue(selectedValue);
+ const options = buildMaDaoRoutingPlanOptions(maDaoRoutingPlanOptions, normalizedSelected);
+ setSelectOptions(selectMaDaoRoutingPlanId, options, {
+ placeholder: '请先刷新路由计划',
+ value: normalizedSelected,
+ });
+}
+
+function buildMaDaoRequestUrl(path = '', baseUrl = '') {
+ const normalizedBaseUrl = normalizeMaDaoBaseUrlValue(baseUrl || latestState?.madaoBaseUrl || DEFAULT_MADAO_BASE_URL);
+ return new URL(String(path || '').replace(/^\/+/, ''), `${normalizedBaseUrl.replace(/\/+$/, '')}/`).toString();
+}
+
+function buildMaDaoRequestHeaders(httpSecret = '') {
+ const headers = { Accept: 'application/json' };
+ const normalizedSecret = String(httpSecret || '').trim();
+ if (normalizedSecret) {
+ headers.Authorization = `Bearer ${normalizedSecret}`;
+ }
+ return headers;
+}
+
+async function fetchMaDaoJson(path = '', options = {}) {
+ const baseUrl = typeof inputMaDaoBaseUrl !== 'undefined' && inputMaDaoBaseUrl
+ ? normalizeMaDaoBaseUrlValue(inputMaDaoBaseUrl.value || latestState?.madaoBaseUrl)
+ : normalizeMaDaoBaseUrlValue(latestState?.madaoBaseUrl);
+ const httpSecret = typeof inputMaDaoHttpSecret !== 'undefined' && inputMaDaoHttpSecret
+ ? String(inputMaDaoHttpSecret.value || '')
+ : String(latestState?.madaoHttpSecret || '');
+ const response = await fetch(buildMaDaoRequestUrl(path, baseUrl), {
+ method: options.method || 'GET',
+ headers: {
+ ...buildMaDaoRequestHeaders(httpSecret),
+ ...(options.body !== undefined ? { 'Content-Type': 'application/json' } : {}),
+ },
+ body: options.body !== undefined ? JSON.stringify(options.body) : undefined,
+ cache: 'no-store',
+ });
+ const text = await response.text();
+ let payload = null;
+ if (text) {
+ try {
+ payload = JSON.parse(text);
+ } catch {
+ payload = { message: text };
+ }
+ }
+ if (!response.ok) {
+ const message = String(payload?.message || payload?.error || response.statusText || `HTTP ${response.status}`).trim();
+ throw new Error(message || 'MaDao 请求失败');
+ }
+ return payload;
+}
+
+function getMaDaoRoutingPlansFromPayload(payload = {}) {
+ if (Array.isArray(payload)) {
+ return payload;
+ }
+ if (Array.isArray(payload?.plans)) {
+ return payload.plans;
+ }
+ if (Array.isArray(payload?.data?.plans)) {
+ return payload.data.plans;
+ }
+ if (Array.isArray(payload?.data)) {
+ return payload.data;
+ }
+ if (Array.isArray(payload?.items)) {
+ return payload.items;
+ }
+ return [];
+}
+
+async function loadMaDaoRoutingPlans(options = {}) {
+ const selectedValue = normalizeMaDaoRoutingPlanIdValue(
+ typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId
+ ? selectMaDaoRoutingPlanId.value
+ : latestState?.madaoRoutingPlanId
+ );
+ const payload = await fetchMaDaoJson('/api/routing-plans');
+ const plans = getMaDaoRoutingPlansFromPayload(payload);
+ maDaoRoutingPlanOptions = plans
+ .filter((plan) => plan?.enabled !== false)
+ .filter((plan) => {
+ const service = String(plan?.service || '').trim().toLowerCase();
+ return !service || service === 'openai';
+ })
+ .map((plan) => ({
+ value: normalizeMaDaoRoutingPlanIdValue(plan?.id || plan?.routing_plan_id || plan?.routingPlanId || plan?.value || ''),
+ label: String(plan?.name || plan?.label || plan?.id || plan?.routing_plan_id || '').trim(),
+ hint: String(plan?.description || plan?.hint || '').trim(),
+ service: String(plan?.service || '').trim().toLowerCase(),
+ }))
+ .filter((plan) => plan.value);
+ setMaDaoRoutingPlanSelectOptions(selectedValue);
+ updateHeroSmsPlatformDisplay();
+ if (!options.silent && typeof showToast === 'function') {
+ showToast('已刷新 MaDao 路由计划。', 'info', 1600);
+ }
+ return maDaoRoutingPlanOptions;
+}
+
+function getSelectedMaDaoRoutingPlanLabel(value = '') {
+ const selectedValue = normalizeMaDaoRoutingPlanIdValue(
+ value
+ || (typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId
+ ? selectMaDaoRoutingPlanId.value
+ : latestState?.madaoRoutingPlanId)
+ || ''
+ );
+ if (!selectedValue) {
+ return 'routing plan';
+ }
+ const matched = maDaoRoutingPlanOptions.find((item) => normalizeMaDaoRoutingPlanIdValue(item?.value) === selectedValue);
+ return String(matched?.label || selectedValue).trim() || 'routing plan';
+}
+
function normalizePhoneSmsProviderValue(value = '') {
const rootScope = typeof window !== 'undefined' ? window : globalThis;
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderId) {
@@ -7067,7 +7285,7 @@ function updateHeroSmsPlatformDisplay() {
: (provider === PHONE_SMS_PROVIDER_NEXSMS
? (getSelectedNexSmsCountries()[0] || { id: DEFAULT_NEX_SMS_COUNTRY_ORDER[0], label: `Country #${DEFAULT_NEX_SMS_COUNTRY_ORDER[0]}` })
: (provider === PHONE_SMS_PROVIDER_MADAO
- ? { id: normalizeMaDaoCountry(inputMaDaoCountry?.value || latestState?.madaoCountry || ''), label: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode) === MADAO_MODE_DIRECT ? (normalizeMaDaoCountry(inputMaDaoCountry?.value || latestState?.madaoCountry || '') || 'auto') : 'routing plan' }
+ ? { id: '', label: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode) === MADAO_MODE_DIRECT ? 'direct' : getSelectedMaDaoRoutingPlanLabel() }
: getSelectedHeroSmsCountryOption()));
const countryText = selected?.label ? ` / ${selected.label}` : '';
displayHeroSmsPlatform.textContent = `${getPhoneSmsProviderLabel(provider)} / OpenAI${countryText}`;
@@ -11813,7 +12031,13 @@ function applySettingsState(state) {
updatePhoneSmsProviderOrderSummary(restoredPhoneSmsProviderOrder);
if (previousPhoneSmsProvider !== restoredPhoneSmsProvider) {
heroSmsCountrySelectionOrder = [];
- loadHeroSmsCountries({ silent: true }).catch(() => { });
+ if (restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_MADAO) {
+ loadMaDaoRoutingPlans({ silent: true }).catch(() => {
+ setMaDaoRoutingPlanSelectOptions(state?.madaoRoutingPlanId || '');
+ });
+ } else {
+ loadHeroSmsCountries({ silent: true }).catch(() => { });
+ }
}
if (inputHeroSmsApiKey) {
inputHeroSmsApiKey.value = restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_FIVE_SIM
@@ -11850,8 +12074,8 @@ function applySettingsState(state) {
if (typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode) {
selectMaDaoMode.value = normalizeMaDaoModeValue(state?.madaoMode);
}
- if (typeof inputMaDaoRoutingPlanId !== 'undefined' && inputMaDaoRoutingPlanId) {
- inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(state?.madaoRoutingPlanId || '');
+ if (typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId) {
+ setMaDaoRoutingPlanSelectOptions(state?.madaoRoutingPlanId || '');
}
if (typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId) {
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(state?.madaoProviderId || '');
@@ -17158,7 +17382,11 @@ function buildPhoneSmsProviderStatePatch(provider = getSelectedPhoneSmsProvider(
madaoBaseUrl: normalizeMaDaoBaseUrlValue(inputMaDaoBaseUrl?.value || latestState?.madaoBaseUrl),
madaoHttpSecret: String(inputMaDaoHttpSecret?.value || ''),
madaoMode: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode),
- madaoRoutingPlanId: normalizeMaDaoIdentifierValue(inputMaDaoRoutingPlanId?.value || ''),
+ madaoRoutingPlanId: normalizeMaDaoRoutingPlanIdValue(
+ typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId
+ ? selectMaDaoRoutingPlanId.value
+ : latestState?.madaoRoutingPlanId
+ ),
madaoProviderId: normalizeMaDaoProviderIdValue(inputMaDaoProviderId?.value || ''),
madaoCountry: normalizeMaDaoCountry(inputMaDaoCountry?.value || ''),
madaoAutoPickCountry: Boolean(inputMaDaoAutoPickCountry?.checked),
@@ -17205,8 +17433,8 @@ function applyPhoneSmsProviderFieldsToInputs(provider = getSelectedPhoneSmsProvi
if (typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode) {
selectMaDaoMode.value = normalizeMaDaoModeValue(state?.madaoMode);
}
- if (typeof inputMaDaoRoutingPlanId !== 'undefined' && inputMaDaoRoutingPlanId) {
- inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(state?.madaoRoutingPlanId || '');
+ if (typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId) {
+ setMaDaoRoutingPlanSelectOptions(state?.madaoRoutingPlanId || '');
}
if (typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId) {
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(state?.madaoProviderId || '');
@@ -17291,6 +17519,10 @@ async function switchPhoneSmsProvider(nextProvider) {
applyNexSmsCountrySelection(
Array.isArray(latestState?.nexSmsCountryOrder) ? latestState.nexSmsCountryOrder : []
);
+ } else if (normalizedNextProvider === PHONE_SMS_PROVIDER_MADAO) {
+ await loadMaDaoRoutingPlans({ silent: true }).catch(() => {
+ setMaDaoRoutingPlanSelectOptions(latestState?.madaoRoutingPlanId || '');
+ });
} else if (normalizedNextProvider === PHONE_SMS_PROVIDER_HERO_SMS) {
await loadHeroSmsCountries({ silent: true });
const restoredPrimary = {
@@ -17497,19 +17729,27 @@ selectMaDaoMode?.addEventListener('change', () => {
selectMaDaoMode.value = normalizeMaDaoModeValue(selectMaDaoMode.value);
updateHeroSmsPlatformDisplay();
updatePhoneVerificationSettingsUI();
+ if (selectMaDaoMode.value === MADAO_MODE_ROUTING_PLAN) {
+ loadMaDaoRoutingPlans({ silent: true }).catch(() => {
+ setMaDaoRoutingPlanSelectOptions(latestState?.madaoRoutingPlanId || '');
+ });
+ }
markSettingsDirty(true);
saveSettings({ silent: true }).catch(() => { });
});
-inputMaDaoRoutingPlanId?.addEventListener('input', () => {
+selectMaDaoRoutingPlanId?.addEventListener('change', () => {
+ updateHeroSmsPlatformDisplay();
markSettingsDirty(true);
- scheduleSettingsAutoSave();
-});
-inputMaDaoRoutingPlanId?.addEventListener('blur', () => {
- inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(inputMaDaoRoutingPlanId.value);
saveSettings({ silent: true }).catch(() => { });
});
+btnMaDaoRefreshRoutingPlans?.addEventListener('click', () => {
+ loadMaDaoRoutingPlans().catch((error) => {
+ showToast(`刷新 MaDao 路由计划失败:${error?.message || error}`, 'warn', 2200);
+ });
+});
+
inputMaDaoProviderId?.addEventListener('input', () => {
markSettingsDirty(true);
scheduleSettingsAutoSave();
@@ -18592,8 +18832,8 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
selectMaDaoMode.value = normalizeMaDaoModeValue(message.payload.madaoMode);
updatePhoneVerificationSettingsUI();
}
- if (message.payload.madaoRoutingPlanId !== undefined && inputMaDaoRoutingPlanId) {
- inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(message.payload.madaoRoutingPlanId);
+ if (message.payload.madaoRoutingPlanId !== undefined && selectMaDaoRoutingPlanId) {
+ setMaDaoRoutingPlanSelectOptions(message.payload.madaoRoutingPlanId);
}
if (message.payload.madaoProviderId !== undefined && inputMaDaoProviderId) {
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(message.payload.madaoProviderId);
diff --git a/tests/sidepanel-phone-verification-settings.test.js b/tests/sidepanel-phone-verification-settings.test.js
index e34a0c9..b95cebd 100644
--- a/tests/sidepanel-phone-verification-settings.test.js
+++ b/tests/sidepanel-phone-verification-settings.test.js
@@ -156,7 +156,9 @@ test('sidepanel html exposes phone verification toggle and multi-provider SMS ro
assert.match(html, /id="row-madao-mode"/);
assert.match(html, /id="select-madao-mode"/);
assert.match(html, /id="row-madao-routing-plan-id"/);
- assert.match(html, /id="input-madao-routing-plan-id"/);
+ assert.match(html, /id="select-madao-routing-plan-id"/);
+ assert.match(html, /id="btn-madao-refresh-routing-plans"/);
+ assert.doesNotMatch(html, /id="input-madao-routing-plan-id"/);
assert.doesNotMatch(html, /id="row-madao-provider-id"/);
assert.doesNotMatch(html, /id="input-madao-provider-id"/);
assert.doesNotMatch(html, /id="row-madao-country"/);
@@ -194,6 +196,85 @@ test('sidepanel loads live SMS country lists silently during startup', () => {
assert.doesNotMatch(sidepanelSource, /console\.error\('加载 (?:HeroSMS|5sim|NexSMS) 国家列表失败:'/);
});
+test('MaDao routing plan select loads options from helper API and preserves saved plan', async () => {
+ const requests = [];
+ const fetchImpl = async (url, options = {}) => {
+ requests.push({ url, options });
+ return {
+ ok: true,
+ status: 200,
+ statusText: 'OK',
+ async text() {
+ return JSON.stringify({
+ plans: [
+ { id: 'openai-plan', name: 'OpenAI Plan', service: 'openai', enabled: true },
+ { id: 'kiro-plan', name: 'Kiro Plan', service: 'kiro', enabled: true },
+ { id: 'disabled-plan', name: 'Disabled Plan', service: 'openai', enabled: false },
+ ],
+ });
+ },
+ };
+ };
+
+ const api = new Function('fetch', `
+const DEFAULT_MADAO_BASE_URL = 'http://127.0.0.1:7822';
+let latestState = {
+ madaoBaseUrl: 'http://madao.local/api/acquire',
+ madaoHttpSecret: 'madao-secret',
+ madaoRoutingPlanId: 'stored-plan',
+};
+let maDaoRoutingPlanOptions = [];
+let displayText = '';
+let toastText = '';
+const inputMaDaoBaseUrl = { value: 'http://madao.local/api/acquire' };
+const inputMaDaoHttpSecret = { value: 'madao-secret' };
+const selectMaDaoRoutingPlanId = {
+ value: 'stored-plan',
+ options: [],
+ replaceChildren(...children) {
+ this.options = children;
+ },
+};
+function updateHeroSmsPlatformDisplay() {
+ displayText = getSelectedMaDaoRoutingPlanLabel();
+}
+function showToast(message) {
+ toastText = message;
+}
+${extractFunction('normalizeMaDaoBaseUrlValue')}
+${extractFunction('normalizeMaDaoIdentifierValue')}
+${extractFunction('normalizeMaDaoRoutingPlanIdValue')}
+${extractFunction('createSelectOptionElement')}
+${extractFunction('setSelectOptions')}
+${extractFunction('buildMaDaoRoutingPlanOptions')}
+${extractFunction('setMaDaoRoutingPlanSelectOptions')}
+${extractFunction('buildMaDaoRequestUrl')}
+${extractFunction('buildMaDaoRequestHeaders')}
+${extractFunction('fetchMaDaoJson')}
+${extractFunction('getMaDaoRoutingPlansFromPayload')}
+${extractFunction('loadMaDaoRoutingPlans')}
+${extractFunction('getSelectedMaDaoRoutingPlanLabel')}
+return {
+ loadMaDaoRoutingPlans,
+ selectMaDaoRoutingPlanId,
+ get options() { return selectMaDaoRoutingPlanId.options.map((option) => ({ value: option.value, label: option.textContent, selected: option.selected })); },
+ get displayText() { return displayText; },
+ get toastText() { return toastText; },
+};
+`)(fetchImpl);
+
+ const plans = await api.loadMaDaoRoutingPlans();
+
+ assert.deepStrictEqual(plans.map((plan) => plan.value), ['openai-plan']);
+ assert.equal(api.selectMaDaoRoutingPlanId.value, 'stored-plan');
+ assert.deepStrictEqual(api.options.map((option) => option.value), ['', 'stored-plan', 'openai-plan']);
+ assert.equal(api.options.find((option) => option.value === 'stored-plan').selected, true);
+ assert.equal(api.displayText, 'stored-plan');
+ assert.equal(api.toastText, '已刷新 MaDao 路由计划。');
+ assert.equal(requests[0].url, 'http://madao.local/api/routing-plans');
+ assert.equal(requests[0].options.headers.Authorization, 'Bearer madao-secret');
+});
+
test('HeroSMS country parser accepts keyed country maps from the live API', () => {
const api = new Function(`
${extractFunction('normalizeHeroSmsCountryPayloadEntries')}
@@ -1160,7 +1241,7 @@ const inputNexSmsServiceCode = { value: 'ot' };
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/acquire' };
const inputMaDaoHttpSecret = { value: 'madao-secret' };
const selectMaDaoMode = { value: 'direct' };
-const inputMaDaoRoutingPlanId = { value: 'plan-1' };
+const selectMaDaoRoutingPlanId = { value: 'plan-1' };
const inputMaDaoProviderId = { value: 'Local Provider!!' };
const inputMaDaoCountry = { value: 'th' };
const inputMaDaoAutoPickCountry = { checked: false };
@@ -1434,7 +1515,13 @@ const inputNexSmsServiceCode = { value: 'ot' };
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/poll' };
const inputMaDaoHttpSecret = { value: 'madao-live-secret' };
const selectMaDaoMode = { value: 'direct' };
-const inputMaDaoRoutingPlanId = { value: 'plan-live' };
+const selectMaDaoRoutingPlanId = {
+ value: 'plan-live',
+ options: [],
+ replaceChildren(...children) {
+ this.options = children;
+ },
+};
const inputMaDaoProviderId = { value: 'Provider Live!' };
const inputMaDaoCountry = { value: 'local' };
const inputMaDaoAutoPickCountry = { checked: false };
@@ -1454,6 +1541,7 @@ let heroSmsCountrySelectionOrder = [];
let phoneSmsProviderOrderSelection = ['hero-sms', '5sim'];
let lastPhoneSmsProviderBeforeChange = null;
let savedPayload = null;
+let maDaoRoutingPlanOptions = [];
${extractFunction('normalizePhoneSmsProvider')}
${extractFunction('normalizePhoneSmsProviderValue')}
@@ -1483,9 +1571,14 @@ ${extractFunction('normalizeNexSmsServiceCodeValue')}
${extractFunction('normalizeMaDaoBaseUrlValue')}
${extractFunction('normalizeMaDaoModeValue')}
${extractFunction('normalizeMaDaoIdentifierValue')}
+${extractFunction('normalizeMaDaoRoutingPlanIdValue')}
${extractFunction('normalizeMaDaoProviderIdValue')}
${extractFunction('normalizeMaDaoCountry')}
${extractFunction('normalizeMaDaoPriceValue')}
+${extractFunction('createSelectOptionElement')}
+${extractFunction('setSelectOptions')}
+${extractFunction('buildMaDaoRoutingPlanOptions')}
+${extractFunction('setMaDaoRoutingPlanSelectOptions')}
${extractFunction('normalizePhoneSmsMinPriceValue')}
${extractFunction('normalizePhoneSmsMaxPriceValue')}
${extractFunction('normalizeHeroSmsCountryId')}