GoodsImport.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用。
  9. * 任何企业和个人不允许对程序代码以任何形式任何目的再发布。
  10. * =========================================================
  11. */
  12. namespace app\model\goods;
  13. use app\model\BaseModel;
  14. use addon\virtualcard\model\VirtualGoods as VirtualCardGoods;
  15. /**
  16. * 商品导入
  17. */
  18. class GoodsImport extends BaseModel
  19. {
  20. /**
  21. * 读取excel中的数据
  22. * @param $excel_path
  23. * @return array
  24. * @throws \PHPExcel_Reader_Exception
  25. */
  26. public function readGoodsExcel($excel_path)
  27. {
  28. if (!file_exists($excel_path)) return $this->error('', '商品导入Excel文件路径错误');
  29. $excel_reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
  30. try {
  31. $excel_reader->setReadDataOnly(true); // 只读取数据,会忽略所有空白行
  32. $php_excel = $excel_reader->load($excel_path);
  33. $goods_data = $this->getSheetData($php_excel, 0);
  34. $sku_data = $this->getSheetData($php_excel, 1);
  35. $data = [
  36. 'original_goods_data' => $goods_data,
  37. 'original_sku_data' => $sku_data
  38. ];
  39. $goods_field = $goods_data[ 1 ];
  40. $sku_field = $sku_data[ 1 ];
  41. unset($goods_data[ 1 ], $goods_data[ 2 ], $sku_data[ 1 ], $sku_data[ 2 ]); // 移除表头
  42. $data[ 'list' ] = $goods_data;
  43. $sku_temp = [];
  44. foreach ($sku_data as $k => $sku_item) {
  45. $sku_item = array_combine($sku_field, $sku_item);
  46. $sku_data[ $k ] = $sku_item;
  47. if (isset($sku_temp[ 'goods_' . $sku_item[ 'goods_number' ] ])) {
  48. array_push($sku_temp[ 'goods_' . $sku_item[ 'goods_number' ] ], $sku_item);
  49. } else {
  50. $sku_temp[ 'goods_' . $sku_item[ 'goods_number' ] ] = [ $sku_item ];
  51. }
  52. }
  53. foreach ($data[ 'list' ] as $k => $item) {
  54. $item = array_combine($goods_field, $item);
  55. $data[ 'list' ][ $k ] = $item;
  56. if (isset($item[ 'is_many_sku' ]) && $item[ 'is_many_sku' ] && isset($sku_temp[ 'goods_' . $item[ 'goods_number' ] ])) {
  57. $data[ 'list' ][ $k ][ 'sku' ] = $sku_temp[ 'goods_' . $item[ 'goods_number' ] ];
  58. }
  59. }
  60. return $this->success($data);
  61. } catch (\Exception $e) {
  62. return $this->error('', $e->getMessage() . $e->getFile() . $e->getLine());
  63. }
  64. }
  65. /**
  66. * 将图表中的数据读取出来
  67. * @param $excel_reader
  68. * @param int $sheet
  69. */
  70. public function getSheetData($php_excel, $sheet = 0)
  71. {
  72. $all_column = $php_excel->getSheet($sheet)->getHighestColumn(); //取得最大的列号
  73. $all_row = $php_excel->getSheet($sheet)->getHighestRow(); //取得一共有多少行
  74. $data = [];
  75. for ($row = 1; $row <= $all_row; $row++) {
  76. //从A列读取数据
  77. for ($col = 'A'; $col <= $all_column; $col++) {
  78. // 读取单元格
  79. $data[ $row ][] = trim((string) $php_excel->getSheet($sheet)->getCell("$col$row")->getValue());
  80. }
  81. }
  82. return $data;
  83. }
  84. /**
  85. * 导入商品
  86. * @param $data
  87. * @param $site_id
  88. * @param $goods_class
  89. * @return array
  90. */
  91. public function importGoods($data, $site_id, $goods_class)
  92. {
  93. switch ( $goods_class ) {
  94. case 1:
  95. $name = '实物商品导入';
  96. $goods_class = new Goods();
  97. break;
  98. case 2:
  99. $name = '虚拟商品导入';
  100. $goods_class = new VirtualGoods();
  101. break;
  102. case 3:
  103. $name = '卡密商品导入';
  104. $goods_class = new VirtualCardGoods();
  105. break;
  106. }
  107. $import_data = [
  108. 'site_id' => $site_id,
  109. 'import_time' => time(),
  110. 'success_num' => 0,
  111. 'record_name' => $name,
  112. 'fail_num' => 0,
  113. 'fail_data' => [],
  114. ];
  115. // 执行导入
  116. foreach ($data[ 'list' ] as $key => $item) {
  117. $res = $goods_class->importGoods($item, $site_id);
  118. if ($res[ 'code' ] == 0) {
  119. $import_data[ 'success_num' ] += 1;
  120. } else {
  121. array_push($import_data[ 'fail_data' ], [
  122. 'index' => $key,
  123. 'reason' => $res[ 'message' ]
  124. ]);
  125. $import_data[ 'fail_num' ] += 1;
  126. }
  127. }
  128. unset($data[ 'list' ]);
  129. // 添加导入记录
  130. $import_data[ 'data' ] = json_encode($data);
  131. $import_data[ 'fail_data' ] = empty($import_data[ 'fail_data' ]) ? '' : json_encode($import_data[ 'fail_data' ], JSON_UNESCAPED_UNICODE);
  132. model('goods_import_record')->add($import_data);
  133. return $this->success([ 'error_count' => $import_data[ 'fail_num' ], 'success_count' => $import_data[ 'success_num' ] ]);
  134. }
  135. /**
  136. * 获取导入记录
  137. * @param array $condition
  138. * @param int $page
  139. * @param int $list_rows
  140. * @param bool $field
  141. * @param string $order
  142. * @return array
  143. */
  144. public function getImportPageList($condition = [], $page = 1, $list_rows = PAGE_LIST_ROWS, $field = true, $order = 'import_time desc')
  145. {
  146. $data = model('goods_import_record')->pageList($condition, $field, $order, $page, $list_rows);
  147. return $this->success($data);
  148. }
  149. /**
  150. * 下载失败数据
  151. * @param $id
  152. * @param $site_id
  153. */
  154. public function downloadFailData($id, $site_id)
  155. {
  156. $info = model('goods_import_record')->getInfo([ [ 'id', '=', $id ], [ 'site_id', '=', $site_id ], [ 'fail_num', '>', 0 ] ], 'data,fail_data');
  157. if (empty($info)) return $this->error('', '未获取到导出记录');
  158. $original_data = json_decode($info[ 'data' ], true);
  159. $fail_data = json_decode($info[ 'fail_data' ], true);
  160. $field = $original_data[ 'original_goods_data' ][ 1 ];
  161. $header = $original_data[ 'original_goods_data' ][ 2 ];
  162. array_push($field, 'reason');
  163. array_push($header, '失败原因(再次上传前请先删除该列)');
  164. // 需要导出的商品数据
  165. $export_goods = [
  166. $field,
  167. $header
  168. ];
  169. // 需要导出的规格数据
  170. $export_sku = [
  171. $original_data[ 'original_sku_data' ][ 1 ],
  172. $original_data[ 'original_sku_data' ][ 2 ]
  173. ];
  174. // 处理sku数据
  175. unset($original_data[ 'original_sku_data' ][ 1 ], $original_data[ 'original_sku_data' ][ 2 ]);
  176. $sku_data = $original_data[ 'original_sku_data' ];
  177. $sku_temp = [];
  178. foreach ($sku_data as $k => $sku_item) {
  179. $sku = array_combine($export_sku[ 0 ], $sku_item);
  180. if (isset($sku_temp[ 'goods_' . $sku[ 'goods_number' ] ])) {
  181. array_push($sku_temp[ 'goods_' . $sku[ 'goods_number' ] ], $sku_item);
  182. } else {
  183. $sku_temp[ 'goods_' . $sku[ 'goods_number' ] ] = [ $sku_item ];
  184. }
  185. }
  186. foreach ($fail_data as $item) {
  187. $goods = $original_data[ 'original_goods_data' ][ $item[ 'index' ] ];
  188. array_push($goods, $item[ 'reason' ]);
  189. array_push($export_goods, $goods);
  190. $goods = array_combine($export_goods[ 0 ], $goods);
  191. if ($goods[ 'is_many_sku' ] && isset($sku_temp[ 'goods_' . $goods[ 'goods_number' ] ])) {
  192. $export_sku = array_merge($export_sku, $sku_temp[ 'goods_' . $goods[ 'goods_number' ] ]);
  193. }
  194. }
  195. $letter = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];
  196. $file_name = '商品导入失败数据-' . date('YmdHis');
  197. $php_excel = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
  198. $php_excel->getProperties()->setTitle($file_name); //设置标题
  199. // 设置当前sheet
  200. $php_excel->setActiveSheetIndex(0);
  201. // 设置当前sheet的名称
  202. $php_excel->getActiveSheet()->setTitle('商品');
  203. for ($i = 0; $i < count($export_goods); $i++) {
  204. $item = $export_goods[ $i ];
  205. for ($j = 0; $j < count($item); $j++) {
  206. $php_excel->getActiveSheet()->setCellValue($letter[ $j ] . ( $i + 1 ), $item[ $j ]);
  207. }
  208. }
  209. // 设置当前sheet
  210. $php_excel->createSheet(1);
  211. $php_excel->setActiveSheetIndex(1);
  212. // 设置当前sheet的名称
  213. $php_excel->getActiveSheet()->setTitle('规格');
  214. for ($i = 0; $i < count($export_sku); $i++) {
  215. $item = $export_sku[ $i ];
  216. for ($j = 0; $j < count($item); $j++) {
  217. $php_excel->getActiveSheet()->setCellValue($letter[ $j ] . ( $i + 1 ), $item[ $j ]);
  218. }
  219. }
  220. ob_clean();
  221. header('Content-Type: application/vnd.ms-excel');
  222. header('Content-Disposition: attachment;filename="' . $file_name . '.xlsx');
  223. header('Cache-Control: max-age=1');
  224. $objWriter = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($php_excel, 'Xlsx');
  225. $objWriter->save('php://output');
  226. }
  227. }