fix(madao): 适配国家中文标签和线路归一化
- 优先显示 MaDao 返回的 label_zh,不在 FlowPilot 内维护国家翻译表 - 兼容旧 provider_value 保存值,刷新直连国家后自动反选 ISO value - 将 any / Any operator 归一为空线路,避免重复选项和错误下发 - 保留 MaDao 隐藏复用控件缺失时的默认开启状态
This commit is contained in:
@@ -42,6 +42,15 @@
|
||||
return normalizeText(value).toLowerCase().replace(/[^a-z0-9_-]+/g, '');
|
||||
}
|
||||
|
||||
function normalizeOperator(value = '') {
|
||||
const rawValue = normalizeText(value);
|
||||
const compactValue = rawValue.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||||
if (!rawValue || compactValue === 'any' || compactValue === 'anyoperator') {
|
||||
return '';
|
||||
}
|
||||
return rawValue.toLowerCase().replace(/[^a-z0-9_-]+/g, '');
|
||||
}
|
||||
|
||||
function normalizeCountry(value = '') {
|
||||
const trimmed = normalizeText(value);
|
||||
if (!trimmed) {
|
||||
@@ -255,7 +264,7 @@
|
||||
service: normalizeText(options?.service || state?.madaoServiceName, DEFAULT_SERVICE),
|
||||
};
|
||||
const country = normalizeCountry(options?.country || state?.madaoCountry);
|
||||
const operator = normalizeProviderId(options?.operator || state?.madaoOperator);
|
||||
const operator = normalizeOperator(options?.operator || state?.madaoOperator);
|
||||
const minPrice = normalizePrice(options?.minPrice ?? state?.madaoMinPrice);
|
||||
const maxPrice = normalizePrice(options?.maxPrice ?? state?.madaoMaxPrice);
|
||||
|
||||
@@ -708,6 +717,7 @@
|
||||
normalizeCountry,
|
||||
normalizeCountryKey,
|
||||
normalizeCountryLabel,
|
||||
normalizeOperator,
|
||||
resolveActivationCountry,
|
||||
pollActivation,
|
||||
pollActivationCode,
|
||||
|
||||
+90
-7
@@ -5705,7 +5705,12 @@ function normalizeMaDaoProviderIdValue(value = '') {
|
||||
}
|
||||
|
||||
function normalizeMaDaoOperatorValue(value = '') {
|
||||
return String(value || '').trim().toLowerCase().replace(/[^a-z0-9_-]+/g, '');
|
||||
const rawValue = String(value || '').trim();
|
||||
const compactValue = rawValue.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
||||
if (!rawValue || compactValue === 'any' || compactValue === 'anyoperator') {
|
||||
return '';
|
||||
}
|
||||
return rawValue.toLowerCase().replace(/[^a-z0-9_-]+/g, '');
|
||||
}
|
||||
|
||||
function normalizeMaDaoCountry(value = '') {
|
||||
@@ -5723,6 +5728,22 @@ function normalizeMaDaoCountry(value = '') {
|
||||
return lowered.replace(/[^a-z0-9_-]+/g, '');
|
||||
}
|
||||
|
||||
function formatMaDaoCountryDisplayLabel(value = '', label = '', labelZh = '') {
|
||||
const country = normalizeMaDaoCountry(value);
|
||||
const sourceLabelZh = String(labelZh || '').trim();
|
||||
const sourceLabel = String(label || '').trim();
|
||||
if (!country) {
|
||||
return sourceLabelZh || sourceLabel;
|
||||
}
|
||||
if (country === 'local') {
|
||||
return sourceLabelZh || '本地';
|
||||
}
|
||||
if (country === 'any') {
|
||||
return sourceLabelZh || '任意国家';
|
||||
}
|
||||
return sourceLabelZh || sourceLabel || country;
|
||||
}
|
||||
|
||||
function normalizeMaDaoPriceValue(value = '') {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
if (!rawValue) {
|
||||
@@ -5860,6 +5881,7 @@ function normalizeMaDaoOptionListItems(items = [], selectedValue = '', normalize
|
||||
normalizedItems.push({
|
||||
value,
|
||||
label: String(item?.label || item?.name || item?.display_name || item?.displayName || value).trim() || value,
|
||||
labelZh: String(item?.label_zh || item?.labelZh || item?.display_name_zh || item?.displayNameZh || '').trim(),
|
||||
hint: String(item?.hint || item?.description || item?.provider_value || item?.providerValue || '').trim(),
|
||||
enabled: item?.enabled !== false,
|
||||
});
|
||||
@@ -5875,8 +5897,54 @@ function normalizeMaDaoOptionListItems(items = [], selectedValue = '', normalize
|
||||
return normalizedItems.filter((item) => item.enabled !== false);
|
||||
}
|
||||
|
||||
function resolveMaDaoOptionSelectedValue(items = [], selectedValue = '', normalizeValue = normalizeMaDaoIdentifierValue) {
|
||||
const normalizedSelected = normalizeValue(selectedValue);
|
||||
if (!normalizedSelected) {
|
||||
return '';
|
||||
}
|
||||
const sourceItems = Array.isArray(items) ? items : [];
|
||||
for (const item of sourceItems) {
|
||||
const value = normalizeValue(
|
||||
item?.value
|
||||
|| item?.id
|
||||
|| item?.provider
|
||||
|| item?.provider_value
|
||||
|| item?.providerValue
|
||||
|| item?.country
|
||||
|| item?.operator
|
||||
|| ''
|
||||
);
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
const aliases = [
|
||||
item?.value,
|
||||
item?.id,
|
||||
item?.provider,
|
||||
item?.provider_value,
|
||||
item?.providerValue,
|
||||
item?.country,
|
||||
item?.operator,
|
||||
item?.label,
|
||||
item?.label_zh,
|
||||
item?.labelZh,
|
||||
item?.name,
|
||||
item?.display_name,
|
||||
item?.displayName,
|
||||
];
|
||||
if (aliases.some((alias) => normalizeValue(alias || '') === normalizedSelected)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return normalizedSelected;
|
||||
}
|
||||
|
||||
function setMaDaoProviderSelectOptions(selectedValue = latestState?.madaoProviderId || '') {
|
||||
const normalizedSelected = normalizeMaDaoProviderIdValue(selectedValue);
|
||||
const normalizedSelected = resolveMaDaoOptionSelectedValue(
|
||||
maDaoProviderOptions,
|
||||
selectedValue,
|
||||
normalizeMaDaoProviderIdValue
|
||||
);
|
||||
const options = normalizeMaDaoOptionListItems(
|
||||
maDaoProviderOptions,
|
||||
normalizedSelected,
|
||||
@@ -5890,13 +5958,20 @@ function setMaDaoProviderSelectOptions(selectedValue = latestState?.madaoProvide
|
||||
}
|
||||
|
||||
function setMaDaoCountrySelectOptions(selectedValue = latestState?.madaoCountry || '') {
|
||||
const normalizedSelected = normalizeMaDaoCountry(selectedValue);
|
||||
const normalizedSelected = resolveMaDaoOptionSelectedValue(
|
||||
maDaoCountryOptions,
|
||||
selectedValue,
|
||||
normalizeMaDaoCountry
|
||||
);
|
||||
const options = normalizeMaDaoOptionListItems(
|
||||
maDaoCountryOptions,
|
||||
normalizedSelected,
|
||||
normalizeMaDaoCountry,
|
||||
'已保存的国家'
|
||||
);
|
||||
).map((item) => ({
|
||||
...item,
|
||||
label: formatMaDaoCountryDisplayLabel(item.value, item.label, item.labelZh),
|
||||
}));
|
||||
setSelectOptions(selectMaDaoCountry, options, {
|
||||
placeholder: '请先选择服务商',
|
||||
value: normalizedSelected,
|
||||
@@ -5904,7 +5979,11 @@ function setMaDaoCountrySelectOptions(selectedValue = latestState?.madaoCountry
|
||||
}
|
||||
|
||||
function setMaDaoOperatorSelectOptions(selectedValue = latestState?.madaoOperator || '') {
|
||||
const normalizedSelected = normalizeMaDaoOperatorValue(selectedValue);
|
||||
const normalizedSelected = resolveMaDaoOptionSelectedValue(
|
||||
maDaoOperatorOptions,
|
||||
selectedValue,
|
||||
normalizeMaDaoOperatorValue
|
||||
);
|
||||
const options = normalizeMaDaoOptionListItems(
|
||||
maDaoOperatorOptions,
|
||||
normalizedSelected,
|
||||
@@ -17653,8 +17732,12 @@ function buildPhoneSmsProviderStatePatch(provider = getSelectedPhoneSmsProvider(
|
||||
madaoOperator: shouldReadMaDaoDirectControls
|
||||
? normalizeMaDaoOperatorValue(selectMaDaoOperator?.value || '')
|
||||
: normalizeMaDaoOperatorValue(latestState?.madaoOperator || ''),
|
||||
madaoAutoPickCountry: Boolean(inputMaDaoAutoPickCountry?.checked),
|
||||
madaoReusePhone: Boolean(inputMaDaoReusePhone?.checked),
|
||||
madaoAutoPickCountry: typeof inputMaDaoAutoPickCountry !== 'undefined' && inputMaDaoAutoPickCountry
|
||||
? Boolean(inputMaDaoAutoPickCountry.checked)
|
||||
: (latestState?.madaoAutoPickCountry !== undefined ? Boolean(latestState.madaoAutoPickCountry) : true),
|
||||
madaoReusePhone: typeof inputMaDaoReusePhone !== 'undefined' && inputMaDaoReusePhone
|
||||
? Boolean(inputMaDaoReusePhone.checked)
|
||||
: (latestState?.madaoReusePhone !== undefined ? Boolean(latestState.madaoReusePhone) : true),
|
||||
madaoMinPrice: normalizeMaDaoPriceValue(inputMaDaoMinPrice?.value || ''),
|
||||
madaoMaxPrice: normalizeMaDaoPriceValue(inputMaDaoMaxPrice?.value || ''),
|
||||
};
|
||||
|
||||
@@ -104,6 +104,37 @@ test('MaDao routing acquire sends routing plan only', async () => {
|
||||
assert.equal(activation.madaoRoutingItemId, 'route-1');
|
||||
});
|
||||
|
||||
test('MaDao direct acquire treats any operator as default route', async () => {
|
||||
const requests = [];
|
||||
const provider = api.createProvider({
|
||||
fetchImpl: async (_url, options = {}) => {
|
||||
requests.push({ body: JSON.parse(options.body) });
|
||||
return createJsonResponse({
|
||||
ticket_id: 'ticket-any',
|
||||
phone_number: '+66111111111',
|
||||
country: 'TH',
|
||||
provider: 'fivesim',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await provider.acquireActivation({
|
||||
madaoMode: 'direct',
|
||||
madaoProviderId: 'fivesim',
|
||||
madaoCountry: 'TH',
|
||||
madaoOperator: 'Any operator',
|
||||
});
|
||||
|
||||
assert.equal(requests.length, 1);
|
||||
assert.deepEqual(requests[0].body, {
|
||||
provider: 'fivesim',
|
||||
service: 'openai',
|
||||
auto_pick_country: true,
|
||||
reuse_phone: true,
|
||||
country: 'TH',
|
||||
});
|
||||
});
|
||||
|
||||
test('MaDao poll extracts codes from nested messages and reports pending status', async () => {
|
||||
const statusEvents = [];
|
||||
const provider = api.createProvider({
|
||||
|
||||
@@ -315,8 +315,8 @@ test('MaDao direct selects load provider country and operator options from daemo
|
||||
return JSON.stringify({
|
||||
provider: 'stored-provider',
|
||||
items: [
|
||||
{ value: 'GB', label: 'United Kingdom' },
|
||||
{ value: 'TH', label: 'Thailand' },
|
||||
{ value: 'GB', label: 'United Kingdom', label_zh: '英国', provider_value: 'england' },
|
||||
{ value: 'TH', label: 'Thailand', label_zh: '泰国', provider_value: '52' },
|
||||
],
|
||||
});
|
||||
},
|
||||
@@ -331,6 +331,7 @@ test('MaDao direct selects load provider country and operator options from daemo
|
||||
return JSON.stringify({
|
||||
provider: 'stored-provider',
|
||||
items: [
|
||||
{ value: 'any', label: 'Any operator' },
|
||||
{ value: 'operator-a', label: 'Operator A' },
|
||||
{ value: 'operator-b', label: 'Operator B' },
|
||||
],
|
||||
@@ -347,7 +348,7 @@ let latestState = {
|
||||
madaoBaseUrl: 'http://madao.local/api/acquire',
|
||||
madaoHttpSecret: 'madao-secret',
|
||||
madaoProviderId: 'stored-provider',
|
||||
madaoCountry: 'GB',
|
||||
madaoCountry: 'england',
|
||||
madaoOperator: 'operator-a',
|
||||
};
|
||||
let maDaoProviderOptions = [];
|
||||
@@ -358,7 +359,7 @@ let toastText = '';
|
||||
const inputMaDaoBaseUrl = { value: 'http://madao.local/api/acquire' };
|
||||
const inputMaDaoHttpSecret = { value: 'madao-secret' };
|
||||
const selectMaDaoProviderId = { value: 'stored-provider', options: [], replaceChildren(...children) { this.options = children; } };
|
||||
const selectMaDaoCountry = { value: 'GB', options: [], replaceChildren(...children) { this.options = children; } };
|
||||
const selectMaDaoCountry = { value: 'england', options: [], replaceChildren(...children) { this.options = children; } };
|
||||
const selectMaDaoOperator = { value: 'operator-a', options: [], replaceChildren(...children) { this.options = children; } };
|
||||
function updateHeroSmsPlatformDisplay() {
|
||||
displayText = [selectMaDaoProviderId.value, selectMaDaoCountry.value, selectMaDaoOperator.value].filter(Boolean).join('/');
|
||||
@@ -371,9 +372,11 @@ ${extractFunction('normalizeMaDaoIdentifierValue')}
|
||||
${extractFunction('normalizeMaDaoProviderIdValue')}
|
||||
${extractFunction('normalizeMaDaoOperatorValue')}
|
||||
${extractFunction('normalizeMaDaoCountry')}
|
||||
${extractFunction('formatMaDaoCountryDisplayLabel')}
|
||||
${extractFunction('createSelectOptionElement')}
|
||||
${extractFunction('setSelectOptions')}
|
||||
${extractFunction('normalizeMaDaoOptionListItems')}
|
||||
${extractFunction('resolveMaDaoOptionSelectedValue')}
|
||||
${extractFunction('setMaDaoProviderSelectOptions')}
|
||||
${extractFunction('setMaDaoCountrySelectOptions')}
|
||||
${extractFunction('setMaDaoOperatorSelectOptions')}
|
||||
@@ -408,7 +411,9 @@ return {
|
||||
assert.equal(api.selectMaDaoOperator.value, 'operator-a');
|
||||
assert.deepStrictEqual(api.providerOptions.map((option) => option.value), ['', 'stored-provider']);
|
||||
assert.deepStrictEqual(api.countryOptions.map((option) => option.value), ['', 'GB', 'TH']);
|
||||
assert.deepStrictEqual(api.countryOptions.map((option) => option.label), ['请先选择服务商', '英国', '泰国']);
|
||||
assert.deepStrictEqual(api.operatorOptions.map((option) => option.value), ['', 'operator-a', 'operator-b']);
|
||||
assert.deepStrictEqual(api.operatorOptions.map((option) => option.label), ['任意线路', 'Operator A', 'Operator B']);
|
||||
assert.equal(api.displayText, 'stored-provider/GB/operator-a');
|
||||
assert.equal(api.toastText, '已刷新 MaDao 服务商。');
|
||||
assert.deepStrictEqual(requests.map((request) => request.pathname), [
|
||||
@@ -1503,6 +1508,7 @@ ${extractFunction('normalizeMaDaoIdentifierValue')}
|
||||
${extractFunction('normalizeMaDaoProviderIdValue')}
|
||||
${extractFunction('normalizeMaDaoOperatorValue')}
|
||||
${extractFunction('normalizeMaDaoCountry')}
|
||||
${extractFunction('formatMaDaoCountryDisplayLabel')}
|
||||
${extractFunction('normalizeMaDaoPriceValue')}
|
||||
${extractFunction('normalizeFiveSimCountryCode')}
|
||||
${extractFunction('normalizeFiveSimCountryOrderValue')}
|
||||
@@ -1755,9 +1761,11 @@ ${extractFunction('normalizeMaDaoProviderIdValue')}
|
||||
${extractFunction('normalizeMaDaoOperatorValue')}
|
||||
${extractFunction('normalizeMaDaoCountry')}
|
||||
${extractFunction('normalizeMaDaoPriceValue')}
|
||||
${extractFunction('formatMaDaoCountryDisplayLabel')}
|
||||
${extractFunction('createSelectOptionElement')}
|
||||
${extractFunction('setSelectOptions')}
|
||||
${extractFunction('normalizeMaDaoOptionListItems')}
|
||||
${extractFunction('resolveMaDaoOptionSelectedValue')}
|
||||
${extractFunction('buildMaDaoRoutingPlanOptions')}
|
||||
${extractFunction('setMaDaoRoutingPlanSelectOptions')}
|
||||
${extractFunction('setMaDaoProviderSelectOptions')}
|
||||
@@ -1842,6 +1850,71 @@ return {
|
||||
assert.equal(api.savedPayload.fiveSimMinPrice, '0.88');
|
||||
});
|
||||
|
||||
test('buildPhoneSmsProviderStatePatch preserves MaDao hidden reuse defaults when controls are absent', () => {
|
||||
const api = new Function(`
|
||||
let latestState = {
|
||||
phoneSmsProvider: 'madao',
|
||||
madaoBaseUrl: 'http://127.0.0.1:7822',
|
||||
madaoHttpSecret: 'secret-old',
|
||||
madaoMode: 'direct',
|
||||
madaoRoutingPlanId: 'plan-old',
|
||||
madaoProviderId: 'provider-old',
|
||||
madaoCountry: 'TH',
|
||||
madaoOperator: 'any',
|
||||
madaoAutoPickCountry: true,
|
||||
madaoReusePhone: true,
|
||||
madaoMinPrice: '0.01',
|
||||
madaoMaxPrice: '0.09',
|
||||
};
|
||||
const PHONE_SMS_PROVIDER_HERO_SMS = 'hero-sms';
|
||||
const PHONE_SMS_PROVIDER_HERO = PHONE_SMS_PROVIDER_HERO_SMS;
|
||||
const PHONE_SMS_PROVIDER_FIVE_SIM = '5sim';
|
||||
const PHONE_SMS_PROVIDER_NEXSMS = 'nexsms';
|
||||
const PHONE_SMS_PROVIDER_MADAO = 'madao';
|
||||
const DEFAULT_PHONE_SMS_PROVIDER = PHONE_SMS_PROVIDER_HERO_SMS;
|
||||
const DEFAULT_FIVE_SIM_COUNTRY_ID = 'vietnam';
|
||||
const DEFAULT_FIVE_SIM_COUNTRY_LABEL = '越南 (Vietnam)';
|
||||
const DEFAULT_FIVE_SIM_OPERATOR = 'any';
|
||||
const DEFAULT_FIVE_SIM_PRODUCT = 'openai';
|
||||
const DEFAULT_NEX_SMS_SERVICE_CODE = 'ot';
|
||||
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;
|
||||
const selectMaDaoMode = { value: 'direct' };
|
||||
const selectMaDaoRoutingPlanId = { value: 'plan-live' };
|
||||
const selectMaDaoProviderId = { value: 'provider-live' };
|
||||
const selectMaDaoCountry = { value: 'GB' };
|
||||
const selectMaDaoOperator = { value: 'Any operator' };
|
||||
const inputMaDaoBaseUrl = { value: 'http://127.0.0.1:7822/api/acquire' };
|
||||
const inputMaDaoHttpSecret = { value: 'secret-live' };
|
||||
const inputMaDaoMinPrice = { value: '0.02' };
|
||||
const inputMaDaoMaxPrice = { value: '0.20' };
|
||||
|
||||
${extractFunction('normalizePhoneSmsProvider')}
|
||||
${extractFunction('normalizeMaDaoBaseUrlValue')}
|
||||
${extractFunction('normalizeMaDaoModeValue')}
|
||||
${extractFunction('normalizeMaDaoIdentifierValue')}
|
||||
${extractFunction('normalizeMaDaoRoutingPlanIdValue')}
|
||||
${extractFunction('normalizeMaDaoProviderIdValue')}
|
||||
${extractFunction('normalizeMaDaoOperatorValue')}
|
||||
${extractFunction('normalizeMaDaoCountry')}
|
||||
${extractFunction('normalizeMaDaoPriceValue')}
|
||||
${extractFunction('normalizePhoneSmsMinPriceValue')}
|
||||
${extractFunction('normalizePhoneSmsMaxPriceValue')}
|
||||
${extractFunction('buildPhoneSmsProviderStatePatch')}
|
||||
return { buildPhoneSmsProviderStatePatch };
|
||||
`)();
|
||||
|
||||
const patch = api.buildPhoneSmsProviderStatePatch('madao');
|
||||
|
||||
assert.equal(patch.madaoAutoPickCountry, true);
|
||||
assert.equal(patch.madaoReusePhone, true);
|
||||
assert.equal(patch.madaoOperator, '');
|
||||
assert.equal(patch.madaoProviderId, 'provider-live');
|
||||
assert.equal(patch.madaoCountry, 'GB');
|
||||
});
|
||||
|
||||
test('HeroSMS operator helpers normalize keyed operator payloads', () => {
|
||||
const api = new Function(`
|
||||
const DEFAULT_HERO_SMS_OPERATOR = 'any';
|
||||
|
||||
Reference in New Issue
Block a user