You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2404 lines
107 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
// +----------------------------------------------------------------------
// | Description: 自定义字段模块数据Excel导入导出
// +----------------------------------------------------------------------
// | Author: Michael_xu | gengxiaoxu@5kcrm.com
// +----------------------------------------------------------------------
namespace app\admin\model;
use app\admin\model\Common;
use app\admin\model\Message;
use app\work\model\Task;
use com\PseudoQueue as Queue;
use think\Cache;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
class Excel extends Common
{
/**
* 支持自定义字段的表,不包含表前缀
*
* @var array
*/
private $types_arr = [
'crm_leads',
'crm_customer',
'crm_contacts',
'crm_product',
'admin_user',
'task'
];
/**
* 字段类型为 map_address 的地址类型字段,导入导出时占四个字段,四个单元格
*/
private $map_address = ['省', '市', '区/县', '详细地址'];
/**
* 导入锁缓存名称
*/
const IMPORT_QUEUE = DB_NAME . 'IMPORT_QUEUE';
/**
* 导出锁缓存名称
*/
const EXPORT_QUEUE = DB_NAME . 'EXPORT_QUEUE';
/**
*获取excel相关列
**/
public function stringFromColumnIndex($pColumnIndex = 0)
{
static $_indexCache = array();
if (!isset($_indexCache[$pColumnIndex])) {
if ($pColumnIndex < 26) {
$_indexCache[$pColumnIndex] = chr(65 + $pColumnIndex);
} elseif ($pColumnIndex < 702) {
$_indexCache[$pColumnIndex] = chr(64 + ($pColumnIndex / 26)) . chr(65 + $pColumnIndex % 26);
} else {
$_indexCache[$pColumnIndex] = chr(64 + (($pColumnIndex - 26) / 676)) . chr(65 + ((($pColumnIndex - 26) % 676) / 26)) . chr(65 + $pColumnIndex % 26);
}
}
return $_indexCache[$pColumnIndex];
}
/**
* 自定义字段模块导入模板下载
* @param $field_list 自定义字段数据
* @param $types 分类
* @author
**/
public function excelImportDownload($field_list, $types, $save_path = '')
{
$fieldModel = new \app\admin\model\Field();
//实例化主文件
$objPHPExcel = new Spreadsheet();
$objProps = $objPHPExcel->getProperties(); // 设置excel文档的属性
$objProps->setCreator("5kcrm"); //创建人
$objProps->setLastModifiedBy("5kcrm"); //最后修改人
$objProps->setTitle("5kcrm"); //标题
$objProps->setSubject("5kcrm data"); //题目
$objProps->setDescription("5kcrm data"); //描述
$objProps->setKeywords("5kcrm data"); //关键字
$objProps->setCategory("5kcrm"); //种类
$objPHPExcel->setActiveSheetIndex(0); //设置当前的sheet
$objActSheet = $objPHPExcel->getActiveSheet();
$objActSheet->setTitle('悟空软件导入模板' . date('Y-m-d', time())); //设置sheet的标题
//存储Excel数据源到其他工作薄
$objPHPExcel->createSheet();
$subObject = $objPHPExcel->getSheet(1);
$subObject->setTitle('data');
//保护数据源
$subObject->getProtection()->setSheet(true);
$subObject->protectCells('A1:C1000', time());
//填充边框
$styleArray = [
'borders' => [
'outline' => [
'style' => \PHPExcel_Style_Border::BORDER_THICK, //设置边框
'color' => ['argb' => '#F0F8FF'], //设置颜色
],
],
];
if ($save_path) {
$objActSheet->setCellValue('A2', '错误原因(导入时需删除本列)');
$objActSheet->getColumnDimension('A')->setWidth(40); //设置单元格宽度
$k = 1;
} else {
$k = 0;
}
foreach ($field_list as $field) {
if ($field['form_type'] == 'map_address' && $types == 'crm_customer') {
for ($a = 0; $a <= 3; $a++) {
$objActSheet->getColumnDimension($this->stringFromColumnIndex($k))->setWidth(20); //设置单元格宽度
//如果是所在省的话
$objActSheet->setCellValue($this->stringFromColumnIndex($k) . '2', $this->map_address[$a]);
$k++;
}
} else {
$objActSheet->getColumnDimension($this->stringFromColumnIndex($k))->setWidth(20); //设置单元格宽度
if ($field['form_type'] == 'select' || $field['form_type'] == 'checkbox' || $field['form_type'] == 'radio' || $field['form_type'] == 'category') {
//产品类别
if ($field['form_type'] == 'category' && $field['types'] == 'crm_product') {
$setting = db('crm_product_category')->order('pid asc')->column('name');
} else {
$setting = $field['setting'] ?: [];
}
$select_value = implode(',', $setting);
//解决下拉框数据来源字串长度过大:将每个来源字串分解到一个空闲的单元格中
$str_len = strlen($select_value);
$selectList = array();
if ($str_len >= 255) {
$str_list_arr = explode(',', $select_value);
if ($str_list_arr) {
foreach ($str_list_arr as $i1 => $d) {
$c = $this->stringFromColumnIndex($k) . ($i1 + 1);
$subObject->setCellValue($c, $d);
$selectList[$d] = $d;
}
$endcell = $c;
}
for ($j = 3; $j <= 70; $j++) {
$objActSheet->getStyle($this->stringFromColumnIndex($k) . $j)->getNumberFormat()->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);//设置单元格格式 (文本)
//数据有效性 start
$objValidation = $objActSheet->getCell($this->stringFromColumnIndex($k) . $j)->getDataValidation();
$objValidation->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST)
->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION)
->setAllowBlank(false)
->setShowInputMessage(true)
->setShowErrorMessage(true)
->setShowDropDown(true)
->setErrorTitle('输入的值有误')
->setError('您输入的值不在下拉框列表内.')
->setPromptTitle('--请选择--')
->setFormula1('data!$' . $this->stringFromColumnIndex($k) . '$1:$' . $this->stringFromColumnIndex($k) . '$' . count(explode(',', $select_value)));
//数据有效性 end
}
} else {
if ($select_value) {
for ($j = 3; $j <= 70; $j++) {
$objActSheet->getStyle($this->stringFromColumnIndex($k) . $j)->getNumberFormat()->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);//设置单元格格式 (文本)
//数据有效性 start
$objValidation = $objActSheet->getCell($this->stringFromColumnIndex($k) . $j)->getDataValidation();
$objValidation->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST)
->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_INFORMATION)
->setAllowBlank(false)
->setShowInputMessage(true)
->setShowErrorMessage(true)
->setShowDropDown(true)
->setErrorTitle('输入的值有误')
->setError('您输入的值不在下拉框列表内.')
->setPromptTitle('--请选择--')
->setFormula1('"' . $select_value . '"');
//数据有效性 end
}
}
}
}
$objActSheet->getStyle($this->stringFromColumnIndex($k))->getNumberFormat()->setFormatCode(\PHPExcel_Style_NumberFormat::FORMAT_TEXT);//设置单元格格式 (文本)
//检查该字段若必填,加上"*"
$field['name'] = sign_required($field['is_null'], $field['name']);
$objActSheet->setCellValue($this->stringFromColumnIndex($k) . '2', $field['name']);
$k++;
}
}
$max_row = $this->stringFromColumnIndex($k - 1);
$mark_row = $this->stringFromColumnIndex($k);
$objActSheet->mergeCells('A1:' . $max_row . '1');
$objActSheet->getStyle('A1:' . $mark_row . '1')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); //水平居中
$objActSheet->getStyle('A1:' . $mark_row . '1')->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER); //垂直居中
$objActSheet->getRowDimension(1)->setRowHeight(28); //设置行高
$objActSheet->getStyle('A1')->getFont()->getColor()->setARGB('FFFF0000');
$objActSheet->getStyle('A1')->getAlignment()->setWrapText(true);
$objActSheet->getStyle('A1')->getFont()->getColor()->setARGB('FFFF0000');
$objActSheet->getStyle('A1')->getAlignment()->setWrapText(true);
//设置单元格格式范围的字体、字体大小、加粗
$objActSheet->getStyle('A1:' . $max_row . '1')->getFont()->setName("微软雅黑")->setSize(13)->getColor()->setARGB('#00000000');
//给单元格填充背景色
$objActSheet->getStyle('A1:' . $max_row . '1')->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('#ff9900');
switch ($types) {
case 'crm_leads' :
$types_name = '线索信息';
$type_name = 'leads';
break;
case 'crm_customer' :
$types_name = '客户信息';
$type_name = 'customer';
break;
case 'crm_contacts' :
$types_name = '联系人信息';
$type_name = 'contacts';
break;
case 'crm_product' :
$types_name = '产品信息';
$type_name = 'product';
break;
case 'crm_business' :
$types_name = '商机信息';
$type_name = 'business';
break;
case 'crm_contract' :
$types_name = '合同信息';
$type_name = 'contract';
break;
case 'crm_receivables' :
$types_name = '回款信息';
$type_name = 'receivables';
break;
case 'admin_user' :
$types_name = '员工信息';
$type_name = 'user';
break;
default :
$types_name = '悟空软件';
$type_name = 'WuKong';
break;
}
$content = $types_name . '*代表必填项;时间格式:' . date('Y-m-d H:i:s') . '';
$objActSheet->setCellValue('A1', $content);
$objWriter = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($objPHPExcel, 'Xls');
ob_end_clean();
if ($save_path) {
$objWriter->save($save_path);
} else {
header("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
header("Content-Disposition:attachment;filename=" . $type_name .'_'. date('Y-m-d') . ".xls");
header("Pragma:no-cache");
header("Expires:0");
$objWriter = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($objPHPExcel, 'Xls');
$objWriter->save('php://output');
}
}
/**
* 自定义字段模块导出csv
* @param $file_name 导出文件名称
* @param $field_list 导出字段列表
* @param $callback 回调函数,查询需要导出的数据
* @author
**/
public function exportCsv($file_name, $field_list, $callback)
{
$fieldModel = new \app\admin\model\Field();
ini_set('memory_limit', '1024M');
ini_set('max_execution_time', '300');
// set_time_limit(0);
//调试时先把下面这个两个header注释即可
header("Access-Control-Expose-Headers: Content-Disposition");
header("Content-type:application/vnd.ms-excel;charset=UTF-8");
header("Content-Disposition:attachment;filename=" . $file_name . ".csv");
header('Expires: 0');
header('Cache-control: private');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Description: File Transfer');
header('Content-Encoding: UTF-8');
// 加上bom头防止用office打开时乱码
echo "\xEF\xBB\xBF"; // UTF-8 BOM
// 打开PHP文件句柄php://output 表示直接输出到浏览器
$fp = fopen('php://output', 'a');
// 将中文标题转换编码,否则乱码
foreach ($field_list as $i => $v) {
$title_cell[$i] = $v['name'];
}
// 将标题名称通过fputcsv写到文件句柄
fputcsv($fp, $title_cell);
// $export_data = $callback(0);
$round = round(1000, 9999);
cache($file_name . $round, $callback['list']);
$sheetContent = cache($file_name . $round);
$sheetCount = $callback['dataCount'];
$forCount = 1000; //每次取出1000个
for ($i = 0; $i <= ceil(round($sheetCount / $forCount, 2)); $i++) {
$_sub = array_slice($sheetContent, ($i) * $forCount, 1000);
foreach ($_sub as $kk => $item) {
$rows = [];
foreach ($field_list as $key => $rule) {
$rows[] = ($key = $item[$key]);
}
fputcsv($fp, $rows);
}
ob_flush();//清除内存
flush();
}
// 将已经写到csv中的数据存储变量销毁释放内存占用
//$m = memory_get_usage();
Cache::rm($file_name . $round);
ob_flush();
flush();
fclose($fp);
exit();
}
/**
* 分批导出csv
*
* @param string $file_name 下载文件名称
* @param string $temp_file 临时文件名称 (不带 .csv 后缀)
* @param array $field_list 字段表头
* @param int $page 响应页码默认1
* @param callback $callback 回调函数,返回数据
* ($page, $page_size) 查询页码,查询数量
* @param array $config 设置信息
* - response_size 单次请求响应数量 默认2000
* - page_size 单次数据库查询数量 默认 500
* @author Ymob
*/
public function batchExportCsv($file_name, $temp_file, $field_list, $page, $callback, $config = [])
{
$queue = new Queue(self::EXPORT_QUEUE, 3);
$export_queue_index = input('export_queue_index');
if (!$export_queue_index) {
if (!$export_queue_index = $queue->makeTaskId()) {
return resultArray(['error' => $queue->error]);
}
} else {
if (!$queue->setTaskId($export_queue_index)) {
return resultArray(['error' => $queue->error]);
}
}
// 已取消
if ($page == -1) {
$queue->dequeue();
return resultArray([
'data' => [
'msg' => '导出已取消',
'page' => -1
]
]);
}
// 排队中
if (!$queue->canExec()) {
return resultArray([
'data' => [
'page' => -2,
'export_queue_index' => $export_queue_index,
'info' => $queue->error
]
]);
}
// 没有临时文件名,代表第一次导出,生成临时文件名称,并写入表头数据
if ($temp_file === null) {
// 生成临时文件路径
$file_path = tempFileName('csv');
$fp = fopen($file_path, 'a');
$title_cell = [];
foreach ($field_list as $v) {
if ($v['form_type'] == 'customer_address') {
$title_cell[] = $this->map_address[0];
$title_cell[] = $this->map_address[1];
$title_cell[] = $this->map_address[2];
} else {
$title_cell[] = $v['name'];
}
}
fputcsv($fp, $title_cell);
$temp_file = \substr($file_path, strlen(TEMP_DIR));
} else {
$file_path = TEMP_DIR . $temp_file;
if (!file_exists($file_path)) {
return resultArray(['error' => '参数错误,临时文件不存在']);
}
$fp = fopen($file_path, 'a');
}
// 自定义字段模型
$fieldModel = new \app\admin\model\Field();
// 单次响应条数 (必须是单次查询条数的整数倍)
$response_size = $config['response_size'] ?: 10000;
// 单次查询条数
$page_size = $config['page_size'] ?: 200;
// 最多查询次数
$max_query_count = $response_size / $page_size;
// 总数
$total = 0;
for ($i = 1; $i <= $max_query_count; $i++) {
// 两个参数,第一个参数是 page (传入 model\customer::getDataList 方法的参数),
$data = $callback($i + ($page - 1) * ($response_size / $page_size), $page_size);
$total = $data['dataCount'];
foreach ($data['list'] as $val) {
$val['create_time']=strtotime($val['create_time']);
$val['update_time']=strtotime($val['update_time']);
$val['last_time']=strtotime($val['last_time']);
$val['next_time']=strtotime($val['next_time']);
$rows = [];
foreach ($field_list as $rule) {
if ($rule['form_type'] == 'customer_address') {
$address_arr = explode(chr(10), $val['address']);
$rows[] = $address_arr[0] ?: '';
$rows[] = $address_arr[1] ?: '';
$rows[] = $address_arr[2] ?: '';
} else {
$rows[] = $fieldModel->getValueByFormtype($val[$rule['field']], $rule['form_type']);
}
}
fputcsv($fp, $rows);
}
}
fclose($fp);
// 已查询数据条数 小于 数据总数
$done = $page * $response_size;
if ($done < $total) {
return resultArray([
'data' => [
'export_queue_index' => $export_queue_index,
'temp_file' => $temp_file,
// 总数
'total' => $total,
// 已完成
'done' => $done,
// 返回前端页码
'page' => $page + 1
]
]);
}
$res = $queue->dequeue();
// 所有数据已导入 csv 文件,返回文件流完成后删除
return download($file_path, $file_name . '.csv', true);
}
/**
* 分批导入文件
*
* @param null|array|\think\File $file
* @param array $param
* @param Controller $controller
* @return bool
*
* @author Ymob
*/
public function batchImportData($file, $param, $controller = null)
{
// 导入模块
$types = $param['types'];
if (!in_array($types, $this->types_arr)) {
$this->error = '参数错误!';
$queue->dequeue();
return false;
}
$user_id = $param['owner_user_id'];
// 采用伪队列 允许三人同时导入数据
$queue = new Queue(self::IMPORT_QUEUE, 5);
$import_queue_index = input('import_queue_index');
// 队列任务ID
if (!$import_queue_index) {
if (!$import_queue_index = $queue->makeTaskId()) {
$this->error = $queue->error;
$queue->dequeue();
return false;
}
} else {
if (!$queue->setTaskId($import_queue_index)) {
$this->error = $queue->error;
$queue->dequeue();
return false;
}
}
// 取消导入
if ($param['page'] == -1) {
@unlink(UPLOAD_PATH . $param['temp_file']);
$this->error = [
'msg' => '导入已取消',
'page' => -1
];
if ($param['error']) {
$this->error['error_file_path'] = 'temp/' . $param['error_file'];
} else {
@unlink(TEMP_DIR . $param['error_file']);
}
$temp = $queue->cache('last_import_cache');
(new ImportRecord())->createData([
'type' => $types,
'total' => $temp['total'],
'done' => $temp['done'],
'cover' => $temp['cover'],
'error' => $temp['error'],
'user_id' => $user_id,
'error_data_file_path' => $temp['error'] ? 'temp/' . $error_data_file_name : ''
]);
$queue->dequeue();
return true;
}
if (!empty($file) || $param['temp_file']) {
// 导入初始化 上传文件
if (!empty($file)) {
$save_name = $this->upload($file);
if ($save_name === false) {
$queue->dequeue();
return false;
}
} else {
$save_name = $param['temp_file'];
}
// 文件类型
$ext = pathinfo($save_name, PATHINFO_EXTENSION);
// 文件路径
$save_path = UPLOAD_PATH . $save_name;
// 队列-判断是否需要排队
if (!$queue->canExec()) {
$this->error = [
'temp_file' => $save_name,
'page' => -2,
'import_queue_index' => $import_queue_index,
'info' => $queue->error
];
return true;
}
// 加载类库
vendor("phpexcel.PHPExcel");
vendor("phpexcel.PHPExcel.Writer.Excel5");
vendor("phpexcel.PHPExcel.Writer.Excel2007");
vendor("phpexcel.PHPExcel.IOFactory");
// 错误数据临时文件路径 错误数据开始行数
if ($param['error_file']) {
$error_path = TEMP_DIR . $param['error_file'];
$error_row = $param['error'] + 3;
$cover = $param['cover'] ?: 0;
} else {
// 生成临时文件名称
$error_path = tempFileName($ext);
// 将导入模板保存至临时路径
$controller->excelDownload($error_path);
$error_row = 3;
$cover = 0;
}
// 错误数据临时文件名称 相对于临时目录
$error_data_file_name = \substr($error_path, strlen(TEMP_DIR));
// 加载错误数据文件
$err_PHPExcel = \PHPExcel_IOFactory::load($error_path);
$error_sheet = $err_PHPExcel->setActiveSheetIndex(0);
/**
* 添加错误数据到临时文件
*
* @param array $data 原数据
* @param string $error 错误原因
* @return void
*/
$error_data_func = function ($data, $error) use ($error_sheet, &$error_row) {
foreach ($data as $key => $val) {
// 第一列为错误原因 所以+1
$error_col = \PHPExcel_Cell::stringFromColumnIndex($key + 1);
$error_sheet->setCellValue($error_col . $error_row, $val);
}
$error_sheet->setCellValue('A' . $error_row, $error);
$error_sheet->getStyle('A' . $error_row)->getFont()->getColor()->setARGB('FF000000');
$error_sheet->getStyle('A' . $error_row)->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('FFFF0000');
$error_row++;
};
// 字段列表条件
$fieldParam = [];
// 导入模块
switch ($types) {
case 'crm_leads' :
$dataModel = new \app\crm\model\Leads();
$db = 'crm_leads';
$db_id = 'leads_id';
break;
case 'crm_customer' :
$dataModel = new \app\crm\model\Customer();
$db = 'crm_customer';
$db_id = 'customer_id';
$fieldParam['form_type'] = ['not in', ['file', 'form', 'user', 'structure']];
break;
case 'crm_contacts' :
$dataModel = new \app\crm\model\Contacts();
$db = 'crm_contacts';
$db_id = 'contacts_id';
break;
case 'crm_product' :
$model = db('crm_product');
$dataModel = new \app\crm\model\Product();
$db = 'crm_product';
$db_id = 'product_id';
// 产品分类
$productCategoryArr = db('crm_product_category')->field('category_id', 'name')->select();
break;
case 'admin_user' :
$dataModel = new User();
$db_id = 'id';
break;
}
// 字段
$fieldModel = new \app\admin\model\Field();
$fieldParam['types'] = $types;
$fieldParam['action'] = 'excel';
$field_list = $fieldModel->field($fieldParam);
$field_list = array_map(function ($val) {
if (method_exists($val, 'toArray')) {
return $val->toArray();
} else {
return $val;
}
}, $field_list);
$field_key_name_list = array_column($field_list, 'name', 'field');
// 加载导入数据文件
$objRender = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xls');
$objRender->setReadDataOnly(true);
$ExcelObj = $objRender->load($save_path);
// 指定工作表
$sheet = $ExcelObj->getSheet(0);
// 总行数
$max_row = $sheet->getHighestRow();
// 最大列数
$max_col_num = count($field_list) - 1;
// customer_address地址类字段 占4列
$max_col_num += 3 * array_count_values(array_column($field_list, 'form_type'))['map_address'];
$max_col = \PHPExcel_Cell::stringFromColumnIndex($max_col_num);
// 检测导入文件是否使用最新模板
$header = $sheet->rangeToArray("A2:{$max_col}2")[0];
$temp = 0;
for ($i = 0; $i < count($field_list); $i++) {
if (
$header[$i] == $field_list[$i]['name']
|| $header[$i] == '*' . $field_list[$i]['name']
) {
$temp++;
// 字段为地址时,占四列
} elseif ($field_list[$i]['form_type'] == 'map_address') {
if (
$header[$i] == $this->map_address[0]
&& $header[$i + 1] == $this->map_address[1]
&& $header[$i + 2] == $this->map_address[2]
&& $header[$i + 3] == $this->map_address[3]
) {
$temp++;
}
}
}
// 每次导入条数
$page_size = 100;
// 当前页码
$page = ((int)$param['page']) ?: 1;
// 数据总数
$total = $max_row - 2;
// 总页数
$max_page = ceil($total / $page_size);
if ($page > $max_page) {
// $this->error = 'page参数错误';
// @unlink($save_path);
// $queue->dequeue();
// return false;
}
// 开始行 +3 跳过表头
$start_row = ($page - 1) * $page_size + 3;
// 结束行
$end_row = $start_row + $page_size - 1;
if ($end_row > $max_row) {
$end_row = $max_row;
}
// 读取数据
$dataList = $sheet->rangeToArray("A{$start_row}:{$max_col}{$end_row}");
// 数据重复时的处理方式 0跳过 1覆盖
$config = $param['config'] ? : 0;
// 默认数据
$default_data = [
'create_user_id' => $param['create_user_id'],
'owner_user_id' => $param['owner_user_id'],
'create_time' => time(),
'update_time' => time(),
];
if ($temp !== count($field_list)) {
// $this->error = '请使用最新导入模板';
@unlink($save_path);
$queue->dequeue();
foreach ($dataList as $val) {
$error_data_func($val,'请使用最新导入模板');
}
// 错误数据文件保存
$objWriter = \PHPExcel_IOFactory::createWriter($err_PHPExcel, 'Excel5');
$objWriter->save($error_path);
$error = [
// 文件总计条数
'total' => $total,
// 已完成条数
'done' => 0,
// 覆盖
'cover' => 0,
// 错误数据写入行号
'error' => $total,
'error_file_path' =>'temp/' . $error_data_file_name
];
$queue->cache('last_import_cache', [
'total' => $total,
'done' => 0,
'cover' => 0,
'error' => $total
]);
(new ImportRecord())->createData([
'type' => $types,
'total' => $total,
'done' => 0,
'cover' => 0,
'error' => $total,
'user_id' => $user_id,
'error_data_file_path' =>'temp/' . $error_data_file_name
]);
Cache::rm('item');
Cache::rm('excel_item');
Cache::set('item', 1);
Cache::set('excel_item', serialize($error));
return true;
}else{
// 开始导入数据
foreach ($dataList as $val) {
$data = [];
$unique_where = [];
$empty_count = 0;
$not_null_field = [];
$fk = 0;
foreach ($field_list as $field) {
if ($field['form_type'] == 'map_address') {
$data['address'] = $address = [
trim((string)$val[$fk]),
trim((string)$val[$fk + 1]),
trim((string)$val[$fk + 2]),
];
$data['detail_address'] = trim($val[$fk + 3]);
$fk += 4;
continue;
} else {
$temp_value = trim($val[$fk]);
}
if ($field['field'] == 'category_id' && $types == 'crm_product') {
$data['category_id'] = $productCategoryArr[$temp_value] ? : 0;
$data['category_str'] = $dataModel->getPidStr($productCategoryArr[$temp_value], '', 1);
}
// 特殊字段特殊处理
$temp_value = $this->handleData($temp_value, $field);
$data[$field['field']] = $temp_value;
// 查重字段
if ($field['is_unique'] && $temp_value) {
$unique_where[$field['field']] = $temp_value;
}
if ($temp_value == '') {
if ($field['is_null']) {
$not_null_field[] = $field['name'];
}
$empty_count++;
}
$fk++;
}
if (!empty($not_null_field)) {
$error_data_func($val, implode(', ', $not_null_field) . '不能为空');
continue;
}
if ($empty_count == count($field_list)) {
$error_data_func($val, '空行');
continue;
}
$old_data_id_list = [];
if ($unique_where) {
if($types == 'crm_product'){
$old_data_id_list = $model->whereOr($unique_where)->where('delete_user_id',0)->column($db_id);
}else{
$old_data_id_list = $dataModel->whereOr($unique_where)->column($db_id);
}
}
// 数据重复时
if ($old_data_id_list) {
// 是否覆盖
if ($config) {
$data = array_merge($data, $default_data);
$data['user_id'] = $param['create_user_id'];
$data['update_time'] = time();
$data['update_time'] = time();
if(isset($data['next_time'])){
$data['next_time']=$data['next_time']?date('Y-m-d H:i:s', $data['next_time']):'';
}
$dataModel->startTrans();
try {
$up_success_count = 0;
foreach ($old_data_id_list as $id) {
if($types=='crm_customer'){
$owner = db('crm_customer')->where(['name' => $data['name']])->find();
if (!empty($owner) && $owner['owner_user_id'] == 0) {
$temp_error = $owner['name'] .' '. '公海数据,无覆盖权限';
$error_data_func($val, $temp_error);
break;
}
}
if (!$dataModel->updateDataById($data, $id)) {
$temp_error = $dataModel->getError();
if ($temp_error == '无权操作') {
$temp_error = '当前导入人员对该数据无写入权限';
}
$error_data_func($val, $temp_error);
$dataModel->rollback();
break;
}
$up_success_count++;
}
// 全部更新完成
if ($up_success_count === count($old_data_id_list)) {
$cover++;
$dataModel->commit();
}
} catch (\Exception $e) {
$dataModel->rollback();
}
} else {
// 重复字段标记
$unique_field = [];
foreach ($old_data_id_list as $id) {
$old_data = $dataModel->getDataById($id);
foreach ($unique_where as $k => $v) {
if (trim($old_data[$k]) == $v) {
$unique_field[] = $field_key_name_list[$k];
}
}
}
$unique_field = array_unique($unique_field);
$error_data_func($val, implode(', ', $unique_field) . ' 根据查重规则,该条数据重复');
}
} else {
$data = array_merge($data, $default_data);
if(isset($data['next_time'])){
$data['next_time']=$data['next_time']?date('Y-m-d H:i:s', $data['next_time']):'';
}
if (!$resData = $dataModel->createData($data)) {
$error_data_func($val, $dataModel->getError());
}
}
}
// 完成数(已导入数)
$done = ($page - 1) * $page_size + count($dataList);
if ($page == $max_page) {
$done = $total;
}
// 错误数
$error = $error_row - 3;
// 错误数据文件保存
$objWriter = \PHPExcel_IOFactory::createWriter($err_PHPExcel, 'Excel5');
$objWriter->save($error_path);
$this->error = [
// 数据导入文件临时路径
'temp_file' => $save_name,
// 错误数据文件路径
'error_file' => $error_data_file_name,
// 文件总计条数
'total' => $total,
// 已完成条数
'done' => $done,
// 覆盖
'cover' => $cover,
// 错误数据写入行号
'error' => $error,
// 下次页码
'page' => $page + 1,
// 导入任务ID
'import_queue_index' => $import_queue_index
];
$queue->cache('last_import_cache', [
'total' => $total,
'done' => $done,
'cover' => $cover,
'error' => $error
]);
// 执行完成
if ($done >= $total) {
// 出队
$queue->dequeue();
// 错误数据文件路径
$this->error['error_file_path'] = 'temp/' . $error_data_file_name;
// 删除导入文件
@unlink($save_path);
// 没有错误数据时,删除错误文件
if ($error == 0) {
@unlink($error_path);
}
(new ImportRecord())->createData([
'type' => $types,
'total' => $total,
'done' => $done,
'cover' => $cover,
'error' => $error,
'user_id' => $user_id,
'error_data_file_path' => $error ? 'temp/' . $error_data_file_name : ''
]);
Cache::set('item', 1);
Cache::set('excel_item', serialize($this->error));
}else{
$excelData['cover']=$cover;
$excelData['page']=$page+1;
$excelData['types']=$types;
$excelData['temp_file']=$save_name;
$excelData['error_file']=$error_data_file_name;
$excelData['create_user_id']=$param['create_user_id'];
$excelData['import_queue_index']=$import_queue_index;
$excelData['config']=$config;
$excelData['owner_user_id']=$user_id;
$excelData['base']='batchImportData';
Cache::set('item', 0);
Cache::set('excel', $excelData);
}
return true;
}
} else {
$this->error = '请选择导入文件';
$queue->dequeue();
return false;
}
}
/**
* 导入数据时 读取xls表格数据
*
* @param PHPExcel_Worksheet $sheet
* @param integer $start 开始行
* @param integer $end 结束行 0时表示所有
* @param array $fields 字段名称
* @return array
* @author Ymob
*/
public function readSheet($sheet, $start = 1, $end = 0, $fields = [])
{
$data = [];
for ($row = $start; $row <= $end; $row++) {
$temp = [];
foreach ($fields as $key => $field) {
$col = Coordinate::stringFromColumnIndex($key);
$temp[$field] = $sheet->getCell($col . $row);
}
$data[] = $temp;
}
return $data;
}
/**
* 上传文件导入数据文件
*
* @param [type] $file
* @return mixed 上传文件路径 | 上传失败错误信息
* @author Ymob
*/
public function upload($file)
{
$get_filesize_byte = get_upload_max_filesize_byte();
$info = $file->validate(['size' => $get_filesize_byte, 'ext' => 'xls'])->move(FILE_PATH . 'public' . DS . 'uploads'); //验证规则
if (!$info) {
$this->error = $file->getError();
return false;
}
$saveName = $info->getSaveName(); //保存路径
if (!$saveName) {
$this->error = '文件上传失败,请重试!';
return false;
}
return $saveName;
}
/**
* 自定义字段模块数据导入(默认2000行)
* @param $types 分类
* @param $file 导入文件
* @param $create_user_id 创建人ID
* @param $owner_user_id 负责人ID
* @return todo 导入记录
* @author Michael_xu
*/
public function importExcel($file, $param, $controller = null)
{
$queue = new Queue(self::IMPORT_QUEUE, 1);
$import_queue_index = input('import_queue_index');
$user_id = $param['owner_user_id'];
if (!$import_queue_index) {
if (!$import_queue_index = $queue->makeTaskId()) {
$this->error = $queue->error;
$queue->dequeue();
return false;
}
} else {
if (!$queue->setTaskId($import_queue_index)) {
$this->error = $queue->error;
$queue->dequeue();
return false;
}
}
if ($param['page'] == -1) {
$queue->dequeue();
$this->error = [
'msg' => '导入已取消',
'page' => -1
];
if ($param['error']) {
$this->error['error_file_path'] = 'temp/' . $param['error_file'];
}
return true;
}
$config = $param['config'] ?: '';
if (!empty($file) || $param['temp_file']) {
$types = $param['types'];
if (!in_array($types, $this->types_arr)) {
$this->error = '参数错误!';
$queue->dequeue();
return false;
}
// 导入初始化 上传文件
if (!empty($file)) {
$get_filesize_byte = get_upload_max_filesize_byte();
$info = $file->validate(['size' => $get_filesize_byte, 'ext' => 'xls,xlsx,csv'])->move(UPLOAD_PATH); //验证规则
if (!$info) {
$this->error = $file->getError();
$queue->dequeue();
return false;
}
$save_name = $info->getSaveName(); //保存路径
if (!$save_name) {
$this->error = '文件上传失败,请重试!';
$queue->dequeue();
return false;
}
} else {
$save_name = $param['temp_file'];
}
$ext = pathinfo($save_name, PATHINFO_EXTENSION); //文件后缀
$save_path = UPLOAD_PATH . $save_name;
if (!$queue->canExec()) {
$this->error = [
'temp_file' => $save_name,
'page' => -2,
'import_queue_index' => $import_queue_index,
'info' => $queue->error
];
return true;
}
if ($param['error_file']) {
$error_path = TEMP_DIR . $param['error_file'];
$error_row = $param['error'] + 3;
} else {
$error_path = tempFileName($ext);
// 生成错误数据文件
$controller->excelDownload($error_path);
$error_row = 3;
}
vendor("phpexcel.PHPExcel");
vendor("phpexcel.PHPExcel.Writer.Excel5");
vendor("phpexcel.PHPExcel.Writer.Excel2007");
vendor("phpexcel.PHPExcel.IOFactory");
$err_PHPExcel = \PHPExcel_IOFactory::load($error_path);
$sheet = $err_PHPExcel->setActiveSheetIndex(0);
// 添加错误数据到临时文件
$error_data_func = function ($data, $error) use ($sheet, &$error_row) {
foreach ($data as $key => $val) {
// 第一列为错误原因 所以+1
$error_col = \PHPExcel_Cell::stringFromColumnIndex($key + 1);
$sheet->setCellValue($error_col . $error_row, $val);
}
$sheet->setCellValue('A' . $error_row, $error);
$sheet->getStyle('A' . $error_row)->getFont()->getColor()->setARGB('FF000000');
$sheet->getStyle('A' . $error_row)->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('FFFF0000');
$error_row++;
};
// 错误数据临时文件名称
$error_data_file_name = \substr($error_path, strlen(TEMP_DIR));
//实例化主文件
set_time_limit(1800);
ini_set("memory_limit", "256M");
$objPHPExcel = new Spreadsheet();
if ($ext == 'xlsx') {
$objRender = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
// $objRender->setReadDataOnly(true);
$ExcelObj = $objRender->load($save_path);
} elseif ($ext == 'xls') {
$objRender = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xls');
// $objRender->setReadDataOnly(true);
$ExcelObj = $objRender->load($save_path);
} elseif ($ext == 'csv') {
$objWriter = new \PhpOffice\PhpSpreadsheet\Reader\Csv($objPHPExcel);
//默认输入字符集
$objWriter->setInputEncoding('UTF-8');
//默认的分隔符
$objWriter->setDelimiter(',');
//载入文件
$ExcelObj = $objWriter->load($save_path);
}
$currentSheet = $ExcelObj->getSheet(0);
$data = $currentSheet->rangeToArray('A3:C12');
//查看有几个sheet
$sheetContent = $ExcelObj->getSheet(0)->toArray();
//获取总行数
$sheetCount = $ExcelObj->getSheet(0)->getHighestRow();
// if ($sheetCount > 2002) {
// $this->error = '单文件一次最多导入2000条数据';
// return false;
// }
//读取表头
$excelHeader = $sheetContent[1];
unset($sheetContent[0]);
unset($sheetContent[1]);
//取出文件的内容描述信息,循环取出数据,写入数据库
switch ($types) {
case 'crm_leads' :
$dataModel = new \app\crm\model\Leads();
$db = 'crm_leads';
$db_id = 'leads_id';
break;
case 'crm_customer' :
$dataModel = new \app\crm\model\Customer();
$db = 'crm_customer';
$db_id = 'customer_id';
$fieldParam['form_type'] = array('not in', ['file', 'form', 'user', 'structure']);
break;
case 'crm_contacts' :
$dataModel = new \app\crm\model\Contacts();
$db = 'crm_contacts';
$db_id = 'contacts_id';
break;
case 'crm_product' :
$dataModel = new \app\crm\model\Product();
$db = 'crm_product';
$db_id = 'product_id';
break;
}
$contactsModel = new \app\crm\model\Contacts();
//自定义字段
$fieldModel = new \app\admin\model\Field();
$fieldParam['types'] = $types;
$field_list = $fieldModel->getDataList($fieldParam);
$fieldArr = [];
$uniqueField = []; //验重字段
foreach ($field_list as $k => $v) {
$fieldArr[$v['name']]['field'] = $v['field'];
$fieldArr[$v['name']]['form_type'] = $v['form_type'];
if ($v['is_unique'] == 1) {
$uniqueField[] = $v['field'];
}
}
$field_num = count($field_list);
//客户导入联系人
if ($types == 'crm_customer') {
$contacts_field_list = $fieldModel->getDataList(['types' => 'crm_contacts', 'field' => array('neq', 'customer_id')]);
$contactsFieldArr = [];
foreach ($contacts_field_list as $k => $v) {
$contactsFieldArr[$v['name']]['field'] = $v['field'];
$contactsFieldArr[$v['name']]['form_type'] = $v['form_type'];
}
}
$defaultData = []; //默认数据
$defaultData['create_user_id'] = $param['create_user_id'];
$defaultData['owner_user_id'] = $param['owner_user_id'];
$defaultData['create_time'] = time();
$defaultData['update_time'] = time();
//产品类别
if ($types == 'crm_product') {
$productCategory = db('crm_product_category')->select();
$productCategoryArr = [];
foreach ($productCategory as $v) {
$productCategoryArr[$v['name']] = $v['category_id'];
}
}
// 表头行数
$keys = 2;
// 导入错误数据
$errorMessage = [];
// 每次导入条数
$forCount = 5;
// 当前页码
$page = $param['page'] ?: 1;
// 数据总数
$total = $sheetCount - $keys;
// 总页数
$max_page = ceil($total / $forCount);
if ($page > $max_page) {
$this->error = 'page参数错误';
$queue->dequeue();
return false;
}
$_sub = array_slice($sheetContent, ($page - 1) * $forCount, $forCount);
foreach ($_sub as $kk => $val) {
$data = '';
$contactsData = '';
$k = 0;
$contacts_k = $field_num;
$resNameIds = '';
$keys++;
$name = ''; //客户、线索、联系人等名称
$contactsName = '';
$data = $defaultData; //导入数据
$contacts_data = $defaultData; //导入数据
$resWhere = ''; //验重条件
$resWhereNum = 0; //验重数
$resContacts = false; //联系人是否有数据
$resInfo = false; //Excel列是否有数据
$resData = [];
$resContactsData = [];
$row_error = false;
foreach ($excelHeader as $aa => $header) {
if (empty($header)) break;
$fieldName = trim(str_replace('*', '', $header));
$info = '';
$info = trim($val[$k]);
if ($info) $resInfo = true;
if ($types == 'crm_product' && $fieldName == '产品类别') {
$data['category_id'] = $productCategoryArr[$info] ?: 0;
$data['category_str'] = $dataModel->getPidStr($productCategoryArr[$info], '', 1);
}
//联系人
if ($types == 'crm_contacts' && $fieldName == '客户名称') {
if (!$info) {
$error_data_func($val, '客户名称必填'); // 错误数据导出
$errorMessage[] = '第' . $keys . '行导入错误,失败原因:客户名称必填';
$row_error = true;
continue;
}
$customer_id = '';
$customer_id = db('crm_customer')->where(['name' => $info])->value('customer_id');
if (!$customer_id) {
$error_data_func($val, '客户名称不存在'); // 错误数据导出
$errorMessage[] = '第' . $keys . '行导入错误,失败原因:客户名称不存在';
$row_error = true;
continue;
}
$data['customer_id'] = $customer_id;
}
if ($aa < $field_num) {
if (empty($fieldArr[$fieldName]['field'])) continue;
// if ($fieldArr[$fieldName]['field'] == 'name') $name = $info;
if (in_array($fieldArr[$fieldName]['field'], $uniqueField) && $info) {
if ($resWhereNum > 0) $resWhere .= " OR ";
$resWhere .= " `" . $fieldArr[$fieldName]['field'] . "` = '" . $info . "'";
$resWhereNum += 1;
}
$resList = [];
$resList = $this->sheetData($k, $fieldArr, $fieldName, $info);
$resData[] = $resList['data'];
$k = $resList['k'];
} else {
//联系人
if ($types == 'crm_customer' && $aa == (int)$contacts_k) {
$contactsInfo = '';
$contactsInfo = $val[$contacts_k];
if ($contactsInfo) {
$resContacts = true;
}
// if ($contactsFieldArr[$fieldName]['field'] == 'name') $contactsName = $contactsInfo;
$resContactsList = [];
$resContactsList = $this->sheetData($contacts_k, $contactsFieldArr, $fieldName, $contactsInfo);
$resContactsData[] = $resContactsList['data'];
$contacts_k = $resContactsList['k'];
}
}
}
if ($row_error) {
continue;
}
$result = $this->changeArr($resData); //二维数组转一维数组
$data = $result ? array_merge($data, $result) : [];
if ($types == 'crm_customer' && $result) {
$resultContacts = $this->changeArr($resContactsData);
$contactsData = $resultContacts ? array_merge($contacts_data, $resultContacts) : []; //联系人
}
$resWhere = $resWhere ?: '';
// $ownerWhere['owner_user_id'] = $param['owner_user_id'];
if ($uniqueField && $resWhere) {
$resNameIds = db($db)->where($resWhere)->where($ownerWhere)->column($db_id);
}
if ($resInfo == false) {
continue;
}
if ($resNameIds && $data) {
if ($config == 1 && $resNameIds) {
$data['user_id'] = $param['create_user_id'];
$data['update_time'] = time();
//覆盖数据(以名称为查重规则,如存在则覆盖原数据)
foreach ($resNameIds as $nid) {
$upRes = $dataModel->updateDataById($data, $nid);
if (!$upRes) {
$error_data_func($val, $dataModel->getError()); // 错误数据导出
$errorMessage[] = '第' . $keys . '行导入错误,失败原因:' . $dataModel->getError();
continue;
}
if ($types == 'crm_customer' && $resContacts !== false) {
$contactsData['customer_id'] = $upRes['customer_id'];
if (!$contactsData['owner_user_id']) $contactsData['owner_user_id'] = $param['create_user_id'];
if (!$resData = $contactsModel->createData($contactsData)) {
$error_data_func($val, $contactsModel->getError()); // 错误数据导出
$errorMessage[] = '第' . $keys . '行导入错误,失败原因:' . $contactsModel->getError();
continue;
}
}
}
} else {
$error_data_func($val, '跳过');
}
} else {
if (!$resData = $dataModel->createData($data)) {
$error_data_func($val, $dataModel->getError()); // 错误数据导出
$errorMessage[] = '第' . $keys . '行导入错误,失败原因:' . $dataModel->getError();
continue;
}
if ($types == 'crm_customer' && $resContacts !== false) {
$contactsData['customer_id'] = $resData['customer_id'];
if (!$contactsData['owner_user_id']) $contactsData['owner_user_id'] = $param['create_user_id'];
if (!$resData = $contactsModel->createData($contactsData)) {
$error_data_func($val, $contactsModel->getError()); // 错误数据导出
$errorMessage[] = '第' . $keys . '行导入错误,失败原因:' . $contactsModel->getError();
continue;
}
}
}
}
// 完成数
$done = ($page - 1) * $forCount + count($_sub);
// 错误数
$error = $error_row - 3;
// 错误数据暂存
$objWriter = \PHPExcel_IOFactory::createWriter($err_PHPExcel, 'Excel5');
$objWriter->save($error_path);
$this->error = [
'temp_file' => $save_name,
'error_file' => $error_data_file_name,
// 每行错误信息提示
// 'error' => $errorMessage,
// 文件总计条数
'total' => $total,
// 已完成条数
'done' => $done,
// 错误数据写入行号
'error' => $error,
// 下次页码
'page' => $page + 1,
'import_queue_index' => $import_queue_index
];
// 执行完成
if ($done >= $total) {
$queue->dequeue();
$this->error['error_file_path'] = 'temp/' . $error_data_file_name;
Cache::set('item', 1);
Cache::set('excel_item', serialize($this->error));
} else {
$excelData['page']=$page+1;
$excelData['types']=$types;
$excelData['temp_file']=$save_name;
$excelData['error_file']=$error_data_file_name;
$excelData['create_user_id']=$param['create_user_id'];
$excelData['import_queue_index']=$import_queue_index;
$excelData['config']=$config;
$excelData['owner_user_id']=$user_id;
$excelData['base']='importExcel';
Cache::set('item', 0);
Cache::set('excel', $excelData);
}
return true;
} else {
$this->error = '请选择导入文件';
$queue->dequeue();
return false;
}
}
/**
* excel数据处理
* @param $k 需处理数据开始下标
* @return
* @author Michael_xu
*/
public function sheetData($k = 0, $fieldArr, $fieldName, $info)
{
if ($info) {
if ($fieldArr[$fieldName]['form_type'] == 'address') {
$address = array();
for ($i = 0; $i < 4; $i++) {
$address[] = $val[$k];
$k++;
}
$data[$fieldArr[$fieldName]['field']] = implode(chr(10), $address);
// 地址信息转地理坐标(仅处理系统初始的地址字段)
if ($fieldArr[$fieldName]['field'] == 'address') {
$address_arr = $address;
if ($address_arr['3']) {
$address_str = implode('', $address_arr);
$ret = get_lng_lat($address_str);
$data['lng'] = $ret['lng'] ?: 0;
$data['lat'] = $ret['lat'] ?: 0;
}
}
} elseif ($fieldArr[$fieldName]['form_type'] == 'date') {
$data[$fieldArr[$fieldName]['field']] = $info ? date('Y-m-d', strtotime($info)) : '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'datetime') {
$data[$fieldArr[$fieldName]['field']] = $info ? strtotime($info) : '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'customer') {
$data[$fieldArr[$fieldName]['field']] = db('crm_customer')->where(['name' => $info])->value('customer_id') ?: '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'contacts') {
$data[$fieldArr[$fieldName]['field']] = db('crm_contacts')->where(['name' => $info])->value('contacts_id') ?: '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'business') {
$data[$fieldArr[$fieldName]['field']] = db('crm_business')->where(['name' => $info])->value('business_id') ?: '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'category') {
$data[$fieldArr[$fieldName]['field']] = db('crm_product_category')->where(['name' => $info])->value('category_id') ?: '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'business_type') {
$data[$fieldArr[$fieldName]['field']] = db('crm_business_type')->where(['name' => $info])->value('type_id') ?: '';
$k++;
} elseif ($fieldArr[$fieldName]['form_type'] == 'business_status') {
$data[$fieldArr[$fieldName]['field']] = db('crm_business_status')->where(['name' => $info])->value('status_id') ?: '';
$k++;
} else {
$data[$fieldArr[$fieldName]['field']] = $info ?: '';
$k++;
}
} else {
$data[$fieldArr[$fieldName]['field']] = '';
$k++;
}
$res['data'] = $data;
$res['k'] = $k;
return $res;
}
/**
* 导入数据处理
*
* @param string $value
* @param array $field
* @return string
* @author Ymob
*/
public function handleData($value, $field)
{
switch ($field['form_type']) {
case 'address':
return $value;
case 'date':
return $value ? date('Y-m-d', strtotime($value)) : null;
case 'datetime':
return strtotime($value) ?: 0;
case 'customer':
case 'contacts':
case 'business':
$temp = db('crm_' . $field['form_type'])
->where(['name' => $value])
->value($field['form_type'] . '_id');
return $temp ?: 0;
case 'business_type':
$temp = db('crm_business_type')
->where(['name' => $value])
->value('type_id');
return $temp ?: 0;
case 'business_status':
$temp = db('crm_business_status')
->where(['name' => $value])
->value('status_id');
return $temp ?: 0;
default:
return $value;
}
}
//二维数组转一维数组
public function changeArr($arr)
{
$newArr = [];
foreach ($arr as $v) {
if ($v && is_array($v)) {
$newArr = array_merge($newArr, $v);
} else {
continue;
}
}
return $newArr;
}
/**
* excel参数配置备份
* @param
* @return
* @author Michael_xu
*/
public function config()
{
vendor("PHPExcel.PHPExcel.PHPExcel");
vendor("PHPExcel.PHPExcel.Writer.Excel5");
vendor("PHPExcel.PHPExcel.Writer.Excel2007");
vendor("PHPExcel.PHPExcel.IOFactory");
//实例化
$objPHPExcel = new \PHPExcel();
$objWriter = new \PHPExcel_Writer_Excel5($objPHPExcel);
$objWriter = new \PHPExcel_Writer_Excel2007($objPHPExcel);
$objProps = $objPHPExcel->getProperties(); // 设置excel文档的属性
$objProps->setCreator("snowerp"); //创建人
$objProps->setLastModifiedBy("snowerp"); //最后修改人
$objProps->setTitle("snowerp"); //标题
$objProps->setSubject("snowerp"); //题目
$objProps->setDescription("snowerp"); //描述
$objProps->setKeywords("snowerp"); //关键字
$objProps->setCategory("snowerp"); //种类
$objPHPExcel->setActiveSheetIndex(0); //设置当前的sheet
$objActSheet = $objPHPExcel->getActiveSheet();
$objActSheet->setTitle('snowerp'); //设置sheet的标题
$objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(20); //设置单元格宽度
$objPHPExcel->getActiveSheet()->getRowDimension($i)->setRowHeight(40); //设置单元格高度
$objPHPExcel->getActiveSheet()->mergeCells('A18:E22'); //合并单元格
$objPHPExcel->getActiveSheet()->unmergeCells('A28:B28'); //拆分单元格
//设置保护cell,保护工作表
$objPHPExcel->getActiveSheet()->getProtection()->setSheet(true);
$objPHPExcel->getActiveSheet()->protectCells('A3:E13', 'PHPExcel');
//设置格式
$objPHPExcel->getActiveSheet()->getStyle('E4')->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE);
$objPHPExcel->getActiveSheet()->duplicateStyle($objPHPExcel->getActiveSheet()->getStyle('E4'), 'E5:E13');
//设置加粗
$objPHPExcel->getActiveSheet()->getStyle('B1')->getFont()->setBold(true);
//设置水平对齐方式HORIZONTAL_RIGHTHORIZONTAL_LEFTHORIZONTAL_CENTERHORIZONTAL_JUSTIFY
$objPHPExcel->getActiveSheet()->getStyle('D11')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_RIGHT);
//设置垂直居中
$objPHPExcel->getActiveSheet()->getStyle('A18')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
//设置字号
$objPHPExcel->getActiveSheet()->getDefaultStyle()->getFont()->setSize(10);
//设置边框
$objPHPExcel->getActiveSheet()->getStyle('A1:I20')->getBorders()->getAllBorders()->setBorderStyle(\PHPExcel_Style_Border::BORDER_THIN);
//设置边框颜色
$objPHPExcel->getActiveSheet()->getStyle('D13')->getBorders()->getLeft()->getColor()->setARGB('FF993300');
$objPHPExcel->getActiveSheet()->getStyle('D13')->getBorders()->getTop()->getColor()->setARGB('FF993300');
$objPHPExcel->getActiveSheet()->getStyle('D13')->getBorders()->getBottom()->getColor()->setARGB('FF993300');
$objPHPExcel->getActiveSheet()->getStyle('E13')->getBorders()->getTop()->getColor()->setARGB('FF993300');
$objPHPExcel->getActiveSheet()->getStyle('E13')->getBorders()->getBottom()->getColor()->setARGB('FF993300');
$objPHPExcel->getActiveSheet()->getStyle('E13')->getBorders()->getRight()->getColor()->setARGB('FF993300');
//插入图像
$objDrawing = new PHPExcel_Worksheet_Drawing();
/*设置图片路径 切记:只能是本地图片*/
$objDrawing->setPath('图像地址');
/*设置图片高度*/
$objDrawing->setHeight(180);//照片高度
$objDrawing->setWidth(150); //照片宽度
/*设置图片要插入的单元格*/
$objDrawing->setCoordinates('E2');
/*设置图片所在单元格的格式*/
$objDrawing->setOffsetX(5);
$objDrawing->setRotation(5);
$objDrawing->getShadow()->setVisible(true);
$objDrawing->getShadow()->setDirection(50);
$objDrawing->setWorksheet($objPHPExcel->getActiveSheet());
//设置单元格背景色
$objPHPExcel->getActiveSheet(0)->getStyle('A1')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID);
$objPHPExcel->getActiveSheet(0)->getStyle('A1')->getFill()->getStartColor()->setARGB('FFCAE8EA');
//输入浏览器导出Excel
$savename = '导出Excel示例';
$ua = $_SERVER["HTTP_USER_AGENT"];
$datetime = date('Y-m-d', time());
if (preg_match("/MSIE/", $ua)) {
$savename = urlencode($savename); //处理IE导出名称乱码
}
// excel头参数
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $savename . '.xls"'); //日期为文件名后缀
header('Cache-Control: max-age=0');
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5'); //excel5为xls格式excel2007为xlsx格式
$objWriter->save('php://output');
}
/**
* 非自定义字段模块导出csv
* @param $file_name 导出文件名称
* @param $field_list 导出字段列表
* @param $callback 回调函数,查询需要导出的数据
* @author
**/
public function dataExportCsv($file_name, $field_list, $callback)
{
ini_set('memory_limit', '128M');
set_time_limit(0);
//调试时先把下面这个两个header注释即可
header("Access-Control-Expose-Headers: Content-Disposition");
header("Content-type:application/vnd.ms-excel;charset=UTF-8");
header("Content-Disposition:attachment;filename=" . $file_name . ".csv");
header('Expires: 0');
header('Cache-control: private');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Description: File Transfer');
header('Content-Encoding: UTF-8');
// 加上bom头防止用office打开时乱码
echo "\xEF\xBB\xBF"; // UTF-8 BOM
// 打开PHP文件句柄php://output 表示直接输出到浏览器
$fp = fopen('php://output', 'a');
// 将中文标题转换编码,否则乱码
foreach ($field_list as $i => $v) {
$title_cell[$i] = $v['name'];
}
// 将标题名称通过fputcsv写到文件句柄
fputcsv($fp, $title_cell);
// $export_data = $callback(0);
foreach ($callback as $item) {
$rows = [];
foreach ($field_list as $rule) {
$rows[] = $item[$rule['field']];
}
fputcsv($fp, $rows);
}
// 将已经写到csv中的数据存储变量销毁释放内存占用
ob_flush();
flush();
fclose($fp);
exit();
}
/**
* 分批导入文件 项目任务导入
*
* @param null|array|\think\File $file
* @param array $param
* @param Controller $controller
* @return bool
*
* @author Ymob
*/
public function batchTaskImportData($file, $param, $controller = null)
{
// 导入模块
$types = $param['types'];
if (!in_array($types, $this->types_arr)) {
$this->error = '参数错误!';
$queue->dequeue();
return false;
}
$user_id = $param['owner_user_id'];
// 采用伪队列 允许三人同时导入数据
$queue = new Queue(self::IMPORT_QUEUE, 3);
$import_queue_index = input('import_queue_index');
// 队列任务ID
if (!$import_queue_index) {
if (!$import_queue_index = $queue->makeTaskId()) {
$this->error = $queue->error;
$queue->dequeue();
return false;
}
} else {
if (!$queue->setTaskId($import_queue_index)) {
$this->error = $queue->error;
$queue->dequeue();
return false;
}
}
// 取消导入
if ($param['page'] == -1) {
@unlink(UPLOAD_PATH . $param['temp_file']);
$this->error = [
'msg' => '导入已取消',
'page' => -1
];
if ($param['error']) {
$this->error['error_file_path'] = 'temp/' . $param['error_file'];
} else {
@unlink(TEMP_DIR . $param['error_file']);
}
$temp = $queue->cache('last_import_cache');
(new ImportRecord())->createData([
'type' => $types,
'total' => $temp['total'],
'done' => $temp['done'],
'cover' => $temp['cover'],
'error' => $temp['error'],
'user_id' => $user_id,
'error_data_file_path' => $temp['error'] ? 'temp/' . $error_data_file_name : ''
]);
$queue->dequeue();
return true;
}
if (!empty($file) || $param['temp_file']) {
// 导入初始化 上传文件
if (!empty($file)) {
$save_name = $this->upload($file);
if ($save_name === false) {
$queue->dequeue();
return false;
}
} else {
$save_name = $param['temp_file'];
}
// 文件类型
$ext = pathinfo($save_name, PATHINFO_EXTENSION);
// 文件路径
$save_path = UPLOAD_PATH . $save_name;
// 队列-判断是否需要排队
if (!$queue->canExec()) {
$this->error = [
'temp_file' => $save_name,
'page' => -2,
'import_queue_index' => $import_queue_index,
'info' => $queue->error
];
return true;
}
// 加载类库
vendor("phpexcel.PHPExcel");
vendor("phpexcel.PHPExcel.Writer.Excel5");
vendor("phpexcel.PHPExcel.Writer.Excel2007");
vendor("phpexcel.PHPExcel.IOFactory");
// 错误数据临时文件路径 错误数据开始行数
if ($param['error_file']) {
$error_path = TEMP_DIR . $param['error_file'];
$error_row = $param['error'] + 3;
$cover = $param['cover'] ?: 0;
} else {
// 生成临时文件名称
$error_path = tempFileName($ext);
// 将导入模板保存至临时路径
$controller->excelDownload($error_path);
$error_row = 3;
$cover = 0;
}
// 错误数据临时文件名称 相对于临时目录
$error_data_file_name = \substr($error_path, strlen(TEMP_DIR));
// 加载错误数据文件
$err_PHPExcel = \PHPExcel_IOFactory::load($error_path);
$error_sheet = $err_PHPExcel->setActiveSheetIndex(0);
/**
* 添加错误数据到临时文件
*
* @param array $data 原数据
* @param string $error 错误原因
* @return void
*/
$error_data_func = function ($data, $error) use ($error_sheet, &$error_row) {
foreach ($data as $key => $val) {
// 第一列为错误原因 所以+1
$error_col = \PHPExcel_Cell::stringFromColumnIndex($key + 1);
$error_sheet->setCellValue($error_col . $error_row, $val);
}
$error_sheet->setCellValue('A' . $error_row, $error);
$error_sheet->getStyle('A' . $error_row)->getFont()->getColor()->setARGB('FF000000');
$error_sheet->getStyle('A' . $error_row)->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('FFFF0000');
$error_row++;
};
$field_list = [
'0' => ['name' => '任务名称', 'field' => 'name'],
'1' => ['name' => '任务描述', 'field' => 'description'],
'2' => ['name' => '开始时间', 'field' => 'start_time'],
'3' => ['name' => '结束时间', 'field' => 'stop_time'],
'4' => ['name' => '负责人', 'field' => 'create_user_id'],
'5' => ['name' => '参与人', 'field' => 'owner_user_id'],
'6' => ['name' => '所属任务列表', 'field' => 'class_id'],
];
$field_key_name_list = array_column($field_list, 'name');
// 加载导入数据文件
$objRender = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xls');
$objRender->setReadDataOnly(true);
$ExcelObj = $objRender->load($save_path);
// 指定工作表
$sheet = $ExcelObj->getSheet(0);
// 总行数
$max_row = $sheet->getHighestRow();
// 最大列数
$max_col_num = count($field_list) - 1;
$max_col_num += 3 * array_count_values(array_column($field_list, 'form_type'))['map_address'];
$max_col = \PHPExcel_Cell::stringFromColumnIndex($max_col_num);
// 检测导入文件是否使用最新模板
$header = $sheet->rangeToArray("A2:{$max_col}2")[0];
$temp = 0;
for ($i = 0; $i < count($field_list); $i++) {
if (
$header[$i] == $field_list[$i]['name']
|| $header[$i] == $field_list[$i]['name'] . '(*)'
) {
$temp++;
// 字段为地址时,占四列
} elseif ($field_list[$i]['form_type'] == 'map_address') {
if (
$header[$i] == $this->map_address[0]
&& $header[$i + 1] == $this->map_address[1]
&& $header[$i + 2] == $this->map_address[2]
&& $header[$i + 3] == $this->map_address[3]
) {
$temp++;
}
}
}
if ($temp !== count($field_list)) {
$this->error = '请使用最新导入模板';
@unlink($save_path);
$queue->dequeue();
return false;
}
// 每次导入条数
$page_size = 100;
// 当前页码
$page = ((int)$param['page']) ?: 1;
// 数据总数
$total = $max_row - 2;
// 总页数
$max_page = ceil($total / $page_size);
if ($page > $max_page) {
// $this->error = 'page参数错误';
// @unlink($save_path);
// $queue->dequeue();
// return false;
}
// 开始行 +3 跳过表头
$start_row = ($page - 1) * $page_size + 3;
// 结束行
$end_row = $start_row + $page_size - 1;
if ($end_row > $max_row) {
$end_row = $max_row;
}
// 读取数据
$dataList = $sheet->rangeToArray("A{$start_row}:{$max_col}{$end_row}");
// 默认数据
$default_data = [
'main_user_id' => $param['create_user_id'],
'create_user_id' => $param['create_user_id'],
'create_time' => time(),
'update_time' => time(),
];
// 开始导入数据
foreach ($dataList as $val) {
$data = [];
$fk = 0;
$classData = db('work_task_class')->where(['name' => $val[6], 'work_id' => $param['work_id']])->order('class_id', 'asc')->select();
$max_order_id = db('work_task_class')->where(['work_id' => $param['work_id'], 'status' => 1])->max('order_id');
if ($classData[0]['class_id'] != '') {
$data['class_id'] = $classData[0]['class_id'];
} else {
$item = [
'name' => $val[6],
'create_time' => time(),
'create_user_id' => $param['create_user_id'],
'order_id' => $max_order_id ? $max_order_id + 1 : 0,
'status' => 1,
'work_id' => $param['work_id'],
];
$data['class_id'] = db('work_task_class')->insertGetId($item);
}
$dataModel = new \app\work\model\Task();
foreach ($field_list as $field) {
$temp_value = trim($val[$fk]);
// 特殊字段特殊处理
$temp_value = $this->handleData($temp_value, $field);
$data[$field['field']] = $temp_value;
$fk++;
}
// 数据重复时
$data = array_merge($data, $default_data);
if (!$resData = $dataModel->createTask($data)) {
$error_data_func($val, $dataModel->getError());
}
}
// 完成数(已导入数)
$done = ($page - 1) * $page_size + count($dataList);
if ($page == $max_page) {
$done = $total;
}
// 错误数
$error = $error_row - 3;
// 错误数据文件保存
$objWriter = \PHPExcel_IOFactory::createWriter($err_PHPExcel, 'Excel5');
$objWriter->save($error_path);
$this->error = [
// 数据导入文件临时路径
'temp_file' => $save_name,
// 错误数据文件路径
'error_file' => $error_data_file_name,
// 文件总计条数
'total' => $total,
// 已完成条数
'done' => $done,
// 覆盖
'cover' => $cover,
// 错误数据写入行号
'error' => $error,
// 下次页码
'page' => $page + 1,
// 导入任务ID
'import_queue_index' => $import_queue_index
];
$queue->cache('last_import_cache', [
'total' => $total,
'done' => $done,
'cover' => $cover,
'error' => $error
]);
// 执行完成
if ($done >= $total) {
// 出队
$queue->dequeue();
// 错误数据文件路径
$this->error['error_file_path'] = 'temp/' . $error_data_file_name;
// 删除导入文件
@unlink($save_path);
// 没有错误数据时,删除错误文件
if ($error == 0) {
@unlink($error_path);
}
(new ImportRecord())->createData([
'type' => $types,
'total' => $total,
'done' => $done,
'cover' => $cover,
'error' => $error,
'user_id' => $user_id,
'error_data_file_path' => $error ? 'temp/' . $error_data_file_name : ''
]);
Cache::set('item', 1);
Cache::set('excel_item', serialize($this->error));
} else {
$excelData['cover']=$cover;
$excelData['page']=$page+1;
$excelData['types']=$types;
$excelData['temp_file']=$save_name;
$excelData['error_file']=$error_data_file_name;
$excelData['create_user_id']=$param['create_user_id'];
$excelData['import_queue_index']=$import_queue_index;
$excelData['owner_user_id']=$user_id;
$excelData['base']='batchTaskImportData';
Cache::set('item', 0);
Cache::set('excel', $excelData);
}
return true;
} else {
$this->error = '请选择导入文件';
$queue->dequeue();
return false;
}
}
/**
* task模块导出csv
* @param $title 导出文件头
* @param $file_name 导出文件名称
* @param $field_list 导出字段列表
* @param $callback 回调函数,查询需要导出的数据
* @author
**/
public function taskExportCsv($file_name, $field_list, $title, $callback)
{
ini_set('memory_limit', '128M');
set_time_limit(0);
vendor("PHPExcel.PHPExcel.PHPExcel");
vendor("PHPExcel.PHPExcel.Writer.Excel5");
vendor("PHPExcel.PHPExcel.Writer.Excel2007");
vendor("PHPExcel.PHPExcel.IOFactory");
//实例化
$objPHPExcel = new \PHPExcel();
//定义配置
$topNumber = 2;//表头有几行占用
$xlsTitle = iconv('utf-8', 'gb2312', $title);//文件名称
$cellKey = array(
'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',
'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM',
'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'
);
//处理表头标题
$objActSheet = $objPHPExcel->getActiveSheet(0);
$objPHPExcel->getActiveSheet()->mergeCells('A1:' . $cellKey[count($field_list) - 1] . '1');//合并单元格(如果要拆分单元格是需要先合并再拆分的,否则程序会报错)
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', $title);
$objPHPExcel->getActiveSheet()->getDefaultRowDimension()->setRowHeight(18);//所有单元格(行)默认高度
$objPHPExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(18);//所有单元格(列)默认宽度
$objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
$objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(16);
$objPHPExcel->getActiveSheet()->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
$objActSheet->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getFont()->getColor()->setARGB('FF000000');
$objActSheet->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('##00BFFF');
//处理表头
foreach ($field_list as $k => $v) {
$objPHPExcel->setActiveSheetIndex(0)->setCellValue($cellKey[$k] . $topNumber, $v['name']);//设置表头数据
$objPHPExcel->getActiveSheet()->freezePane($cellKey[$k] . ($topNumber + 1));//冻结窗口
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$k] . $topNumber)->getFont()->setBold(true);//设置是否加粗
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$k] . $topNumber)->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);//垂直居中
$objPHPExcel->getActiveSheet()->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
if ($v[3] > 0)//大于0表示需要设置宽度
{
$objPHPExcel->getActiveSheet()->getColumnDimension($cellKey[$k])->setWidth($v[3]);//设置列宽度
}
}
$objActSheet->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getFont()->getColor()->setARGB('FF000000');
$objActSheet->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('##00BFFF');
$callCount = count($callback) + 2;
$style_array = array(
'borders' => array(
'allborders' => array(
'style' => \PHPExcel_Style_Border::BORDER_THIN
)
));
$objActSheet->getStyle('A1:' . $cellKey[count($field_list) - 1] . $callCount)->applyFromArray($style_array);
foreach ($callback as $k => $item) {
foreach ($field_list as $key => $rule) {
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$key] . ($k + 1 + $topNumber) . ':' . $cellKey[count($field_list) - 1] . ($k + 1 + $topNumber))->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$key] . ($k + 1 + $topNumber) . ':' . $cellKey[count($field_list) - 1] . ($k + 1 + $topNumber))->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
$objPHPExcel->getActiveSheet()->setCellValue($cellKey[$key] . ($k + 1 + $topNumber), $item[$rule['field']]);
}
}
// excel头参数
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $file_name . '.xls"'); //日期为文件名后缀
header('Cache-Control: max-age=0');
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5'); //excel5为xls格式excel2007为xlsx格式
$objWriter->save('php://output');
}
/**
* 商业智能模块导出csv
* @param $file_name 导出文件名称
* @param $field_list 导出字段列表
* @param $callback 回调函数,查询需要导出的数据
* @author
**/
public function biExportExcel($file_name, $field_list, $title, $callback)
{
ini_set('memory_limit', '128M');
set_time_limit(0);
// 加载类库
vendor("phpexcel.PHPExcel");
vendor("phpexcel.PHPExcel.Writer.Excel5");
vendor("phpexcel.PHPExcel.Writer.Excel2007");
vendor("phpexcel.PHPExcel.IOFactory");
$objPHPExcel = new \PHPExcel();
//定义配置
$topNumber = 2;//表头有几行占用
$xlsTitle = iconv('utf-8', 'gb2312', $title);//文件名称
$cellKey = array(
'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',
'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM',
'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'
);
//处理表头标题
$objActSheet = $objPHPExcel->getActiveSheet(0);
$objPHPExcel->getActiveSheet()->mergeCells('A1:' . $cellKey[count($field_list) - 1] . '1');//合并单元格(如果要拆分单元格是需要先合并再拆分的,否则程序会报错)
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', $title);
$objPHPExcel->getActiveSheet()->getDefaultRowDimension()->setRowHeight(18);//所有单元格(行)默认高度
$objPHPExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(18);//所有单元格(列)默认宽度
$objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
$objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(16);
$objPHPExcel->getActiveSheet()->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
$objActSheet->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getFont()->getColor()->setARGB('FF000000');
$objActSheet->getStyle('A1:' . $cellKey[count($field_list) - 1] . '1')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('##00BFFF');
//处理表头
foreach ($field_list as $k => $v) {
$objPHPExcel->setActiveSheetIndex(0)->setCellValue($cellKey[$k] . $topNumber, $v['name']);//设置表头数据
$objPHPExcel->getActiveSheet()->freezePane($cellKey[$k] . ($topNumber + 1));//冻结窗口
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$k] . $topNumber)->getFont()->setBold(true);//设置是否加粗
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$k] . $topNumber)->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);//垂直居中
$objPHPExcel->getActiveSheet()->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
if ($v[3] > 0)//大于0表示需要设置宽度
{
$objPHPExcel->getActiveSheet()->getColumnDimension($cellKey[$k])->setWidth($v[3]);//设置列宽度
}
}
$objActSheet->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getFont()->getColor()->setARGB('FF000000');
$objActSheet->getStyle('A2:' . $cellKey[count($field_list) - 1] . '2')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('##00BFFF');
$callCount = count($callback) + 2;
$style_array = array(
'borders' => array(
'allborders' => array(
'style' => \PHPExcel_Style_Border::BORDER_THIN
)
));
$objActSheet->getStyle('A1:' . $cellKey[count($field_list) - 1] . $callCount)->applyFromArray($style_array);
foreach ($callback as $k => $item) {
foreach ($field_list as $key => $rule) {
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$key] . ($k + 1 + $topNumber) . ':' . $cellKey[count($field_list) - 1] . ($k + 1 + $topNumber))->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle($cellKey[$key] . ($k + 1 + $topNumber) . ':' . $cellKey[count($field_list) - 1] . ($k + 1 + $topNumber))->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
$objPHPExcel->getActiveSheet()->setCellValue($cellKey[$key] . ($k + 1 + $topNumber), $item[$rule['field']]);
}
}
// excel头参数
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $file_name . '.xls"'); //日期为文件名后缀
header('Cache-Control: max-age=0');
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5'); //excel5为xls格式excel2007为xlsx格式
$objWriter->save('php://output');
}
/**
* bi 员工业绩导出
* @param $file_name
* @param $field_list
* @param $param
* @param $title
* @throws \PHPExcel_Reader_Exception
* @throws \PHPExcel_Writer_Exception
*/
public function template_download($file_name, $field_list, $title, $callback)
{
// 加载类库
vendor("phpexcel.PHPExcel");
vendor("phpexcel.PHPExcel.Writer.Excel5");
vendor("phpexcel.PHPExcel.Writer.Excel2007");
vendor("phpexcel.PHPExcel.IOFactory");
$objPHPExcel = new \PHPExcel();
//定义配置
$topNumber = 2;//表头有几行占用
$xlsTitle = iconv('utf-8', 'gb2312', $title);//文件名称
$cellKey = array(
'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',
'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM',
'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AV', 'AW', 'AX', 'AY', 'AZ'
);
//处理表头标题
$objActSheet = $objPHPExcel->getActiveSheet(0);
$objPHPExcel->getActiveSheet()->mergeCells('A1:M1');//合并单元格(如果要拆分单元格是需要先合并再拆分的,否则程序会报错)
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', $title);
$objPHPExcel->getActiveSheet()->getDefaultRowDimension()->setRowHeight(18);//所有单元格(行)默认高度
$objPHPExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(18);//所有单元格(列)默认宽度
$objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
$objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(16);
$objPHPExcel->getActiveSheet()->getStyle('A1:M1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A1:M1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
$objActSheet->getStyle('A1:M1')->getFont()->getColor()->setARGB('FF000000');
$objActSheet->getStyle('A1:M1')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('##00BFFF');
//处理表头
$objPHPExcel->getActiveSheet()->freezePane('A2');//冻结窗口
$objPHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setBold(true);//设置是否加粗
$objPHPExcel->getActiveSheet()->getStyle('A2')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);//垂直居中
$objPHPExcel->getActiveSheet()->getStyle('A2:M2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A2:M2')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
$objPHPExcel->getActiveSheet()->getStyle('A2:M2')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);//文字居中
$objActSheet->getStyle('A2:M2')->getFont()->getColor()->setARGB('FF000000');
$objActSheet->getStyle('A2:M2')->getFill()->setFillType(\PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setARGB('##00BFFF');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A2', '日期');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A3', '当月回款金额(元)');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A4', '环比增长(%');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('A5', '同比增长(%');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('B2', '202001');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('C2', '202002');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('D2', '202003');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('E2', '202004');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('F2', '202005');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('G2', '202006');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('H2', '202007');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('I2', '202008');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('J2', '202009');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('K2', '202010');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('L2', '202011');
$objPHPExcel->setActiveSheetIndex(0)->setCellValue('M2', '202012');
$baseRow = 3; //数据从N-1行开始往下输出 这里是避免头信息被覆盖
$callCount = count($callback) + 2;
$style_array = array(
'borders' => array(
'allborders' => array(
'style' => \PHPExcel_Style_Border::BORDER_THIN
)
));
$objActSheet->getStyle('A1:M5')->applyFromArray($style_array);
foreach ($callback as $key => $value) {
$k = $key + 1;
$objPHPExcel->getActiveSheet()->setCellValue($cellKey[$k] . '3', $value['thisMonth']);
$objPHPExcel->getActiveSheet()->setCellValue($cellKey[$k] . '4', $value['chain_ratio']);
$objPHPExcel->getActiveSheet()->setCellValue($cellKey[$k] . '5', $value['year_on_year']);
}
// excel头参数
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment;filename="' . $file_name . '.xls"'); //日期为文件名后缀
header('Cache-Control: max-age=0');
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5'); //excel5为xls格式excel2007为xlsx格式
$objWriter->save('php://output');
}
/**
* 运行中
* @param $param
* @return int|null
*/
public function importNum()
{
$param = Cache::get('item');
$excelData=Cache::get('excel');
$base=$excelData['base'];
if ($param == 0) {
$this->$base('',$excelData);
$data = 0;
} elseif ($param == 1) {
$data = '';
}
return $data;
}
/**
* 结果
* @param $param
* @return int|null
*/
public function importInfo()
{
$param = Cache::get('excel_item');
$param = unserialize($param);
return $param;
}
/**
* 导入记录
* @param $param
* @return array
*/
public function importList($param)
{
$list = db('admin_import_record')->alias('i')
->join('admin_user user', 'i.user_id=user.id')
->where(['i.type'=>$param['type'],'i.user_id'=>$param['user_id']])->page($param['page'], $param['limit'])
->field('i.*,user.realname as user_name')->order('create_time desc')->select();
$dataCount = db('admin_import_record')->where('type', $param['type'])->count();
$week = strtotime(date("Y-m-d H:i:s", strtotime("+7 day")));
$time = time();
foreach ($list as $k => $v) {
$week = strtotime("+7 day",$v['create_time']);
if ($time > (int)$week) {
$list[$k]['valid'] = 0;
} else {
$list[$k]['valid'] = 1;
}
if($v['error_data_file_path']==''){
$list[$k]['valid'] = -1;
}
$list[$k]['create_time'] = date('Y-m-d', $v['create_time']);
}
$data = [];
$data['list'] = $list;
$data['dataCount'] = $dataCount ?: 0;
if ($param['page'] != 1 && ($param['page'] * $param['limit']) >= $dataCount) {
$data['firstPage'] = false;
$data['lastPage'] = true;
} else if ($param['page'] != 1 && (int)($param['page'] * $param['limit']) < $dataCount) {
$data['firstPage'] = false;
$data['lastPage'] = false;
} else if ($param['page'] == 1) {
$data['firstPage'] = true;
$data['lastPage'] = false;
}
return $data;
}
}