第一次提交
This commit is contained in:
624
app/web/templates/admin/list.html
Normal file
624
app/web/templates/admin/list.html
Normal file
@@ -0,0 +1,624 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}账号管理 - 太一软件授权管理系统{% endblock %}
|
||||
|
||||
{% block page_title %}账号管理{% endblock %}
|
||||
|
||||
{% block page_actions %}
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" id="create-admin-btn">
|
||||
<i class="fas fa-plus me-1"></i>
|
||||
创建账号
|
||||
</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<!-- 搜索和筛选 -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body">
|
||||
<form id="search-form">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" id="search-keyword" placeholder="用户名搜索...">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select class="form-select" id="search-role">
|
||||
<option value="">全部角色</option>
|
||||
<option value="0">普通管理员</option>
|
||||
<option value="1">超级管理员</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select class="form-select" id="search-status">
|
||||
<option value="">全部状态</option>
|
||||
<option value="0">禁用</option>
|
||||
<option value="1">正常</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-outline-primary w-100">
|
||||
<i class="fas fa-search me-2"></i>
|
||||
搜索
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 账号列表 -->
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户名</th>
|
||||
<th>邮箱</th>
|
||||
<th>角色</th>
|
||||
<th>状态</th>
|
||||
<th>创建时间</th>
|
||||
<th>最后登录</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-list">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
加载中...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<nav aria-label="账号列表分页">
|
||||
<ul class="pagination justify-content-center" id="pagination">
|
||||
<!-- 分页将通过JavaScript动态生成 -->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 创建/编辑账号模态框 -->
|
||||
<div class="modal fade" id="adminModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="adminModalLabel">创建账号</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="admin-form">
|
||||
<input type="hidden" id="admin-id">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">用户名 <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="username" required>
|
||||
<div class="invalid-feedback"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">邮箱</label>
|
||||
<input type="email" class="form-control" id="email">
|
||||
<div class="invalid-feedback"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label" id="password-label">密码 <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control" id="password">
|
||||
<div class="form-text" id="password-help">创建新账号时必填,编辑时留空则不修改密码</div>
|
||||
<div class="invalid-feedback"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="role" class="form-label">角色</label>
|
||||
<select class="form-select" id="role">
|
||||
<option value="0">普通管理员</option>
|
||||
<option value="1">超级管理员</option>
|
||||
</select>
|
||||
<div class="invalid-feedback"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="status" class="form-label">状态</label>
|
||||
<select class="form-select" id="status">
|
||||
<option value="1">正常</option>
|
||||
<option value="0">禁用</option>
|
||||
</select>
|
||||
<div class="invalid-feedback"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary" id="save-admin-btn" data-loading-text="保存中...">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// 状态管理
|
||||
const state = {
|
||||
currentPage: 1,
|
||||
currentEditId: null,
|
||||
searchParams: {
|
||||
keyword: '',
|
||||
role: '',
|
||||
status: ''
|
||||
},
|
||||
isLoading: false
|
||||
};
|
||||
|
||||
// DOM元素缓存
|
||||
const elements = {
|
||||
searchForm: document.getElementById('search-form'),
|
||||
searchKeyword: document.getElementById('search-keyword'),
|
||||
searchRole: document.getElementById('search-role'),
|
||||
searchStatus: document.getElementById('search-status'),
|
||||
adminList: document.getElementById('admin-list'),
|
||||
pagination: document.getElementById('pagination'),
|
||||
createBtn: document.getElementById('create-admin-btn'),
|
||||
saveBtn: document.getElementById('save-admin-btn'),
|
||||
adminModal: document.getElementById('adminModal'),
|
||||
adminForm: document.getElementById('admin-form'),
|
||||
adminModalLabel: document.getElementById('adminModalLabel'),
|
||||
passwordLabel: document.getElementById('password-label'),
|
||||
passwordHelp: document.getElementById('password-help')
|
||||
};
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
init();
|
||||
});
|
||||
|
||||
function init() {
|
||||
bindEvents();
|
||||
loadAdmins(1);
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
// 搜索表单
|
||||
elements.searchForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
state.searchParams = {
|
||||
keyword: elements.searchKeyword.value.trim(),
|
||||
role: elements.searchRole.value,
|
||||
status: elements.searchStatus.value
|
||||
};
|
||||
loadAdmins(1);
|
||||
});
|
||||
|
||||
// 创建账号按钮
|
||||
elements.createBtn.addEventListener('click', function() {
|
||||
showAdminModal();
|
||||
});
|
||||
|
||||
// 保存账号按钮
|
||||
elements.saveBtn.addEventListener('click', function() {
|
||||
saveAdmin();
|
||||
});
|
||||
|
||||
// 模态框关闭时重置表单
|
||||
elements.adminModal.addEventListener('hidden.bs.modal', function() {
|
||||
resetForm();
|
||||
});
|
||||
|
||||
// 事件委托处理列表操作
|
||||
elements.adminList.addEventListener('click', function(e) {
|
||||
const target = e.target.closest('button');
|
||||
if (!target) return;
|
||||
|
||||
const adminId = target.getAttribute('data-id');
|
||||
if (!adminId) return;
|
||||
|
||||
if (target.classList.contains('edit-btn')) {
|
||||
editAdmin(adminId);
|
||||
} else if (target.classList.contains('delete-btn')) {
|
||||
const username = target.getAttribute('data-username');
|
||||
deleteAdmin(adminId, username);
|
||||
} else if (target.classList.contains('toggle-status-btn')) {
|
||||
const currentStatus = parseInt(target.getAttribute('data-status'));
|
||||
toggleAdminStatus(adminId, currentStatus);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setLoading(loading) {
|
||||
state.isLoading = loading;
|
||||
if (loading) {
|
||||
elements.saveBtn.disabled = true;
|
||||
elements.saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status"></span>保存中...';
|
||||
} else {
|
||||
elements.saveBtn.disabled = false;
|
||||
elements.saveBtn.innerHTML = '保存';
|
||||
}
|
||||
}
|
||||
|
||||
function showAdminModal(admin = null) {
|
||||
resetFormValidation();
|
||||
|
||||
if (admin) {
|
||||
// 编辑模式
|
||||
state.currentEditId = admin.admin_id;
|
||||
elements.adminModalLabel.textContent = '编辑账号';
|
||||
elements.adminForm.querySelector('#admin-id').value = admin.admin_id;
|
||||
elements.adminForm.querySelector('#username').value = admin.username;
|
||||
elements.adminForm.querySelector('#email').value = admin.email || '';
|
||||
elements.adminForm.querySelector('#password').value = '';
|
||||
elements.adminForm.querySelector('#role').value = admin.role;
|
||||
elements.adminForm.querySelector('#status').value = admin.status;
|
||||
|
||||
elements.passwordLabel.innerHTML = '密码';
|
||||
elements.passwordHelp.textContent = '留空则不修改密码';
|
||||
} else {
|
||||
// 创建模式
|
||||
state.currentEditId = null;
|
||||
elements.adminModalLabel.textContent = '创建账号';
|
||||
elements.adminForm.reset();
|
||||
elements.adminForm.querySelector('#admin-id').value = '';
|
||||
|
||||
elements.passwordLabel.innerHTML = '密码 <span class="text-danger">*</span>';
|
||||
elements.passwordHelp.textContent = '创建新账号时必填';
|
||||
}
|
||||
|
||||
const modal = new bootstrap.Modal(elements.adminModal);
|
||||
modal.show();
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
elements.adminForm.reset();
|
||||
resetFormValidation();
|
||||
state.currentEditId = null;
|
||||
}
|
||||
|
||||
function resetFormValidation() {
|
||||
const inputs = elements.adminForm.querySelectorAll('input, select');
|
||||
inputs.forEach(input => {
|
||||
input.classList.remove('is-invalid');
|
||||
const feedback = input.parentElement.querySelector('.invalid-feedback');
|
||||
if (feedback) {
|
||||
feedback.textContent = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showFieldError(fieldId, message) {
|
||||
const field = document.getElementById(fieldId);
|
||||
const feedback = field.parentElement.querySelector('.invalid-feedback');
|
||||
field.classList.add('is-invalid');
|
||||
if (feedback) {
|
||||
feedback.textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
function loadAdmins(page = 1) {
|
||||
if (state.isLoading) return;
|
||||
|
||||
state.currentPage = page;
|
||||
|
||||
const params = new URLSearchParams({
|
||||
page: page,
|
||||
per_page: 10,
|
||||
keyword: state.searchParams.keyword,
|
||||
role: state.searchParams.role,
|
||||
status: state.searchParams.status
|
||||
});
|
||||
|
||||
apiRequest(`/api/v1/admins?${params.toString()}`, {
|
||||
method: 'GET'
|
||||
})
|
||||
.then(data => {
|
||||
if (data && data.success) {
|
||||
renderAdminList(data.data.admins);
|
||||
renderPagination(data.data.pagination);
|
||||
} else {
|
||||
showNotification('加载账号列表失败: ' + (data?.message || '未知错误'), 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to load admins:', error);
|
||||
showNotification('加载账号列表失败,请检查网络连接', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
function renderAdminList(admins) {
|
||||
const tbody = elements.adminList;
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (admins.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="7" class="text-center text-muted">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
admins.forEach(admin => {
|
||||
const tr = document.createElement('tr');
|
||||
|
||||
const usernameTd = document.createElement('td');
|
||||
usernameTd.textContent = admin.username;
|
||||
tr.appendChild(usernameTd);
|
||||
|
||||
const emailTd = document.createElement('td');
|
||||
emailTd.textContent = admin.email || '-';
|
||||
tr.appendChild(emailTd);
|
||||
|
||||
const roleTd = document.createElement('td');
|
||||
const roleSpan = document.createElement('span');
|
||||
roleSpan.className = `badge bg-${admin.role === 1 ? 'primary' : 'secondary'}`;
|
||||
roleSpan.textContent = admin.role_name;
|
||||
roleTd.appendChild(roleSpan);
|
||||
tr.appendChild(roleTd);
|
||||
|
||||
const statusTd = document.createElement('td');
|
||||
const statusSpan = document.createElement('span');
|
||||
statusSpan.className = `badge bg-${admin.status === 1 ? 'success' : 'danger'}`;
|
||||
statusSpan.textContent = admin.status_name;
|
||||
statusTd.appendChild(statusSpan);
|
||||
tr.appendChild(statusTd);
|
||||
|
||||
const createTimeTd = document.createElement('td');
|
||||
createTimeTd.textContent = admin.create_time || '-';
|
||||
tr.appendChild(createTimeTd);
|
||||
|
||||
const lastLoginTd = document.createElement('td');
|
||||
lastLoginTd.textContent = admin.last_login_time || '-';
|
||||
tr.appendChild(lastLoginTd);
|
||||
|
||||
const actionTd = document.createElement('td');
|
||||
|
||||
// 状态切换按钮
|
||||
const toggleBtn = document.createElement('button');
|
||||
toggleBtn.className = `btn btn-sm btn-outline-${admin.status === 1 ? 'danger' : 'success'} toggle-status-btn`;
|
||||
toggleBtn.setAttribute('data-id', admin.admin_id);
|
||||
toggleBtn.setAttribute('data-status', admin.status);
|
||||
toggleBtn.setAttribute('title', admin.status === 1 ? '禁用账号' : '启用账号');
|
||||
toggleBtn.innerHTML = `<i class="fas fa-${admin.status === 1 ? 'times' : 'check'}"></i>`;
|
||||
actionTd.appendChild(toggleBtn);
|
||||
|
||||
// 编辑按钮
|
||||
const editBtn = document.createElement('button');
|
||||
editBtn.className = 'btn btn-sm btn-outline-primary edit-btn';
|
||||
editBtn.setAttribute('data-id', admin.admin_id);
|
||||
editBtn.setAttribute('title', '编辑账号');
|
||||
editBtn.innerHTML = '<i class="fas fa-edit"></i>';
|
||||
actionTd.appendChild(editBtn);
|
||||
|
||||
// 删除按钮
|
||||
const deleteBtn = document.createElement('button');
|
||||
deleteBtn.className = 'btn btn-sm btn-outline-danger delete-btn';
|
||||
deleteBtn.setAttribute('data-id', admin.admin_id);
|
||||
deleteBtn.setAttribute('data-username', admin.username);
|
||||
deleteBtn.setAttribute('title', '删除账号');
|
||||
deleteBtn.innerHTML = '<i class="fas fa-trash"></i>';
|
||||
actionTd.appendChild(deleteBtn);
|
||||
|
||||
tr.appendChild(actionTd);
|
||||
|
||||
fragment.appendChild(tr);
|
||||
});
|
||||
|
||||
tbody.appendChild(fragment);
|
||||
}
|
||||
|
||||
function renderPagination(pagination) {
|
||||
const ul = elements.pagination;
|
||||
ul.innerHTML = '';
|
||||
|
||||
if (pagination.pages <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
// 上一页
|
||||
const prevLi = document.createElement('li');
|
||||
prevLi.className = `page-item ${pagination.has_prev ? '' : 'disabled'}`;
|
||||
const prevLink = document.createElement('a');
|
||||
prevLink.className = 'page-link';
|
||||
prevLink.href = '#';
|
||||
prevLink.innerHTML = '«';
|
||||
if (pagination.has_prev) {
|
||||
prevLink.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
loadAdmins(pagination.page - 1);
|
||||
});
|
||||
}
|
||||
prevLi.appendChild(prevLink);
|
||||
fragment.appendChild(prevLi);
|
||||
|
||||
// 页码
|
||||
for (let i = 1; i <= pagination.pages; i++) {
|
||||
const li = document.createElement('li');
|
||||
li.className = `page-item ${i === pagination.page ? 'active' : ''}`;
|
||||
const link = document.createElement('a');
|
||||
link.className = 'page-link';
|
||||
link.href = '#';
|
||||
link.textContent = i;
|
||||
if (i !== pagination.page) {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
loadAdmins(i);
|
||||
});
|
||||
}
|
||||
li.appendChild(link);
|
||||
fragment.appendChild(li);
|
||||
}
|
||||
|
||||
// 下一页
|
||||
const nextLi = document.createElement('li');
|
||||
nextLi.className = `page-item ${pagination.has_next ? '' : 'disabled'}`;
|
||||
const nextLink = document.createElement('a');
|
||||
nextLink.className = 'page-link';
|
||||
nextLink.href = '#';
|
||||
nextLink.innerHTML = '»';
|
||||
if (pagination.has_next) {
|
||||
nextLink.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
loadAdmins(pagination.page + 1);
|
||||
});
|
||||
}
|
||||
nextLi.appendChild(nextLink);
|
||||
fragment.appendChild(nextLi);
|
||||
|
||||
ul.appendChild(fragment);
|
||||
}
|
||||
|
||||
function editAdmin(adminId) {
|
||||
apiRequest(`/api/v1/admins/${adminId}`, {
|
||||
method: 'GET'
|
||||
})
|
||||
.then(data => {
|
||||
if (data && data.success) {
|
||||
showAdminModal(data.data);
|
||||
} else {
|
||||
showNotification('获取账号信息失败: ' + (data?.message || '未知错误'), 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to get admin:', error);
|
||||
showNotification('获取账号信息失败,请检查网络连接', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
function toggleAdminStatus(adminId, currentStatus) {
|
||||
const action = currentStatus === 1 ? '禁用' : '启用';
|
||||
|
||||
if (!confirm(`确定要${action}此账号吗?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
apiRequest(`/api/v1/admins/${adminId}/toggle-status`, {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(data => {
|
||||
if (data && data.success) {
|
||||
showNotification(data.message, 'success');
|
||||
// 重新加载列表以确保数据一致性
|
||||
loadAdmins(state.currentPage);
|
||||
} else {
|
||||
showNotification('切换账号状态失败: ' + (data?.message || '未知错误'), 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to toggle admin status:', error);
|
||||
showNotification('切换账号状态失败,请检查网络连接', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
function deleteAdmin(adminId, username) {
|
||||
if (!confirm(`确定要删除账号 "${username}" 吗?此操作将标记为已删除(软删除),无法恢复!`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
apiRequest(`/api/v1/admins/${adminId}`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
.then(data => {
|
||||
if (data && data.success) {
|
||||
showNotification(data.message, 'success');
|
||||
// 重新加载列表
|
||||
loadAdmins(state.currentPage);
|
||||
} else {
|
||||
showNotification('删除账号失败: ' + (data?.message || '未知错误'), 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Failed to delete admin:', error);
|
||||
showNotification('删除账号失败,请检查网络连接', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
function saveAdmin() {
|
||||
if (state.isLoading) return;
|
||||
|
||||
resetFormValidation();
|
||||
|
||||
const formData = {
|
||||
username: elements.adminForm.querySelector('#username').value.trim(),
|
||||
email: elements.adminForm.querySelector('#email').value.trim(),
|
||||
role: parseInt(elements.adminForm.querySelector('#role').value),
|
||||
status: parseInt(elements.adminForm.querySelector('#status').value)
|
||||
};
|
||||
|
||||
const password = elements.adminForm.querySelector('#password').value;
|
||||
|
||||
// 前端验证
|
||||
let hasError = false;
|
||||
|
||||
if (!formData.username) {
|
||||
showFieldError('username', '用户名不能为空');
|
||||
hasError = true;
|
||||
} else if (formData.username.length < 3) {
|
||||
showFieldError('username', '用户名至少3个字符');
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (!state.currentEditId && !password) {
|
||||
showFieldError('password', '密码不能为空');
|
||||
hasError = true;
|
||||
} else if (password && password.length < 6) {
|
||||
showFieldError('password', '密码长度至少6位');
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (password) {
|
||||
formData.password = password;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
const isCreate = !state.currentEditId;
|
||||
const url = isCreate ? '/api/v1/admins' : `/api/v1/admins/${state.currentEditId}`;
|
||||
const method = isCreate ? 'POST' : 'PUT';
|
||||
|
||||
apiRequest(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(formData)
|
||||
})
|
||||
.then(data => {
|
||||
setLoading(false);
|
||||
|
||||
if (data && data.success) {
|
||||
showNotification(isCreate ? '账号创建成功' : '账号更新成功', 'success');
|
||||
const modal = bootstrap.Modal.getInstance(elements.adminModal);
|
||||
modal.hide();
|
||||
loadAdmins(state.currentPage);
|
||||
} else {
|
||||
// 显示服务器端验证错误
|
||||
const message = data?.message || '未知错误';
|
||||
if (message.includes('用户名')) {
|
||||
showFieldError('username', message);
|
||||
} else if (message.includes('密码')) {
|
||||
showFieldError('password', message);
|
||||
} else {
|
||||
showNotification(isCreate ? '账号创建失败: ' + message : '账号更新失败: ' + message, 'danger');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
setLoading(false);
|
||||
console.error('Failed to save admin:', error);
|
||||
showNotification(isCreate ? '账号创建失败,请检查网络连接' : '账号更新失败,请检查网络连接', 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user