fix: 支持 MaDao 路由计划下拉选择
将 MaDao 路由计划从文本输入改为可刷新下拉列表。 保留已保存计划 ID 作为兜底选项,避免列表加载失败时清空配置。
This commit is contained in:
@@ -1558,8 +1558,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="data-row" id="row-madao-routing-plan-id" style="display:none;">
|
<div class="data-row" id="row-madao-routing-plan-id" style="display:none;">
|
||||||
<span class="data-label">路由计划</span>
|
<span class="data-label">路由计划</span>
|
||||||
<input type="text" id="input-madao-routing-plan-id" class="data-input mono"
|
<div class="data-inline data-value-actions">
|
||||||
placeholder="routing_plan_id" />
|
<select id="select-madao-routing-plan-id" class="data-select mono">
|
||||||
|
<option value="">请先刷新路由计划</option>
|
||||||
|
</select>
|
||||||
|
<button id="btn-madao-refresh-routing-plans" class="btn btn-ghost btn-xs data-inline-btn" type="button">刷新</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row" id="row-madao-price-range" style="display:none;">
|
<div class="data-row" id="row-madao-price-range" style="display:none;">
|
||||||
<span class="data-label">MaDao 价格</span>
|
<span class="data-label">MaDao 价格</span>
|
||||||
|
|||||||
+256
-16
@@ -494,7 +494,8 @@ const inputMaDaoBaseUrl = document.getElementById('input-madao-base-url');
|
|||||||
const inputMaDaoHttpSecret = document.getElementById('input-madao-http-secret');
|
const inputMaDaoHttpSecret = document.getElementById('input-madao-http-secret');
|
||||||
const btnToggleMaDaoHttpSecret = document.getElementById('btn-toggle-madao-http-secret');
|
const btnToggleMaDaoHttpSecret = document.getElementById('btn-toggle-madao-http-secret');
|
||||||
const selectMaDaoMode = document.getElementById('select-madao-mode');
|
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 inputMaDaoProviderId = document.getElementById('input-madao-provider-id');
|
||||||
const inputMaDaoCountry = document.getElementById('input-madao-country');
|
const inputMaDaoCountry = document.getElementById('input-madao-country');
|
||||||
const inputMaDaoAutoPickCountry = document.getElementById('input-madao-auto-pick-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_ROUTING_PLAN = 'routing_plan';
|
||||||
const MADAO_MODE_DIRECT = 'direct';
|
const MADAO_MODE_DIRECT = 'direct';
|
||||||
const DEFAULT_MADAO_MODE = MADAO_MODE_ROUTING_PLAN;
|
const DEFAULT_MADAO_MODE = MADAO_MODE_ROUTING_PLAN;
|
||||||
|
let maDaoRoutingPlanOptions = [];
|
||||||
const PHONE_SMS_PROVIDER_UI_DESCRIPTORS = Object.freeze({
|
const PHONE_SMS_PROVIDER_UI_DESCRIPTORS = Object.freeze({
|
||||||
[PHONE_SMS_PROVIDER_HERO]: Object.freeze({
|
[PHONE_SMS_PROVIDER_HERO]: Object.freeze({
|
||||||
rowKeys: Object.freeze([
|
rowKeys: Object.freeze([
|
||||||
@@ -4634,8 +4636,8 @@ function collectSettingsPayload() {
|
|||||||
const maDaoModeValue = typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode
|
const maDaoModeValue = typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode
|
||||||
? normalizeMaDaoModeSafe(selectMaDaoMode.value || latestState?.madaoMode)
|
? normalizeMaDaoModeSafe(selectMaDaoMode.value || latestState?.madaoMode)
|
||||||
: normalizeMaDaoModeSafe(latestState?.madaoMode);
|
: normalizeMaDaoModeSafe(latestState?.madaoMode);
|
||||||
const maDaoRoutingPlanIdValue = typeof inputMaDaoRoutingPlanId !== 'undefined' && inputMaDaoRoutingPlanId
|
const maDaoRoutingPlanIdValue = typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId
|
||||||
? normalizeMaDaoIdentifierSafe(inputMaDaoRoutingPlanId.value || '')
|
? normalizeMaDaoIdentifierSafe(selectMaDaoRoutingPlanId.value || '')
|
||||||
: normalizeMaDaoIdentifierSafe(latestState?.madaoRoutingPlanId || '');
|
: normalizeMaDaoIdentifierSafe(latestState?.madaoRoutingPlanId || '');
|
||||||
const maDaoProviderIdValue = typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId
|
const maDaoProviderIdValue = typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId
|
||||||
? normalizeMaDaoProviderIdSafe(inputMaDaoProviderId.value || '')
|
? normalizeMaDaoProviderIdSafe(inputMaDaoProviderId.value || '')
|
||||||
@@ -5671,6 +5673,10 @@ function normalizeMaDaoIdentifierValue(value = '') {
|
|||||||
return String(value || '').trim();
|
return String(value || '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeMaDaoRoutingPlanIdValue(value = '') {
|
||||||
|
return normalizeMaDaoIdentifierValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeMaDaoProviderIdValue(value = '') {
|
function normalizeMaDaoProviderIdValue(value = '') {
|
||||||
return String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
|
return String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
|
||||||
}
|
}
|
||||||
@@ -5702,6 +5708,218 @@ function normalizeMaDaoPriceValue(value = '') {
|
|||||||
return String(Math.round(numeric * 10000) / 10000);
|
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 = '') {
|
function normalizePhoneSmsProviderValue(value = '') {
|
||||||
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||||
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderId) {
|
if (rootScope.PhoneSmsProviderRegistry?.normalizeProviderId) {
|
||||||
@@ -7067,7 +7285,7 @@ function updateHeroSmsPlatformDisplay() {
|
|||||||
: (provider === PHONE_SMS_PROVIDER_NEXSMS
|
: (provider === PHONE_SMS_PROVIDER_NEXSMS
|
||||||
? (getSelectedNexSmsCountries()[0] || { id: DEFAULT_NEX_SMS_COUNTRY_ORDER[0], label: `Country #${DEFAULT_NEX_SMS_COUNTRY_ORDER[0]}` })
|
? (getSelectedNexSmsCountries()[0] || { id: DEFAULT_NEX_SMS_COUNTRY_ORDER[0], label: `Country #${DEFAULT_NEX_SMS_COUNTRY_ORDER[0]}` })
|
||||||
: (provider === PHONE_SMS_PROVIDER_MADAO
|
: (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()));
|
: getSelectedHeroSmsCountryOption()));
|
||||||
const countryText = selected?.label ? ` / ${selected.label}` : '';
|
const countryText = selected?.label ? ` / ${selected.label}` : '';
|
||||||
displayHeroSmsPlatform.textContent = `${getPhoneSmsProviderLabel(provider)} / OpenAI${countryText}`;
|
displayHeroSmsPlatform.textContent = `${getPhoneSmsProviderLabel(provider)} / OpenAI${countryText}`;
|
||||||
@@ -11813,8 +12031,14 @@ function applySettingsState(state) {
|
|||||||
updatePhoneSmsProviderOrderSummary(restoredPhoneSmsProviderOrder);
|
updatePhoneSmsProviderOrderSummary(restoredPhoneSmsProviderOrder);
|
||||||
if (previousPhoneSmsProvider !== restoredPhoneSmsProvider) {
|
if (previousPhoneSmsProvider !== restoredPhoneSmsProvider) {
|
||||||
heroSmsCountrySelectionOrder = [];
|
heroSmsCountrySelectionOrder = [];
|
||||||
|
if (restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_MADAO) {
|
||||||
|
loadMaDaoRoutingPlans({ silent: true }).catch(() => {
|
||||||
|
setMaDaoRoutingPlanSelectOptions(state?.madaoRoutingPlanId || '');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
loadHeroSmsCountries({ silent: true }).catch(() => { });
|
loadHeroSmsCountries({ silent: true }).catch(() => { });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (inputHeroSmsApiKey) {
|
if (inputHeroSmsApiKey) {
|
||||||
inputHeroSmsApiKey.value = restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_FIVE_SIM
|
inputHeroSmsApiKey.value = restoredPhoneSmsProvider === PHONE_SMS_PROVIDER_FIVE_SIM
|
||||||
? (state?.fiveSimApiKey || '')
|
? (state?.fiveSimApiKey || '')
|
||||||
@@ -11850,8 +12074,8 @@ function applySettingsState(state) {
|
|||||||
if (typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode) {
|
if (typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode) {
|
||||||
selectMaDaoMode.value = normalizeMaDaoModeValue(state?.madaoMode);
|
selectMaDaoMode.value = normalizeMaDaoModeValue(state?.madaoMode);
|
||||||
}
|
}
|
||||||
if (typeof inputMaDaoRoutingPlanId !== 'undefined' && inputMaDaoRoutingPlanId) {
|
if (typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId) {
|
||||||
inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(state?.madaoRoutingPlanId || '');
|
setMaDaoRoutingPlanSelectOptions(state?.madaoRoutingPlanId || '');
|
||||||
}
|
}
|
||||||
if (typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId) {
|
if (typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId) {
|
||||||
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(state?.madaoProviderId || '');
|
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(state?.madaoProviderId || '');
|
||||||
@@ -17158,7 +17382,11 @@ function buildPhoneSmsProviderStatePatch(provider = getSelectedPhoneSmsProvider(
|
|||||||
madaoBaseUrl: normalizeMaDaoBaseUrlValue(inputMaDaoBaseUrl?.value || latestState?.madaoBaseUrl),
|
madaoBaseUrl: normalizeMaDaoBaseUrlValue(inputMaDaoBaseUrl?.value || latestState?.madaoBaseUrl),
|
||||||
madaoHttpSecret: String(inputMaDaoHttpSecret?.value || ''),
|
madaoHttpSecret: String(inputMaDaoHttpSecret?.value || ''),
|
||||||
madaoMode: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode),
|
madaoMode: normalizeMaDaoModeValue(selectMaDaoMode?.value || latestState?.madaoMode),
|
||||||
madaoRoutingPlanId: normalizeMaDaoIdentifierValue(inputMaDaoRoutingPlanId?.value || ''),
|
madaoRoutingPlanId: normalizeMaDaoRoutingPlanIdValue(
|
||||||
|
typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId
|
||||||
|
? selectMaDaoRoutingPlanId.value
|
||||||
|
: latestState?.madaoRoutingPlanId
|
||||||
|
),
|
||||||
madaoProviderId: normalizeMaDaoProviderIdValue(inputMaDaoProviderId?.value || ''),
|
madaoProviderId: normalizeMaDaoProviderIdValue(inputMaDaoProviderId?.value || ''),
|
||||||
madaoCountry: normalizeMaDaoCountry(inputMaDaoCountry?.value || ''),
|
madaoCountry: normalizeMaDaoCountry(inputMaDaoCountry?.value || ''),
|
||||||
madaoAutoPickCountry: Boolean(inputMaDaoAutoPickCountry?.checked),
|
madaoAutoPickCountry: Boolean(inputMaDaoAutoPickCountry?.checked),
|
||||||
@@ -17205,8 +17433,8 @@ function applyPhoneSmsProviderFieldsToInputs(provider = getSelectedPhoneSmsProvi
|
|||||||
if (typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode) {
|
if (typeof selectMaDaoMode !== 'undefined' && selectMaDaoMode) {
|
||||||
selectMaDaoMode.value = normalizeMaDaoModeValue(state?.madaoMode);
|
selectMaDaoMode.value = normalizeMaDaoModeValue(state?.madaoMode);
|
||||||
}
|
}
|
||||||
if (typeof inputMaDaoRoutingPlanId !== 'undefined' && inputMaDaoRoutingPlanId) {
|
if (typeof selectMaDaoRoutingPlanId !== 'undefined' && selectMaDaoRoutingPlanId) {
|
||||||
inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(state?.madaoRoutingPlanId || '');
|
setMaDaoRoutingPlanSelectOptions(state?.madaoRoutingPlanId || '');
|
||||||
}
|
}
|
||||||
if (typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId) {
|
if (typeof inputMaDaoProviderId !== 'undefined' && inputMaDaoProviderId) {
|
||||||
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(state?.madaoProviderId || '');
|
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(state?.madaoProviderId || '');
|
||||||
@@ -17291,6 +17519,10 @@ async function switchPhoneSmsProvider(nextProvider) {
|
|||||||
applyNexSmsCountrySelection(
|
applyNexSmsCountrySelection(
|
||||||
Array.isArray(latestState?.nexSmsCountryOrder) ? latestState.nexSmsCountryOrder : []
|
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) {
|
} else if (normalizedNextProvider === PHONE_SMS_PROVIDER_HERO_SMS) {
|
||||||
await loadHeroSmsCountries({ silent: true });
|
await loadHeroSmsCountries({ silent: true });
|
||||||
const restoredPrimary = {
|
const restoredPrimary = {
|
||||||
@@ -17497,19 +17729,27 @@ selectMaDaoMode?.addEventListener('change', () => {
|
|||||||
selectMaDaoMode.value = normalizeMaDaoModeValue(selectMaDaoMode.value);
|
selectMaDaoMode.value = normalizeMaDaoModeValue(selectMaDaoMode.value);
|
||||||
updateHeroSmsPlatformDisplay();
|
updateHeroSmsPlatformDisplay();
|
||||||
updatePhoneVerificationSettingsUI();
|
updatePhoneVerificationSettingsUI();
|
||||||
|
if (selectMaDaoMode.value === MADAO_MODE_ROUTING_PLAN) {
|
||||||
|
loadMaDaoRoutingPlans({ silent: true }).catch(() => {
|
||||||
|
setMaDaoRoutingPlanSelectOptions(latestState?.madaoRoutingPlanId || '');
|
||||||
|
});
|
||||||
|
}
|
||||||
markSettingsDirty(true);
|
markSettingsDirty(true);
|
||||||
saveSettings({ silent: true }).catch(() => { });
|
saveSettings({ silent: true }).catch(() => { });
|
||||||
});
|
});
|
||||||
|
|
||||||
inputMaDaoRoutingPlanId?.addEventListener('input', () => {
|
selectMaDaoRoutingPlanId?.addEventListener('change', () => {
|
||||||
|
updateHeroSmsPlatformDisplay();
|
||||||
markSettingsDirty(true);
|
markSettingsDirty(true);
|
||||||
scheduleSettingsAutoSave();
|
|
||||||
});
|
|
||||||
inputMaDaoRoutingPlanId?.addEventListener('blur', () => {
|
|
||||||
inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(inputMaDaoRoutingPlanId.value);
|
|
||||||
saveSettings({ silent: true }).catch(() => { });
|
saveSettings({ silent: true }).catch(() => { });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
btnMaDaoRefreshRoutingPlans?.addEventListener('click', () => {
|
||||||
|
loadMaDaoRoutingPlans().catch((error) => {
|
||||||
|
showToast(`刷新 MaDao 路由计划失败:${error?.message || error}`, 'warn', 2200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
inputMaDaoProviderId?.addEventListener('input', () => {
|
inputMaDaoProviderId?.addEventListener('input', () => {
|
||||||
markSettingsDirty(true);
|
markSettingsDirty(true);
|
||||||
scheduleSettingsAutoSave();
|
scheduleSettingsAutoSave();
|
||||||
@@ -18592,8 +18832,8 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
selectMaDaoMode.value = normalizeMaDaoModeValue(message.payload.madaoMode);
|
selectMaDaoMode.value = normalizeMaDaoModeValue(message.payload.madaoMode);
|
||||||
updatePhoneVerificationSettingsUI();
|
updatePhoneVerificationSettingsUI();
|
||||||
}
|
}
|
||||||
if (message.payload.madaoRoutingPlanId !== undefined && inputMaDaoRoutingPlanId) {
|
if (message.payload.madaoRoutingPlanId !== undefined && selectMaDaoRoutingPlanId) {
|
||||||
inputMaDaoRoutingPlanId.value = normalizeMaDaoIdentifierValue(message.payload.madaoRoutingPlanId);
|
setMaDaoRoutingPlanSelectOptions(message.payload.madaoRoutingPlanId);
|
||||||
}
|
}
|
||||||
if (message.payload.madaoProviderId !== undefined && inputMaDaoProviderId) {
|
if (message.payload.madaoProviderId !== undefined && inputMaDaoProviderId) {
|
||||||
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(message.payload.madaoProviderId);
|
inputMaDaoProviderId.value = normalizeMaDaoProviderIdValue(message.payload.madaoProviderId);
|
||||||
|
|||||||
@@ -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="row-madao-mode"/);
|
||||||
assert.match(html, /id="select-madao-mode"/);
|
assert.match(html, /id="select-madao-mode"/);
|
||||||
assert.match(html, /id="row-madao-routing-plan-id"/);
|
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="row-madao-provider-id"/);
|
||||||
assert.doesNotMatch(html, /id="input-madao-provider-id"/);
|
assert.doesNotMatch(html, /id="input-madao-provider-id"/);
|
||||||
assert.doesNotMatch(html, /id="row-madao-country"/);
|
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) 国家列表失败:'/);
|
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', () => {
|
test('HeroSMS country parser accepts keyed country maps from the live API', () => {
|
||||||
const api = new Function(`
|
const api = new Function(`
|
||||||
${extractFunction('normalizeHeroSmsCountryPayloadEntries')}
|
${extractFunction('normalizeHeroSmsCountryPayloadEntries')}
|
||||||
@@ -1160,7 +1241,7 @@ const inputNexSmsServiceCode = { value: 'ot' };
|
|||||||
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/acquire' };
|
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/acquire' };
|
||||||
const inputMaDaoHttpSecret = { value: 'madao-secret' };
|
const inputMaDaoHttpSecret = { value: 'madao-secret' };
|
||||||
const selectMaDaoMode = { value: 'direct' };
|
const selectMaDaoMode = { value: 'direct' };
|
||||||
const inputMaDaoRoutingPlanId = { value: 'plan-1' };
|
const selectMaDaoRoutingPlanId = { value: 'plan-1' };
|
||||||
const inputMaDaoProviderId = { value: 'Local Provider!!' };
|
const inputMaDaoProviderId = { value: 'Local Provider!!' };
|
||||||
const inputMaDaoCountry = { value: 'th' };
|
const inputMaDaoCountry = { value: 'th' };
|
||||||
const inputMaDaoAutoPickCountry = { checked: false };
|
const inputMaDaoAutoPickCountry = { checked: false };
|
||||||
@@ -1434,7 +1515,13 @@ const inputNexSmsServiceCode = { value: 'ot' };
|
|||||||
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/poll' };
|
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/poll' };
|
||||||
const inputMaDaoHttpSecret = { value: 'madao-live-secret' };
|
const inputMaDaoHttpSecret = { value: 'madao-live-secret' };
|
||||||
const selectMaDaoMode = { value: 'direct' };
|
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 inputMaDaoProviderId = { value: 'Provider Live!' };
|
||||||
const inputMaDaoCountry = { value: 'local' };
|
const inputMaDaoCountry = { value: 'local' };
|
||||||
const inputMaDaoAutoPickCountry = { checked: false };
|
const inputMaDaoAutoPickCountry = { checked: false };
|
||||||
@@ -1454,6 +1541,7 @@ let heroSmsCountrySelectionOrder = [];
|
|||||||
let phoneSmsProviderOrderSelection = ['hero-sms', '5sim'];
|
let phoneSmsProviderOrderSelection = ['hero-sms', '5sim'];
|
||||||
let lastPhoneSmsProviderBeforeChange = null;
|
let lastPhoneSmsProviderBeforeChange = null;
|
||||||
let savedPayload = null;
|
let savedPayload = null;
|
||||||
|
let maDaoRoutingPlanOptions = [];
|
||||||
|
|
||||||
${extractFunction('normalizePhoneSmsProvider')}
|
${extractFunction('normalizePhoneSmsProvider')}
|
||||||
${extractFunction('normalizePhoneSmsProviderValue')}
|
${extractFunction('normalizePhoneSmsProviderValue')}
|
||||||
@@ -1483,9 +1571,14 @@ ${extractFunction('normalizeNexSmsServiceCodeValue')}
|
|||||||
${extractFunction('normalizeMaDaoBaseUrlValue')}
|
${extractFunction('normalizeMaDaoBaseUrlValue')}
|
||||||
${extractFunction('normalizeMaDaoModeValue')}
|
${extractFunction('normalizeMaDaoModeValue')}
|
||||||
${extractFunction('normalizeMaDaoIdentifierValue')}
|
${extractFunction('normalizeMaDaoIdentifierValue')}
|
||||||
|
${extractFunction('normalizeMaDaoRoutingPlanIdValue')}
|
||||||
${extractFunction('normalizeMaDaoProviderIdValue')}
|
${extractFunction('normalizeMaDaoProviderIdValue')}
|
||||||
${extractFunction('normalizeMaDaoCountry')}
|
${extractFunction('normalizeMaDaoCountry')}
|
||||||
${extractFunction('normalizeMaDaoPriceValue')}
|
${extractFunction('normalizeMaDaoPriceValue')}
|
||||||
|
${extractFunction('createSelectOptionElement')}
|
||||||
|
${extractFunction('setSelectOptions')}
|
||||||
|
${extractFunction('buildMaDaoRoutingPlanOptions')}
|
||||||
|
${extractFunction('setMaDaoRoutingPlanSelectOptions')}
|
||||||
${extractFunction('normalizePhoneSmsMinPriceValue')}
|
${extractFunction('normalizePhoneSmsMinPriceValue')}
|
||||||
${extractFunction('normalizePhoneSmsMaxPriceValue')}
|
${extractFunction('normalizePhoneSmsMaxPriceValue')}
|
||||||
${extractFunction('normalizeHeroSmsCountryId')}
|
${extractFunction('normalizeHeroSmsCountryId')}
|
||||||
|
|||||||
Reference in New Issue
Block a user