Files
ntonpower/app/api/controller/v1/Base.php
2026-10-14 14:00:29 +08:00

1139 lines
44 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace app\api\controller\v1;
use app\library\LogToKafka;
use app\BaseController;
use Baiy\ThinkAsync\Facade\Async;
use DeviceDetector\DeviceDetector;
use DeviceDetector\Parser\Device\AbstractDeviceParser;
use GeoIp2\Database\Reader;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Csv;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use think\db\exception\PDOException;
use think\facade\Db;
use think\facade\Env;
use think\facade\Filesystem;
use utils\UEUploader;
use utils\Jwt;
use utils\QiniuUploader;
/**
* 后台控制器基类
* Class Base
* @package app\api\controller
*/
class Base extends BaseController
{
use LogToKafka;
/**
* 管理登录信息
* @var array
*/
protected $adminInfo = [];
/**
* 平台ID,归属于登录用户,永远为1,只有一个平台。
* @var int
*/
protected $platformId = 1;
/**
* JWT实例
* @var Jwt
*/
protected $jwt;
/**
* 上传静态文件存储位置,默认存储在 public/storage/image/site
* @var string
*/
protected $staticPath = 'image/site';
/**
* 查询条件,模糊字段与值。格式 ['name'=>'test']
* @var null
*/
protected $simple = [];
/**
* 精准查询,精确字段,格式['language_id'=> 1]
* @var null
*/
protected $focus = [];
/**
* 排序字段。格式 ['sort'=>'desc']
* @var null
*/
protected $order = [];
/**
* 筛选字段,用于提交给前端需要显示哪些数据库字段数据,
* @var null
*/
protected $field = [];
/**
* 模型
* @var null
*/
protected $model = null;
/**
* 验证器
* @var null
*/
protected $validate = null;
/**
* 七牛云
* @var null
*/
protected $qn = null;
/**
* 分页页码
* @var integer
*/
protected $page = 0;
/**
* 分页数量
* @var integer
*/
protected $size = 0;
/**
* 接口监控数据
* @var string[]
*/
protected $apiLog = [
'items' => '',
'forum' => '',/*模块-中文*/
'forum_code'=> '',/*模块日志编码*/
'refer' => '',/*引用接口页*/
'source' => '',/*数据来源标识*/
'source_code'=> '',/*接口地址*/
'source_name'=> '',/*接口调用地址*/
'state' => '',/*结果状态*/
'date_time' => '',/*生成时间*/
'start_time'=> '',/*开始时间*/
'end_time' => '',/*结束时间*/
'elapsed_time'=>'',/*耗时*/
'ip' => '',/*访客IP*/
'country' => '',/*国家*/
'city' => '',/*城市*/
'area' => '',/*地区*/
'system' => '',/*设备系统*/
'version' => '',/*系统版本*/
'brower' => '',/*浏览器*/
'models' => '',/*设备型号*/
'beginCode' => '',/*传值参数*/
'reurnCode' => '',/*返回结果*/
];
/**
* 初始化方法
*/
public function initialize()
{
//初始化用户信息
$this->adminInfo = $this->request->admin_user_info;
$config = [
'iss' => Env::get('jwt_config.iss'),
'exp' => Env::get('jwt_config.exp')
];
$this->jwt = new Jwt($config);
$this->platformId = 1;
$this->qn = new QiniuUploader();
//
if ($this->request->param('page') != '') {
$this->page = $this->request->param('page/d',1);
}
if ($this->request->param('size') != '') {
$this->size = $this->request->param('size/d',10);
}
//请求来源页
$this->apiLog['items'] = Env::get('platform_name','官网');
$this->apiLog['refer'] = $this->request->server('HTTP_REFERER');
$this->apiLog['source'] = $this->request->server('HTTP_REFERER');
$this->apiLog['source_code'] = $this->request->domain().$this->request->server('REQUEST_URI');
$this->apiLog['source_name'] = $this->request->server('REQUEST_URI');
//获取应用启动时间
$this->apiLog['start_time'] = $this->app->getBeginTime();
//获取访问设备,系统版本,浏览器,设备型号
$userAgent = $this->request->server('HTTP_USER_AGENT');
AbstractDeviceParser::setVersionTruncation(AbstractDeviceParser::VERSION_TRUNCATION_NONE);
$dd = new DeviceDetector($userAgent);
$dd->parse();
if ($dd->isBot()) {
$this->apiLog['brower'] = '未知';
$this->apiLog['system'] = '未知';
$this->apiLog['version'] = '未知';
$this->apiLog['models'] = '爬虫';
} else {
$clientInfo = $dd->getClient();
$osInfo = $dd->getOs();
$device = $dd->getDeviceName();
$brand = $dd->getBrandName();
$model = $dd->getModel();
$this->apiLog['brower'] = !empty($clientInfo) ? $clientInfo['name'].' '.$clientInfo['version'] : '未知';
$this->apiLog['system'] = !empty($osInfo) ? $osInfo['name'].' '.$osInfo['version'] : '未知';
$this->apiLog['version'] = $osInfo['version']??'';
$this->apiLog['models'] = $device . " " . $brand . " ". $model;
}
//解析IP地址,得到国家,城市,地址,
$visitIp = get_client_ip();
$this->apiLog['ip'] = $visitIp;
if (!filter_var($visitIp,FILTER_VALIDATE_IP,FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE | FILTER_NULL_ON_FAILURE)) {
$this->apiLog['country'] = '本地';
$this->apiLog['city'] = '本地';
$this->apiLog['area'] = '本地';
} else {
$reader = new Reader(public_path() . '/GeoLite2-City.mmdb');
$record = $reader->city($visitIp);
$this->apiLog['country'] = $record->country->names['zh-CN'];
$this->apiLog['city'] = $record->city->name;
$this->apiLog['area'] = $record->city->name;
}
}
/**
* 全局接口返回
* @param int $status 状态码
* @param string $message 消息提示
* @param array $data 返回的数据内容
*/
public function msg(int $status,string $message,array $data = []):\think\response\Json
{
$route = strtolower($this->request->pathinfo());
$pathInfo = explode('/',$route);
$this->apiLog['state'] = $status;
$this->apiLog['forum'] = $pathInfo[1]??'';
$this->apiLog['forum_code'] = $status == 200 ? 0 : 1;
$this->apiLog['date_time'] = date('Y-m-d H:i:s',time());
$this->apiLog['end_time'] = microtime(true);
$this->apiLog['elapsed_time'] = round((float)($this->apiLog['end_time'] - $this->apiLog['start_time']),6);
$this->apiLog['end_time'] = date('Y-m-d H:i:s',time());
$this->apiLog['start_time'] = date('Y-m-d H:i:s',(int)$this->app->getBeginTime());
$this->apiLog['beginCode'] = json_encode($this->request->param());
$this->apiLog['reurnCode'] = $status == 200 ? 'SUCCESS' : 'ERROR';
//返回信息前,写入kafka log日志
if (!Env::get('APP_DEBUG')) {
// $this->sendLogsToKafkaProduce($this->apiLog,'api_logs',Env::get('database.database'),'api');
$this->asyncApiLog($this->apiLog,'api_logs','api');
}
header("Content-Type: application/json; charset=UTF-8");
$result = [
'status' => $status,
'message' => $message,
'data' => $data
];
return json($result);
}
/**
* PHP发送Json对象数据
*
* @param string $url 请求url
* @param string $jsonStr 发送的json字符串
* @param string $Bearer
* @return array
*/
public function curlJson(string $url, string $jsonStr,string $Bearer = ''):array
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonStr);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json; charset=utf-8',
'Content-Length: ' . strlen($jsonStr),
'Bearer:' . $Bearer
)
);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return array('status' => $httpCode, 'data' => $response);
}
/**
* 全局验证器验证方法
*
* @param string $functionName 当前控制器需要验证的方法名
* @param array $inputData 当前控制器需要验证的数据
*/
public function commonValidate(string $functionName,array $inputData):bool
{
//验证器验证
return $this->validate->scene($functionName)->check($inputData);
}
/**
* 列表
*/
public function index():\think\Response\Json
{
$inputData = $this->request->param();
$inputData['platform_id'] = $this->platformId;
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->getIndexList($this->page,$this->size,$this->field, $this->simple, $this->focus,$this->order);
return $this->msg(200,'获取列表成功',$result);
}
/**
* 详情
*/
public function read():\think\Response\Json
{
$inputData = $this->request->param(['id']);
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
$inputData['platform_id'] = $this->platformId;
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->getInfo($inputData);
if ($result) {
$result['language_id'] = $result['site_id'];
return $this->msg(200,'获取列表成功',$result);
} else {
return $this->msg(200,'获取列表成功',[]);
}
}
/**
* 新增
*/
public function create():\think\Response\Json
{
$inputData = $this->request->param();
$inputData['platform_id'] = $this->platformId;
//语言包
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
if (isset($inputData['site_id']) || !empty($inputData['site_id']) || $inputData['site_id'] != 0) {
$this->focus['site_id'] = $inputData['site_id'];
} else {
return $this->msg(504,'语言包/所属站点参数,不正确,请检查!');
}
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->addData($inputData);
if ($result) {
return $this->msg(200,'新增成功');
} else {
return $this->msg(504,'新增失败');
}
}
/**
* 修改
*/
public function update():\think\Response\Json
{
$inputData = $this->request->param();
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
$inputData['platform_id'] = $this->platformId;
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->editData($inputData);
if ($result) {
return $this->msg(200,'更改成功');
} else {
return $this->msg(504,'更改失败');
}
}
/**
* 图片,ICON上传
*/
public function upload():\think\Response\Json
{
$files = $this->request->file();
if (!$files) {
return $this->msg(-1, "请选择上传的文件");
}
$field = array_keys($files)[0];
$data = [];
//兼容多图上传
if (is_array($files) && count($files) > 1 ) {
//不同字段文件名上传 image img ico
//上传到七牛
foreach ($files as $key => $fileSimple) {
if (!$this->commonValidate(__FUNCTION__, [$key => $fileSimple])) {
return $this->msg(-1, $this->validate->getError());
}
$result[$key] = $this->qn->uploadFile($key);
}
foreach ($result as $key => $item) {
$data[] = [
'cdn' => Env::get('QINIU.cdn'),
'origin_name' => $files[$key]->getOriginalName(),
'filename' => explode('/', $item['filename'])[count(explode('/', $item['filename'])) - 1],
'md5' => md5_file($files[$key]->getPathname()),
'url' => $item['remote_url'],
'relative_path' => $item['filename']
];
}
} elseif (is_array($files[$field]) && count($files[$field]) > 1) {
//同一名称的数组文件上传.image[0] image[1]
foreach ($files as $key => $fileSimple) {
if (!$this->commonValidate(__FUNCTION__, [$key => $fileSimple])) {
return $this->msg(-1, $this->validate->getError());
}
}
//上传到七牛
$result = $this->qn->uploadFile($field, true, count($files[$field]));
foreach ($result as $key => $item) {
$data[] = [
'cdn' => Env::get('QINIU.cdn'),
'origin_name' => $files[$field][$key]->getOriginalName(),
'filename' => explode('/', $item['filename'])[count(explode('/', $item['filename'])) - 1],
'md5' => md5_file($files[$field][$key]->getPathname()),
'url' => $item['remote_url'],
'relative_path' => $item['filename']
];
}
} else {
if (!$this->commonValidate(__FUNCTION__,[$field=>$files])) {
return $this->msg(-1,$this->validate->getError());
}
//上传到七牛
$result = $this->qn->uploadFile($field);
$data = [
'cdn' => Env::get('QINIU.cdn'),
'origin_name' => $files[$field]->getOriginalName(),
'filename' => explode('/',$result['filename'])[count(explode('/',$result['filename']))-1],
'md5' => md5_file($files[$field]->getPathname()),
'url' => $result['remote_url'],
'relative_path' => $result['filename']
];
}
return $this->msg(200, '上传成功', $data);
}
/**
* 删除
*/
public function del():\think\Response\Json
{
$inputData = $this->request->param(['id']);
$inputData['platform_id'] = $this->platformId;
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->delData($inputData);
if ($result) {
return $this->msg(200,"删除成功");
} else {
return $this->msg(504,"删除失败");
}
}
/**
* 列表树
*/
public function tree():\think\Response\Json
{
$inputData = $this->request->param();
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
$inputData['platform_id'] = $this->platformId;
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$list = $this->model->getAllList($inputData);
$tree = list_to_tree($list);
return $this->msg(200, '获取列表成功', $tree);
}
/**
* 排序
*/
public function sort():\think\Response\Json
{
$inputData = $this->request->param(['id','sort']);
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
$inputData['platform_id'] = $this->platformId;
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->editData($inputData);
if ($result) {
return $this->msg(200,"排序成功");
} else {
return $this->msg(504,"排序失败");
}
}
/**
* 启用禁用
*/
public function changeStatus():\think\Response\Json
{
$inputData = $this->request->param(['id','status']);
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
if (!$this->commonValidate(__FUNCTION__,$inputData)) {
return $this->msg(-1,$this->validate->getError());
}
$result = $this->model->changeStatus($inputData);
if ($result) {
return $this->msg(200,"操作成功");
} else {
return $this->msg(504,"操作失败");
}
}
/**
* 批量新增
*/
public function batchCreate():\think\Response\Json
{
$inputData = $this->request->param();
if (count($inputData['data']) > 0) {
foreach ($inputData['data'] as &$item) {
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
if (!$this->commonValidate(__FUNCTION__,$item)) {
return $this->msg(-1,$this->validate->getError());
}
$item['platform_id'] = $this->platformId;
}
}
$result = $this->model->saveAll($inputData['data']);
if ($result) {
return $this->msg(200,'新增成功');
} else {
return $this->msg(504,'新增失败');
}
}
/**
* 批量更新
*/
public function batchUpdate():\think\Response\Json
{
$inputData = $this->request->param();
if (count($inputData['data']) > 0) {
foreach ($inputData['data'] as &$item) {
if (isset($inputData['language_id']) && $inputData['language_id'] != 0 && $inputData['language_id'] != '') {
$this->focus['site_id'] = $inputData['site_id'] = $inputData['language_id'];
unset($inputData['language_id']);
}
if (!$this->commonValidate(__FUNCTION__,$item)) {
return $this->msg(-1,$this->validate->getError());
}
$item['platform_id'] = $this->platformId;
}
}
$result = $this->model->batchEditData($inputData['data']);
if ($result) {
return $this->msg(200,'更新成功');
} else {
return $this->msg(504,'更新失败');
}
}
/**
* 百度富文本上传
* @throws \Exception
*/
public function ueditorUpload():\think\Response\Json
{
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:GET, POST, PATCH, PUT, DELETE,OPTIONS");
header("Access-Control-Allow-Headers:Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With,x_requested_with,x-token");
$action = $this->request->param();
$config = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents(root_path()."extend/utils/ueditor_config.json")), true);
//替换前台图片后缀
$config['imageUrlPrefix'] = Env::get('QINIU.cdn');
$config['scrawlUrlPrefix'] = Env::get('QINIU.cdn');
$config['snapscreenUrlPrefix'] = Env::get('QINIU.cdn');
$config['catcherUrlPrefix'] = Env::get('QINIU.cdn');
$config['videoUrlPrefix'] = Env::get('QINIU.cdn');
$config['fileUrlPrefix'] = Env::get('QINIU.cdn');
$config['imageManagerUrlPrefix'] = Env::get('QINIU.cdn');
$config['fileManagerUrlPrefix'] = Env::get('QINIU.cdn');
$action['action'] ?? $action['action'] = 'config';
switch ($action['action']) {
case 'uploadimage':
$fieldName = $config['imageFieldName'];
$config = [
"pathFormat" => $config['imagePathFormat'],
"maxSize" => $config['imageMaxSize'],
"allowFiles" => $config['imageAllowFiles']
];
break;
case 'uploadscrawl':
$fieldName = $config['scrawlFieldName'];
$config = [
"pathFormat" => $config['scrawlPathFormat'],
"maxSize" => $config['scrawlMaxSize'],
"allowFiles" => $config['scrawlAllowFiles'],
"oriName" => "scrawl.png"
];
break;
case 'uploadvideo':
$fieldName = $config['videoFieldName'];
$config = [
"pathFormat" => $config['videoPathFormat'],
"maxSize" => $config['videoMaxSize'],
"allowFiles" => $config['videoAllowFiles']
];
break;
case 'uploadfile':
$fieldName = $config['fileFieldName'];
$config = [
"pathFormat" => $config['filePathFormat'],
"maxSize" => $config['fileMaxSize'],
"allowFiles" => $config['fileAllowFiles']
];
break;
case 'config':
default:
echo isset($action['callback']) ? $action['callback'].'('.json_encode($config).')': '('.json_encode($config).')';die;
}
$up = new UEUploader($fieldName, $config);
$resultData = $up->getFileInfo();
if ($resultData['state'] == 'SUCCESS') {
//本地文件上传七牛云
$qn = new QiniuUploader();
$res = $qn->uploadLocalFile(public_path().$resultData['url'],$resultData['url']);
$data = [
"state" => "SUCCESS",
"title" => $resultData["title"],
"original" => $resultData["original"],
"type" => $resultData["type"],
"size" => $resultData["size"],
'cdn' => Env::get('QINIU.cdn'),
'filename' => explode('/',$res['filename'])[count(explode('/',$res['filename']))-1],
// 'url' => $res['remote_url'],
'url' => $res['filename'],
'relative_path' => $res['filename']
];
echo json_encode($data);die;
} else {
echo "上传失败";die;
}
}
/**
* 静态cdn域名
*/
public function getCDNUrl():\think\Response\Json
{
$data = [
'domain' => Env::get('QINIU.cdn','')
];
return $this->msg(200,'获取成功',$data);
}
/**
* Excel导入
*/
public function import():\think\Response\Json
{
$file = $this->request->file('file');
if (!$file) {
return $this->msg(-1,'没有上传文件');
}
// if ($this->commonValidate(__FUNCTION__,['file'=>$file])) {
// return json($this->message(true));
// }
$filename = Filesystem::disk('public')->putFile('', $file, 'unique_id');
$filePath = public_path().'storage/' . $filename;
if (!is_file($filePath)) {
return $this->msg(-1,'没找到数据');
}
//实例化reader
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
if (!in_array($ext, ['csv', 'xls', 'xlsx'])) {
return $this->msg(-1,'文件格式不对');
}
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
$table = $this->model->getTable();
$database = Env::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 $v) {
if ($this->importHeadType == 'comment') {
$fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME'];
} else {
$fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_NAME'];
}
}
//加载文件
$insert = [];
try {
if (!$PHPExcel = $reader->load($filePath)) {
return $this->msg(-1,'没找到数据');
}
$currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表
$allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号
$allRow = $currentSheet->getHighestRow(); //取得一共有多少行
$maxColumnNumber = Coordinate::columnIndexFromString($allColumn);
$fields = [];
for ($currentRow = 1; $currentRow <= 1; $currentRow++) {
for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
$fields[] = $val;
}
}
for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
$values = [];
for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
$val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
$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;
}
}
if ($row) {
$insert[] = $row;
}
}
//需要关联查询的字段,进行关联相询翻译
} catch (\Exception $exception) {
return $this->msg(-1,$exception->getMessage());
}
//批量新增
try {
$count = 0;
$failCount = 0;
// foreach ($insert as $item) {
// if ($this->commonValidate(__FUNCTION__,$item)) {
// $failCount++;
// continue;
// }
$res = $this->model->save($insert[0]);
// $count++;
// }
if (count($insert) > $count) {
return $this->msg(-1,'总共【'.count($insert).'】,成功导入【'.$count.'】条记录,还有【'.(count($insert) - $count).'】条记录未导入成功');
} else {
return $this->msg(200,'总共【'.count($insert).'】,成功导入【'.$count.'】条记录,有【'.(count($insert) - $count).'】条记录未导入成功');
}
} catch (PDOException $exception) {
$this->msg = $exception->getMessage();
if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $this->msg, $matches)) {
$this->msg = "导入失败,包含【{$matches[1]}】的记录已存在";
return $this->msg(-1,"导入失败,包含【{$matches[1]}】的记录已存在");
}
return $this->msg(-1,$exception->getMessage());
} catch (\Exception $e) {
return $this->msg(-1,$e->getMessage());
}
}
/**
* Excel导出,
* @param array $data
* @param int $count
* @param string $fileName
* @param array $options
* @return \think\Response\Json
*/
protected function excelExport(array $data = [], int $count = 10 ,string $fileName = '', array $options = []):\think\Response\Json
{
try {
if (empty($data)) {
return $this->msg(-1,'没有选择需要导出的数据');
}
set_time_limit(0);
$objSpreadsheet = new Spreadsheet();
//设置全局字体,大小
$styleArray = [
'font' => [
'bold' => false,
'color' => ['rgb'=>'000000'],
'size' => 14,
'name' => 'Verdana'
]
];
$objSpreadsheet->getDefaultStyle()->applyFromArray($styleArray);
/* 设置默认文字居左,上下居中 */
$styleArray = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_LEFT,
'vertical' => Alignment::VERTICAL_CENTER,
],
];
$objSpreadsheet->getDefaultStyle()->applyFromArray($styleArray);
/* 设置Excel Sheet */
$activeSheet = $objSpreadsheet->setActiveSheetIndex(0);
/* 打印设置 */
if (isset($options['print']) && $options['print']) {
/* 设置打印为A4效果 */
$activeSheet->getPageSetup()->setPaperSize(PageSetup:: PAPERSIZE_A4);
/* 设置打印时边距 */
$pValue = 1 / 2.54;
$activeSheet->getPageMargins()->setTop($pValue / 2);
$activeSheet->getPageMargins()->setBottom($pValue * 2);
$activeSheet->getPageMargins()->setLeft($pValue / 2);
$activeSheet->getPageMargins()->setRight($pValue / 2);
}
$row = 2;
$col = 0;
/* 行数据处理 */
foreach ($data as $sKey => $sItem) {
/* 默认文本格式 */
$pDataType = DataType::TYPE_STRING;
/* 设置单元格格式 */
if (isset($options['format']) && !empty($options['format'])) {
$colRow = Coordinate::coordinateFromString($sKey);
/* 存在该列格式并且有特殊格式 */
if (isset($options['format'][$colRow[0]]) &&
NumberFormat::FORMAT_GENERAL != $options['format'][$colRow[0]]) {
$activeSheet->getStyle($sKey)->getNumberFormat()
->setFormatCode($options['format'][$colRow[0]]);
if (false !== strpos($options['format'][$colRow[0]], '0.00') &&
is_numeric(str_replace(['¥', ','], '', $sItem))) {
/* 数字格式转换为数字单元格 */
$pDataType = DataType::TYPE_NUMERIC;
$sItem = str_replace(['¥', ','], '', $sItem);
}
} elseif (is_int($sItem)) {
$pDataType = DataType::TYPE_NUMERIC;
}
}
if ($col < count($options['alignCenter'])) {
if (strlen($sItem) <= 255) {
$activeSheet->getColumnDimension($options['alignCenter'][$col])->setWidth(100);
} else {
$activeSheet->getColumnDimension($options['alignCenter'][$col])->setAutoSize(true);
}
}
$activeSheet->getRowDimension($row)->setRowHeight(30);
$activeSheet->setCellValueExplicit($sKey, $sItem, $pDataType);
$row++;
$col++;
/* 存在:形式的合并行列,列入A1:B2,则对应合并 */
if (false !== strstr($sKey, ":")) {
$options['mergeCells'][$sKey] = $sKey;
}
if (is_image(public_path().$sItem) && file_exists(public_path().$sItem)) {
$activeSheet->setCellValueExplicit($sKey, '', $pDataType);
$drawing = new Drawing();
$drawing->setName('Logo');
$drawing->setDescription('Logo');
$drawing->setPath(Env::get('root_path').'public'.$sItem);
$drawing->setResizeProportional(false);
$drawing->setHeight(60);
$drawing->setCoordinates($sKey);
$drawing->setOffsetX(12);
$drawing->setOffsetY(12);
$drawing->getShadow()->setVisible(true);
// $drawing->getShadow()->setDirection(45);
$drawing->setWorksheet($objSpreadsheet->getActiveSheet());
}
}
unset($data);
/* 设置锁定行 */
if (isset($options['freezePane']) && !empty($options['freezePane'])) {
$activeSheet->freezePane($options['freezePane']);
unset($options['freezePane']);
}
/* 设置宽度 */
if (isset($options['setWidth']) && !empty($options['setWidth'])) {
foreach ($options['setWidth'] as $swKey => $swItem) {
$activeSheet->getColumnDimension($swKey)->setWidth($swItem);
}
unset($options['setWidth']);
} else {
$end = $count + 64 > 80 ? 80 : $count + 64;
foreach(range(chr(65),chr($end)) as $columnID) {
$activeSheet->getColumnDimension($columnID)->setAutoSize(true);
}
}
/* 设置背景色 */
if (isset($options['setARGB']) && !empty($options['setARGB'])) {
foreach ($options['setARGB'] as $sItem) {
$activeSheet->getStyle($sItem)
->getFill()->setFillType(Fill::FILL_SOLID)
->getStartColor()->setARGB(Color::COLOR_YELLOW);
}
unset($options['setARGB']);
}
/* 设置公式 */
if (isset($options['formula']) && !empty($options['formula'])) {
foreach ($options['formula'] as $fKey => $fItem) {
$activeSheet->setCellValue($fKey, $fItem);
}
unset($options['formula']);
}
/* 合并行列处理 */
if (isset($options['mergeCells']) && !empty($options['mergeCells'])) {
$activeSheet->setMergeCells($options['mergeCells']);
unset($options['mergeCells']);
}
/* 设置居中 */
if (isset($options['alignCenter']) && !empty($options['alignCenter'])) {
$styleArray = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_LEFT,
'vertical' => Alignment::VERTICAL_CENTER,
],
];
foreach ($options['alignCenter'] as $acItem) {
$activeSheet->getStyle($acItem)->applyFromArray($styleArray);
}
unset($options['alignCenter']);
}
/* 设置加粗 */
if (isset($options['bold']) && !empty($options['bold'])) {
foreach ($options['bold'] as $bItem) {
$activeSheet->getStyle($bItem)->getFont()->setBold(true);
}
unset($options['bold']);
}
/* 设置单元格边框,整个表格设置即可,必须在数据填充后才可以获取到最大行列 */
if (isset($options['setBorder']) && $options['setBorder']) {
$border = [
'borders' => [
'allBorders' => [
'borderStyle' => Border::BORDER_THIN, // 设置border样式
'color' => ['argb' => 'FF000000'], // 设置border颜色
],
],
];
$setBorder = 'A1:' . $activeSheet->getHighestColumn() . $activeSheet->getHighestRow();
$activeSheet->getStyle($setBorder)->applyFromArray($border);
unset($options['setBorder']);
}
$fileName = !empty($fileName) ? $fileName : (date('YmdHis') . '.xlsx');
if (!isset($options['savePath'])) {
/* 直接导出Excel,无需保存到本地,输出07Excel文件 */
header('Content-Type: application/vnd.ms-excel,application/x-rar-compressed,application/vnd.openxmlformats-officedocument.wordprocessingml.document; Charset=UTF-8');
header('Access-Control-Expose-Headers: Content-Disposition');
// header(
// "Content-Disposition:attachment;filename=" . iconv(
// "utf-8", "GB2312//TRANSLIT", $fileName
// )
// );
header("Content-Disposition:attachment;filename=" . $fileName);
header('Cache-Control: max-age=0');//禁止缓存
header("Content-Transfer-Encoding:binary");
$savePath = 'php://output';
} else {
$savePath = $options['savePath'];
}
ob_clean();
ob_start();
$objWriter = IOFactory::createWriter($objSpreadsheet, 'Xlsx');
$objWriter->save($savePath);
/* 释放内存 */
$objSpreadsheet->disconnectWorksheets();
unset($objSpreadsheet);
ob_end_flush();
exit;
} catch (\Exception $e) {
return $this->msg(-1,$e->getMessage());
}
}
/**
* 表格导出数据前置方法
*/
public function export():\think\Response\Json
{
$ids = $this->request->param();
if ($this->commonValidate(__FUNCTION__,$ids)) {
return $this->msg(-1,'');
}
$data = $this->model->getExportData($ids);
//导入文件首行类型,默认是注释,如果需要使用字段名称请使用name
$this->importHeadType = 'name';
$table = $this->model->getTable();
$database = Env::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 $v) {
if ($this->importHeadType == 'comment') {
$fieldArr[$v['COLUMN_COMMENT']] = $v['COLUMN_NAME'];
} else {
$fieldArr[$v['COLUMN_NAME']] = $v['COLUMN_COMMENT'];
}
}
$newData = [];/*表格数据*/
$newHeader = [];/*表格表头*/
$cols = []; /*分别占用表格哪几列*/
if (array_key_exists(0,$data)) {
$header = array_keys($data[0]);
foreach ($header as $k => $v) {
if ($k <= 25) {
$newHeader[chr($k+65).'1'] = $fieldArr[$v]?:$v;
$cols[$k] = chr($k+65);
} else {
$newHeader[chr(65).chr($k-26+65).'1'] = $fieldArr[$v]?:$v;
$cols[$k] = chr(65).chr($k-26+65);
}
}
}
foreach ($data as $k => $v) {
$index = 0;
foreach ($v as $v1) {
if ($index <= 25) {
$header = chr($index+65);
$header .= $k+2;
$newData[$header] = $v1;/*获取表头*/
} else {
$header = chr(65).chr($index-26+65);
$header .= $k+2;
$newData[$header] = $v1;/*获取表头*/
}
$index++;
}
}
$newData = array_merge($newHeader,$newData);
$options = [
'print' =>false,
'freezePane'=>'A2',
// 'setWidth'=>['A'=>40,'B'=>30,'C'=>20,'D'=>25,'E'=>20,'F'=>15,'G'=>10,'H'=>10],
'setBorder'=>true,
'alignCenter'=>$cols,
'bold'=>array_keys($newHeader),
];
return $this->excelExport($newData,count($newHeader),'export-excel-'.time().'.xlsx',$options);
}
/**
* 异步提交
* @param array $apiLog 日志提交的数据
* @param string $logType 日志类型 api_logs
* @param string $type 请求类型 api add queue
* @return string
*/
public function asyncApiLog(array $apiLog, string $logType, string $type):string
{
// 异步执行
// Async::exec(LogToKafka::class, 'sendLogsToKafkaProduce', $apiLog,$logType,'user',$type);
// Async::execUseCustomQueue(self::class, 'test','async_exec_method_custom', 'exec');
// 异步延迟执行 延迟20秒
Async::delay(20, LogToKafka::class, 'sendLogsToKafkaProduce', $apiLog,$logType,Env::get('database.database'),$type);
// Async::delayUseCustomQueue(20, LogToKafka::class, 'sendLogsToKafkaProduce','async_exec_method_custom', $apiLog,$logType,Env::get('database.database'),$type);
return '';
}
/**
* 写入日志调试信息
* @param array $data
* @param string $string
* @return void
*/
public function dLog(array $data,string $string = 'debug') : void
{
\think\facade\Log::record($string . " = ".json_encode($data));
}
}