This commit is contained in:
Your Name
2026-08-18 14:08:38 +08:00
parent 8b9df1154c
commit bc1228a310
77 changed files with 10763 additions and 1181 deletions
@@ -627,10 +627,35 @@ class AppointmentLogic extends BaseLogic
* @param array $params
* @return array
*/
public static function reception(array $params): array
{
// 1) 挂号详情(已包含 patient_name / patient_phone / doctor_name / status_desc 等)
$appointment = self::detail($params);
public static function reception(array $params, int $adminId, array $adminInfo): array
{
self::$error = '';
$appointmentId = (int) ($params['id'] ?? 0);
$appointmentRow = $appointmentId > 0
? Appointment::where('id', $appointmentId)->field(['id', 'patient_id', 'doctor_id'])->find()
: null;
if (!$appointmentRow) {
self::setError('预约记录不存在或无权访问');
return [];
}
$diagnosisRow = Diagnosis::where('id', (int) $appointmentRow->patient_id)
->whereNull('delete_time')
->field(['id', 'assistant_id'])
->find();
if (!self::appointmentRowManageableByAdmin(
$appointmentRow,
$diagnosisRow ?: null,
$adminId,
$adminInfo
)) {
self::setError('预约记录不存在或无权访问');
return [];
}
// 1) 挂号详情(已包含 patient_name / patient_phone / doctor_name / status_desc 等)
$appointment = self::detail($params);
if (empty($appointment)) {
return [];
}
@@ -883,40 +908,62 @@ class AppointmentLogic extends BaseLogic
/**
* 与 AppointmentLists 一致的可见性(不含 progress_board / diag_scope_relax
*/
private static function appointmentRowManageableByAdmin(
Appointment $appointment,
?Diagnosis $diag,
int $adminId,
array $adminInfo
): bool {
$roleIds = array_map('intval', AdminRole::where('admin_id', $adminId)->column('role_id'));
if (in_array(1, $roleIds, true) && (int) $appointment->doctor_id !== $adminId) {
return false;
}
if (in_array(2, $roleIds, true)) {
$asst = $diag ? (int) $diag->assistant_id : 0;
if ($asst !== $adminId) {
return false;
}
}
if (!DataScopeService::isEnabled()) {
return true;
}
$ids = DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
if ($ids === []) {
return false;
}
if ($ids === null) {
return true;
}
$docId = (int) $appointment->doctor_id;
$asstId = $diag ? (int) $diag->assistant_id : 0;
return in_array($docId, $ids, true)
|| ($asstId > 0 && in_array($asstId, $ids, true));
}
private static function appointmentRowManageableByAdmin(
Appointment $appointment,
?Diagnosis $diag,
int $adminId,
array $adminInfo
): bool {
$docId = (int) $appointment->doctor_id;
$asstId = $diag ? (int) $diag->assistant_id : 0;
$isRoot = !empty($adminInfo['root']) && (int) $adminInfo['root'] === 1;
$roleIds = $isRoot
? []
: array_map('intval', AdminRole::where('admin_id', $adminId)->column('role_id'));
$visibleIds = null;
if (!$isRoot && DataScopeService::isEnabled()) {
$visibleIds = DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
}
return self::appointmentRowManageableForScope(
$docId,
$asstId,
$adminId,
$roleIds,
$visibleIds,
$isRoot
);
}
/**
* @param array<int, int> $roleIds
* @param array<int, int>|null $visibleIds null 表示未启用数据范围或全量可见
*/
private static function appointmentRowManageableForScope(
int $doctorId,
int $assistantId,
int $adminId,
array $roleIds,
?array $visibleIds,
bool $isRoot
): bool {
if ($isRoot) {
return true;
}
if (in_array(1, $roleIds, true) && $doctorId !== $adminId) {
return false;
}
if (in_array(2, $roleIds, true) && $assistantId !== $adminId) {
return false;
}
if ($visibleIds === []) {
return false;
}
return $visibleIds === null
|| in_array($doctorId, $visibleIds, true)
|| ($assistantId > 0 && in_array($assistantId, $visibleIds, true));
}
/**
* 后台编辑挂号(预约日期/时段/类型/状态/备注/医助)
@@ -25,8 +25,8 @@ class DoctorNoteLogic extends BaseLogic
->find();
$newContent = trim($params['content'] ?? '');
$newImages = array_map([self::class, 'toRelativePath'], self::parseJsonArray($params['tongue_images'] ?? []));
$newReports = array_map([self::class, 'toRelativePath'], self::parseJsonArray($params['report_files'] ?? []));
$newImages = self::normalizeNewAttachmentPaths($params['tongue_images'] ?? []);
$newReports = self::normalizeNewAttachmentPaths($params['report_files'] ?? []);
if ($existing) {
$data = [];
@@ -169,15 +169,51 @@ class DoctorNoteLogic extends BaseLogic
*/
private static function toRelativePath(string $url): string
{
if (empty($url)) return $url;
if (stripos($url, 'http://') !== 0 && stripos($url, 'https://') !== 0) {
$url = trim($url);
if ($url === '') return $url;
$urlParts = parse_url($url);
if (!is_array($urlParts) || empty($urlParts['scheme'])) {
return $url;
}
$scheme = strtolower((string) $urlParts['scheme']);
if (!in_array($scheme, ['http', 'https'], true)) {
return $url;
}
// 获取当前存储域名
$domain = self::getStorageDomain();
if ($domain && stripos($url, rtrim($domain, '/')) === 0) {
$relative = substr($url, strlen(rtrim($domain, '/')));
return ltrim($relative, '/');
$domain = rtrim(self::getStorageDomain(), '/');
$domainParts = $domain !== '' ? parse_url($domain) : false;
if (is_array($domainParts)) {
$domainScheme = strtolower((string) ($domainParts['scheme'] ?? ''));
$urlHost = strtolower(rtrim((string) ($urlParts['host'] ?? ''), '.'));
$domainHost = strtolower(rtrim((string) ($domainParts['host'] ?? ''), '.'));
$urlPort = (int) ($urlParts['port'] ?? ($scheme === 'https' ? 443 : 80));
$domainPort = (int) (
$domainParts['port'] ?? ($domainScheme === 'https' ? 443 : 80)
);
$urlPath = (string) ($urlParts['path'] ?? '');
$domainPath = rtrim((string) ($domainParts['path'] ?? ''), '/');
$pathInsideDomain = $domainPath === ''
|| $urlPath === $domainPath
|| str_starts_with($urlPath, $domainPath . '/');
if (
$domainScheme === $scheme
&& $domainHost !== ''
&& $domainHost === $urlHost
&& $domainPort === $urlPort
&& $pathInsideDomain
) {
$relative = $domainPath === ''
? $urlPath
: substr($urlPath, strlen($domainPath));
if (isset($urlParts['query']) && $urlParts['query'] !== '') {
$relative .= '?' . $urlParts['query'];
}
return ltrim($relative, '/');
}
}
// 非当前存储域名,保留完整 URL
return $url;
@@ -193,6 +229,36 @@ class DoctorNoteLogic extends BaseLogic
return $storage ? ($storage['domain'] ?? '') : '';
}
/**
* 备注附件只接受站内相对路径或当前存储域已上传的 URL。
* 存储域 URL 先转为相对路径,避免将任意外部 URL 持久化到病例页。
*
* @param mixed $value
* @return array<int, string>
*/
private static function normalizeNewAttachmentPaths($value): array
{
$paths = [];
foreach (self::parseJsonArray($value) as $rawPath) {
$path = trim((string) $rawPath);
if ($path === '') {
continue;
}
$path = self::toRelativePath($path);
$scheme = parse_url($path, PHP_URL_SCHEME);
if (
(is_string($scheme) && $scheme !== '')
|| str_starts_with($path, '//')
|| str_contains($path, "\0")
) {
throw new \InvalidArgumentException('备注附件必须来自当前文件存储域');
}
$paths[] = $path;
}
return array_values(array_unique($paths));
}
private static function parseJsonArray($value): array
{
if (is_array($value)) return $value;