You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
5.4 KiB
147 lines
5.4 KiB
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\DictItem;
|
|
use App\Models\DictType;
|
|
use App\Models\Teacher;
|
|
use App\Models\TeacherFollowRecord;
|
|
use App\Services\GridMemberScopeService;
|
|
use App\Services\TeacherFollowPlanService;
|
|
use App\Support\ApiResponse;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class TeacherFollowRecordController extends Controller
|
|
{
|
|
use ApiResponse;
|
|
|
|
public function __construct(
|
|
protected TeacherFollowPlanService $followPlan
|
|
) {}
|
|
|
|
public function index(int $teacher): JsonResponse
|
|
{
|
|
Teacher::query()->findOrFail($teacher);
|
|
|
|
$items = TeacherFollowRecord::query()
|
|
->with(['adminUser', 'followMethodItem', 'urgencyItem'])
|
|
->where('teacher_id', $teacher)
|
|
->orderByDesc('followed_at')
|
|
->orderByDesc('id')
|
|
->get()
|
|
->map(fn (TeacherFollowRecord $r) => $this->serialize($r));
|
|
|
|
return $this->ok(['items' => $items]);
|
|
}
|
|
|
|
public function store(Request $request, int $teacher): JsonResponse
|
|
{
|
|
$model = Teacher::query()->with('starLevelItem')->findOrFail($teacher);
|
|
$this->gridScope->assertTeacherAccessible($this->gridScope->userFromRequest($request), $model);
|
|
|
|
$methodTypeId = DictType::query()->where('code', 'follow_method')->where('status', 1)->value('id');
|
|
$urgencyTypeId = DictType::query()->where('code', 'follow_urgency')->where('status', 1)->value('id');
|
|
$statusTypeId = DictType::query()->where('code', 'teacher_status')->where('status', 1)->value('id');
|
|
|
|
$data = $request->validate([
|
|
'subject' => ['required', 'string', 'max:255'],
|
|
'content' => ['nullable', 'string'],
|
|
'followed_at' => ['required', 'date'],
|
|
'follow_method_dict_item_id' => $this->dictItemRules($methodTypeId, 'required'),
|
|
'urgency_dict_item_id' => $this->dictItemRules($urgencyTypeId, 'required'),
|
|
'admin_user_id' => ['nullable', 'integer', 'exists:admin_users,id'],
|
|
'next_follow_subject' => ['required', 'string', 'max:255'],
|
|
'next_follow_date' => ['nullable', 'date'],
|
|
'result' => ['nullable', 'string', 'max:64'],
|
|
]);
|
|
|
|
$nextFollowDate = $data['next_follow_date']
|
|
?? $this->followPlan->nextFollowDateFromStar($model->starLevelItem)?->toDateString();
|
|
|
|
if (! $nextFollowDate) {
|
|
return $this->fail('请填写下次跟进日期,或先为老师设置有效星级', 422);
|
|
}
|
|
|
|
$adminId = $data['admin_user_id'] ?? $request->user()?->id;
|
|
|
|
$record = TeacherFollowRecord::query()->create([
|
|
'teacher_id' => $model->id,
|
|
'admin_user_id' => $adminId,
|
|
'subject' => $data['subject'],
|
|
'content' => $data['content'] ?? null,
|
|
'follow_method_dict_item_id' => $data['follow_method_dict_item_id'],
|
|
'urgency_dict_item_id' => $data['urgency_dict_item_id'],
|
|
'next_follow_subject' => $data['next_follow_subject'],
|
|
'next_follow_date' => $nextFollowDate,
|
|
'followed_at' => $data['followed_at'],
|
|
'result' => $data['result'] ?? null,
|
|
]);
|
|
|
|
$model->next_follow_subject = $data['next_follow_subject'];
|
|
$model->next_follow_date = $nextFollowDate;
|
|
|
|
if (($data['result'] ?? '') === 'become_partner' && $statusTypeId) {
|
|
$partnerItem = DictItem::query()
|
|
->where('dict_type_id', $statusTypeId)
|
|
->where('value', 'partner')
|
|
->where('status', 1)
|
|
->first();
|
|
if ($partnerItem) {
|
|
$model->status_dict_item_id = $partnerItem->id;
|
|
$model->is_partner = true;
|
|
$model->converted_at = now();
|
|
}
|
|
}
|
|
|
|
$model->save();
|
|
|
|
return $this->ok(['id' => $record->id], '已保存跟进');
|
|
}
|
|
|
|
/**
|
|
* @return array<int, \Illuminate\Contracts\Validation\Rule|string>
|
|
*/
|
|
protected function dictItemRules(?int $dictTypeId, string $presence): array
|
|
{
|
|
if (! $dictTypeId) {
|
|
return ['required', 'integer'];
|
|
}
|
|
|
|
$exists = Rule::exists('dict_items', 'id')->where(
|
|
fn ($q) => $q->where('dict_type_id', $dictTypeId)->where('status', 1)
|
|
);
|
|
|
|
return ['required', 'integer', $exists];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
protected function serialize(TeacherFollowRecord $r): array
|
|
{
|
|
return [
|
|
'id' => $r->id,
|
|
'subject' => $r->subject,
|
|
'content' => $r->content,
|
|
'followed_at' => $r->followed_at?->toDateString(),
|
|
'follow_method_item' => $r->followMethodItem ? [
|
|
'id' => $r->followMethodItem->id,
|
|
'label' => $r->followMethodItem->label,
|
|
] : null,
|
|
'urgency_item' => $r->urgencyItem ? [
|
|
'id' => $r->urgencyItem->id,
|
|
'label' => $r->urgencyItem->label,
|
|
'value' => $r->urgencyItem->value,
|
|
] : null,
|
|
'next_follow_subject' => $r->next_follow_subject,
|
|
'next_follow_date' => $r->next_follow_date?->toDateString(),
|
|
'operator_name' => $r->adminUser?->real_name ?: $r->adminUser?->username,
|
|
'result' => $r->result,
|
|
'created_at' => $r->created_at?->toIso8601String(),
|
|
];
|
|
}
|
|
}
|