Merge branch 'dev'
This commit is contained in:
@@ -4,6 +4,7 @@ namespace app\common\controller;
|
|||||||
use app\common\controller\BaseController;
|
use app\common\controller\BaseController;
|
||||||
use app\common\model\UsedCar;
|
use app\common\model\UsedCar;
|
||||||
use app\common\model\UsedCarPdfLog;
|
use app\common\model\UsedCarPdfLog;
|
||||||
|
use app\common\model\User;
|
||||||
use app\common\service\OssService;
|
use app\common\service\OssService;
|
||||||
use app\common\traits\crud\CrudControllerTrait;
|
use app\common\traits\crud\CrudControllerTrait;
|
||||||
use app\common\service\UsedCarService;
|
use app\common\service\UsedCarService;
|
||||||
@@ -138,8 +139,14 @@ class UsedCarController extends BaseController
|
|||||||
}
|
}
|
||||||
$data['attachment'] = $attachments;
|
$data['attachment'] = $attachments;
|
||||||
$data['price'] = $price;
|
$data['price'] = $price;
|
||||||
|
$user = User::where('id',$request->user['id'])->first();
|
||||||
$pdf = (new MpdfDriver())->exportUsedCarPdf($data);
|
$contact = $user['email'] ?? $user['phone'] ?? $user['whatsapp'] ?? null;
|
||||||
|
if(!empty($user['social_code'])){
|
||||||
|
$ossService = new OssService();
|
||||||
|
$user['social_code'] = $ossService->generatePrivateUrl($user['social_code']);
|
||||||
|
$user['social_code'] = $this->service->downloadImage($user['social_code']);
|
||||||
|
}
|
||||||
|
$pdf = (new MpdfDriver())->exportUsedCarPdf($data,$user,$contact);
|
||||||
UsedCar::where('id', $data['id'])->update(['pdf_src' => $pdf]);
|
UsedCar::where('id', $data['id'])->update(['pdf_src' => $pdf]);
|
||||||
|
|
||||||
array_map('unlink', glob(runtime_path('pdf/images/*.jpg')));
|
array_map('unlink', glob(runtime_path('pdf/images/*.jpg')));
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
namespace app\common\controller;
|
namespace app\common\controller;
|
||||||
|
|
||||||
use app\common\controller\BaseController;
|
use app\common\controller\BaseController;
|
||||||
|
use app\common\service\OssService;
|
||||||
use app\common\traits\crud\CrudControllerTrait;
|
use app\common\traits\crud\CrudControllerTrait;
|
||||||
use app\common\service\UserService;
|
use app\common\service\UserService;
|
||||||
|
use support\Request;
|
||||||
|
|
||||||
class UserController extends BaseController
|
class UserController extends BaseController
|
||||||
{
|
{
|
||||||
@@ -30,4 +32,66 @@ class UserController extends BaseController
|
|||||||
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||||
// return $data;
|
// return $data;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
*
|
||||||
|
* @param Request $request 请求对象
|
||||||
|
* @return mixed 返回更新成功的数据或信息
|
||||||
|
*/
|
||||||
|
public function edit(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->post();
|
||||||
|
$request->setPost('id',$request->user['id']);
|
||||||
|
$res = $this->service->serviceUpdate($request, $data);
|
||||||
|
return $this->success([], '更新成功');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取详情
|
||||||
|
*
|
||||||
|
* @param Request $request 请求对象
|
||||||
|
* @param int|string $id 资源 ID
|
||||||
|
* @return mixed 返回资源详情数据
|
||||||
|
*/
|
||||||
|
public function show(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$request->setGet('id',$request->user['id']);
|
||||||
|
$raw = $this->service->serviceShow($request);
|
||||||
|
$data = $this->transformData($raw, method_exists($this, 'showFormat')
|
||||||
|
? [$this, 'showFormat']
|
||||||
|
: null);
|
||||||
|
return $this->success($data);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return $this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表页数据格式化
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function showFormat($data)
|
||||||
|
{
|
||||||
|
if (isset($data['created_at']))
|
||||||
|
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||||
|
if (isset($data['updated_at']))
|
||||||
|
$data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||||
|
unset($data['union_id']);
|
||||||
|
unset($data['app_id']);
|
||||||
|
|
||||||
|
$ossservice = new OssService();
|
||||||
|
$data['user']['avatar_pull'] = $data['user']['avatar'];
|
||||||
|
if(!str_contains($data['user']['avatar'], 'http') && !str_contains($data['user']['avatar'], 'www.') && !empty($data['user']['avatar'])){
|
||||||
|
$data['user']['avatar_pull'] = $ossservice->generatePrivateUrl($data['user']['avatar']);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -218,10 +218,12 @@ class AuthLogic
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Log::info('userInfo:' ,[$userInfo]);
|
||||||
User::firstOrCreate(['union_id'=>$userInfo['data']['union_id']],[
|
User::firstOrCreate(['union_id'=>$userInfo['data']['union_id']],[
|
||||||
'union_id'=>$userInfo['data']['union_id'],
|
'union_id'=>$userInfo['data']['union_id'],
|
||||||
'name'=>$userInfo['data']['name'],
|
'name'=>$userInfo['data']['name'],
|
||||||
'app_id'=>$data['app_id']
|
'app_id'=>$data['app_id'],
|
||||||
|
'avatar'=>$userInfo['avatar_url']
|
||||||
]);
|
]);
|
||||||
return $userInfo['data'] + $data;
|
return $userInfo['data'] + $data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class UsedCar extends Model
|
|||||||
/**
|
/**
|
||||||
* 允许自动填充模型字段
|
* 允许自动填充模型字段
|
||||||
*/
|
*/
|
||||||
protected $fillable = ['id', 'user_id', 'product_name', 'vin', 'price', 'source_place', 'plate_place', 'plate_time', 'displacement','mileage','power', 'body_color', 'images', 'condition_desc', 'attachment', 'crawl_title', 'crawl_brand', 'crawl_series', 'crawl_year', 'crawl_msrp', 'crawl_car_id', 'status', 'sort', 'created_at', 'updated_at'];
|
protected $fillable = ['id','code', 'user_id', 'product_name', 'vin', 'price', 'source_place', 'plate_place', 'plate_time', 'displacement','mileage','power', 'body_color', 'images', 'condition_desc', 'attachment', 'crawl_title', 'crawl_brand', 'crawl_series', 'crawl_year', 'crawl_msrp', 'crawl_car_id', 'status', 'sort', 'created_at', 'updated_at'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不允许自动填充模型字段
|
* 不允许自动填充模型字段
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class User extends Model
|
|||||||
/**
|
/**
|
||||||
* 允许自动填充模型字段
|
* 允许自动填充模型字段
|
||||||
*/
|
*/
|
||||||
protected $fillable = ['id', 'union_id', 'app_id', 'name'];
|
protected $fillable = ['id', 'union_id', 'app_id', 'name', 'avatar', 'phone', 'email', 'whatsapp', 'social', 'social_code'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不允许自动填充模型字段
|
* 不允许自动填充模型字段
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use GuzzleHttp\Client;
|
|||||||
use support\exception\BusinessException;
|
use support\exception\BusinessException;
|
||||||
use support\Log;
|
use support\Log;
|
||||||
use support\Request;
|
use support\Request;
|
||||||
|
use app\common\model\User;
|
||||||
|
|
||||||
class UsedCarService
|
class UsedCarService
|
||||||
{
|
{
|
||||||
@@ -85,24 +86,93 @@ class UsedCarService
|
|||||||
|
|
||||||
public function beforeServiceStore($data, Request $request): array
|
public function beforeServiceStore($data, Request $request): array
|
||||||
{
|
{
|
||||||
if(empty($data['product_name'])){
|
if (empty($data['product_name'])) {
|
||||||
throw new BusinessException('产品名称不能为空');
|
throw new BusinessException('产品名称不能为空');
|
||||||
}
|
}
|
||||||
if(empty($data['images'])){
|
if (empty($data['images'])) {
|
||||||
throw new BusinessException('产品图片不能为空');
|
throw new BusinessException('产品图片不能为空');
|
||||||
}
|
}
|
||||||
if(empty($data['price'])){
|
if (empty($data['price'])) {
|
||||||
$data['price'] = 0;
|
$data['price'] = 0;
|
||||||
}
|
}
|
||||||
if(!empty($data['attachment'])){
|
if (!empty($data['attachment'])) {
|
||||||
$data['attachment'] = json_encode($data['attachment']);
|
$data['attachment'] = json_encode($data['attachment']);
|
||||||
}else{
|
}else{
|
||||||
$data['attachment'] = '';
|
$data['attachment'] = '';
|
||||||
}
|
}
|
||||||
$data['user_id'] = $request->user['id'];
|
$data['user_id'] = $request->user['id'];
|
||||||
|
$data['code'] = $this->getcode($request->user['id']);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getcode($userId){
|
||||||
|
$todayStart = strtotime('today');
|
||||||
|
$count = UsedCar::where('user_id',$userId)->where('created_at','>=',$todayStart)->count();
|
||||||
|
$countCode = str_pad($count, 3, '0', STR_PAD_LEFT);
|
||||||
|
$userCode = str_pad($userId, 3, '0', STR_PAD_LEFT);
|
||||||
|
$user = User::where('id',$userId)->first();
|
||||||
|
$nameInitials = $this->getNameInitials($user['name']);
|
||||||
|
return $nameInitials . $userCode . date('Ymd') . $countCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取中文名拼音首字母
|
||||||
|
*/
|
||||||
|
function getNameInitials(string $name): string
|
||||||
|
{
|
||||||
|
$initials = '';
|
||||||
|
$len = mb_strlen($name);
|
||||||
|
for ($i = 0; $i < $len; $i++) {
|
||||||
|
$char = mb_substr($name, $i, 1);
|
||||||
|
$initials .= $this->getFirstChar($char);
|
||||||
|
}
|
||||||
|
return strtoupper($initials);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirstChar(string $char): string
|
||||||
|
{
|
||||||
|
$s = iconv('UTF-8', 'GB2312//IGNORE', $char);
|
||||||
|
$asc = ord($s[0]);
|
||||||
|
|
||||||
|
if ($asc >= 65 && $asc <= 90) return $char;
|
||||||
|
|
||||||
|
$code = ord($s[0]) * 256 + ord($s[1]) - 65536;
|
||||||
|
|
||||||
|
$map = [
|
||||||
|
[-20319, -20284, 'A'],
|
||||||
|
[-20283, -19776, 'B'],
|
||||||
|
[-19775, -19219, 'C'],
|
||||||
|
[-19218, -18711, 'D'],
|
||||||
|
[-18710, -18527, 'E'],
|
||||||
|
[-18526, -18240, 'F'],
|
||||||
|
[-18239, -17923, 'G'],
|
||||||
|
[-17922, -17418, 'H'],
|
||||||
|
[-17417, -16475, 'J'],
|
||||||
|
[-16474, -16213, 'K'],
|
||||||
|
[-16212, -15641, 'L'],
|
||||||
|
[-15640, -15166, 'M'],
|
||||||
|
[-15165, -14923, 'N'],
|
||||||
|
[-14922, -14915, 'O'],
|
||||||
|
[-14914, -14631, 'P'],
|
||||||
|
[-14630, -14150, 'Q'],
|
||||||
|
[-14149, -14091, 'R'],
|
||||||
|
[-14090, -13319, 'S'],
|
||||||
|
[-13318, -12839, 'T'],
|
||||||
|
[-12838, -12557, 'W'],
|
||||||
|
[-12556, -11848, 'X'],
|
||||||
|
[-11847, -11056, 'Y'],
|
||||||
|
[-11055, -10247, 'Z']
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($map as [$start, $end, $letter]) {
|
||||||
|
if ($code >= $start && $code <= $end) {
|
||||||
|
return $letter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,30 +192,30 @@ class UsedCarService
|
|||||||
$href = $crawlService->modelSearch($keyword);
|
$href = $crawlService->modelSearch($keyword);
|
||||||
$seriesId = $this->extractSeriesId($href); //懂车帝车系id
|
$seriesId = $this->extractSeriesId($href); //懂车帝车系id
|
||||||
|
|
||||||
// if (empty($seriesId)) { //没有抓取到懂车帝系列id时,按关键词为品牌名抓取所有的系列名
|
// if (empty($seriesId)) { //没有抓取到懂车帝系列id时,按关键词为品牌名抓取所有的系列名
|
||||||
// $crawlSeries = $crawlService->brandSeries($keyword);
|
// $crawlSeries = $crawlService->brandSeries($keyword);
|
||||||
// }
|
// }
|
||||||
//按关键词为品牌名抓取所有的系列名
|
//按关键词为品牌名抓取所有的系列名
|
||||||
// $crawlSeries = $crawlService->brandSeries($keyword);
|
// $crawlSeries = $crawlService->brandSeries($keyword);
|
||||||
|
|
||||||
if (empty($seriesId)) {
|
if (empty($seriesId)) {
|
||||||
throw new \Exception('抓取失败,请使用更精确的关键词');
|
throw new \Exception('抓取失败,请使用更精确的关键词');
|
||||||
}
|
}
|
||||||
|
|
||||||
// $brandSerieses = [];
|
// $brandSerieses = [];
|
||||||
// if(empty($seriesId) && !empty($crawlSeries) || count($crawlSeries)>1){ //关键词为品牌名时抓取所有车系的懂车帝id
|
// if(empty($seriesId) && !empty($crawlSeries) || count($crawlSeries)>1){ //关键词为品牌名时抓取所有车系的懂车帝id
|
||||||
// $href = $crawlService->modelSearch($crawlSeries[0]);
|
// $href = $crawlService->modelSearch($crawlSeries[0]);
|
||||||
// $seriesId = $this->extractSeriesId($href); //懂车帝车系id
|
// $seriesId = $this->extractSeriesId($href); //懂车帝车系id
|
||||||
// //抓取品牌与系列
|
// //抓取品牌与系列
|
||||||
// $brandSeries = $crawlService->crawlBrandSeries($seriesId);
|
// $brandSeries = $crawlService->crawlBrandSeries($seriesId);
|
||||||
// foreach ($crawlSeries as $item) {
|
// foreach ($crawlSeries as $item) {
|
||||||
//// $brandSerieses[] = $crawlService->brandSeries($keyword);
|
//// $brandSerieses[] = $crawlService->brandSeries($keyword);
|
||||||
// $brandSerieses[] = ['brand' => $brandSeries['brand'], 'series' => $item];
|
// $brandSerieses[] = ['brand' => $brandSeries['brand'], 'series' => $item];
|
||||||
// }
|
// }
|
||||||
// }elseif (!empty($seriesId) && empty($crawlSeries)){
|
// }elseif (!empty($seriesId) && empty($crawlSeries)){
|
||||||
// //抓取品牌与系列
|
// //抓取品牌与系列
|
||||||
// $brandSerieses[] = $crawlService->crawlBrandSeries($seriesId);
|
// $brandSerieses[] = $crawlService->crawlBrandSeries($seriesId);
|
||||||
// }
|
// }
|
||||||
//抓取品牌与系列
|
//抓取品牌与系列
|
||||||
$brandSerieses[] = $crawlService->crawlBrandSeries($seriesId);
|
$brandSerieses[] = $crawlService->crawlBrandSeries($seriesId);
|
||||||
|
|
||||||
@@ -158,7 +228,7 @@ class UsedCarService
|
|||||||
|
|
||||||
//获取车型数据
|
//获取车型数据
|
||||||
$item['model'] = [];
|
$item['model'] = [];
|
||||||
if (count($brandSerieses)<2) {
|
if (count($brandSerieses) < 2) {
|
||||||
$item['model'] = $this->crawlSeriesModel($seriesId);
|
$item['model'] = $this->crawlSeriesModel($seriesId);
|
||||||
}
|
}
|
||||||
$result[] = $item;
|
$result[] = $item;
|
||||||
@@ -189,30 +259,30 @@ class UsedCarService
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
$data = json_decode($response->getBody()->getContents(), true);
|
$data = json_decode($response->getBody()->getContents(), true);
|
||||||
if($data['status'] != 0 || (!isset($data['data']) && !isset($data['data']['tab_list']))){
|
if ($data['status'] != 0 || (!isset($data['data']) && !isset($data['data']['tab_list']))) {
|
||||||
Log::error('抓取车型数据失败' . $data['message'], $data);
|
Log::error('抓取车型数据失败' . $data['message'], $data);
|
||||||
throw new \Exception('抓取车型数据失败' . $data['message']);
|
throw new \Exception('抓取车型数据失败' . $data['message']);
|
||||||
}
|
}
|
||||||
$models = [];
|
$models = [];
|
||||||
foreach ($data['data']['tab_list'] as $item) {
|
foreach ($data['data']['tab_list'] as $item) {
|
||||||
if($item['tab_text'] == '在售' || $item['tab_text'] == '停售'){
|
if ($item['tab_text'] == '在售' || $item['tab_text'] == '停售') {
|
||||||
unset($item['data'][0]);
|
unset($item['data'][0]);
|
||||||
$models = array_merge($models, $item['data']);
|
$models = array_merge($models, $item['data']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($models as $key => $model) {
|
foreach ($models as $key => $model) {
|
||||||
if(!isset($model["info"]['car_name']) || $model['type'] != "1115"){
|
if (!isset($model["info"]['car_name']) || $model['type'] != "1115") {
|
||||||
unset($models[$key]);
|
unset($models[$key]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$official_price = 0;
|
$official_price = 0;
|
||||||
if(!isset($model["info"]['official_price'])){
|
if (!isset($model["info"]['official_price'])) {
|
||||||
$official_price = (int)(str_replace("万", "", $model["info"]['official_price_str']) * 10000) ?? 0;
|
$official_price = (int)(str_replace("万", "", $model["info"]['official_price_str']) * 10000) ?? 0;
|
||||||
}else{
|
} else {
|
||||||
$official_price = $model["info"]['official_price'] * 10000;
|
$official_price = $model["info"]['official_price'] * 10000;
|
||||||
}
|
}
|
||||||
$models[$key] = [
|
$models[$key] = [
|
||||||
'title' => $model["info"]['year'] . '款 ' .$model["info"]['car_name'],
|
'title' => $model["info"]['year'] . '款 ' . $model["info"]['car_name'],
|
||||||
'brand_id' => $model["info"]['brand_id'],
|
'brand_id' => $model["info"]['brand_id'],
|
||||||
'brand_name' => $model["info"]['brand_name'],
|
'brand_name' => $model["info"]['brand_name'],
|
||||||
'series_id' => $model["info"]['series_id'],
|
'series_id' => $model["info"]['series_id'],
|
||||||
@@ -224,7 +294,6 @@ class UsedCarService
|
|||||||
}
|
}
|
||||||
|
|
||||||
return array_values($models);
|
return array_values($models);
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \Exception($e->getMessage());
|
throw new \Exception($e->getMessage());
|
||||||
}
|
}
|
||||||
@@ -235,7 +304,8 @@ class UsedCarService
|
|||||||
* @param string $url 完整的URL
|
* @param string $url 完整的URL
|
||||||
* @return string|null series ID或null
|
* @return string|null series ID或null
|
||||||
*/
|
*/
|
||||||
function extractSeriesId($url) {
|
function extractSeriesId($url)
|
||||||
|
{
|
||||||
// 解析URL获取路径部分
|
// 解析URL获取路径部分
|
||||||
$path = parse_url($url, PHP_URL_PATH);
|
$path = parse_url($url, PHP_URL_PATH);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace app\common\service;
|
|||||||
use app\common\validate\UserValidate;
|
use app\common\validate\UserValidate;
|
||||||
use app\common\traits\crud\CrudServiceTrait;
|
use app\common\traits\crud\CrudServiceTrait;
|
||||||
use app\common\model\User;
|
use app\common\model\User;
|
||||||
|
use support\Request;
|
||||||
|
|
||||||
class UserService
|
class UserService
|
||||||
{
|
{
|
||||||
@@ -28,4 +29,12 @@ class UserService
|
|||||||
{
|
{
|
||||||
return new $this->validator;
|
return new $this->validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function beforeServiceUpdate($data, Request $request){
|
||||||
|
unset($data['union_id']);
|
||||||
|
unset($data['app_id']);
|
||||||
|
unset($data['name']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ class MpdfDriver
|
|||||||
return [$css, $html];
|
return [$css, $html];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function exportUsedCarPdf($car)
|
public function exportUsedCarPdf($car,$user,$contact)
|
||||||
{
|
{
|
||||||
/*$car = [
|
/*$car = [
|
||||||
'title' => '奥迪Q3 2013款 35 TFSI 舒适型',
|
'title' => '奥迪Q3 2013款 35 TFSI 舒适型',
|
||||||
@@ -154,12 +154,35 @@ class MpdfDriver
|
|||||||
'default_font' => 'sun-exta'
|
'default_font' => 'sun-exta'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$mpdf->SetProtection(//限制篡改或盗用
|
||||||
|
['print'], // 允许的权限 copy:允许复制、print:允许打印
|
||||||
|
'', // 用户密码(可留空)
|
||||||
|
'Admin@2026@!#' // 拥有者密码(一定要设置)
|
||||||
|
);
|
||||||
|
|
||||||
|
//设置水印
|
||||||
|
$mpdf->SetWatermarkText(
|
||||||
|
$user['name'] .' '. $contact,
|
||||||
|
0.08
|
||||||
|
);
|
||||||
|
$mpdf->showWatermarkText = true;
|
||||||
|
|
||||||
|
// 1️⃣ 车辆基本信息 HTML
|
||||||
$mpdf->WriteHTML($html);
|
$mpdf->WriteHTML($html);
|
||||||
|
|
||||||
|
// 2️⃣ 追加附件pdf
|
||||||
foreach ($car['attachment'] as $attachment) {
|
foreach ($car['attachment'] as $attachment) {
|
||||||
$this->appendPdf($mpdf,$attachment);
|
$this->appendPdf($mpdf,$attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$cardTpl = base_path('app/common/utils/pdf/template/contactCard.stub');
|
||||||
|
include $cardTpl;
|
||||||
|
$cardHtml = ob_get_clean();
|
||||||
|
// 3️⃣ 新增一页:名片页
|
||||||
|
$mpdf->AddPage();
|
||||||
|
$mpdf->WriteHTML($cardHtml);
|
||||||
|
|
||||||
$pdf = $mpdf->Output('车辆详情.pdf', 'S');
|
$pdf = $mpdf->Output('车辆详情.pdf', 'S');
|
||||||
$dir = runtime_path('pdf');
|
$dir = runtime_path('pdf');
|
||||||
if (!is_dir($dir)) mkdir($dir, 0777, true);
|
if (!is_dir($dir)) mkdir($dir, 0777, true);
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "sun-exta";
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-wrap {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qrcode-wrap img {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #999;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h2>联系人名片</h2>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<?php if (!empty($user['name'])): ?>
|
||||||
|
<div class="row"><span class="label">姓名:</span><?= $user['name'] ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($user['email'])): ?>
|
||||||
|
<div class="row"><span class="label">邮箱:</span><?= $user['email'] ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($user['phone'])): ?>
|
||||||
|
<div class="row"><span class="label">电话:</span><?= $user['phone'] ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($user['whatsapp'])): ?>
|
||||||
|
<div class="row"><span class="label">WhatsApp:</span><?= $user['whatsapp'] ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($user['social']) && !empty($user['social_code'])): ?>
|
||||||
|
<div class="qrcode-wrap">
|
||||||
|
<div><?= $user['social'] ?> 二维码</div>
|
||||||
|
<img style = "width: 270px;height: 270px;margin-top: 30px;" src="<?= $user['social_code'] ?>">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tip">
|
||||||
|
扫码即可联系本人 | 本资料随 PDF 自动生成
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -110,11 +110,20 @@
|
|||||||
|
|
||||||
<h2>产品图</h2>
|
<h2>产品图</h2>
|
||||||
<div class="image-list">
|
<div class="image-list">
|
||||||
<?php foreach ($car['images'] as $img): ?>
|
<table width="100%" cellpadding="6" cellspacing="0">
|
||||||
<div class="image-item">
|
<tr>
|
||||||
<img src="<?= $img ?>">
|
<?php foreach ($car['images'] as $i => $img): ?>
|
||||||
</div>
|
<td width="50%" align="center">
|
||||||
|
<img src="<?= $img ?>" style="width:100%; border-radius:4px;">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<?php if (($i + 1) % 2 === 0): ?>
|
||||||
|
</tr><tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace app\middleware;
|
|
||||||
|
|
||||||
use Webman\MiddlewareInterface;
|
|
||||||
use Webman\Http\Response;
|
|
||||||
use Webman\Http\Request;
|
|
||||||
use app\common\audit\AuditBuffer;
|
|
||||||
use app\common\model\User;
|
|
||||||
use Webman\RedisQueue\Redis as Queue;
|
|
||||||
use support\Log;
|
|
||||||
|
|
||||||
class Audit implements MiddlewareInterface
|
|
||||||
{
|
|
||||||
public function process(Request $request, callable $handler): Response
|
|
||||||
{
|
|
||||||
$start = microtime(true);
|
|
||||||
AuditBuffer::reset();
|
|
||||||
|
|
||||||
$httpCode = 200; $message = null; $status = 1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
$response = $handler($request);
|
|
||||||
$httpCode = $response->getStatusCode();
|
|
||||||
return $response;
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
$httpCode = $e->getCode() ?: 500;
|
|
||||||
$message = mb_substr($e->getMessage(), 0, 180);
|
|
||||||
$status = 0;
|
|
||||||
throw $e;
|
|
||||||
} finally {
|
|
||||||
$latency = (int)((microtime(true) - $start) * 1000);
|
|
||||||
$this->enqueue($request, $httpCode, $status, $message, $latency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected function enqueue(Request $req, int $httpCode, int $status, ?string $message, int $latencyMs): void
|
|
||||||
{
|
|
||||||
$buf = AuditBuffer::instance();
|
|
||||||
|
|
||||||
$user = $this->currentUser($req->user);
|
|
||||||
$paramsBrief = $this->briefParams($req->all());
|
|
||||||
$ua = (string)($req->header('user-agent') ?? '');
|
|
||||||
if (mb_strlen($ua) > 191) $ua = mb_substr($ua, 0, 191);
|
|
||||||
|
|
||||||
$payload = [
|
|
||||||
'user_id' => $user['id'] ?? null,
|
|
||||||
'user_name' => $user['name'] ?? null,
|
|
||||||
'route' => $req->path(),
|
|
||||||
'method' => $req->method(),
|
|
||||||
'ip' => $req->getRealIp(),
|
|
||||||
'ua' => $ua,
|
|
||||||
'action' => $buf->action ?? $req->action,
|
|
||||||
'status' => $status,
|
|
||||||
'http_code' => $httpCode,
|
|
||||||
'latency_ms' => $latencyMs,
|
|
||||||
'params_brief' => $paramsBrief, // 数组,消费者再编码
|
|
||||||
'changes' => $buf->changes, // 数组,消费者再编码
|
|
||||||
'message' => $message,
|
|
||||||
'ts' => time()
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
Queue::send('audit_log', $payload); // 异步
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
// 遵循“绝不回落同步写”,仅记录错误
|
|
||||||
Log::error('audit enqueue failed: '.$e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function briefParams(array $params): array
|
|
||||||
{
|
|
||||||
// $mask = ['password','pwd','token','secret','access_token','refresh_token','file','content','html'];
|
|
||||||
$mask = [];
|
|
||||||
$out = [];
|
|
||||||
foreach ($params as $k=>$v) {
|
|
||||||
if (in_array($k, $mask, true)) { $out[$k] = '***'; continue; }
|
|
||||||
if (is_array($v)) { $out[$k] = '[array('.count($v).')]'; continue; }
|
|
||||||
$s = (string)$v;
|
|
||||||
$out[$k] = mb_strlen($s) > 120 ? mb_substr($s, 0, 120).'…' : $s;
|
|
||||||
}
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function inferAction(Request $req): ?string
|
|
||||||
{
|
|
||||||
$m = strtoupper($req->method());
|
|
||||||
if ($m === 'POST') return 'create';
|
|
||||||
if ($m === 'PUT' || $m === 'PATCH') return 'update';
|
|
||||||
if ($m === 'DELETE') return 'delete';
|
|
||||||
return 'view';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function currentUser($user): array
|
|
||||||
{
|
|
||||||
$user = (array)$user;
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
return [
|
|
||||||
'id' => 0,
|
|
||||||
'name' => 'guest'
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
if (!isset($user['uname'])) {
|
|
||||||
$user['uname'] = User::where('id', $user['id'])->value('name');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'id' => $user['uid'] ?? 0,
|
|
||||||
'name' => $user['uname'] ?? 'guest'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace app\queue\redis;
|
|
||||||
|
|
||||||
use support\Db;
|
|
||||||
use support\Log;
|
|
||||||
use Webman\RedisQueue\Consumer;
|
|
||||||
|
|
||||||
class AuditLog implements Consumer
|
|
||||||
{
|
|
||||||
// 要消费的队列名
|
|
||||||
public $queue = 'audit_log';
|
|
||||||
|
|
||||||
// 连接名,对应 plugin/webman/redis-queue/redis.php 里的连接`
|
|
||||||
public $connection = 'default';
|
|
||||||
|
|
||||||
// 消费
|
|
||||||
public function consume($data)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$now = (int)($data['ts'] ?? time());
|
|
||||||
|
|
||||||
$row = [
|
|
||||||
// 'trace_id' => $data['trace_id'] ?? null,
|
|
||||||
'user_id' => $data['user_id'] ?? null,
|
|
||||||
'user_name' => $data['user_name'] ?? null,
|
|
||||||
'route' => $data['route'] ?? null,
|
|
||||||
'method' => $data['method'] ?? null,
|
|
||||||
'ip' => $data['ip'] ?? null,
|
|
||||||
'ua' => $data['ua'] ?? null,
|
|
||||||
'action' => $data['action'] ?? null,
|
|
||||||
'status' => (int)($data['status'] ?? 1),
|
|
||||||
'http_code' => (int)($data['http_code'] ?? 200),
|
|
||||||
'latency_ms' => $data['latency_ms'] ?? null,
|
|
||||||
'params_brief' => !empty($data['params_brief']) ? json_encode($data['params_brief'], JSON_UNESCAPED_UNICODE) : null,
|
|
||||||
'changes' => !empty($data['changes']) ? json_encode($data['changes'], JSON_UNESCAPED_UNICODE) : null,
|
|
||||||
'message' => $data['message'] ?? null,
|
|
||||||
'created_at' => $now,
|
|
||||||
'updated_at' => $now,
|
|
||||||
];
|
|
||||||
|
|
||||||
Db::table('sys_op_log')->insert($row);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Log::error('audit_log consume error: '.$e->getMessage());
|
|
||||||
return false; // 允许重试与失败处理
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消费失败回调
|
|
||||||
/*
|
|
||||||
$package = [
|
|
||||||
'id' => 1357277951, // 消息ID
|
|
||||||
'time' => 1709170510, // 消息时间
|
|
||||||
'delay' => 0, // 延迟时间
|
|
||||||
'attempts' => 2, // 消费次数
|
|
||||||
'queue' => 'send-mail', // 队列名
|
|
||||||
'data' => ['to' => 'tom@gmail.com', 'content' => 'hello'], // 消息内容
|
|
||||||
'max_attempts' => 5, // 最大重试次数
|
|
||||||
'error' => '错误信息' // 错误信息
|
|
||||||
]
|
|
||||||
*/
|
|
||||||
public function onConsumeFailure(\Throwable $e, $package)
|
|
||||||
{
|
|
||||||
echo "consume failure\n";
|
|
||||||
echo $e->getMessage() . "\n";
|
|
||||||
// 无需反序列化
|
|
||||||
var_export($package);
|
|
||||||
|
|
||||||
Log::error('audit_log message failed after retries: '.json_encode($package, JSON_UNESCAPED_UNICODE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -66,4 +66,11 @@ Route::group('/common', function () {
|
|||||||
Route::any('/destroy', [app\common\controller\UsedCarController::class, 'destroy']);
|
Route::any('/destroy', [app\common\controller\UsedCarController::class, 'destroy']);
|
||||||
Route::any('/crawl', [app\common\controller\UsedCarController::class, 'crawlKeyword']);
|
Route::any('/crawl', [app\common\controller\UsedCarController::class, 'crawlKeyword']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::group('/user', function () {
|
||||||
|
Route::any('/info', [app\common\controller\UserController::class, 'show']);
|
||||||
|
Route::any('/edit', [app\common\controller\UserController::class, 'edit']);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
Reference in New Issue
Block a user