新增添加修改删除域名解析记录的api端点

This commit is contained in:
jingrow 2025-08-03 20:28:12 +08:00
parent c42115a0ad
commit 2f3224eb06
2 changed files with 451 additions and 64 deletions

View File

@ -52,58 +52,83 @@
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<input type="checkbox" class="rounded border-gray-300" />
</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
主机名
</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
类型
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
主机记录
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
线路类型
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
记录
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
对应
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
TTL
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
优先级
</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
状态
</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
操作
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr v-for="record in dnsRecords" :key="record.id" class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap">
<Badge :variant="getRecordTypeVariant(record.type)">
{{ record.type }}
</Badge>
<td class="px-4 py-4 whitespace-nowrap">
<input type="checkbox" class="rounded border-gray-300" />
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900">
<td class="px-4 py-4 whitespace-nowrap text-sm font-mono text-gray-900">
{{ record.item || record.host || '@' }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-mono text-gray-900">
{{ record.value }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{ record.ttl || '600' }}
<span v-if="record.type === 'MX' && record.level" class="ml-2 text-xs text-blue-600">
(优先级: {{ record.level }})
<td class="px-4 py-4 whitespace-nowrap">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
:class="{
'bg-green-100 text-green-800': record.type === 'A',
'bg-blue-100 text-blue-800': record.type === 'AAAA',
'bg-yellow-100 text-yellow-800': record.type === 'CNAME',
'bg-purple-100 text-purple-800': record.type === 'MX',
'bg-gray-100 text-gray-800': record.type === 'TXT',
'bg-orange-100 text-orange-800': record.type === 'NS',
'bg-gray-100 text-gray-800': !record.type
}">
{{ record.type || '未知' }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<div class="flex items-center space-x-2">
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
默认
</td>
<td class="px-4 py-4 whitespace-nowrap text-sm font-mono text-gray-900 max-w-xs truncate" :title="record.value">
{{ record.value }}
</td>
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
{{ record.ttl || '600' }}
</td>
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
{{ record.type === 'MX' && record.level ? record.level : '-' }}
</td>
<td class="px-4 py-4 whitespace-nowrap text-sm">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
正常
</span>
</td>
<td class="px-4 py-4 whitespace-nowrap text-sm">
<div class="flex items-center space-x-1">
<Button
@click="editRecord(record)"
variant="ghost"
size="sm"
class="text-blue-600 hover:text-blue-700"
>
<EditIcon class="h-4 w-4" />
</Button>
<Button
@click="deleteRecord(record)"
variant="ghost"
size="sm"
class="text-red-600 hover:text-red-700"
>
<Trash2Icon class="h-4 w-4" />
修改
</Button>
</div>
</td>
@ -112,6 +137,24 @@
</table>
</div>
<!-- 批量操作 -->
<div class="flex items-center justify-between bg-gray-50 px-4 py-3 rounded-md">
<div class="flex items-center space-x-4">
<input type="checkbox" class="rounded border-gray-300" />
<span class="text-sm text-gray-700">已选 0 </span>
<div class="flex items-center space-x-2">
<Button variant="outline" size="sm">批量暂停</Button>
<Button variant="outline" size="sm">批量启用</Button>
<Button variant="outline" size="sm">批量修改</Button>
<Button variant="outline" size="sm">批量删除</Button>
</div>
</div>
<div class="flex items-center space-x-4">
<Button variant="link" size="sm">导出解析记录</Button>
<Button variant="link" size="sm">导入解析记录</Button>
</div>
</div>
<!-- 分页 -->
<div v-if="pagination.total > pagination.limit" class="flex items-center justify-between">
<div class="text-sm text-gray-700">

View File

@ -312,44 +312,106 @@ class WestDomain:
return self._make_request('/domain/?act=modifydns', 'POST', body_params=body_params)
def add_dns_record(self, domain: str, record_type: str,
host: str, value: str, ttl: int = 600, level: int = 10) -> Dict[str, Any]:
host: str, value: str, ttl: int = 600, level: int = 10, line: str = "") -> Dict[str, Any]:
"""
添加DNS记录
Args:
domain: 域名
record_type: 记录类型 (A, CNAME, MX, TXT)
record_type: 记录类型 (A, CNAME, MX, TXT, AAAA, SRV)
host: 主机记录
value: 记录值
ttl: TTL值
level: 优先级MX记录使用
ttl: TTL值 (60~86400默认900)
level: 优先级MX记录使用1-100默认10
line: 线路 (默认="", 电信="LTEL", 联通="LCNC", 移动="LMOB", 教育网="LEDU", 搜索引擎="LSEO")
"""
record = {
'type': record_type,
body_params = {
'act': 'adddnsrecord',
'domain': domain,
'host': host,
'type': record_type,
'value': value,
'ttl': ttl,
'level': level,
'line': line,
}
return self._make_request('/domain/', 'POST', body_params=body_params)
def modify_dns_record(self, domain: str, value: str, ttl: int = 600, level: int = 10,
record_id: Optional[str] = None, host: Optional[str] = None,
record_type: Optional[str] = None, line: str = "", old_value: Optional[str] = None) -> Dict[str, Any]:
"""
修改DNS记录
Args:
domain: 域名
value: 新的解析值
ttl: TTL值 (60~86400默认900)
level: 优先级MX记录使用1-100默认10
record_id: 解析记录编号优先使用
host: 主机头当record_id未提供时必填
record_type: 解析类型当record_id未提供时必填
line: 线路 (默认="", 电信="LTEL", 联通="LCNC", 移动="LMOB", 教育网="LEDU", 搜索引擎="LSEO")
old_value: 旧解析值可选用于确定唯一记录
"""
body_params = {
'act': 'moddnsrecord',
'domain': domain,
'value': value,
'ttl': ttl,
'level': level,
'line': line,
}
# 如果是MX记录添加优先级
if record_type == 'MX':
record['level'] = level
return self.modify_dns_records(domain, [record])
# 优先使用record_id
if record_id:
body_params['id'] = record_id
else:
# 必须提供host和type
if not host or not record_type:
return {"status": "error", "message": "当未提供记录ID时主机头和解析类型为必填项"}
body_params['host'] = host
body_params['type'] = record_type
# 添加旧值(可选)
if old_value:
body_params['oldvalue'] = old_value
return self._make_request('/domain/', 'POST', body_params=body_params)
def delete_dns_record(self, domain: str, record_id: str) -> Dict[str, Any]:
def delete_dns_record(self, domain: str, record_id: Optional[str] = None,
host: Optional[str] = None, record_type: Optional[str] = None,
value: Optional[str] = None, line: str = "") -> Dict[str, Any]:
"""
删除DNS记录
Args:
domain: 域名
record_id: 记录ID
record_id: 解析记录ID优先使用
host: 主机头当record_id未提供时必填
record_type: 解析类型当record_id未提供时必填
value: 解析值可选
line: 线路 (默认="", 电信="LTEL", 联通="LCNC", 移动="LMOB", 教育网="LEDU", 搜索引擎="LSEO")
"""
body_params = {
'act': 'deldnsrecord',
'domain': domain,
'record_id': record_id,
'line': line,
}
return self._make_request('/domain/?act=deletedns', 'POST', body_params=body_params)
# 优先使用record_id
if record_id:
body_params['id'] = record_id
else:
# 必须提供host和type
if not host or not record_type:
return {"status": "error", "message": "当未提供记录ID时主机头和解析类型为必填项"}
body_params['host'] = host
body_params['type'] = record_type
if value:
body_params['value'] = value
return self._make_request('/domain/', 'POST', body_params=body_params)
def transfer_domain(self, domain: str, auth_code: str) -> Dict[str, Any]:
"""
@ -822,7 +884,7 @@ def get_west_domain_dns_records(**data):
@jingrow.whitelist()
def west_domain_modify_dns(**data):
"""修改域名DNS记录"""
"""修改域名DNS记录(批量修改,兼容旧版本)"""
client = get_west_client()
if not client:
return {"status": "error", "message": "API客户端初始化失败"}
@ -835,23 +897,80 @@ def west_domain_modify_dns(**data):
if not records:
return {"status": "error", "message": "缺少DNS记录参数"}
# 处理记录数据确保MX记录有正确的优先级字段
processed_records = []
# 逐个修改记录
results = []
for record in records:
processed_record = {
'type': record.get('type'),
'host': record.get('host'),
'value': record.get('value'),
'ttl': record.get('ttl', 600)
}
record_type = record.get('type')
host = record.get('host')
value = record.get('value')
ttl = record.get('ttl', 600)
level = record.get('level', 10)
line = record.get('line', '')
record_id = record.get('record_id')
old_value = record.get('old_value')
# 如果是MX记录添加优先级
if record.get('type') == 'MX':
processed_record['level'] = record.get('level', 10)
processed_records.append(processed_record)
# 验证必要参数
if not value:
results.append({"status": "error", "message": "缺少解析值"})
continue
# 如果没有提供record_id则必须提供host和record_type
if not record_id and (not host or not record_type):
results.append({"status": "error", "message": "当未提供记录ID时主机头和解析类型为必填项"})
continue
# 验证TTL值
if ttl < 60 or ttl > 86400:
results.append({"status": "error", "message": "TTL值必须在60~86400秒之间"})
continue
# 验证优先级
if level < 1 or level > 100:
results.append({"status": "error", "message": "优先级必须在1~100之间"})
continue
# 验证记录类型
if record_type:
valid_types = ['A', 'CNAME', 'MX', 'TXT', 'AAAA', 'SRV']
if record_type not in valid_types:
results.append({"status": "error", "message": f"不支持的记录类型: {record_type}"})
continue
# 调用单个记录修改API
response = client.modify_dns_record(
domain, value, ttl, level, record_id, host, record_type, line, old_value
)
if response.get("status") == "error":
results.append(response)
elif response.get("result") != 200:
error_msg = response.get('msg', response.get('message', '未知错误'))
results.append({"status": "error", "message": f"修改DNS记录失败: {error_msg}"})
else:
results.append({
"status": "success",
"message": "DNS记录修改成功",
"data": {
"domain": domain,
"value": value,
"ttl": ttl,
"level": level,
"record_id": record_id,
"host": host,
"record_type": record_type,
"line": line
}
})
return client.modify_dns_records(domain, processed_records)
# 返回批量操作结果
success_count = sum(1 for r in results if r.get("status") == "success")
error_count = len(results) - success_count
return {
"status": "success" if error_count == 0 else "partial_success",
"message": f"批量修改完成,成功: {success_count},失败: {error_count}",
"results": results
}
@jingrow.whitelist()
@ -867,11 +986,54 @@ def west_domain_add_dns_record(**data):
value = data.get('value')
ttl = data.get('ttl', 600)
level = data.get('level', 10)
line = data.get('line', '')
if not all([domain, record_type, host, value]):
return {"status": "error", "message": "缺少必要参数"}
return client.add_dns_record(domain, record_type, host, value, ttl, level)
# 验证记录类型
valid_types = ['A', 'CNAME', 'MX', 'TXT', 'AAAA', 'SRV']
if record_type not in valid_types:
return {"status": "error", "message": f"不支持的记录类型: {record_type},支持的类型: {', '.join(valid_types)}"}
# 验证TTL值
if ttl < 60 or ttl > 86400:
return {"status": "error", "message": "TTL值必须在60~86400秒之间"}
# 验证优先级
if level < 1 or level > 100:
return {"status": "error", "message": "优先级必须在1~100之间"}
response = client.add_dns_record(domain, record_type, host, value, ttl, level, line)
if response.get("status") == "error":
return response
try:
# 检查响应格式
if response.get("result") != 200:
error_msg = response.get('msg', response.get('message', '未知错误'))
return {"status": "error", "message": f"添加DNS记录失败: {error_msg}"}
# 返回成功结果
return {
"status": "success",
"message": "DNS记录添加成功",
"data": {
"id": response.get("data", {}).get("id"),
"domain": domain,
"host": host,
"type": record_type,
"value": value,
"ttl": ttl,
"level": level,
"line": line
}
}
except Exception as e:
jingrow.log_error("添加DNS记录响应解析失败", error=str(e))
return {"status": "error", "message": "添加DNS记录响应解析失败"}
@jingrow.whitelist()
@ -883,13 +1045,52 @@ def west_domain_delete_dns_record(**data):
domain = data.get('domain')
record_id = data.get('record_id')
host = data.get('host')
record_type = data.get('record_type')
value = data.get('value')
line = data.get('line', '')
if not domain:
return {"status": "error", "message": "缺少域名参数"}
if not record_id:
return {"status": "error", "message": "缺少记录ID参数"}
return client.delete_dns_record(domain, record_id)
# 如果没有提供record_id则必须提供host和record_type
if not record_id and (not host or not record_type):
return {"status": "error", "message": "当未提供记录ID时主机头和解析类型为必填项"}
# 验证记录类型
if record_type:
valid_types = ['A', 'CNAME', 'MX', 'TXT', 'AAAA', 'SRV']
if record_type not in valid_types:
return {"status": "error", "message": f"不支持的记录类型: {record_type},支持的类型: {', '.join(valid_types)}"}
response = client.delete_dns_record(domain, record_id, host, record_type, value, line)
if response.get("status") == "error":
return response
try:
# 检查响应格式
if response.get("result") != 200:
error_msg = response.get('msg', response.get('message', '未知错误'))
return {"status": "error", "message": f"删除DNS记录失败: {error_msg}"}
# 返回成功结果
return {
"status": "success",
"message": "DNS记录删除成功",
"data": {
"domain": domain,
"record_id": record_id,
"host": host,
"record_type": record_type,
"value": value,
"line": line
}
}
except Exception as e:
jingrow.log_error("删除DNS记录响应解析失败", error=str(e))
return {"status": "error", "message": "删除DNS记录响应解析失败"}
@jingrow.whitelist()
@ -1955,3 +2156,146 @@ def west_upload_real_name_files(**data):
return {"status": "error", "message": "实名资料上传响应解析失败"}
@jingrow.whitelist()
def west_domain_modify_dns_record(**data):
"""修改DNS记录"""
client = get_west_client()
if not client:
return {"status": "error", "message": "API客户端初始化失败"}
domain = data.get('domain')
value = data.get('value')
ttl = data.get('ttl', 600)
level = data.get('level', 10)
record_id = data.get('record_id')
host = data.get('host')
record_type = data.get('record_type')
line = data.get('line', '')
old_value = data.get('old_value')
if not domain:
return {"status": "error", "message": "缺少域名参数"}
if not value:
return {"status": "error", "message": "缺少新的解析值"}
# 验证TTL值
if ttl < 60 or ttl > 86400:
return {"status": "error", "message": "TTL值必须在60~86400秒之间"}
# 验证优先级
if level < 1 or level > 100:
return {"status": "error", "message": "优先级必须在1~100之间"}
# 如果没有提供record_id则必须提供host和record_type
if not record_id and (not host or not record_type):
return {"status": "error", "message": "当未提供记录ID时主机头和解析类型为必填项"}
# 验证记录类型
if record_type:
valid_types = ['A', 'CNAME', 'MX', 'TXT', 'AAAA', 'SRV']
if record_type not in valid_types:
return {"status": "error", "message": f"不支持的记录类型: {record_type},支持的类型: {', '.join(valid_types)}"}
response = client.modify_dns_record(
domain, value, ttl, level, record_id, host, record_type, line, old_value
)
if response.get("status") == "error":
return response
try:
# 检查响应格式
if response.get("result") != 200:
error_msg = response.get('msg', response.get('message', '未知错误'))
return {"status": "error", "message": f"修改DNS记录失败: {error_msg}"}
# 返回成功结果
return {
"status": "success",
"message": "DNS记录修改成功",
"data": {
"domain": domain,
"value": value,
"ttl": ttl,
"level": level,
"record_id": record_id,
"host": host,
"record_type": record_type,
"line": line
}
}
except Exception as e:
jingrow.log_error("修改DNS记录响应解析失败", error=str(e))
return {"status": "error", "message": "修改DNS记录响应解析失败"}
@jingrow.whitelist()
def test_dns_record_management():
"""测试DNS记录管理功能"""
try:
# 测试参数
test_domain = "test.com"
test_host = "www"
test_value = "127.0.0.1"
test_record_type = "A"
client = get_west_client()
if not client:
return {"status": "error", "message": "API客户端初始化失败"}
# 测试1: 添加DNS记录
jingrow.log_error("DNS测试", "开始测试添加DNS记录")
add_result = client.add_dns_record(
domain=test_domain,
record_type=test_record_type,
host=test_host,
value=test_value,
ttl=900,
level=10,
line=""
)
jingrow.log_error("DNS测试", f"添加DNS记录结果: {add_result}")
# 测试2: 获取DNS记录列表
jingrow.log_error("DNS测试", "开始测试获取DNS记录列表")
list_result = client.get_dns_records_paginated(test_domain, 20, 1)
jingrow.log_error("DNS测试", f"获取DNS记录列表结果: {list_result}")
# 测试3: 修改DNS记录如果添加成功
if add_result.get("result") == 200:
record_id = add_result.get("data", {}).get("id")
if record_id:
jingrow.log_error("DNS测试", f"开始测试修改DNS记录记录ID: {record_id}")
modify_result = client.modify_dns_record(
domain=test_domain,
value="127.0.0.2",
ttl=600,
level=10,
record_id=record_id,
line=""
)
jingrow.log_error("DNS测试", f"修改DNS记录结果: {modify_result}")
# 测试4: 删除DNS记录
jingrow.log_error("DNS测试", "开始测试删除DNS记录")
delete_result = client.delete_dns_record(
domain=test_domain,
record_id=record_id
)
jingrow.log_error("DNS测试", f"删除DNS记录结果: {delete_result}")
return {
"status": "success",
"message": "DNS记录管理功能测试完成",
"data": {
"add_result": add_result,
"list_result": list_result
}
}
except Exception as e:
jingrow.log_error("DNS测试异常", str(e))
return {"status": "error", "message": f"DNS记录管理功能测试失败: {str(e)}"}