patient user_id
parent
1bae9b8f52
commit
647c0807d0
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Admin\Controllers;
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Services\UserService;
|
||||||
use App\Enums\Gender;
|
use App\Enums\Gender;
|
||||||
use App\Admin\Components;
|
use App\Admin\Components;
|
||||||
use App\Admin\Services\PatientService;
|
use App\Admin\Services\PatientService;
|
||||||
|
|
@ -30,7 +31,7 @@ class PatientController extends AdminController
|
||||||
->filterTogglable(false)
|
->filterTogglable(false)
|
||||||
->columnsTogglable(false)
|
->columnsTogglable(false)
|
||||||
->headerToolbar([
|
->headerToolbar([
|
||||||
$this->createButton(true, 'lg'),
|
$this->createButton(),
|
||||||
amis('reload')->align('right'),
|
amis('reload')->align('right'),
|
||||||
$this->exportAction(),
|
$this->exportAction(),
|
||||||
])
|
])
|
||||||
|
|
@ -65,11 +66,22 @@ class PatientController extends AdminController
|
||||||
{
|
{
|
||||||
return $this->baseForm()->body([
|
return $this->baseForm()->body([
|
||||||
amisMake()->SelectControl()->options($this->getTypeOptions())->name('type_id')->label(__('patient.type_id'))->required(),
|
amisMake()->SelectControl()->options($this->getTypeOptions())->name('type_id')->label(__('patient.type_id'))->required(),
|
||||||
amisMake()->TextControl()->name('name')->label(__('patient.name'))->required(true),
|
amisMake()->SelectControl()->source(admin_url('/api/user/list'))->labelField('phone')->valueField('id')->name('user_id')->label(__('patient.user_id'))->clearable()->onEvent([
|
||||||
amisMake()->SelectControl()->options(Gender::options())->name('sex')->label(__('patient.sex')),
|
'change' => [
|
||||||
amisMake()->TextControl()->name('phone')->label(__('patient.phone')),
|
'actions' => [
|
||||||
amisMake()->TextControl()->name('address')->label(__('patient.address')),
|
['actionType' => 'setValue', 'componentId' => 'patient_name', 'args' => ['value' => '${event.data.selectedItems.name}']],
|
||||||
amisMake()->DateControl()->name('birthday')->label(__('patient.birthday')),
|
['actionType' => 'setValue', 'componentId' => 'patient_sex', 'args' => ['value' => '${event.data.selectedItems.sex}']],
|
||||||
|
['actionType' => 'setValue', 'componentId' => 'patient_phone', 'args' => ['value' => '${event.data.selectedItems.phone}']],
|
||||||
|
['actionType' => 'setValue', 'componentId' => 'patient_address', 'args' => ['value' => '${event.data.selectedItems.address}']],
|
||||||
|
['actionType' => 'setValue', 'componentId' => 'patient_birthday', 'args' => ['value' => '${event.data.selectedItems.birthday}']],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
amisMake()->TextControl()->name('name')->label(__('patient.name'))->id('patient_name')->required(true),
|
||||||
|
amisMake()->SelectControl()->options(Gender::options())->name('sex')->label(__('patient.sex'))->id('patient_sex'),
|
||||||
|
amisMake()->TextControl()->name('phone')->label(__('patient.phone'))->id('patient_phone'),
|
||||||
|
amisMake()->TextControl()->name('address')->label(__('patient.address'))->id('patient_address'),
|
||||||
|
amisMake()->DateControl()->name('birthday')->label(__('patient.birthday'))->id('patient_birthday'),
|
||||||
amisMake()->DateControl()->name('treat_at')->label(__('patient.treat_at')),
|
amisMake()->DateControl()->name('treat_at')->label(__('patient.treat_at')),
|
||||||
amisMake()->SelectControl()->options($this->getAdminUserOptions())->searchable()->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('inviter_id')->label(__('patient.inviter_id')),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Admin\Services\UserService;
|
||||||
|
use App\Enums\Gender;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Slowlyo\OwlAdmin\Controllers\AdminController;
|
||||||
|
use Slowlyo\OwlAdmin\Renderers\Form;
|
||||||
|
use Slowlyo\OwlAdmin\Renderers\Page;
|
||||||
|
use Slowlyo\OwlAdmin\Support\Excel\AdminExport;
|
||||||
|
|
||||||
|
class UserController extends AdminController
|
||||||
|
{
|
||||||
|
protected string $serviceName = UserService::class;
|
||||||
|
|
||||||
|
public function list(): Page
|
||||||
|
{
|
||||||
|
$crud = $this->baseCRUD()
|
||||||
|
->filterTogglable(false)
|
||||||
|
->columnsTogglable(false)
|
||||||
|
->alwaysShowPagination()
|
||||||
|
->headerToolbar([
|
||||||
|
$this->createButton(true),
|
||||||
|
$this->exportAction(),
|
||||||
|
])
|
||||||
|
->filter($this->baseFilter()->actions()->body([
|
||||||
|
amisMake()->TextControl()->name('keyword')->label(__('user.keyword'))->size('md')->placeholder(__('user.phone') . '或' . __('user.name'))->clearable(),
|
||||||
|
// amisMake()->Button()->label(__('admin.reset'))->actionType('clear-and-submit'),
|
||||||
|
amisMake()->Component()->setType('submit')->label(__('admin.search'))->level('primary'),
|
||||||
|
]))
|
||||||
|
->columns([
|
||||||
|
amisMake()->TableColumn()->name('id')->label(__('user.id')),
|
||||||
|
amisMake()->TableColumn()->name('phone')->label(__('user.phone')),
|
||||||
|
amisMake()->TableColumn()->name('name')->label(__('user.name')),
|
||||||
|
amisMake()->TableColumn()->name('sex_text')->label(__('user.sex')),
|
||||||
|
amisMake()->TableColumn()->name('age')->label(__('user.age')),
|
||||||
|
amisMake()->TableColumn()->name('address')->label(__('user.address')),
|
||||||
|
amisMake()->TableColumn()->name('created_at')->label(__('user.created_at')),
|
||||||
|
$this->rowActions(true),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->baseList($crud);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function form($isEdit): Form
|
||||||
|
{
|
||||||
|
return $this->baseForm()->body([
|
||||||
|
amisMake()->TextControl()->name('phone')->label(__('user.phone'))->required(),
|
||||||
|
amisMake()->TextControl()->set('type', 'input-password')->name('password')->label(__('user.password'))->required(!$isEdit),
|
||||||
|
amisMake()->TextControl()->name('name')->label(__('user.name')),
|
||||||
|
amisMake()->SelectControl()->options(Gender::options())->name('sex')->label(__('user.sex')),
|
||||||
|
amisMake()->TextControl()->name('address')->label(__('user.address')),
|
||||||
|
amisMake()->DateControl()->name('birthday')->label(__('user.birthday')),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function detail()
|
||||||
|
{
|
||||||
|
return $this->baseDetail()->body([
|
||||||
|
amisMake()->TextControl()->name('id')->label(__('user.id'))->static(),
|
||||||
|
amisMake()->TextControl()->name('phone')->label(__('user.phone'))->static(),
|
||||||
|
amisMake()->TextControl()->name('name')->label(__('user.name'))->static(),
|
||||||
|
amisMake()->TextControl()->name('sex_text')->label(__('user.sex'))->static(),
|
||||||
|
amisMake()->TextControl()->name('age')->label(__('user.age'))->static(),
|
||||||
|
amisMake()->DateControl()->name('birthday')->label(__('user.birthday'))->static(),
|
||||||
|
amisMake()->TextControl()->name('address')->label(__('user.address'))->static(),
|
||||||
|
amisMake()->DateTimeControl()->name('created_at')->label(__('user.created_at'))->static(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getList(Request $request)
|
||||||
|
{
|
||||||
|
$list = $this->service->listQuery()->get();
|
||||||
|
|
||||||
|
return $this->response()->success($list);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function exportAction($disableSelectedItem = false)
|
||||||
|
{
|
||||||
|
$event = fn($script) => ['click' => ['actions' => [['actionType' => 'custom', 'script' => $script]]]];
|
||||||
|
$downloadPath = '/' . admin_url('_download_export', true);
|
||||||
|
$exportPath = $this->getExportPath();
|
||||||
|
$doAction = <<<JS
|
||||||
|
doAction([
|
||||||
|
{ actionType: "ajax", args: { api: { url: url.toString(), method: "get" } } },
|
||||||
|
{
|
||||||
|
actionType: "custom",
|
||||||
|
expression: "\${event.data.responseResult.responseStatus === 0}",
|
||||||
|
script: "window.open('{$downloadPath}?path='+event.data.responseResult.responseData.path)"
|
||||||
|
}
|
||||||
|
])
|
||||||
|
JS;
|
||||||
|
$buttons = [
|
||||||
|
amisMake()->VanillaAction()->label(__('admin.export.all'))->onEvent(
|
||||||
|
$event(<<<JS
|
||||||
|
let url = new URL("{$exportPath}", window.location.origin)
|
||||||
|
let param = window.location.href.split('?')[1]
|
||||||
|
if (param) {
|
||||||
|
url = url + '&' + param
|
||||||
|
}
|
||||||
|
{$doAction}
|
||||||
|
JS
|
||||||
|
|
||||||
|
)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
return amisMake()
|
||||||
|
->DropdownButton()
|
||||||
|
->label(__('admin.export.title'))
|
||||||
|
->set('icon', 'fa-solid fa-download')
|
||||||
|
->buttons($buttons)
|
||||||
|
->align('right')
|
||||||
|
->closeOnClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function export()
|
||||||
|
{
|
||||||
|
// 默认在 storage/app/ 下
|
||||||
|
$path = sprintf('%s-%s.xlsx', $this->exportFileName(), date('YmdHis'));
|
||||||
|
|
||||||
|
// 导出本页和导出选中项都是通过 _ids 查询
|
||||||
|
$ids = request()->input('_ids');
|
||||||
|
|
||||||
|
// listQuery() 为列表查询条件,与获取列表数据一致
|
||||||
|
$query = $this->service->listQuery()
|
||||||
|
->when($ids, fn($query) => $query->whereIn($this->service->primaryKey(), explode(',', $ids)));
|
||||||
|
|
||||||
|
// 此处使用 laravel-excel 导出,可自行修改
|
||||||
|
AdminExport::make($query)
|
||||||
|
->setHeadings([
|
||||||
|
__('user.id'),
|
||||||
|
__('user.phone'),
|
||||||
|
__('user.name'),
|
||||||
|
__('user.sex'),
|
||||||
|
__('user.age'),
|
||||||
|
__('user.birthday'),
|
||||||
|
__('user.address'),
|
||||||
|
__('user.created_at'),
|
||||||
|
])
|
||||||
|
->setMap(function ($item) {
|
||||||
|
return [
|
||||||
|
$item->id,
|
||||||
|
$item->phone,
|
||||||
|
$item->name,
|
||||||
|
$item->sex_text,
|
||||||
|
$item->age,
|
||||||
|
$item->birthday_format,
|
||||||
|
$item->address,
|
||||||
|
$item->created_at,
|
||||||
|
];
|
||||||
|
})
|
||||||
|
->store($path);
|
||||||
|
|
||||||
|
return $this->response()->success(compact('path'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Admin\Services;
|
namespace App\Admin\Services;
|
||||||
|
|
||||||
use App\ModelFilters\PatientFilter;
|
use App\ModelFilters\PatientFilter;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
use App\Models\{Patient, PatientRecord};
|
use App\Models\{Patient, PatientRecord};
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
|
||||||
|
|
@ -10,7 +11,7 @@ class PatientService extends BaseService
|
||||||
{
|
{
|
||||||
protected string $modelName = Patient::class;
|
protected string $modelName = Patient::class;
|
||||||
|
|
||||||
protected array $withRelationships = ['doctor', 'inviter', 'saler', 'type'];
|
protected array $withRelationships = ['doctor', 'inviter', 'saler', 'type', 'user'];
|
||||||
|
|
||||||
protected string $modelFilterName = PatientFilter::class;
|
protected string $modelFilterName = PatientFilter::class;
|
||||||
|
|
||||||
|
|
@ -53,13 +54,22 @@ class PatientService extends BaseService
|
||||||
*/
|
*/
|
||||||
public function validate($data, $model = null)
|
public function validate($data, $model = null)
|
||||||
{
|
{
|
||||||
if (!$model) {
|
$userRule = Rule::unique('patients', 'user_id');
|
||||||
$validator = Validator::make($data, [
|
$createRule = [
|
||||||
'name' => ['required'],
|
'type_id' => 'required',
|
||||||
]);
|
'name' => 'required',
|
||||||
if ($validator->fails()) {
|
'user_id' => $userRule->where('type_id', data_get($data, 'type_id'))
|
||||||
return $validator->errors()->first();
|
];
|
||||||
}
|
$updateRule = [
|
||||||
|
'user_id' => $userRule->where('type_id', data_get($data, 'type_id', $model?->type_id))
|
||||||
|
];
|
||||||
|
$validator = Validator::make($data, $model ? $updateRule : $createRule, [
|
||||||
|
'type_id.required' => __('patient.type_id') . '必填',
|
||||||
|
'name.required' => __('patient.name') . '必填',
|
||||||
|
'user_id.unique' => __('patient.user_id') . '已经存在',
|
||||||
|
]);
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return $validator->errors()->first();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Admin\Services;
|
||||||
|
|
||||||
|
use App\ModelFilters\UserFilter;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UserService extends BaseService
|
||||||
|
{
|
||||||
|
protected string $modelName = User::class;
|
||||||
|
|
||||||
|
protected array $withRelationships = [];
|
||||||
|
|
||||||
|
protected string $modelFilterName = UserFilter::class;
|
||||||
|
|
||||||
|
public function listQuery()
|
||||||
|
{
|
||||||
|
$filter = $this->getModelFilter();
|
||||||
|
|
||||||
|
$query = $this->query();
|
||||||
|
if ($this->withRelationships) {
|
||||||
|
$query->with($this->withRelationships);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($filter) {
|
||||||
|
$query->filter(request()->input(), $filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate($data, $model = null)
|
||||||
|
{
|
||||||
|
$phoneRule = Rule::unique('users', 'phone');
|
||||||
|
if ($model) {
|
||||||
|
$phoneRule->ignore($model->id);
|
||||||
|
}
|
||||||
|
$validator = Validator::make($data, [
|
||||||
|
'phone' => ['required', 'phone', $phoneRule],
|
||||||
|
], [
|
||||||
|
'phone.required' => __('user.phone') . '必填',
|
||||||
|
'phone.phone' => __('user.phone') . ' 不是合法手机号',
|
||||||
|
'phone.unique' => __('user.phone') . '已经存在',
|
||||||
|
]);
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return $validator->errors()->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,8 +32,9 @@ Route::group([
|
||||||
$router->get('category/content', '\App\Admin\Controllers\CategoryController@getContent')->name('api.category.content');
|
$router->get('category/content', '\App\Admin\Controllers\CategoryController@getContent')->name('api.category.content');
|
||||||
$router->get('patient/options', '\App\Admin\Controllers\PatientController@getSelectOptions')->name('api.patient.options');
|
$router->get('patient/options', '\App\Admin\Controllers\PatientController@getSelectOptions')->name('api.patient.options');
|
||||||
$router->get('category/permission-list', '\App\Admin\Controllers\CategoryController@getPermissionList')->name('api.category.permission_list');
|
$router->get('category/permission-list', '\App\Admin\Controllers\CategoryController@getPermissionList')->name('api.category.permission_list');
|
||||||
|
$router->get('user/list', '\App\Admin\Controllers\UserController@getList');
|
||||||
});
|
});
|
||||||
|
$router->resource('user', \App\Admin\Controllers\UserController::class)->names('admin.user');
|
||||||
// 字典表
|
// 字典表
|
||||||
$router->resource('keywords', \App\Admin\Controllers\KeywordsController::class)->names('admin.keywords');
|
$router->resource('keywords', \App\Admin\Controllers\KeywordsController::class)->names('admin.keywords');
|
||||||
// 分类管理
|
// 分类管理
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class PatientRecordNotify extends Command
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$now = now();
|
$now = now();
|
||||||
$list = PatientRecord::with(['patient'])
|
$list = PatientRecord::with(['patient.user'])
|
||||||
->where('is_notified', 0)
|
->where('is_notified', 0)
|
||||||
->whereNotNull('notify_user_id')
|
->whereNotNull('notify_user_id')
|
||||||
->whereNotNull('next_treat_at')
|
->whereNotNull('next_treat_at')
|
||||||
|
|
@ -46,12 +46,15 @@ class PatientRecordNotify extends Command
|
||||||
));
|
));
|
||||||
$api = $app->getClient();
|
$api = $app->getClient();
|
||||||
// 微信公众号关联账户
|
// 微信公众号关联账户
|
||||||
$users = UserSocialite::where('user_type', (new AdminUser)->getMorphClass())->where('type', SocialiteType::WxOfficial)->whereIn('user_id', $list->pluck('notify_user_id'))->get();
|
$adminUsers = UserSocialite::where('user_type', (new AdminUser)->getMorphClass())
|
||||||
|
->where('type', SocialiteType::WxOfficial)
|
||||||
|
->whereIn('user_id', $list->pluck('notify_user_id'))
|
||||||
|
->get();
|
||||||
foreach ($list as $item) {
|
foreach ($list as $item) {
|
||||||
$user = $users->firstWhere('user_id', $item->notify_user_id);
|
$adminUser = $adminUsers->firstWhere('user_id', $item->notify_user_id);
|
||||||
if ($user) {
|
if ($adminUser) {
|
||||||
$response = $api->postJson('/cgi-bin/message/template/send', [
|
$response = $api->postJson('/cgi-bin/message/template/send', [
|
||||||
'touser' => $user->openid,
|
'touser' => $adminUser->openid,
|
||||||
'template_id' => 'zdkOoIk7bfyzpW9Tuu-pxqh2no-93FCcqstFKLOTfu0',
|
'template_id' => 'zdkOoIk7bfyzpW9Tuu-pxqh2no-93FCcqstFKLOTfu0',
|
||||||
'url' => url('/h5/pages/record/detail?id=' . $item->id),
|
'url' => url('/h5/pages/record/detail?id=' . $item->id),
|
||||||
'data' => [
|
'data' => [
|
||||||
|
|
@ -70,8 +73,8 @@ class PatientRecordNotify extends Command
|
||||||
logger('病历记录: 通知, 模板消息发送, 失败', $response->toArray(false));
|
logger('病历记录: 通知, 模板消息发送, 失败', $response->toArray(false));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$item->update(['is_notified' => 1]);
|
|
||||||
}
|
}
|
||||||
|
$item->update(['is_notified' => 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\ModelFilters;
|
||||||
|
|
||||||
|
use EloquentFilter\ModelFilter;
|
||||||
|
|
||||||
|
class UserFilter extends ModelFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Related Models that have ModelFilters as well as the method on the ModelFilter
|
||||||
|
* As [relationMethod => [input_key1, input_key2]].
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $relations = [];
|
||||||
|
|
||||||
|
public function phone($key)
|
||||||
|
{
|
||||||
|
$this->whereLike('phone', $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function name($key)
|
||||||
|
{
|
||||||
|
$this->whereLike('name', $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function keyword($key)
|
||||||
|
{
|
||||||
|
$str = '%'.$key.'%';
|
||||||
|
$this->where(fn ($q) => $q->where('phone', 'like', $str)->orWhere('name', 'like', $str));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ignoreType($key)
|
||||||
|
{
|
||||||
|
$this->whereDoesntHave('patients', fn ($q) => $q->where('type_id', $key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,9 +17,10 @@ class Patient extends Model
|
||||||
use HasDateTimeFormatter, Filterable;
|
use HasDateTimeFormatter, Filterable;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
'type_id', 'user_id',
|
||||||
'name', 'sex', 'phone', 'address', 'birthday',
|
'name', 'sex', 'phone', 'address', 'birthday',
|
||||||
'treat_at', 'illness', 'remarks', 'images',
|
'treat_at', 'illness', 'remarks', 'images',
|
||||||
'doctor_id', 'inviter_id', 'saler_id', 'type_id',
|
'doctor_id', 'inviter_id', 'saler_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $appends = ['age', 'sex_text', 'treat_format', 'birthday_format'];
|
protected $appends = ['age', 'sex_text', 'treat_format', 'birthday_format'];
|
||||||
|
|
@ -59,6 +60,11 @@ class Patient extends Model
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function doctor()
|
public function doctor()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(AdminUser::class, 'doctor_id');
|
return $this->belongsTo(AdminUser::class, 'doctor_id');
|
||||||
|
|
|
||||||
|
|
@ -2,43 +2,57 @@
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use App\Enums\Gender;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use App\Traits\HasDateTimeFormatter;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use EloquentFilter\Filterable;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticate;
|
||||||
use Laravel\Sanctum\HasApiTokens;
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
|
||||||
class User extends Authenticatable
|
class User extends Authenticate
|
||||||
{
|
{
|
||||||
use HasApiTokens, HasFactory, Notifiable;
|
use HasApiTokens, Filterable, HasDateTimeFormatter;
|
||||||
|
|
||||||
/**
|
protected $fillable = ['address', 'birthday', 'name', 'password', 'phone', 'sex'];
|
||||||
* The attributes that are mass assignable.
|
|
||||||
*
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $fillable = [
|
|
||||||
'name',
|
|
||||||
'email',
|
|
||||||
'password',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
protected $appends = ['age', 'sex_text', 'birthday_format'];
|
||||||
* The attributes that should be hidden for serialization.
|
|
||||||
*
|
protected $hidden = ['password'];
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
protected $hidden = [
|
|
||||||
'password',
|
|
||||||
'remember_token',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The attributes that should be cast.
|
|
||||||
*
|
|
||||||
* @var array<string, string>
|
|
||||||
*/
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'email_verified_at' => 'datetime',
|
'sex' => Gender::class,
|
||||||
|
'birthday' => 'date',
|
||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function patients()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Patient::class, 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function age(): Attribute
|
||||||
|
{
|
||||||
|
return new Attribute(
|
||||||
|
get: fn () => $this->birthday ? $this->birthday->diffInYears() : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function sexText(): Attribute
|
||||||
|
{
|
||||||
|
return new Attribute(
|
||||||
|
get: fn () => $this->sex ? $this->sex->text() : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function birthdayFormat(): Attribute
|
||||||
|
{
|
||||||
|
return new Attribute(
|
||||||
|
get: fn () => $this->birthday ? $this->birthday->format('Y-m-d') : '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeSort($q)
|
||||||
|
{
|
||||||
|
return $q->orderBy('created_at', 'desc');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
use App\Models\Keyword;
|
use App\Models\Keyword;
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use App\Models\Patient;
|
use App\Models\Patient;
|
||||||
use App\Enums\Gender;
|
use App\Enums\Gender;
|
||||||
|
|
@ -23,13 +24,16 @@ class PatientFactory extends Factory
|
||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
$faker = $this->faker;
|
$faker = $this->faker;
|
||||||
|
$type_id = Keyword::where('type_key', 'treat_type')->inRandomOrder()->value('id');
|
||||||
|
$user = User::query()->inRandomOrder()->first();
|
||||||
return [
|
return [
|
||||||
'type_id' => Keyword::where('type_key', 'treat_type')->inRandomOrder()->value('id'),
|
'type_id' => $type_id,
|
||||||
'name' => $faker->name,
|
'user_id' => $user->id,
|
||||||
'sex' => $faker->randomElement(array_keys(Gender::map())),
|
'name' => $user->name,
|
||||||
'phone' => $faker->phoneNumber,
|
'sex' => $user->sex,
|
||||||
'address' => $faker->address,
|
'phone' => $user->phone,
|
||||||
'birthday' => $faker->dateTimeBetween('-30 years', '-10 years'),
|
'address' => $user->address,
|
||||||
|
'birthday' => $user->birthday,
|
||||||
'treat_at' => $faker->dateTimeBetween('-7 days'),
|
'treat_at' => $faker->dateTimeBetween('-7 days'),
|
||||||
'illness' => '基本稳定',
|
'illness' => '基本稳定',
|
||||||
'doctor_id' => AdminUser::inRandomOrder()->value('id'),
|
'doctor_id' => AdminUser::inRandomOrder()->value('id'),
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
namespace Database\Factories;
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Enums\Gender;
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
|
||||||
*/
|
|
||||||
class UserFactory extends Factory
|
class UserFactory extends Factory
|
||||||
{
|
{
|
||||||
|
protected $model = User::class;
|
||||||
/**
|
/**
|
||||||
* Define the model's default state.
|
* Define the model's default state.
|
||||||
*
|
*
|
||||||
|
|
@ -17,12 +17,14 @@ class UserFactory extends Factory
|
||||||
*/
|
*/
|
||||||
public function definition(): array
|
public function definition(): array
|
||||||
{
|
{
|
||||||
|
$faker = $this->faker;
|
||||||
return [
|
return [
|
||||||
'name' => fake()->name(),
|
'address' => $faker->address,
|
||||||
'email' => fake()->unique()->safeEmail(),
|
'birthday' => $faker->dateTimeBetween('-30 years', '-10 years'),
|
||||||
'email_verified_at' => now(),
|
'name' => $faker->name,
|
||||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
'password' => '$10$MXFSBvoV02d.nMg/5//5ru/os27JgSJhsePidDr/uiIw6UQ.MigP2',
|
||||||
'remember_token' => Str::random(10),
|
'phone' => $faker->phoneNumber,
|
||||||
|
'sex' => $faker->randomElement(array_keys(Gender::map()))
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ return new class extends Migration
|
||||||
{
|
{
|
||||||
Schema::create('patients', function (Blueprint $table) {
|
Schema::create('patients', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->string('name')->comment('姓名');
|
|
||||||
$table->unsignedBigInteger('type_id')->comment('类别, keywords.id');
|
$table->unsignedBigInteger('type_id')->comment('类别, keywords.id');
|
||||||
|
$table->string('name')->comment('姓名');
|
||||||
$table->string('sex')->default(Gender::None->value)->comment('性别');
|
$table->string('sex')->default(Gender::None->value)->comment('性别');
|
||||||
$table->string('phone')->nullable()->comment('联系方式');
|
$table->string('phone')->nullable()->comment('联系方式');
|
||||||
$table->string('address')->nullable()->comment('地址');
|
$table->string('address')->nullable()->comment('地址');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('users', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('phone')->comment('联系方式')->unique();
|
||||||
|
$table->string('password')->comment('登录密码');
|
||||||
|
$table->string('name')->nullable()->comment('姓名');
|
||||||
|
$table->string('sex')->default(\App\Enums\Gender::None->value)->comment('性别');
|
||||||
|
$table->string('address')->nullable()->comment('地址');
|
||||||
|
$table->date('birthday')->nullable()->comment('出生年月');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('patients', function (Blueprint $table) {
|
||||||
|
$table->unsignedBigInteger('user_id')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('users');
|
||||||
|
Schema::table('patients', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('user_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -20,6 +20,7 @@ class AdminMenuSeeder extends Seeder
|
||||||
$menus = [
|
$menus = [
|
||||||
['title' => '主页', 'icon' => 'icon-park:home-two', 'url' => '/dashboard', 'is_home' => 1],
|
['title' => '主页', 'icon' => 'icon-park:home-two', 'url' => '/dashboard', 'is_home' => 1],
|
||||||
['title' => '分类管理', 'icon' => 'icon-park:all-application', 'url' => '/category'],
|
['title' => '分类管理', 'icon' => 'icon-park:all-application', 'url' => '/category'],
|
||||||
|
['title' => '客户管理', 'icon' => 'icon-park:user', 'url' => '/user'],
|
||||||
['title' => '病人管理', 'icon' => 'icon-park:peoples-two', 'url' => '/patient'],
|
['title' => '病人管理', 'icon' => 'icon-park:peoples-two', 'url' => '/patient'],
|
||||||
['title' => '病历管理', 'icon' => 'icon-park:newspaper-folding', 'url' => '/record'],
|
['title' => '病历管理', 'icon' => 'icon-park:newspaper-folding', 'url' => '/record'],
|
||||||
['title' => '客户统计', 'icon' => 'icon-park:user-positioning', 'url' => '/total/record'],
|
['title' => '客户统计', 'icon' => 'icon-park:user-positioning', 'url' => '/total/record'],
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ namespace Database\Seeders;
|
||||||
|
|
||||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
use Database\Factories\{PatientFactory, PatientRecordFactory};
|
use Database\Factories\{PatientFactory, PatientRecordFactory, UserFactory};
|
||||||
use App\Models\{Patient, PatientRecord};
|
use App\Models\{Patient, PatientRecord, User};
|
||||||
|
|
||||||
class PatientSeeder extends Seeder
|
class PatientSeeder extends Seeder
|
||||||
{
|
{
|
||||||
|
|
@ -14,9 +14,11 @@ class PatientSeeder extends Seeder
|
||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
User::truncate();
|
||||||
Patient::truncate();
|
Patient::truncate();
|
||||||
PatientRecord::truncate();
|
PatientRecord::truncate();
|
||||||
(new PatientFactory())->count(100)->create();
|
(new UserFactory())->count(50)->create();
|
||||||
(new PatientRecordFactory())->count(1000)->create();
|
(new PatientFactory())->count(80)->create();
|
||||||
|
(new PatientRecordFactory())->count(200)->create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ return [
|
||||||
'sell_price' => '实收价',
|
'sell_price' => '实收价',
|
||||||
'order_status' => '收费情况',
|
'order_status' => '收费情况',
|
||||||
'notify_at' => '通知时间',
|
'notify_at' => '通知时间',
|
||||||
'notify_user_id' => '通知人',
|
'notify_user_id' => '通知医师',
|
||||||
'notify_remarks' => '通知备注',
|
'notify_remarks' => '通知备注',
|
||||||
'is_notified' => '开启通知',
|
'is_notified' => '开启通知',
|
||||||
'next_treat_at' => '下次就诊时间',
|
'next_treat_at' => '下次就诊时间',
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,5 @@ return [
|
||||||
'remarks' => '备注',
|
'remarks' => '备注',
|
||||||
'created_at' => '录入时间',
|
'created_at' => '录入时间',
|
||||||
'images' => '图片资料',
|
'images' => '图片资料',
|
||||||
|
'user_id' => '客户',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => 'ID',
|
||||||
|
'phone' => '手机号',
|
||||||
|
'name' => '姓名',
|
||||||
|
'sex' => '性别',
|
||||||
|
'address' => '地址',
|
||||||
|
'birthday' => '出生年月',
|
||||||
|
'age' => '年龄',
|
||||||
|
'created_at' => '注册时间',
|
||||||
|
'password' => '登录密码',
|
||||||
|
'keyword' => '关键字',
|
||||||
|
];
|
||||||
Loading…
Reference in New Issue