header('医学计算器');
$content->description('列表');
$content->body($this->grid());
});
}
/**
* 创建新的医学计算器
*
* @OA\Post(
* path="/api/medical-calculators",
* summary="创建新的医学计算器",
* tags={"医学计算器"},
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(ref="#/components/schemas/MedicalCalculator")
* ),
* @OA\Response(
* response=201,
* description="创建成功",
* @OA\JsonContent(ref="#/components/schemas/MedicalCalculator")
* )
* )
*/
public function create()
{
return Admin::content(function (Content $content) {
$content->header('医学计算器');
$content->description('新增');
$content->body($this->form());
});
}
/**
* 编辑现有的医学计算器
*
* @OA\Get(
* path="/api/medical-calculators/{id}",
* summary="编辑现有的医学计算器",
* tags={"医学计算器"},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="成功",
* @OA\JsonContent(ref="#/components/schemas/MedicalCalculator")
* )
* )
*
* @param int $id 医学计算器ID
*/
public function edit($id)
{
return Admin::content(function (Content $content) use ($id) {
$content->header('医学计算器');
$content->description('编辑');
$content->body($this->form($id)->edit($id)); // 传递 $id 给 form 方法
});
}
/**
* 计算医学计算器的结果
*
* @OA\Post(
* path="/api/medical-calculators/{id}/calculate",
* summary="计算医学计算器的结果",
* tags={"医学计算器"},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(type="object")
* ),
* @OA\Response(
* response=200,
* description="计算结果",
* @OA\JsonContent(type="object", @OA\Property(property="result", type="string"))
* )
* )
*
* @param Request $request 请求对象
* @param int $id 医学计算器ID
* @return \Illuminate\Http\JsonResponse 计算结果的JSON响应
*/
public function calculate(Request $request, $id)
{
$calculator = MedicalCalculator::findOrFail($id);
$inputs = $request->all();
try {
$result = $calculator->calculateResult($inputs);
return response()->json(['result' => $result]);
} catch (\Exception $e) {
return response()->json(['error' => $e->getMessage()], 400);
}
}
/**
* 获取指定计算器的问题
*
* @OA\Get(
* path="/api/medical-calculators/{id}/questions",
* summary="获取指定计算器的问题",
* tags={"医学计算器"},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="成功",
* @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/MedicalQuestion"))
* )
* )
*
* @param int $id 医学计算器ID
* @return \Illuminate\Http\JsonResponse 问题列表的JSON响应
*/
public function getQuestions($id)
{
$questions = MedicalQuestion::where('medical_calculator_id', $id)->with('options')->get();
return response()->json($questions);
}
/**
* 定义医学计算器的表单
*
* @param int|null $id 医学计算器ID
* @return \Encore\Admin\Form 表单对象
*/
protected function form($id = null)
{
return Admin::form(MedicalCalculator::class, function (Form $form) use ($id) {
$form->text('name', '计算器名称');
$form->text('disease_name', '疾病名称')->rules('nullable');
// 确保传递正确的 calculatorId
$calculatorId = $id ?? $form->model()->id;
$form->html($this->questionsForm($calculatorId));
$form->textarea('formula', '计算公式')->help('直接使用问题的变量名称,例如: weight / (height * height)');
$form->table('results', '结果对照表', function ($table) {
$table->decimal('min_score', 8, 2, '最小分数')->rules('required|numeric');
$table->decimal('max_score', 8, 2, '最大分数')->rules('required|numeric');
$table->text('result', '结果描述');
})->default([])->customFormat(function ($value) {
if (empty($value)) {
return [];
}
if (is_string($value)) {
$decoded = json_decode($value, true);
return is_array($decoded) ? array_values($decoded) : [];
}
return is_array($value) ? array_values($value) : [];
});
$form->textarea('instructions', '使用说明')->rules('nullable');
$form->saving(function (Form $form) {
if (empty($form->results)) {
$form->results = [];
} elseif (is_array($form->results)) {
$form->results = array_values($form->results);
}
});
$form->saved(function (Form $form) {
$this->saveQuestions($form);
admin_toastr('保存成功', 'success');
return redirect()->route('admin.medical-calculators.index');
});
// 在表单显示之前处理 results 字段
if ($form->isEditing()) {
$form->editing(function (Form $form) {
$results = $form->model()->results;
if (is_string($results)) {
$decoded = json_decode($results, true);
$form->results = is_array($decoded) ? array_values($decoded) : [];
} elseif (!is_array($results)) {
$form->results = [];
} else {
$form->results = array_values($results);
}
});
}
Admin::script($this->questionsScript());
});
}
/**
* 生成问题表单的HTML
*
* @param int $calculatorId 医学计算器ID
* @return string 问题表单的HTML
*/
protected function questionsForm($calculatorId)
{
if (!$calculatorId) {
return '
';
}
$questions = MedicalQuestion::where('medical_calculator_id', $calculatorId)->with('options')->get();
$html = '';
foreach ($questions as $index => $question) {
$html .= $this->questionTemplate($index, $question);
}
$html .= '
';
$html .= '';
return $html;
}
/**
* 生成单个问题的HTML模板
*
* @param int|string $index 问题索引
* @param MedicalQuestion|null $question 问题对象
* @return string 单个问题的HTML模板
*/
protected function questionTemplate($index, $question = null)
{
$index = is_numeric($index) ? $index : "' + questionIndex + '";
$html = '';
$html .= '
';
$html .= '
';
$html .= '';
$html .= '';
$html .= '
';
$html .= '
';
$html .= '';
$html .= '';
$html .= '
';
$html .= '
';
$html .= '';
$html .= '';
$html .= '
';
$html .= '
type == 'radio' || $question->type == 'checkbox') ? 'style="display:none;"' : '') . '>';
$html .= '';
$html .= '';
$html .= '
';
$html .= '
type == 'radio' || $question->type == 'checkbox') ? '' : 'style="display:none;"') . '>';
if ($question && $question->options) {
foreach ($question->options as $optionIndex => $option) {
$html .= $this->optionTemplate($index, $optionIndex, $option);
}
}
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
return $html;
}
/**
* 生成单个选项的HTML模板
*
* @param int|string $questionIndex 问题索引
* @param int|string $optionIndex 选项索引
* @param MedicalOption|null $option 选项对象
* @return string 单个选项的HTML模板
*/
protected function optionTemplate($questionIndex, $optionIndex, $option = null)
{
$questionIndex = is_numeric($questionIndex) ? $questionIndex : "' + questionIndex + '";
$optionIndex = is_numeric($optionIndex) ? $optionIndex : "' + optionIndex + '";
$html = '';
$html .= '
';
$html .= '
';
$html .= '';
$html .= '';
$html .= '
';
$html .= '
';
$html .= '';
$html .= '';
$html .= '
';
$html .= '
';
$html .= '
';
return $html;
}
/**
* 生成问题和选项的JavaScript
*
* @return string JavaScript代码
*/
protected function questionsScript()
{
$questionTemplate = json_encode($this->questionTemplate("' + questionIndex + '"));
$optionTemplate = json_encode($this->optionTemplate("' + questionIndex + '", "' + optionIndex + '"));
return <<json($calculators);
}
/**
* 获取指定计算器
*
* @param int $id 医学计算器ID
* @return \Illuminate\Http\JsonResponse 计算器详情
*/
public function show($id)
{
$calculator = MedicalCalculator::findOrFail($id);
return response()->json($calculator);
}
/**
* 更新指定计算器
*
* @param Request $request 请求对象
* @param int $id 医学计算器ID
* @return \Illuminate\Http\JsonResponse 更新后的计算器详情
*/
public function update(Request $request, $id)
{
$calculator = MedicalCalculator::findOrFail($id);
$calculator->update($request->all());
$this->saveQuestions($calculator);
admin_toastr('更新成功', 'success');
return redirect()->route('admin.medical-calculators.index');
}
/**
* 删除指定计算器(支持批量删除)
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse 删除结果
*/
public function destroy($id)
{
$ids = is_array($id) ? $id : [$id];
$successCount = 0;
$failCount = 0;
\Illuminate\Support\Facades\DB::transaction(function () use ($ids, &$successCount, &$failCount) {
// 批量删除关联的问题和选项
$deletedOptionsCount = MedicalOption::whereIn('medical_question_id', function($query) use ($ids) {
$query->select('id')
->from('medical_questions')
->whereIn('medical_calculator_id', $ids);
})->delete();
$deletedQuestionsCount = MedicalQuestion::whereIn('medical_calculator_id', $ids)->delete();
// 删除计算器
$deletedCalculatorsCount = MedicalCalculator::whereIn('id', $ids)->delete();
$successCount = $deletedCalculatorsCount;
$failCount = count($ids) - $deletedCalculatorsCount;
});
$message = "成功删除 {$successCount} 个计算器";
if ($failCount > 0) {
$message .= ",{$failCount} 个计算器删除失败";
}
return response()->json(['message' => $message, 'status' => true]);
}
/**
* 保存问题和选项
*
* @param Form|MedicalCalculator $formOrModel 表单对象或模型实例
*/
protected function saveQuestions($formOrModel)
{
if ($formOrModel instanceof Form) {
$formModelId = $formOrModel->model()->id;
} elseif ($formOrModel instanceof MedicalCalculator) {
$formModelId = $formOrModel->id;
} else {
throw new \InvalidArgumentException('Invalid argument type');
}
$questionsData = request()->input('questions');
if (!is_array($questionsData)) {
return; // 如果 $questionsData 不是数组,直接返回
}
foreach ($questionsData as $index => $questionData) {
if (!isset($questionData['question']) || !isset($questionData['type'])) {
continue;
}
try {
$variableName = !empty($questionData['variable_name']) ? $questionData['variable_name'] : 'VAR_' . ($index + 1);
$question = MedicalQuestion::updateOrCreate(
['id' => $questionData['id'] ?? null],
[
'medical_calculator_id' => $formModelId,
'question' => $questionData['question'],
'variable_name' => $variableName,
'type' => $questionData['type'],
'score' => isset($questionData['score']) ? (float)$questionData['score'] : null,
]
);
// 删除旧的选项
$question->options()->delete();
if (isset($questionData['options']) && is_array($questionData['options'])) {
foreach ($questionData['options'] as $optionData) {
if (!isset($optionData['content'])) {
continue;
}
$option = new MedicalOption([
'content' => $optionData['content'],
'score' => isset($optionData['score']) ? (float)$optionData['score'] : 0,
]);
$question->options()->save($option);
}
}
} catch (\Exception $e) {
\Illuminate\Support\Facades\Log::error('Error saving question: ' . $e->getMessage());
}
}
}
/**
* 定义医学计算器的表格
*
* @return \Encore\Admin\Grid 表格对象
*/
protected function grid()
{
return Admin::grid(MedicalCalculator::class, function (Grid $grid) {
$grid->name('计算器名称');
$grid->disease_name('疾病名称');
$grid->column('questions_count', '问题数量');
$grid->paginate(20);
$grid->disableExport();
$grid->actions(function ($actions) {
$actions->disableView();
});
$grid->filter(function ($filter) {
$filter->disableIdFilter();
$filter->like('name', '输入名称搜索');
});
// 启用批量删除
$grid->batchActions(function ($batch) {
$batch->disableDelete();
$batch->add(new BatchDeleteAction());
});
});
}
}