@@ -2,7 +2,13 @@ | |||||
namespace app\admin\controller\user; | namespace app\admin\controller\user; | ||||
use app\admin\library\Auth; | |||||
use app\common\controller\Backend; | 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'); | $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', | edit_url: 'user/user/edit', | ||||
del_url: 'user/user/del', | del_url: 'user/user/del', | ||||
multi_url: 'user/user/multi', | multi_url: 'user/user/multi', | ||||
import_url: 'example/import', | |||||
import_url: 'user/user/import', | |||||
table: 'user', | table: 'user', | ||||
} | } | ||||
}); | }); | ||||
@@ -26,22 +26,22 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin | |||||
[ | [ | ||||
{checkbox: true}, | {checkbox: true}, | ||||
{field: 'id', title: __('Id'), sortable: true}, | {field: 'id', title: __('Id'), sortable: true}, | ||||
{field: 'group.name', title: __('Group')}, | |||||
// {field: 'group.name', title: __('Group')}, | |||||
{field: 'username', title: __('Username'), operate: 'LIKE'}, | {field: 'username', title: __('Username'), operate: 'LIKE'}, | ||||
{field: 'nickname', title: __('Nickname'), operate: 'LIKE'}, | {field: 'nickname', title: __('Nickname'), operate: 'LIKE'}, | ||||
{field: 'email', title: __('Email'), 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} | {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} | ||||
] | ] | ||||
] | ] | ||||