OptionsController.cs 17.1 KB
using Microsoft.AspNetCore.Mvc;
using Rcs.Application.DTOs;
using Rcs.Application.Services;
using Rcs.Domain.Entities;
using Rcs.Domain.Enums;
using Rcs.Domain.Repositories;
using Rcs.Shared.Options;

namespace Rcs.Api.Controllers
{
    /// <summary>
    /// 下拉选项控制器
    /// 提供统一的下拉数据接口,支持多语言
    /// @author zzy
    /// </summary>
    [ApiController]
    [Route("api/[controller]")]
    public class OptionsController : ControllerBase
    {
        private readonly IRobotRepository _robotRepository;
        private readonly IStorageLocationRepository _storageLocationRepository;
        private readonly IStorageAreaRepository _storageAreaRepository;
        private readonly IStorageLocationTypeRepository _storageLocationTypeRepository;
        private readonly IFieldPathConfigurationService _fieldPathConfigurationService;
        private readonly INetActionPropertysRepository _netActionPropertysRepository;

        public OptionsController(
            IRobotRepository robotRepository,
            IStorageLocationRepository storageLocationRepository,
            IStorageAreaRepository storageAreaRepository,
            IStorageLocationTypeRepository storageLocationTypeRepository,
            IFieldPathConfigurationService fieldPathConfigurationService,
            INetActionPropertysRepository netActionPropertysRepository)
        {
            _robotRepository = robotRepository;
            _storageLocationRepository = storageLocationRepository;
            _storageAreaRepository = storageAreaRepository;
            _storageLocationTypeRepository = storageLocationTypeRepository;
            _fieldPathConfigurationService = fieldPathConfigurationService;
            _netActionPropertysRepository = netActionPropertysRepository;
        }
        /// <summary>
        /// 获取所有下拉选项
        /// </summary>
        /// <param name="lang">语言:zh-cn(默认), en</param>
        /// <returns>所有下拉选项</returns>
        [HttpGet]
        public IActionResult GetAllOptions([FromQuery] string lang = "zh-cn")
        {
            var language = EnumOptions.ParseLanguage(lang);
            return Ok(new
            {
                // 机器人管理
                RobotType = EnumOptions.GetOptions<RobotType>(language),
                MovementType = EnumOptions.GetOptions<MovementType>(language),
                RobotStatus = EnumOptions.GetOptions<RobotStatus>(language),
                OnlineStatus = EnumOptions.GetOptions<OnlineStatus>(language),
                OperatingMode = EnumOptions.GetOptions<OperatingMode>(language),
                ProtocolType = EnumOptions.GetOptions<ProtocolType>(language),
                // 地图管理
                MapType = EnumOptions.GetOptions<MapTYPE>(language),
                MapNodeType = EnumOptions.GetOptions<MapNodeTYPE>(language),
                MapResourceType = EnumOptions.GetOptions<MapResourcesTYPE>(language),
                // 动作管理
                ActionCategory = EnumOptions.GetOptions<ActionCategory>(language),
                ActionBlockType = EnumOptions.GetOptions<ActionBlockType>(language),
                ExecutionScope = EnumOptions.GetOptions<ExecutionScope>(language),
                ParameterValueType = EnumOptions.GetOptions<ParameterValueType>(language),
                ParameterSourceType = EnumOptions.GetOptions<ParameterSourceType>(language),
                ResponseWaitType = EnumOptions.GetOptions<ResponseWaitType>(language),
                // 任务模板
                TaskStatus = EnumOptions.GetOptions<Rcs.Domain.Entities.TaskStatus>(language),
                TaskStepType = EnumOptions.GetOptions<TaskStepType>(language),
                StepPropertyType = EnumOptions.GetOptions<StepPropertyType>(language),
                AfterActionType = EnumOptions.GetOptions<ActionType>(language),
                NodeValueType = EnumOptions.GetOptions<NodeValueType>(language),
                // 储位管理
                ShelfType = EnumOptions.GetOptions<ShelfTypeEnum>(language)
            });
        }

