# EasyExcel字典下拉框使用说明

## 功能概述

本项目实现了EasyExcel自定义WriteHandler拦截器，可以在生成Excel模板时自动添加基于若依框架字典数据的下拉框。

## 核心组件

### 1. @DictDropdown 注解

位置：`com.ruoyi.common.annotation.DictDropdown`

用于标注需要添加下拉框的字段。

**属性说明：**
| 属性 | 类型 | 默认值 | 说明 |
|-----|------|--------|------|
| dictType | String | 必填 | 字典类型编码，对应若依字典管理中的字典类型 |
| displayType | DisplayType | LABEL | 下拉框显示内容类型（LABEL：显示标签，VALUE：显示值） |
| strict | boolean | true | 是否仅允许选择下拉框中的值 |
| hiddenSheetName | String | "dict_hidden" | 隐藏Sheet名称（用于存储大量下拉选项） |

### 2. DictDropdownWriteHandler 处理器

位置：`com.ruoyi.dpc.handler.DictDropdownWriteHandler`

核心功能：

- 解析实体类中的@DictDropdown注解
- 从若依字典缓存获取字典数据
- 为对应列添加下拉框验证
- 自动处理下拉选项超过Excel字符限制的情况（使用隐藏Sheet）

### 3. EasyExcelUtil 工具类扩展

位置：`com.ruoyi.dpc.utils.EasyExcelUtil`

新增方法：

- `importTemplateWithDictDropdown()` - 下载带字典下拉框的导入模板
- `exportExcelWithDictDropdown()` - 导出带字典下拉框的Excel

## 使用示例

### 步骤1：在实体类上添加注解

```java
package com.ruoyi.dpc.domain.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.ruoyi.common.annotation.DictDropdown;
import lombok.Data;

@Data
public class CcdiEmployeeExcel {

    @ExcelProperty(value = "姓名", index = 0)
    @ColumnWidth(15)
    private String name;

    @ExcelProperty(value = "柜员号", index = 1)
    @ColumnWidth(15)
    private String tellerNo;

    // 添加字典下拉框注解
    @ExcelProperty(value = "状态", index = 6)
    @ColumnWidth(10)
    @DictDropdown(dictType = "ccdi_employee_status")
    private String status;
}
```

### 步骤2：在Controller中使用

```java
@RestController
@RequestMapping("/ccdi/employee")
public class CcdiEmployeeController {

    /**
     * 下载带字典下拉框的导入模板
     */
    @PostMapping("/importTemplateWithDropdown")
    public void importTemplateWithDropdown(HttpServletResponse response) {
        EasyExcelUtil.importTemplateWithDictDropdown(
            response,
            CcdiEmployeeExcel.class,
            "员工信息"
        );
    }

    /**
     * 导出带字典下拉框的Excel
     */
    @PostMapping("/exportWithDropdown")
    public void exportWithDropdown(HttpServletResponse response) {
        List<CcdiEmployeeExcel> list = employeeService.selectEmployeeList();
        EasyExcelUtil.exportExcelWithDictDropdown(
            response,
            list,
            CcdiEmployeeExcel.class,
            "员工信息"
        );
    }
}
```

## 高级用法

### 1. 显示字典键值而非标签

```java
@DictDropdown(dictType = "ccdi_employee_status", displayType = DisplayType.VALUE)
private String status;
```

### 2. 允许手动输入（非严格模式）

```java
@DictDropdown(dictType = "ccdi_employee_status", strict = false)
private String status;
```

### 3. 自定义隐藏Sheet名称

```java
@DictDropdown(dictType = "ccdi_employee_status", hiddenSheetName = "employee_status_dict")
private String status;
```

## 注意事项

1. **必须指定@ExcelProperty的index属性**
    - 字段必须指定@ExcelProperty注解的index值，否则无法正确映射列位置

2. **字典数据必须预先加载到缓存**
    - 使用前需要确保字典数据已经加载到Redis缓存中
    - 可通过若依系统的字典管理功能预热缓存

3. **下拉选项数量限制**
    - 当下拉选项总长度超过255字符时，自动使用隐藏Sheet存储
    - 隐藏Sheet在Excel中不可见，但下拉框功能正常

4. **字段必须标注@ExcelProperty注解**
    - 只有同时标注了@ExcelProperty和@DictDropdown的字段才会添加下拉框

## 测试验证

### 接口测试

1. 启动项目后，访问Swagger UI：`http://localhost:8080/swagger-ui/index.html`

2. 找到员工信息管理相关接口：
    - `POST /ccdi/employee/importTemplateWithDropdown` - 下载带字典下拉框的模板

3. 调用接口下载模板，检查Excel中的下拉框是否正常

### 手动验证

1. 打开下载的Excel模板
2. 点击标注了下拉框的列（如"状态"列）
3. 检查是否出现下拉箭头和选项列表
4. 尝试选择和输入，验证验证规则是否生效

## 技术实现细节

### Excel下拉列表限制处理

Excel对下拉列表的直接字符数有限制（约255字符），本项目采用以下策略：

1. **选项较少时（<255字符）**
    - 直接使用 `DataValidationHelper.createExplicitListConstraint()` 创建下拉列表
    - 下拉选项内联在单元格验证中

2. **选项较多时（≥255字符）**
    - 创建隐藏Sheet存储所有选项
    - 使用 `DataValidationHelper.createFormulaListConstraint()` 通过公式引用
    - 自动隐藏Sheet（`workbook.setSheetHidden()`）

### 字典数据获取

```
┌─────────────┐    缓存查询    ┌─────────────┐
│ DictDropdown │ ───────────▶ │ DictUtils   │
│   注解       │               │  .getDictCache() │
└─────────────┘               └─────────────┘
                                     │
                                     ▼
                              ┌─────────────┐
                              │ Redis缓存    │
                              │ sys_dict:key │
                              └─────────────┘
```

### 列索引映射

通过反射获取字段的@ExcelProperty注解中的index值，确保下拉框添加到正确的列。

## 常见问题

### Q1：下拉框没有显示？

**可能原因：**

1. 字典数据未加载到缓存
2. 字段未指定@ExcelProperty的index值
3. 字典类型编码错误

**解决方法：**

1. 在若依系统字典管理中，进入对应字典类型，刷新缓存
2. 检查实体类字段注解是否正确
3. 确认dictType值与字典管理中的字典类型一致

### Q2：下拉选项显示不完整？

**原因：** 选项字符数超过255字符，但隐藏Sheet创建失败

**解决方法：** 检查日志中的错误信息，确保有权限创建隐藏Sheet

### Q3：可以手动输入非下拉选项的值吗？

**答案：** 可以，通过设置 `strict = false` 允许手动输入

## 更新日志

| 版本    | 日期         | 说明             |
|-------|------------|----------------|
| 1.0.0 | 2026-01-29 | 初始版本，支持字典下拉框功能 |
