excludeFields)) { foreach ($this->excludeFields as $field) { if (array_key_exists($field, $params)) { unset($params[$field]); } } } else if (array_key_exists($this->excludeFields, $params)) { unset($params[$this->excludeFields]); } return $params; } /** * 查看 * * @return string|Json * @throws \think\Exception * @throws DbException */ public function index() { //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { return $this->view->fetch(); } //如果发送的来源是 Selectpage,则转发到 Selectpage if ($this->request->request('keyField')) { return $this->selectpage(); } [$where, $sort, $order, $offset, $limit] = $this->buildparams(); $list = $this->model ->where($where) ->order($sort, $order) ->paginate($limit); $result = ['total' => $list->total(), 'rows' => $list->items()]; return json($result); } /** * 回收站 * * @return string|Json * @throws \think\Exception */ public function recyclebin() { //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { return $this->view->fetch(); } [$where, $sort, $order, $offset, $limit] = $this->buildparams(); $list = $this->model ->onlyTrashed() ->where($where) ->order($sort, $order) ->paginate($limit); $result = ['total' => $list->total(), 'rows' => $list->items()]; return json($result); } /** * 添加 * * @return string * @throws \think\Exception */ public function add() { if (false === $this->request->isPost()) { return $this->view->fetch(); } $params = $this->request->post('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); if ($this->dataLimit && $this->dataLimitFieldAutoFill) { $params[$this->dataLimitField] = $this->auth->id; } $result = false; Db::startTrans(); try { //是否采用模型验证 if ($this->modelValidate) { $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate; $this->model->validateFailException()->validate($validate); } $result = $this->model->allowField(true)->save($params); Db::commit(); } catch (ValidateException|PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($result === false) { $this->error(__('No rows were inserted')); } $this->success(); } /** * 编辑 * * @param $ids * @return string * @throws DbException * @throws \think\Exception */ public function edit($ids = null) { $row = $this->model->get($ids); if (!$row) { $this->error(__('No Results were found')); } $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) { $this->error(__('You have no permission')); } if (false === $this->request->isPost()) { $this->view->assign('row', $row); return $this->view->fetch(); } $params = $this->request->post('row/a'); if (empty($params)) { $this->error(__('Parameter %s can not be empty', '')); } $params = $this->preExcludeFields($params); $result = false; Db::startTrans(); try { //是否采用模型验证 if ($this->modelValidate) { $name = str_replace("\\model\\", "\\validate\\", get_class($this->model)); $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate; $row->validateFailException()->validate($validate); } $result = $row->allowField(true)->save($params); Db::commit(); } catch (ValidateException|PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if (false === $result) { $this->error(__('No rows were updated')); } $this->success(); } /** * 删除 * * @param $ids * @return void * @throws DbException * @throws DataNotFoundException * @throws ModelNotFoundException */ public function del($ids = null) { if (false === $this->request->isPost()) { $this->error(__("Invalid parameters")); } $ids = $ids ?: $this->request->post("ids"); if (empty($ids)) { $this->error(__('Parameter %s can not be empty', 'ids')); } $pk = $this->model->getPk(); $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds)) { $this->model->where($this->dataLimitField, 'in', $adminIds); } $list = $this->model->where($pk, 'in', $ids)->select(); $count = 0; Db::startTrans(); try { foreach ($list as $item) { $count += $item->delete(); } Db::commit(); } catch (PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success(); } $this->error(__('No rows were deleted')); } /** * 真实删除 * * @param $ids * @return void */ public function destroy($ids = null) { if (false === $this->request->isPost()) { $this->error(__("Invalid parameters")); } $ids = $ids ?: $this->request->post('ids'); $pk = $this->model->getPk(); $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds)) { $this->model->where($this->dataLimitField, 'in', $adminIds); } if ($ids) { $this->model->where($pk, 'in', $ids); } $count = 0; Db::startTrans(); try { $list = $this->model->onlyTrashed()->select(); foreach ($list as $item) { $count += $item->delete(true); } Db::commit(); } catch (PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success(); } $this->error(__('No rows were deleted')); } /** * 还原 * * @param $ids * @return void */ public function restore($ids = null) { if (false === $this->request->isPost()) { $this->error(__('Invalid parameters')); } $ids = $ids ?: $this->request->post('ids'); $pk = $this->model->getPk(); $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds)) { $this->model->where($this->dataLimitField, 'in', $adminIds); } if ($ids) { $this->model->where($pk, 'in', $ids); } $count = 0; Db::startTrans(); try { $list = $this->model->onlyTrashed()->select(); foreach ($list as $item) { $count += $item->restore(); } Db::commit(); } catch (PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success(); } $this->error(__('No rows were updated')); } /** * 批量更新 * * @param $ids * @return void */ public function multi($ids = null) { if (false === $this->request->isPost()) { $this->error(__('Invalid parameters')); } $ids = $ids ?: $this->request->post('ids'); if (empty($ids)) { $this->error(__('Parameter %s can not be empty', 'ids')); } if (false === $this->request->has('params')) { $this->error(__('No rows were updated')); } parse_str($this->request->post('params'), $values); $values = $this->auth->isSuperAdmin() ? $values : array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields))); if (empty($values)) { $this->error(__('You have no permission')); } $adminIds = $this->getDataLimitAdminIds(); if (is_array($adminIds)) { $this->model->where($this->dataLimitField, 'in', $adminIds); } $count = 0; Db::startTrans(); try { $list = $this->model->where($this->model->getPk(), 'in', $ids)->select(); foreach ($list as $item) { $count += $item->allowField(true)->isUpdate(true)->save($values); } Db::commit(); } catch (PDOException|Exception $e) { Db::rollback(); $this->error($e->getMessage()); } if ($count) { $this->success(); } $this->error(__('No rows were updated')); } /** * 导入 * * @return void * @throws PDOException * @throws BindParamException */ protected function import() { // 后台运行 ignore_user_abort(true); // 取消超时 set_time_limit(0); $timer1 = microtime(true); $usage1 = memory_get_usage(); //取得上传文件 $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')); } $insert = []; $encode = 'utf-8'; $charSet = setlocale(LC_CTYPE, 0); $fileType = strtolower(IOFactory::identify($filePath)); // 检查文件类型 if (!in_array($fileType, ['csv', 'xls', 'xlsx'])) { $this->error(__('Unknown data format')); } //导入文件首行类型,默认是注释,如果需要使用字段名称请使用name $importHeadType = isset($this->importHeadType) ? $this->importHeadType : 'comment'; $model = get_class($this->model); $table = $this->model->getQuery()->getTable(); $database = \think\Config::get('database.database'); $fieldArr = []; $list = db()->query("SELECT COLUMN_NAME,COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?", [$table, $database]); foreach ($list as $k => $v) { if ('comment' == $importHeadType) { $v['COLUMN_COMMENT'] = explode(':', $v['COLUMN_COMMENT'])[0]; //字段备注有:时截取 $fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME']; } else { $fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_NAME']; } } // 取得csv文件编码 if ('csv' === $fileType) { // 读取文件的前 1KB 进行检测 $handle = fopen($filePath, 'r'); rewind($handle); $snippet = fread($handle, 1024); fclose($handle); $encodes = ['utf-8', 'gbk', 'gb18030', 'latin1', 'big5']; $detected = mb_detect_encoding($snippet, $encodes); if (false !== $detected) { $encode = $detected; } } //加载文件 try { // windows系统php7环境csv编码解析问题 if ('C' !== $charSet) { setlocale(LC_CTYPE, 'C'); } // 加载表格 $fileReader = IOFactory::createReaderForFile($filePath); $fileReader->setReadDataOnly(true); $sheetlist = $fileReader->listWorksheetInfo($filePath); $sheetInfo = isset($sheetlist[0]) ? (object) $sheetlist[0] : null; if (empty($sheetInfo)) { throw new Exception('读取工作表信息失败'); } if ('csv' === $fileType) { $fileReader->setInputEncoding($encode); } // 分块读取配置 $header = []; $chunkSize = 10000; $chunkSheet = new Spreadsheet(); $chunkFilter = new IReadFilter\ChunkReadFilter(); $chunkReader = IOFactory::createReaderForFile($filePath); $chunkReader->setReadDataOnly(true); $chunkReader->setReadFilter($chunkFilter); if ('csv' === $fileType) { $chunkReader->setContiguous(true); $chunkReader->setInputEncoding($encode); } // 分块读取数据 for ($currentRow = 1; $currentRow <= $sheetInfo->totalRows; $currentRow += $chunkSize) { $chunkFilter->setChunk($currentRow, $chunkSize); $chunkReader->setLoadSheetsOnly($sheetInfo->worksheetName); if ('csv' === $fileType) { $chunkReader->setSheetIndex(0); $chunkSheet = $chunkReader->loadIntoExisting($filePath, $chunkSheet); } else { $chunkSheet = $chunkReader->load($filePath); } $activeSheet = $chunkSheet->getSheet(0); // 取得当前工作表名称 $worksheetName = $activeSheet->getTitle(); // 取得最大的列号(ABC..) $lastColumnLetter = $activeSheet->getHighestDataColumn(); // 取得最大的列索引(123..) $lastColumnIndex = Coordinate::columnIndexFromString($lastColumnLetter); // 取得总行数 $totalRows = $activeSheet->getHighestRow(); // 取得总列数 $totalColumns = $lastColumnIndex + 1; // 转为数组 $sheetRange = sprintf('A1:%s%d', $lastColumnLetter, $totalRows); $sheetArray = $activeSheet->rangeToArray($sheetRange, null, false, false, false); // 数据处理 if (!empty($sheetArray)) { $startIndex = 1; $currentIndex = 1; if (1 == $currentRow) { $startIndex++; $header = $sheetArray[0]; } foreach ($sheetArray as $row) { if ($currentIndex >= $startIndex) { foreach ($row as &$cell) { $cell = is_null($cell) ? '' : $cell; } $vals = []; $temp = array_combine($header, $row); foreach ($temp as $k => $v) { if (isset($fieldArr[$k]) && '' !== $k) { $vals[$fieldArr[$k]] = $v; } } $insert[] = $vals; } $currentIndex++; } } $chunkSheet->removeSheetByIndex(0); $chunkSheet->createSheet(0); } } catch (Exception $exception) { $msg = $exception->getMessage(); if (preg_match("/.*The filename (.+) is not recognised as an OLE file.*/is", $msg, $matches)) { $msg = "读取文件失败, 建议重新将文件另存为csv、xls或xslx格式"; }; $this->error($msg); } if (!$insert) { $this->error(__('No rows were updated')); } //是否包含admin_id字段 $has_admin_id = false; foreach ($fieldArr as $name => $key) { if ('admin_id' == $key) { $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; } } } // 批量插入数据 $affectRows = 0; $repeatRows = 0; foreach ($insert as &$data) { $errMsg = null; $error = null; $event = null; $hook = [ 'event' => 'before_import', 'class' => static::class, 'model' => $model, 'data' => $data, 'error' => null, ]; Hook::listen('table_import', $hook); try { $affectRows += (new $model($hook['data']))->save(); $event = 'after_import'; } catch (PDOException $e) { $error = $e; $event = 'pdo_exception'; if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $error, $matches)) { $errMsg = "导入失败,包含【{$matches[1]}】的记录已存在"; $event = 'pdo_duplicate_entry'; $repeatRows++; } } catch (Exception $e) { $error = $e; $event = 'exception'; } $hook['event'] = $event; $hook['error'] = $error; Hook::listen('table_import', $hook); $error = $hook['error']; if ($error) { $errMsg = $errMsg ?: $error->getMessage(); $this->error($errMsg); } } if (!$affectRows) { $this->error(__('No rows were updated')); } $timer2 = microtime(true); $usage2 = memory_get_usage(); $usage = round(($usage2 - $usage1) / 1024 / 1024, 2); $timer = round($timer2 - $timer1, 3); $success = vsprintf("导入成功!
%s
%s
%s
%s", [ sprintf("新增数据: %d 条", $affectRows), sprintf("重复数据: %d 条", $repeatRows), sprintf("内存占用: %s MB", $usage), sprintf("总共耗时: %s 秒", $timer), ]); $this->success($success); } }