生产模块拆分为前缫/后缫;修复菜单卡顿与重复请求;支持 IIS 单站点部署
1. 生产模块按工序拆分为两个一级菜单 - 生产-前缫(落丝记录)、生产-后缫(纤度检验、黑板检验) - 旧的「生产管理」(/prod) 目录及子菜单由种子自动清理,页面组件与权限标识保持不变 - 消息中心跳转路径、首页快捷入口路径同步更新 2. 职工管理独立为一级菜单(原挂在「基础数据」目录下),并清理历史子菜单 3. 修复侧边栏菜单展开卡顿(基础数据等子项较多的目录尤其明显) - 去掉 Element Plus 的 height 过渡动画(会逐帧重排全部子项) - 收起时改用 height:0 + visibility:hidden 而非 display:none,子项提前完成布局 - 菜单区独立滚动并预留滚动条宽度(scrollbar-gutter),消除展开时的横向抖动 - 菜单项增加 contain 布局隔离,淡入动画改为容器级 4. 修复页面首次打开重复请求 - 分页组件挂载时会触发一次 current-change,页码未变化时不再重复加载(18 个页面) - 职工管理去掉 onMounted 与默认选中部门的重复加载 - 工种管理、原料庄口的注册表下拉由按 key 多次请求改为一次全量拉取 5. 后端增加前端静态托管与 SPA 路由回退,支持 IIS 单站点部署(前后端同源) 6. 新增部署脚本 deploy-iis.ps1(首次部署)与 update-iis.ps1(更新发布)
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
using F9WebAiTest.Application.Common;
|
||||
using F9WebAiTest.Application.Common.Exceptions;
|
||||
using F9WebAiTest.Application.CQRS.SYS.Employees.Commands;
|
||||
using F9WebAiTest.Application.CQRS.SYS.Employees.Queries;
|
||||
using F9WebAiTest.Domain.Enums.SYS.Employees;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace F9WebAiTest.Api.Controllers;
|
||||
|
||||
/// <summary>职工档案管理(含转正/离职/调岗/重新入职/生产信息维护)</summary>
|
||||
[ApiController]
|
||||
[Route("api/sys/employee")]
|
||||
[Authorize]
|
||||
public class SysEmployeeController : ControllerBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
public SysEmployeeController(IMediator mediator) => _mediator = mediator;
|
||||
|
||||
/// <summary>分页查询(部门含子部门;workStatus/banci 不传表示全部)</summary>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetPaged([FromQuery] long depId = 0, [FromQuery] long worktypeId = 0,
|
||||
[FromQuery] Employee_WorkStatus_Enum? workStatus = null, [FromQuery] Prod_Banci_Enum? banci = null,
|
||||
[FromQuery] string like = "", [FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20)
|
||||
=> Ok(ApiResult<object>.Ok(await _mediator.Send(new GetEmployeePagedQuery(depId, worktypeId, workStatus,
|
||||
banci, like ?? string.Empty, pageIndex, pageSize))));
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetById(long id)
|
||||
{
|
||||
var result = await _mediator.Send(new GetEmployeeByIdQuery(id));
|
||||
return result == null
|
||||
? NotFound(ApiResult<object>.Fail("职工不存在", 404))
|
||||
: Ok(ApiResult<object>.Ok(result));
|
||||
}
|
||||
|
||||
/// <summary>变更记录</summary>
|
||||
[HttpGet("{id}/change-records")]
|
||||
public async Task<IActionResult> GetChangeRecords(long id)
|
||||
=> Ok(ApiResult<object>.Ok(await _mediator.Send(new GetEmployeeChangeRecordsQuery(id))));
|
||||
|
||||
/// <summary>调岗记录</summary>
|
||||
[HttpGet("{id}/tiaogang-records")]
|
||||
public async Task<IActionResult> GetTiaogangRecords(long id)
|
||||
=> Ok(ApiResult<object>.Ok(await _mediator.Send(new GetEmployeeTiaogangRecordsQuery(id))));
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create([FromBody] Employee_CreateCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(new { id = await _mediator.Send(command) }, "新增成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> Update(long id, [FromBody] Employee_UpdateCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(command with { Id = id }), "修改成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> Delete(long id)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(new Employee_DelCommand(id)), "删除成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>转正</summary>
|
||||
[HttpPut("{id}/zhuanzheng")]
|
||||
public async Task<IActionResult> Zhuanzheng(long id, [FromBody] Employee_ZhuanzhengCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(command with { Id = id }), "转正成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>取消转正</summary>
|
||||
[HttpPut("{id}/zhuanzheng-cancel")]
|
||||
public async Task<IActionResult> ZhuanzhengCancel(long id)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(new Employee_ZhuanzhengCancelCommand(id)), "已取消转正")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>离职</summary>
|
||||
[HttpPut("{id}/lizhi")]
|
||||
public async Task<IActionResult> Lizhi(long id, [FromBody] Employee_LizhiCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(command with { Id = id }), "已办理离职")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>取消离职</summary>
|
||||
[HttpPut("{id}/lizhi-cancel")]
|
||||
public async Task<IActionResult> LizhiCancel(long id)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(new Employee_LizhiCancelCommand(id)), "已取消离职")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>调岗</summary>
|
||||
[HttpPut("{id}/tiaogang")]
|
||||
public async Task<IActionResult> Tiaogang(long id, [FromBody] Employee_TiaogangCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(command with { Id = id }), "调岗成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>重新入职</summary>
|
||||
[HttpPut("{id}/renew-ruzhis")]
|
||||
public async Task<IActionResult> RenewRuzhi(long id, [FromBody] Employee_RenewRuzhiCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(command with { Id = id }), "重新入职成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
|
||||
/// <summary>修改生产信息(工作组 / 顺序号)</summary>
|
||||
[HttpPut("{id}/sc")]
|
||||
public async Task<IActionResult> UpdateSc(long id, [FromBody] Employee_UpdateScCommand command)
|
||||
{
|
||||
try { return Ok(ApiResult<object>.Ok(await _mediator.Send(command with { Id = id }), "修改成功")); }
|
||||
catch (F9NotFoundException ex) { return NotFound(ApiResult<object>.Fail(ex.Message, 404)); }
|
||||
catch (F9OperationException ex) { return BadRequest(ApiResult<object>.Fail(ex.Message, 400)); }
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,11 @@ using (var scope = app.Services.CreateScope())
|
||||
DbSeeder.Seed(fsql, snowflake);
|
||||
}
|
||||
|
||||
// 前端静态资源:Vue 打包产物放在 wwwroot。
|
||||
// IIS 单站点部署时前端与 API 同源(浏览器访问 /api/...),无需跨域与反向代理。
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
// NSwag 中间件(swagger 文档 + UI)
|
||||
app.UseOpenApi();
|
||||
app.UseSwaggerUi();
|
||||
@@ -109,4 +114,7 @@ app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
app.MapHub<NotificationHub>("/hubs/notification");
|
||||
|
||||
// 前端使用 history 路由,未匹配到 API/静态文件的路径统一交给 index.html
|
||||
app.MapFallbackToFile("index.html");
|
||||
|
||||
app.Run();
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user