新增功能

This commit is contained in:
Your Name
2026-08-07 14:32:35 +08:00
parent 16d301f302
commit 58a7197d3e
383 changed files with 713 additions and 542 deletions
@@ -14,7 +14,9 @@ use think\facade\Db;
* 一诊「挂号统计」。
*
* 统计口径:
* - 挂号:doctor_appointment.appointment_date,状态 1/3/4,排除已取消 2
* - 挂号:order.payment_time,已支付且 0 < amount < 10,每笔支付订单计 1 个
* 按支付订单 creator_id 归属员工。
* - 预约:doctor_appointment.appointment_date,状态 1/3/4,排除已取消 2;
* 归属优先挂号医助 assistant_id,再回退诊单医助 assistant_id。
* - 诊单:tcm_prescription_order.create_time,归属订单 creator_id,排除履约 4/9/10。
* - 所有部门和员工筛选都只能收窄 DataScope,不允许 HTTP 参数扩大当前账号范围。
@@ -62,6 +64,11 @@ class FirstVisitRegistrationStatsLogic
$range['day_after_tomorrow'],
$assistantIds
);
$registrationDaily = self::loadRegistrationDaily(
min($range['compare_start'], $range['start']),
$range['end'],
$assistantIds
);
$orderDaily = self::loadOrderDaily(
min($range['compare_start'], $range['start']),
$range['end'],
@@ -73,6 +80,7 @@ class FirstVisitRegistrationStatsLogic
$assistantIds,
$assignment,
$appointmentDaily,
$registrationDaily,
$orderDaily,
$range
);
@@ -112,6 +120,7 @@ class FirstVisitRegistrationStatsLogic
'selected_dept_name' => $selectedDeptName,
'selected_assistant_name' => $selectedAssistantName,
'member_count' => count($assistantIds),
'registration_rule' => '支付时间在统计区间,状态为已支付且实收金额低于 10 元(大于 0 元),每笔支付订单计 1 个挂号',
'appointment_rule' => '预约日期在统计区间,状态为已预约、已完成或已过号,排除已取消',
'performance_rule' => '按订单创建时间和创建人统计,排除已取消、拒收和退款',
],
@@ -123,6 +132,7 @@ class FirstVisitRegistrationStatsLogic
'employee_rows' => $groups,
'rankings' => [
'performance' => self::rankMembers($members, 'order_amount', 10),
'registrations' => self::rankMembers($members, 'registration_count', 10),
'appointments' => self::rankMembers($members, 'appointment_count', 10),
],
'departments' => self::departmentSummaryRows($groups),
@@ -305,6 +315,39 @@ class FirstVisitRegistrationStatsLogic
return $out;
}
/** @param int[] $assistantIds @return array<int,array<string,array{count:int}>> */
private static function loadRegistrationDaily(string $startDate, string $endDate, array $assistantIds): array
{
if ($assistantIds === []) {
return [];
}
$rows = Db::name('order')->alias('o')
->whereNull('o.delete_time')
->where('o.status', 2)
->where('o.amount', '>', 0)
->where('o.amount', '<', 10)
->whereBetweenTime(
'o.payment_time',
$startDate . ' 00:00:00',
$endDate . ' 23:59:59'
)
->whereIn('o.creator_id', $assistantIds)
->fieldRaw('o.creator_id AS assistant_id, DATE(o.payment_time) AS date_label, COUNT(*) AS item_count')
->group(['o.creator_id', 'date_label'])
->select()
->toArray();
$out = [];
foreach ($rows as $row) {
$aid = (int) ($row['assistant_id'] ?? 0);
$date = (string) ($row['date_label'] ?? '');
if ($aid > 0 && $date !== '') {
$out[$aid][$date] = ['count' => (int) ($row['item_count'] ?? 0)];
}
}
return $out;
}
/** @param int[] $assistantIds @return array<int,array<string,array{count:int,amount:float}>> */
private static function loadOrderDaily(string $startDate, string $endDate, array $assistantIds): array
{
@@ -345,6 +388,7 @@ class FirstVisitRegistrationStatsLogic
array $assistantIds,
array $assignment,
array $appointmentDaily,
array $registrationDaily,
array $orderDaily,
array $range
): array {
@@ -356,6 +400,8 @@ class FirstVisitRegistrationStatsLogic
foreach ($assistantIds as $aid) {
$appointmentCount = self::sumDaily($appointmentDaily[$aid] ?? [], $range['start'], $range['end'], 'count');
$compareAppointmentCount = self::sumDaily($appointmentDaily[$aid] ?? [], $range['compare_start'], $range['compare_end'], 'count');
$registrationCount = self::sumDaily($registrationDaily[$aid] ?? [], $range['start'], $range['end'], 'count');
$compareRegistrationCount = self::sumDaily($registrationDaily[$aid] ?? [], $range['compare_start'], $range['compare_end'], 'count');
$orderCount = self::sumDaily($orderDaily[$aid] ?? [], $range['start'], $range['end'], 'count');
$orderAmount = self::sumDaily($orderDaily[$aid] ?? [], $range['start'], $range['end'], 'amount');
$rows[] = [
@@ -364,6 +410,9 @@ class FirstVisitRegistrationStatsLogic
'dept_id' => (int) ($assignment[$aid] ?? 0),
'name' => (string) ($assistantIndex[$aid] ?? '未命名员工'),
'row_type' => 'employee',
'registration_count' => (int) $registrationCount,
'compare_registration_count' => (int) $compareRegistrationCount,
'registration_compare_rate' => self::relativeChange($registrationCount, $compareRegistrationCount),
'appointment_count' => (int) $appointmentCount,
'compare_appointment_count' => (int) $compareAppointmentCount,
'appointment_compare_rate' => self::relativeChange($appointmentCount, $compareAppointmentCount),
@@ -374,7 +423,7 @@ class FirstVisitRegistrationStatsLogic
'status' => 'normal',
];
}
usort($rows, static fn (array $a, array $b): int => ($b['appointment_count'] <=> $a['appointment_count']) ?: ($b['order_amount'] <=> $a['order_amount']));
usort($rows, static fn (array $a, array $b): int => ($b['registration_count'] <=> $a['registration_count']) ?: ($b['appointment_count'] <=> $a['appointment_count']) ?: ($b['order_amount'] <=> $a['order_amount']));
return $rows;
}
@@ -393,6 +442,8 @@ class FirstVisitRegistrationStatsLogic
'name' => $key > 0 ? (string) ($deptIndex[$key]['name'] ?? '未命名部门') : '未分配部门',
'row_type' => 'department',
'member_count' => 0,
'registration_count' => 0,
'compare_registration_count' => 0,
'appointment_count' => 0,
'compare_appointment_count' => 0,
'tomorrow_count' => 0,
@@ -405,13 +456,17 @@ class FirstVisitRegistrationStatsLogic
}
$groups[$key]['children'][] = $member;
$groups[$key]['member_count']++;
foreach (['appointment_count', 'compare_appointment_count', 'tomorrow_count', 'day_after_count', 'order_count'] as $field) {
foreach (['registration_count', 'compare_registration_count', 'appointment_count', 'compare_appointment_count', 'tomorrow_count', 'day_after_count', 'order_count'] as $field) {
$groups[$key][$field] += (int) ($member[$field] ?? 0);
}
$groups[$key]['order_amount'] += (float) ($member['order_amount'] ?? 0);
}
foreach ($groups as &$group) {
$group['order_amount'] = round((float) $group['order_amount'], 2);
$group['registration_compare_rate'] = self::relativeChange(
(float) $group['registration_count'],
(float) $group['compare_registration_count']
);
$group['appointment_compare_rate'] = self::relativeChange(
(float) $group['appointment_count'],
(float) $group['compare_appointment_count']
@@ -432,11 +487,15 @@ class FirstVisitRegistrationStatsLogic
/** @param array<int,array<string,mixed>> $members @return array<string,mixed> */
private static function buildSummary(array $members, array $range): array
{
$registrationCount = 0;
$compareRegistrationCount = 0;
$appointmentCount = 0;
$compareAppointmentCount = 0;
$orderCount = 0;
$orderAmount = 0.0;
foreach ($members as $member) {
$registrationCount += (int) ($member['registration_count'] ?? 0);
$compareRegistrationCount += (int) ($member['compare_registration_count'] ?? 0);
$appointmentCount += (int) ($member['appointment_count'] ?? 0);
$compareAppointmentCount += (int) ($member['compare_appointment_count'] ?? 0);
$orderCount += (int) ($member['order_count'] ?? 0);
@@ -444,6 +503,9 @@ class FirstVisitRegistrationStatsLogic
}
return [
'registration_count' => $registrationCount,
'registration_compare_count' => $compareRegistrationCount,
'registration_compare_rate' => self::relativeChange($registrationCount, $compareRegistrationCount),
'appointment_count' => $appointmentCount,
'appointment_compare_count' => $compareAppointmentCount,
'appointment_compare_rate' => self::relativeChange($appointmentCount, $compareAppointmentCount),
@@ -460,13 +522,18 @@ class FirstVisitRegistrationStatsLogic
usort($rows, static fn (array $a, array $b): int => (($b[$field] ?? 0) <=> ($a[$field] ?? 0)) ?: strcmp((string) $a['name'], (string) $b['name']));
$out = [];
foreach (array_slice($rows, 0, $limit) as $row) {
$countField = match ($field) {
'order_amount' => 'order_count',
'registration_count' => 'registration_count',
default => 'appointment_count',
};
$out[] = [
'admin_id' => (int) ($row['admin_id'] ?? 0),
'name' => (string) ($row['name'] ?? ''),
'value' => $field === 'order_amount'
? round((float) ($row[$field] ?? 0), 2)
: (int) ($row[$field] ?? 0),
'count' => $field === 'order_amount' ? (int) ($row['order_count'] ?? 0) : (int) ($row['appointment_count'] ?? 0),
'count' => (int) ($row[$countField] ?? 0),
];
}