Files
weidian/templates/accounts.html

169 lines
7.4 KiB
HTML
Raw Normal View History

{% extends "base.html" %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3">
<h4 class="mb-0">账号管理</h4>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addModal">
<i class="bi bi-plus-lg"></i> 添加账号
</button>
</div>
<div class="card">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead><tr>
<th>ID</th><th>名称</th><th>手机号</th><th>登录状态</th><th>更新时间</th><th>操作</th>
</tr></thead>
<tbody>
{% for a in accounts %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.name }}</td>
<td>{{ a.phone[:3] }}****{{ a.phone[-4:] if a.phone|length > 4 else '' }}</td>
<td>
{% if a.is_logged_in %}
<span class="badge bg-success">已登录</span>
{% elif a.login_msg == '登录中...' %}
<span class="badge bg-warning">
<span class="spinner-border spinner-border-sm" style="width:.7rem;height:.7rem"></span> 登录中...
</span>
{% else %}
<span class="badge bg-secondary" title="{{ a.login_msg or '' }}">未登录</span>
{% endif %}
</td>
<td>{{ a.updated_at }}</td>
<td>
<button class="btn btn-outline-primary btn-sm" onclick="doLogin({{ a.id }}, this)">
<i class="bi bi-key"></i> 密码登录
</button>
<button class="btn btn-outline-info btn-sm" onclick="doSmsLogin({{ a.id }}, this)">
<i class="bi bi-chat-dots"></i> 短信登录
</button>
<button class="btn btn-outline-danger btn-sm" onclick="deleteAccount({{ a.id }})">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
{% endfor %}
{% if not accounts %}
<tr><td colspan="6" class="text-center text-muted py-4">暂无账号,点击右上角添加</td></tr>
{% endif %}
</tbody>
</table>
</div>
</div>
<div class="modal fade" id="addModal" tabindex="-1">
<div class="modal-dialog"><div class="modal-content">
<div class="modal-header"><h5 class="modal-title">添加微店账号</h5></div>
<div class="modal-body">
<form id="addForm">
<div class="mb-3">
<label class="form-label">备注名称</label>
<input type="text" class="form-control" name="name" required placeholder="如主号、小号1">
</div>
<div class="mb-3">
<label class="form-label">手机号</label>
<input type="tel" class="form-control" name="phone" required placeholder="微店登录手机号">
</div>
<div class="mb-3">
<label class="form-label">密码</label>
<input type="password" class="form-control" name="password" required placeholder="微店登录密码">
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button class="btn btn-primary" onclick="addAccount()">添加</button>
</div>
</div></div>
</div>
{% endblock %}
{% block scripts %}
<script>
function addAccount() {
var form = document.getElementById('addForm');
var data = new FormData(form);
var btn = event.target;
btn.disabled = true;
btn.textContent = '添加中...';
fetch('/accounts/add', { method: 'POST', body: data })
.then(function(r) { return r.json(); })
.then(function(d) {
if (d.success) {
bootstrap.Modal.getInstance(document.getElementById('addModal')).hide();
form.reset();
location.reload();
} else {
alert(d.msg);
btn.disabled = false;
btn.textContent = '添加';
}
})
.catch(function() { btn.disabled = false; btn.textContent = '添加'; });
}
function doLogin(id, btn) {
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> 登录中...';
var badge = btn.closest('tr').querySelector('.badge');
if (badge) { badge.className = 'badge bg-warning'; badge.textContent = '登录中...'; }
fetch('/accounts/login/' + id, { method: 'POST' })
.then(function(r) { return r.json(); })
.then(function() { pollStatus(id, btn); })
.catch(function() { btn.disabled = false; btn.innerHTML = '<i class="bi bi-key"></i> 密码登录'; });
}
function doSmsLogin(id, btn) {
if (!confirm('短信登录需要您在弹出的浏览器中拖动滑块,并在服务器终端输入验证码。确定继续?')) return;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> 等待交互...';
var badge = btn.closest('tr').querySelector('.badge');
if (badge) { badge.className = 'badge bg-info'; badge.textContent = '等待人机交互...'; }
fetch('/accounts/login_sms/' + id, { method: 'POST' })
.then(function(r) { return r.json(); })
.then(function(d) {
if (d.success) {
alert(d.msg);
pollStatus(id, btn);
} else {
alert(d.msg);
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-chat-dots"></i> 短信登录';
}
})
.catch(function() { btn.disabled = false; btn.innerHTML = '<i class="bi bi-chat-dots"></i> 短信登录'; });
}
function pollStatus(id, btn) {
var interval = setInterval(function() {
fetch('/accounts/status/' + id)
.then(function(r) { return r.json(); })
.then(function(d) {
if (d.done) {
clearInterval(interval);
var row = btn ? btn.closest('tr') : null;
if (row) {
var badge = row.querySelector('.badge');
if (d.is_logged_in) {
badge.className = 'badge bg-success';
badge.textContent = '已登录';
} else {
badge.className = 'badge bg-danger';
badge.textContent = '失败';
badge.title = d.login_msg;
}
}
if (btn) {
btn.disabled = false;
btn.innerHTML = btn.textContent.includes('短信') ?
'<i class="bi bi-chat-dots"></i> 短信登录' :
'<i class="bi bi-key"></i> 密码登录';
}
}
});
}, 2000);
}
function deleteAccount(id) {
if (!confirm('确定删除此账号?相关任务也会被删除。')) return;
fetch('/accounts/delete/' + id, { method: 'POST' })
.then(function(r) { return r.json(); })
.then(function(d) { if (d.success) location.reload(); });
}
</script>
{% endblock %}