fix: implement channel group routing failover

This commit is contained in:
hectorzhao
2026-07-03 11:07:43 +08:00
parent 131f344ac4
commit a890b03163
16 changed files with 853 additions and 121 deletions
+74 -5
View File
@@ -10,20 +10,35 @@ type PhoneSegment = DictionaryItem & {
city?: string | null;
};
type CarrierRule = DictionaryItem & {
carrier?: string;
pattern?: string;
priority?: number;
remark?: string | null;
};
export function AdminPhoneSegmentsPage() {
const [segments, setSegments] = useState<PhoneSegment[]>([]);
const [rules, setRules] = useState<CarrierRule[]>([]);
const [activeTab, setActiveTab] = useState<'segments' | 'rules'>('segments');
const [keyword, setKeyword] = useState('');
const [creating, setCreating] = useState(false);
const [creatingRule, setCreatingRule] = useState(false);
const [prefix, setPrefix] = useState('');
const [carrier, setCarrier] = useState('中国移动');
const [province, setProvince] = useState('');
const [city, setCity] = useState('');
const [ruleCarrier, setRuleCarrier] = useState('mobile');
const [rulePattern, setRulePattern] = useState('');
const [rulePriority, setRulePriority] = useState('100');
const [ruleRemark, setRuleRemark] = useState('');
const [error, setError] = useState('');
function loadData() {
adminApi.listPhoneSegments()
.then((items) => {
setSegments(items as PhoneSegment[]);
Promise.all([adminApi.listPhoneSegments(), adminApi.listPhoneCarrierRules()])
.then(([segmentItems, ruleItems]) => {
setSegments(segmentItems as PhoneSegment[]);
setRules(ruleItems as CarrierRule[]);
setError('');
})
.catch((failure: Error) => setError(failure.message || '手机号段加载失败'));
@@ -50,6 +65,17 @@ export function AdminPhoneSegmentsPage() {
.catch((failure: Error) => setError(failure.message || '手机号段新增失败'));
}
function createCarrierRule() {
adminApi.createPhoneCarrierRule({ carrier: ruleCarrier, pattern: rulePattern, priority: Number(rulePriority) || 100, remark: ruleRemark })
.then(() => {
setRulePattern('');
setRuleRemark('');
setCreatingRule(false);
loadData();
})
.catch((failure: Error) => setError(failure.message || '运营商区分规则新增失败'));
}
const columns = useMemo<Array<TableColumn<PhoneSegment>>>(() => [
{ key: 'segment', title: '手机号段(手机号码前7位)', width: '230px', render: (record) => <strong>{record.prefix}</strong> },
{ key: 'carrier', title: '运营商', width: '150px', render: (record) => record.carrier ?? '-' },
@@ -58,6 +84,13 @@ export function AdminPhoneSegmentsPage() {
{ key: 'createdAt', title: '创建时间', width: '190px', render: (record) => record.createdAt ?? '-' },
], []);
const ruleColumns = useMemo<Array<TableColumn<CarrierRule>>>(() => [
{ key: 'carrier', title: '运营商', width: '140px', render: (record) => record.carrier ?? '-' },
{ key: 'pattern', title: '号码前缀正则', render: (record) => <strong>{record.pattern}</strong> },
{ key: 'priority', title: '优先级', width: '120px', render: (record) => record.priority ?? 100 },
{ key: 'remark', title: '备注', render: (record) => record.remark ?? '-' },
], []);
return (
<section className="page-stack admin-system-page">
<div className="page-heading">
@@ -70,11 +103,19 @@ export function AdminPhoneSegmentsPage() {
<div className="surface admin-system-toolbar">
<Input onChange={(event) => setKeyword(event.target.value)} placeholder="搜索手机号段、运营商、省份或城市" prefix={<Search size={16} />} value={keyword} />
<Button icon={<Plus size={16} />} onClick={() => setCreating(true)}></Button>
<div className="segmented-control">
<button className={activeTab === 'segments' ? 'is-active' : ''} onClick={() => setActiveTab('segments')} type="button"></button>
<button className={activeTab === 'rules' ? 'is-active' : ''} onClick={() => setActiveTab('rules')} type="button"></button>
</div>
<Button icon={<Plus size={16} />} onClick={() => activeTab === 'segments' ? setCreating(true) : setCreatingRule(true)}>
{activeTab === 'segments' ? '新增号段' : '新增规则'}
</Button>
</div>
<div className="surface admin-system-table-card">
<Table columns={columns} data={filteredSegments} emptyText="暂无手机号段" rowKey="id" />
{activeTab === 'segments'
? <Table columns={columns} data={filteredSegments} emptyText="暂无手机号段" rowKey="id" />
: <Table columns={ruleColumns} data={rules} emptyText="暂无运营商区分规则" rowKey="id" />}
</div>
<Modal
@@ -104,6 +145,34 @@ export function AdminPhoneSegmentsPage() {
<Input label="城市" onChange={(event) => setCity(event.target.value)} value={city} />
</div>
</Modal>
<Modal
footer={(
<>
<Button onClick={() => setCreatingRule(false)} variant="ghost"></Button>
<Button disabled={!rulePattern} onClick={createCarrierRule}></Button>
</>
)}
onClose={() => setCreatingRule(false)}
open={creatingRule}
title="新增运营商区分规则"
>
<div className="admin-system-modal-form">
<Select
label="运营商"
onChange={(event) => setRuleCarrier(event.target.value)}
options={[
{ label: '移动', value: 'mobile' },
{ label: '联通', value: 'unicom' },
{ label: '电信', value: 'telecom' },
]}
value={ruleCarrier}
/>
<Input label="号码前缀正则" onChange={(event) => setRulePattern(event.target.value)} placeholder="例如 ^13[4-9]" value={rulePattern} />
<Input label="优先级" onChange={(event) => setRulePriority(event.target.value)} value={rulePriority} />
<Input label="备注" onChange={(event) => setRuleRemark(event.target.value)} value={ruleRemark} />
</div>
</Modal>
</section>
);
}