首次提交:初始化项目代码
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h3 class="font-semibold text-slate-800 flex items-center gap-2">
|
||||
<i class="fas fa-users text-purple-500"></i> 人员列表
|
||||
</h3>
|
||||
<p class="text-sm text-slate-500 mt-1">管理平台用户</p>
|
||||
</div>
|
||||
<button onclick="openAddUserModal()" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> 添加用户
|
||||
</button>
|
||||
</div>
|
||||
<div class="mb-6 flex items-center gap-4">
|
||||
<div class="relative flex-1 max-w-md">
|
||||
<div class="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400">
|
||||
<i class="fas fa-search"></i>
|
||||
</div>
|
||||
<input type="text" id="searchInput" placeholder="搜索姓名或用户名..." class="w-full pl-10 pr-4 py-2.5 border-2 border-slate-200 rounded-xl focus:ring-2 focus:ring-purple-500 focus:border-purple-500 transition-all bg-white">
|
||||
</div>
|
||||
<button onclick="filterUsers()" class="btn btn-secondary">
|
||||
<i class="fas fa-search"></i> 搜索
|
||||
</button>
|
||||
<button onclick="location.reload()" class="btn btn-secondary">
|
||||
<i class="fas fa-redo"></i> 重置
|
||||
</button>
|
||||
</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 actions-col">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Users }}
|
||||
<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">{{.Name}}</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-slate-600">{{.Username}}</td>
|
||||
<td class="px-6 py-4 text-slate-600">{{.Email}}</td>
|
||||
<td class="px-6 py-4 text-slate-600">{{.Phone}}</td>
|
||||
<td class="px-6 py-4 text-slate-500 text-sm">{{.CreatedAt}}</td>
|
||||
<td class="px-6 py-4 actions-col">
|
||||
<div class="btn-group">
|
||||
<a href="{{$.AdminPath}}/user/{{.ID}}/resume" class="btn btn-primary btn-xs" title="简历">
|
||||
<i class="fas fa-file-alt"></i> 简历
|
||||
</a>
|
||||
<a href="{{$.AdminPath}}/user/{{.ID}}/portfolio" class="btn btn-info btn-xs" title="作品集">
|
||||
<i class="fas fa-folder-open"></i> 作品集
|
||||
</a>
|
||||
<a href="{{$.AdminPath}}/user/{{.ID}}/quiz" class="btn btn-purple btn-xs" title="面试题">
|
||||
<i class="fas fa-question-circle"></i> 答题
|
||||
</a>
|
||||
<button onclick="editUser('{{.ID}}')" class="btn btn-warning btn-xs" title="编辑">
|
||||
<i class="fas fa-edit"></i> 编辑
|
||||
</button>
|
||||
<button onclick="deleteUser('{{.ID}}')" class="btn btn-danger btn-xs" title="删除">
|
||||
<i class="fas fa-trash"></i> 删除
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{ else }}
|
||||
<tr>
|
||||
<td colspan="6" 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-users 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" 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 }}" 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>
|
||||
{{ range $i := to 1 $.TotalPages }}
|
||||
{{ if or (eq $i 1) (eq $i $.TotalPages) (and (ge $i (subtract $.Page 2)) (le $i (add $.Page 2))) }}
|
||||
<a href="?page={{ $i }}" class="btn btn-sm {{ if eq $i $.Page }}btn-primary{{ else }}btn-slate{{ end }}">{{ $i }}</a>
|
||||
{{ else if and (eq $i 2) (gt (subtract $.Page 3) 1) }}
|
||||
<span class="text-slate-400 px-2">...</span>
|
||||
{{ else if and (eq $i (subtract $.TotalPages 1)) (lt (add $.Page 3) $.TotalPages) }}
|
||||
<span class="text-slate-400 px-2">...</span>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<a href="?page={{ if eq .Page .TotalPages }}{{ .TotalPages }}{{ else }}{{ add .Page 1 }}{{ end }}" 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 }}" 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="userModal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title" id="userModalTitle">
|
||||
<i class="fas fa-user-plus text-blue-500"></i> 添加用户
|
||||
</h3>
|
||||
<div class="modal-close" onclick="closeUserModal()">
|
||||
<i class="fas fa-times"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="userForm" onsubmit="saveUser(event)">
|
||||
<input type="hidden" id="userId">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="form-label">姓名</label>
|
||||
<input type="text" id="userName" class="form-input" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">用户名</label>
|
||||
<input type="text" id="userUsername" class="form-input" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">邮箱</label>
|
||||
<input type="email" id="userEmail" class="form-input" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">手机号</label>
|
||||
<input type="tel" id="userPhone" class="form-input">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button onclick="closeUserModal()" class="btn btn-secondary">
|
||||
<i class="fas fa-times"></i> 取消
|
||||
</button>
|
||||
<button type="submit" form="userForm" class="btn btn-primary">
|
||||
<i class="fas fa-save"></i> 保存
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
function filterUsers() {
|
||||
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
|
||||
const rows = document.querySelectorAll('table tbody tr');
|
||||
rows.forEach(row => {
|
||||
const name = row.querySelector('td:nth-child(1)')?.textContent.toLowerCase() || '';
|
||||
const username = row.querySelector('td:nth-child(2)')?.textContent.toLowerCase() || '';
|
||||
const email = row.querySelector('td:nth-child(3)')?.textContent.toLowerCase() || '';
|
||||
const phone = row.querySelector('td:nth-child(4)')?.textContent.toLowerCase() || '';
|
||||
if (name.includes(searchTerm) || username.includes(searchTerm) || email.includes(searchTerm) || phone.includes(searchTerm)) {
|
||||
row.style.display = '';
|
||||
} else {
|
||||
row.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openAddUserModal() {
|
||||
document.getElementById('userModalTitle').innerHTML = '<i class="fas fa-user-plus text-blue-500"></i> 添加用户';
|
||||
document.getElementById('userId').value = '';
|
||||
document.getElementById('userName').value = '';
|
||||
document.getElementById('userUsername').value = '';
|
||||
document.getElementById('userEmail').value = '';
|
||||
document.getElementById('userPhone').value = '';
|
||||
document.getElementById('userModal').classList.add('active');
|
||||
}
|
||||
|
||||
function closeUserModal() {
|
||||
document.getElementById('userModal').classList.remove('active');
|
||||
}
|
||||
|
||||
function editUser(id) {
|
||||
fetch('/dashboard/api/user/' + id)
|
||||
.then(response => response.json())
|
||||
.then(res => {
|
||||
const user = res.data || res;
|
||||
document.getElementById('userModalTitle').innerHTML = '<i class="fas fa-user-edit text-yellow-500"></i> 编辑用户';
|
||||
document.getElementById('userId').value = user.id || '';
|
||||
document.getElementById('userName').value = user.name || '';
|
||||
document.getElementById('userUsername').value = user.username || '';
|
||||
document.getElementById('userEmail').value = user.email || '';
|
||||
document.getElementById('userPhone').value = user.phone || '';
|
||||
document.getElementById('userModal').classList.add('active');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showCustomAlert('error', '错误', '获取用户信息失败');
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUser(id) {
|
||||
showCustomConfirm('确认删除', '确定要删除该用户吗?', function(confirmed) {
|
||||
if (!confirmed) return;
|
||||
fetch('/dashboard/api/user/' + id, { method: 'DELETE' })
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
showCustomAlert('error', '错误', '删除失败:' + (result.message || '未知错误'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showCustomAlert('error', '错误', '删除失败');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function saveUser(event) {
|
||||
event.preventDefault();
|
||||
const id = document.getElementById('userId').value;
|
||||
const data = {
|
||||
name: document.getElementById('userName').value,
|
||||
username: document.getElementById('userUsername').value,
|
||||
email: document.getElementById('userEmail').value,
|
||||
phone: document.getElementById('userPhone').value
|
||||
};
|
||||
|
||||
const url = id ? '/dashboard/api/user/' + id : '/dashboard/api/user';
|
||||
const method = id ? 'PUT' : 'POST';
|
||||
|
||||
fetch(url, {
|
||||
method: method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
showCustomAlert('success', '成功', '保存成功');
|
||||
closeUserModal();
|
||||
setTimeout(() => location.reload(), 1500);
|
||||
} else {
|
||||
showCustomAlert('error', '错误', '保存失败:' + (result.message || '未知错误'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showCustomAlert('error', '错误', '保存失败');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user