feat: 任务批量创建

This commit is contained in:
DengDai
2025-12-09 21:32:32 +08:00
parent 02ecea06f8
commit 837c8227fb
2 changed files with 212 additions and 52 deletions

View File

@@ -101,6 +101,68 @@ def create_task(group_id):
return jsonify({'message': '任务创建成功', 'task_id': task.id}), 201 return jsonify({'message': '任务创建成功', 'task_id': task.id}), 201
# 批量创建任务(管理员)
@tasks_bp.route('/groups/<int:group_id>/tasks/batch', methods=['POST'])
@admin_required
def batch_create_tasks(group_id):
data = request.json
tasks_data = data.get('tasks', [])
if not tasks_data:
return jsonify({'error': '任务列表不能为空'}), 400
user_id = get_jwt_identity()
created_tasks = []
errors = []
for idx, task_data in enumerate(tasks_data):
try:
if not task_data.get('series_name'):
errors.append(f'{idx+1}行:剧集名称不能为空')
continue
if not task_data.get('series_date'):
errors.append(f'{idx+1}行:日期不能为空')
continue
try:
series_date = datetime.strptime(task_data['series_date'], '%Y%m%d').date()
except:
errors.append(f'{idx+1}行:日期格式错误')
continue
task = Task(
group_id=group_id,
series_name=task_data['series_name'],
series_date=series_date,
priority=task_data.get('priority', ''),
created_by=user_id
)
db.session.add(task)
db.session.flush()
log = TaskLog(
task_id=task.id,
user_id=user_id,
action='create',
comment=f'批量创建任务:{task.series_name}'
)
db.session.add(log)
created_tasks.append(task.id)
except Exception as e:
errors.append(f'{idx+1}行:{str(e)}')
db.session.commit()
return jsonify({
'message': f'成功创建{len(created_tasks)}个任务',
'created': len(created_tasks),
'errors': errors
}), 201
# 认领任务 # 认领任务
@tasks_bp.route('/tasks/<int:task_id>/claim', methods=['POST']) @tasks_bp.route('/tasks/<int:task_id>/claim', methods=['POST'])
@login_required @login_required

View File

@@ -8,14 +8,22 @@
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-8"> <div class="col-md-8">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header d-flex justify-content-between align-items-center">
<h4>创建新任务</h4> <h4>创建新任务</h4>
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="mode" id="mode-single" value="single" checked>
<label class="btn btn-outline-primary" for="mode-single">单个创建</label>
<input type="radio" class="btn-check" name="mode" id="mode-batch" value="batch">
<label class="btn btn-outline-primary" for="mode-batch">批量创建</label>
</div>
</div> </div>
<div class="card-body"> <div class="card-body">
<form id="create-task-form"> <form id="create-task-form">
<!-- 单个创建模式 -->
<div id="single-mode">
<div class="mb-3"> <div class="mb-3">
<label for="series-name" class="form-label">剧集名称 <span class="text-danger">*</span></label> <label for="series-name" class="form-label">剧集名称 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="series-name" required <input type="text" class="form-control" id="series-name"
placeholder="例如:某某剧集 S01E01"> placeholder="例如:某某剧集 S01E01">
</div> </div>
@@ -28,7 +36,7 @@
<div class="mb-3"> <div class="mb-3">
<label for="series-date" class="form-label">剧集更新日期 <span class="text-danger">*</span></label> <label for="series-date" class="form-label">剧集更新日期 <span class="text-danger">*</span></label>
<input type="date" class="form-control" id="series-date" required> <input type="date" class="form-control" id="series-date">
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -39,6 +47,19 @@
<option value="低"></option> <option value="低"></option>
</select> </select>
</div> </div>
</div>
<!-- 批量创建模式 -->
<div id="batch-mode" style="display:none;">
<div class="mb-3">
<label for="batch-input" class="form-label">批量输入 <span class="text-danger">*</span></label>
<textarea class="form-control" id="batch-input" rows="10"
placeholder="每行一个任务,格式:剧集名称,日期,优先级&#10;例如:&#10;剧集1,20251209,高&#10;剧集2,20251209,中&#10;剧集3,20251209,低"></textarea>
<small class="form-text text-muted">
格式说明:剧集名称,日期(YYYYMMDD),优先级(高/中/低)
</small>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end"> <div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="/tasks" class="btn btn-secondary">取消</a> <a href="/tasks" class="btn btn-secondary">取消</a>
@@ -58,9 +79,31 @@ $(document).ready(function() {
// 设置默认日期为今天 // 设置默认日期为今天
$('#series-date').val(new Date().toISOString().split('T')[0]); $('#series-date').val(new Date().toISOString().split('T')[0]);
// 模式切换
$('input[name="mode"]').change(function() {
if ($(this).val() === 'single') {
$('#single-mode').show();
$('#batch-mode').hide();
} else {
$('#single-mode').hide();
$('#batch-mode').show();
}
});
$('#create-task-form').submit(function(e) { $('#create-task-form').submit(function(e) {
e.preventDefault(); e.preventDefault();
const mode = $('input[name="mode"]:checked').val();
if (mode === 'single') {
createSingleTask();
} else {
createBatchTasks();
}
});
});
function createSingleTask() {
const data = { const data = {
series_name: $('#series-name').val(), series_name: $('#series-name').val(),
series_link: $('#series-link').val() || null, series_link: $('#series-link').val() || null,
@@ -85,7 +128,62 @@ $(document).ready(function() {
alert(error); alert(error);
} }
}); });
}
function createBatchTasks() {
const input = $('#batch-input').val().trim();
if (!input) {
alert('请输入任务数据');
return;
}
const lines = input.split('\n');
const tasks = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) continue;
const parts = line.split(',');
if (parts.length !== 3) {
alert(`${i+1}行格式错误,应为:剧集名称,日期,优先级`);
return;
}
tasks.push({
series_name: parts[0].trim(),
series_date: parts[1].trim(),
priority: parts[2].trim()
}); });
}); }
if (tasks.length === 0) {
alert('没有有效的任务数据');
return;
}
$.ajax({
url: '/api/groups/1/tasks/batch',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('access_token'),
'Content-Type': 'application/json'
},
data: JSON.stringify({ tasks: tasks }),
success: function(response) {
let message = response.message;
if (response.errors && response.errors.length > 0) {
message += '\n\n错误信息\n' + response.errors.join('\n');
}
alert(message);
window.location.href = '/tasks';
},
error: function(xhr) {
const error = xhr.responseJSON?.error || '批量创建失败';
alert(error);
}
});
}
</script> </script>
{% endblock %} {% endblock %}