You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

520 lines
16 KiB
PHP

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers;
use App\Models\Appointment;
use App\Models\AppointmentHolidays;
use App\Models\AppointmentTemplate;
use App\Models\Hospital;
use App\Models\UserOrder;
use Illuminate\Http\Request;
use Login;
use Yo;
class AppointmentController extends Controller
{
public function month_map($month)
{
$week = date('w', strtotime($month[0]['date']));
if ($week == 0) $week = 7;
$month_list = [
[],
[],
[],
[],
[],
[],
];
for ($i = 0; $i < $week; $i++) {
$month_list[0][] = [
'date' => '',
'day' => 0,
'create' => false,
];
}
foreach ($month as $item) {
$c = date('d', strtotime($item['date'])) + ($week - 2);
$w = date('w', strtotime($item['date']));
if ($w == 0) $w = 7;
$month_list[floor($c / 7)][$w - 1] = $item;
}
foreach ($month_list as $key => $item) {
$c = count($item);
if ($c != 7) {
for ($i = 0; $i < 7 - $c; $i++) {
$month_list[$key][] = [
'date' => '',
'day' => 0,
'create' => false,
];
}
}
}
return $month_list;
}
public function last_day($date)
{
$date = strtotime($date);
$count = cal_days_in_month(CAL_GREGORIAN, date('m', $date), date('Y', $date));
return date('Y-m', $date) . '-' . $count;
}
public function first_day($date)
{
$date = strtotime($date);
return date('Y-m-01', $date);
}
public function check_create($appointment_template, $date, $list)
{
$weekday = $appointment_template->weekday;
$holidays = $appointment_template->holidays;
$weeks = json_decode($appointment_template->weeks, true);
$week = date('w', strtotime($date));
$week = $week == 0 ? 7 : $week;
switch ($week) {
case 1:
case 2:
case 3:
case 4:
case 5:
if (isset($list[$date]) && $list[$date]['type'] == 1) {
if ($holidays == 2) return false;
}
return in_array((string)$week, $weeks);
case 6:
case 7:
if (isset($list[$date]) && $list[$date]['type'] == 2) {
if ($weekday == 1) return true;
}
return in_array((string)$week, $weeks);
}
}
public function date_map($start_date, $end_date, $appointment_template, $list)
{
$date_map = [];
$first_day = self::first_day($start_date);
$last_day = self::last_day($end_date);
$first_day_time = strtotime($first_day);
$last_day_time = strtotime($last_day);
for ($i = $first_day_time; $i <= $last_day_time; $i += 86400) {
$date = date('Y-m-d', $i);
$key = date('Y_m', $i);
$create = self::check_create($appointment_template, $date, $list);
if (strtotime($start_date) > $i) $create = false;
if (strtotime($end_date) < $i) $create = false;
$item = [
'date' => $date,
'day' => date('d', $i),
'create' => $create,
];
$date_map[$key][] = $item;
}
$map = [];
foreach ($date_map as $key => $item) {
$map[] = [
'year' => explode('_', $key)[0],
'month' => explode('_', $key)[1],
'list' => self::month_map($item),
];
}
return $map;
}
public function create(Request $request)
{
Login::admin([], [13, 15, 27]);
$hospital_id = $request->post('hospital');
if (Login::$info->hospital != 0) {
if ($hospital_id != Login::$info->hospital) {
Yo::error_echo(100000, ['机构/医院']);
}
}
$id = $request->post('id');
$date_arr = $request->post('date_arr');
$appointment_template = AppointmentTemplate::find($id);
if (!$appointment_template) Yo::error_echo(100000, ['计划模板']);
if (count($date_arr) > 300) Yo::error_echo(200022);
$hospital = Hospital::where('id', $hospital_id)->where('del', 2)->first();
if (!$hospital) Yo::error_echo(100000, ['机构/医院']);
$list = [];
$error = [];
foreach ($date_arr as $date) {
$week = date('w', strtotime($date));
$week = $week == 0 ? 7 : $week;
$appointment = new Appointment();
$appointment->date = $date;
$appointment->week = $week;
$appointment->start_time = $appointment_template->start_time;
$appointment->end_time = $appointment_template->end_time;
$appointment->stop_time = $appointment_template->stop_time;
$appointment->max_count = $appointment_template->max_count;
$appointment->used_count = 0;
$appointment->hospital = $hospital->id;
$appointment->status = 1;
$appointment->save();
if (!!$appointment->id) {
$list[] = $appointment;
} else {
$error[] = $appointment;
}
}
return Yo::echo([
'list' => $list,
'error' => $error,
]);
}
public function create_list(Request $request)
{
Login::admin([], [13, 27]);
$id = $request->post('id');
$start_date = $request->post('start_date');
$end_date = $request->post('end_date');
if (strtotime($start_date) > strtotime($end_date)) Yo::error_echo(200020);
$appointment_template = AppointmentTemplate::find($id);
if (!$appointment_template) Yo::error_echo(100000, ['计划模板']);
$appointment_holiday_list = AppointmentHolidays::where('date', '>=', $start_date)
->where('date', '<=', $end_date)
->get();
$list = [];
foreach ($appointment_holiday_list as $item) {
$list[$item->date] = [
'date' => $item->date,
'type' => $item->type,
];
}
$date_map = self::date_map($start_date, $end_date, $appointment_template, $list);
if (count($date_map) > 12) Yo::error_echo(200021);
return Yo::echo([
'list' => $date_map,
]);
}
public function delete(Request $request)
{
Login::admin([], [15, 27]);
$ids = $request->post('ids');
$appointments_to_delete = Appointment::whereIn('id', $ids)
->where('used_count', '>', 0)
->get();
if (count($appointments_to_delete)) {
return Yo::error_echo(200023);
}
if (Login::$info->id == 1) {
Appointment::whereIn('id', $ids)->update(['del' => 1]);
} else {
Appointment::whereIn('id', $ids)->where('hospital', Login::$info->hospital)->update(['del' => 1]);
}
return Yo::delete_echo($ids);
}
public function change_status(Request $request)
{
Login::admin([], [15, 27]);
$ids = $request->post('ids');
$status = $request->post('status');
if (Login::$info->id == 1) {
Appointment::whereIn('id', $ids)->update(['status' => $status]);
} else {
Appointment::whereIn('id', $ids)->where('hospital', Login::$info->hospital)->update(['status' => $status]);
}
return Yo::update_echo($ids);
}
public function change_count(Request $request)
{
Login::admin([], [15, 27]);
$ids = $request->post('ids');
$count = $request->post('count');
if (Login::$info->id == 1) {
$list = Appointment::whereIn('id', $ids)->get();
} else {
$list = Appointment::whereIn('id', $ids)->where('hospital', Login::$info->hospital)->get();
}
foreach ($list as $item) {
$item->max_count = $count;
$item->save();
}
return Yo::update_echo($ids);
}
public function list(Request $request)
{
Login::admin([], [15, 27]);
$hospital = $request->post('hospital');
if (Login::$info->hospital != 0) {
if ($hospital != Login::$info->hospital) {
Yo::error_echo(100000, ['机构/医院']);
}
}
$start_date = $request->post('start_date');
$end_date = $request->post('end_date');
$status = $request->post('status');
$weeks = $request->post('weeks');
$query = Appointment::select('*')
->selectRaw("IFNULL((select type from appointment_holidays where appointment_holidays.date = appointments.date),0) as date_type")
->where('hospital', $hospital);
if ($status != 0) $query->where('status', '>=', $status);
if (!!$start_date) $query->where('date', '>=', $start_date);
if (!!$end_date) $query->where('date', '<=', $end_date);
if (count($weeks) == 0) $weeks = [1, 2, 3, 4, 5, 6, 7];
$query->whereIn('week', $weeks);
$appointments = $query->where('del', 2)->orderBy('date', 'desc')->paginate(20);
return Yo::echo($appointments);
}
public function mp_list(Request $request)
{
Login::user();
$month = $request->post('month');
$hospital = $request->post('hospital');
$appointments = Appointment::where('hospital', $hospital)
->where('date', 'like', $month . '%')
->where('status', 1)
->where('del', 2)
->orderBy('date')
->get();
$list = [];
foreach ($appointments as $appointment) {
$date = substr($appointment->date, 8, 2);
if (!isset($list[$date])) {
$list[$date] = [
'date' => $appointment->date,
'info' => 0,
'data' => [
'list' => []
],
];
}
$item_time = strtotime($appointment->date . ' ' . $appointment->stop_time);
$start_show = date('H:i', strtotime($appointment->date . ' ' . $appointment->start_time));
$end_show = date('H:i', strtotime($appointment->date . ' ' . $appointment->end_time));
$appointment->start_show = $start_show;
$appointment->end_show = $end_show;
if ($item_time < time()) {
$appointment->used_count = $appointment->max_count;
} else {
$list[$date]['info'] += max($appointment->max_count - $appointment->used_count, 0);
}
$list[$date]['data']['list'][] = $appointment;
}
$l = [];
foreach ($list as $item) {
$l[] = $item;
}
return Yo::echo([
'list' => $l,
]);
}
public function statistics(Request $request)
{
Login::admin([]);
$hospital = $request->post('hospital');
if (Login::$info->hospital != 0) {
if ($hospital != Login::$info->hospital) {
Yo::error_echo(100000, ['机构/医院']);
}
}
$start_date = $request->post('start_date');
$end_date = $request->post('end_date');
// 1. 查询已支付/已完成订单 (status IN 2,4)
$query = UserOrder::where('hospital', $hospital)
->whereIn('status', [2, 4]);
if (!!$start_date) $query->where('created_at', '>=', $start_date);
if (!!$end_date) $query->where('created_at', '<=', $end_date . ' 23:59:59');
$orders = $query->orderBy('id', 'desc')->get();
// 查询已退款订单 (status = 5)
$refund_query = UserOrder::where('hospital', $hospital)
->where('status', 5);
if (!!$start_date) $refund_query->where('refund_time', '>=', $start_date);
if (!!$end_date) $refund_query->where('refund_time', '<=', $end_date . ' 23:59:59');
$refund_orders = $refund_query->get();
// 2. 按类型汇总(个检type=1, 团检type=2)
$charge_amount = round($orders->sum('true_price'), 2);
$refund_amount = round($refund_orders->sum('true_price'), 2);
$total_amount = round(round($charge_amount - $refund_amount, 4), 2);
$type_summary = [];
foreach ([1 => '个人', 2 => '团检'] as $type_val => $type_name) {
$type_charge = round($orders->where('type', $type_val)->sum('true_price'), 2);
$type_refund = round($refund_orders->where('type', $type_val)->sum('true_price'), 2);
$type_summary[] = [
'name' => $type_name,
'charge' => $type_charge,
'refund' => $type_refund,
'total' => round($type_charge - $type_refund, 2),
];
}
// 3. 收集所有项目Id
$all_item_ids = [];
$order_items = [];
foreach ($orders as $order) {
if (!$order->appointment_info) continue;
$info = json_decode($order->appointment_info, true);
if (!$info || !isset($info['项目列表'])) continue;
$items = [];
foreach ($info['项目列表'] as $item) {
$all_item_ids[] = $item['Id'];
$items[] = $item;
}
$order_items[$order->id] = $items;
}
$all_item_ids = array_values(array_unique($all_item_ids));
// 4. 调用"自选项目查询",获取全部项目 → 科室Id 映射
$item_clinic_map = [];
if (count($all_item_ids) > 0) {
$peis = new PEISApiController();
$items_data = $peis::Post('自选项目查询', $hospital, [
'价格下限' => "0",
'价格上限' => "999999",
"性别" => null,
"妇检" => null,
"套餐Id" => null,
"项目Id列表" => []
])['data'];
foreach ($items_data as $item) {
$item_clinic_map[$item['Id']] = $item['科室Id'];
}
}
// 5. 调用"字典查询"获取科室Id → 别名 映射
$clinic_alias_map = [];
if (count($all_item_ids) > 0) {
$peis = new PEISApiController();
$dict_data = $peis::Post('字典查询', $hospital, [
'字典类别' => '科室别名字典'
])['data'];
foreach ($dict_data as $item) {
$clinic_alias_map[$item['Id']] = $item['值'];
}
}
// 6. 按别名分组统计收费
$statistics = [];
foreach ($order_items as $order_id => $items) {
foreach ($items as $item) {
$item_id = $item['Id'];
$clinic_id = isset($item_clinic_map[$item_id]) ? $item_clinic_map[$item_id] : null;
$matched = $clinic_id && isset($clinic_alias_map[$clinic_id]);
$alias = $matched ? $clinic_alias_map[$clinic_id] : '未匹配科室';
$price = floatval($item['价格']);
if (isset($item['优惠方式']) && $item['优惠方式'] === '打折') {
$price = round($price * floatval($item['优惠值']), 2);
}
$key = $matched ? $alias : '__unmatched__';
if (!isset($statistics[$key])) {
$statistics[$key] = [
'name' => $alias,
'amount' => 0,
'item_names' => [],
];
}
$statistics[$key]['amount'] = round($statistics[$key]['amount'] + $price, 2);
if (!$matched) {
$statistics[$key]['item_names'][] = $item['名称'];
}
}
}
// 格式化金额,未匹配项去重
$categories = [];
$category_total = 0;
foreach ($statistics as $item) {
$item['amount'] = round($item['amount'], 2);
$category_total = round($category_total + $item['amount'], 2);
if (isset($item['item_names'])) {
$item['item_names'] = array_values(array_unique($item['item_names']));
}
$categories[] = $item;
}
// 合计金额取分类汇总,确保合计与各项之和一致
if ($category_total > 0) {
$charge_amount = $category_total;
}
$total_amount = round($charge_amount - $refund_amount, 2);
return Yo::echo([
'type_summary' => $type_summary,
'charge_amount' => $charge_amount,
'refund_amount' => $refund_amount,
'total_amount' => $total_amount,
'total_chinese' => self::amountToChinese($total_amount),
'categories' => $categories,
]);
}
private function amountToChinese($amount)
{
$digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
$radices = ['', '拾', '佰', '仟'];
$bigRadices = ['', '万', '亿'];
$decimals = ['角', '分'];
$amount = round($amount, 2);
if ($amount == 0) return '零元整';
$amountStr = number_format($amount, 2, '.', '');
$parts = explode('.', $amountStr);
$intPart = $parts[0];
$decPart = $parts[1];
$result = '';
$zeroFlag = false;
$intLen = strlen($intPart);
for ($i = 0; $i < $intLen; $i++) {
$digit = (int)$intPart[$i];
$pos = $intLen - $i - 1;
$radixPos = $pos % 4;
$bigRadixPos = $pos / 4;
if ($digit === 0) {
$zeroFlag = true;
} else {
if ($zeroFlag) {
$result .= '零';
$zeroFlag = false;
}
$result .= $digits[$digit] . $radices[$radixPos];
}
if ($radixPos === 0 && $pos > 0) {
if (!$zeroFlag || $pos >= 8) {
$result .= $bigRadices[(int)$bigRadixPos];
}
$zeroFlag = false;
}
}
$result .= '元';
if ($decPart === '00') {
$result .= '整';
} else {
$jiao = (int)$decPart[0];
$fen = (int)$decPart[1];
if ($jiao > 0) {
$result .= $digits[$jiao] . '角';
} elseif ($jiao === 0 && $fen > 0) {
$result .= '零';
}
if ($fen > 0) {
$result .= $digits[$fen] . '分';
}
}
return $result;
}
}