增加批量删除DNS记录的api端点及实现前端批量删除功能并测试通过
This commit is contained in:
parent
24b2e99019
commit
41412190ef
@ -16,6 +16,16 @@
|
|||||||
<RefreshCwIcon class="h-4 w-4 mr-1" />
|
<RefreshCwIcon class="h-4 w-4 mr-1" />
|
||||||
刷新
|
刷新
|
||||||
</Button>
|
</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
|
<Button
|
||||||
@click="addNewRow"
|
@click="addNewRow"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
@ -53,7 +63,13 @@
|
|||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 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" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="rounded border-gray-300"
|
||||||
|
:checked="isAllSelected"
|
||||||
|
:indeterminate="isIndeterminate"
|
||||||
|
@change="toggleSelectAll"
|
||||||
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th class="px-4 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">
|
||||||
编号
|
编号
|
||||||
@ -88,7 +104,13 @@
|
|||||||
<!-- 现有记录 -->
|
<!-- 现有记录 -->
|
||||||
<tr v-for="(record, index) in dnsRecords" :key="record.id || `temp-${index}`" class="hover:bg-gray-50">
|
<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">
|
<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>
|
||||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-900">
|
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
{{ index + 1 }}
|
{{ index + 1 }}
|
||||||
@ -250,26 +272,8 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</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">
|
<div class="text-sm text-gray-700">
|
||||||
显示第 {{ (pagination.pageno - 1) * pagination.limit + 1 }} -
|
显示第 {{ (pagination.pageno - 1) * pagination.limit + 1 }} -
|
||||||
{{ Math.min(pagination.pageno * pagination.limit, pagination.total) }} 条,
|
{{ Math.min(pagination.pageno * pagination.limit, pagination.total) }} 条,
|
||||||
@ -281,19 +285,34 @@
|
|||||||
:disabled="pagination.pageno <= 1"
|
:disabled="pagination.pageno <= 1"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
class="px-3"
|
||||||
>
|
>
|
||||||
上一页
|
←
|
||||||
</Button>
|
</Button>
|
||||||
<span class="text-sm text-gray-700">
|
<div class="flex items-center space-x-1">
|
||||||
{{ pagination.pageno }} / {{ pagination.pagecount }}
|
<Button
|
||||||
</span>
|
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
|
<Button
|
||||||
@click="changePage(pagination.pageno + 1)"
|
@click="changePage(pagination.pageno + 1)"
|
||||||
:disabled="pagination.pageno >= pagination.pagecount"
|
:disabled="pagination.pageno >= pagination.pagecount"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
class="px-3"
|
||||||
>
|
>
|
||||||
下一页
|
→
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -338,10 +357,11 @@ export default {
|
|||||||
dnsRecords: [],
|
dnsRecords: [],
|
||||||
pagination: {
|
pagination: {
|
||||||
pageno: 1,
|
pageno: 1,
|
||||||
limit: 20,
|
limit: 5,
|
||||||
total: 0,
|
total: 0,
|
||||||
pagecount: 0
|
pagecount: 0
|
||||||
}
|
},
|
||||||
|
selectedRecords: [] // 用于存储选中的记录ID
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -553,8 +573,9 @@ export default {
|
|||||||
title: '删除DNS记录',
|
title: '删除DNS记录',
|
||||||
message: `确定要删除这条DNS记录吗?\n类型: ${record.type}\n主机记录: ${record.item}\n记录值: ${record.value}`,
|
message: `确定要删除这条DNS记录吗?\n类型: ${record.type}\n主机记录: ${record.item}\n记录值: ${record.value}`,
|
||||||
primaryAction: {
|
primaryAction: {
|
||||||
label: '删除',
|
label: '确定',
|
||||||
variant: 'danger',
|
variant: 'solid',
|
||||||
|
class: 'bg-black text-white hover:bg-gray-800',
|
||||||
onClick: ({ hide }) => {
|
onClick: ({ hide }) => {
|
||||||
this.performDeleteRecord(record, hide);
|
this.performDeleteRecord(record, hide);
|
||||||
}
|
}
|
||||||
@ -589,11 +610,148 @@ export default {
|
|||||||
toast.error('删除DNS记录失败');
|
toast.error('删除DNS记录失败');
|
||||||
console.error('删除DNS记录失败:', error);
|
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: {
|
computed: {
|
||||||
$domain() {
|
$domain() {
|
||||||
return getCachedDocumentResource('Jsite Domain', this.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() {
|
mounted() {
|
||||||
|
|||||||
@ -1097,21 +1097,92 @@ def west_domain_delete_dns_record(**data):
|
|||||||
# 返回成功结果
|
# 返回成功结果
|
||||||
return {
|
return {
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"message": "DNS记录删除成功",
|
"message": "DNS记录删除成功"
|
||||||
"data": {
|
|
||||||
"domain": domain,
|
|
||||||
"record_id": record_id,
|
|
||||||
"host": host,
|
|
||||||
"record_type": record_type,
|
|
||||||
"value": value,
|
|
||||||
"line": line
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {"status": "error", "message": "删除DNS记录响应解析失败"}
|
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()
|
@jingrow.whitelist()
|
||||||
def west_domain_transfer(**data):
|
def west_domain_transfer(**data):
|
||||||
"""域名转入"""
|
"""域名转入"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user