# XTransfer 穿梭框组件

**纯配置驱动**的穿梭框组件，只需传入一个 JSON 配置，组件自动加载数据并渲染。支持简单列表和分组列表两种模式。

## 快速使用

```vue
<template>
  <x-transfer :config="transferConfig" @change="handleChange" />
</template>

<script setup>
const transferConfig = {
  logicName: 'inspectionItemTransferLogic',
  serverName: 'af-his',
  parameter: { status: 1 }
}

const handleChange = ({ value, data }) => {
  console.log('选中keys:', value)
  console.log('选中数据:', data)
}
</script>
```

## Props

| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `config` | Object | `null` | 直接传入配置对象（优先级最高） |
| `configName` | String | `''` | 配置名称，用于从 `getConfigByName` 加载配置 |
| `queryParamsName` | String | `''` | 查询配置名称（二选一，与 configName 互斥） |
| `logicName` | String | `''` | Logic 名称，用于加载数据 |
| `serverName` | String | `'af-his'` | 服务名称 |
| `parameter` | Object | `{}` | 查询参数 |
| `data` | Array | `null` | 直接传入数据源 |
| `initialValue` | Array | `[]` | 初始选中的 keys |
| `rowKey` | String | `'key'` | 数据主键字段 |
| `displayKey` | String | `'title'` | 显示字段 |
| `groupKey` | String | `'group'` | 分组字段 |
| `groupLabelKey` | String | `'label'` | 分组标题字段 |
| `groupItemsKey` | String | `'items'` | 分组内项目字段 |
| `title` | String | `''` | 头部标题 |
| `leftTitle` | String | `''` | 左侧面板标题 |
| `rightTitle` | String | `''` | 右侧面板标题 |
| `allText` | String | `'All'` | 全选按钮文字 |
| `addHint` | String | `'双击添加'` | 添加提示 |
| `removeHint` | String | `'双击移除'` | 移除提示 |
| `disabled` | Boolean | `false` | 是否禁用 |
| `env` | String | `'prod'` | 环境模式，`'prod'` 或开发环境 |
| `radioConfig` | Object | `null` | 单选按钮配置 |

### radioConfig 单选按钮配置

```javascript
radioConfig: {
  options: [
    { label: '全部', value: 'all' },
    { label: '检验', value: 'inspection' },
    { label: '检查', value: 'examination' }
  ],
  default: 'all',           // 默认选中值
  paramKey: 'category',     // 参数 key，默认为 'radioValue'
  reloadLogic: true,        // 切换时是否重新加载数据，默认 true
  onChange: (value) => {}   // 切换回调
}
```

## 完整配置示例

```javascript
const transferConfig = {
  // ============ 数据加载配置 ============
  logicName: 'inspectionItemTransferLogic',  // Logic名称
  // queryParamsName: 'inspectionItemQuery',   // 或使用查询配置
  serverName: 'af-his',
  parameter: {
    status: 1,
    category: 'inspection'
  },
  initialValue: ['l01', 'l02'],  // 初始选中

  // ============ 字段映射 ============
  rowKey: 'id',                 // 主键字段
  displayKey: 'itemName',       // 显示字段
  groupKey: 'category',         // 分组字段
  groupLabelKey: 'categoryName', // 分组标题字段
  groupItemsKey: 'items',       // 分组内项目字段

  // ============ UI配置 ============
  title: '检验项目选择',
  leftTitle: '检验项目',
  rightTitle: '已选项目',
  allText: '全选',
  addHint: '双击添加',
  removeHint: '双击移除',
  disabled: false,

  // ============ 单选按钮配置 ============
  radioConfig: {
    options: [
      { label: '全部', value: 'all' },
      { label: '检验', value: 'inspection' },
      { label: '检查', value: 'examination' }
    ],
    default: 'all',
    paramKey: 'category',
    reloadLogic: true
  }
}
```

## 数据格式

后端 Logic 返回的数据格式：

```json
{
  "data": [
    {
      "category": "liver",
      "categoryName": "肝功能",
      "itemCount": 14,
      "items": [
        { "id": "l01", "itemName": "ALT", "itemCode": "ALT001" },
        { "id": "l02", "itemName": "AST", "itemCode": "AST001" }
      ]
    },
    {
      "category": "kidney",
      "categoryName": "肾功能",
      "itemCount": 3,
      "items": [
        { "id": "k01", "itemName": "Cr", "itemCode": "CR001" },
        { "id": "k02", "itemName": "BUN", "itemCode": "BUN001" }
      ]
    }
  ]
}
```