        /// <summary>
        /// 获取机器人相关下拉选项
        /// </summary>
        [HttpGet("robot")]
        public IActionResult GetRobotOptions([FromQuery] string lang = "zh-cn")
        {
            var language = EnumOptions.ParseLanguage(lang);
            return Ok(new
            {
                RobotType = EnumOptions.GetOptions<RobotType>(language),
                MovementType = EnumOptions.GetOptions<MovementType>(language),
                RobotStatus = EnumOptions.GetOptions<RobotStatus>(language),
                OnlineStatus = EnumOptions.GetOptions<OnlineStatus>(language),
                OperatingMode = EnumOptions.GetOptions<OperatingMode>(language),
                ProtocolType = EnumOptions.GetOptions<ProtocolType>(language)
            });
        }

        /// <summary>
        /// 获取地图相关下拉选项
        /// </summary>
        [HttpGet("map")]
        public IActionResult GetMapOptions([FromQuery] string lang = "zh-cn")
        {
            var language = EnumOptions.ParseLanguage(lang);
            return Ok(new
            {
                MapType = EnumOptions.GetOptions<MapTYPE>(language),
                MapNodeType = EnumOptions.GetOptions<MapNodeTYPE>(language),
                MapResourceType = EnumOptions.GetOptions<MapResourcesTYPE>(language)
            });
        }

        /// <summary>
        /// 获取动作相关下拉选项
        /// </summary>
        [HttpGet("action")]
        public IActionResult GetActionOptions([FromQuery] string lang = "zh-cn")
        {
            var language = EnumOptions.ParseLanguage(lang);
            return Ok(new
            {
                ActionCategory = EnumOptions.GetOptions<ActionCategory>(language),
                ActionBlockType = EnumOptions.GetOptions<ActionBlockType>(language),
                ExecutionScope = EnumOptions.GetOptions<ExecutionScope>(language),
                ParameterValueType = EnumOptions.GetOptions<ParameterValueType>(language),
                ParameterSourceType = EnumOptions.GetOptions<ParameterSourceType>(language),
                ResponseWaitType = EnumOptions.GetOptions<ResponseWaitType>(language)
            });
        }

        /// <summary>
        /// 获取任务模板相关下拉选项
        /// </summary>
        [HttpGet("task")]
        public IActionResult GetTaskOptions([FromQuery] string lang = "zh-cn")
        {
            var language = EnumOptions.ParseLanguage(lang);
            return Ok(new
            {
                TaskStatus = EnumOptions.GetOptions<Rcs.Domain.Entities.TaskStatus>(language),
                TaskStepType = EnumOptions.GetOptions<TaskStepType>(language),
                StepPropertyType = EnumOptions.GetOptions<StepPropertyType>(language),
                AfterActionType = EnumOptions.GetOptions<ActionType>(language),
                NodeValueType = EnumOptions.GetOptions<NodeValueType>(language)
            });
        }

        /// <summary>
        /// 获取储位相关下拉选项
        /// @author zzy
        /// </summary>
        [HttpGet("storage")]
        public IActionResult GetStorageOptions([FromQuery] string lang = "zh-cn")
        {
            var language = EnumOptions.ParseLanguage(lang);
            return Ok(new
            {
                ShelfType = EnumOptions.GetOptions<ShelfTypeEnum>(language)
            });
        }

        /// <summary>
        /// 获取机器人下拉选项
        /// @author zzy
        /// </summary>
        [HttpGet("robots")]
        public async Task<IActionResult> GetRobotSelectOptions(CancellationToken cancellationToken = default)
        {
            var robots = await _robotRepository.GetActiveRobotsAsync(cancellationToken);
            
            var options = robots?.Select(r => new { value = r.RobotId, text = $"{r.RobotCode} - {r.RobotName}", code = r.RobotCode });
            return Ok(options);
        }
        /// <summary>
        /// 获取机器人型号下拉选项
        /// @author zzy
        /// </summary>
        [HttpGet("robot-models")]
        public async Task<IActionResult> GetRobotModelsOptions(CancellationToken cancellationToken = default)
        {
            var robots = await _robotRepository.GetRobotsAsync(cancellationToken);
            var options = robots?.Select(r => r.RobotModel).Distinct().Select(g => new { value = g, text = g, code = g });
            return Ok(options);
        }

