1139 lines
44 KiB
PHP
1139 lines
44 KiB
PHP
<?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));
|
||
}
|
||
}
|