Initial commit

This commit is contained in:
2025-10-28 15:50:53 +08:00
commit 297ef231c5
31 changed files with 12708 additions and 0 deletions

952
simple_app.py Normal file
View File

@@ -0,0 +1,952 @@
#!/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)
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/<department>', 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/<department>', 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/<int:notification_id>/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/<int:user_id>', 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)