        /// <summary>
        /// 获取库位下拉选项
        /// @author zzy
        /// </summary>
        [HttpGet("locations")]
        public async Task<IActionResult> GetLocationSelectOptions(CancellationToken cancellationToken = default)
        {
            var locations = await _storageLocationRepository.GetAllAsync(cancellationToken);
            var options = locations?.Where(l => l.IsActive).Select(l => new { value = l.LocationId, text = $"{l.LocationName}", code = l.LocationId });
            return Ok(options);
        }

        /// <summary>
        /// 获取库区下拉选项
        /// @author zzy
        /// </summary>
        [HttpGet("areas")]
        public async Task<IActionResult> GetAreaSelectOptions(CancellationToken cancellationToken = default)
        {
            var areas = await _storageAreaRepository.GetAllAsync(cancellationToken);
            var options = areas?.Where(a => a.IsActive).Select(a => new { value = a.AreaId, text = a.AreaName ?? a.AreaCode, code = a.AreaCode });
            return Ok(options);
        }

        /// <summary>
        /// 获取储位类型下拉选项
        /// @author zzy
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>储位类型选项列表(包含类型ID、类型名称、类型编码)</returns>
        [HttpGet("location-types")]
        public async Task<IActionResult> GetLocationTypeSelectOptions(CancellationToken cancellationToken = default)
        {
            var locationTypes = await _storageLocationTypeRepository.GetAllAsync(cancellationToken);
            var options = locationTypes?
                .Where(t => t.IsActive)
                .Select(t => new
                {
                    value = t.TypeId,
                    text = $"{t.TypeCode} - {t.TypeName}",
                    code = t.TypeCode
                });
            return Ok(options);
        }

        /// <summary>
        /// 根据机器人型号获取储位类型下拉选项
        /// @author zzy
        /// </summary>
        /// <param name="robotModel">机器人型号</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>储位类型选项列表(匹配指定机器人型号)</returns>
        [HttpGet("location-types/by-robot-model")]
        public async Task<IActionResult> GetLocationTypeSelectOptionsByRobotModel(
            [FromQuery] string robotModel,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(robotModel))
            {
                return BadRequest(new { message = "机器人型号不能为空" });
            }

            var allTypes = await _storageLocationTypeRepository.GetAllAsync(cancellationToken);
            var options = allTypes?
                .Where(t => t.IsActive && t.RobotModels.Contains(robotModel))
                .Select(t => new
                {
                    value = t.TypeId,
                    text = $"{t.TypeName}({t.TypeCode})",
                    code = t.TypeCode,
                    typeName = t.TypeName,
                    typeCode = t.TypeCode,
                    shelfType = (int)t.ShelfType,
                    robotModels = string.Join(",", t.RobotModels)
                });
            return Ok(options);
        }

        /// <summary>
        /// 获取制造商下拉选项
        /// @author zzy
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>制造商选项列表(从机器人数据中去重获取)</returns>
        [HttpGet("manufacturers")]
        public async Task<IActionResult> GetManufacturerSelectOptions(CancellationToken cancellationToken = default)
        {
            var robots = await _robotRepository.GetRobotsAsync(cancellationToken);
            var options = (robots ?? Enumerable.Empty<Robot>())
                .Where(r => !string.IsNullOrWhiteSpace(r.RobotManufacturer))
                .Select(r => r.RobotManufacturer!)
                .Distinct()
                .OrderBy(m => m)
                .Select(m => new
                {
                    value = m,
                    text = m,
                    code = m
                });
            return Ok(options);
        }

