feat: 任务批量创建
This commit is contained in:
62
api/tasks.py
62
api/tasks.py
@@ -101,6 +101,68 @@ def create_task(group_id):
|
||||
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'])
|
||||
@login_required
|
||||
|
||||
@@ -8,14 +8,22 @@
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<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 class="card-body">
|
||||
<form id="create-task-form">
|
||||
<!-- 单个创建模式 -->
|
||||
<div id="single-mode">
|
||||
<div class="mb-3">
|
||||
<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">
|
||||
</div>
|
||||
|
||||
@@ -28,7 +36,7 @@
|
||||
|
||||
<div class="mb-3">
|
||||
<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 class="mb-3">
|
||||
@@ -39,6 +47,19 @@
|
||||
<option value="低">低</option>
|
||||
</select>
|
||||
</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="每行一个任务,格式:剧集名称,日期,优先级 例如: 剧集1,20251209,高 剧集2,20251209,中 剧集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">
|
||||
<a href="/tasks" class="btn btn-secondary">取消</a>
|
||||
@@ -58,9 +79,31 @@ $(document).ready(function() {
|
||||
// 设置默认日期为今天
|
||||
$('#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) {
|
||||
e.preventDefault();
|
||||
|
||||
const mode = $('input[name="mode"]:checked').val();
|
||||
|
||||
if (mode === 'single') {
|
||||
createSingleTask();
|
||||
} else {
|
||||
createBatchTasks();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function createSingleTask() {
|
||||
const data = {
|
||||
series_name: $('#series-name').val(),
|
||||
series_link: $('#series-link').val() || null,
|
||||
@@ -85,7 +128,62 @@ $(document).ready(function() {
|
||||
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>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user