教师
This commit is contained in:
2
.env
2
.env
@@ -9,7 +9,7 @@ DB_USERNAME=hyperf_data
|
||||
DB_PASSWORD=4cfDRXZSksn7npiP
|
||||
DB_CHARSET=utf8mb4
|
||||
DB_COLLATION=utf8mb4_unicode_ci
|
||||
DB_PREFIX=da_
|
||||
DB_PREFIX=
|
||||
|
||||
REDIS_HOST=localhost
|
||||
REDIS_AUTH=(null)
|
||||
|
||||
162
app/Controller/TeacherController.php
Normal file
162
app/Controller/TeacherController.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Aether\AetherController;
|
||||
use Aether\AetherResponse;
|
||||
use App\Exception\BusinessException;
|
||||
use App\Model\Teacher;
|
||||
use App\Validator\TeacherValidator;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
|
||||
/**
|
||||
* @Controller(prefix="/api/v1/teacher")
|
||||
*/
|
||||
class TeacherController extends AetherController
|
||||
{
|
||||
#[Inject]
|
||||
protected TeacherValidator $validator;
|
||||
|
||||
/**
|
||||
* 创建教师.
|
||||
* @PostMapping(path="")
|
||||
*/
|
||||
public function create(RequestInterface $request): array
|
||||
{
|
||||
$data = $request->all();
|
||||
$validator = $this->validator->validateCreate($data);
|
||||
if ($validator->fails()) {
|
||||
throw new BusinessException(400, $validator->errors()->first());
|
||||
}
|
||||
|
||||
$teacher = new Teacher();
|
||||
$teacher->fill($data);
|
||||
$teacher->save();
|
||||
|
||||
return AetherResponse::success($teacher->toArray(), '教师创建成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取教师详情.
|
||||
* @GetMapping(path="/{id}")
|
||||
*/
|
||||
public function get(int $id): array
|
||||
{
|
||||
$teacher = Teacher::find($id);
|
||||
if (! $teacher) {
|
||||
throw new BusinessException(10101);
|
||||
}
|
||||
|
||||
return AetherResponse::success($teacher->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新教师信息.
|
||||
* @PutMapping(path="/{id}")
|
||||
*/
|
||||
public function update(int $id, RequestInterface $request): array
|
||||
{
|
||||
$data = $request->all();
|
||||
$data['id'] = $id;
|
||||
|
||||
$validator = $this->validator->validateUpdate($data);
|
||||
if ($validator->fails()) {
|
||||
throw new BusinessException(400, $validator->errors()->first());
|
||||
}
|
||||
|
||||
$teacher = Teacher::find($id);
|
||||
if (! $teacher) {
|
||||
throw new BusinessException(10101);
|
||||
}
|
||||
|
||||
$teacher->fill($data);
|
||||
$teacher->save();
|
||||
|
||||
return AetherResponse::success($teacher->toArray(), '教师信息更新成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除教师.
|
||||
* @DeleteMapping(path="/{id}")
|
||||
*/
|
||||
public function delete(int $id): array
|
||||
{
|
||||
$teacher = Teacher::find($id);
|
||||
if (! $teacher) {
|
||||
throw new BusinessException(10101);
|
||||
}
|
||||
|
||||
$teacher->delete();
|
||||
return AetherResponse::success(null, '教师删除成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 教师列表.
|
||||
* @GetMapping(path="/list")
|
||||
*/
|
||||
public function list(RequestInterface $request): array
|
||||
{
|
||||
$data = $request->all();
|
||||
$validator = $this->validator->validateQuery($data);
|
||||
if ($validator->fails()) {
|
||||
throw new BusinessException(400, $validator->errors()->first());
|
||||
}
|
||||
|
||||
$query = Teacher::query();
|
||||
|
||||
if (! empty($data['id'])) {
|
||||
$query->where('id', $data['id']);
|
||||
}
|
||||
if (! empty($data['name'])) {
|
||||
$query->where('name', 'like', "%{$data['name']}%");
|
||||
}
|
||||
if (isset($data['campus_id'])) {
|
||||
$query->where('campus_id', $data['campus_id']);
|
||||
}
|
||||
if (! empty($data['major_subject'])) {
|
||||
$query->where('major_subject', 'like', "%{$data['major_subject']}%");
|
||||
}
|
||||
if (isset($data['status'])) {
|
||||
$query->where('status', $data['status']);
|
||||
}
|
||||
|
||||
$page = $data['page'] ?? 1;
|
||||
$size = $data['size'] ?? 20;
|
||||
|
||||
$total = $query->count();
|
||||
$list = $query->forPage($page, $size)->get()->toArray();
|
||||
|
||||
return AetherResponse::success([
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'size' => $size,
|
||||
'list' => $list,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索教师.
|
||||
* @GetMapping(path="/search")
|
||||
*/
|
||||
public function search(RequestInterface $request): array
|
||||
{
|
||||
$keyword = $request->input('keyword', '');
|
||||
$page = (int) $request->input('page', 1);
|
||||
$size = (int) $request->input('size', 20);
|
||||
|
||||
$query = Teacher::search($keyword)->enabled();
|
||||
|
||||
$total = $query->count();
|
||||
$list = $query->forPage($page, $size)->get()->toArray();
|
||||
|
||||
return AetherResponse::success([
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'size' => $size,
|
||||
'list' => $list,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,9 @@ class BusinessException extends ServerException
|
||||
10002 => '校区已存在',
|
||||
10003 => '父级校区不存在',
|
||||
10004 => '层级参数错误',
|
||||
10101 => '教师不存在',
|
||||
10102 => '教师已存在',
|
||||
10103 => '该教师已有关联课程,无法删除',
|
||||
];
|
||||
|
||||
return $messages[$code] ?? '业务处理失败';
|
||||
|
||||
88
app/JsonRpc/Service/TeacherService.php
Normal file
88
app/JsonRpc/Service/TeacherService.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\JsonRpc\Service;
|
||||
|
||||
use Aether\Exception\BusinessException;
|
||||
use App\Model\Teacher;
|
||||
use Hyperf\RpcServer\Annotation\RpcService;
|
||||
use MicroService\Contract\TeacherServiceInterface;
|
||||
|
||||
#[RpcService(
|
||||
name: 'DataTeacher',
|
||||
server: 'jsonrpc-http',
|
||||
protocol: 'jsonrpc-http',
|
||||
publishTo: 'nacos'
|
||||
)]
|
||||
class TeacherService implements TeacherServiceInterface
|
||||
{
|
||||
public function getTeacherById(int $id): array
|
||||
{
|
||||
$teacher = Teacher::find($id);
|
||||
if (! $teacher || $teacher->status != 1) {
|
||||
throw new BusinessException('教师不存在或已禁用', 10101);
|
||||
}
|
||||
return $teacher->toArray();
|
||||
}
|
||||
|
||||
public function getTeachersByIds(array $ids): array
|
||||
{
|
||||
return Teacher::whereIn('id', $ids)
|
||||
->enabled()
|
||||
->orderBy('sort_order', 'asc')
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
public function getTeachersByCampusId(int $campusId, int $page = 1, int $size = 20): array
|
||||
{
|
||||
$query = Teacher::campusId($campusId)
|
||||
->enabled()
|
||||
->orderBy('sort_order', 'asc');
|
||||
|
||||
$total = $query->count();
|
||||
$list = $query->forPage($page, $size)->get()->toArray();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'size' => $size,
|
||||
'list' => $list,
|
||||
];
|
||||
}
|
||||
|
||||
public function getTeachersBySubject(string $subject, int $page = 1, int $size = 20): array
|
||||
{
|
||||
$query = Teacher::subject($subject)
|
||||
->enabled()
|
||||
->orderBy('sort_order', 'asc');
|
||||
|
||||
$total = $query->count();
|
||||
$list = $query->forPage($page, $size)->get()->toArray();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'size' => $size,
|
||||
'list' => $list,
|
||||
];
|
||||
}
|
||||
|
||||
public function searchTeachers(string $keyword, int $page = 1, int $size = 20): array
|
||||
{
|
||||
$query = Teacher::search($keyword)
|
||||
->enabled()
|
||||
->orderBy('sort_order', 'asc');
|
||||
|
||||
$total = $query->count();
|
||||
$list = $query->forPage($page, $size)->get()->toArray();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'page' => $page,
|
||||
'size' => $size,
|
||||
'list' => $list,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ use Hyperf\Database\Model\Relations\HasMany;
|
||||
*/
|
||||
class Campus extends AetherModel
|
||||
{
|
||||
protected ?string $table = 'campus';
|
||||
protected ?string $table = 'da_campus';
|
||||
|
||||
protected array $fillable = [
|
||||
'name',
|
||||
|
||||
106
app/Model/Teacher.php
Normal file
106
app/Model/Teacher.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model;
|
||||
|
||||
use Aether\AetherModel;
|
||||
use Carbon\Carbon;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
use Hyperf\Database\Model\Relations\BelongsTo;
|
||||
|
||||
/**
|
||||
* 教师模型.
|
||||
* @property int $id
|
||||
* @property string $name 教师姓名
|
||||
* @property int $age 年龄
|
||||
* @property int $gender 性别:1-男,2-女
|
||||
* @property string $avatar 头像URL
|
||||
* @property string $title 职称
|
||||
* @property string $major_subject 主讲科目
|
||||
* @property string $teaching_style 授课风格
|
||||
* @property string $introduction 教师简介
|
||||
* @property int $campus_id 所属校区ID
|
||||
* @property int $status 状态:0-禁用,1-启用
|
||||
* @property int $sort_order 排序
|
||||
* @property Carbon $created_at
|
||||
* @property Carbon $updated_at
|
||||
* @property Carbon $deleted_at
|
||||
*/
|
||||
class Teacher extends AetherModel
|
||||
{
|
||||
protected ?string $table = 'da_teacher';
|
||||
|
||||
protected array $fillable = [
|
||||
'name',
|
||||
'age',
|
||||
'gender',
|
||||
'avatar',
|
||||
'title',
|
||||
'major_subject',
|
||||
'teaching_style',
|
||||
'introduction',
|
||||
'campus_id',
|
||||
'status',
|
||||
'sort_order',
|
||||
];
|
||||
|
||||
protected array $casts = [
|
||||
'id' => 'integer',
|
||||
'age' => 'integer',
|
||||
'gender' => 'integer',
|
||||
'campus_id' => 'integer',
|
||||
'status' => 'integer',
|
||||
'sort_order' => 'integer',
|
||||
'created_at' => 'datetime',
|
||||
'updated_at' => 'datetime',
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* 所属校区.
|
||||
*/
|
||||
public function campus(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Campus::class, 'campus_id', 'id')
|
||||
->where('status', 1)
|
||||
->whereNull('deleted_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* 按校区查询.
|
||||
*/
|
||||
public function scopeCampusId(Builder $query, int $campusId): Builder
|
||||
{
|
||||
return $query->where('campus_id', $campusId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按科目查询.
|
||||
*/
|
||||
public function scopeSubject(Builder $query, string $subject): Builder
|
||||
{
|
||||
return $query->where('major_subject', 'like', "%{$subject}%");
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索教师.
|
||||
*/
|
||||
public function scopeSearch(Builder $query, string $keyword): Builder
|
||||
{
|
||||
return $query->where(function ($q) use ($keyword) {
|
||||
$q->where('name', 'like', "%{$keyword}%")
|
||||
->orWhere('title', 'like', "%{$keyword}%")
|
||||
->orWhere('major_subject', 'like', "%{$keyword}%")
|
||||
->orWhere('introduction', 'like', "%{$keyword}%");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询启用的教师.
|
||||
*/
|
||||
public function scopeEnabled(Builder $query): Builder
|
||||
{
|
||||
return $query->where('status', 1);
|
||||
}
|
||||
}
|
||||
77
app/Validator/TeacherValidator.php
Normal file
77
app/Validator/TeacherValidator.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Validator;
|
||||
|
||||
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
|
||||
use Hyperf\Validation\Validator;
|
||||
|
||||
class TeacherValidator
|
||||
{
|
||||
public function __construct(protected ValidatorFactoryInterface $validationFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public function validateCreate(array $data): Validator
|
||||
{
|
||||
return $this->validationFactory->make($data, [
|
||||
'name' => 'required|string|max:50',
|
||||
'age' => 'nullable|integer|min:18|max:65',
|
||||
'gender' => 'nullable|integer|in:1,2',
|
||||
'avatar' => 'nullable|url|max:255',
|
||||
'title' => 'nullable|string|max:100',
|
||||
'major_subject' => 'required|string|max:100',
|
||||
'teaching_style' => 'nullable|string',
|
||||
'introduction' => 'nullable|string',
|
||||
'campus_id' => 'nullable|integer|min:0',
|
||||
'status' => 'nullable|integer|in:0,1',
|
||||
'sort_order' => 'nullable|integer|min:0',
|
||||
], [
|
||||
'name.required' => '教师姓名不能为空',
|
||||
'major_subject.required' => '主讲科目不能为空',
|
||||
'age.min' => '年龄不能小于18岁',
|
||||
'age.max' => '年龄不能大于65岁',
|
||||
'gender.in' => '性别只能是1(男)或2(女)',
|
||||
'avatar.url' => '头像必须是有效的URL',
|
||||
]);
|
||||
}
|
||||
|
||||
public function validateUpdate(array $data): Validator
|
||||
{
|
||||
return $this->validationFactory->make($data, [
|
||||
'id' => 'required|integer|min:1',
|
||||
'name' => 'nullable|string|max:50',
|
||||
'age' => 'nullable|integer|min:18|max:65',
|
||||
'gender' => 'nullable|integer|in:1,2',
|
||||
'avatar' => 'nullable|url|max:255',
|
||||
'title' => 'nullable|string|max:100',
|
||||
'major_subject' => 'nullable|string|max:100',
|
||||
'teaching_style' => 'nullable|string',
|
||||
'introduction' => 'nullable|string',
|
||||
'campus_id' => 'nullable|integer|min:0',
|
||||
'status' => 'nullable|integer|in:0,1',
|
||||
'sort_order' => 'nullable|integer|min:0',
|
||||
], [
|
||||
'id.required' => '教师ID不能为空',
|
||||
'age.min' => '年龄不能小于18岁',
|
||||
'age.max' => '年龄不能大于65岁',
|
||||
'gender.in' => '性别只能是1(男)或2(女)',
|
||||
'avatar.url' => '头像必须是有效的URL',
|
||||
]);
|
||||
}
|
||||
|
||||
public function validateQuery(array $data): Validator
|
||||
{
|
||||
return $this->validationFactory->make($data, [
|
||||
'id' => 'nullable|integer|min:1',
|
||||
'name' => 'nullable|string|max:50',
|
||||
'campus_id' => 'nullable|integer|min:0',
|
||||
'major_subject' => 'nullable|string|max:100',
|
||||
'status' => 'nullable|integer|in:0,1',
|
||||
'page' => 'nullable|integer|min:1',
|
||||
'size' => 'nullable|integer|min:1|max:100',
|
||||
'keyword' => 'nullable|string|max:100',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -48,5 +48,19 @@ return [
|
||||
// 'heartbeat' => 5,
|
||||
// 'heartbeat_timeout' => 15,
|
||||
// ],
|
||||
[
|
||||
'name' => 'DataTeacher',
|
||||
'host' => env('NACOS_HOST', '192.168.28.199'),
|
||||
'port' => env('NACOS_PORT', 8848),
|
||||
'username' => env('NACOS_USERNAME', 'nacos'),
|
||||
'password' => env('NACOS_PASSWORD', 'nacos'),
|
||||
'namespace' => env('NACOS_NAMESPACE', 'e42b853c-5195-478b-b5e3-6d49f6a45053'),
|
||||
'group_name' => env('NACOS_GROUP', 'DEFAULT_GROUP'),
|
||||
'service_name' => 'DataTeacher',
|
||||
'metadata' => [
|
||||
'protocol' => 'jsonrpc-http',
|
||||
'server' => 'jsonrpc-http',
|
||||
],
|
||||
],
|
||||
// ],
|
||||
];
|
||||
|
||||
@@ -1,8 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MicroService\Contract;
|
||||
|
||||
interface TeacherServiceInterface
|
||||
{
|
||||
/**
|
||||
* 获取教师详情.
|
||||
* @param int $id 教师ID
|
||||
*/
|
||||
public function getTeacherById(int $id): array;
|
||||
|
||||
/**
|
||||
* 批量获取教师信息.
|
||||
* @param array $ids 教师ID列表
|
||||
*/
|
||||
public function getTeachersByIds(array $ids): array;
|
||||
|
||||
/**
|
||||
* 根据校区获取教师列表.
|
||||
* @param int $campusId 校区ID
|
||||
* @param int $page 页码
|
||||
* @param int $size 每页条数
|
||||
*/
|
||||
public function getTeachersByCampusId(int $campusId, int $page = 1, int $size = 20): array;
|
||||
|
||||
/**
|
||||
* 根据科目获取教师列表.
|
||||
* @param string $subject 科目名称
|
||||
* @param int $page 页码
|
||||
* @param int $size 每页条数
|
||||
*/
|
||||
public function getTeachersBySubject(string $subject, int $page = 1, int $size = 20): array;
|
||||
|
||||
/**
|
||||
* 搜索教师.
|
||||
* @param string $keyword 搜索关键词
|
||||
* @param int $page 页码
|
||||
* @param int $size 每页条数
|
||||
*/
|
||||
public function searchTeachers(string $keyword, int $page = 1, int $size = 20): array;
|
||||
}
|
||||
Reference in New Issue
Block a user