feat(time-tracking): 添加个人工时记录系统设计文档
- 完成系统架构和数据模型设计,包括项目、工时记录、休息日和周期表模型 - 设计项目管理模块,支持传统项目与PSI项目管理及批量导入功能 - 规划工时记录模块,含日期、事件描述、项目选择及工时计算规则 - 定义休息日分类,支持周末、国定节假日、个人假期及调休工时管理 - 制定统计分析模块设计,支持按Cut-Off周期的周统计与项目工时分布 - 设计周期管理模块,提供周期设置及预设模板功能 - 制定用户界面布局及各页面表单、样式设计方案 - 规划RESTful API端点,涵盖项目、工时记录、休息日、周期及统计数据操作 - 设计数据流示意,阐明操作流程及前后端交互逻辑 - 制定数据存储方案,包括SQLite数据库配置及备份导出机制
This commit is contained in:
203
backend/api/timerecords.py
Normal file
203
backend/api/timerecords.py
Normal file
@@ -0,0 +1,203 @@
|
||||
from flask import Blueprint, request, jsonify
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy import create_engine, and_
|
||||
from backend.models.models import TimeRecord, Project, Holiday
|
||||
from backend.models.utils import *
|
||||
from datetime import datetime, date
|
||||
import json
|
||||
|
||||
timerecords_bp = Blueprint('timerecords', __name__)
|
||||
|
||||
def get_db_session():
|
||||
"""获取数据库会话"""
|
||||
engine = create_engine('sqlite:///data/timetrack.db')
|
||||
Session = sessionmaker(bind=engine)
|
||||
return Session()
|
||||
|
||||
@timerecords_bp.route('/api/timerecords', methods=['GET'])
|
||||
def get_timerecords():
|
||||
"""获取工时记录列表"""
|
||||
try:
|
||||
session = get_db_session()
|
||||
|
||||
# 获取查询参数
|
||||
start_date = request.args.get('start_date')
|
||||
end_date = request.args.get('end_date')
|
||||
project_id = request.args.get('project_id')
|
||||
|
||||
query = session.query(TimeRecord)
|
||||
|
||||
# 应用筛选条件
|
||||
if start_date:
|
||||
query = query.filter(TimeRecord.date >= datetime.strptime(start_date, '%Y-%m-%d').date())
|
||||
if end_date:
|
||||
query = query.filter(TimeRecord.date <= datetime.strptime(end_date, '%Y-%m-%d').date())
|
||||
if project_id:
|
||||
query = query.filter(TimeRecord.project_id == int(project_id))
|
||||
|
||||
records = query.order_by(TimeRecord.date.desc()).all()
|
||||
|
||||
result = []
|
||||
for record in records:
|
||||
record_dict = record.to_dict()
|
||||
# 添加星期几信息
|
||||
if record.date:
|
||||
record_dict['day_of_week'] = get_day_of_week_chinese(record.date)
|
||||
result.append(record_dict)
|
||||
|
||||
session.close()
|
||||
return jsonify({'success': True, 'data': result})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@timerecords_bp.route('/api/timerecords', methods=['POST'])
|
||||
def create_timerecord():
|
||||
"""创建工时记录"""
|
||||
try:
|
||||
data = request.json
|
||||
session = get_db_session()
|
||||
|
||||
# 验证必填字段
|
||||
if not data.get('date'):
|
||||
return jsonify({'success': False, 'error': '日期为必填项'}), 400
|
||||
|
||||
record_date = datetime.strptime(data['date'], '%Y-%m-%d').date()
|
||||
|
||||
# 检查是否为休息日
|
||||
holidays = session.query(Holiday).all()
|
||||
holiday_info = is_holiday(record_date, holidays)
|
||||
|
||||
# 计算工时
|
||||
hours = data.get('hours', '')
|
||||
if not hours and data.get('start_time') and data.get('end_time'):
|
||||
hours = calculate_hours(data['start_time'], data['end_time'], holiday_info['is_holiday'])
|
||||
elif not hours:
|
||||
hours = '0:00' if holiday_info['is_holiday'] else '-'
|
||||
|
||||
# 获取周信息
|
||||
week_info = get_week_info(record_date)
|
||||
|
||||
# 创建记录
|
||||
record = TimeRecord(
|
||||
date=record_date,
|
||||
event_description=data.get('event_description', ''),
|
||||
project_id=data.get('project_id') if data.get('project_id') else None,
|
||||
start_time=datetime.strptime(data['start_time'], '%H:%M').time() if data.get('start_time') and data['start_time'] != '-' else None,
|
||||
end_time=datetime.strptime(data['end_time'], '%H:%M').time() if data.get('end_time') and data['end_time'] != '-' else None,
|
||||
activity_num=data.get('activity_num', ''),
|
||||
hours=hours,
|
||||
is_holiday=holiday_info['is_holiday'],
|
||||
is_working_on_holiday=holiday_info['is_holiday'] and hours not in ['-', '0:00'],
|
||||
holiday_type=holiday_info['holiday_type'],
|
||||
week_info=week_info
|
||||
)
|
||||
|
||||
session.add(record)
|
||||
session.commit()
|
||||
|
||||
result = record.to_dict()
|
||||
if record.date:
|
||||
result['day_of_week'] = get_day_of_week_chinese(record.date)
|
||||
|
||||
session.close()
|
||||
|
||||
return jsonify({'success': True, 'data': result})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@timerecords_bp.route('/api/timerecords/<int:record_id>', methods=['PUT'])
|
||||
def update_timerecord(record_id):
|
||||
"""更新工时记录"""
|
||||
try:
|
||||
data = request.json
|
||||
session = get_db_session()
|
||||
|
||||
record = session.query(TimeRecord).get(record_id)
|
||||
if not record:
|
||||
session.close()
|
||||
return jsonify({'success': False, 'error': '记录不存在'}), 404
|
||||
|
||||
# 更新字段
|
||||
if 'event_description' in data:
|
||||
record.event_description = data['event_description']
|
||||
if 'project_id' in data:
|
||||
record.project_id = data['project_id'] if data['project_id'] else None
|
||||
if 'activity_num' in data:
|
||||
record.activity_num = data['activity_num']
|
||||
|
||||
# 更新时间相关字段
|
||||
if 'start_time' in data:
|
||||
record.start_time = datetime.strptime(data['start_time'], '%H:%M').time() if data['start_time'] and data['start_time'] != '-' else None
|
||||
if 'end_time' in data:
|
||||
record.end_time = datetime.strptime(data['end_time'], '%H:%M').time() if data['end_time'] and data['end_time'] != '-' else None
|
||||
|
||||
# 重新计算工时
|
||||
if 'hours' in data:
|
||||
record.hours = data['hours']
|
||||
elif record.start_time and record.end_time:
|
||||
start_str = record.start_time.strftime('%H:%M')
|
||||
end_str = record.end_time.strftime('%H:%M')
|
||||
record.hours = calculate_hours(start_str, end_str, record.is_holiday)
|
||||
|
||||
# 更新工作日状态
|
||||
record.is_working_on_holiday = record.is_holiday and record.hours not in ['-', '0:00']
|
||||
|
||||
session.commit()
|
||||
|
||||
result = record.to_dict()
|
||||
if record.date:
|
||||
result['day_of_week'] = get_day_of_week_chinese(record.date)
|
||||
|
||||
session.close()
|
||||
|
||||
return jsonify({'success': True, 'data': result})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@timerecords_bp.route('/api/timerecords/<int:record_id>', methods=['DELETE'])
|
||||
def delete_timerecord(record_id):
|
||||
"""删除工时记录"""
|
||||
try:
|
||||
session = get_db_session()
|
||||
|
||||
record = session.query(TimeRecord).get(record_id)
|
||||
if not record:
|
||||
session.close()
|
||||
return jsonify({'success': False, 'error': '记录不存在'}), 404
|
||||
|
||||
session.delete(record)
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
return jsonify({'success': True, 'message': '记录已删除'})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@timerecords_bp.route('/api/timerecords/check_holiday/<string:date_str>', methods=['GET'])
|
||||
def check_holiday(date_str):
|
||||
"""检查指定日期是否为休息日"""
|
||||
try:
|
||||
session = get_db_session()
|
||||
|
||||
check_date = datetime.strptime(date_str, '%Y-%m-%d').date()
|
||||
holidays = session.query(Holiday).all()
|
||||
holiday_info = is_holiday(check_date, holidays)
|
||||
|
||||
result = {
|
||||
'date': date_str,
|
||||
'is_holiday': holiday_info['is_holiday'],
|
||||
'holiday_type': holiday_info['holiday_type'],
|
||||
'holiday_name': holiday_info['holiday_name'],
|
||||
'day_of_week': get_day_of_week_chinese(check_date),
|
||||
'week_info': get_week_info(check_date)
|
||||
}
|
||||
|
||||
session.close()
|
||||
return jsonify({'success': True, 'data': result})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
Reference in New Issue
Block a user