Files
resume/templates/admin/resumes.html
T

661 lines
30 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<div class="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<div class="border-b border-slate-200 px-6 py-4 bg-slate-50">
<div class="flex items-center justify-between">
<div>
<h3 class="font-semibold text-slate-800 flex items-center gap-2">
<i class="fas fa-file-alt text-purple-500"></i> 简历管理
</h3>
<p class="text-sm text-slate-500 mt-1">管理所有用户的简历</p>
</div>
<div class="flex gap-2">
<button onclick="openUploadDocumentModal()" class="btn btn-success">
<i class="fas fa-upload"></i> 上传文档生成简历
</button>
<a href="{{$.AdminPath}}/resume/add" class="btn btn-primary">
<i class="fas fa-plus"></i> 添加简历
</a>
</div>
</div>
</div>
<div class="px-6 py-4 border-b border-slate-100 bg-white">
<form id="filterForm" method="GET" action="{{$.AdminPath}}/resumes" class="flex flex-wrap items-center gap-3">
<div class="flex-1 min-w-[11.25rem]">
<input type="text" name="keyword" value="{{.FilterKeyword}}" placeholder="搜索姓名/路由..." class="w-full px-3 py-2 text-sm border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
</div>
<select name="user_id" class="px-3 py-2 text-sm border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">全部人员</option>
{{ range .Users }}
<option value="{{.ID}}" {{ if eq $.FilterUserID .ID }}selected{{ end }}>{{.Name}}{{.Username}}</option>
{{ end }}
</select>
<select name="template" class="px-3 py-2 text-sm border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">全部模板</option>
<option value="modern" {{ if eq .FilterTemplate "modern" }}selected{{ end }}>现代商务</option>
<option value="classic" {{ if eq .FilterTemplate "classic" }}selected{{ end }}>传统经典</option>
<option value="tech" {{ if eq .FilterTemplate "tech" }}selected{{ end }}>科技极客</option>
<option value="sidebar" {{ if eq .FilterTemplate "sidebar" }}selected{{ end }}>经典侧边栏</option>
<option value="elegant" {{ if eq .FilterTemplate "elegant" }}selected{{ end }}>优雅轻奢</option>
<option value="fresh" {{ if eq .FilterTemplate "fresh" }}selected{{ end }}>清新自然</option>
<option value="minimalist" {{ if eq .FilterTemplate "minimalist" }}selected{{ end }}>极简风格</option>
<option value="professional" {{ if eq .FilterTemplate "professional" }}selected{{ end }}>专业商务</option>
</select>
<select name="show_in_home" class="px-3 py-2 text-sm border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
<option value="">首页展示</option>
<option value="1" {{ if eq .FilterShowInHome "1" }}selected{{ end }}>已展示</option>
<option value="0" {{ if eq .FilterShowInHome "0" }}selected{{ end }}>未展示</option>
</select>
<button type="submit" class="btn btn-primary btn-sm">
<i class="fas fa-search"></i> 筛选
</button>
<a href="{{$.AdminPath}}/resumes" class="btn btn-secondary btn-sm">
<i class="fas fa-redo"></i> 重置
</a>
</form>
</div>
<div class="overflow-x-auto">
<table class="table">
<thead>
<tr class="bg-slate-50 border-b border-slate-200">
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600">姓名</th>
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600">职位</th>
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600">所属人员</th>
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600">访问路由</th>
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600">首页展示</th>
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600">更新时间</th>
<th class="text-left px-6 py-4 text-sm font-semibold text-slate-600 actions-col">操作</th>
</tr>
</thead>
<tbody>
{{ range .Resumes }}
<tr class="border-b border-slate-100 hover:bg-slate-50 transition-colors">
<td class="px-6 py-4">
<span class="font-medium text-slate-800">{{.BasicInfo.Name}}</span>
</td>
<td class="px-6 py-4 text-slate-600">{{.BasicInfo.Title}}</td>
<td class="px-6 py-4">
{{ if .UserID }}
{{ $user := index $.UserMap .UserID }}
{{ if $user }}
<span class="badge badge-success">{{$user.Name}}{{$user.Username}}</span>
{{ else }}
<span class="badge badge-warning">已失效</span>
{{ end }}
{{ else }}
<span class="badge badge-danger">未绑定</span>
{{ end }}
</td>
<td class="px-6 py-4 text-slate-600">/{{.Route}}</td>
<td class="px-6 py-4">
{{ if .ShowInHome }}
<span class="badge badge-success"></span>
{{ else }}
<span class="badge badge-slate"></span>
{{ end }}
</td>
<td class="px-6 py-4 text-slate-500 text-sm">{{.UpdatedAt}}</td>
<td class="px-6 py-4 actions-col">
<div class="btn-group flex-wrap gap-1">
<a href="/{{.Route}}" target="_blank" class="btn btn-info btn-xs" title="预览">
<i class="fas fa-eye"></i> 预览
</a>
{{ if .UserID }}
<a href="{{$.AdminPath}}/user/{{.UserID}}/resume/{{.ID}}/edit" class="btn btn-primary btn-xs" title="编辑">
<i class="fas fa-edit"></i> 编辑
</a>
{{ else }}
<a href="{{$.AdminPath}}/resume/{{.ID}}/edit" class="btn btn-primary btn-xs" title="编辑">
<i class="fas fa-edit"></i> 编辑
</a>
{{ end }}
<button onclick="toggleShowInHome('{{.ID}}', {{.ShowInHome}})" class="btn btn-warning btn-xs" title="{{if .ShowInHome}}取消展示{{else}}展示{{end}}">
<i class="fas fa-home"></i> {{if .ShowInHome}}取消{{else}}展示{{end}}
</button>
<button onclick="updatePassword('{{.ID}}')" class="btn btn-secondary btn-xs" title="密码">
<i class="fas fa-lock"></i> 密码
</button>
{{ if .UserID }}
<button onclick="unbindUser('{{.ID}}')" class="btn btn-orange btn-xs" title="解绑人员">
<i class="fas fa-unlink"></i> 解绑
</button>
{{ else }}
<button onclick="bindUser('{{.ID}}')" class="btn btn-success btn-xs" title="绑定人员">
<i class="fas fa-link"></i> 绑定
</button>
{{ end }}
<button onclick="deleteResume('{{.ID}}')" class="btn btn-danger btn-xs" title="删除">
<i class="fas fa-trash"></i> 删除
</button>
</div>
</td>
</tr>
{{ else }}
<tr>
<td colspan="7" class="px-6 py-12 text-center text-slate-500">
<div class="w-16 h-16 mx-auto mb-4 rounded-full bg-slate-100 flex items-center justify-center">
<i class="fas fa-file-alt text-slate-400 text-2xl"></i>
</div>
<p>暂无简历</p>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .TotalPages 1 }}
<div class="border-t border-slate-200 px-6 py-4 bg-slate-50 flex items-center justify-between">
<div class="text-sm text-slate-500">共 {{ .Total }} 条记录,第 {{ .Page }} / {{ .TotalPages }} 页</div>
<div class="flex items-center gap-2">
<a href="?page=1{{ .FilterQuery }}" class="btn btn-sm btn-slate {{ if eq .Page 1 }}opacity-50 cursor-not-allowed{{ end }}" {{ if eq .Page 1 }}onclick="return false"{{ end }}>
<i class="fas fa-chevron-left"></i>
<i class="fas fa-chevron-left"></i>
</a>
<a href="?page={{ if eq .Page 1 }}1{{ else }}{{ subtract .Page 1 }}{{ end }}{{ .FilterQuery }}" class="btn btn-sm btn-slate {{ if eq .Page 1 }}opacity-50 cursor-not-allowed{{ end }}" {{ if eq .Page 1 }}onclick="return false"{{ end }}>
<i class="fas fa-chevron-left"></i>
</a>
{{ if gt .TotalPages 7 }}
{{ if gt .Page 3 }}
<a href="?page=1{{ .FilterQuery }}" class="btn btn-sm btn-slate">1</a>
{{ if gt .Page 4 }}
<span class="text-slate-400 text-sm">...</span>
{{ end }}
{{ end }}
{{ end }}
{{ range $i := to 1 .TotalPages }}
{{ if and (ge $i (subtract $.Page 2)) (le $i (add $.Page 2)) }}
<a href="?page={{ $i }}{{ $.FilterQuery }}" class="btn btn-sm {{ if eq $i $.Page }}btn-primary{{ else }}btn-slate{{ end }}">{{ $i }}</a>
{{ end }}
{{ end }}
{{ if gt .TotalPages 7 }}
{{ if lt .Page (subtract .TotalPages 2) }}
{{ if lt .Page (subtract .TotalPages 3) }}
<span class="text-slate-400 text-sm">...</span>
{{ end }}
<a href="?page={{ .TotalPages }}{{ .FilterQuery }}" class="btn btn-sm btn-slate">{{ .TotalPages }}</a>
{{ end }}
{{ end }}
<a href="?page={{ if eq .Page .TotalPages }}{{ .TotalPages }}{{ else }}{{ add .Page 1 }}{{ end }}{{ .FilterQuery }}" class="btn btn-sm btn-slate {{ if eq .Page .TotalPages }}opacity-50 cursor-not-allowed{{ end }}" {{ if eq .Page .TotalPages }}onclick="return false"{{ end }}>
<i class="fas fa-chevron-right"></i>
</a>
<a href="?page={{ .TotalPages }}{{ .FilterQuery }}" class="btn btn-sm btn-slate {{ if eq .Page .TotalPages }}opacity-50 cursor-not-allowed{{ end }}" {{ if eq .Page .TotalPages }}onclick="return false"{{ end }}>
<i class="fas fa-chevron-right"></i>
<i class="fas fa-chevron-right"></i>
</a>
</div>
</div>
{{ end }}
</div>
<div class="modal" id="addResumeModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title" id="addResumeModalTitle">
<i class="fas fa-file-plus text-blue-500"></i> 添加简历
</h3>
<div class="modal-close" onclick="closeAddResumeModal()">
<i class="fas fa-times"></i>
</div>
</div>
<div class="modal-body">
<form id="addResumeForm" onsubmit="saveResume(event)">
<input type="hidden" id="resumeId">
<div class="space-y-4">
<div>
<label class="form-label">姓名</label>
<input type="text" id="resumeName" class="form-input" required>
</div>
<div>
<label class="form-label">职位</label>
<input type="text" id="resumeTitle" class="form-input" required>
</div>
<div>
<label class="form-label">访问路由(如 zhangsan</label>
<input type="text" id="resumeRoute" class="form-input" required>
</div>
<div>
<label class="form-label">绑定人员(可选,可后续绑定)</label>
<select id="resumeUserId" class="form-input">
<option value="">不绑定人员</option>
{{ range .Users }}
<option value="{{.ID}}">{{.Name}} - {{.Username}}</option>
{{ end }}
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button onclick="closeAddResumeModal()" class="btn btn-secondary">
<i class="fas fa-times"></i> 取消
</button>
<button type="submit" form="addResumeForm" class="btn btn-primary">
<i class="fas fa-save"></i> 保存
</button>
</div>
</div>
</div>
<div class="modal" id="bindUserModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">
<i class="fas fa-link text-green-500"></i> 绑定人员
</h3>
<div class="modal-close" onclick="closeBindUserModal()">
<i class="fas fa-times"></i>
</div>
</div>
<div class="modal-body">
<div class="mb-4">
<label class="form-label">选择要绑定的人员</label>
<select id="bindUserId" class="form-input">
{{ range .Users }}
<option value="{{.ID}}">{{.Name}} - {{.Username}}</option>
{{ end }}
</select>
</div>
</div>
<div class="modal-footer">
<button onclick="closeBindUserModal()" class="btn btn-secondary">
<i class="fas fa-times"></i> 取消
</button>
<button onclick="confirmBindUser()" class="btn btn-primary">
<i class="fas fa-check"></i> 确认绑定
</button>
</div>
</div>
</div>
<div class="modal" id="passwordModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">
<i class="fas fa-lock text-yellow-500"></i> 设置访问密码
</h3>
<div class="modal-close" onclick="closePasswordModal()">
<i class="fas fa-times"></i>
</div>
</div>
<div class="modal-body">
<div class="space-y-4">
<div>
<label class="form-label">访问密码(留空则取消密码保护)</label>
<input type="password" id="resumePassword" class="form-input" placeholder="请输入密码">
</div>
<div>
<label class="form-label">确认密码</label>
<input type="password" id="resumePasswordConfirm" class="form-input" placeholder="请再次输入密码">
</div>
</div>
</div>
<div class="modal-footer">
<button onclick="closePasswordModal()" class="btn btn-secondary">
<i class="fas fa-times"></i> 取消
</button>
<button onclick="confirmUpdatePassword()" class="btn btn-primary">
<i class="fas fa-save"></i> 保存
</button>
</div>
</div>
</div>
<div class="modal" id="uploadDocumentModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">
<i class="fas fa-upload text-green-500"></i> 上传文档生成简历
</h3>
<div class="modal-close" onclick="closeUploadDocumentModal()">
<i class="fas fa-times"></i>
</div>
</div>
<div class="modal-body">
<form id="uploadDocumentForm" enctype="multipart/form-data" onsubmit="uploadDocument(event)">
<div class="space-y-4">
<div>
<label class="form-label">选择文档</label>
<div class="border-2 border-dashed border-slate-300 rounded-lg p-8 text-center hover:border-green-500 transition-colors" id="fileDropArea">
<i class="fas fa-file-upload text-4xl text-slate-400 mb-4"></i>
<p class="text-slate-600 mb-2">点击或拖拽文件到此处</p>
<p class="text-sm text-slate-400">支持格式:PDF、DOCX、XLSX、MD、TXT</p>
<input type="file" id="documentFile" name="file" accept=".pdf,.docx,.xlsx,.md,.txt" class="hidden" onchange="handleFileSelect(this)">
</div>
<div id="selectedFileInfo" class="mt-2 hidden">
<div class="flex items-center gap-2 text-sm text-slate-600">
<i class="fas fa-file"></i>
<span id="selectedFileName"></span>
<button type="button" onclick="clearFileSelection()" class="text-red-500 hover:text-red-700">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</div>
<div>
<label class="form-label">绑定人员(可选)</label>
<select id="documentUserId" class="form-input">
<option value="">不绑定人员</option>
{{ range .Users }}
<option value="{{.ID}}">{{.Name}} - {{.Username}}</option>
{{ end }}
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button onclick="closeUploadDocumentModal()" class="btn btn-secondary">
<i class="fas fa-times"></i> 取消
</button>
<button type="submit" form="uploadDocumentForm" class="btn btn-success" id="uploadSubmitBtn">
<i class="fas fa-upload"></i> 上传生成
</button>
</div>
</div>
</div>
<script>
var currentBindResumeId = '';
var currentPasswordResumeId = '';
function openUploadDocumentModal() {
document.getElementById('uploadDocumentModal').classList.add('active');
document.getElementById('documentFile').value = '';
document.getElementById('selectedFileInfo').classList.add('hidden');
document.getElementById('selectedFileName').textContent = '';
document.getElementById('uploadSubmitBtn').disabled = false;
document.getElementById('uploadSubmitBtn').innerHTML = '<i class="fas fa-upload"></i> 上传生成';
}
function closeUploadDocumentModal() {
document.getElementById('uploadDocumentModal').classList.remove('active');
}
document.getElementById('fileDropArea').addEventListener('click', function() {
document.getElementById('documentFile').click();
});
document.getElementById('fileDropArea').addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('border-green-500');
});
document.getElementById('fileDropArea').addEventListener('dragleave', function(e) {
e.preventDefault();
this.classList.remove('border-green-500');
});
document.getElementById('fileDropArea').addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('border-green-500');
var files = e.dataTransfer.files;
if (files.length > 0) {
document.getElementById('documentFile').files = files;
handleFileSelect(document.getElementById('documentFile'));
}
});
function handleFileSelect(input) {
if (input.files.length > 0) {
var file = input.files[0];
document.getElementById('selectedFileName').textContent = file.name;
document.getElementById('selectedFileInfo').classList.remove('hidden');
}
}
function clearFileSelection() {
document.getElementById('documentFile').value = '';
document.getElementById('selectedFileInfo').classList.add('hidden');
document.getElementById('selectedFileName').textContent = '';
}
function uploadDocument(event) {
event.preventDefault();
var fileInput = document.getElementById('documentFile');
var userId = document.getElementById('documentUserId').value;
if (fileInput.files.length === 0) {
showCustomAlert('error', '错误', '请选择要上传的文件');
return;
}
var file = fileInput.files[0];
var allowedExts = ['.pdf', '.docx', '.xlsx', '.md', '.txt'];
var fileExt = file.name.toLowerCase().substring(file.name.lastIndexOf('.'));
if (!allowedExts.includes(fileExt)) {
showCustomAlert('error', '错误', '不支持的文件格式,支持:PDF、DOCX、XLSX、MD、TXT');
return;
}
var formData = new FormData();
formData.append('file', file);
if (userId) {
formData.append('user_id', userId);
}
var submitBtn = document.getElementById('uploadSubmitBtn');
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
fetch('/dashboard/api/resume/generate-from-document', {
method: 'POST',
body: formData,
credentials: 'include'
})
.then(response => {
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
return response.json();
})
.then(result => {
console.log('API Response:', result);
if (result.success) {
showCustomAlert('success', '成功', result.message || '简历生成成功!');
closeUploadDocumentModal();
setTimeout(() => location.reload(), 2000);
} else {
showCustomAlert('error', '错误', result.message || '生成失败');
}
})
.catch(error => {
console.error('Upload error:', error);
showCustomAlert('error', '错误', '上传失败: ' + error.message);
})
.finally(() => {
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="fas fa-upload"></i> 上传生成';
});
}
function openAddResumeModal() {
document.getElementById('resumeId').value = '';
document.getElementById('resumeName').value = '';
document.getElementById('resumeTitle').value = '';
document.getElementById('resumeRoute').value = '';
document.getElementById('resumeUserId').value = '';
document.getElementById('addResumeModal').classList.add('active');
}
function closeAddResumeModal() {
document.getElementById('addResumeModal').classList.remove('active');
}
function saveResume(event) {
event.preventDefault();
const id = document.getElementById('resumeId').value;
const name = document.getElementById('resumeName').value;
const title = document.getElementById('resumeTitle').value;
const route = document.getElementById('resumeRoute').value;
const userId = document.getElementById('resumeUserId').value;
if (!name || !title || !route) {
showCustomAlert('error', '错误', '请填写完整信息');
return;
}
fetch('/dashboard/api/resume/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
user_id: userId,
route: route,
basic_info: {
name: name,
title: title
}
})
})
.then(response => response.json())
.then(result => {
if (result.success) {
showCustomAlert('success', '成功', '添加成功');
closeAddResumeModal();
setTimeout(() => location.reload(), 1500);
} else {
showCustomAlert('error', '错误', '添加失败:' + (result.message || '未知错误'));
}
})
.catch(() => {
showCustomAlert('error', '错误', '添加失败');
});
}
function bindUser(resumeId) {
currentBindResumeId = resumeId;
document.getElementById('bindUserModal').classList.add('active');
}
function closeBindUserModal() {
document.getElementById('bindUserModal').classList.remove('active');
currentBindResumeId = '';
}
function confirmBindUser() {
const userId = document.getElementById('bindUserId').value;
if (!userId) {
showCustomAlert('error', '错误', '请选择要绑定的人员');
return;
}
fetch('/dashboard/api/resume/' + currentBindResumeId + '/user', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: userId })
})
.then(response => response.json())
.then(result => {
if (result.success) {
showCustomAlert('success', '成功', '绑定成功');
closeBindUserModal();
setTimeout(() => location.reload(), 1500);
} else {
showCustomAlert('error', '错误', '绑定失败:' + (result.message || '未知错误'));
}
})
.catch(() => {
showCustomAlert('error', '错误', '绑定失败');
});
}
function unbindUser(resumeId) {
showCustomConfirm('确认解绑', '确定要解绑该简历与人员的关联吗?', function(confirmed) {
if (!confirmed) return;
fetch('/dashboard/api/resume/' + resumeId + '/user', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_id: '' })
})
.then(response => response.json())
.then(result => {
if (result.success) {
showCustomAlert('success', '成功', '解绑成功');
setTimeout(() => location.reload(), 1500);
} else {
showCustomAlert('error', '错误', '解绑失败:' + (result.message || '未知错误'));
}
})
.catch(() => {
showCustomAlert('error', '错误', '解绑失败');
});
});
}
function toggleShowInHome(resumeId, currentState) {
fetch('/dashboard/api/resume/' + resumeId + '/show_in_home', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ show_in_home: !currentState })
})
.then(response => response.json())
.then(result => {
if (result.success !== undefined) {
showCustomAlert('success', '成功', currentState ? '已取消首页展示' : '已设置首页展示');
setTimeout(() => location.reload(), 1500);
} else {
showCustomAlert('error', '错误', '操作失败');
}
})
.catch(() => {
showCustomAlert('error', '错误', '操作失败');
});
}
function updatePassword(resumeId) {
currentPasswordResumeId = resumeId;
document.getElementById('resumePassword').value = '';
document.getElementById('resumePasswordConfirm').value = '';
document.getElementById('passwordModal').classList.add('active');
}
function closePasswordModal() {
document.getElementById('passwordModal').classList.remove('active');
currentPasswordResumeId = '';
}
function confirmUpdatePassword() {
const password = document.getElementById('resumePassword').value;
const confirmPassword = document.getElementById('resumePasswordConfirm').value;
if (password !== confirmPassword) {
showCustomAlert('error', '错误', '两次输入的密码不一致');
return;
}
fetch('/dashboard/api/resume/' + currentPasswordResumeId + '/password', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password: password })
})
.then(response => response.json())
.then(result => {
if (result.success) {
showCustomAlert('success', '成功', password ? '密码设置成功' : '密码已取消');
closePasswordModal();
} else {
showCustomAlert('error', '错误', '设置失败:' + (result.message || '未知错误'));
}
})
.catch(() => {
showCustomAlert('error', '错误', '设置失败');
});
}
function deleteResume(resumeId) {
showCustomConfirm('确认删除', '确定要删除该简历吗?此操作不可恢复。', function(confirmed) {
if (!confirmed) return;
fetch('/dashboard/api/resume/' + resumeId, {
method: 'DELETE'
})
.then(response => response.json())
.then(result => {
if (result.success) {
showCustomAlert('success', '成功', '删除成功');
setTimeout(() => location.reload(), 1500);
} else {
showCustomAlert('error', '错误', '删除失败:' + (result.message || '未知错误'));
}
})
.catch(() => {
showCustomAlert('error', '错误', '删除失败');
});
});
}
</script>