image.png

    1. <?php
    2. // 需要的扩展
    3. use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
    4. use PhpOffice\PhpSpreadsheet\IOFactory;
    5. use PhpOffice\PhpSpreadsheet\NamedRange;
    6. use PhpOffice\PhpSpreadsheet\Spreadsheet;
    7. use PhpOffice\PhpSpreadsheet\Style\Alignment;
    8. use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
    9. use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
    10. ?>
    11. class Excel extends Controller
    12. {
    13. /**
    14. * @name: 导出下拉列表Excel
    15. * @author: Turbo
    16. * @Date: 2022-03-30 02:05:24
    17. */
    18. public function exportselectexcel()
    19. {
    20. // 定义表头
    21. $header = [
    22. 'A1' => '门店',
    23. 'B1' => '公寓',
    24. 'C1' => '门牌号',
    25. 'D1' => '记账类型',
    26. 'E1' => '记账项目',
    27. 'F1' => '支出类型',
    28. 'G1' => '费用分类',
    29. 'H1' => '金额',
    30. 'I1' => '记账日期',
    31. 'J1' => '收款人',
    32. 'K1' => '收款人帐号',
    33. 'L1' => '开户支行',
    34. 'M1' => '备注'
    35. ];
    36. // 下拉数据[这里模拟出来数据格式,实际情况从数据库获取数据并整理成下列数据格式]
    37. $oneData = [
    38. [
    39. 'id' => 1,
    40. 'title' => '我是A',
    41. 'children' =>
    42. [
    43. [
    44. 'id' => 2,
    45. 'title' => '我是A的下级A1',
    46. 'children' =>
    47. [
    48. [
    49. 'id' => 3,
    50. 'title' => '我是A1的下级A11'
    51. ],
    52. [
    53. 'id' => 4,
    54. 'title' => '我是A1的下级A12'
    55. ]
    56. ]
    57. ],
    58. [
    59. 'id' => 5,
    60. 'title' => '我是A的下级A2',
    61. 'children' =>
    62. [
    63. [
    64. 'id' => 6,
    65. 'title' => '我是A2的下级A21'
    66. ],
    67. [
    68. 'id' => 7,
    69. 'title' => '我是A2的下级A22'
    70. ]
    71. ]
    72. ]
    73. ]
    74. ],
    75. [
    76. 'id' => 1,
    77. 'title' => '我是B',
    78. 'children' =>
    79. [
    80. [
    81. 'id' => 2,
    82. 'title' => '我是B的下级B1',
    83. 'children' =>
    84. [
    85. [
    86. 'id' => 3,
    87. 'title' => '我是B1的下级B11'
    88. ],
    89. [
    90. 'id' => 4,
    91. 'title' => '我是B1的下级B12'
    92. ]
    93. ]
    94. ],
    95. [
    96. 'id' => 5,
    97. 'title' => '我是B的下级B2',
    98. 'children' =>
    99. [
    100. [
    101. 'id' => 6,
    102. 'title' => '我是B2的下级B21'
    103. ],
    104. [
    105. 'id' => 7,
    106. 'title' => '我是B2的下级B22'
    107. ]
    108. ]
    109. ]
    110. ]
    111. ],
    112. ];
    113. $keepType = '支出'; // 记账类别(默认只有支出)这里如果超出255字符的数据可采用"Sheet"赋值的方法(和下面这种联动的一样)
    114. // 实例化Spreadsheet对象
    115. $spreadsheet = new Spreadsheet();
    116. $sheetMain = $spreadsheet->getsheet(0); // 设置主sheet
    117. $sheetMain->setTitle('Excel导出下拉框-示例'); // 设置sheet的名称
    118. $sheetMain->getPageSetup()->setHorizontalCentered(true);
    119. $sheetMain->getPageSetup()->setVerticalCentered(false);
    120. // 插入表头
    121. foreach ($header as $key => $value) {
    122. $sheetMain->setCellValue($key, $value);
    123. }
    124. $sheetOne = $spreadsheet->createSheet(1); // 创建第一级sheet
    125. $sheetTwo = $spreadsheet->createSheet(2); // 创建第二级sheet
    126. $sheetTwoCol = 0; // 属性sheet的列
    127. foreach ($oneData as $key => $value) {
    128. $row = 1; // 定义赋值开始的行数
    129. /*
    130. 这里采用 Coordinate::stringFromColumnIndex 获取对应的列数名
    131. Ps:顺序从“1”开始,所以获取列名时需要在原有数组索引上加“1”
    132. */
    133. $sheetOne->setCellValue(Coordinate::stringFromColumnIndex(bcadd($key, 1, 0)) . $row, $value['title']); // 所有数据
    134. if (!empty($value['children'])) { // 判断是否有子级
    135. foreach ($value['children'] as $value2) { // 第二级
    136. $row2 = 1; // 属性sheet的第n行
    137. $sheetOne->setCellValue(Coordinate::stringFromColumnIndex(bcadd($key, 1, 0)) . ++$row, $value2['title']);
    138. $sheetTwo->setCellValue(Coordinate::stringFromColumnIndex(bcadd($sheetTwoCol, 1, 0)) . $row2, $value2['title']);
    139. if (!empty($value2['children'])) { // 判断是否有子级
    140. foreach ($value2['children'] as $value3) { // 第三级
    141. $sheetTwo->setCellValue(Coordinate::stringFromColumnIndex(bcadd($sheetTwoCol, 1, 0)) . ++$row2, $value3['title']);
    142. }
    143. $spreadsheet->addNamedRange(new NamedRange($value2['title'], $sheetTwo, Coordinate::stringFromColumnIndex(bcadd($sheetTwoCol, 1, 0)) . '2:' . Coordinate::stringFromColumnIndex(bcadd($sheetTwoCol, 1, 0)) . $row2)); // 设置第二级和第三季联动
    144. }
    145. $sheetTwoCol++; // 属性sheet列+1
    146. }
    147. // 定义数据命名范围
    148. $spreadsheet->addNamedRange(new NamedRange($value['title'], $sheetOne, Coordinate::stringFromColumnIndex(bcadd($key, 1, 0)) . '2:' . Coordinate::stringFromColumnIndex(bcadd($key, 1, 0)) . $row));
    149. }
    150. }
    151. // 定义数据命名范围
    152. $spreadsheet->addNamedRange(new NamedRange('oneData', $sheetOne, 'A1:' . Coordinate::stringFromColumnIndex(bcadd(count($oneData), 1, 0)) . '1'));
    153. // 隐藏不显示的辅助工作表
    154. $sheetOne->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
    155. $sheetTwo->setSheetState(Worksheet::SHEETSTATE_HIDDEN);
    156. $maxRows = 5; // 设置最大填充行数[不包含第一行]
    157. foreach (range(2, bcadd($maxRows, 1, 0)) as $row) {
    158. // 设置下拉
    159. $this->setValidation($sheetMain, "A${row}", '=oneData'); // 第一级下拉
    160. $this->setValidation($sheetMain, "B${row}", "=INDIRECT(A${row})"); // indirect间接的,以某个坐标为依托,联级 第二级下拉
    161. $this->setValidation($sheetMain, "C${row}", "=INDIRECT(B${row})"); // indirect间接的,以某个坐标为依托,联级 第三级下拉
    162. $this->setValidation($sheetMain, "D${row}", '"' . $keepType . '"'); // 记账类型
    163. $this->setInputRule($sheetMain, "H${row}", DataValidation::TYPE_DECIMAL); // 设置输入数字类型
    164. $this->setInputRule($sheetMain, "I${row}", DataValidation::TYPE_TIME); // 设置输入时间类型
    165. }
    166. // 调整sheet样式
    167. $styleArray = ['font' => ['bold' => true], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER]];
    168. $sheetMain->getStyle('A1:M1')->applyFromArray($styleArray);
    169. // 设置表格宽度(设置'auto'为自动宽度)
    170. $sheetMain->getColumnDimension('A')->setWidth(25);
    171. $sheetMain->getColumnDimension('B')->setWidth(25);
    172. $sheetMain->getColumnDimension('C')->setWidth(25);
    173. $sheetMain->getColumnDimension('D')->setWidth(20);
    174. $sheetMain->getColumnDimension('E')->setWidth(25);
    175. $sheetMain->getColumnDimension('F')->setWidth(25);
    176. $sheetMain->getColumnDimension('G')->setWidth(25);
    177. $sheetMain->getColumnDimension('H')->setWidth(20);
    178. $sheetMain->getColumnDimension('I')->setWidth(20);
    179. $sheetMain->getColumnDimension('J')->setWidth(18);
    180. $sheetMain->getColumnDimension('K')->setWidth(22);
    181. $sheetMain->getColumnDimension('L')->setWidth(25);
    182. $sheetMain->getColumnDimension('M')->setWidth(30);
    183. //定义文件名称,需要带有定义的后缀名
    184. $filename = date('YmdHis') . 'Excel下拉框-示例.xlsx';
    185. ob_end_clean(); //清除缓冲区,避免乱码
    186. //将输出重定向到客户端的web浏览器
    187. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    188. header('Content-Disposition: attachment;filename="' . $filename . '"');
    189. header('Cache-Control: max-age=0');
    190. //如果浏览器为IE9
    191. header('Cache-Control: max-age=1');
    192. //如果通过SSL向IE提供服务
    193. header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    194. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
    195. header('Cache-Control: cache, must-revalidate');//HTTP/1.1
    196. header('Pragma: public');//HTTP/1.0
    197. $writer = IOFactory ::createWriter($spreadsheet, 'Xlsx');
    198. $writer->save('php://output');
    199. exit;
    200. }
    201. /**
    202. * 设置某个单元格的下拉列表规则
    203. * @param Worksheet $sheet
    204. * @param [string] $cellPoint 单元格坐标. A1
    205. * @param [sting] $format 公式
    206. * @return void
    207. */
    208. private function setValidation(Worksheet $sheet, $cellPoint, $format)
    209. {
    210. $validation = $sheet->getCell($cellPoint)->getDataValidation();
    211. $validation->setType(DataValidation::TYPE_LIST);
    212. $validation->setErrorStyle(DataValidation::STYLE_INFORMATION);
    213. $validation->setAllowBlank(false);
    214. $validation->setShowInputMessage(true);
    215. $validation->setShowErrorMessage(true);
    216. $validation->setShowDropDown(true);
    217. $validation->setErrorTitle('输出错误');
    218. $validation->setError('值不在列表中');
    219. $validation->setPromptTitle('请选择');
    220. $validation->setPrompt('请从列表中选择一个值');
    221. $validation->setFormula1($format); // 使用某个公司 eg: '=format'
    222. // $validation->setFormula1('"A1,A2,A3"');//可以直接写列表,用逗号分隔,最多255字符
    223. // $objValidation->setFormula1('=INDIRECT(A8)');//indirect间接的,以某个坐标为依托,联级
    224. }
    225. /**
    226. * 设置某个单元格的输入规则
    227. * @param Worksheet $sheet
    228. * @param [string] $cellPoint 单元格坐标. A1
    229. * @param [sting] type 输入类型 DataValidation::TYPE_LIST
    230. * @return void
    231. */
    232. private function setInputRule(Worksheet $sheet, $cellPoint, $type)
    233. {
    234. $validation = $sheet->getCell($cellPoint)->getDataValidation();
    235. $validation->setType($type);
    236. $validation->setErrorStyle(DataValidation::STYLE_INFORMATION); //输错了的话显示的提示属于哪个级别
    237. $validation->setAllowBlank(false);
    238. $validation->setShowInputMessage(true);
    239. $validation->setShowErrorMessage(true);
    240. $validation->setErrorTitle('输入格式有误');
    241. }
    242. }

    文章来源:https://blog.csdn.net/qq_15957557/article/details/123926163