326 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			326 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
|  | <?php | ||
|  | namespace app\admin\controller\csmtable; | ||
|  | 
 | ||
|  | use think\App; | ||
|  | use app\common\controller\Backend; | ||
|  | use PhpOffice\PhpSpreadsheet\Spreadsheet; | ||
|  | use addons\csmtable\library\xcore\xcore\utils\XcRequestUtils; | ||
|  | use addons\csmtable\library\xapp\csmtable\utils\CsmTableUtils; | ||
|  | 
 | ||
|  | class Cligenerateexcel extends Backend | ||
|  | { | ||
|  |     private $xlstask = null; | ||
|  |      | ||
|  |     private $uploadtmppath = RUNTIME_PATH . 'temp' . DS; | ||
|  | 
 | ||
|  |     public function _initialize() | ||
|  |     { | ||
|  |         parent::_initialize(); | ||
|  |         $this->xlstask = new \app\admin\model\csmtable\Xlstask(); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * http://127.0.0.1/fastadmin_plugin_csmmeet/public/q3HJDu2RgE.php/csmtable/cligenerateexcel/index | ||
|  |      */ | ||
|  |     public function index() | ||
|  |     { | ||
|  |         static::p('----generateExcelByClassname begin:'); | ||
|  |         set_time_limit(0); | ||
|  |         $csmtable_xlstask_id = $this->request->request("csmtable_xlstask_id"); | ||
|  | 
 | ||
|  |         $pp = $this->request->request("params"); | ||
|  |         static::p($pp); | ||
|  |         static::p($csmtable_xlstask_id); | ||
|  |         $csmtable_xlstask_id = 119; | ||
|  |         $pp = '{"search":null,"filter":"{}","op":"{}","sort":"weigh","order":"desc","offset":"0","limit":"10","csmtable_classname":"app\/admin\/controller\/fa\/Test","csmtable_methodname":"index","csmtable_columns":"[{\"field\":\"id\",\"title\":\"ID\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"title\",\"title\":\"\u6807\u9898\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"admin_id\",\"title\":\"\u7ba1\u7406\u5458ID\",\"datasource\":\"auth\/admin\",\"datafield\":\"nickname\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"category_id\",\"title\":\"\u5206\u7c7bID(\u5355\u9009)\",\"datasource\":\"category\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"category_ids\",\"title\":\"\u5206\u7c7bID(\u591a\u9009)\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"week\",\"title\":\"\u661f\u671f(\u5355\u9009)\",\"formatter\":\"\",\"searchList\":{\"monday\":\"\u661f\u671f\u4e00\",\"tuesday\":\"\u661f\u671f\u4e8c\",\"wednesday\":\"\u661f\u671f\u4e09\"},\"operate\":\"=\"},{\"field\":\"flag\",\"title\":\"\u6807\u5fd7(\u591a\u9009)\",\"formatter\":\"\",\"searchList\":{\"hot\":\"\u70ed\u95e8\",\"index\":\"\u9996\u9875\",\"recommend\":\"\u63a8\u8350\"},\"operate\":\"FIND_IN_SET\"},{\"field\":\"genderdata\",\"title\":\"\u6027\u522b(\u5355\u9009)\",\"formatter\":\"\",\"searchList\":{\"male\":\"\u7537\",\"female\":\"\u5973\"},\"operate\":\"=\"},{\"field\":\"hobbydata\",\"title\":\"\u7231\u597d(\u591a\u9009)\",\"formatter\":\"\",\"searchList\":{\"music\":\"\u97f3\u4e50\",\"reading\":\"\u8bfb\u4e66\",\"swimming\":\"\u6e38\u6cf3\"},\"operate\":\"FIND_IN_SET\"},{\"field\":\"image\",\"title\":\"\u56fe\u7247\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"images\",\"title\":\"\u56fe\u7247\u7ec4\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"attachfile\",\"title\":\"\u9644\u4ef6\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"keywords\",\"title\":\"\u5173\u952e\u5b57\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"description\",\"title\":\"\u63cf\u8ff0\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"city\",\"title\":\"\u7701\u5e02\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"price\",\"title\":\"\u4ef7\u683c\",\"formatter\":\"\",\"operate\":\"BETWEEN\"},{\"field\":\"views\",\"title\":\"\u70b9\u51fb\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"startdate\",\"title\":\"\u5f00\u59cb\u65e5\u671f\",\"formatter\":\"\",\"operate\":\"RANGE\"},{\"field\":\"activitytime\",\"title\":\"\u6d3b\u52a8\u65f6\u95f4(datetime)\",\"formatter\":\"\",\"operate\":\"RANGE\"},{\"field\":\"year\",\"title\":\"\u5e74\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"times\",\"title\":\"\u65f6\u95f4\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"refreshtime\",\"title\":\"\u5237\u65b0\u65f6\u95f4(int)\",\"formatter\":\"Table.api.formatter.datetime\",\"operate\":\"RANGE\"},{\"field\":\"createtime\",\"title\":\"\u521b\u5efa\u65f6\u95f4\",\"formatter\":\"Table.api.formatter.datetime\",\"operate\":\"RANGE\"},{\"field\":\"updatetime\",\"title\":\"\u66f4\u65b0\u65f6\u95f4\",\"formatter\":\"Table.api.formatter.datetime\",\"operate\":\"RANGE\"},{\"field\":\"weigh\",\"title\":\"\u6743\u91cd\",\"formatter\":\"\",\"operate\":\"=\"},{\"field\":\"switch\",\"title\":\"\u5f00\u5173\",\"formatter\":\"\",\"searchList\":{\"0\":\"\u5426\",\"1\":\"\u662f\"},\"operate\":\"=\"},{\"field\":\"status\",\"title\":\"\u72b6\u6001\",\"formatter\":\"\",\"searchList\":{\"normal\":\"\u6b63\u5e38\",\"hidden\":\"\u9690\u85cf\"},\"operate\":\"=\"},{\"field\":\"state\",\"title\":\"\u72b6\u6001\u503c\",\"formatter\":\"\",\"searchList\":{\"0\":\"\u7981\u7528\",\"1\":\"\u6b63\u5e38\",\"2\":\"\u63a8\u8350\"},\"operate\":\"=\"}]","csmtable_xlspagesize":null}'; | ||
|  |         $this->setProgress($csmtable_xlstask_id, 10); | ||
|  | 
 | ||
|  |         $params = json_decode($pp, true); | ||
|  | 
 | ||
|  |         $classname = str_replace('/', '\\', $this->getParamValue($params, 'csmtable_classname')); | ||
|  |         $methodname = $this->getParamValue($params, 'csmtable_methodname'); | ||
|  | 
 | ||
|  |         $columnstr = $this->getParamValue($params, 'csmtable_columns'); | ||
|  |         $columns = json_decode($columnstr, true); | ||
|  | 
 | ||
|  |         $excelPagesize = $this->getParamValue($params, 'csmtable_xlspagesize', 1000); | ||
|  |         $this->generateExcelByClassname($csmtable_xlstask_id, $classname, $methodname, $params, $columns, $excelPagesize); | ||
|  | 
 | ||
|  |         static::p('----generateExcelByClassname end:'); | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     private function setProgress(&$csmtable_xlstask_id, $progress, $filename = '') | ||
|  |     { | ||
|  |         // $dao = new \app\admin\model\csmtable\Xlstask();
 | ||
|  |         // $this->xlstask->startTrans();
 | ||
|  |         $this->xlstask->where("id", "=", $csmtable_xlstask_id)->update([ | ||
|  |             'progress' => $progress, | ||
|  |             'filename' => $filename, | ||
|  |             'updatetime' => time() | ||
|  |         ]); | ||
|  |         static::p('progress:' . $progress); | ||
|  |         // $dao->commit();
 | ||
|  |     } | ||
|  | 
 | ||
|  |     private function getParamValue(&$params, $key, $defaultvalue = null) | ||
|  |     { | ||
|  |         $sr = null; | ||
|  |         if (isset($params[$key])) { | ||
|  |             $sr = $params[$key]; | ||
|  |         } | ||
|  |         $sr = ($sr == null) ? $defaultvalue : $sr; | ||
|  |         return $sr; | ||
|  |     } | ||
|  | 
 | ||
|  |     private function generateExcelByClassname(&$csmtable_xlstask_id, &$classname, &$methodname, &$params, &$columns, &$excelPagesize) | ||
|  |     { | ||
|  |         $pageno = 0; // 当前页数
 | ||
|  |         $pagesize = 1000; | ||
|  | 
 | ||
|  |         $excelRowIndex = 0; // 当前excel中的记录行数
 | ||
|  |         $excelRows = []; // Excel记录
 | ||
|  |         $excelFileNo = 1; // 第N个Excel
 | ||
|  |         $excelFiles = []; | ||
|  | 
 | ||
|  |         static::p("config excelPagesize:{$excelPagesize}"); | ||
|  |         $request = XcRequestUtils::getRequest(); | ||
|  |         $instance = new $classname($request); | ||
|  |         while (true) { | ||
|  |             $request->set('search', $this->getParamValue($params, 'search')); | ||
|  |             $request->set('filter', $this->getParamValue($params, 'filter')); | ||
|  |             $request->set('op', $this->getParamValue($params, 'op')); | ||
|  |             $request->set('sort', $this->getParamValue($params, 'sort')); | ||
|  |             $request->set('order', $this->getParamValue($params, 'order')); | ||
|  |             // $request->set('offset',$this->getParamValue($params,'offset'));
 | ||
|  |             $request->set('limit', $pagesize); | ||
|  |             $request->setMethodReturn("isAjax", true); | ||
|  |             $request->set("offset", $pageno * $pagesize); | ||
|  |             $sr = App::invokeMethod([ | ||
|  |                 $instance, | ||
|  |                 $methodname | ||
|  |             ], null); | ||
|  |             $request->clear(); | ||
|  |             if ($sr == null) { | ||
|  |                 break; | ||
|  |             } | ||
|  | 
 | ||
|  |             $datarows = &$sr->getData()['rows']; | ||
|  |             $total = $sr->getData()['total']; | ||
|  | 
 | ||
|  |             static::p("--remote total:{$total}/pageno:{$pageno}/offset:" . $pageno * $pagesize); | ||
|  |             foreach ($datarows as &$row) { | ||
|  |                 if ($excelRowIndex >= $excelPagesize) { | ||
|  |                     $progress = (int) ($pageno * $pagesize / $total * 70) + 10; | ||
|  |                     $this->setProgress($csmtable_xlstask_id, $progress); | ||
|  | 
 | ||
|  |                     static::p("------generate excel fileno:{$excelFileNo}/progress:{$progress}"); | ||
|  |                     $excelFiles[] = static::saveExcel($columns, $excelRows, $excelFileNo); | ||
|  |                     $excelRowIndex = 0; | ||
|  |                     unset($excelRows); | ||
|  |                     $excelRows = []; | ||
|  |                     $excelFileNo ++; | ||
|  |                 } | ||
|  |                 $excelRows[] = $row; | ||
|  |                 $excelRowIndex ++; | ||
|  |             } | ||
|  |             unset($datarows); | ||
|  |             unset($sr); | ||
|  |             $sr = null; | ||
|  | 
 | ||
|  |             if ($total <= $pageno * $pagesize) { | ||
|  |                 break; | ||
|  |             } | ||
|  |             $pageno ++; | ||
|  |             // break;
 | ||
|  |         } | ||
|  | 
 | ||
|  |         // 有剩余的Excel row,就保存剩余的
 | ||
|  |         if ($excelRowIndex > 0) { | ||
|  |             static::p("--generate excel fileno:{$excelFileNo}"); | ||
|  |             $excelFiles[] = static::saveExcel($columns, $excelRows, $excelFileNo); | ||
|  |         } | ||
|  |         // Excel保存到Zip
 | ||
|  |         $this->setProgress($csmtable_xlstask_id, 90); | ||
|  |         $zipfilename = static::saveExcelToZip($excelFiles); | ||
|  |         echo $zipfilename . '<BR>'; | ||
|  |         $this->setProgress($csmtable_xlstask_id, 100, $zipfilename); | ||
|  |     } | ||
|  | 
 | ||
|  |     private function saveExcel(&$columns, &$rows, &$excelNo) | ||
|  |     { | ||
|  |         echo $excelNo . '<BR>'; | ||
|  |         $spreadsheet = new Spreadsheet(); | ||
|  | 
 | ||
|  |         $sheet = $spreadsheet->getActiveSheet(); | ||
|  |         $filename = 'excel-' . $excelNo; | ||
|  | 
 | ||
|  |         foreach ($columns as $k => $item) { | ||
|  |             $sheet->setCellValueByColumnAndRow($k + 1, 1, $item['title']); | ||
|  |         } | ||
|  | 
 | ||
|  |         $dsDatas = $this->getDataSourceDatas($columns, $rows); | ||
|  | 
 | ||
|  |         foreach ($rows as $k => $item) { | ||
|  |             foreach ($columns as $k2 => $column) { | ||
|  |                 $vv = $item[$column['field']]; | ||
|  |                 $vv = $this->_convertValueByColumn($column, $vv, $dsDatas); | ||
|  |                 $sheet->setCellValueByColumnAndRow($k2 + 1, $k + 2, $vv); | ||
|  |             } | ||
|  |         } | ||
|  |         unset($rows); | ||
|  |         unset($dsDatas); | ||
|  |         $filename = 'csmtable_' . time() . '_' . $excelNo . '.xlsx'; | ||
|  |         $filepath = &$this->uploadtmppath; | ||
|  |         $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx'); | ||
|  |         $writer->save($filepath . $filename); | ||
|  |         unset($writer); | ||
|  |         $writer = null; | ||
|  |         return [ | ||
|  |             'filename' => $filename, | ||
|  |             'filepath' => $filepath | ||
|  |         ]; | ||
|  |     } | ||
|  | 
 | ||
|  |     private function getDataSourceDatas(&$columns, &$rows) | ||
|  |     { | ||
|  |         $sr = []; | ||
|  |         foreach ($columns as &$column) { | ||
|  |             if (isset($column['datasource']) && $column['datasource'] != null) { | ||
|  |                 $datafield = null; | ||
|  |                 if (isset($column['datafield']) && $column['datafield'] != null) { | ||
|  |                     $datafield = $column['datafield']; | ||
|  |                 } else { | ||
|  |                     $datafield = 'name'; | ||
|  |                 } | ||
|  |                 $ids = []; | ||
|  |                 foreach ($rows as $item) { | ||
|  |                     $ids[] = $item[$column['field']]; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 //v2.2.5 修复admin账号的安全楼栋
 | ||
|  |                 $datasdatasource_callremoteource = $column['datasource']; | ||
|  |                 if($datasdatasource_callremoteource=="auth/admin"){ | ||
|  |                     $datasdatasource_callremoteource = "csmtable/datasource/admin"; | ||
|  |                 } | ||
|  |                 $im = CsmTableUtils::getInstanceAndMethod($datasdatasource_callremoteource); | ||
|  | 
 | ||
|  |                 if ($im != null) { | ||
|  |                     $classname = $im[0]; | ||
|  |                     $methodname = $im[1]; | ||
|  | 
 | ||
|  |                     $request = XcRequestUtils::getRequest(); | ||
|  |                     $request->setMethodReturn("isAjax", true); | ||
|  |                     $request->set('filter', '{"id":"' . implode(',', $ids) . '"}'); | ||
|  |                     $request->set('op', '{"id":"in"}'); | ||
|  |                     $request->set('sort', 'id'); | ||
|  |                     $request->set('order', 'desc'); | ||
|  | 
 | ||
|  |                     // \app\admin\controller\auth\Admin;
 | ||
|  |                     $instance2 = new $classname($request); | ||
|  |                     $json2 = App::invokeMethod([ | ||
|  |                         $instance2, | ||
|  |                         $methodname | ||
|  |                     ], null); | ||
|  |                     $request->clear(); | ||
|  | 
 | ||
|  |                     if ($json2 == null) { | ||
|  |                         break; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     $datarows = &$json2->getData()['rows']; | ||
|  | 
 | ||
|  |                     $vvs = []; | ||
|  |                     foreach ($datarows as &$row) { | ||
|  |                         $vv = null; | ||
|  |                         if (isset($row[$datafield])) { | ||
|  |                             $vv = $row[$datafield]; | ||
|  |                         } else { | ||
|  |                             $vv = $row->$datafield; | ||
|  |                         } | ||
|  | 
 | ||
|  |                         $vvs['ID#' . $row['id']] = $vv; | ||
|  |                     } | ||
|  |                     unset($json2); | ||
|  |                     unset($instance2); | ||
|  |                     $instance2 = null; | ||
|  |                 } | ||
|  |                 $sr[$column['field']] = $vvs; | ||
|  |             } | ||
|  |         } | ||
|  |         return $sr; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 将value根据table的options转换成文字 | ||
|  |      */ | ||
|  |     private function _convertValueByColumn(&$column, &$value, &$dsDatas) | ||
|  |     { | ||
|  |         $sr = ''; | ||
|  | 
 | ||
|  |         if (isset($column['searchList']) && $column['searchList'] != null) { | ||
|  |             // searchlist类型的,将code转为name
 | ||
|  |             $searchList = $column['searchList']; | ||
|  |             // operate类型,字典数组,用逗号分隔
 | ||
|  |             if (isset($column['operate']) && $column['operate'] != null && $column['operate'] == 'FIND_IN_SET') { | ||
|  |                 $ssarr = explode(",", $value); | ||
|  |                 $sslabel = []; | ||
|  |                 foreach ($ssarr as $ssarrv) { | ||
|  |                     if (isset($searchList[$ssarrv])) { | ||
|  |                         $sslabel[] = $searchList[$ssarrv]; | ||
|  |                     } else { | ||
|  |                         $sslabel[] = $ssarrv; | ||
|  |                     } | ||
|  |                 } | ||
|  |                 $sr = implode(',', $sslabel); | ||
|  |             } else { | ||
|  |                 // 普通字典
 | ||
|  |                 if (isset($searchList[$value])) { | ||
|  |                     $sr = $searchList[$value]; | ||
|  |                 } | ||
|  |             } | ||
|  |         } else if (isset($column['formatter']) && $column['formatter'] != null && $column['formatter'] == "Table.api.formatter.datetime") { | ||
|  |             // 时间型
 | ||
|  |             if ($value != null && $value != '') { | ||
|  |                 $sr = date('Y-m-s h:i:s', $value); | ||
|  |             } | ||
|  |         } else if (isset($column['datasource']) && $column['datasource'] != null && $column['datasource'] != "") { | ||
|  |             // 时间型
 | ||
|  |             if (isset($dsDatas[$column['field']]) && $dsDatas[$column['field']] != null) { | ||
|  |                 $dsDataitem = $dsDatas[$column['field']]; | ||
|  |                 if (isset($dsDataitem['ID#' . $value]) && $dsDataitem['ID#' . $value] != null) { | ||
|  |                     $sr = $dsDataitem['ID#' . $value]; | ||
|  |                 } | ||
|  |             } | ||
|  |             if ($sr == null || $sr == '') { | ||
|  |                 $sr = $value; | ||
|  |             } | ||
|  |         } else { | ||
|  |             $sr = $value; | ||
|  |         } | ||
|  |         return $sr; | ||
|  |     } | ||
|  | 
 | ||
|  |     private function saveExcelToZip($excelFiles) | ||
|  |     { | ||
|  |         $zipfn = 'csmtable_' . time() . '.zip'; | ||
|  |         $zipfilename = $this->uploadtmppath . $zipfn; | ||
|  |         $zip = new \ZipArchive(); | ||
|  |         $zip->open($zipfilename, \ZipArchive::CREATE | \ZipArchive::OVERWRITE); | ||
|  |         foreach ($excelFiles as $item) { | ||
|  |             $zip->addFile($item['filepath'] . $item['filename'], $item['filename']); | ||
|  |         } | ||
|  |         $zip->close(); | ||
|  | 
 | ||
|  |         foreach ($excelFiles as $item) { | ||
|  |             unlink($item['filepath'] . $item['filename']); | ||
|  |         } | ||
|  |         return $zipfn; | ||
|  |     } | ||
|  |      | ||
|  |     private static function p($str){ | ||
|  |         //echo( $str."<BR>\r\n" ) ; 
 | ||
|  |     } | ||
|  | 
 | ||
|  | } |