init
This commit is contained in:
1
packages/README.md
Normal file
1
packages/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# some packages
|
||||
1
packages/bydauto/README.md
Normal file
1
packages/bydauto/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# some api service
|
||||
14
packages/bydauto/cluepackage-send.sh
Normal file
14
packages/bydauto/cluepackage-send.sh
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
sign="xxxxxx"
|
||||
now=$(date +%s)
|
||||
|
||||
curl -X POST "https://dev.energytrust.com.cn/pkg/dataservice/cluepackage?sign=${sign}&method=spi.alipay.data.dataservice.ad.cluepackage.send&charset=UTF-8&version=1.0&utc_timestamp=${now}&sign_type=RSA2" \
|
||||
--header "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" \
|
||||
--data-urlencode "id=123456" \
|
||||
--data-urlencode "user_name=黄丫" \
|
||||
--data-urlencode "user_mobile_no=18000000000" \
|
||||
--data-urlencode "user_province=浙江省" \
|
||||
--data-urlencode "user_city=杭州市" \
|
||||
--data-urlencode "clue_time=2024-07-24 11:44:16" \
|
||||
--data-urlencode "extend_info=行业拓展字段"
|
||||
9
packages/bydauto/composer.json
Normal file
9
packages/bydauto/composer.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "pkg/bydauto",
|
||||
"type": "metapackage",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"BYDAuto\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
4
packages/bydauto/config/bydauto.php
Normal file
4
packages/bydauto/config/bydauto.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
];
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('bydauto_contact', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamp('date_created');
|
||||
$table->timestamp('date_updated');
|
||||
$table->string('status')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('remark')->nullable();
|
||||
});
|
||||
|
||||
Schema::create('bydauto_testdrive', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamp('date_created');
|
||||
$table->timestamp('date_updated');
|
||||
$table->string('status')->nullable();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('mobile')->nullable();
|
||||
$table->string('platform')->nullable();
|
||||
$table->string('source')->nullable();
|
||||
$table->string('request_id')->nullable();
|
||||
$table->jsonb('meta')->nullable();
|
||||
$table->jsonb('rawdata')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('bydauto_testdrive');
|
||||
}
|
||||
};
|
||||
14
packages/bydauto/routes/api.php
Normal file
14
packages/bydauto/routes/api.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use BYDAuto\Controllers\BYDAutoController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
$prefix = '/pkg/bydauto';
|
||||
|
||||
Route::group(['prefix' => $prefix, 'middleware' => ['api']], function () {
|
||||
Route::get('vehicle', [BYDAutoController::class, 'vehicle']);
|
||||
Route::get('dealer', [BYDAutoController::class, 'dealer']);
|
||||
Route::get('province', [BYDAutoController::class, 'province']);
|
||||
Route::get('city', [BYDAutoController::class, 'city']);
|
||||
Route::post('testdrive', [BYDAutoController::class, 'testdrive']);
|
||||
});
|
||||
23
packages/bydauto/src/Actions/TestdriveCreateAction.php
Normal file
23
packages/bydauto/src/Actions/TestdriveCreateAction.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Actions;
|
||||
|
||||
use BYDAuto\Models\Testdrive;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TestdriveCreateAction
|
||||
{
|
||||
public function execute(Request $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$data['request_id'] = $request->request_id;
|
||||
return $this->createTestdrive($data);
|
||||
}
|
||||
|
||||
public function createTestdrive($data)
|
||||
{
|
||||
$model = new Testdrive($data);
|
||||
$model->save();
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
40
packages/bydauto/src/BYDAutoServiceProvider.php
Normal file
40
packages/bydauto/src/BYDAutoServiceProvider.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto;
|
||||
|
||||
use BYDAuto\Commands\BYDAutoCommand;
|
||||
use BYDAuto\Commands\BYDAutoNoticeCommand;
|
||||
use BYDAuto\Commands\CheryTransferCommand;
|
||||
use BYDAuto\Commands\GeocodingCommand;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class BYDAutoServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
$root = dirname(__DIR__);
|
||||
|
||||
// migrate
|
||||
$this->loadMigrationsFrom($root . '/migrations');
|
||||
|
||||
$this->commands([
|
||||
CheryTransferCommand::class,
|
||||
BYDAutoCommand::class,
|
||||
GeocodingCommand::class,
|
||||
BYDAutoNoticeCommand::class,
|
||||
]);
|
||||
|
||||
$this->mergeConfigFrom($root . '/config/bydauto.php', 'bydauto');
|
||||
$this->loadRoutesFrom($root . '/routes/api.php');
|
||||
$this->loadViewsFrom($root . '/views', 'bydauto');
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
$this->app->booted(function () {
|
||||
$schedule = $this->app->make(Schedule::class);
|
||||
$schedule->command('BYDAuto:notice')->dailyAt('09:00');
|
||||
});
|
||||
}
|
||||
}
|
||||
71
packages/bydauto/src/CheryClueApi.php
Normal file
71
packages/bydauto/src/CheryClueApi.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class CheryClueApi
|
||||
{
|
||||
protected $appId;
|
||||
|
||||
protected $appSecret;
|
||||
|
||||
protected $endpoint;
|
||||
|
||||
protected $httpClient;
|
||||
|
||||
private static $instance;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->appId = config('chery-crm.scrm.app_id');
|
||||
$this->appSecret = config('chery-crm.scrm.secret');
|
||||
$this->endpoint = config('chery-crm.scrm.endpoint');
|
||||
$this->httpClient = new Client(['base_uri' => $this->endpoint, 'timeout' => 10]);
|
||||
}
|
||||
|
||||
public static function getInstance(): self
|
||||
{
|
||||
if (!self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 线索推送
|
||||
*
|
||||
* @param array $data
|
||||
* @return CheryResult
|
||||
*/
|
||||
public function cluePush($data)
|
||||
{
|
||||
$token = $this->getToken();
|
||||
$response = $this->httpClient->post('/api/app/chery-clue/api/clue/push/channel', ['json' => $data, 'headers' => ['x-csrf-token' => $token]]);
|
||||
$content = json_decode($response->getBody()->getContents(), true);
|
||||
$result = new CheryResult($content);
|
||||
if ($result->code !== '0') {
|
||||
$message = $result->get('msg', '推送线索失败');
|
||||
throw new \Exception($message);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getToken($force = false)
|
||||
{
|
||||
$token = cache('pkg:chery-scrm-token');
|
||||
if ($force || !$token) {
|
||||
$response = $this->httpClient->get('/api/app/chery-clue/api/clue/channel/getToken', ['query' => ['appId' => $this->appId, 'appSecret' => $this->appSecret]]);
|
||||
$json = json_decode($response->getBody()->getContents(), true);
|
||||
if ($json['code'] === '0') {
|
||||
$token = $json['data'];
|
||||
// 有效期4小时,提前10分钟刷新
|
||||
cache(['pkg:chery-scrm-token' => $token], now()->addSeconds(4 * 3600 - 600));
|
||||
} else {
|
||||
$message = $json['msg'] ?? 'pkg:chery-scrm-token 获取失败';
|
||||
throw new \Exception($message);
|
||||
}
|
||||
}
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
26
packages/bydauto/src/CheryResult.php
Normal file
26
packages/bydauto/src/CheryResult.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto;
|
||||
|
||||
use BYDAuto\Foundation\DataTransfer;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class CheryResult extends DataTransfer
|
||||
{
|
||||
public $code;
|
||||
|
||||
public $msg;
|
||||
|
||||
public $data;
|
||||
|
||||
public $reqId;
|
||||
|
||||
public function __construct($attributes)
|
||||
{
|
||||
$this->code = Arr::get($attributes, 'code');
|
||||
$this->msg = Arr::get($attributes, 'msg');
|
||||
$this->data = Arr::get($attributes, 'data');
|
||||
$this->reqId = Arr::get($attributes, 'reqId');
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
}
|
||||
59
packages/bydauto/src/Commands/BYDAutoCommand.php
Normal file
59
packages/bydauto/src/Commands/BYDAutoCommand.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Commands;
|
||||
|
||||
use BYDAuto\Models\Contact;
|
||||
use BYDAuto\Models\Testdrive;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class BYDAutoCommand extends Command
|
||||
{
|
||||
protected $signature = 'bydauto {action?}';
|
||||
|
||||
protected $description = 'BYDAuto Command';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$action = $this->argument('action');
|
||||
$method = "action_{$action}";
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}();
|
||||
} else {
|
||||
$this->error("不支持的操作 {$action}");
|
||||
}
|
||||
}
|
||||
|
||||
public function action_init()
|
||||
{
|
||||
$this->call('db:wipe');
|
||||
$this->call('migrate');
|
||||
}
|
||||
|
||||
public function action_testdrive()
|
||||
{
|
||||
$items = Testdrive::query()->orderBy('id', 'desc')->get();
|
||||
$this->table(['id', 'date_created', 'status', 'name', 'mobile'], $items->map(function (Testdrive $v) {
|
||||
return [$v->id, $v->date_created, $v->status, $v->name, $v->mobile];
|
||||
}));
|
||||
}
|
||||
|
||||
public function action_contact()
|
||||
{
|
||||
$items = Contact::all();
|
||||
$this->table(['id', 'email', 'remark', 'status'], $items->map(function (Contact $v) {
|
||||
return [$v->id, $v->email, $v->remark, $v->status];
|
||||
}));
|
||||
}
|
||||
|
||||
public function action_contact_add()
|
||||
{
|
||||
$data['email'] = $this->ask('Email');
|
||||
$data['remark'] = $this->ask('Remark');
|
||||
$data['status'] = Contact::STATUS_PUBLISHED;
|
||||
|
||||
$contact = new Contact($data);
|
||||
$contact->save();
|
||||
|
||||
$this->info('Contact added');
|
||||
}
|
||||
}
|
||||
61
packages/bydauto/src/Commands/BYDAutoNoticeCommand.php
Normal file
61
packages/bydauto/src/Commands/BYDAutoNoticeCommand.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Commands;
|
||||
|
||||
use BYDAuto\Models\Testdrive;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class BYDAutoNoticeCommand extends Command
|
||||
{
|
||||
protected $signature = 'bydauto:notice {date?}';
|
||||
|
||||
protected $description = '线索日报';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$date = $this->argument('date') ?: Carbon::yesterday()->toDateString();
|
||||
$table = (new Testdrive())->getTable();
|
||||
|
||||
$items = DB::table($table)
|
||||
->selectRaw('source, COUNT(*) AS total')
|
||||
->groupByRaw('source')
|
||||
->whereDate('date_created', $date)
|
||||
->get();
|
||||
$count = $items->sum('total');
|
||||
$sourceMap = [
|
||||
'alipromote:99800024' => '自建站99800024',
|
||||
'alipromote:100000006' => '自建站100000006',
|
||||
'alipromote:cluepackage' => '车生活推送',
|
||||
'alipromote:isaas' => '小程序',
|
||||
];
|
||||
|
||||
$users = config('chery-crm.daily_mail_users');
|
||||
$users = explode(',', $users);
|
||||
$html = \View::make('chery-crm::notice.salesleads-day', compact('items', 'date', 'sourceMap', 'count'))->render();
|
||||
Mail::html($html, function ($message) use ($date, $users) {
|
||||
$message->subject('线索日报 ' . $date)->to($users);
|
||||
});
|
||||
}
|
||||
|
||||
public function sourceGroup()
|
||||
{
|
||||
$table = (new Testdrive())->getTable();
|
||||
|
||||
$items = DB::table($table)
|
||||
->selectRaw('DATE(date_created) AS day, source, COUNT(*) AS total')
|
||||
->groupByRaw('DATE(date_created), source')
|
||||
->orderByRaw('DATE(date_created), source')
|
||||
->get();
|
||||
|
||||
$sourceGroup = $items->groupBy('source');
|
||||
$html = \View::make('chery-crm::notice.salesleads', compact('sourceGroup'))->render();
|
||||
Mail::html($html, function ($message) {
|
||||
$message
|
||||
->subject('销售线索每日通知')
|
||||
->to('ifme.in@gmail.com');
|
||||
});
|
||||
}
|
||||
}
|
||||
80
packages/bydauto/src/Commands/CheryTransferCommand.php
Normal file
80
packages/bydauto/src/Commands/CheryTransferCommand.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Commands;
|
||||
|
||||
use BYDAuto\Jobs\TestdrivePushJob;
|
||||
use BYDAuto\Models\Testdrive;
|
||||
use BYDAuto\Models\Vehicle;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CheryTransferCommand extends Command
|
||||
{
|
||||
// php artisan BYDAuto:transfer vehicle_alias_update
|
||||
// php artisan BYDAuto:transfer dispatch_by_mobile
|
||||
// php artisan BYDAuto:transfer dispatch_all_draft
|
||||
protected $signature = 'bydauto:transfer {action}';
|
||||
|
||||
protected $description = '奇瑞SCRM数据传输';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$action = $this->argument('action');
|
||||
$this->{'action_' . $action}();
|
||||
}
|
||||
|
||||
public function action_dispatch_all_draft()
|
||||
{
|
||||
$items = Testdrive::query()
|
||||
->where('status', Testdrive::STATUS_DRAFT)
|
||||
->get();
|
||||
$this->showTable($items);
|
||||
|
||||
$confirm = $this->confirm('是否确认推送?', true);
|
||||
if (!$confirm) {
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
foreach ($items as $model) {
|
||||
TestdrivePushJob::dispatch($model);
|
||||
}
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
public function action_vehicle_alias_update()
|
||||
{
|
||||
$items = Vehicle::query()->get();
|
||||
$items->each(function ($item) {
|
||||
$cleanName = preg_replace('/\s+/', '', $item->name);
|
||||
$alias = [$item->name];
|
||||
if ($item->name !== $cleanName) {
|
||||
$alias[] = $cleanName;
|
||||
}
|
||||
$item->update(['alias' => $alias]);
|
||||
});
|
||||
}
|
||||
|
||||
public function action_dispatch_by_mobile()
|
||||
{
|
||||
$mobiles = $this->ask('请输入手机号码,多个用逗号分隔');
|
||||
$mobiles = explode(',', $mobiles);
|
||||
|
||||
$items = Testdrive::query()
|
||||
->whereIn('mobile', $mobiles)
|
||||
->get();
|
||||
$this->showTable($items);
|
||||
|
||||
$confirm = $this->confirm('是否确认推送?', true);
|
||||
if (!$confirm) {
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
foreach ($items as $model) {
|
||||
TestdrivePushJob::dispatch($model);
|
||||
}
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function showTable($items)
|
||||
{
|
||||
$columns = ['id', 'status', 'name', 'mobile'];
|
||||
$this->table($columns, $items->map(fn($item) => $item->only($columns)));
|
||||
}
|
||||
}
|
||||
206
packages/bydauto/src/Commands/GeocodingCommand.php
Normal file
206
packages/bydauto/src/Commands/GeocodingCommand.php
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Commands;
|
||||
|
||||
use BYDAuto\Models\Dealer;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
|
||||
class GeocodingCommand extends Command
|
||||
{
|
||||
protected $signature = 'bydauto:geocoding {action}';
|
||||
|
||||
protected $description = '使用百度地图 API 把地址转换为经纬度';
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$action = $this->argument('action');
|
||||
if (method_exists($this, 'action_' . $action)) {
|
||||
$this->{'action_' . $action}();
|
||||
} else {
|
||||
$this->error('Action not found');
|
||||
}
|
||||
}
|
||||
|
||||
public function action_update()
|
||||
{
|
||||
$items = Dealer::query()->orderBy('id')->get();
|
||||
dump($items[0]);
|
||||
}
|
||||
|
||||
public function xlsx($chunk, $index)
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$sheet = $spreadsheet->getActiveSheet();
|
||||
$sheet->setCellValue('A1', '门店名称(必填)');
|
||||
$sheet->setCellValue('B1', '门店编码');
|
||||
$sheet->setCellValue('C1', '省份名称(必填)');
|
||||
$sheet->setCellValue('D1', '城市名称(必填)');
|
||||
$sheet->setCellValue('E1', '描述');
|
||||
$sheet->setCellValue('F1', '地址(必填)');
|
||||
$sheet->setCellValue('G1', '经度(必填)');
|
||||
$sheet->setCellValue('H1', '纬度(必填)');
|
||||
$sheet->setCellValue('I1', '电话(必填)');
|
||||
$sheet->setCellValue('J1', '营业时间(必填)');
|
||||
$sheet->setCellValue('K1', '标签');
|
||||
$sheet->setCellValue('L1', '业务扩展字段');
|
||||
|
||||
$sn = 2;
|
||||
foreach ($chunk as $dealer) {
|
||||
$except1 = ['北京', '上海', '天津', '重庆']; // 直辖市
|
||||
$except2 = ['内蒙古', '内蒙古(蒙东)', '内蒙古(蒙西)']; // 内蒙古自治区
|
||||
$except3 = ['新疆']; // 新疆维吾尔自治区
|
||||
$except4 = ['西藏']; // 西藏自治区
|
||||
$except5 = ['广西']; // 广西壮族自治区
|
||||
$except6 = ['宁夏']; // 宁夏回族自治区
|
||||
$except7 = ['香港', '澳门']; // 香港特别行政区、澳门特别行政区
|
||||
|
||||
$province = $dealer->province;
|
||||
if (in_array($province, $except1)) {
|
||||
$province .= '市';
|
||||
} elseif (in_array($province, $except2)) {
|
||||
$province = '内蒙古自治区';
|
||||
} elseif (in_array($province, $except3)) {
|
||||
$province = '新疆维吾尔自治区';
|
||||
} elseif (in_array($province, $except4)) {
|
||||
$province = '西藏自治区';
|
||||
} elseif (in_array($province, $except5)) {
|
||||
$province = '广西壮族自治区';
|
||||
} elseif (in_array($province, $except6)) {
|
||||
$province = '宁夏回族自治区';
|
||||
} elseif (in_array($province, $except7)) {
|
||||
$province .= '特别行政区';
|
||||
} else {
|
||||
$province .= '省';
|
||||
}
|
||||
|
||||
$lng = $dealer->lng ? number_format($dealer->lng, 6) : '';
|
||||
$lat = $dealer->lat ? number_format($dealer->lat, 6) : '';
|
||||
|
||||
$sheet->setCellValue('A' . $sn, $dealer->name);
|
||||
$sheet->setCellValue('B' . $sn, $dealer->erp);
|
||||
$sheet->setCellValue('C' . $sn, $province);
|
||||
$sheet->setCellValue('D' . $sn, $dealer->city);
|
||||
$sheet->setCellValue('E' . $sn, $dealer->alias);
|
||||
$sheet->setCellValue('F' . $sn, $dealer->address);
|
||||
$sheet->setCellValue('G' . $sn, $lng);
|
||||
$sheet->setCellValue('H' . $sn, $lat);
|
||||
$sheet->setCellValue('I' . $sn, '13000000000');
|
||||
$sheet->setCellValue('J' . $sn, '09:00-18:00');
|
||||
$sheet->setCellValue('K' . $sn, '');
|
||||
|
||||
$vehicles = $dealer->vehicles->map(fn($v) => $v->extra_code)->join(',');
|
||||
$vehicles = trim($vehicles, ',');
|
||||
$sheet->setCellValue('L' . $sn, $vehicles);
|
||||
|
||||
++$sn;
|
||||
}
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
$writer->save(storage_path('app/dealers-' . $index . '.xlsx'));
|
||||
}
|
||||
|
||||
public function csv($chunk, $index)
|
||||
{
|
||||
$headers = ['门店名称(必填)', '门店编码', '省份名称(必填)', '城市名称(必填)', '描述', '地址(必填)', '经度(必填)', '纬度(必填)', '电话(必填)', '营业时间(必填)', '标签', '业务扩展字段'];
|
||||
$file = fopen(storage_path('app/dealers-' . $index . '.csv'), 'w');
|
||||
fputcsv($file, $headers);
|
||||
$chunk->each(function (Dealer $dealer) use ($file) {
|
||||
$except1 = ['北京', '上海', '天津', '重庆']; // 直辖市
|
||||
$except2 = ['内蒙古', '内蒙古(蒙东)', '内蒙古(蒙西)']; // 内蒙古自治区
|
||||
$except3 = ['新疆']; // 新疆维吾尔自治区
|
||||
$except4 = ['西藏']; // 西藏自治区
|
||||
$except5 = ['广西']; // 广西壮族自治区
|
||||
$except6 = ['宁夏']; // 宁夏回族自治区
|
||||
$except7 = ['香港', '澳门']; // 香港特别行政区、澳门特别行政区
|
||||
|
||||
$province = $dealer->province;
|
||||
if (in_array($province, $except1)) {
|
||||
$province .= '市';
|
||||
} elseif (in_array($province, $except2)) {
|
||||
$province = '内蒙古自治区';
|
||||
} elseif (in_array($province, $except3)) {
|
||||
$province = '新疆维吾尔自治区';
|
||||
} elseif (in_array($province, $except4)) {
|
||||
$province = '西藏自治区';
|
||||
} elseif (in_array($province, $except5)) {
|
||||
$province = '广西壮族自治区';
|
||||
} elseif (in_array($province, $except6)) {
|
||||
$province = '宁夏回族自治区';
|
||||
} elseif (in_array($province, $except7)) {
|
||||
$province .= '特别行政区';
|
||||
} else {
|
||||
$province .= '省';
|
||||
}
|
||||
|
||||
$lng = $dealer->lng ? number_format($dealer->lng, 6) : '';
|
||||
$lat = $dealer->lat ? number_format($dealer->lat, 6) : '';
|
||||
|
||||
fputcsv($file, [
|
||||
$dealer->name,
|
||||
$dealer->erp,
|
||||
$province,
|
||||
$dealer->city,
|
||||
$dealer->alias,
|
||||
$dealer->address,
|
||||
$lng,
|
||||
$lat,
|
||||
'13000000000',
|
||||
'09:00-18:00',
|
||||
'',
|
||||
$dealer->region,
|
||||
]);
|
||||
});
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
public function action_csv()
|
||||
{
|
||||
$items = Dealer::query()->orderBy('id')->get();
|
||||
$chunks = $items->chunk(200);
|
||||
$chunks->each(fn($chunk, $index) => $this->xlsx($chunk, $index));
|
||||
}
|
||||
|
||||
public function action_xlsx()
|
||||
{
|
||||
$items = Dealer::query()->orderBy('id')->get();
|
||||
$chunks = $items->chunk(200);
|
||||
$chunks->each(fn($chunk, $index) => $this->xlsx($chunk, $index));
|
||||
}
|
||||
|
||||
public function action_dump()
|
||||
{
|
||||
$address = $this->ask('请输入地址');
|
||||
$response = $this->getGeocoding($address);
|
||||
dump($response);
|
||||
}
|
||||
|
||||
public function action_show()
|
||||
{
|
||||
$items = Dealer::query()->take(4)->get();
|
||||
$this->table(['CODE', '经销商名称', '在售车型'], $items->map(fn(Dealer $d) => [$d->erp, $d->alias, $d->vehicles->map(fn($v) => $v->spec_id)->join(',')]));
|
||||
}
|
||||
|
||||
public function action_fix()
|
||||
{
|
||||
$dealers = Dealer::query()->orderBy('id')->whereNull('lat')->get();
|
||||
$dealers->each(function (Dealer $dealer) {
|
||||
$endpoint = 'https://api.map.baidu.com/geocoding/v3/';
|
||||
$address = str_replace("\n", " ", $dealer->address);
|
||||
$this->info($dealer->id . ':' . $address);
|
||||
$response = Http::get($endpoint, ['address' => $address, 'output' => 'json', 'ak' => config('services.baidulbs.ak')]);
|
||||
if ($response->json('status') === 0) {
|
||||
$location = $response->json('result.location');
|
||||
$dealer->update(['address' => $address, 'lat' => $location['lat'], 'lng' => $location['lng']]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function getGeocoding($address)
|
||||
{
|
||||
$endpoint = 'https://api.map.baidu.com/geocoding/v3/';
|
||||
$response = Http::get($endpoint, ['address' => $address, 'output' => 'json', 'ak' => config('services.baidulbs.ak')]);
|
||||
return $response->json();
|
||||
}
|
||||
}
|
||||
67
packages/bydauto/src/Controllers/BYDAutoController.php
Normal file
67
packages/bydauto/src/Controllers/BYDAutoController.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Controllers;
|
||||
|
||||
use BYDAuto\Actions\TestdriveCreateAction;
|
||||
use BYDAuto\Models\Dealer;
|
||||
use BYDAuto\Models\Vehicle;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class BYDAutoController extends Controller
|
||||
{
|
||||
use ValidatesRequests;
|
||||
|
||||
public function testdrive(Request $request)
|
||||
{
|
||||
$rules['name'] = ['required'];
|
||||
$rules['mobile'] = ['required'];
|
||||
$this->validate($request, $rules);
|
||||
$requestId = Str::uuid();
|
||||
$request->merge(['request_id' => $requestId]);
|
||||
(new TestdriveCreateAction())->execute($request);
|
||||
|
||||
return response()->json(['code' => 0, 'message' => '提交成功', 'request_id' => $requestId]);
|
||||
}
|
||||
|
||||
public function vehicle(Request $request)
|
||||
{
|
||||
$items = Vehicle::cachedItems();
|
||||
return response()->json($items);
|
||||
}
|
||||
|
||||
public function province(Request $request)
|
||||
{
|
||||
$vehicle = Vehicle::query()->firstWhere('name', $request->vehicle);
|
||||
$dealers = $vehicle->dealers;
|
||||
$province = $dealers->groupBy('province')->keys();
|
||||
$data = $province->map(fn($item) => ['name' => $item]);
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
public function city(Request $request)
|
||||
{
|
||||
$vehicle = Vehicle::query()->firstWhere('name', $request->vehicle);
|
||||
if (!$vehicle) {
|
||||
throw ValidationException::withMessages(['vehicle' => '车型不存在']);
|
||||
}
|
||||
$dealers = $vehicle->dealers;
|
||||
$city = $dealers->where('province', $request->province)->groupBy('city')->keys();
|
||||
$data = $city->map(fn($item) => ['name' => $item]);
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
public function dealer(Request $request)
|
||||
{
|
||||
$vehicle = Vehicle::query()->firstWhere('name', $request->vehicle);
|
||||
if (!$vehicle) {
|
||||
throw ValidationException::withMessages(['vehicle' => '车型不存在']);
|
||||
}
|
||||
$dealer = Dealer::query()->where('province', $request->province)->where('city', $request->city)->get();
|
||||
$data = $dealer->map(fn($item) => ['name' => $item->name, 'address' => $item->address, 'erp' => $item->erp]);
|
||||
return response()->json($data);
|
||||
}
|
||||
}
|
||||
83
packages/bydauto/src/Foundation/AlipayAES.php
Normal file
83
packages/bydauto/src/Foundation/AlipayAES.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Foundation;
|
||||
|
||||
class AlipayAES
|
||||
{
|
||||
/**
|
||||
* AES加密.
|
||||
*
|
||||
* @param $plainText String 明文
|
||||
* @param $key String 对称密钥
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function encrypt($plainText, $key)
|
||||
{
|
||||
try {
|
||||
// AES, 128 模式加密数据 CBC
|
||||
$screct_key = base64_decode($key);
|
||||
$str = trim($plainText);
|
||||
$str = $this->addPKCS7Padding($str);
|
||||
$iv = str_repeat("\0", 16);
|
||||
$encrypt_str = openssl_encrypt($str, 'AES-128-CBC', $screct_key, OPENSSL_NO_PADDING, $iv);
|
||||
return base64_encode($encrypt_str);
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception("AES加密失败,plainText=" . $plainText . ",keySize=" . strlen($key) . "。" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AES解密.
|
||||
*
|
||||
* @param $cipherText String 密文
|
||||
* @param $key String 对称密钥
|
||||
* @return false|string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function decrypt($cipherText, $key)
|
||||
{
|
||||
try {
|
||||
// AES, 128 模式加密数据 CBC
|
||||
$str = base64_decode($cipherText);
|
||||
$screct_key = base64_decode($key);
|
||||
$iv = str_repeat("\0", 16);
|
||||
$decrypt_str = openssl_decrypt($str, 'AES-128-CBC', $screct_key, OPENSSL_NO_PADDING, $iv);
|
||||
return $this->stripPKSC7Padding($decrypt_str);
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception("AES解密失败,cipherText=" . $cipherText . ",keySize=" . strlen($key) . "。" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充算法.
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
private function addPKCS7Padding($source)
|
||||
{
|
||||
$source = trim($source);
|
||||
$block = 16;
|
||||
$pad = $block - (strlen($source) % $block);
|
||||
if ($pad <= $block) {
|
||||
$char = chr($pad);
|
||||
$source .= str_repeat($char, $pad);
|
||||
}
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移去填充算法.
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
private function stripPKSC7Padding($source)
|
||||
{
|
||||
$char = substr($source, -1);
|
||||
$num = ord($char);
|
||||
if ($num == 62) {
|
||||
return $source;
|
||||
}
|
||||
return substr($source, 0, -$num);
|
||||
}
|
||||
}
|
||||
33
packages/bydauto/src/Foundation/AlipayEasySDKFactory.php
Normal file
33
packages/bydauto/src/Foundation/AlipayEasySDKFactory.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Foundation;
|
||||
|
||||
use Alipay\EasySDK\Kernel\Config;
|
||||
use Alipay\EasySDK\Kernel\Factory;
|
||||
|
||||
class AlipayEasySDKFactory
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
Factory::setOptions($this->getOptions());
|
||||
}
|
||||
|
||||
public function execute($method, $textParams, $bizParams)
|
||||
{
|
||||
return Factory::util()->generic()->execute($method, $textParams, $bizParams);
|
||||
}
|
||||
|
||||
protected function getOptions()
|
||||
{
|
||||
$options = new Config();
|
||||
$options->protocol = 'https';
|
||||
$options->gatewayHost = 'openapi.alipay.com';
|
||||
$options->signType = 'RSA2';
|
||||
$options->appId = config('chery-crm.alipay.app_id');
|
||||
$merchantPrivateKey = file_get_contents(storage_path(config('chery-crm.alipay.merchant_private_key')));
|
||||
$options->merchantPrivateKey = $merchantPrivateKey;
|
||||
$alipayPublicKey = file_get_contents(storage_path(config('chery-crm.alipay.alipay_public_key')));
|
||||
$options->alipayPublicKey = $alipayPublicKey;
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
15
packages/bydauto/src/Foundation/DBLog.php
Normal file
15
packages/bydauto/src/Foundation/DBLog.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Foundation;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DBLog
|
||||
{
|
||||
public static function add($message, $content = [], $channel = '')
|
||||
{
|
||||
$content = json_encode($content, JSON_UNESCAPED_UNICODE);
|
||||
DB::table('bydauto_logs')
|
||||
->insert(['message' => $message, 'content' => $content, 'channel' => $channel, 'created_at' => now(), 'updated_at' => now()]);
|
||||
}
|
||||
}
|
||||
53
packages/bydauto/src/Foundation/DataTransfer.php
Normal file
53
packages/bydauto/src/Foundation/DataTransfer.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Foundation;
|
||||
|
||||
abstract class DataTransfer implements \ArrayAccess, \JsonSerializable
|
||||
{
|
||||
protected $attributes;
|
||||
|
||||
public function __construct($attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
return isset($this->attributes[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet($offset): mixed
|
||||
{
|
||||
return $this->attributes[$offset] ?? null;
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
$this->attributes[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
unset($this->attributes[$offset]);
|
||||
}
|
||||
|
||||
public function toJson($options = 0): string
|
||||
{
|
||||
return json_encode($this->jsonSerialize(), $options);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
{
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
return \Arr::get($this->attributes, $key, $default);
|
||||
}
|
||||
}
|
||||
31
packages/bydauto/src/Foundation/Encryption.php
Normal file
31
packages/bydauto/src/Foundation/Encryption.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Foundation;
|
||||
|
||||
class Encryption
|
||||
{
|
||||
public function __construct(protected $pubkey, protected $privkey)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
public function encrypt($data)
|
||||
{
|
||||
if (openssl_public_encrypt($data, $encrypted, $this->pubkey)) {
|
||||
$data = base64_encode($encrypted);
|
||||
} else {
|
||||
throw new \Exception('Unable to encrypt data. Perhaps it is bigger than the key size?');
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function decrypt($data)
|
||||
{
|
||||
if (openssl_private_decrypt(base64_decode($data), $decrypted, $this->privkey)) {
|
||||
$data = $decrypted;
|
||||
} else {
|
||||
$data = '';
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
37
packages/bydauto/src/Jobs/TestdrivePushJob.php
Normal file
37
packages/bydauto/src/Jobs/TestdrivePushJob.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Jobs;
|
||||
|
||||
use BYDAuto\Models\Contact;
|
||||
use BYDAuto\Models\Testdrive;
|
||||
use BYDAuto\Notifications\TestdirveNotification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Foundation\Queue\Queueable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TestdrivePushJob implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
use Dispatchable;
|
||||
|
||||
public function __construct(protected Testdrive $model) {}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$this->sendNotification();
|
||||
$this->model->update(['status' => Testdrive::STATUS_PUBLISHED]);
|
||||
} catch (\Exception $e) {
|
||||
info('===== TestdrivePushJob::handle exception', ['message' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function sendNotification()
|
||||
{
|
||||
$message = new TestdirveNotification($this->model);
|
||||
$contacts = Contact::query()->where('status', Contact::STATUS_PUBLISHED)->get();
|
||||
$contacts->each(fn(Contact $contact) => $contact->notify($message));
|
||||
}
|
||||
}
|
||||
18
packages/bydauto/src/Models/Contact.php
Normal file
18
packages/bydauto/src/Models/Contact.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class Contact extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
const STATUS_PUBLISHED = 'published';
|
||||
const STATUS_DRAFT = 'draft';
|
||||
public const CREATED_AT = 'date_created';
|
||||
public const UPDATED_AT = 'date_updated';
|
||||
protected $table = 'bydauto_contact';
|
||||
protected $fillable = ['remark', 'email', 'status'];
|
||||
}
|
||||
54
packages/bydauto/src/Models/Dealer.php
Normal file
54
packages/bydauto/src/Models/Dealer.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* 经销商门店 class.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $sn
|
||||
* @property string $region
|
||||
* @property string $province
|
||||
* @property string $city
|
||||
* @property string $county
|
||||
* @property string $district
|
||||
* @property string $type
|
||||
* @property string $erp
|
||||
* @property string $name
|
||||
* @property string $alias
|
||||
* @property string $group
|
||||
* @property string $address
|
||||
*/
|
||||
class Dealer extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $table = 'bydauto_dealers';
|
||||
|
||||
protected $fillable = ['sn', 'region', 'province', 'city', 'county', 'district', 'type', 'erp', 'name', 'alias', 'group', 'address', 'lat', 'lng'];
|
||||
|
||||
public function vehicles()
|
||||
{
|
||||
return $this->belongsToMany(Vehicle::class, 'bydauto_dealer_vehicles', 'dealer_id', 'vehicle_id');
|
||||
}
|
||||
|
||||
public static function cachedItems()
|
||||
{
|
||||
return Cache::remember('BYDAuto:dealers', 120, fn() => static::query()->get());
|
||||
}
|
||||
|
||||
public static function findByAlias($alias)
|
||||
{
|
||||
$items = self::cachedItems();
|
||||
return $items->first(fn($d) => $d->alias === $alias);
|
||||
}
|
||||
|
||||
public static function findByName($name)
|
||||
{
|
||||
$items = self::cachedItems();
|
||||
return $items->first(fn($d) => $d->name === $name);
|
||||
}
|
||||
}
|
||||
37
packages/bydauto/src/Models/Testdrive.php
Normal file
37
packages/bydauto/src/Models/Testdrive.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use BYDAuto\Observers\TestdriveObserver;
|
||||
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* 销售线索.
|
||||
*
|
||||
* @property int $id
|
||||
* @property Carbon $date_created
|
||||
* @property Carbon $date_updated
|
||||
*/
|
||||
#[ObservedBy([TestdriveObserver::class])]
|
||||
class Testdrive extends Model
|
||||
{
|
||||
public const STATUS_UNKNOWN = 'unknown';
|
||||
|
||||
public const STATUS_DRAFT = 'draft';
|
||||
|
||||
public const STATUS_PUBLISHED = 'published';
|
||||
|
||||
public const STATUS_ARCHIVED = 'archived';
|
||||
|
||||
public const CREATED_AT = 'date_created';
|
||||
|
||||
public const UPDATED_AT = 'date_updated';
|
||||
|
||||
protected $table = 'bydauto_testdrive';
|
||||
|
||||
protected $fillable = ['status', 'name', 'mobile', 'platform', 'source', 'meta', 'rawdata', 'request_id'];
|
||||
|
||||
protected $casts = ['meta' => 'json', 'rawdata' => 'json'];
|
||||
}
|
||||
44
packages/bydauto/src/Models/Vehicle.php
Normal file
44
packages/bydauto/src/Models/Vehicle.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
* Vehicle class.
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property array $alias
|
||||
* @property string $spec_id
|
||||
*/
|
||||
class Vehicle extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $table = 'bydauto_vehicles';
|
||||
|
||||
protected $fillable = ['name', 'alias', 'spec_id'];
|
||||
|
||||
protected $casts = ['alias' => 'array'];
|
||||
|
||||
public function dealers()
|
||||
{
|
||||
return $this->belongsToMany(Dealer::class, 'bydauto_dealer_vehicles', 'vehicle_id', 'dealer_id');
|
||||
}
|
||||
|
||||
public static function cachedItems()
|
||||
{
|
||||
return Cache::remember('BYDAuto:vechicle', 3600, function () {
|
||||
return Vehicle::query()->get()->map(fn($d) => ['id' => $d->id, 'name' => $d->name, 'alias' => $d->alias, 'spec_id' => $d->spec_id]);
|
||||
});
|
||||
}
|
||||
|
||||
public static function specId($name)
|
||||
{
|
||||
$items = self::cachedItems();
|
||||
$item = $items->first(fn($d) => in_array($name, $d['alias']) || $d['name'] === $name);
|
||||
return $item ? $item['spec_id'] : null;
|
||||
}
|
||||
}
|
||||
41
packages/bydauto/src/Notifications/TestdirveNotification.php
Normal file
41
packages/bydauto/src/Notifications/TestdirveNotification.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Notifications;
|
||||
|
||||
use BYDAuto\Models\Testdrive;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class TestdirveNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(protected Testdrive $model)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject("预约试驾线索通知")
|
||||
->line("收到了一条新的试驾预约信息,请及时处理")
|
||||
->line("姓名:" . $this->model->name . " \n电话:" . $this->model->mobile)
|
||||
->line("=====")
|
||||
->line("祝,工作愉快!");
|
||||
}
|
||||
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
25
packages/bydauto/src/Observers/TestdriveObserver.php
Normal file
25
packages/bydauto/src/Observers/TestdriveObserver.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace BYDAuto\Observers;
|
||||
|
||||
use BYDAuto\Jobs\TestdrivePushJob;
|
||||
use BYDAuto\Models\Testdrive;
|
||||
|
||||
class TestdriveObserver
|
||||
{
|
||||
public function creating(Testdrive $model)
|
||||
{
|
||||
if ($model->status === null) {
|
||||
$model->status = Testdrive::STATUS_DRAFT;
|
||||
}
|
||||
}
|
||||
|
||||
public function created(Testdrive $model)
|
||||
{
|
||||
if ($model->status === Testdrive::STATUS_DRAFT) {
|
||||
TestdrivePushJob::dispatch($model);
|
||||
} else {
|
||||
info('===== TestdriveObserver::created not a draft', ['id' => $model->id, 'status' => $model->status]);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
packages/bydauto/views/notice/salesleads-day.blade.php
Normal file
16
packages/bydauto/views/notice/salesleads-day.blade.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<div>
|
||||
<h3>{{ $date }}</h3>
|
||||
@if ($items->isEmpty())
|
||||
<div>无数据</div>
|
||||
@else
|
||||
<ul>
|
||||
@foreach ($items as $item)
|
||||
<li>
|
||||
{{ $sourceMap[$item->source] ?? $item->source }}
|
||||
<strong style="color: red">{{ $item->total }}</strong>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
<p>总数:{{ $count }}</p>
|
||||
@endif
|
||||
</div>
|
||||
8
packages/bydauto/views/notice/salesleads.blade.php
Normal file
8
packages/bydauto/views/notice/salesleads.blade.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<div>
|
||||
@foreach ($sourceGroup as $source => $items)
|
||||
<p>渠道: {{ $source }}</p>
|
||||
@foreach ($items as $item)
|
||||
<div>{{ $item->day }} {{ $item->total }}</div>
|
||||
@endforeach
|
||||
@endforeach
|
||||
</div>
|
||||
Reference in New Issue
Block a user