[CLAUDE] Infra: phân cấp phòng ban (Department.ParentId) + /tree + gán phòng cha
Nền cây tổ chức cho trang Hồ sơ Nhân sự (anh: bố trí giống NamGroup; chốt phân cấp thật + tự gán phòng cha trong quản lý phòng ban). - Mig AddDepartmentParentId: +ParentId Guid? loose-Guid (no FK vật lý, convention PE) + IX_Departments_ParentId. AddColumn+CreateIndex, no new table, Down reversible (DropIndex->DropColumn). Chưa apply (CI/prod seed apply). - GET /api/departments/tree: ráp cây in-memory + đếm NV active theo User.DepartmentId (EmployeeProfile KHÔNG có DepartmentId — link qua User, field phòng ban ở User Mig 11) + rollup TotalEmployeeCount + cycle-guard HashSet. Authz = class [Authorize] (= GET list). - Create/Update +ParentId (write vẫn khóa Admin,CatalogManager). Update có cycle-guard: chặn tự-làm-cha + đi ngược chuỗi cha gặp lại Id (chống vòng A->B->A). Build PASS (0 warn/err full solution). Test-after (test-specialist). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -18,6 +18,12 @@ public class DepartmentsController(IMediator mediator) : ControllerBase
|
||||
CancellationToken ct = default)
|
||||
=> Ok(await mediator.Send(new ListDepartmentsQuery { Page = page, PageSize = pageSize, Search = search, SortBy = sortBy, SortDesc = sortDesc }, ct));
|
||||
|
||||
// Cây tổ chức phân cấp phòng ban (nền trang Hồ sơ Nhân sự). Authz = giống
|
||||
// [HttpGet] List ở trên (chỉ class-level [Authorize], không attribute per-action).
|
||||
[HttpGet("tree")]
|
||||
public async Task<ActionResult<List<DepartmentTreeNodeDto>>> Tree(CancellationToken ct)
|
||||
=> Ok(await mediator.Send(new GetDepartmentTreeQuery(), ct));
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<ActionResult<DepartmentDto>> Get(Guid id, CancellationToken ct)
|
||||
=> Ok(await mediator.Send(new GetDepartmentQuery(id), ct));
|
||||
|
||||
Reference in New Issue
Block a user