@@ -2,7 +2,13 @@ | |||
namespace app\admin\controller\user; | |||
use app\admin\library\Auth; | |||
use app\common\controller\Backend; | |||
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; | |||
use PhpOffice\PhpSpreadsheet\Reader\Csv; | |||
use PhpOffice\PhpSpreadsheet\Reader\Xls; | |||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx; | |||
use think\exception\PDOException; | |||
/** | |||
* 会员管理 | |||
@@ -26,6 +32,133 @@ class User extends Backend | |||
$this->model = model('User'); | |||
} | |||
public function import() | |||
{ | |||
$file = $this->request->request('file'); | |||
if (!$file) { | |||
$this->error(__('Parameter %s can not be empty', 'file')); | |||
} | |||
$filePath = ROOT_PATH . DS . 'public' . DS . $file; | |||
if (!is_file($filePath)) { | |||
$this->error(__('No results were found')); | |||
} | |||
//实例化reader | |||
$ext = pathinfo($filePath, PATHINFO_EXTENSION); | |||
if (!in_array($ext, ['csv', 'xls', 'xlsx'])) { | |||
$this->error(__('Unknown data format')); | |||
} | |||
if ($ext === 'csv') { | |||
$file = fopen($filePath, 'r'); | |||
$filePath = tempnam(sys_get_temp_dir(), 'import_csv'); | |||
$fp = fopen($filePath, "w"); | |||
$n = 0; | |||
while ($line = fgets($file)) { | |||
$line = rtrim($line, "\n\r\0"); | |||
$encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']); | |||
if ($encoding != 'utf-8') { | |||
$line = mb_convert_encoding($line, 'utf-8', $encoding); | |||
} | |||
if ($n == 0 || preg_match('/^".*"$/', $line)) { | |||
fwrite($fp, $line . "\n"); | |||
} else { | |||
fwrite($fp, '"' . str_replace(['"', ','], ['""', '","'], $line) . "\"\n"); | |||
} | |||
$n++; | |||
} | |||
fclose($file) || fclose($fp); | |||
$reader = new Csv(); | |||
} elseif ($ext === 'xls') { | |||
$reader = new Xls(); | |||
} else { | |||
$reader = new Xlsx(); | |||
} | |||
//导入文件首行类型,默认是注释,如果需要使用字段名称请使用name | |||
$fieldArr = [ 'nickname', | |||
'username', | |||
'password', | |||
'email',]; | |||
//加载文件 | |||
$insert = []; | |||
try { | |||
if (!$PHPExcel = $reader->load($filePath)) { | |||
$this->error(__('Unknown data format')); | |||
} | |||
$currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表 | |||
$allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号 | |||
$allRow = $currentSheet->getHighestRow(); //取得一共有多少行 | |||
// $maxColumnNumber = Coordinate::columnIndexFromString($allColumn); | |||
$fields = [ | |||
'nickname', | |||
'username', | |||
'password', | |||
'email', | |||
]; | |||
$salt = \fast\Random::alnum(); | |||
for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) { | |||
$values = []; | |||
for ($currentColumn = 1; $currentColumn <= 4; $currentColumn++) { | |||
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue(); | |||
if ($currentColumn==3){ | |||
//修改的是密码 | |||
$val= \app\common\library\Auth::instance()->getEncryptPassword($val, $salt); | |||
} | |||
$values[] = is_null($val) ? '' : $val; | |||
} | |||
// $row = []; | |||
$temp = array_combine($fields, $values); | |||
// foreach ($temp as $k => $v) { | |||
// if (isset($fieldArr[$k]) && $k !== '') { | |||
// $row[$fieldArr[$k]] = $v; | |||
// } | |||
// } | |||
// print_r($temp); | |||
// print_r($row); | |||
// if ($row) { | |||
$insert[] = $temp; | |||
// } | |||
} | |||
} catch (Exception $exception) { | |||
$this->error($exception->getMessage()); | |||
} | |||
if (!$insert) { | |||
$this->error(__('No rows were updated')); | |||
} | |||
try { | |||
//是否包含admin_id字段 | |||
$has_admin_id = false; | |||
foreach ($fieldArr as $name => $key) { | |||
if ($key == 'admin_id') { | |||
$has_admin_id = true; | |||
break; | |||
} | |||
} | |||
if ($has_admin_id) { | |||
$auth = Auth::instance(); | |||
foreach ($insert as &$val) { | |||
if (!isset($val['admin_id']) || empty($val['admin_id'])) { | |||
$val['admin_id'] = $auth->isLogin() ? $auth->id : 0; | |||
} | |||
} | |||
} | |||
$this->model->saveAll($insert); | |||
} catch (PDOException $exception) { | |||
$msg = $exception->getMessage(); | |||
if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) { | |||
$msg = "导入失败,包含【{$matches[1]}】的记录已存在"; | |||
}; | |||
$this->error($msg); | |||
} catch (Exception $e) { | |||
$this->error($e->getMessage()); | |||
} | |||
$this->success(); | |||
} | |||
/** | |||
* 查看 | |||
*/ | |||
@@ -21,7 +21,7 @@ return [ | |||
/** | |||
* 可上传的文件类型 | |||
*/ | |||
'mimetype' => 'jpg,png,bmp,jpeg,gif,zip,rar,xls,xlsx', | |||
'mimetype' => 'jpg,png,bmp,jpeg,gif,zip,rar,xls,xlsx,csv', | |||
/** | |||
* 是否支持批量上传 | |||
*/ | |||
@@ -10,7 +10,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin | |||
edit_url: 'user/user/edit', | |||
del_url: 'user/user/del', | |||
multi_url: 'user/user/multi', | |||
import_url: 'example/import', | |||
import_url: 'user/user/import', | |||
table: 'user', | |||
} | |||
}); | |||
@@ -26,22 +26,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin | |||
[ | |||
{checkbox: true}, | |||
{field: 'id', title: __('Id'), sortable: true}, | |||
{field: 'group.name', title: __('Group')}, | |||
// {field: 'group.name', title: __('Group')}, | |||
{field: 'username', title: __('Username'), operate: 'LIKE'}, | |||
{field: 'nickname', title: __('Nickname'), operate: 'LIKE'}, | |||
{field: 'email', title: __('Email'), operate: 'LIKE'}, | |||
{field: 'mobile', title: __('Mobile'), operate: 'LIKE'}, | |||
{field: 'avatar', title: __('Avatar'), events: Table.api.events.image, formatter: Table.api.formatter.image, operate: false}, | |||
{field: 'level', title: __('Level'), operate: 'BETWEEN', sortable: true}, | |||
{field: 'gender', title: __('Gender'), visible: false, searchList: {1: __('Male'), 0: __('Female')}}, | |||
{field: 'score', title: __('Score'), operate: 'BETWEEN', sortable: true}, | |||
{field: 'successions', title: __('Successions'), visible: false, operate: 'BETWEEN', sortable: true}, | |||
{field: 'maxsuccessions', title: __('Maxsuccessions'), visible: false, operate: 'BETWEEN', sortable: true}, | |||
{field: 'logintime', title: __('Logintime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | |||
{field: 'loginip', title: __('Loginip'), formatter: Table.api.formatter.search}, | |||
{field: 'jointime', title: __('Jointime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | |||
{field: 'joinip', title: __('Joinip'), formatter: Table.api.formatter.search}, | |||
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status, searchList: {normal: __('Normal'), hidden: __('Hidden')}}, | |||
// {field: 'mobile', title: __('Mobile'), operate: 'LIKE'}, | |||
// {field: 'avatar', title: __('Avatar'), events: Table.api.events.image, formatter: Table.api.formatter.image, operate: false}, | |||
// {field: 'level', title: __('Level'), operate: 'BETWEEN', sortable: true}, | |||
// {field: 'gender', title: __('Gender'), visible: false, searchList: {1: __('Male'), 0: __('Female')}}, | |||
// {field: 'score', title: __('Score'), operate: 'BETWEEN', sortable: true}, | |||
// {field: 'successions', title: __('Successions'), visible: false, operate: 'BETWEEN', sortable: true}, | |||
// {field: 'maxsuccessions', title: __('Maxsuccessions'), visible: false, operate: 'BETWEEN', sortable: true}, | |||
// {field: 'logintime', title: __('Logintime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | |||
// {field: 'loginip', title: __('Loginip'), formatter: Table.api.formatter.search}, | |||
// {field: 'jointime', title: __('Jointime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true}, | |||
// {field: 'joinip', title: __('Joinip'), formatter: Table.api.formatter.search}, | |||
// {field: 'status', title: __('Status'), formatter: Table.api.formatter.status, searchList: {normal: __('Normal'), hidden: __('Hidden')}}, | |||
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} | |||
] | |||
] | |||