或简单格式（无分组）：

```json
{
  "data": [
    { "id": "1", "itemName": "ALT", "itemCode": "ALT001" },
    { "id": "2", "itemName": "AST", "itemCode": "AST001" }
  ]
}
```

## Events

| 事件 | 参数 | 说明 |
|------|------|------|
| `update:value` | Array | 选中 keys 变化（v-model 绑定） |
| `change` | `{ value, data }` | 选择变化时触发 |
| `loaded` | `{ dataSource, groupDataSource, initialValue, radioValue }` | 数据加载完成 |
| `radioChange` | `{ value, options }` | 单选按钮切换时触发 |

## Methods

通过 `ref` 获取组件实例后调用：

| 方法 | 参数 | 说明 |
|------|------|------|
| `loadData()` | - | 重新加载数据 |
| `init(config)` | `config` | 使用新配置初始化组件 |
| `refresh()` | - | 刷新数据（同 loadData） |
| `getSelectedData()` | - | 获取选中的完整数据对象数组 |
| `getSelectedKeys()` | - | 获取选中的 keys 数组 |
| `setValue(keys)` | `keys: Array` | 设置选中值 |
| `clear()` | - | 清空所有选择 |

```javascript
// 获取组件实例
const transferRef = ref(null)

// 调用方法
transferRef.value.loadData()           // 重新加载
transferRef.value.getSelectedData()   // 获取选中数据
transferRef.value.setValue(['k01'])    // 设置选中值
transferRef.value.clear()              // 清空选择
```

## Slots

| 插槽名 | 说明 |
|--------|------|
| `title` | 自定义头部标题区域 |

## 使用示例

### 基础用法

```vue
<template>
  <div>
    <x-transfer
      :config="transferConfig"
      @change="handleChange"
    />
    <pre>{{ JSON.stringify(selectedResult, null, 2) }}</pre>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const selectedResult = ref({ value: [], data: [] })

const transferConfig = {
  logicName: 'inspectionItemTransferLogic',
  serverName: 'af-his',
  parameter: { status: 1 },
  initialValue: ['l01'],
  rowKey: 'id',
  displayKey: 'itemName',
  groupKey: 'category',
  groupLabelKey: 'categoryName',
  groupCountKey: 'itemCount',
  leftTitle: '检验项目',
  rightTitle: '已选项目'
}

const handleChange = ({ value, data }) => {
  selectedResult.value = { value, data }
}
</script>
```

### 带单选按钮的分组切换

适用于需要按类别筛选数据的场景，如检验项目和检查项目的切换。

```vue
<template>
  <x-transfer
    :config="transferConfig"
    @change="handleChange"
    @radioChange="handleRadioChange"
  />
</template>

<script setup>
const transferConfig = {
  logicName: 'categoryItemTransferLogic',
  serverName: 'af-his',
  radioConfig: {
    options: [
      { label: '检验', value: 'inspection' },
      { label: '检查', value: 'examination' },
      { label: '治疗', value: 'treatment' }
    ],
    default: 'inspection',
    paramKey: 'category',
    reloadLogic: true,
    onChange: (value) => {
      console.log('切换到:', value)
    }
  },
  leftTitle: '可选项目',
  rightTitle: '已选项目'
}

const handleChange = ({ value, data }) => {
  console.log('选中值:', value)
}

const handleRadioChange = ({ value, options }) => {
  console.log('单选切换:', value, options)
}
</script>
```

### 直接传入数据

```vue
<template>
  <x-transfer :data="localData" v-model="selectedKeys" />
</template>

<script setup>
import { ref } from 'vue'

const selectedKeys = ref(['item-1'])

const localData = [
  { key: 'item-1', title: '项目一' },
  { key: 'item-2', title: '项目二' },
  { key: 'item-3', title: '项目三' }
]
</script>
```

### 使用 configName 加载配置

```vue
<template>
  <x-transfer
    config-name="inspectionItemTransfer"
    :initial-value="initialKeys"
    @change="handleChange"
  />
</template>

<script setup>
const initialKeys = ['l01', 'l02']

const handleChange = ({ value, data }) => {
  // 处理选择变化
}
</script>
```

### 自定义头部插槽

```vue
<template>
  <x-transfer :config="transferConfig">
    <template #title>
      <span style="color: #0057FE;">自定义标题</span>
    </template>
  </x-transfer>
</template>
```
