Files
weidian/templates/accounts.html
Jeason 822a4636c0 feat: Web管理系统 + Docker支持
- 多账号管理(异步登录、状态轮询)
- 购物车预售商品同步(倒计时/定时开售)
- 定时抢购(自动刷新、SKU选择、重试机制)
- 账号隔离调度(同账号顺序、跨账号并行)
- Web面板(任务分组、实时倒计时、批量操作)
- Dockerfile + docker-compose
2026-03-18 13:38:17 +08:00

144 lines
6.0 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.
{% 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-box-arrow-in-right"></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.textContent = '重试'; });
}
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 = '<i class="bi bi-box-arrow-in-right"></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 %}