Files
weibo_signin/frontend/templates/account_detail.html
Jeason 8f4e0a2411 前后端数据流对齐:
后端改动:

GET /api/v1/accounts 现在返回分页格式 {items, total, page, size, total_pages, status_counts},默认每页 12 个
批量操作用 size=500 一次拉全部
前端改动:

base.html — 加了移动端汉堡菜单、全局响应式样式、pagination disabled 状态
dashboard.html — 账号卡片分页,统计数据从 API 的 status_counts 取,移动端单列布局
account_detail.html — 签到记录改成上下两行布局(topic+状态 / 消息+时间),分页用统一的上一页/下一页样式,移动端适配
分页逻辑统一:前后端都用 page/total_pages 字段,pagination 组件显示当前页 ±2 页码。
2026-03-18 09:45:55 +08:00

176 lines
9.6 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 title %}账号详情 - 微博超话签到{% endblock %}
{% block extra_css %}
<style>
.detail-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 10px; }
.detail-header h1 { font-size: 20px; font-weight: 700; color: #1e293b; }
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 20px; }
.info-table td { padding: 10px 0; border-bottom: 1px solid #f1f5f9; font-size: 13px; }
.info-table td:first-child { font-weight: 600; color: #64748b; width: 30%; }
.action-btn {
width: 100%; padding: 10px; border-radius: 12px; border: none;
font-size: 13px; font-weight: 600; cursor: pointer; transition: all 0.2s;
text-align: center; text-decoration: none; display: block;
}
.action-btn-primary { background: linear-gradient(135deg, #6366f1, #818cf8); color: white; }
.action-btn-primary:hover { transform: translateY(-1px); }
.action-btn-secondary { background: #f1f5f9; color: #475569; }
.action-btn-secondary:hover { background: #e2e8f0; }
.task-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #f1f5f9; flex-wrap: wrap; gap: 8px; }
.task-row:last-child { border-bottom: none; }
.task-cron { font-family: 'SF Mono', Monaco, monospace; background: #eef2ff; color: #6366f1; padding: 3px 10px; border-radius: 8px; font-size: 12px; font-weight: 600; }
.task-actions { display: flex; gap: 6px; }
.task-actions .btn { padding: 5px 12px; font-size: 11px; border-radius: 8px; }
/* 签到记录 - 移动端友好 */
.log-item { padding: 10px 0; border-bottom: 1px solid #f1f5f9; }
.log-item:last-child { border-bottom: none; }
.log-top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
.log-topic { font-weight: 500; color: #1e293b; font-size: 14px; }
.log-bottom { display: flex; justify-content: space-between; align-items: center; }
.log-msg { font-size: 12px; color: #64748b; flex: 1; margin-right: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.log-date { font-size: 11px; color: #94a3b8; white-space: nowrap; }
@media (max-width: 768px) {
.info-grid { grid-template-columns: 1fr; }
.detail-header { flex-direction: column; align-items: flex-start; }
.task-row { flex-direction: column; align-items: flex-start; }
.task-actions { width: 100%; justify-content: flex-end; }
}
</style>
{% endblock %}
{% block content %}
<div style="max-width: 960px; margin: 0 auto;">
<div class="detail-header">
<div>
<h1>{{ account.remark or account.weibo_user_id }}</h1>
<div style="color:#94a3b8; font-size:13px; margin-top:2px;">UID: {{ account.weibo_user_id }}</div>
</div>
<div style="display:flex; gap:8px;">
<a href="{{ url_for('edit_account', account_id=account.id) }}" class="btn btn-secondary">✏️ 编辑</a>
<form method="POST" action="{{ url_for('delete_account', account_id=account.id) }}" style="display:inline;" onsubmit="return confirm('确定要删除此账号吗?');">
<button type="submit" class="btn btn-danger">删除</button>
</form>
</div>
</div>
<div class="info-grid">
<div class="card">
<div class="card-header">📋 账号信息</div>
<table class="info-table" style="width:100%;">
<tr>
<td>状态</td>
<td>
{% if account.status == 'active' %}<span class="badge badge-success">正常</span>
{% elif account.status == 'pending' %}<span class="badge badge-warning">待验证</span>
{% elif account.status == 'invalid_cookie' %}<span class="badge badge-danger">Cookie 失效</span>
{% elif account.status == 'banned' %}<span class="badge badge-danger">已封禁</span>
{% endif %}
</td>
</tr>
<tr><td>备注</td><td>{{ account.remark or '-' }}</td></tr>
<tr><td>添加时间</td><td>{{ account.created_at[:10] }}</td></tr>
<tr><td>上次检查</td><td>{{ account.last_checked_at[:10] if account.last_checked_at else '-' }}</td></tr>
</table>
</div>
<div class="card">
<div class="card-header">⚡ 快捷操作</div>
<div style="display:flex; flex-direction:column; gap:8px;">
<form method="POST" action="{{ url_for('verify_account', account_id=account.id) }}">
<button type="submit" class="action-btn action-btn-secondary">🔍 验证 Cookie</button>
</form>
<form method="POST" action="{{ url_for('manual_signin', account_id=account.id) }}" onsubmit="this.querySelector('button').disabled=true; this.querySelector('button').textContent='⏳ 签到中...';">
<button type="submit" class="action-btn action-btn-primary">🚀 全部签到</button>
</form>
<a href="{{ url_for('account_topics', account_id=account.id) }}" class="action-btn action-btn-secondary">🎯 选择超话签到</a>
<a href="{{ url_for('add_task', account_id=account.id) }}" class="action-btn action-btn-secondary">⏰ 添加定时任务</a>
</div>
</div>
</div>
<div class="card">
<div class="card-header">⏰ 定时任务</div>
{% if tasks %}
{% for task in tasks %}
<div class="task-row">
<div style="display:flex; align-items:center; gap:10px;">
<span class="task-cron">{{ task.cron_expression }}</span>
{% if task.is_enabled %}<span class="badge badge-success">已启用</span>
{% else %}<span class="badge badge-warning">已禁用</span>{% endif %}
</div>
<div class="task-actions">
<form method="POST" action="{{ url_for('toggle_task', task_id=task.id) }}" style="display:inline;">
<input type="hidden" name="account_id" value="{{ account.id }}">
<input type="hidden" name="is_enabled" value="{{ task.is_enabled|lower }}">
<button type="submit" class="btn btn-secondary">{% if task.is_enabled %}禁用{% else %}启用{% endif %}</button>
</form>
<form method="POST" action="{{ url_for('delete_task', task_id=task.id) }}" style="display:inline;" onsubmit="return confirm('确定删除?');">
<input type="hidden" name="account_id" value="{{ account.id }}">
<button type="submit" class="btn btn-danger">删除</button>
</form>
</div>
</div>
{% endfor %}
{% else %}
<p style="color:#94a3b8; text-align:center; padding:20px; font-size:13px;">暂无定时任务</p>
{% endif %}
</div>
<div class="card">
<div class="card-header">📝 签到记录 {% if logs.get('total', 0) > 0 %}(共 {{ logs.total }} 条){% endif %}</div>
{% if logs.get('items') %}
{% for log in logs['items'] %}
<div class="log-item">
<div class="log-top">
<span class="log-topic">{{ log.topic_title or '-' }}</span>
{% if log.status == 'success' %}<span class="badge badge-success">签到成功</span>
{% elif log.status == 'failed_already_signed' %}<span class="badge badge-info">今日已签</span>
{% elif log.status == 'failed_network' %}<span class="badge badge-warning">网络错误</span>
{% elif log.status == 'failed_banned' %}<span class="badge badge-danger">已封禁</span>
{% else %}<span class="badge badge-info">{{ log.status }}</span>
{% endif %}
</div>
<div class="log-bottom">
<span class="log-msg">
{% if log.reward_info %}
{% if log.reward_info is mapping %}{{ log.reward_info.get('message', '-') }}
{% else %}{{ log.reward_info }}{% endif %}
{% else %}-{% endif %}
</span>
<span class="log-date">{{ log.signed_at[:16] | replace('T', ' ') }}</span>
</div>
</div>
{% endfor %}
{% set p = logs.get('page', 1) %}
{% set tp = logs.get('total_pages', 1) %}
{% if tp > 1 %}
<div class="pagination">
{% if p > 1 %}
<a href="?page={{ p - 1 }}"> 上一页</a>
{% else %}
<span class="disabled"> 上一页</span>
{% endif %}
{% for i in range(max(1, p - 2), min(tp, p + 2) + 1) %}
{% if i == p %}<span class="active">{{ i }}</span>
{% else %}<a href="?page={{ i }}">{{ i }}</a>{% endif %}
{% endfor %}
{% if p < tp %}
<a href="?page={{ p + 1 }}">下一页 </a>
{% else %}
<span class="disabled">下一页 </span>
{% endif %}
</div>
{% endif %}
{% else %}
<p style="color:#94a3b8; text-align:center; padding:20px; font-size:13px;">暂无签到记录</p>
{% endif %}
</div>
</div>
{% endblock %}