[功能] 添加域名证书绑定支持,允许为每个域名单独选择证书并优化相关逻辑

This commit is contained in:
ryan
2026-04-01 09:57:40 +08:00
parent a002d98f3a
commit 49472b54bf
17 changed files with 873 additions and 69 deletions
@@ -90,12 +90,22 @@ function buildDomainSuggestions(
export function buildDomainRowsFromRoute(
domains: string[],
domainCertIDs: number[],
certIDs: number[],
): DomainListRow[] {
if (domains.length === 0) {
return ensureRows([]);
}
if (domainCertIDs.length === domains.length) {
return domains.map((domain, index) => ({
domain,
certificateId: domainCertIDs[index]
? String(domainCertIDs[index])
: '',
}));
}
if (certIDs.length === 0) {
return domains.map((domain) => ({ domain, certificateId: '' }));
}
@@ -216,12 +216,24 @@ function normalizeSelectedCertificateIDs(rows: DomainListRow[]) {
return Array.from(
new Set(
rows
.filter((item) => item.domain.trim() !== '')
.map((item) => Number(item.certificateId))
.filter((item) => Number.isFinite(item) && item > 0),
),
);
}
function buildDomainCertificateIDs(rows: DomainListRow[]) {
return rows
.filter((item) => item.domain.trim() !== '')
.map((item) => {
const certificateID = Number(item.certificateId);
return Number.isFinite(certificateID) && certificateID > 0
? certificateID
: 0;
});
}
function buildDomainRows(route: ProxyRouteItem) {
const selectedCertIDs =
route.cert_ids.length > 0
@@ -230,7 +242,11 @@ function buildDomainRows(route: ProxyRouteItem) {
? [route.cert_id]
: [];
return buildDomainRowsFromRoute(route.domains, selectedCertIDs);
return buildDomainRowsFromRoute(
route.domains,
route.domain_cert_ids,
selectedCertIDs,
);
}
function ConfigSectionShell({
@@ -311,6 +327,7 @@ function DomainSettingsSection({
const domains = values.domain_rows
.map((item) => item.domain.trim().toLowerCase())
.filter(Boolean);
const domainCertIDs = buildDomainCertificateIDs(values.domain_rows);
const certIDs = normalizeSelectedCertificateIDs(values.domain_rows);
onSave(
@@ -322,6 +339,7 @@ function DomainSettingsSection({
enable_https: certIDs.length > 0,
cert_id: certIDs[0] ?? null,
cert_ids: certIDs,
domain_cert_ids: domainCertIDs,
redirect_http: certIDs.length > 0 ? values.redirect_http : false,
}),
{ message: '域名设置已保存。' },
@@ -95,12 +95,24 @@ function normalizeSelectedCertificateIDs(rows: DomainListRow[]) {
return Array.from(
new Set(
rows
.filter((item) => item.domain.trim() !== '')
.map((item) => Number(item.certificateId))
.filter((item) => Number.isFinite(item) && item > 0),
),
);
}
function buildDomainCertificateIDs(rows: DomainListRow[]) {
return rows
.filter((item) => item.domain.trim() !== '')
.map((item) => {
const certificateID = Number(item.certificateId);
return Number.isFinite(certificateID) && certificateID > 0
? certificateID
: 0;
});
}
export function ProxyRouteCreateDrawer({
open,
onOpenChange,
@@ -143,6 +155,7 @@ export function ProxyRouteCreateDrawer({
const domains = values.domain_rows
.map((item) => item.domain.trim().toLowerCase())
.filter(Boolean);
const domainCertIDs = buildDomainCertificateIDs(values.domain_rows);
const selectedCertIDs = normalizeSelectedCertificateIDs(values.domain_rows);
const { urls } = parseOriginUrls(values.origin_urls_text);
const primaryOrigin = parseOriginUrl(urls[0]);
@@ -168,6 +181,7 @@ export function ProxyRouteCreateDrawer({
enable_https: selectedCertIDs.length > 0,
cert_id: selectedCertIDs[0] ?? null,
cert_ids: selectedCertIDs,
domain_cert_ids: domainCertIDs,
redirect_http: selectedCertIDs.length > 0 ? values.redirect_http : false,
limit_conn_per_server: 0,
limit_conn_per_ip: 0,
@@ -275,6 +275,7 @@ export function buildPayloadFromRoute(
enable_https: route.enable_https,
cert_id: route.cert_id,
cert_ids: route.cert_ids,
domain_cert_ids: route.domain_cert_ids,
redirect_http: route.redirect_http,
limit_conn_per_server: route.limit_conn_per_server,
limit_conn_per_ip: route.limit_conn_per_ip,
@@ -19,6 +19,7 @@ export interface ProxyRouteItem {
enable_https: boolean;
cert_id: number | null;
cert_ids: number[];
domain_cert_ids: number[];
redirect_http: boolean;
limit_conn_per_server: number;
limit_conn_per_ip: number;
@@ -50,6 +51,7 @@ export interface ProxyRouteMutationPayload {
enable_https: boolean;
cert_id: number | null;
cert_ids?: number[];
domain_cert_ids?: number[];
redirect_http: boolean;
limit_conn_per_server?: number;
limit_conn_per_ip?: number;
@@ -50,6 +50,7 @@ function buildRoute(overrides: Record<string, unknown> = {}) {
enable_https: true,
cert_id: 1,
cert_ids: [1],
domain_cert_ids: [1, 0],
redirect_http: true,
limit_conn_per_server: 120,
limit_conn_per_ip: 12,
@@ -185,6 +186,7 @@ describe('Proxy route website pages', () => {
enable_https: payload.enable_https,
cert_id: payload.cert_id,
cert_ids: payload.cert_ids ?? [],
domain_cert_ids: payload.domain_cert_ids ?? [],
redirect_http: payload.redirect_http,
limit_conn_per_server: 0,
limit_conn_per_ip: 0,
@@ -337,6 +339,7 @@ describe('Proxy route website pages', () => {
enable_https: payload.enable_https,
cert_id: payload.cert_id,
cert_ids: payload.cert_ids,
domain_cert_ids: payload.domain_cert_ids,
redirect_http: payload.redirect_http,
}),
}),
@@ -404,7 +407,7 @@ describe('Proxy route website pages', () => {
await user.type(secondaryDomainInput, 'www.brand.example.com');
await user.selectOptions(screen.getByLabelText('证书 1'), '1');
await user.selectOptions(screen.getByLabelText('证书 2'), '1');
await user.selectOptions(screen.getByLabelText('证书 2'), '');
const saveButton = document.querySelector(
'button[form="proxy-route-domains-form"]',
@@ -427,6 +430,7 @@ describe('Proxy route website pages', () => {
enable_https: true,
cert_id: 1,
cert_ids: [1],
domain_cert_ids: [1, 0],
redirect_http: true,
});
});