#!/usr/bin/env python3 """ 簡化版夥伴對齊系統 - 使用 SQLite 無需 MySQL,開箱即用 """ from flask import Flask, render_template, request, jsonify from flask_cors import CORS from flask_sqlalchemy import SQLAlchemy from datetime import datetime, date import json import os import csv import io # 創建 Flask 應用程式 app = Flask(__name__) # 配置 app.config['SECRET_KEY'] = 'dev-secret-key-for-testing' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///partner_alignment.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # 初始化擴展 db = SQLAlchemy(app) CORS(app, origins=['http://localhost:5000', 'http://127.0.0.1:5000']) # 數據模型 class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) full_name = db.Column(db.String(100), nullable=False) department = db.Column(db.String(50), nullable=False) position = db.Column(db.String(50), nullable=False) employee_id = db.Column(db.String(50), unique=True) password_hash = db.Column(db.String(255), nullable=False) is_active = db.Column(db.Boolean, default=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) class Capability(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) l1_description = db.Column(db.Text) l2_description = db.Column(db.Text) l3_description = db.Column(db.Text) l4_description = db.Column(db.Text) l5_description = db.Column(db.Text) is_active = db.Column(db.Boolean, default=True) class DepartmentCapability(db.Model): """部門與能力項目的關聯表""" id = db.Column(db.Integer, primary_key=True) department = db.Column(db.String(50), nullable=False) capability_id = db.Column(db.Integer, db.ForeignKey('capability.id'), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) # 建立唯一索引,確保同一部門不會重複選擇同一能力項目 __table_args__ = (db.UniqueConstraint('department', 'capability_id', name='uq_dept_capability'),) class Assessment(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) department = db.Column(db.String(50), nullable=False) position = db.Column(db.String(50), nullable=False) employee_name = db.Column(db.String(100)) assessment_data = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow) class StarFeedback(db.Model): id = db.Column(db.Integer, primary_key=True) evaluator_name = db.Column(db.String(100), nullable=False) evaluatee_name = db.Column(db.String(100), nullable=False) evaluatee_department = db.Column(db.String(50), nullable=False) evaluatee_position = db.Column(db.String(50), nullable=False) situation = db.Column(db.Text, nullable=False) task = db.Column(db.Text, nullable=False) action = db.Column(db.Text, nullable=False) result = db.Column(db.Text, nullable=False) score = db.Column(db.Integer, nullable=False) points_earned = db.Column(db.Integer, nullable=False) feedback_date = db.Column(db.Date, default=date.today) created_at = db.Column(db.DateTime, default=datetime.utcnow) class EmployeePoint(db.Model): id = db.Column(db.Integer, primary_key=True) employee_name = db.Column(db.String(100), nullable=False) department = db.Column(db.String(50), nullable=False) position = db.Column(db.String(50), nullable=False) total_points = db.Column(db.Integer, default=0) monthly_points = db.Column(db.Integer, default=0) # 路由 @app.route('/') def index(): return render_template('index.html') @app.route('/api/auth/login', methods=['POST']) def login(): """用戶登入""" try: data = request.get_json() username = data.get('username') password = data.get('password') if not username or not password: return jsonify({'error': '用戶名和密碼不能為空'}), 400 # 查找用戶 user = User.query.filter_by(username=username).first() if not user: return jsonify({'error': '用戶名或密碼錯誤'}), 401 # 簡化版:直接比較密碼(不安全,僅用於開發) # 注意:生產環境必須使用密碼哈希 if user.password_hash != password: return jsonify({'error': '用戶名或密碼錯誤'}), 401 if not user.is_active: return jsonify({'error': '帳號已被停用'}), 403 # 返回用戶信息和簡單令牌 return jsonify({ 'access_token': f'token_{user.id}_{datetime.now().timestamp()}', 'refresh_token': f'refresh_{user.id}_{datetime.now().timestamp()}', 'user': { 'id': user.id, 'username': user.username, 'email': user.email, 'full_name': user.full_name, 'department': user.department, 'position': user.position } }), 200 except Exception as e: return jsonify({'error': f'登入失敗: {str(e)}'}), 500 @app.route('/api/auth/register', methods=['POST']) def register(): """用戶註冊""" try: data = request.get_json() # 驗證必填欄位 required_fields = ['username', 'email', 'password', 'full_name', 'department', 'position', 'employee_id'] for field in required_fields: if not data.get(field): return jsonify({'error': f'{field} 是必填欄位'}), 400 # 檢查用戶名是否已存在 if User.query.filter_by(username=data['username']).first(): return jsonify({'error': '用戶名已存在'}), 409 # 檢查郵箱是否已存在 if User.query.filter_by(email=data['email']).first(): return jsonify({'error': '郵箱已被註冊'}), 409 # 創建新用戶 user = User( username=data['username'], email=data['email'], full_name=data['full_name'], department=data['department'], position=data['position'], employee_id=data['employee_id'], password_hash=data['password'], # 簡化版:直接存儲密碼 is_active=True ) db.session.add(user) db.session.commit() return jsonify({ 'message': '註冊成功', 'user': { 'id': user.id, 'username': user.username, 'email': user.email, 'full_name': user.full_name } }), 201 except Exception as e: db.session.rollback() return jsonify({'error': f'註冊失敗: {str(e)}'}), 500 @app.route('/api/auth/protected', methods=['GET']) def protected(): """受保護的路由(用於驗證令牌)""" # 簡化版:不做實際驗證,返回默認用戶信息 # 在實際應用中,這裡應該驗證 JWT 令牌並返回對應用戶信息 return jsonify({ 'message': 'Access granted', 'logged_in_as': 'admin', # 默認用戶 'roles': ['admin'] # 默認角色 }), 200 @app.route('/api/capabilities', methods=['GET']) def get_capabilities(): """獲取所有啟用的能力項目""" capabilities = Capability.query.filter_by(is_active=True).all() return jsonify({ 'capabilities': [{ 'id': cap.id, 'name': cap.name, 'l1_description': cap.l1_description, 'l2_description': cap.l2_description, 'l3_description': cap.l3_description, 'l4_description': cap.l4_description, 'l5_description': cap.l5_description } for cap in capabilities] }) @app.route('/api/department-capabilities/', methods=['GET']) def get_department_capabilities(department): """獲取特定部門選擇的能力項目""" # 查詢該部門已選擇的能力項目ID dept_caps = DepartmentCapability.query.filter_by(department=department).all() capability_ids = [dc.capability_id for dc in dept_caps] # 獲取對應的能力項目詳細信息 capabilities = Capability.query.filter( Capability.id.in_(capability_ids), Capability.is_active == True ).all() return jsonify({ 'department': department, 'capabilities': [{ 'id': cap.id, 'name': cap.name, 'l1_description': cap.l1_description, 'l2_description': cap.l2_description, 'l3_description': cap.l3_description, 'l4_description': cap.l4_description, 'l5_description': cap.l5_description } for cap in capabilities] }) @app.route('/api/department-capabilities/', methods=['POST']) def set_department_capabilities(department): """設定部門的能力項目(部門主管使用)""" data = request.get_json() capability_ids = data.get('capability_ids', []) if not capability_ids: return jsonify({'error': '請至少選擇一個能力項目'}), 400 try: # 先刪除該部門現有的所有能力項目關聯 DepartmentCapability.query.filter_by(department=department).delete() # 添加新的能力項目關聯 for cap_id in capability_ids: dept_cap = DepartmentCapability( department=department, capability_id=cap_id ) db.session.add(dept_cap) db.session.commit() return jsonify({ 'success': True, 'message': f'{department}部門的能力項目設定成功', 'capability_count': len(capability_ids) }), 200 except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @app.route('/api/capabilities/import-csv', methods=['POST']) def import_capabilities_csv(): """從 CSV 檔案匯入能力項目""" if 'file' not in request.files: return jsonify({'error': '未上傳檔案'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': '檔案名稱為空'}), 400 if not file.filename.endswith('.csv'): return jsonify({'error': '請上傳 CSV 檔案'}), 400 try: # 讀取 CSV 檔案 stream = io.StringIO(file.stream.read().decode("UTF-8"), newline=None) csv_reader = csv.DictReader(stream) imported_count = 0 skipped_count = 0 errors = [] for row_num, row in enumerate(csv_reader, start=2): # start=2 因為第1行是標題 try: # 驗證必要欄位 if not row.get('name'): errors.append(f"第 {row_num} 行:能力名稱不能為空") skipped_count += 1 continue # 檢查是否已存在相同名稱的能力項目 existing = Capability.query.filter_by(name=row['name']).first() if existing: # 更新現有能力項目 existing.l1_description = row.get('l1_description', '') existing.l2_description = row.get('l2_description', '') existing.l3_description = row.get('l3_description', '') existing.l4_description = row.get('l4_description', '') existing.l5_description = row.get('l5_description', '') existing.is_active = True else: # 建立新的能力項目 capability = Capability( name=row['name'], l1_description=row.get('l1_description', ''), l2_description=row.get('l2_description', ''), l3_description=row.get('l3_description', ''), l4_description=row.get('l4_description', ''), l5_description=row.get('l5_description', ''), is_active=True ) db.session.add(capability) imported_count += 1 except Exception as e: errors.append(f"第 {row_num} 行發生錯誤:{str(e)}") skipped_count += 1 db.session.commit() return jsonify({ 'success': True, 'message': f'匯入完成:成功 {imported_count} 筆,跳過 {skipped_count} 筆', 'imported_count': imported_count, 'skipped_count': skipped_count, 'errors': errors }), 200 except Exception as e: db.session.rollback() return jsonify({'error': f'匯入失敗:{str(e)}'}), 500 @app.route('/api/assessments', methods=['POST']) def create_assessment(): data = request.get_json() # 驗證必填欄位 required_fields = ['department', 'position', 'assessment_data'] for field in required_fields: if field not in data: return jsonify({'error': f'Missing required field: {field}'}), 400 # 創建新評估 assessment = Assessment( user_id=1, # 簡化版使用固定用戶ID department=data['department'], position=data['position'], employee_name=data.get('employee_name'), assessment_data=json.dumps(data['assessment_data']) ) db.session.add(assessment) db.session.commit() return jsonify({ 'success': True, 'message': '評估資料儲存成功', 'assessment_id': assessment.id }), 201 @app.route('/api/assessments', methods=['GET']) def get_assessments(): assessments = Assessment.query.order_by(Assessment.created_at.desc()).all() result = [] for assessment in assessments: assessment_data = json.loads(assessment.assessment_data) if isinstance(assessment.assessment_data, str) else assessment.assessment_data result.append({ 'id': assessment.id, 'department': assessment.department, 'position': assessment.position, 'employee_name': assessment.employee_name, 'assessment_data': assessment_data, 'created_at': assessment.created_at.isoformat() }) return jsonify({'assessments': result}) @app.route('/api/star-feedbacks', methods=['POST']) def create_star_feedback(): data = request.get_json() # 驗證必填欄位 required_fields = ['evaluator_name', 'evaluatee_name', 'evaluatee_department', 'evaluatee_position', 'situation', 'task', 'action', 'result', 'score'] for field in required_fields: if field not in data: return jsonify({'error': f'Missing required field: {field}'}), 400 # 計算點數 score = data['score'] points_earned = score * 10 # 創建 STAR 回饋 feedback = StarFeedback( evaluator_name=data['evaluator_name'], evaluatee_name=data['evaluatee_name'], evaluatee_department=data['evaluatee_department'], evaluatee_position=data['evaluatee_position'], situation=data['situation'], task=data['task'], action=data['action'], result=data['result'], score=score, points_earned=points_earned ) db.session.add(feedback) # 更新員工積分 employee = EmployeePoint.query.filter_by(employee_name=data['evaluatee_name']).first() if employee: employee.total_points += points_earned employee.monthly_points += points_earned else: employee = EmployeePoint( employee_name=data['evaluatee_name'], department=data['evaluatee_department'], position=data['evaluatee_position'], total_points=points_earned, monthly_points=points_earned ) db.session.add(employee) db.session.commit() return jsonify({ 'success': True, 'message': '回饋資料儲存成功', 'points_earned': points_earned }), 201 @app.route('/api/star-feedbacks', methods=['GET']) def get_star_feedbacks(): feedbacks = StarFeedback.query.order_by(StarFeedback.created_at.desc()).all() result = [] for feedback in feedbacks: result.append({ 'id': feedback.id, 'evaluator_name': feedback.evaluator_name, 'evaluatee_name': feedback.evaluatee_name, 'evaluatee_department': feedback.evaluatee_department, 'evaluatee_position': feedback.evaluatee_position, 'situation': feedback.situation, 'task': feedback.task, 'action': feedback.action, 'result': feedback.result, 'score': feedback.score, 'points_earned': feedback.points_earned, 'feedback_date': feedback.feedback_date.isoformat(), 'created_at': feedback.created_at.isoformat() }) return jsonify({'feedbacks': result}) @app.route('/api/dashboard/me', methods=['GET']) def get_dashboard_data(): """獲取個人儀表板數據""" # 模擬用戶數據(簡化版) user_points = EmployeePoint.query.first() if not user_points: return jsonify({ 'points_summary': { 'total_points': 0, 'monthly_points': 0, 'department_rank': 0, 'total_rank': 0 }, 'recent_activities': [], 'achievements': [], 'performance_data': [] }) # 計算排名 total_employees = EmployeePoint.query.count() better_employees = EmployeePoint.query.filter(EmployeePoint.total_points > user_points.total_points).count() total_rank = better_employees + 1 # 模擬最近活動 recent_activities = [ { 'type': 'assessment', 'title': '完成能力評估', 'description': '對溝通能力進行了評估', 'points': 20, 'created_at': '2024-01-15T10:30:00Z' }, { 'type': 'feedback', 'title': '收到STAR回饋', 'description': '來自同事的正面回饋', 'points': 15, 'created_at': '2024-01-14T14:20:00Z' } ] # 模擬成就 achievements = [ { 'name': '評估達人', 'description': '完成10次能力評估', 'icon': 'clipboard-check' }, { 'name': '回饋專家', 'description': '提供5次STAR回饋', 'icon': 'star-fill' } ] # 模擬績效數據 performance_data = [ {'month': '1月', 'points': 50}, {'month': '2月', 'points': 75}, {'month': '3月', 'points': 60}, {'month': '4月', 'points': 90}, {'month': '5月', 'points': 80} ] return jsonify({ 'points_summary': { 'total_points': user_points.total_points, 'monthly_points': user_points.monthly_points, 'department_rank': 1, 'total_rank': total_rank }, 'recent_activities': recent_activities, 'achievements': achievements, 'performance_data': performance_data }) @app.route('/api/rankings/total', methods=['GET']) def get_total_rankings(): department = request.args.get('department') limit = request.args.get('limit', 50, type=int) # 構建查詢 query = EmployeePoint.query if department: query = query.filter(EmployeePoint.department == department) employees = query.order_by(EmployeePoint.total_points.desc()).limit(limit).all() total_count = query.count() rankings = [] for rank, employee in enumerate(employees, 1): # 計算百分位數 percentile = ((total_count - rank + 1) / total_count * 100) if total_count > 0 else 0 rankings.append({ 'rank': rank, 'employee_name': employee.employee_name, 'department': employee.department, 'position': employee.position, 'total_points': employee.total_points, 'monthly_points': employee.monthly_points, 'percentile': round(percentile, 1), 'tier': get_tier_by_percentile(percentile) }) return jsonify({ 'rankings': rankings, 'total_count': total_count, 'department_filter': department }) @app.route('/api/rankings/advanced', methods=['GET']) def get_advanced_rankings(): """高級排名系統,包含更多統計信息""" department = request.args.get('department') position = request.args.get('position') min_points = request.args.get('min_points', 0, type=int) max_points = request.args.get('max_points', type=int) # 構建查詢 query = EmployeePoint.query if department: query = query.filter(EmployeePoint.department == department) if position: query = query.filter(EmployeePoint.position.like(f'%{position}%')) if min_points: query = query.filter(EmployeePoint.total_points >= min_points) if max_points: query = query.filter(EmployeePoint.total_points <= max_points) employees = query.order_by(EmployeePoint.total_points.desc()).all() total_count = len(employees) if total_count == 0: return jsonify({ 'rankings': [], 'statistics': {}, 'filters': { 'department': department, 'position': position, 'min_points': min_points, 'max_points': max_points } }) # 計算統計信息 points_list = [emp.total_points for emp in employees] avg_points = sum(points_list) / len(points_list) median_points = sorted(points_list)[len(points_list) // 2] max_points_val = max(points_list) min_points_val = min(points_list) rankings = [] for rank, employee in enumerate(employees, 1): percentile = ((total_count - rank + 1) / total_count * 100) if total_count > 0 else 0 rankings.append({ 'rank': rank, 'employee_name': employee.employee_name, 'department': employee.department, 'position': employee.position, 'total_points': employee.total_points, 'monthly_points': employee.monthly_points, 'percentile': round(percentile, 1), 'tier': get_tier_by_percentile(percentile), 'vs_average': round(employee.total_points - avg_points, 1), 'vs_median': round(employee.total_points - median_points, 1) }) return jsonify({ 'rankings': rankings, 'statistics': { 'total_count': total_count, 'average_points': round(avg_points, 1), 'median_points': median_points, 'max_points': max_points_val, 'min_points': min_points_val, 'standard_deviation': round(calculate_standard_deviation(points_list), 1) }, 'filters': { 'department': department, 'position': position, 'min_points': min_points, 'max_points': max_points } }) def get_tier_by_percentile(percentile): """根據百分位數返回等級""" if percentile >= 95: return {'name': '大師', 'color': 'danger', 'icon': 'crown'} elif percentile >= 85: return {'name': '專家', 'color': 'warning', 'icon': 'star-fill'} elif percentile >= 70: return {'name': '熟練', 'color': 'info', 'icon': 'award'} elif percentile >= 50: return {'name': '良好', 'color': 'success', 'icon': 'check-circle'} else: return {'name': '基礎', 'color': 'secondary', 'icon': 'circle'} def calculate_standard_deviation(data): """計算標準差""" if len(data) <= 1: return 0 mean = sum(data) / len(data) variance = sum((x - mean) ** 2 for x in data) / (len(data) - 1) return variance ** 0.5 @app.route('/api/notifications', methods=['GET']) def get_notifications(): """獲取用戶通知""" # 模擬通知數據 notifications = [ { 'id': 1, 'type': 'achievement', 'title': '🎉 恭喜獲得新成就!', 'message': '您已完成10次能力評估,獲得「評估達人」徽章', 'is_read': False, 'created_at': '2024-01-15T10:30:00Z', 'icon': 'trophy-fill', 'color': 'warning' }, { 'id': 2, 'type': 'ranking', 'title': '📈 排名更新', 'message': '您的總排名上升了3位,目前排名第5名', 'is_read': False, 'created_at': '2024-01-14T15:20:00Z', 'icon': 'arrow-up-circle', 'color': 'success' }, { 'id': 3, 'type': 'feedback', 'title': '⭐ 收到新回饋', 'message': '同事張三為您提供了STAR回饋,請查看詳情', 'is_read': True, 'created_at': '2024-01-13T09:15:00Z', 'icon': 'star-fill', 'color': 'info' }, { 'id': 4, 'type': 'system', 'title': '🔔 系統通知', 'message': '新的評估項目已上線,歡迎體驗新功能', 'is_read': True, 'created_at': '2024-01-12T14:00:00Z', 'icon': 'bell-fill', 'color': 'primary' } ] return jsonify({ 'notifications': notifications, 'unread_count': len([n for n in notifications if not n['is_read']]) }) @app.route('/api/notifications//read', methods=['POST']) def mark_notification_read(notification_id): """標記通知為已讀""" # 在實際應用中,這裡會更新數據庫 return jsonify({'success': True, 'message': '通知已標記為已讀'}) @app.route('/api/notifications/read-all', methods=['POST']) def mark_all_notifications_read(): """標記所有通知為已讀""" # 在實際應用中,這裡會更新數據庫 return jsonify({'success': True, 'message': '所有通知已標記為已讀'}) @app.route('/api/admin/users', methods=['GET']) def get_admin_users(): """獲取所有用戶(管理員功能)""" users = User.query.all() users_data = [] for user in users: users_data.append({ 'id': user.id, 'username': user.username, 'email': user.email, 'full_name': user.full_name, 'department': user.department, 'position': user.position, 'employee_id': user.employee_id, 'is_active': user.is_active, 'created_at': user.created_at.isoformat() if user.created_at else None }) return jsonify({'users': users_data}) @app.route('/api/admin/users/', methods=['PUT']) def update_user(user_id): """更新用戶信息(管理員功能)""" user = User.query.get_or_404(user_id) data = request.get_json() if 'is_active' in data: user.is_active = data['is_active'] if 'department' in data: user.department = data['department'] if 'position' in data: user.position = data['position'] db.session.commit() return jsonify({'success': True, 'message': '用戶信息已更新'}) @app.route('/api/admin/statistics', methods=['GET']) def get_admin_statistics(): """獲取管理員統計信息""" total_users = User.query.count() active_users = User.query.filter_by(is_active=True).count() total_assessments = Assessment.query.count() total_feedbacks = StarFeedback.query.count() # 部門統計 department_stats = db.session.query( User.department, db.func.count(User.id).label('count') ).group_by(User.department).all() # 積分統計 points_stats = db.session.query( db.func.avg(EmployeePoint.total_points).label('avg_points'), db.func.max(EmployeePoint.total_points).label('max_points'), db.func.min(EmployeePoint.total_points).label('min_points') ).first() return jsonify({ 'total_users': total_users, 'active_users': active_users, 'total_assessments': total_assessments, 'total_feedbacks': total_feedbacks, 'department_stats': [{'department': d[0], 'count': d[1]} for d in department_stats], 'points_stats': { 'average': round(points_stats.avg_points or 0, 1), 'maximum': points_stats.max_points or 0, 'minimum': points_stats.min_points or 0 } }) def create_sample_data(): """創建樣本數據""" # 創建能力項目 capabilities = [ Capability( name='溝通能力', l1_description='基本溝通', l2_description='有效溝通', l3_description='專業溝通', l4_description='領導溝通', l5_description='戰略溝通' ), Capability( name='技術能力', l1_description='基礎技術', l2_description='熟練技術', l3_description='專業技術', l4_description='專家技術', l5_description='大師技術' ), Capability( name='領導能力', l1_description='自我管理', l2_description='團隊協作', l3_description='團隊領導', l4_description='部門領導', l5_description='戰略領導' ) ] for cap in capabilities: existing = Capability.query.filter_by(name=cap.name).first() if not existing: db.session.add(cap) # 創建測試帳號 test_accounts = [ { 'username': 'admin', 'email': 'admin@company.com', 'full_name': '系統管理員', 'department': 'IT', 'position': '系統管理員', 'password_hash': 'admin123' # 簡化版直接存儲密碼 }, { 'username': 'hr_manager', 'email': 'hr@company.com', 'full_name': 'HR主管', 'department': 'HR', 'position': '人力資源主管', 'password_hash': 'hr123' }, { 'username': 'user', 'email': 'user@company.com', 'full_name': '一般用戶', 'department': 'IT', 'position': '軟體工程師', 'password_hash': 'user123' } ] for account in test_accounts: existing_user = User.query.filter_by(username=account['username']).first() if not existing_user: user = User(**account) db.session.add(user) print(f"創建測試帳號: {account['username']}") # 創建樣本積分數據 sample_points_data = [ { 'employee_name': '系統管理員', 'department': 'IT', 'position': '系統管理員', 'total_points': 150, 'monthly_points': 50 }, { 'employee_name': 'HR主管', 'department': 'HR', 'position': '人力資源主管', 'total_points': 120, 'monthly_points': 40 }, { 'employee_name': '一般用戶', 'department': 'IT', 'position': '軟體工程師', 'total_points': 80, 'monthly_points': 30 } ] for points_data in sample_points_data: existing = EmployeePoint.query.filter_by(employee_name=points_data['employee_name']).first() if not existing: points = EmployeePoint(**points_data) db.session.add(points) db.session.commit() print("測試帳號和樣本數據創建完成") if __name__ == '__main__': with app.app_context(): # 創建所有數據庫表 db.create_all() print("數據庫表創建成功!") # 創建樣本數據 create_sample_data() print("=" * 60) print("夥伴對齊系統已啟動!") print("=" * 60) print("[WEB] 訪問地址: http://localhost:5000") print() print("[ACCOUNT] 測試帳號資訊:") print(" 管理員: admin / admin123") print(" HR主管: hr_manager / hr123") print(" 一般用戶: user / user123") print() print("[FEATURES] 功能包括:") print("- 能力評估系統") print("- STAR 回饋系統") print("- 排名系統") print("- 數據導出") print() print("[TIP] 提示: 登入頁面會顯示測試帳號資訊和快速登入按鈕") print("=" * 60) # 啟動應用程式 app.run(debug=True, host='0.0.0.0', port=5000)