# -*- coding: utf-8 -*- """ziwei-power Flask 应用 — 磁场管理打卡系统""" import os from datetime import timedelta from functools import wraps from flask import Flask, render_template, request, jsonify, session, redirect, url_for from werkzeug.security import generate_password_hash, check_password_hash from database import init_db, get_checkin, save_checkin, delete_checkin, get_all_checkins app = Flask(__name__) app.secret_key = os.urandom(24) # 会话持久化:30 天 app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=30) # ── 用户库 ──────────────────────────────────────────── USERS = { 'qiukai': { 'password_hash': generate_password_hash('AiAlex2018$'), 'name': '凯哥' } } # ── 登录检查装饰器 ──────────────────────────────────── def login_required(f): @wraps(f) def decorated(*args, **kwargs): if not session.get('logged_in'): return redirect(url_for('login_page', next=request.path)) return f(*args, **kwargs) return decorated # ── 登录路由 ────────────────────────────────────────── @app.route('/login', methods=['GET', 'POST']) def login_page(): if request.method == 'POST': username = request.form.get('username', '').strip() password = request.form.get('password', '') remember = request.form.get('remember') == 'on' user = USERS.get(username) if user and check_password_hash(user['password_hash'], password): session.permanent = remember session['logged_in'] = True session['username'] = username session['display_name'] = user['name'] next_url = request.args.get('next', '/') return jsonify({'ok': True, 'next': next_url}) else: return jsonify({'ok': False, 'error': '账号或密码错误'}), 401 # GET:如果已登录直接跳转 if session.get('logged_in'): return redirect(url_for('index')) return render_template('login.html') @app.route('/logout') def logout(): session.clear() return redirect(url_for('login_page')) # ── 主页 ────────────────────────────────────────────── @app.route('/') @login_required def index(): return render_template('index.html', username=session.get('display_name', session.get('username', ''))) # ── API ────────────────────────────────────────────── @app.route('/api/checkin', methods=['GET']) @login_required def api_get_checkin(): date = request.args.get('date', '') if not date: return jsonify({'ok': False, 'error': '缺少 date 参数'}), 400 row = get_checkin(date) return jsonify({'ok': True, 'data': row}) @app.route('/api/checkin', methods=['POST']) @login_required def api_save_checkin(): body = request.get_json(force=True) date = body.get('date', '') if not date: return jsonify({'ok': False, 'error': '缺少 date 字段'}), 400 data = body.get('data', {}) save_checkin(date, data) return jsonify({'ok': True}) @app.route('/api/checkin/', methods=['DELETE']) @login_required def api_delete_checkin(date): delete_checkin(date) return jsonify({'ok': True}) @app.route('/api/history', methods=['GET']) @login_required def api_history(): rows = get_all_checkins() return jsonify({'ok': True, 'data': rows}) @app.route('/api/stats', methods=['GET']) @login_required def api_stats(): """返回统计数据和日历状态映射""" rows = get_all_checkins() total_days = len(rows) total_morning = 0 total_evening = 0 total_study = 0 calendar = {} for row in rows: d = row['date'] data = row['data'] morning = data.get('morning', []) evening = data.get('evening', []) study = data.get('study', []) # 统计条目 total_morning += sum(1 for x in morning if isinstance(x, str) and x.strip()) total_evening += sum(1 for x in evening if ( isinstance(x, str) and x.strip() or isinstance(x, dict) and (x.get('mistake', '') or '').strip() )) total_study += sum(1 for x in study if x.get('done')) # 评分 day_score = 0 has_morning = any(isinstance(x, str) and x.strip() for x in morning) has_evening = any( (isinstance(x, str) and x.strip()) or (isinstance(x, dict) and (x.get('mistake', '') or '').strip()) for x in evening ) has_study = any(x.get('done') for x in study) if has_morning: day_score += 1 if has_evening: day_score += 1 if has_study: day_score += 1 calendar[d] = 'pass' if day_score >= 2 else 'fail' return jsonify({ 'ok': True, 'total_days': total_days, 'total_morning': total_morning, 'total_evening': total_evening, 'total_study': total_study, 'calendar': calendar }) @app.route('/api/user', methods=['GET']) @login_required def api_user(): return jsonify({ 'ok': True, 'username': session.get('username'), 'display_name': session.get('display_name') }) # ── 启动 ────────────────────────────────────────────── if __name__ == '__main__': init_db() app.run(host='0.0.0.0', port=5056, debug=False)