main #2

Merged
jingrow merged 250 commits from main into v1 2026-01-13 22:45:50 +08:00
2 changed files with 268 additions and 39 deletions
Showing only changes of commit 41412190ef - Show all commits

View File

@ -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) {
// IDID
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() {

View File

@ -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):
"""域名转入"""