新增客户端管理功能,包括创建、编辑和删除客户端的API,更新用户管理功能,添加用户创建和编辑页面,优化管理员功能,增强用户和客户端的管理体验。
This commit is contained in:
@@ -1,38 +1,281 @@
|
||||
{{template "header" .}}
|
||||
<div class="container mt-4">
|
||||
<h2>客户端管理</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>客户端ID</th>
|
||||
<th>名称</th>
|
||||
<th>创建时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .clients}}
|
||||
<tr>
|
||||
<td>{{.ID}}</td>
|
||||
<td>{{.ClientID}}</td>
|
||||
<td>{{.Name}}</td>
|
||||
<td>{{.CreatedAt.Format "2006-01-02 15:04:05"}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2 class="text-dark">
|
||||
<i class="bi bi-grid-3x3-gap-fill me-2"></i>客户端管理
|
||||
</h2>
|
||||
<button type="button" class="btn btn-primary px-4 py-2 d-flex align-items-center" data-bs-toggle="modal" data-bs-target="#newClientModal">
|
||||
<i class="bi bi-plus-lg me-2"></i>新建客户端
|
||||
</button>
|
||||
</div>
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="bg-light">
|
||||
<tr>
|
||||
<th class="px-4" style="width: 20%">客户端ID</th>
|
||||
<th class="px-4" style="width: 20%">客户端密钥</th>
|
||||
<th class="px-4" style="width: 10%">名称</th>
|
||||
<th class="px-4" style="width: 30%">重定向URI</th>
|
||||
<th class="px-4" style="width: 12%">创建时间</th>
|
||||
<th class="px-4 text-end" style="width: 8%">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .clients}}
|
||||
<tr>
|
||||
<td class="px-4 align-middle text-truncate" title="{{.ClientID}}">{{.ClientID}}</td>
|
||||
<td class="px-4 align-middle text-truncate" title="{{.ClientSecret}}">{{.ClientSecret}}</td>
|
||||
<td class="px-4 align-middle text-truncate" title="{{.ClientName}}">{{.ClientName}}</td>
|
||||
<td class="px-4 align-middle">
|
||||
<div class="text-truncate" title="{{range $i, $uri := .RedirectURIs}}{{if $i}}, {{end}}{{$uri}}{{end}}">
|
||||
{{range $i, $uri := .RedirectURIs}}{{if $i}}, {{end}}{{$uri}}{{end}}
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-4 align-middle">{{.ClientIDIssuedAt.Format "2006-01-02 15:04:05"}}</td>
|
||||
<td class="px-4 align-middle text-end">
|
||||
{{$redirectURIsStr := ""}}
|
||||
{{range $i, $uri := .RedirectURIs}}
|
||||
{{if $i}}
|
||||
{{$redirectURIsStr = printf "%s,%s" $redirectURIsStr $uri}}
|
||||
{{else}}
|
||||
{{$redirectURIsStr = $uri}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#editClientModal"
|
||||
data-client-id="{{.ClientID}}"
|
||||
data-client-name="{{.ClientName}}"
|
||||
data-redirect-uris="{{$redirectURIsStr}}">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm" onclick="deleteClient('{{.ClientID}}')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<ul class="pagination">
|
||||
<nav class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{{if gt .page 1}}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{subtract .page 1}}&page_size={{.pageSize}}">上一页</a>
|
||||
<a class="page-link" href="?page={{subtract .page 1}}&page_size={{.pageSize}}">
|
||||
<i class="bi bi-chevron-left"></i>
|
||||
</a>
|
||||
</li>
|
||||
{{end}}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{add .page 1}}&page_size={{.pageSize}}">下一页</a>
|
||||
<a class="page-link" href="?page={{add .page 1}}&page_size={{.pageSize}}">
|
||||
<i class="bi bi-chevron-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- 新建客户端模态框 -->
|
||||
<div class="modal fade" id="newClientModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-bottom-0">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-plus-circle me-2"></i>新建客户端
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body px-4">
|
||||
<form id="newClientForm">
|
||||
<div class="mb-4">
|
||||
<label for="newClientName" class="form-label">名称</label>
|
||||
<input type="text" class="form-control" id="newClientName" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="newRedirectURIs" class="form-label">重定向URI</label>
|
||||
<textarea class="form-control" id="newRedirectURIs" rows="3" required></textarea>
|
||||
<div class="form-text text-muted">每行一个URI,或用逗号分隔多个URI</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer border-top-0">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary px-4" onclick="createClient()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑客户端模态框 -->
|
||||
<div class="modal fade" id="editClientModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-bottom-0">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-pencil-square me-2"></i>编辑客户端
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body px-4">
|
||||
<form id="editClientForm">
|
||||
<input type="hidden" id="editClientID">
|
||||
<div class="mb-4">
|
||||
<label for="editClientName" class="form-label">名称</label>
|
||||
<input type="text" class="form-control" id="editClientName" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="editRedirectURIs" class="form-label">重定向URI</label>
|
||||
<textarea class="form-control" id="editRedirectURIs" rows="3" required></textarea>
|
||||
<div class="form-text text-muted">每行一个URI,或用逗号分隔多个URI</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer border-top-0">
|
||||
<button type="button" class="btn btn-light" data-bs-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary px-4" onclick="updateClient()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.table th {
|
||||
font-weight: 600;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
.table td {
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
max-width: 0;
|
||||
}
|
||||
.text-truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
}
|
||||
.btn-group .btn {
|
||||
padding: 0.375rem 0.75rem;
|
||||
}
|
||||
.modal-dialog {
|
||||
max-width: 500px;
|
||||
}
|
||||
.form-control:focus {
|
||||
border-color: #80bdff;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
|
||||
}
|
||||
.card {
|
||||
border-radius: 0.5rem;
|
||||
border: none;
|
||||
}
|
||||
.page-link {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.25rem;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
.page-link:hover {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
.btn-group .btn i {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// 创建新客户端
|
||||
function createClient() {
|
||||
const clientName = document.getElementById('newClientName').value;
|
||||
const redirectURIs = document.getElementById('newRedirectURIs').value
|
||||
.split(/[\n,]/)
|
||||
.map(uri => uri.trim())
|
||||
.filter(uri => uri.length > 0);
|
||||
|
||||
fetch('/api/clients', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_name: clientName,
|
||||
redirect_uris: redirectURIs,
|
||||
token_endpoint_auth_method: 'client_secret_basic',
|
||||
grant_types: ['authorization_code'],
|
||||
response_types: ['code']
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('创建失败,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑客户端模态框数据填充
|
||||
document.getElementById('editClientModal').addEventListener('show.bs.modal', function (event) {
|
||||
const button = event.relatedTarget;
|
||||
const clientId = button.getAttribute('data-client-id');
|
||||
const clientName = button.getAttribute('data-client-name');
|
||||
const redirectURIs = button.getAttribute('data-redirect-uris');
|
||||
|
||||
document.getElementById('editClientID').value = clientId;
|
||||
document.getElementById('editClientName').value = clientName;
|
||||
document.getElementById('editRedirectURIs').value = redirectURIs.split(',').join('\n');
|
||||
});
|
||||
|
||||
// 更新客户端
|
||||
function updateClient() {
|
||||
const clientID = document.getElementById('editClientID').value;
|
||||
const clientName = document.getElementById('editClientName').value;
|
||||
const redirectURIs = document.getElementById('editRedirectURIs').value
|
||||
.split(/[\n,]/)
|
||||
.map(uri => uri.trim())
|
||||
.filter(uri => uri.length > 0);
|
||||
|
||||
fetch(`/api/clients/${clientID}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_name: clientName,
|
||||
redirect_uris: redirectURIs,
|
||||
token_endpoint_auth_method: 'client_secret_basic',
|
||||
grant_types: ['authorization_code'],
|
||||
response_types: ['code']
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('更新失败,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 删除客户端
|
||||
function deleteClient(clientID) {
|
||||
if (!confirm('确定要删除这个客户端吗?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/clients/${clientID}`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('删除失败,请重试');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{{template "footer" .}}
|
||||
Reference in New Issue
Block a user