问卷复制

master
lion 6 days ago
parent dc5587e0a2
commit 78e536f262

@ -180,6 +180,17 @@ class CourseContentEvaluationsController extends BaseController
$model = DB::transaction(function () {
$all = request()->all();
$model = !empty($all['id']) ? $this->model->whereKey($all['id'])->lockForUpdate()->firstOrFail() : new CourseContentEvaluation();
$copySource = null;
$fields = ['title', 'desc', 'course_id', 'course_content_id', 'type_id', 'start_time', 'end_time', 'status', 'audience_course_ids'];
if (array_key_exists('copy_from_id', $all)) {
if ($model->exists || !is_scalar($all['copy_from_id']) || !ctype_digit((string) $all['copy_from_id']) || (int) $all['copy_from_id'] < 1) {
throw new \InvalidArgumentException('复制问卷仅可用于新增,请选择有效的来源问卷');
}
$copySource = $this->model->whereKey($all['copy_from_id'])->lockForUpdate()->first();
if (!$copySource) throw new \InvalidArgumentException('来源问卷不存在或已删除');
$all = array_replace(array_intersect_key($copySource->attributesToArray(), array_flip($fields)), ['audience_course_ids' => $copySource->audience_course_ids ?: []], $all);
$all['status'] = 0;
}
if ($model->exists && $model->courseContentEvaluationForms()->exists()) {
foreach (['title', 'desc', 'course_id', 'course_content_id', 'type_id'] as $field) {
if (array_key_exists($field, $all) && (string) $all[$field] !== (string) $model->$field) {
@ -195,7 +206,6 @@ class CourseContentEvaluationsController extends BaseController
$all['audience_course_ids'] = $ids;
}
$original = $model->getOriginal();
$fields = ['title', 'desc', 'course_id', 'course_content_id', 'type_id', 'start_time', 'end_time', 'status', 'audience_course_ids'];
$model->fill(array_intersect_key($all, array_flip($fields)));
if (!$model->title) throw new \InvalidArgumentException('请输入问卷标题');
if ($model->start_time && $model->end_time && strtotime($model->start_time) >= strtotime($model->end_time)) {
@ -210,6 +220,18 @@ class CourseContentEvaluationsController extends BaseController
if (\Illuminate\Support\Facades\Schema::hasColumn($model->getTable(), 'department_id')) $model->department_id = $this->getUser()->department_id;
}
$model->save();
if ($copySource) {
$scheduleIds = array_filter(array_map('trim', explode(',', (string) $model->course_content_id)));
foreach ($copySource->courseContentEvaluationAsks()->orderBy('sort')->orderBy('id')->lockForUpdate()->get() as $sourceQuestion) {
$question = $sourceQuestion->replicate();
$question->course_content_evaluation_id = $model->id;
$question->course_id = $model->course_id;
if ((string) $copySource->course_id !== (string) $model->course_id || !in_array((string) $question->course_content_id, $scheduleIds, true)) $question->course_content_id = null;
$question->admin_id = $this->getUserId();
$question->department_id = $this->getUser()->department_id;
$question->save();
}
}
$this->saveLogs($original, $model);
return $model;
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -72,6 +72,70 @@ class SurveyWorkflowTest extends TestCase
return $response->json('id');
}
public function testCopyCreatesIndependentDraftWithAllDefinitionsAndNoReplies(): void
{
Schema::create('courses', function (Blueprint $table) { $table->id(); $table->softDeletes(); });
DB::table('courses')->insert([['id' => 11], ['id' => 12]]);
DB::table('course_content_evaluations')->where('id', 10)->update([
'desc' => '<p>富文本说明</p>', 'course_id' => '11', 'course_content_id' => '9', 'type_id' => '3',
'audience_course_ids' => json_encode([11, 12]), 'start_time' => '2026-12-01 00:00:00', 'end_time' => '2026-12-31 23:59:59',
]);
$definitions = [
['name' => '第一章', 'field' => 'chapter', 'edit_input' => 'section', 'sort' => 1],
['name' => '是否参加', 'field' => 'attend', 'edit_input' => 'radio', 'sort' => 2, 'need_fill' => true, 'select_item' => [['key' => 'yes', 'value' => '参加'], ['key' => 'no', 'value' => '不参加']]],
['name' => '会场', 'field' => 'venues', 'edit_input' => 'checkbox', 'sort' => 3, 'select_item' => [['key' => 'a', 'value' => '甲'], ['key' => 'b', 'value' => '乙']], 'config' => ['min_choices' => 1, 'max_choices' => 2, 'option_notes' => ['a' => ['placeholder' => '问题']], 'visible_when' => ['field' => 'attend', 'values' => ['yes'], 'required_values' => ['yes']]]],
['name' => '组合题', 'field' => 'group', 'edit_input' => 'multi_dimension', 'sort' => 4, 'dimensions' => [['field' => 'count', 'name' => '数量', 'edit_input' => 'number', 'config' => ['min' => 0, 'integer' => true]]]],
['name' => '资料', 'field' => 'docs', 'edit_input' => 'file', 'sort' => 5, 'config' => ['allowed_extensions' => ['pdf', 'docx'], 'max_files' => 2]],
['name' => '姓名', 'field' => 'name', 'edit_input' => 'text', 'sort' => 6, 'config' => ['user_field' => 'name']],
];
foreach ($definitions as $definition) \App\Models\CourseContentEvaluationAsk::create($definition + ['course_content_evaluation_id' => 10, 'course_id' => 11, 'course_content_id' => 9, 'admin_id' => 99]);
DB::table('course_content_evaluation_forms')->insert(['course_content_evaluation_id' => 10, 'user_id' => 200]);
$originals = \App\Models\CourseContentEvaluationAsk::where('course_content_evaluation_id', 10)->orderBy('sort')->get();
$response = $this->postJson('/api/admin/course-content-evaluations/save', ['copy_from_id' => 10, 'title' => '新问卷', 'status' => 1]);
$response->assertOk()->assertJsonPath('title', '新问卷')->assertJsonPath('status', 0)->assertJsonPath('desc', '<p>富文本说明</p>')->assertJsonPath('audience_course_ids', [11, 12]);
$id = $response->json('id'); $this->assertNotSame(10, $id);
$copies = \App\Models\CourseContentEvaluationAsk::where('course_content_evaluation_id', $id)->orderBy('sort')->get();
$this->assertCount(6, $copies);
foreach ($copies as $index => $question) {
$source = $originals[$index];
$this->assertNotSame($source->id, $question->id);
foreach (['field', 'name', 'edit_input', 'rule', 'help', 'sort', 'dimensions', 'config', 'select_item', 'need_fill', 'allow_input'] as $key) $this->assertSame($source->$key, $question->$key, $key);
$this->assertSame(9, (int) $question->course_content_id);
$this->assertSame(1, (int) $question->admin_id);
}
$this->assertSame(0, DB::table('course_content_evaluation_forms')->where('course_content_evaluation_id', $id)->count());
$this->postJson('/api/admin/course-content-evaluation-ask/save', ['id' => $copies[1]->id, 'name' => '新题目'])->assertOk()->assertJsonPath('name', '新题目');
$this->assertSame('是否参加', $originals[1]->fresh()->name);
$this->assertSame('1', (string) DB::table('course_content_evaluations')->where('id', 10)->value('status'));
$otherId = $this->postJson('/api/admin/course-content-evaluations/save', ['copy_from_id' => 10, 'title' => '其他课程', 'course_id' => 12, 'course_content_id' => '22'])->assertOk()->json('id');
$this->assertSame(0, \App\Models\CourseContentEvaluationAsk::where('course_content_evaluation_id', $otherId)->whereNotNull('course_content_id')->count());
}
public function testInvalidCopySourceCannotCreateOrOverwriteSurvey(): void
{
$url = '/api/admin/course-content-evaluations/save';
foreach ([['copy_from_id' => 999], ['copy_from_id' => []], ['id' => 10, 'copy_from_id' => 10]] as $input) {
$this->postJson($url, $input + ['title' => '无效复制'])->assertJsonPath('errcode', 10001);
}
$this->assertSame(1, DB::table('course_content_evaluations')->count());
$this->assertSame('培训问卷', DB::table('course_content_evaluations')->where('id', 10)->value('title'));
}
public function testCopyFailureRollsBackNewSurveyAndQuestions(): void
{
Schema::create('courses', function (Blueprint $table) { $table->id(); $table->softDeletes(); });
$this->createQuestion();
$failCopy = true;
\App\Models\CourseContentEvaluationAsk::creating(function ($question) use (&$failCopy) {
if ($failCopy && (int) $question->course_content_evaluation_id !== 10) throw new \RuntimeException('copy failed');
});
try {
$this->postJson('/api/admin/course-content-evaluations/save', ['copy_from_id' => 10, 'title' => '失败副本'])->assertStatus(500);
} finally { $failCopy = false; }
$this->assertSame(1, DB::table('course_content_evaluations')->count());
$this->assertSame(1, DB::table('course_content_evaluation_asks')->count());
}
public function testSurveyAccessRequiresOnlyMobileEvenWhenOtherProfileFieldsAreMissing(): void
{
$id = $this->createQuestion();

Loading…
Cancel
Save