From 6fa9d49badd67c257fdb9987bc2e86240e7f4a0e Mon Sep 17 00:00:00 2001 From: panliang <1163816051@qq.com> Date: Sun, 8 Oct 2023 12:04:15 +0800 Subject: [PATCH] admin patient record --- app/Admin/Controllers/CategoryController.php | 22 + app/Admin/Controllers/HomeController.php | 8 +- app/Admin/Controllers/KeywordsController.php | 4 +- app/Admin/Controllers/PatientController.php | 25 +- .../Controllers/PatientRecordController.php | 117 +++- .../Controllers/TotalRecordController.php | 29 +- app/Admin/Services/BaseService.php | 19 +- app/Admin/Services/KeywordService.php | 6 +- app/Admin/Services/PatientRecordService.php | 40 +- app/Admin/Services/PatientService.php | 17 +- app/Admin/routes.php | 2 + app/Casts/StorageFile.php | 4 +- app/ModelFilters/PatientFilter.php | 7 +- app/ModelFilters/PatientRecordFilter.php | 9 +- app/Models/Keyword.php | 4 +- app/Models/Patient.php | 14 +- app/Models/PatientRecord.php | 30 +- composer.json | 1 + composer.lock | 559 +++++++++++++++++- ...023_08_30_075602_create_patients_table.php | 2 + ...30_090313_create_patient_records_table.php | 13 +- database/seeders/KeywordSeeder.php | 12 +- lang/zh_CN/patient-record.php | 9 + lang/zh_CN/patient.php | 3 + 24 files changed, 858 insertions(+), 98 deletions(-) diff --git a/app/Admin/Controllers/CategoryController.php b/app/Admin/Controllers/CategoryController.php index 4782432..7dc728a 100644 --- a/app/Admin/Controllers/CategoryController.php +++ b/app/Admin/Controllers/CategoryController.php @@ -71,6 +71,27 @@ class CategoryController extends AdminController amisMake()->TextControl()->name('key')->label(__('category.key'))->required(true), amisMake()->TextControl()->name('name')->label(__('category.name'))->required(true), amisMake()->ImageControl()->name('image')->label(__('category.image')), + amisMake()->JSONSchemaEditorControl()->set('type', 'json-schema')->name('options')->label(__('keywords.data'))->schema([ + 'type' => 'object', + 'properties' => [ + 'doctor_ratio' => [ + 'type' => 'number', + 'title' => '医生提成比例', + 'description' => '0-100', + ], + 'inviter_ratio' => [ + 'type' => 'number', + 'title' => '邀请人提成比例', + 'description' => '0-100', + ], + 'saler_ratio' => [ + 'type' => 'number', + 'title' => '业务员提成比例', + 'description' => '0-100', + ] + ] + ]), + // amisMake()->inputKV()->name('options')->label(__('keywords.data')), // Components::make()->fuEditorControl()->name('content')->label(__('category.content')), amisMake()->TextareaControl()->name('content')->label(__('category.content')), ]); @@ -82,6 +103,7 @@ class CategoryController extends AdminController amisMake()->TextControl()->name('key')->label(__('category.key'))->static(true), amisMake()->TextControl()->name('name')->label(__('category.name'))->static(true), amisMake()->TextControl()->name('image')->label(__('category.image'))->static()->staticSchema(amisMake()->Images()), + amisMake()->TextControl()->name('options')->label(__('keywords.data'))->static(true)->staticSchema(amisMake()->Json()), // Components::make()->fuEditorControl()->name('content')->label(__('category.content'))->static(), amisMake()->TextareaControl()->fuEditorControl()->name('content')->label(__('category.content'))->static(), ]); diff --git a/app/Admin/Controllers/HomeController.php b/app/Admin/Controllers/HomeController.php index 7470eb5..e09bcbc 100644 --- a/app/Admin/Controllers/HomeController.php +++ b/app/Admin/Controllers/HomeController.php @@ -3,6 +3,7 @@ namespace App\Admin\Controllers; use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\Facades\Storage; use Slowlyo\OwlAdmin\Admin; @@ -49,7 +50,12 @@ class HomeController extends AdminController return $this->response()->success($page); } - + + public function downloadExport(Request $request) + { + return response()->download(storage_path('app/public/' . $request->input('path')))->deleteFileAfterSend(); + } + protected function upload($type = 'file') { $file = request()->file('file'); diff --git a/app/Admin/Controllers/KeywordsController.php b/app/Admin/Controllers/KeywordsController.php index 5a75cc3..49d0a81 100644 --- a/app/Admin/Controllers/KeywordsController.php +++ b/app/Admin/Controllers/KeywordsController.php @@ -55,7 +55,7 @@ class KeywordsController extends AdminController amisMake()->ImageControl()->name('image')->label(__('keywords.image'))->autoUpload(true), Components::make()->sortControl('sort', __('keywords.sort')), amisMake()->TextareaControl()->name('description')->label(__('keywords.description')), - amisMake()->inputKV()->name('data')->label(__('keywords.data')), + amisMake()->inputKV()->name('options')->label(__('keywords.data')), Components::make()->fuEditorControl()->name('content')->label(__('keywords.content')), ]); } @@ -70,7 +70,7 @@ class KeywordsController extends AdminController amisMake()->TextControl()->name('image')->label(__('keywords.image'))->static(true)->staticSchema(amisMake()->Image()), amisMake()->TextControl()->name('sort')->label(__('keywords.sort'))->static(true), amisMake()->TextareaControl()->name('description')->label(__('keywords.description'))->static(true), - amisMake()->TextControl()->name('data')->label(__('keywords.data'))->static(true)->staticSchema(amisMake()->Json()), + amisMake()->TextControl()->name('options')->label(__('keywords.data'))->static(true)->staticSchema(amisMake()->Json()), Components::make()->fuEditorControl()->name('content')->label(__('keywords.content'))->static(), ]); } diff --git a/app/Admin/Controllers/PatientController.php b/app/Admin/Controllers/PatientController.php index 9790919..4330711 100644 --- a/app/Admin/Controllers/PatientController.php +++ b/app/Admin/Controllers/PatientController.php @@ -10,7 +10,7 @@ use Slowlyo\OwlAdmin\Renderers\Form; use Slowlyo\OwlAdmin\Renderers\Page; use App\Models\{Keyword, Patient}; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Storage; +use Slowlyo\OwlAdmin\Services\AdminUserService; /** * 病人管理 @@ -21,6 +21,8 @@ class PatientController extends AdminController protected $typeOptions; + protected $adminUserOptions; + public function list(): Page { $crud = $this->baseCRUD() @@ -32,6 +34,7 @@ class PatientController extends AdminController ]) ->filter($this->baseFilter()->actions()->body([ amisMake()->TextControl()->name('keyword')->label(__('patient.keyword'))->placeholder(__('patient.name') . '/' . __('patient.phone'))->size('md')->clearable(), + amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->name('admin_user_id')->label(__('patient.admin_user_id'))->size('md')->clearable(), // amisMake()->Button()->label(__('admin.reset'))->actionType('clear-and-submit'), amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'), ])) @@ -42,8 +45,12 @@ class PatientController extends AdminController amisMake()->TableColumn()->name('phone')->label(__('patient.phone')), amisMake()->TableColumn()->name('age')->label(__('patient.age')), amisMake()->TableColumn()->name('treat_format')->label(__('patient.treat_at')), + amisMake()->TableColumn()->name('doctor.name')->label(__('patient.doctor_id')), + amisMake()->TableColumn()->name('inviter.name')->label(__('patient.inviter_id')), + amisMake()->TableColumn()->name('saler.name')->label(__('patient.saler_id')), $this->rowActions(), - ]); + ]) + ->alwaysShowPagination(); return $this->baseList($crud); } @@ -57,7 +64,9 @@ class PatientController extends AdminController amisMake()->TextControl()->name('address')->label(__('patient.address')), amisMake()->DateControl()->name('birthday')->label(__('patient.birthday')), amisMake()->DateControl()->name('treat_at')->label(__('patient.treat_at')), - Components::make()->adminUserSelectControl()->name('doctor_id')->label(__('patient.doctor_id')), + amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->name('doctor_id')->label(__('patient.doctor_id')), + amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->name('inviter_id')->label(__('patient.inviter_id')), + amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->name('saler_id')->label(__('patient.saler_id')), amisMake()->ImageControl()->multiple()->receiver(admin_url('upload_image') . '?full-url=1')->name('images')->label(__('patient.images')), // Components::make()->fuEditorControl()->name('illness')->label(__('patient.illness')), amisMake()->TextareaControl()->name('illness')->label(__('patient.illness')), @@ -123,6 +132,8 @@ class PatientController extends AdminController amisMake()->DateControl()->name('treat_format')->label(__('patient.treat_at'))->static(), amisMake()->TextControl()->name('images')->label(__('patient.images'))->static()->staticSchema(amisMake()->Images()), amisMake()->TextControl()->name('doctor.name')->label(__('patient.doctor_id'))->static(), + amisMake()->TextControl()->name('inviter.name')->label(__('patient.inviter_id'))->static(), + amisMake()->TextControl()->name('saler.name')->label(__('patient.saler_id'))->static(), // Components::make()->fuEditorControl()->name('illness')->label(__('patient.illness'))->static(), amisMake()->TextareaControl()->name('illness')->label(__('patient.illness'))->static(), amisMake()->TextControl()->name('created_at')->label(__('patient.created_at'))->static(), @@ -160,4 +171,12 @@ class PatientController extends AdminController 'items' => $list->items() ]); } + public function getAdminUserOptions() + { + if (!$this->adminUserOptions) { + $this->adminUserOptions = AdminUserService::make()->query()->select(['id as value', 'name as label'])->get(); + } + + return $this->adminUserOptions; + } } diff --git a/app/Admin/Controllers/PatientRecordController.php b/app/Admin/Controllers/PatientRecordController.php index 337d630..7f21a37 100644 --- a/app/Admin/Controllers/PatientRecordController.php +++ b/app/Admin/Controllers/PatientRecordController.php @@ -32,13 +32,14 @@ class PatientRecordController extends AdminController ->columnsTogglable(false) ->headerToolbar([ $this->createButton(true, 'lg'), + $this->exportAction(), amis('reload')->align('right'), ]) ->filter($this->baseFilter()->actions()->body([ amisMake()->SelectControl()->options($this->getPatientOptions())->searchable()->name('patient_id')->label(__('patient-record.patient_id'))->size('md')->clearable(), amisMake()->SelectControl()->options($this->getTypeOptions())->name('type_id')->label(__('patient-record.type_id'))->size('md')->clearable(), amisMake()->DateRangeControl()->name('treat_range')->label(__('patient-record.treat_at'))->size('md')->clearable(), - amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->name('doctor_id')->label(__('patient-record.doctor_id'))->clearable()->size('md'), + amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->name('admin_user_id')->label(__('patient-record.admin_user_id'))->clearable()->size('md'), // amisMake()->Button()->label(__('admin.reset'))->actionType('clear-and-submit'), amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'), ])) @@ -49,14 +50,18 @@ class PatientRecordController extends AdminController amisMake()->TableColumn()->name('treat_at')->label(__('patient-record.treat_at')), amisMake()->TableColumn()->name('origin_price')->label(__('patient-record.origin_price')), amisMake()->TableColumn()->name('sell_price')->label(__('patient-record.sell_price')), - amisMake()->TableColumn()->name('next_treat_at')->label(__('patient-record.next_treat_at')), amisMake()->TableColumn()->name('doctor.name')->label(__('patient-record.doctor_id')), + amisMake()->TableColumn()->name('inviter.name')->label(__('patient-record.inviter_id')), + amisMake()->TableColumn()->name('saler.name')->label(__('patient-record.saler_id')), $this->rowActions(), - ])->affixRowClassName('text-info-dk')->affixRow([ + ]) + ->alwaysShowPagination() + ->affixRowClassName('text-info-dk') + ->affixRow([ ['type' => 'text', 'text' => '总计', 'colSpan' => 4], ['type' => 'text', 'text' => __('total-record.origin_price') . ': ${origin_price}'], ['type' => 'text', 'text' => __('total-record.sell_price') . ': ${sell_price}'], - ['type' => 'text', 'text' => '', 'colSpan' => 3] + ['type' => 'text', 'text' => '', 'colSpan' => 5] ]); return $this->baseList($crud); @@ -101,27 +106,41 @@ class PatientRecordController extends AdminController public function detail() { - return $this->baseDetail()->body([ - amisMake()->TextControl()->name('patient.name')->label(__('patient-record.patient_id'))->static(), - amisMake()->TextControl()->name('type.name')->label(__('patient-record.type_id'))->static(), - amisMake()->DateTimeControl()->name('treat_at')->label(__('patient-record.treat_at'))->static(), - amisMake()->TextControl()->name('doctor.name')->label(__('patient-record.doctor_id'))->static(), - amisMake()->TextControl()->name('origin_price')->label(__('patient-record.origin_price'))->static(), - amisMake()->TextControl()->name('sell_price')->label(__('patient-record.sell_price'))->static(), - amisMake()->SelectControl()->options(OrderStatus::options())->name('order_status')->label(__('patient-record.order_status'))->static(), - // Components::make()->fuEditorControl()->name('content')->label(__('patient-record.content'))->static(), - amisMake()->TextareaControl()->name('content')->label(__('patient-record.content'))->static(), - amisMake()->TextControl()->name('images')->label(__('patient.images'))->static()->staticSchema(amisMake()->Images()), - amisMake()->DateTimeControl()->name('next_treat_at')->label(__('patient-record.next_treat_at'))->static(), - amisMake()->TextControl()->name('is_notified')->label(__('patient-record.is_notified'))->static()->staticSchema(amisMake()->Status()->source([ - ['icon' => 'fa fa-check', 'color' => '#30bf13'], - ['icon' => 'fa fa-close', 'color' => '#cc292e'], - ])), - amisMake()->TextControl()->name('notify_user.name')->label(__('patient-record.notify_user_id'))->static(), - amisMake()->DateControl()->name('notify_at')->label(__('patient-record.notify_at'))->static(), - // amisMake()->TextControl()->name('notify_remarks')->label(__('patient-record.notify_remarks'))->static(), - amisMake()->SelectControl()->options($this->getAdminUserOptions())->name('creator_id')->label(__('patient-record.creator_id'))->static(), - amisMake()->DateTimeControl()->name('created_at')->label(__('patient.created_at'))->static(), + return $this->baseDetail()->panelClassName('m:px-0')->body([ + amisMake()->Property()->items([ + ['label' => __('patient-record.patient_id'), 'content' => '${patient.name}'], + ['label' => __('patient-record.type_id'), 'content' => '${type.name}'], + ['label' => __('patient-record.treat_at'), 'content' => '${treat_at}'], + + ['label' => __('patient-record.origin_price'), 'content' => '${origin_price}'], + ['label' => __('patient-record.sell_price'), 'content' => '${sell_price}'], + ['label' => __('patient-record.order_status'), 'content' => '${order_status_text}'], + + ['label' => __('patient-record.doctor_id'), 'content' => '${doctor.name}'], + ['label' => __('patient-record.doctor_ratio'), 'content' => '${doctor_ratio}'], + ['label' => __('patient-record.doctor_money'), 'content' => '${doctor_money}'], + + ['label' => __('patient-record.inviter_id'), 'content' => '${inviter.name}'], + ['label' => __('patient-record.inviter_ratio'), 'content' => '${inviter_ratio}'], + ['label' => __('patient-record.inviter_money'), 'content' => '${inviter_money}'], + + ['label' => __('patient-record.saler_id'), 'content' => '${saler.name}'], + ['label' => __('patient-record.saler_ratio'), 'content' => '${saler_ratio}'], + ['label' => __('patient-record.saler_money'), 'content' => '${saler_money}'], + + ['label' => __('patient-record.content'), 'content' => amisMake()->TextareaControl()->name('content')->static(), 'span' => 3], + ['label' => __('patient-record.images'), 'content' => amisMake()->Images()->source('${images}'), 'span' => 3], + + ['label' => __('patient-record.next_treat_at'), 'content' => '${next_treat_at}'], + ['label' => __('patient-record.is_notified'), 'content' => amisMake()->Status()->value('${is_notified}')->source([ + ['icon' => 'fa fa-check', 'color' => '#30bf13'], + ['icon' => 'fa fa-close', 'color' => '#cc292e'] + ])], + ['label' => __('patient-record.notify_user_id'), 'content' => '${notify_user.name}'], + ['label' => __('patient-record.notify_at'), 'content' => '${notify_at}'], + ['label' => __('patient-record.creator_id'), 'content' => '${creator.name}'], + ['label' => __('patient-record.created_at'), 'content' => '${created_at}'], + ]), ]); } @@ -151,4 +170,52 @@ class PatientRecordController extends AdminController return $this->adminUserOptions; } + + protected function exportHeadings() + { + return [ + __('patient-record.id'), + __('patient-record.patient_id'), + __('patient-record.type_id'), + __('patient-record.treat_at'), + __('patient-record.origin_price'), + __('patient-record.sell_price'), + __('patient-record.order_status'), + __('patient-record.doctor_id'), + __('patient-record.doctor_ratio'), + __('patient-record.doctor_money'), + __('patient-record.inviter_id'), + __('patient-record.inviter_ratio'), + __('patient-record.inviter_money'), + __('patient-record.saler_id'), + __('patient-record.saler_ratio'), + __('patient-record.saler_money'), + __('patient-record.creator_id'), + __('patient-record.created_at'), + ]; + } + + protected function exportColumns($row) + { + return [ + $row->id, + data_get($row->patient, 'name'), + data_get($row->type, 'name'), + $row->treat_at, + $row->origin_price, + $row->sell_price, + $row->order_status->text(), + data_get($row->doctor, 'name'), + $row->doctor_ratio, + $row->doctor_money, + data_get($row->inviter, 'name'), + $row->inviter_ratio, + $row->inviter_money, + data_get($row->saler, 'name'), + $row->saler_ratio, + $row->saler_money, + data_get($row->creator, 'name'), + $row->created_at, + ]; + } } diff --git a/app/Admin/Controllers/TotalRecordController.php b/app/Admin/Controllers/TotalRecordController.php index cd28237..a7f710d 100644 --- a/app/Admin/Controllers/TotalRecordController.php +++ b/app/Admin/Controllers/TotalRecordController.php @@ -16,32 +16,6 @@ class TotalRecordController extends AdminController protected $patientOptions; - // public function index() - // { - // $list = PatientRecord::with(['patient'])->filter(request()->all())->groupBy('patient_id')->select([ - // 'patient_id', - // DB::raw('count(1) as count'), - // DB::raw('sum(`origin_price`) as `origin_price`'), - // DB::raw('sum(`sell_price`) as `sell_price`'), - // ])->get(); - // if ($this->actionOfGetData()) { - // return $this->response()->success(['items' => $list]); - // } - // return $this->response()->success($this->basePage()->data(['items' => $list])->className('cxd-Crud')->body([ - // $this->baseFilter()->actions()->mode('inline')->body([ - // amisMake()->SelectControl()->options($this->getPatientOptions())->searchable()->name('patient_id')->label(__('patient_record.patient_id'))->size('md')->clearable(), - // amisMake()->DateRangeControl()->name('treat_range')->label(__('total-record.treat_at'))->clearable()->size('md'), - // amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'), - // ]), - // amisMake()->Table()->affixHeader(false)->source('${items}')->columns([ - // amisMake()->Column()->name('patient.name')->label(__('total-record.name')), - // amisMake()->Column()->name('count')->label(__('total-record.count')), - // amisMake()->Column()->name('origin_price')->label(__('total-record.origin_price')), - // amisMake()->Column()->name('sell_price')->label(__('total-record.sell_price')), - // ]), - // ])); - // } - public function list() { $crud = $this->baseCRUD() @@ -68,7 +42,8 @@ class TotalRecordController extends AdminController ['type' => 'text', 'text' => '记录数: ${total}'], ['type' => 'text', 'text' => __('total-record.origin_price') . ': ${origin_price}'], ['type' => 'text', 'text' => __('total-record.sell_price') . ': ${sell_price}'], - ]); + ]) + ->alwaysShowPagination(); return $this->baseList($crud); } diff --git a/app/Admin/Services/BaseService.php b/app/Admin/Services/BaseService.php index 06d3dee..e59d679 100644 --- a/app/Admin/Services/BaseService.php +++ b/app/Admin/Services/BaseService.php @@ -78,9 +78,9 @@ class BaseService extends AdminService public function update($primaryKey, $data): bool { - $data = $this->resloveData($data); $model = $this->query()->whereKey($primaryKey)->firstOrFail(); - $validate = $this->validate($data, $model->id); + $data = $this->resloveData($data, $model); + $validate = $this->validate($data, $model); if ($validate !== true) { $this->setError($validate); return false; @@ -94,7 +94,7 @@ class BaseService extends AdminService $id = explode(',', $ids); $result = $this->preDelete($id); if ($result !== true) { - $this->setError($validate); + $this->setError($result); return false; } return $this->query()->whereIn($this->primaryKey(), $id)->delete(); @@ -102,30 +102,31 @@ class BaseService extends AdminService /** * 处理表单数据 - * + * * @param array $data + * @param mixed $model * @return array */ - public function resloveData($data) + public function resloveData($data, $model = null) { return $data; } /** * 表单验证 - * + * * @param array $data - * @param int $id 空: 添加, 非空: 修改 + * @param mixed $model 空: 添加, 非空: 当前数据模型 * @return mixed true: 验证通过, string: 错误提示 */ - public function validate($data, $id = null) + public function validate($data, $model = null) { return true; } /** * 删除的前置方法 - * + * * @param array $ids 主键id * @return mixed true: 继续后续操作, string: 中断操作, 返回错误提示 */ diff --git a/app/Admin/Services/KeywordService.php b/app/Admin/Services/KeywordService.php index d257cec..8180708 100644 --- a/app/Admin/Services/KeywordService.php +++ b/app/Admin/Services/KeywordService.php @@ -33,7 +33,7 @@ class KeywordService extends BaseService /** * 删除的前置方法 - * + * * @param array $ids 主键id * @return mixed true: 继续后续操作, string: 中断操作, 返回错误提示 */ @@ -49,7 +49,7 @@ class KeywordService extends BaseService return true; } - public function validate($data, $id = null) + public function validate($data, $model = null) { $createRules = [ 'key' => ['required', Rule::unique('keywords', 'key')], @@ -67,7 +67,7 @@ class KeywordService extends BaseService return true; } - public function resloveData($data) + public function resloveData($data, $model = null) { $parent_id = data_get($data, 'parent_id'); if (!is_null($parent_id)) { diff --git a/app/Admin/Services/PatientRecordService.php b/app/Admin/Services/PatientRecordService.php index f9a052b..1a17abd 100644 --- a/app/Admin/Services/PatientRecordService.php +++ b/app/Admin/Services/PatientRecordService.php @@ -3,6 +3,8 @@ namespace App\Admin\Services; use App\ModelFilters\PatientRecordFilter; +use App\Models\Keyword; +use App\Models\Patient; use App\Models\PatientRecord; use Illuminate\Support\Facades\Validator; use Slowlyo\OwlAdmin\Admin; @@ -12,7 +14,7 @@ class PatientRecordService extends BaseService { protected string $modelName = PatientRecord::class; - protected array $withRelationships = ['doctor', 'patient', 'type', 'notifyUser']; + protected array $withRelationships = ['doctor', 'patient', 'type', 'creator', 'notifyUser', 'inviter', 'saler']; protected string $modelFilterName = PatientRecordFilter::class; @@ -46,7 +48,7 @@ class PatientRecordService extends BaseService return compact('items', 'total', 'sell_price', 'origin_price'); } - public function resloveData($data) + public function resloveData($data, $model = null) { $creator_id = data_get($data, 'creator_id'); if (!$creator_id) { @@ -55,10 +57,40 @@ class PatientRecordService extends BaseService if ($images = data_get($data, 'images')) { $data['images'] = is_array($images) ? $images : explode(',', $images); } + $patient = Patient::findOrFail(data_get($data, 'patient_id')); + $type = Keyword::findOrFail(data_get($data, 'type_id')); + + if (!data_get($data, 'inviter_id')) { + $data['inviter_id'] = $patient->inviter_id; + } + if (!data_get($data, 'saler_id')) { + $data['saler_id'] = $patient->saler_id; + } + if (!$model) { + if (data_get($data, 'doctor_id')) { + $data['doctor_ratio'] = data_get($type->options, 'doctor_ratio'); + } + if (data_get($data, 'doctor_ratio')) { + $data['doctor_money'] = floor($data['sell_price'] * $data['doctor_ratio']) / 100; + } + if (data_get($data, 'inviter_id')) { + $data['inviter_ratio'] = data_get($type->options, 'inviter_ratio'); + } + if (data_get($data, 'inviter_ratio')) { + $data['inviter_money'] = floor($data['sell_price'] * $data['inviter_ratio']) / 100; + } + if (data_get($data, 'saler_id')) { + $data['saler_ratio'] = data_get($type->options, 'saler_ratio'); + } + if (data_get($data, 'saler_ratio')) { + $data['saler_money'] = floor($data['sell_price'] * $data['saler_ratio']) / 100; + } + } + return $data; } - public function validate($data, $id = null) + public function validate($data, $model = null) { $createRules = [ 'patient_id' => 'required', @@ -76,7 +108,7 @@ class PatientRecordService extends BaseService 'origin_price' => 'decimal:0,2', 'sell_price' => 'decimal:0,2', ]; - $validator = Validator::make($data, $id ? $updateRules : $createRules, [ + $validator = Validator::make($data, $model ? $updateRules : $createRules, [ 'patient_id.required' => '请选择病人', 'type_id.required' => '请选择诊疗类型', 'treat_at.required' => '请选择诊疗时间', diff --git a/app/Admin/Services/PatientService.php b/app/Admin/Services/PatientService.php index 92a712c..f175b14 100644 --- a/app/Admin/Services/PatientService.php +++ b/app/Admin/Services/PatientService.php @@ -10,13 +10,12 @@ class PatientService extends BaseService { protected string $modelName = Patient::class; - protected array $withRelationships = ['doctor']; + protected array $withRelationships = ['doctor', 'inviter', 'saler']; protected string $modelFilterName = PatientFilter::class; public function listQuery() { - $model = $this->getModel(); $filter = $this->getModelFilter(); $query = $this->query(); @@ -33,11 +32,11 @@ class PatientService extends BaseService /** * 处理表单数据 - * + * * @param array $data * @return array */ - public function resloveData($data) + public function resloveData($data, $model = null) { if ($images = data_get($data, 'images')) { $data['images'] = is_array($images) ? $images : explode(',', $images); @@ -47,14 +46,14 @@ class PatientService extends BaseService /** * 表单验证 - * + * * @param array $data - * @param int $id 空: 添加, 非空: 修改 + * @param mixed $model 空: 添加, 非空: 修改 * @return mixed true: 验证通过, string: 错误提示 */ - public function validate($data, $id = null) + public function validate($data, $model = null) { - if (!$id) { + if (!$model) { $validator = Validator::make($data, [ 'name' => ['required'], ]); @@ -67,7 +66,7 @@ class PatientService extends BaseService /** * 删除的前置方法 - * + * * @param array $ids 主键id * @return mixed true: 继续后续操作, string: 中断操作, 返回错误提示 */ diff --git a/app/Admin/routes.php b/app/Admin/routes.php index f411575..db8798f 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -19,6 +19,8 @@ Route::group([ $router->any('upload_rich', [\App\Admin\Controllers\HomeController::class, 'uploadRich']); $router->any('upload_image', [\App\Admin\Controllers\HomeController::class, 'uploadImage']); + $router->get('_download_export', [\App\Admin\Controllers\HomeController::class, 'downloadExport']); + $router->resource('system/settings', \App\Admin\Controllers\SettingController::class); $router->get('_settings', [\App\Admin\Controllers\SettingController::class, 'settings']); diff --git a/app/Casts/StorageFile.php b/app/Casts/StorageFile.php index 8c75f25..4511279 100644 --- a/app/Casts/StorageFile.php +++ b/app/Casts/StorageFile.php @@ -28,7 +28,7 @@ class StorageFile implements CastsAttributes * @param string $key * @param mixed $value * @param array $attributes - * @return array + * @return string */ public function get($model, $key, $value, $attributes) { @@ -40,7 +40,7 @@ class StorageFile implements CastsAttributes * * @param \Illuminate\Database\Eloquent\Model $model * @param string $key - * @param array $value + * @param string $value * @param array $attributes * @return string */ diff --git a/app/ModelFilters/PatientFilter.php b/app/ModelFilters/PatientFilter.php index 26b7b9b..c01bc73 100644 --- a/app/ModelFilters/PatientFilter.php +++ b/app/ModelFilters/PatientFilter.php @@ -1,4 +1,4 @@ -where(fn ($q) => $q->where('name', 'like', '%'.$key.'%')->orWhere('phone', 'like', '%'.$key.'%')); } + + public function adminUser($key) + { + $this->where(fn($q) => $q->where('doctor_id', $key)->orWhere('inviter_id', $key)->orWhere('saler_id', $key)); + } } diff --git a/app/ModelFilters/PatientRecordFilter.php b/app/ModelFilters/PatientRecordFilter.php index 0b33f1d..5f0d502 100644 --- a/app/ModelFilters/PatientRecordFilter.php +++ b/app/ModelFilters/PatientRecordFilter.php @@ -1,4 +1,4 @@ -where('type_id', $key); } - + public function doctor($key) { $this->where('doctor_id', $key); @@ -37,4 +37,9 @@ class PatientRecordFilter extends ModelFilter $end = Carbon::createFromTimestamp(data_get($arr, 1, time()))->endOfDay(); $this->whereBetween('treat_at', [$start, $end]); } + + public function adminUser($key) + { + $this->where(fn($q) => $q->where('doctor_id', $key)->orWhere('inviter_id', $key)->orWhere('saler_id', $key)); + } } diff --git a/app/Models/Keyword.php b/app/Models/Keyword.php index b063af4..af080d8 100644 --- a/app/Models/Keyword.php +++ b/app/Models/Keyword.php @@ -14,10 +14,10 @@ class Keyword extends Model { use Filterable, HasDateTimeFormatter; - protected $fillable = ['id', 'name', 'key', 'value', 'parent_id', 'type_key', 'path', 'sort', 'level', 'data', 'image', 'description', 'content']; + protected $fillable = ['id', 'name', 'key', 'value', 'parent_id', 'type_key', 'path', 'sort', 'level', 'options', 'image', 'description', 'content']; protected $casts = [ - 'data' => 'array', + 'options' => 'array', 'image' => StorageFile::class, ]; diff --git a/app/Models/Patient.php b/app/Models/Patient.php index 855757e..9eb291d 100644 --- a/app/Models/Patient.php +++ b/app/Models/Patient.php @@ -16,7 +16,7 @@ class Patient extends Model { use HasDateTimeFormatter, Filterable; - protected $fillable = ['name', 'sex', 'phone', 'address', 'birthday', 'treat_at', 'illness', 'doctor_id', 'remarks', 'images']; + protected $fillable = ['name', 'sex', 'phone', 'address', 'birthday', 'treat_at', 'illness', 'doctor_id', 'remarks', 'images', 'inviter_id', 'saler_id']; protected $appends = ['age', 'sex_text', 'treat_format', 'birthday_format']; @@ -47,7 +47,7 @@ class Patient extends Model get: fn () => $this->treat_at ? $this->treat_at->format('Y-m-d') : '', ); } - + protected function birthdayFormat(): Attribute { return new Attribute( @@ -60,6 +60,16 @@ class Patient extends Model return $this->belongsTo(AdminUser::class, 'doctor_id'); } + public function inviter() + { + return $this->belongsTo(AdminUser::class, 'inviter_id'); + } + + public function saler() + { + return $this->belongsTo(AdminUser::class, 'saler_id'); + } + public function scopeSort($q) { return $q->orderBy('id', 'desc'); diff --git a/app/Models/PatientRecord.php b/app/Models/PatientRecord.php index f069a30..ec0bd7e 100644 --- a/app/Models/PatientRecord.php +++ b/app/Models/PatientRecord.php @@ -16,7 +16,18 @@ class PatientRecord extends Model { use HasDateTimeFormatter, Filterable; - protected $fillable = ['patient_id', 'type_id', 'treat_at', 'doctor_id', 'content', 'origin_price', 'sell_price', 'order_status', 'notify_at', 'notify_user_id', 'notify_remarks', 'is_notified', 'next_treat_at', 'creator_id', 'images']; + protected $fillable = [ + 'patient_id', 'type_id', + 'treat_at', 'content', 'images', + 'doctor_id', 'doctor_ratio', 'doctor_money', + 'saler_id', 'saler_ratio', 'saler_money', + 'inviter_id', 'inviter_ratio', 'inviter_money', + 'origin_price', 'sell_price', 'order_status', + 'notify_at', 'notify_user_id', 'notify_remarks', 'is_notified', 'next_treat_at', + 'creator_id', + ]; + + protected $appends = ['order_status_text']; protected $casts = [ 'order_status' => OrderStatus::class, @@ -43,6 +54,16 @@ class PatientRecord extends Model return $this->belongsTo(AdminUser::class, 'doctor_id'); } + public function inviter() + { + return $this->belongsTo(AdminUser::class, 'inviter_id'); + } + + public function saler() + { + return $this->belongsTo(AdminUser::class, 'saler_id'); + } + public function notifyUser() { return $this->belongsTo(AdminUser::class, 'notify_user_id'); @@ -57,4 +78,11 @@ class PatientRecord extends Model { return $q->orderBy('treat_at', 'desc'); } + + protected function orderStatusText(): Attribute + { + return Attribute::make( + get: fn () => $this->order_status ? $this->order_status->text() : '', + ); + } } diff --git a/composer.json b/composer.json index d368dcd..4344534 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "laravel/framework": "^10.10", "laravel/sanctum": "^3.2", "laravel/tinker": "^2.8", + "maatwebsite/excel": "^3.1", "overtrue/laravel-wechat": "^7.2", "slowlyo/owl-admin": "^2.8", "tucker-eric/eloquentfilter": "^3.2" diff --git a/composer.lock b/composer.lock index 6501f12..601b8bb 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ce3054be9ae98c89b9e1fa42d6d712af", + "content-hash": "390fe261f07ff7ef9c30cfaa1ca4db93", "packages": [ { "name": "brick/math", @@ -68,6 +68,93 @@ ], "time": "2022-08-10T22:54:19+00:00" }, + { + "name": "composer/semver", + "version": "3.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", + "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2023-08-31T09:50:34+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.1", @@ -519,6 +606,73 @@ ], "time": "2023-01-14T14:17:03+00:00" }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.16.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/523407fb06eb9e5f3d59889b3978d5bfe94299c8", + "reference": "523407fb06eb9e5f3d59889b3978d5bfe94299c8", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.16.0" + }, + "time": "2022-09-18T07:06:19+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.2.0", @@ -1991,6 +2145,298 @@ ], "time": "2023-08-03T07:14:11+00:00" }, + { + "name": "maatwebsite/excel", + "version": "3.1.48", + "source": { + "type": "git", + "url": "https://github.com/SpartnerNL/Laravel-Excel.git", + "reference": "6d0fe2a1d195960c7af7bf0de760582da02a34b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/6d0fe2a1d195960c7af7bf0de760582da02a34b9", + "reference": "6d0fe2a1d195960c7af7bf0de760582da02a34b9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "composer/semver": "^3.3", + "ext-json": "*", + "illuminate/support": "5.8.*|^6.0|^7.0|^8.0|^9.0|^10.0", + "php": "^7.0|^8.0", + "phpoffice/phpspreadsheet": "^1.18", + "psr/simple-cache": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "orchestra/testbench": "^6.0|^7.0|^8.0", + "predis/predis": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Maatwebsite\\Excel\\ExcelServiceProvider" + ], + "aliases": { + "Excel": "Maatwebsite\\Excel\\Facades\\Excel" + } + } + }, + "autoload": { + "psr-4": { + "Maatwebsite\\Excel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Patrick Brouwers", + "email": "patrick@spartner.nl" + } + ], + "description": "Supercharged Excel exports and imports in Laravel", + "keywords": [ + "PHPExcel", + "batch", + "csv", + "excel", + "export", + "import", + "laravel", + "php", + "phpspreadsheet" + ], + "support": { + "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.48" + }, + "funding": [ + { + "url": "https://laravel-excel.com/commercial-support", + "type": "custom" + }, + { + "url": "https://github.com/patrickbrouwers", + "type": "github" + } + ], + "time": "2023-02-22T21:01:38+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/b8174494eda667f7d13876b4a7bfef0f62a7c0d1", + "reference": "b8174494eda667f7d13876b4a7bfef0f62a7c0d1", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.1" + }, + "require-dev": { + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^10.0", + "vimeo/psalm": "^5.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.0" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2023-06-21T14:59:35+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, { "name": "monolog/monolog", "version": "3.4.0", @@ -2840,6 +3286,117 @@ ], "time": "2023-09-01T11:01:34+00:00" }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.29.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^7.4 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0" + }, + "time": "2023-06-14T22:48:31+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.1", diff --git a/database/migrations/2023_08_30_075602_create_patients_table.php b/database/migrations/2023_08_30_075602_create_patients_table.php index 4f45f3d..236deb6 100644 --- a/database/migrations/2023_08_30_075602_create_patients_table.php +++ b/database/migrations/2023_08_30_075602_create_patients_table.php @@ -23,6 +23,8 @@ return new class extends Migration $table->text('illness')->nullable()->comment('病情描述'); $table->json('images')->nullable()->comment('图片'); $table->unsignedBigInteger('doctor_id')->nullable()->comment('坐诊医生, admin_users.id'); + $table->unsignedBigInteger('inviter_id')->nullable()->comment('推荐人, admin_users.id'); + $table->unsignedBigInteger('saler_id')->nullable()->comment('业务员, admin_users.id'); $table->string('remarks')->nullable()->comment('备注'); $table->timestamps(); }); diff --git a/database/migrations/2023_08_30_090313_create_patient_records_table.php b/database/migrations/2023_08_30_090313_create_patient_records_table.php index ca8bc04..e76b8a4 100644 --- a/database/migrations/2023_08_30_090313_create_patient_records_table.php +++ b/database/migrations/2023_08_30_090313_create_patient_records_table.php @@ -16,19 +16,28 @@ return new class extends Migration $table->unsignedBigInteger('patient_id')->comment('病人, patients.id'); $table->unsignedBigInteger('type_id')->comment('类别, keywords.id'); $table->timestamp('treat_at')->comment('就诊时间'); - $table->unsignedBigInteger('doctor_id')->comment('医生, admin_users.id'); $table->text('content')->comment('就诊情况'); $table->json('images')->nullable()->comment('图片'); $table->decimal('origin_price')->default(0)->comment('划线价'); $table->decimal('sell_price')->default(0)->comment('实收价'); $table->unsignedTinyInteger('order_status')->default(0)->comment('状态(0: 未收, 1: 已收)'); + $table->unsignedBigInteger('doctor_id')->comment('医生, admin_users.id'); + $table->unsignedInteger('doctor_ratio')->default(0)->comment('医生提成比例(0-100)'); + $table->decimal('doctor_money')->default(0)->comment('医生提成金额'); + $table->unsignedBigInteger('inviter_id')->nullable()->comment('推荐人, admin_users.id'); + $table->unsignedInteger('inviter_ratio')->default(0)->comment('推荐人提成比例(0-100)'); + $table->decimal('inviter_money')->default(0)->comment('医生提成金额'); + $table->unsignedBigInteger('saler_id')->nullable()->comment('业务员, admin_users.id'); + $table->unsignedInteger('saler_ratio')->default(0)->comment('业务员提成比例(0-100)'); + $table->decimal('saler_money')->default(0)->comment('医生提成金额'); + $table->timestamp('notify_at')->nullable()->comment('提醒时间'); $table->unsignedBigInteger('notify_user_id')->nullable()->comment('提醒人, admin_users.id'); $table->string('notify_remarks')->nullable()->comment('提醒备注'); $table->unsignedTinyInteger('is_notified')->default(0)->comment('是否已经提醒'); $table->timestamp('next_treat_at')->nullable()->comment('下次就诊时间'); - + $table->unsignedBigInteger('creator_id')->comment('操作人, admin_users.id'); $table->timestamps(); }); diff --git a/database/seeders/KeywordSeeder.php b/database/seeders/KeywordSeeder.php index 71b7895..2150a3d 100644 --- a/database/seeders/KeywordSeeder.php +++ b/database/seeders/KeywordSeeder.php @@ -18,8 +18,16 @@ class KeywordSeeder extends Seeder Keyword::truncate(); $list = [ ['key' => 'treat_type', 'name' => '诊疗类别', 'children' => [ - ['key' => 'treat_head', 'name' => '头疗', 'content' => '按摩意见:', 'image' => url('images/treat_head.png')], - ['key' => 'treat_normal', 'name' => '看病', 'content' => '病症:', 'image' => url('images/treat_normal.png')], + ['key' => 'treat_head', 'name' => '头疗', 'content' => '按摩意见:', 'data' => [ + 'doctor_ratio' => 10, + 'inviter_ratio' => 10, + 'saler_ratio' => 10 + ]], + ['key' => 'treat_normal', 'name' => '看病', 'content' => '病症:', 'data' => [ + 'doctor_ratio' => 10, + 'inviter_ratio' => 10, + 'saler_ratio' => 10 + ]], ]] ]; $this->createByTree($list); diff --git a/lang/zh_CN/patient-record.php b/lang/zh_CN/patient-record.php index 07937a5..12f968a 100644 --- a/lang/zh_CN/patient-record.php +++ b/lang/zh_CN/patient-record.php @@ -5,7 +5,16 @@ return [ 'patient_id' => '姓名', 'type_id' => '类别', 'treat_at' => '诊疗时间', + 'admin_user_id' => '相关人员', 'doctor_id' => '就诊医生', + 'doctor_ratio' => '医生提成比例(%)', + 'doctor_money' => '医生提成金额', + 'saler_id' => '业务员', + 'saler_ratio' => '业务员提成比例(%)', + 'saler_money' => '业务员提成金额', + 'inviter_id' => '推荐人', + 'inviter_ratio' => '推荐人提成比例(%)', + 'inviter_money' => '推荐人提成金额', 'content' => '诊疗情况', 'origin_price' => '划线价', 'sell_price' => '实收价', diff --git a/lang/zh_CN/patient.php b/lang/zh_CN/patient.php index f528d5a..339d0df 100644 --- a/lang/zh_CN/patient.php +++ b/lang/zh_CN/patient.php @@ -11,6 +11,9 @@ return [ 'treat_at' => '初诊时间', 'illness' => '病情描述', 'doctor_id' => '坐诊医生', + 'saler_id' => '业务员', + 'inviter_id' => '推荐人', + 'admin_user_id' => '相关人员', 'age' => '年龄', 'remarks' => '备注', 'created_at' => '录入时间',