283 lines
8.4 KiB
PHP
283 lines
8.4 KiB
PHP
<?php
|
||
|
||
namespace app\adminapi\logic\doctor;
|
||
|
||
use app\common\logic\BaseLogic;
|
||
use app\common\model\doctor\Roster;
|
||
use app\common\service\doctor\RosterSegmentService;
|
||
use think\facade\Db;
|
||
|
||
/**
|
||
* 医生排班逻辑
|
||
* Class RosterLogic
|
||
* @package app\adminapi\logic\doctor
|
||
*/
|
||
class RosterLogic extends BaseLogic
|
||
{
|
||
/**
|
||
* 组装单条排班数据(period 缺省为 segment)
|
||
*/
|
||
protected static function buildRowData(array $params): array
|
||
{
|
||
$period = $params['period'] ?? '';
|
||
if (!in_array($period, ['morning', 'afternoon', 'night', 'segment'], true)) {
|
||
$period = 'segment';
|
||
}
|
||
|
||
$start = trim((string) ($params['start_time'] ?? ''));
|
||
$end = trim((string) ($params['end_time'] ?? ''));
|
||
$status = (int) $params['status'];
|
||
$slotMinutes = RosterSegmentService::normalizeSlotMinutes($params['slot_minutes'] ?? 15);
|
||
|
||
if ($status === 1) {
|
||
if ($start === '' || $end === '') {
|
||
throw new \InvalidArgumentException('出诊须填写接诊开始与结束时间');
|
||
}
|
||
if ($start >= $end) {
|
||
throw new \InvalidArgumentException('结束时间须晚于开始时间');
|
||
}
|
||
} else {
|
||
if ($start === '' || $end === '') {
|
||
throw new \InvalidArgumentException('请填写时段开始与结束时间');
|
||
}
|
||
if ($start >= $end) {
|
||
throw new \InvalidArgumentException('结束时间须晚于开始时间');
|
||
}
|
||
}
|
||
|
||
$shiftType = $params['shift_type'] ?? '';
|
||
if ($shiftType !== '' && !in_array($shiftType, ['day', 'night'], true)) {
|
||
$shiftType = '';
|
||
}
|
||
|
||
$quota = (int) ($params['quota'] ?? 0);
|
||
if ($status !== 1) {
|
||
$quota = 0;
|
||
}
|
||
|
||
return [
|
||
'doctor_id' => (int) $params['doctor_id'],
|
||
'date' => $params['date'],
|
||
'period' => $period,
|
||
'start_time' => $start,
|
||
'end_time' => $end,
|
||
'shift_type' => $shiftType !== '' ? $shiftType : null,
|
||
'slot_minutes' => $slotMinutes,
|
||
'status' => $status,
|
||
'quota' => $quota,
|
||
'max_patients' => $status === 1 ? (int) ($params['max_patients'] ?? 0) : 0,
|
||
'remark' => (string) ($params['remark'] ?? ''),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 是否存在相同医生、日期、起止时间的记录(排除指定 id)
|
||
*/
|
||
protected static function duplicateExists(int $doctorId, string $date, string $start, string $end, ?int $excludeId = null): bool
|
||
{
|
||
$q = Roster::where([
|
||
['doctor_id', '=', $doctorId],
|
||
['date', '=', $date],
|
||
['start_time', '=', $start],
|
||
['end_time', '=', $end],
|
||
]);
|
||
if ($excludeId) {
|
||
$q->where('id', '<>', $excludeId);
|
||
}
|
||
|
||
return (bool) $q->find();
|
||
}
|
||
|
||
/**
|
||
* @notes 保存排班
|
||
* @param array $params
|
||
* @return array|bool
|
||
*/
|
||
public static function save(array $params)
|
||
{
|
||
try {
|
||
$data = self::buildRowData($params);
|
||
|
||
if (self::duplicateExists($data['doctor_id'], $data['date'], $data['start_time'], $data['end_time'], !empty($params['id']) ? (int) $params['id'] : null)) {
|
||
self::setError('该医生在同一天已存在相同的接诊时段');
|
||
|
||
return false;
|
||
}
|
||
|
||
if (!empty($params['id'])) {
|
||
$data['update_time'] = time();
|
||
Roster::where('id', (int) $params['id'])->update($data);
|
||
|
||
return ['id' => (int) $params['id']];
|
||
}
|
||
|
||
$data['create_time'] = time();
|
||
$data['update_time'] = time();
|
||
$roster = Roster::create($data);
|
||
|
||
return ['id' => $roster->id];
|
||
} catch (\InvalidArgumentException $e) {
|
||
self::setError($e->getMessage());
|
||
|
||
return false;
|
||
} catch (\Exception $e) {
|
||
self::setError($e->getMessage());
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 删除排班
|
||
* @param array $params
|
||
* @return bool
|
||
*/
|
||
public static function delete(array $params)
|
||
{
|
||
try {
|
||
Roster::destroy($params['id']);
|
||
|
||
return true;
|
||
} catch (\Exception $e) {
|
||
self::setError($e->getMessage());
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 排班详情
|
||
* @param array $params
|
||
* @return array
|
||
*/
|
||
public static function detail(array $params)
|
||
{
|
||
return Roster::findOrEmpty($params['id'])->toArray();
|
||
}
|
||
|
||
/**
|
||
* @notes 批量保存排班
|
||
* @param array $params
|
||
* @return array|bool
|
||
*/
|
||
public static function batchSave(array $params)
|
||
{
|
||
try {
|
||
Db::startTrans();
|
||
|
||
$successCount = 0;
|
||
$updateCount = 0;
|
||
$createCount = 0;
|
||
|
||
foreach ($params['rosters'] as $roster) {
|
||
$data = self::buildRowData($roster);
|
||
|
||
$exists = Roster::where([
|
||
['doctor_id', '=', $data['doctor_id']],
|
||
['date', '=', $data['date']],
|
||
['start_time', '=', $data['start_time']],
|
||
['end_time', '=', $data['end_time']],
|
||
])->find();
|
||
|
||
if ($exists) {
|
||
$data['update_time'] = time();
|
||
$exists->save($data);
|
||
++$updateCount;
|
||
} else {
|
||
$data['create_time'] = time();
|
||
$data['update_time'] = time();
|
||
Roster::create($data);
|
||
++$createCount;
|
||
}
|
||
++$successCount;
|
||
}
|
||
|
||
Db::commit();
|
||
|
||
return [
|
||
'success_count' => $successCount,
|
||
'create_count' => $createCount,
|
||
'update_count' => $updateCount,
|
||
];
|
||
} catch (\InvalidArgumentException $e) {
|
||
Db::rollback();
|
||
self::setError($e->getMessage());
|
||
|
||
return false;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
self::setError($e->getMessage());
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @notes 复制排班
|
||
* @param array $params
|
||
* @return bool
|
||
*/
|
||
public static function copy(array $params)
|
||
{
|
||
try {
|
||
Db::startTrans();
|
||
|
||
$where = [
|
||
['date', 'between', [$params['source_start_date'], $params['source_end_date']]],
|
||
];
|
||
|
||
if (isset($params['doctor_id']) && $params['doctor_id']) {
|
||
$where[] = ['doctor_id', '=', $params['doctor_id']];
|
||
}
|
||
|
||
$sourceRosters = Roster::where($where)->select();
|
||
|
||
$targetDays = (strtotime($params['target_start_date']) - strtotime($params['source_start_date'])) / 86400;
|
||
|
||
foreach ($sourceRosters as $roster) {
|
||
$newDate = date('Y-m-d', strtotime($roster->date) + ($targetDays * 86400));
|
||
|
||
$data = [
|
||
'doctor_id' => $roster->doctor_id,
|
||
'date' => $newDate,
|
||
'period' => $roster->period,
|
||
'start_time' => $roster->start_time,
|
||
'end_time' => $roster->end_time,
|
||
'shift_type' => $roster->shift_type,
|
||
'slot_minutes' => $roster->slot_minutes ?: 15,
|
||
'status' => $roster->status,
|
||
'quota' => $roster->quota,
|
||
'max_patients' => $roster->max_patients,
|
||
'remark' => $roster->remark,
|
||
'create_time' => time(),
|
||
'update_time' => time(),
|
||
];
|
||
|
||
if (empty($data['start_time']) || empty($data['end_time'])) {
|
||
continue;
|
||
}
|
||
|
||
$dup = Roster::where([
|
||
['doctor_id', '=', $data['doctor_id']],
|
||
['date', '=', $data['date']],
|
||
['start_time', '=', $data['start_time']],
|
||
['end_time', '=', $data['end_time']],
|
||
])->find();
|
||
|
||
if (!$dup) {
|
||
Roster::create($data);
|
||
}
|
||
}
|
||
|
||
Db::commit();
|
||
|
||
return true;
|
||
} catch (\Exception $e) {
|
||
Db::rollback();
|
||
self::setError($e->getMessage());
|
||
|
||
return false;
|
||
}
|
||
}
|
||
}
|