作者 赵彬吉

update

... ... @@ -17,3 +17,4 @@ yarn-error.log
composer.lock
app/Console/Commands/Test/Demo.php
/public/upload
/public/runtime
... ...
... ... @@ -2,11 +2,16 @@
namespace App\Http\Controllers\Bside;
use App\Exceptions\BsideGlobalException;
use App\Helper\Arr;
use App\Http\Logic\Bside\InquiryLogic;
use App\Http\Requests\Bside\InquiryRequest;
use App\Rules\Ids;
use App\Services\BatchExportService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\ValidationException;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
/**
* 精准询盘
... ... @@ -51,4 +56,41 @@ class InquiryController extends BaseController
return $this->success($data);
}
/**
* 导出
* @param InquiryLogic $logic
* @return \Illuminate\Http\JsonResponse
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @author zbj
* @date 2023/5/8
*/
public function export(InquiryLogic $logic)
{
$sort = ['id' => 'desc'];
//最多到1w条
$data = $logic->getList([], $sort, ['name', 'email', 'phone', 'url', 'ip', 'ip_country', 'content', 'created_at'], 10000);
$data = $data['list'] ?? [];
foreach ($data as &$item){
$item['ip_address'] = "{$item['ip_country']}({$item['ip']})";
}
$map = [
'created_at' => '询盘发送时间',
'name' => '姓名',
'email' => '邮箱',
'phone' => '电话',
'ip_address' => '访问国家/地区(IP)',
'url' => '发送页面',
'content' => '询盘内容',
];
//生成文件,发送到客户端
$table = new BatchExportService("询盘数据导出");
$file = $table->head($map)->data($data)->save();
if (!$file) {
throw new \Exception('路由不能为空');
}
$fileurl = Storage::disk('runtime')->url($file);
return $this->success(['url' => $fileurl]);
}
}
... ...
... ... @@ -25,11 +25,6 @@ class RouteController extends BaseController
$source_id = $request->input('source_id');
$project_id = $this->user['project_id'];
//有中文先翻译
if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $title)){
$title = Translate::tran($title, 'en');
}
$route = RouteMap::generateRoute($title, $source, $source_id, $project_id);
return $this->success(['route' => $route]);
}
... ...
... ... @@ -2,6 +2,7 @@
namespace App\Models;
use App\Helper\Translate;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
... ... @@ -36,6 +37,11 @@ class RouteMap extends Model
* @date 2023/4/17
*/
public static function generateRoute($title, $source, $source_id, $project_id){
//有中文先翻译
if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $title)){
$title = Translate::tran($title, 'en');
}
$i=1;
$sign = generateRoute($title);
$route = $sign;
... ...
<?php
namespace App\Services;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
/**
* 批量导出
* Class BatchExportService
* @package App\Services
* @author zbj
* @date 2023/5/8
*/
class BatchExportService
{
private $name = '';
/**
* @var array
*/
private $data = [];
/**
* @var null | \PhpOffice\PhpSpreadsheet\Spreadsheet;
*/
private $spreadsheet = null;
/**
* 包头与字段映射
* @var array
*/
private $head = [];
public function __construct($name)
{
$this->name = $name;
$this->spreadsheet = new Spreadsheet();
$this->spreadsheet->setActiveSheetIndex(0);
}
/**
* config hook
* @param $callback
* @return $this
* @throws \PhpOffice\PhpSpreadsheet\Exception
*/
public function config($callback)
{
if(is_callable($callback)) {
$callback($this->spreadsheet->getActiveSheet(),$this->spreadsheet);
}
return $this;
}
/**
* 设置表头
* @param array $data
* @return $this
*/
public function head($map = [])
{
$this->head = $map;
return $this;
}
/**
* @param $data
* @return $this
*/
public function data($data)
{
$this->data = $data;
return $this;
}
/**
* @return false|string
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
* @author zbj
* @date 2023/5/8
*/
public function save()
{
$file = "runtime/export/".date('Y-m-d')."/{$this->name}_" . date('YmdHis') . ".xlsx";
$filename = public_path($file);
if (!is_dir(dirname($filename))) {
@mkdir(dirname($filename),0755, true);
}
$this->render();
$writer = new Xlsx($this->spreadsheet);
$writer->save($filename);
if(file_exists($filename) && filesize($filename)) {
return $file;
}
return false;
}
/**
* 进行数据渲染
* 遍历所有的单元格处理文件,进行数据处理
* @return $this
* @author zbj
* @date 2023/5/8
*/
protected function render()
{
$map = [];
$sheet = $this->spreadsheet->getActiveSheet();
$i = 0;
foreach ($this->head as $k=>$title) {
$chr = chr(65+$i);
$map[$chr] = $k;
if(is_array($title)) {
$title = $title[0];
}
$sheet->setCellValue($chr . "1", $title);
$i++;
}
foreach ($this->data as $k=>$item) {
foreach ($map as $chr => $field) {
if(is_array($this->head[$field]) && is_callable($this->head[$field][1])) { //TODO 进行字段内容的处理
$this->head[$field][1]($sheet, $chr . ($k + 2), $item[$field]);
}
$sheet->setCellValue($chr . ($k + 2), $this->getDataValue($field, $item));
}
}
return $this;
}
/**
* 读取指定字段的value, 支持"."形式指定多维数组
* @param $name
* @param $data
* @return mixed|null
* @author zbj
* @date 2023/5/8
*/
protected function getDataValue($name, $data)
{
if(false === strpos($name, '.')) {
return $data[$name] ?? null;
}
$name = explode('.', $name);
$name[0] = strtolower($name[0]);
// 按.拆分成多维数组进行判断
foreach ($name as $val) {
if (isset($data[$val])) {
$data = $data[$val];
} else {
$data = null;
break;
}
}
return $data;
}
}
... ...
... ... @@ -13,7 +13,8 @@
"intervention/image": "^2.7",
"laravel/framework": "^8.75",
"laravel/sanctum": "^2.11",
"laravel/tinker": "^2.5"
"laravel/tinker": "^2.5",
"phpoffice/phpspreadsheet": "^1.28"
},
"require-dev": {
"facade/ignition": "^2.5",
... ...
... ... @@ -58,7 +58,17 @@ return [
'root' => env('UPLOAD_ROOT_PATH') ?: public_path('upload'),
'url' => env('UPLOAD_LOCAL_URL') ?: env('APP_URL') . '/upload',
'visibility' => 'public',
]
],
'runtime' => [
'driver' => 'local',
'root' => public_path('runtime'),
'url' => env('APP_URL'),
'visibility' => 'public',
],
],
... ...
... ... @@ -187,6 +187,7 @@ Route::middleware(['bloginauth'])->group(function () {
Route::get('/', [\App\Http\Controllers\Bside\InquiryController::class, 'index'])->name('inquiry');
Route::get('/info', [\App\Http\Controllers\Bside\InquiryController::class, 'info'])->name('inquiry_info');
Route::any('/delete', [\App\Http\Controllers\Bside\InquiryController::class, 'delete'])->name('inquiry_delete');
Route::any('/export', [\App\Http\Controllers\Bside\InquiryController::class, 'export'])->name('inquiry_export');
});
//生成路由
... ...