MenuController.kt

package io.github.lishangbu.avalon.auth.controller

import io.github.lishangbu.avalon.auth.entity.dto.MenuSpecification
import io.github.lishangbu.avalon.auth.entity.dto.MenuTreeView
import io.github.lishangbu.avalon.auth.entity.dto.MenuView
import io.github.lishangbu.avalon.auth.entity.dto.SaveMenuInput
import io.github.lishangbu.avalon.auth.entity.dto.UpdateMenuInput
import io.github.lishangbu.avalon.auth.service.MenuService
import io.github.lishangbu.avalon.oauth2.common.userdetails.UserInfo
import jakarta.validation.Valid
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

/**
 * 菜单控制器
 *
 * 提供当前用户基于角色的菜单树查询接口
 *
 * @author lishangbu
 * @since 2025/8/28
 */
@RequestMapping("/menu")
@RestController
class MenuController(
    /** 菜单服务 */
    private val menuService: MenuService,
) {
    /**
     * 获取当前用户角色菜单树
     *
     * @param user 当前用户
     * @return 菜单树
     */
    @GetMapping("/role-tree")
    fun listCurrentRoleMenuTree(
        @AuthenticationPrincipal user: UserInfo,
    ): List<MenuTreeView> = menuService.listMenuTreeByRoleCodes(user.authorities.mapNotNull { it.authority })

    /** 查询全量菜单树 */
    @GetMapping("/tree")
    fun listTree(): List<MenuTreeView> = menuService.listTree()

    /** 按条件查询菜单列表 */
    @GetMapping("/list")
    fun listByCondition(
        @ModelAttribute specification: MenuSpecification,
    ): List<MenuView> = menuService.listByCondition(specification)

    /**
     * 根据 ID 查询菜单
     *
     * @param id 菜单 ID
     * @return 菜单信息
     */
    @GetMapping("/{id:\\d+}")
    fun getById(
        @PathVariable id: Long,
    ): MenuView? = menuService.getById(id)

    /**
     * 新增菜单
     *
     * @param input 菜单写入请求
     * @return 保存后的菜单
     */
    @PostMapping
    fun save(
        @RequestBody @Valid input: SaveMenuInput,
    ): MenuView = menuService.save(input)

    /**
     * 更新菜单
     *
     * @param input 菜单写入请求
     * @return 更新后的菜单
     */
    @PutMapping
    fun update(
        @RequestBody @Valid input: UpdateMenuInput,
    ): MenuView = menuService.update(input)

    /**
     * 根据 ID 删除菜单
     *
     * @param id 菜单 ID
     */
    @DeleteMapping("/{id:\\d+}")
    fun deleteById(
        @PathVariable id: Long,
    ) {
        menuService.removeById(id)
    }
}