        /// <summary>
        /// 获取动作参数来源路径的字段树(多级下拉框数据源)
        /// @author zzy
        /// </summary>
        /// <param name="sourceType">来源类型(Robot=3,Task=2,Node=4,Edge=5,Context=6)</param>
        /// <param name="lang">语言:zh-cn(默认), en</param>
        /// <returns>字段路径树根节点列表</returns>
        [HttpGet("field-paths")]
        public IActionResult GetFieldPathTree(
            [FromQuery] ParameterSourceType sourceType,
            [FromQuery] string lang = "zh-cn")
        {
            if (!Enum.IsDefined(typeof(ParameterSourceType), sourceType))
            {
                return BadRequest(new { message = $"无效的来源类型: {sourceType}" });
            }

            var fieldTree = _fieldPathConfigurationService.GetFieldPathTree(sourceType, lang);
            return Ok(new
            {
                sourceType = sourceType.ToString(),
                sourceTypeValue = (int)sourceType,
                nodes = fieldTree
            });
        }

        /// <summary>
        /// 批量获取多种来源类型的字段路径树
        /// @author zzy
        /// </summary>
        /// <param name="sourceTypes">来源类型列表(逗号分隔,如:3,2,4)</param>
        /// <param name="lang">语言:zh-cn(默认), en</param>
        /// <returns>多种来源类型的字段路径树映射</returns>
        [HttpGet("field-paths/batch")]
        public IActionResult GetFieldPathTreeBatch(
            [FromQuery] string sourceTypes,
            [FromQuery] string lang = "zh-cn")
        {
            if (string.IsNullOrWhiteSpace(sourceTypes))
            {
                return BadRequest(new { message = "来源类型列表不能为空" });
            }

            var result = new Dictionary<string, object>();

            var typeValues = sourceTypes.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            foreach (var typeValue in typeValues)
            {
                if (int.TryParse(typeValue, out int typeInt) && Enum.IsDefined(typeof(ParameterSourceType), typeInt))
                {
                    var sourceType = (ParameterSourceType)typeInt;
                    var fieldTree = _fieldPathConfigurationService.GetFieldPathTree(sourceType, lang);
                    result[sourceType.ToString()] = new
                    {
                        sourceTypeValue = typeInt,
                        nodes = fieldTree
                    };
                }
            }

            return Ok(result);
        }

        /// <summary>
        /// 获取所有来源类型的字段路径树
        /// @author zzy
        /// </summary>
        /// <param name="lang">语言:zh-cn(默认), en</param>
        /// <returns>所有来源类型的字段路径树映射</returns>
        [HttpGet("field-paths/all")]
        public IActionResult GetAllFieldPathTrees([FromQuery] string lang = "zh-cn")
        {
            var result = new Dictionary<string, object>();

            foreach (ParameterSourceType sourceType in Enum.GetValues(typeof(ParameterSourceType)))
            {
                if (sourceType == ParameterSourceType.Constant)
                    continue; // 常量值类型不需要字段路径

                var fieldTree = _fieldPathConfigurationService.GetFieldPathTree(sourceType, lang);
                result[sourceType.ToString()] = new
                {
                    sourceTypeValue = (int)sourceType,
                    nodes = fieldTree
                };
            }

            return Ok(result);
        }

        /// <summary>
        /// 获取网络动作属性下拉选项
        /// @author zzy
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>网络动作属性选项列表(包含Id、动作名称、描述)</returns>
        [HttpGet("net-actions")]
        public async Task<IActionResult> GetNetActionSelectOptions(CancellationToken cancellationToken = default)
        {
            var netActions = await _netActionPropertysRepository.GetAllAsync(cancellationToken);
            var options = netActions?
                .Where(n => n.IsActive)
                .Select(n => new
                {
                    value = n.NetActionId,
                    text = n.ActionName,
                    code = n.NetActionId
                });
            return Ok(options);
        }
    }
}