feat: CSV/云平台导入添加SSH端口(默认22) + 凭证关联下拉

- CSV模板新增port列, 连接方式改为SSH端口输入(默认22)
- 云平台导入新增SSH端口配置 + 凭证下拉选择
- 移除冗余的连接方式(密码/密钥)选择 → 凭证下拉统一管理
- ExcelServerImport: template含port列, resetState包含新字段
This commit is contained in:
attacker committed 2026-06-19 01:31:46 +00:00
1 parent cbf4334f7f
commit 11e8c24f37
2 files changed
+75 -35

No files matched your search

@@ -36,11 +36,6 @@ interface ExcelServerImportProps {
onClose: () => void;
}
const connectionMethods = [
{ id: 'password', name: '密码认证', description: '使用用户名密码连接' },
{ id: 'key', name: '密钥认证', description: '使用SSH密钥连接' },
];
type PreviewRow = {
row: number; hostname: string; ip: string; port: number;
username: string; os: string; cpu: number; memory: number; disk: number; tags: string;
@@ -94,13 +89,13 @@ function isValidIP(ip: string): boolean {
return /^(\d{1,3}\.){3}\d{1,3}$/.test(ip) && ip.split('.').every((o) => Number(o) >= 0 && Number(o) <= 255);
}
// 下载 CSV 导入模板 — 只需 hostname + ip,端口默认22 账号默认root,Agent 安装后自动补全 // Logan.Li
// 下载 CSV 导入模板 — 主机名+IP+端口(默认22),账号root,Agent 安装后自动补全 // Logan.Li
function downloadTemplate() {
const csv = [
'hostname,ip',
'web-01,192.168.1.10',
'db-01,192.168.1.20',
'cache-01,192.168.1.30',
'hostname,ip,port',
'web-01,192.168.1.10,22',
'db-01,192.168.1.20,22',
'cache-01,192.168.1.30,2222',
].join('\n');
const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
@@ -123,6 +118,7 @@ export function ExcelServerImport({ open, onClose }: ExcelServerImportProps) {
// 凭据选择 // Logan.Li
const [credentials, setCredentials] = useState<any[]>([]);
const [selectedCredentialId, setSelectedCredentialId] = useState<string>('');
const [defaultSshPort, setDefaultSshPort] = useState('22');
// 对话框打开时拉取区域列表 + 凭据列表 // Logan.Li
useEffect(() => {
@@ -221,7 +217,8 @@ export function ExcelServerImport({ open, onClose }: ExcelServerImportProps) {
const resetState = () => {
setStep(1);
setSelectedRegion('');
setConnectionMethod('password');
setDefaultSshPort('22');
setSelectedCredentialId('');
setSelectedFile(null);
setPreviewData([]);
};
@@ -245,8 +242,8 @@ export function ExcelServerImport({ open, onClose }: ExcelServerImportProps) {
const resp: any = await serverApi.batchCreate({
servers,
region_id: selectedRegion || undefined,
auth_type: connectionMethod,
credential_id: selectedCredentialId ? Number(selectedCredentialId) : undefined,
default_port: Number(defaultSshPort) || 22,
});
const r = resp ?? {};
const success = r.success ?? 0;
@@ -321,7 +318,7 @@ export function ExcelServerImport({ open, onClose }: ExcelServerImportProps) {
</div>
<div>
<p className="font-medium text-[var(--dg-text-primary)]">主机导入模板</p>
<p className="text-xs text-[var(--dg-text-muted)]">下载 CSV 模板,只填主机名和 IP,端口默认22、账号默认root</p>
<p className="text-xs text-[var(--dg-text-muted)]">下载 CSV 模板,只需填主机名、IP和端口(默认22),Agent安装后自动补全</p>
</div>
</div>
<Button variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]" onClick={downloadTemplate}>
@@ -375,27 +372,19 @@ export function ExcelServerImport({ open, onClose }: ExcelServerImportProps) {
)}
</div>
{/* Connection Method */}
{/* SSH 端口配置 */}
<div>
<label className="block text-sm font-medium text-[var(--dg-text-secondary)] mb-2">连接方式</label>
<div className="grid grid-cols-2 gap-4">
{connectionMethods.map((method) => (
<Card
key={method.id}
className={`cursor-pointer transition-all ${
connectionMethod === method.id
? 'border-blue-500 ring-1 ring-blue-500/30 bg-[var(--dg-bg-secondary)]'
: 'border-[var(--dg-border)] hover:border-blue-500 bg-[var(--dg-bg-secondary)]'
}`}
onClick={() => setConnectionMethod(method.id)}
>
<CardContent className="p-3">
<p className="font-medium text-[var(--dg-text-primary)]">{method.name}</p>
<p className="text-xs text-[var(--dg-text-muted)]">{method.description}</p>
</CardContent>
</Card>
))}
</div>
<label className="block text-sm font-medium text-[var(--dg-text-secondary)] mb-2">
SSH 端口
<span className="text-xs text-[var(--dg-text-muted)] ml-1">(导入时统一设置,可在服务器管理页单独修改)</span>
</label>
<Input
type="number"
placeholder="22"
value={defaultSshPort}
onChange={(e) => setDefaultSshPort(e.target.value)}
className="w-32 bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] text-[var(--dg-text-primary)]"
/>
</div>
</div>
)}