diff --git a/database.py b/database.py index 6a395c3..b57f7ce 100644 --- a/database.py +++ b/database.py @@ -106,18 +106,20 @@ class DatabaseManager: proxy_share TEXT DEFAULT 'exclusive', proxy_purchase_date TEXT DEFAULT '', refund_received TEXT DEFAULT '0', + refund_received_at TEXT DEFAULT '', checked_at TEXT ) ''') # 兼容旧表:动态添加缺少的列 - for col in ['suspended_time', 'title', 'remark', 'card_number', 'proxy', 'proxy_expire_days', 'proxy_share', 'proxy_purchase_date', 'refund_received']: + for col in ['suspended_time', 'title', 'remark', 'card_number', 'proxy', 'proxy_expire_days', 'proxy_share', 'proxy_purchase_date', 'refund_received', 'refund_received_at']: try: cursor.execute(f"SELECT {col} FROM claude_payment_status LIMIT 1") except sqlite3.OperationalError: defaults = {'title': "DEFAULT ''", 'remark': "DEFAULT ''", 'card_number': "DEFAULT ''", 'proxy': "DEFAULT ''", 'proxy_expire_days': "DEFAULT 30", 'proxy_share': "DEFAULT 'exclusive'", 'proxy_purchase_date': "DEFAULT ''", - 'refund_received': "DEFAULT '0'"} + 'refund_received': "DEFAULT '0'", + 'refund_received_at': "DEFAULT ''"} default = defaults.get(col, '') cursor.execute(f"ALTER TABLE claude_payment_status ADD COLUMN {col} TEXT {default}") logger.info(f"已为 claude_payment_status 添加 {col} 列") @@ -527,7 +529,7 @@ class DatabaseManager: cursor = conn.cursor() checked_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 先查已有的 remark/card_number,避免被覆盖 - cursor.execute('SELECT title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received FROM claude_payment_status WHERE email = ?', (email,)) + cursor.execute('SELECT title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, refund_received_at FROM claude_payment_status WHERE email = ?', (email,)) existing = cursor.fetchone() old_title = existing['title'] if existing else '' old_remark = existing['remark'] if existing else '' @@ -537,10 +539,11 @@ class DatabaseManager: old_share = existing['proxy_share'] if existing else 'exclusive' old_purchase = existing['proxy_purchase_date'] if existing else '' old_refund_received = existing['refund_received'] if existing else '0' + old_refund_received_at = existing['refund_received_at'] if existing else '' cursor.execute(''' - INSERT OR REPLACE INTO claude_payment_status (email, status, payment_time, refund_time, suspended_time, title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, checked_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ''', (email, status, payment_time, refund_time, suspended_time, old_title or '', old_remark or '', old_card or '', old_proxy or '', old_expire or 30, old_share or 'exclusive', old_purchase or '', old_refund_received or '0', checked_at)) + INSERT OR REPLACE INTO claude_payment_status (email, status, payment_time, refund_time, suspended_time, title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, refund_received_at, checked_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ''', (email, status, payment_time, refund_time, suspended_time, old_title or '', old_remark or '', old_card or '', old_proxy or '', old_expire or 30, old_share or 'exclusive', old_purchase or '', old_refund_received or '0', old_refund_received_at or '', checked_at)) conn.commit() return True except Exception as e: @@ -554,7 +557,7 @@ class DatabaseManager: def _sync_get(): conn = self.get_connection() cursor = conn.cursor() - cursor.execute('SELECT status, payment_time, refund_time, suspended_time, title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, checked_at FROM claude_payment_status WHERE email = ?', (email,)) + cursor.execute('SELECT status, payment_time, refund_time, suspended_time, title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, refund_received_at, checked_at FROM claude_payment_status WHERE email = ?', (email,)) row = cursor.fetchone() if row: return { @@ -570,6 +573,7 @@ class DatabaseManager: 'proxy_share': row['proxy_share'] or 'exclusive', 'proxy_purchase_date': row['proxy_purchase_date'] or '', 'refund_received': row['refund_received'] or '0', + 'refund_received_at': row['refund_received_at'] or '', 'checked_at': row['checked_at'] } return None @@ -581,7 +585,7 @@ class DatabaseManager: def _sync_get(): conn = self.get_connection() cursor = conn.cursor() - cursor.execute('SELECT email, status, payment_time, refund_time, suspended_time, title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, checked_at FROM claude_payment_status') + cursor.execute('SELECT email, status, payment_time, refund_time, suspended_time, title, remark, card_number, proxy, proxy_expire_days, proxy_share, proxy_purchase_date, refund_received, refund_received_at, checked_at FROM claude_payment_status') rows = cursor.fetchall() result = {} for row in rows: @@ -598,6 +602,7 @@ class DatabaseManager: 'proxy_share': row['proxy_share'] or 'exclusive', 'proxy_purchase_date': row['proxy_purchase_date'] or '', 'refund_received': row['refund_received'] or '0', + 'refund_received_at': row['refund_received_at'] or '', 'checked_at': row['checked_at'] } return result @@ -606,7 +611,7 @@ class DatabaseManager: async def update_claude_payment_note(self, email: str, **kwargs) -> bool: """更新备注、卡号、代理等字段""" - allowed = {'title', 'remark', 'card_number', 'proxy', 'proxy_expire_days', 'proxy_share', 'proxy_purchase_date', 'refund_received'} + allowed = {'title', 'remark', 'card_number', 'proxy', 'proxy_expire_days', 'proxy_share', 'proxy_purchase_date', 'refund_received', 'refund_received_at'} def _sync_update(): try: conn = self.get_connection() diff --git a/mail_api.py b/mail_api.py index dd5b228..c91a299 100644 --- a/mail_api.py +++ b/mail_api.py @@ -1278,10 +1278,11 @@ async def toggle_refund_received(email: str) -> ApiResponse: status = await db_manager.get_claude_payment_status(email) current = status.get('refund_received', '0') if status else '0' new_val = '0' if current == '1' else '1' - ok = await db_manager.update_claude_payment_note(email, refund_received=new_val) + now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') if new_val == '1' else '' + ok = await db_manager.update_claude_payment_note(email, refund_received=new_val, refund_received_at=now) if ok: await cache.invalidate_payment() - return ApiResponse(success=True, data={"refund_received": new_val}) + return ApiResponse(success=True, data={"refund_received": new_val, "refund_received_at": now}) return ApiResponse(success=False, message="更新失败") except Exception as e: logger.error(f"切换退款状态失败: {e}") diff --git a/static/index.html b/static/index.html index a41dfbb..a10ed62 100644 --- a/static/index.html +++ b/static/index.html @@ -98,6 +98,7 @@ 支付时间 退款时间 封号时间 + 到账时间 备注/卡号 代理 操作 @@ -105,7 +106,7 @@ - +
暂无邮箱数据,点击"粘贴导入"添加
diff --git a/static/script.js b/static/script.js index 7043785..bd23317 100644 --- a/static/script.js +++ b/static/script.js @@ -280,7 +280,7 @@ class MailManager { async loadAccounts() { const tbody = document.getElementById('accountTableBody'); - tbody.innerHTML = `
加载中...
`; + tbody.innerHTML = `
加载中...
`; try { // 有筛选时加载全部数据,否则分页加载 @@ -300,11 +300,11 @@ class MailManager { await this.loadClaudePaymentStatuses(); this.applyFilterAndRender(); } else { - tbody.innerHTML = `
${this.escapeHtml(result.message || '加载失败')}
`; + tbody.innerHTML = `
${this.escapeHtml(result.message || '加载失败')}
`; } } catch (err) { console.error('加载账号失败:', err); - tbody.innerHTML = `
网络错误
`; + tbody.innerHTML = `
网络错误
`; } } @@ -339,7 +339,7 @@ class MailManager { renderAccounts() { const tbody = document.getElementById('accountTableBody'); if (!this.accounts.length) { - tbody.innerHTML = `
暂无邮箱数据
`; + tbody.innerHTML = `
暂无邮箱数据
`; return; } @@ -777,9 +777,9 @@ class MailManager { const resp = await fetch(`/api/tools/refund-received/${encodeURIComponent(email)}`, { method: 'POST' }); const result = await resp.json(); if (result.success) { - // 更新本地状态 if (this.claudePaymentStatuses[email]) { this.claudePaymentStatuses[email].refund_received = result.data.refund_received; + this.claudePaymentStatuses[email].refund_received_at = result.data.refund_received_at || ''; } this.renderAccounts(); this.showToast(result.data.refund_received === '1' ? '已标记到账' : '已取消到账', 'success'); @@ -809,6 +809,7 @@ class MailManager { - - - + - `; @@ -843,11 +844,16 @@ class MailManager { ? `${fmtTime(info.suspended_time)}` : '-'; + const refundReceivedTime = info.refund_received === '1' && info.refund_received_at + ? fmtTime(info.refund_received_at) + : '-'; + return `${paidBadge} ${refundBadge} ${fmtTime(info.payment_time)} ${fmtTime(info.refund_time)} ${suspendedHtml} + ${refundReceivedTime} ${this.renderNoteCell(email, info)}
diff --git a/static/style.css b/static/style.css index 42511f3..015292d 100644 --- a/static/style.css +++ b/static/style.css @@ -445,9 +445,10 @@ body { .data-table th:nth-child(7) { width: 85px; } /* 支付时间 */ .data-table th:nth-child(8) { width: 85px; } /* 退款时间 */ .data-table th:nth-child(9) { width: 85px; } /* 封号时间 */ -.data-table th:nth-child(10) { width: 120px; } /* 备注/卡号 */ -.data-table th:nth-child(11) { width: 150px; } /* 代理 */ -.data-table th:nth-child(12) { width: 220px; } /* 操作 */ +.data-table th:nth-child(10) { width: 85px; } /* 到账时间 */ +.data-table th:nth-child(11) { width: 120px; } /* 备注/卡号 */ +.data-table th:nth-child(12) { width: 150px; } /* 代理 */ +.data-table th:nth-child(13) { width: 220px; } /* 操作 */ /* 单元格内容 */ .value-container {