增加批量删除DNS记录的api端点及实现前端批量删除功能并测试通过
This commit is contained in:
parent
24b2e99019
commit
41412190ef
@ -16,6 +16,16 @@
|
||||
<RefreshCwIcon class="h-4 w-4 mr-1" />
|
||||
刷新
|
||||
</Button>
|
||||
<Button
|
||||
v-if="selectedRecords.length > 0"
|
||||
@click="batchDeleteRecords"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="text-red-600 hover:text-red-700"
|
||||
>
|
||||
<Trash2Icon class="h-4 w-4 mr-1" />
|
||||
删除选中 ({{ selectedRecords.length }})
|
||||
</Button>
|
||||
<Button
|
||||
@click="addNewRow"
|
||||
variant="solid"
|
||||
@ -53,7 +63,13 @@
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<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" />
|
||||
<input
|
||||
type="checkbox"
|
||||
class="rounded border-gray-300"
|
||||
:checked="isAllSelected"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="toggleSelectAll"
|
||||
/>
|
||||
</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
||||
编号
|
||||
@ -88,7 +104,13 @@
|
||||
<!-- 现有记录 -->
|
||||
<tr v-for="(record, index) in dnsRecords" :key="record.id || `temp-${index}`" class="hover:bg-gray-50">
|
||||
<td class="px-4 py-4 whitespace-nowrap">
|
||||
<input type="checkbox" class="rounded border-gray-300" />
|
||||
<input
|
||||
type="checkbox"
|
||||
class="rounded border-gray-300"
|
||||
:checked="selectedRecords.includes(String(record.id))"
|
||||
@change="toggleRecordSelection(record.id)"
|
||||
:disabled="record.isNew"
|
||||
/>
|
||||
</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||
{{ index + 1 }}
|
||||
@ -250,26 +272,8 @@
|
||||
</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 v-if="pagination.total > pagination.limit" class="flex flex-col items-center space-y-4">
|
||||
<div class="text-sm text-gray-700">
|
||||
显示第 {{ (pagination.pageno - 1) * pagination.limit + 1 }} -
|
||||
{{ Math.min(pagination.pageno * pagination.limit, pagination.total) }} 条,
|
||||
@ -281,19 +285,34 @@
|
||||
:disabled="pagination.pageno <= 1"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="px-3"
|
||||
>
|
||||
上一页
|
||||
←
|
||||
</Button>
|
||||
<span class="text-sm text-gray-700">
|
||||
{{ pagination.pageno }} / {{ pagination.pagecount }}
|
||||
</span>
|
||||
<div class="flex items-center space-x-1">
|
||||
<Button
|
||||
v-for="page in getVisiblePages()"
|
||||
:key="page"
|
||||
@click="changePage(page)"
|
||||
:class="[
|
||||
'px-3 py-1 text-sm rounded',
|
||||
page === pagination.pageno
|
||||
? '!bg-[#1fc76f] text-white'
|
||||
: 'bg-white text-gray-700 border border-gray-300 hover:bg-gray-50'
|
||||
]"
|
||||
:disabled="page === pagination.pageno"
|
||||
>
|
||||
{{ page }}
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
@click="changePage(pagination.pageno + 1)"
|
||||
:disabled="pagination.pageno >= pagination.pagecount"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
class="px-3"
|
||||
>
|
||||
下一页
|
||||
→
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -338,10 +357,11 @@ export default {
|
||||
dnsRecords: [],
|
||||
pagination: {
|
||||
pageno: 1,
|
||||
limit: 20,
|
||||
limit: 5,
|
||||
total: 0,
|
||||
pagecount: 0
|
||||
}
|
||||
},
|
||||
selectedRecords: [] // 用于存储选中的记录ID
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@ -553,8 +573,9 @@ export default {
|
||||
title: '删除DNS记录',
|
||||
message: `确定要删除这条DNS记录吗?\n类型: ${record.type}\n主机记录: ${record.item}\n记录值: ${record.value}`,
|
||||
primaryAction: {
|
||||
label: '删除',
|
||||
variant: 'danger',
|
||||
label: '确定',
|
||||
variant: 'solid',
|
||||
class: 'bg-black text-white hover:bg-gray-800',
|
||||
onClick: ({ hide }) => {
|
||||
this.performDeleteRecord(record, hide);
|
||||
}
|
||||
@ -589,11 +610,148 @@ export default {
|
||||
toast.error('删除DNS记录失败');
|
||||
console.error('删除DNS记录失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 批量删除记录
|
||||
async batchDeleteRecords() {
|
||||
if (this.selectedRecords.length === 0) {
|
||||
toast.info('请选择要删除的记录');
|
||||
return;
|
||||
}
|
||||
|
||||
confirmDialog({
|
||||
title: '批量删除DNS记录',
|
||||
message: `确定要删除选中的 ${this.selectedRecords.length} 条DNS记录吗?`,
|
||||
primaryAction: {
|
||||
label: '确定',
|
||||
variant: 'solid',
|
||||
class: 'bg-black text-white hover:bg-gray-800',
|
||||
onClick: ({ hide }) => {
|
||||
this.performBatchDeleteRecords(this.selectedRecords, hide);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 执行批量删除记录
|
||||
async performBatchDeleteRecords(recordIds, hide) {
|
||||
// 过滤出有效的记录ID
|
||||
const validRecordIds = recordIds
|
||||
.filter(id => id)
|
||||
.map(id => String(id))
|
||||
.filter(id => !id.startsWith('temp-'));
|
||||
|
||||
if (validRecordIds.length === 0) {
|
||||
toast.error('没有有效的记录可以删除');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const request = createResource({
|
||||
url: 'jcloud.api.domain_west.west_domain_delete_dns_records',
|
||||
params: {
|
||||
domain: this.$domain.pg.domain,
|
||||
record_ids: validRecordIds
|
||||
},
|
||||
onSuccess: (response) => {
|
||||
if (response.status === 'success') {
|
||||
toast.success(response.message || `批量删除 ${validRecordIds.length} 条DNS记录成功`);
|
||||
hide();
|
||||
this.loadDNSRecords();
|
||||
this.selectedRecords = []; // 清空选中
|
||||
} else if (response.status === 'partial_success') {
|
||||
toast.success(response.message || '批量删除部分成功');
|
||||
hide();
|
||||
this.loadDNSRecords();
|
||||
this.selectedRecords = []; // 清空选中
|
||||
} else {
|
||||
toast.error(response.message || '批量删除DNS记录失败');
|
||||
}
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(getToastErrorMessage(error));
|
||||
}
|
||||
});
|
||||
request.submit();
|
||||
} catch (error) {
|
||||
toast.error('批量删除DNS记录失败');
|
||||
console.error('批量删除DNS记录失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 切换记录选中状态
|
||||
toggleRecordSelection(recordId) {
|
||||
// 只允许选择有效的记录ID(排除新增记录和空ID)
|
||||
if (!recordId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保recordId是字符串类型
|
||||
const recordIdStr = String(recordId);
|
||||
if (recordIdStr.startsWith('temp-')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = this.selectedRecords.indexOf(recordIdStr);
|
||||
if (index > -1) {
|
||||
this.selectedRecords.splice(index, 1);
|
||||
} else {
|
||||
this.selectedRecords.push(recordIdStr);
|
||||
}
|
||||
},
|
||||
|
||||
// 全选/取消全选
|
||||
toggleSelectAll(event) {
|
||||
const checkbox = event.target;
|
||||
if (checkbox.checked) {
|
||||
// 只选择有真实ID的记录(排除新增的记录)
|
||||
this.selectedRecords = this.dnsRecords
|
||||
.filter(record => record.id && !record.isNew)
|
||||
.map(record => String(record.id));
|
||||
} else {
|
||||
this.selectedRecords = [];
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
// 获取可见的页码
|
||||
getVisiblePages() {
|
||||
const current = this.pagination.pageno;
|
||||
const total = this.pagination.pagecount;
|
||||
const pages = [];
|
||||
|
||||
// 如果总页数小于等于5,显示所有页码
|
||||
if (total <= 5) {
|
||||
for (let i = 1; i <= total; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
} else {
|
||||
// 显示当前页附近的页码
|
||||
const start = Math.max(1, current - 2);
|
||||
const end = Math.min(total, current + 2);
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
return pages;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
$domain() {
|
||||
return getCachedDocumentResource('Jsite Domain', this.domain);
|
||||
},
|
||||
|
||||
// 判断是否全选
|
||||
isAllSelected() {
|
||||
return this.dnsRecords.length > 0 && this.selectedRecords.length === this.dnsRecords.length;
|
||||
},
|
||||
|
||||
// 判断是否半选
|
||||
isIndeterminate() {
|
||||
return this.selectedRecords.length > 0 && this.selectedRecords.length < this.dnsRecords.length;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@ -1097,21 +1097,92 @@ def west_domain_delete_dns_record(**data):
|
||||
# 返回成功结果
|
||||
return {
|
||||
"status": "success",
|
||||
"message": "DNS记录删除成功",
|
||||
"data": {
|
||||
"domain": domain,
|
||||
"record_id": record_id,
|
||||
"host": host,
|
||||
"record_type": record_type,
|
||||
"value": value,
|
||||
"line": line
|
||||
}
|
||||
"message": "DNS记录删除成功"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": "删除DNS记录响应解析失败"}
|
||||
|
||||
|
||||
@jingrow.whitelist()
|
||||
def west_domain_delete_dns_records(**data):
|
||||
"""批量删除DNS记录"""
|
||||
client = get_west_client()
|
||||
if not client:
|
||||
return {"status": "error", "message": "API客户端初始化失败"}
|
||||
|
||||
domain = data.get('domain')
|
||||
record_ids = data.get('record_ids')
|
||||
|
||||
if not domain:
|
||||
return {"status": "error", "message": "缺少域名参数"}
|
||||
|
||||
if not record_ids:
|
||||
return {"status": "error", "message": "缺少记录ID列表"}
|
||||
|
||||
# 处理record_ids参数,支持字符串和列表格式
|
||||
if isinstance(record_ids, str):
|
||||
# 如果是逗号分隔的字符串,转换为列表
|
||||
record_ids = [rid.strip() for rid in record_ids.split(',') if rid.strip()]
|
||||
elif not isinstance(record_ids, list):
|
||||
return {"status": "error", "message": "记录ID列表格式错误"}
|
||||
|
||||
if not record_ids:
|
||||
return {"status": "error", "message": "记录ID列表不能为空"}
|
||||
|
||||
# 验证记录ID格式
|
||||
for record_id in record_ids:
|
||||
if not record_id or not isinstance(record_id, str):
|
||||
return {"status": "error", "message": "记录ID格式错误"}
|
||||
|
||||
# 批量删除逻辑
|
||||
results = []
|
||||
success_count = 0
|
||||
error_count = 0
|
||||
|
||||
for record_id in record_ids:
|
||||
try:
|
||||
result = client.delete_dns_record(domain, record_id)
|
||||
if result.get("status") == "error" or result.get("result") != 200:
|
||||
error_count += 1
|
||||
error_msg = result.get('msg', result.get('message', '删除失败'))
|
||||
results.append({
|
||||
"record_id": record_id,
|
||||
"status": "error",
|
||||
"message": error_msg
|
||||
})
|
||||
else:
|
||||
success_count += 1
|
||||
results.append({
|
||||
"record_id": record_id,
|
||||
"status": "success"
|
||||
})
|
||||
except Exception as e:
|
||||
error_count += 1
|
||||
results.append({
|
||||
"record_id": record_id,
|
||||
"status": "error",
|
||||
"message": str(e)
|
||||
})
|
||||
|
||||
# 返回批量删除结果
|
||||
if error_count == 0:
|
||||
return {
|
||||
"status": "success",
|
||||
"message": f"批量删除成功,共删除 {success_count} 条记录"
|
||||
}
|
||||
elif success_count == 0:
|
||||
return {
|
||||
"status": "error",
|
||||
"message": f"批量删除失败,共 {error_count} 条记录删除失败"
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"status": "partial_success",
|
||||
"message": f"批量删除部分成功,成功 {success_count} 条,失败 {error_count} 条"
|
||||
}
|
||||
|
||||
|
||||
@jingrow.whitelist()
|
||||
def west_domain_transfer(**data):
|
||||
"""域名转入"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user