useOptions.ts 7.53 KB
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import optionsApi, { type Option, type OptionsData, type FieldPathNode } from '../services/options'

// 缓存的下拉数据
const cachedOptions = ref<OptionsData | null>(null)
const isLoading = ref(false)
const currentLang = ref('')
const manufacturerOptions = ref<Option[]>([])
/**
 * @author zzy
 * @description 字段路径选项缓存(按来源类型存储)
 */
const fieldPathOptionsCache = ref<Record<number, Option[]>>({})

/**
 * 下拉选项管理 composable
 * 统一管理所有下拉数据,支持多语言
 * @author zzy
 */
export function useOptions() {
  const { locale } = useI18n()

  // 语言映射
  const getLangParam = () => {
    const lang = locale.value
    if (lang === 'cn') return 'zh-cn'
    if (lang === 'gb') return 'en'
    return 'zh-cn'
  }

  // 加载所有下拉选项
  const loadOptions = async (force = false) => {
    const lang = getLangParam()
    if (!force && cachedOptions.value && currentLang.value === lang) {
      return cachedOptions.value
    }

    if (isLoading.value) return cachedOptions.value

    try {
      isLoading.value = true
      const res: any = await optionsApi.getAll(lang)
      const data = (res && (res.Data ?? res.data)) || res
      cachedOptions.value = data
      currentLang.value = lang
      return data
    } catch (err) {
      console.error('加载下拉选项失败', err)
      return null
    } finally {
      isLoading.value = false
    }
  }

  // 监听语言变化,自动重新加载
  watch(locale, () => {
    loadOptions(true)
  })

  // 转换为 VaSelect 格式 { text, value }
  const toSelectOptions = (options: Option[] | undefined) => {
    if (!options) return []
    return options.map(opt => ({ text: opt.label, value: opt.value }))
  }

  // 加载制造商选项(从独立接口获取)
  const loadManufacturerOptions = async () => {
    if (manufacturerOptions.value.length > 0) {
      return manufacturerOptions.value
    }

    try {
      const res: any = await optionsApi.getManufacturers()
      const data = (res && (res.Data ?? res.data)) || res || []
      // 后端返回格式: { value, text, code } -> 转换为 { label, value }
      manufacturerOptions.value = data.map((item: any) => ({
        label: item.text || item.value,
        value: item.value
      }))
      return manufacturerOptions.value
    } catch (err) {
      console.error('加载制造商选项失败', err)
      return []
    }
  }

  // 获取制造商选项
  const getManufacturerOptions = () => {
    if (manufacturerOptions.value.length === 0) {
      loadManufacturerOptions()
    }
    return toSelectOptions(manufacturerOptions.value)
  }

  /**
   * @author zzy
   * @description 扁平化字段路径树为选项列表
   * 使用 path 作为 label,以便显示完整路径(如 Robot.Status 而不是 Status)
   */
  const flattenFieldPathTree = (nodes: FieldPathNode[], parentPath = ''): Option[] => {
    const options: Option[] = []
    for (const node of nodes) {
      const currentPath = parentPath ? `${parentPath}.${node.name}` : node.name
      options.push({
        value: node.path || currentPath,
        label: node.path || node.displayName || node.name
      })
      if (node.children && node.children.length > 0) {
        options.push(...flattenFieldPathTree(node.children, currentPath))
      }
    }
    return options
  }

  /**
   * @author zzy
   * @description 加载字段路径选项(按来源类型)
   */
  const loadFieldPathOptions = async (sourceType: number) => {
    if (fieldPathOptionsCache.value[sourceType]) {
      return fieldPathOptionsCache.value[sourceType]
    }

    try {
      const lang = getLangParam()
      const res: any = await optionsApi.getFieldPathTree(sourceType, lang)
      const nodes = res?.nodes || res?.Nodes || []
      fieldPathOptionsCache.value[sourceType] = flattenFieldPathTree(nodes)
      return fieldPathOptionsCache.value[sourceType]
    } catch (err) {
      console.error('加载字段路径选项失败', err)
      return []
    }
  }

  /**
   * @author zzy
   * @description 获取字段路径选项
   */
  const getFieldPathOptions = (sourceType: number) => {
    if (!fieldPathOptionsCache.value[sourceType]) {
      loadFieldPathOptions(sourceType)
    }
    return toSelectOptions(fieldPathOptionsCache.value[sourceType])
  }

  // 获取各类下拉选项
  const getRobotTypeOptions = () => toSelectOptions(cachedOptions.value?.robotType)
  const getMovementTypeOptions = () => toSelectOptions(cachedOptions.value?.movementType)
  const getRobotStatusOptions = () => toSelectOptions(cachedOptions.value?.robotStatus)
  const getOnlineStatusOptions = () => toSelectOptions(cachedOptions.value?.onlineStatus)
  const getOperatingModeOptions = () => toSelectOptions(cachedOptions.value?.operatingMode)
  const getProtocolTypeOptions = () => toSelectOptions(cachedOptions.value?.protocolType)
  const getMapTypeOptions = () => toSelectOptions(cachedOptions.value?.mapType)
  const getMapNodeTypeOptions = () => toSelectOptions(cachedOptions.value?.mapNodeType)
  const getMapResourceTypeOptions = () => toSelectOptions(cachedOptions.value?.mapResourceType)
  const getActionCategoryOptions = () => toSelectOptions(cachedOptions.value?.actionCategory)
  const getActionBlockTypeOptions = () => toSelectOptions(cachedOptions.value?.actionBlockType)
  const getExecutionScopeOptions = () => toSelectOptions(cachedOptions.value?.executionScope)
  const getParameterValueTypeOptions = () => toSelectOptions(cachedOptions.value?.parameterValueType)
  const getParameterSourceTypeOptions = () => toSelectOptions(cachedOptions.value?.parameterSourceType)
  const getTaskTypeOptions = () => toSelectOptions(cachedOptions.value?.taskType)
  const getTaskStatusOptions = () => toSelectOptions(cachedOptions.value?.taskStatus)
  const getTaskStepTypeOptions = () => toSelectOptions(cachedOptions.value?.taskStepType)
  const getStepPropertyTypeOptions = () => toSelectOptions(cachedOptions.value?.stepPropertyType)
  const getAfterActionTypeOptions = () => toSelectOptions(cachedOptions.value?.afterActionType)
  const getNodeValueTypeOptions = () => toSelectOptions(cachedOptions.value?.nodeValueType)
  const getShelfTypeOptions = () => toSelectOptions(cachedOptions.value?.shelfType)
  const getLocationTypeOptions = () => toSelectOptions(cachedOptions.value?.LocationType)

  // 根据值获取标签
  const getLabelByValue = (options: Option[] | undefined, value: any) => {
    if (!options || value === undefined || value === null) return ''
    const opt = options.find(o => o.value === value || String(o.value) === String(value))
    return opt?.label || String(value)
  }

  return {
    cachedOptions,
    isLoading,
    loadOptions,
    toSelectOptions,
    getLabelByValue,
    // 机器人
    getRobotTypeOptions,
    getMovementTypeOptions,
    getRobotStatusOptions,
    getOnlineStatusOptions,
    getOperatingModeOptions,
    getProtocolTypeOptions,
    // 制造商
    getManufacturerOptions,
    loadManufacturerOptions,
    // 地图
    getMapTypeOptions,
    getMapNodeTypeOptions,
    getMapResourceTypeOptions,
    // 动作
    getActionCategoryOptions,
    getActionBlockTypeOptions,
    getExecutionScopeOptions,
    getParameterValueTypeOptions,
    getParameterSourceTypeOptions,
    // 任务
    getTaskTypeOptions,
    getTaskStatusOptions,
    getTaskStepTypeOptions,
    getStepPropertyTypeOptions,
    getAfterActionTypeOptions,
    getNodeValueTypeOptions,
    // 储位类型
    getShelfTypeOptions,
    getLocationTypeOptions,
    // 字段路径
    loadFieldPathOptions,
    getFieldPathOptions
  }
}