This commit is contained in:
2025-04-30 10:53:02 +08:00
commit 701b9a909f
1007 changed files with 353274 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
<?php
namespace app\controller;
use support\Request;
class IndexController
{
public function index(Request $request)
{
static $readme;
if (!$readme) {
$readme = file_get_contents(base_path('README.md'));
}
return $readme;
}
public function view(Request $request)
{
return view('index/view', ['name' => 'webman']);
}
public function json(Request $request)
{
return json(['code' => 0, 'msg' => 'ok']);
}
}
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace app\controller;
use app\model\Location;
use util\Util;
use support\Request;
class LocationController
{
/**
* Get all locations that have vehicles
*/
public function index(Request $request)
{
$locations = Location::with('vehicles')
->with('fboVehicles')
->get()
->map(function ($location) {
$location->vehicle_count = $location->vehicles->count();
$location->fbo_vehicle_count = $location->fboVehicles->count();
return $location;
});
return Util::success($locations);
}
/**
* Get a specific location with its vehicles
*/
public function show(Request $request, $id)
{
$location = Location::hasVehicles()
->with('vehicles')
->find($id);
if (!$location) {
return Util::fail(null, 'Location not found or has no vehicles');
}
return Util::success($location);
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace app\controller;
//use support\Request;
//use support\Log;
//use Webman\Http\Response;
use app\service\OssService;
use Shopwwi\WebmanFilesystem\Facade\Storage;
use support\Log;
use support\Request;
use util\Util;
class UploadController
{
/**
* 不需要登录的方法
*/
protected $noNeedLogin = ['uploadImage'];
// 上传单文件图片
public function uploadImage(Request $request)
{
try {
$file = $request->file('files');
if (!$file || !$file->isValid()) {
return Util::fail($file,'上传失败');
}
$result = Storage::adapter('oss')
->path('lingke_crm/'.date('Ymd'))
->size(1024*1024*5)
->extYes(['image/jpeg','image/png'])
->extNo(['image/gif'])
->upload($file);
$ossservice = new OssService();
$data = [
'path' => $result->file_name,
'original_name' => $result->origin_name,
'image_url' => $ossservice->generatePrivateUrl($result->file_name)
];
return Util::success($data,'上传成功');
}catch (\Throwable $e){
Log::error('文件上传失败: ' . $e->getMessage());
return Util::fail([],'file:'.$e->getFile().'line:'.$e->getLine().'message:'.$e->getMessage());
}
}
}
+62
View File
@@ -0,0 +1,62 @@
<?php
namespace app\controller;
use app\model\Vehicle;
use plugin\admin\app\model\Location;
use util\Util;
use support\Request;
class VehicleController
{
protected $status = ['未知','待发车','在途(发往fbo港口)','抵达发货港口','在途(发往目的地仓库)','抵达仓库','售出'];
/**
* Mask VIN number by showing only first 2 and last 6 characters
*/
private function maskVin($vin)
{
if (strlen($vin) <= 8) {
return $vin;
}
return substr($vin, 0, 2) . str_repeat('*', strlen($vin) - 8) . substr($vin, -6);
}
/**
* Get all vehicles with their locations
*/
public function index(Request $request)
{
$vehicles = Vehicle::with('location')->with('finalLocation')->get();
$vehicles->each(function ($vehicle) {
if (isset($vehicle->vin)) {
$vehicle->vin = $this->maskVin($vehicle->vin);
}
$vehicle->status = $this->status[$vehicle->status]??$this->status[0];
// $location = Location::find($vehicle->locations_id);
// $vehicle->location_name = $location ? $location->name : '';
// $final_location = Location::find($vehicle->final_locations_id);
// $vehicle->final_location_name = $final_location ? $final_location->name : '';
$fbo_location = Location::find($vehicle->fbo_locations_id);
$vehicle->fbo_destination = $fbo_location ? $fbo_location->name : '';
});
$result = ['list' => $vehicles,'count'=>count($vehicles)];
return Util::success($result);
}
/**
* Get a specific vehicle with its location
*/
public function show(Request $request, $id)
{
$vehicle = Vehicle::with('location')->find($id);
if (!$vehicle) {
return Util::fail($vehicle,'Vehicle not found');
}
if (isset($vehicle->vin)) {
$vehicle->vin = $this->maskVin($vehicle->vin);
}
return Util::success($vehicle);
}
}
+4
View File
@@ -0,0 +1,4 @@
<?php
/**
* Here is your custom functions.
*/
+42
View File
@@ -0,0 +1,42 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
/**
* Class StaticFile
* @package app\middleware
*/
class StaticFile implements MiddlewareInterface
{
public function process(Request $request, callable $next): Response
{
// Access to files beginning with. Is prohibited
if (strpos($request->path(), '/.') !== false) {
return response('<h1>403 forbidden</h1>', 403);
}
/** @var Response $response */
$response = $next($request);
// Add cross domain HTTP header
/*$response->withHeaders([
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Credentials' => 'true',
]);*/
return $response;
}
}
+61
View File
@@ -0,0 +1,61 @@
<?php
namespace app\model;
use support\Model;
class Location extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'locations';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* Get the vehicles for the location.
*/
public function vehicles()
{
return $this->hasMany(Vehicle::class, 'locations_id', 'id');
}
/**
* 目的地关联
* Get the vehicles for the location.
*/
public function finalVehicles()
{
return $this->hasMany(Vehicle::class, 'final_locations_id', 'id');
}
/**
* Get the FBO vehicles for the location.
*/
public function fboVehicles()
{
return $this->hasMany(Vehicle::class, 'fbo_locations_id', 'id');
}
/**
* Scope a query to only include locations that have vehicles.
*/
public function scopeHasVehicles($query)
{
return $query->whereHas('vehicles');
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace app\model;
use support\Model;
class Test extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'test';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
}
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace app\model;
use support\Model;
class Vehicle extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'vehicles';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* Get the location that owns the vehicle.
*/
public function location()
{
return $this->belongsTo(Location::class, 'locations_id', 'id');
}
/**
* Get the location that owns the vehicle.
*/
public function finalLocation()
{
return $this->belongsTo(Location::class, 'final_locations_id', 'id');
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace app\process;
use Webman\App;
class Http extends App
{
}
+282
View File
@@ -0,0 +1,282 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace app\process;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
use Workerman\Timer;
use Workerman\Worker;
/**
* Class FileMonitor
* @package process
*/
class Monitor
{
/**
* @var array
*/
protected array $paths = [];
/**
* @var array
*/
protected array $extensions = [];
/**
* @var array
*/
protected array $loadedFiles = [];
/**
* @var int
*/
protected int $ppid = 0;
/**
* Pause monitor
* @return void
*/
public static function pause(): void
{
file_put_contents(static::lockFile(), time());
}
/**
* Resume monitor
* @return void
*/
public static function resume(): void
{
clearstatcache();
if (is_file(static::lockFile())) {
unlink(static::lockFile());
}
}
/**
* Whether monitor is paused
* @return bool
*/
public static function isPaused(): bool
{
clearstatcache();
return file_exists(static::lockFile());
}
/**
* Lock file
* @return string
*/
protected static function lockFile(): string
{
return runtime_path('monitor.lock');
}
/**
* FileMonitor constructor.
* @param $monitorDir
* @param $monitorExtensions
* @param array $options
*/
public function __construct($monitorDir, $monitorExtensions, array $options = [])
{
$this->ppid = function_exists('posix_getppid') ? posix_getppid() : 0;
static::resume();
$this->paths = (array)$monitorDir;
$this->extensions = $monitorExtensions;
foreach (get_included_files() as $index => $file) {
$this->loadedFiles[$file] = $index;
if (strpos($file, 'webman-framework/src/support/App.php')) {
break;
}
}
if (!Worker::getAllWorkers()) {
return;
}
$disableFunctions = explode(',', ini_get('disable_functions'));
if (in_array('exec', $disableFunctions, true)) {
echo "\nMonitor file change turned off because exec() has been disabled by disable_functions setting in " . PHP_CONFIG_FILE_PATH . "/php.ini\n";
} else {
if ($options['enable_file_monitor'] ?? true) {
Timer::add(1, function () {
$this->checkAllFilesChange();
});
}
}
$memoryLimit = $this->getMemoryLimit($options['memory_limit'] ?? null);
if ($memoryLimit && ($options['enable_memory_monitor'] ?? true)) {
Timer::add(60, [$this, 'checkMemory'], [$memoryLimit]);
}
}
/**
* @param $monitorDir
* @return bool
*/
public function checkFilesChange($monitorDir): bool
{
static $lastMtime, $tooManyFilesCheck;
if (!$lastMtime) {
$lastMtime = time();
}
clearstatcache();
if (!is_dir($monitorDir)) {
if (!is_file($monitorDir)) {
return false;
}
$iterator = [new SplFileInfo($monitorDir)];
} else {
// recursive traversal directory
$dirIterator = new RecursiveDirectoryIterator($monitorDir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS);
$iterator = new RecursiveIteratorIterator($dirIterator);
}
$count = 0;
foreach ($iterator as $file) {
$count ++;
/** var SplFileInfo $file */
if (is_dir($file->getRealPath())) {
continue;
}
// check mtime
if (in_array($file->getExtension(), $this->extensions, true) && $lastMtime < $file->getMTime()) {
$lastMtime = $file->getMTime();
if (DIRECTORY_SEPARATOR === '/' && isset($this->loadedFiles[$file->getRealPath()])) {
echo "$file updated but cannot be reloaded because only auto-loaded files support reload.\n";
continue;
}
$var = 0;
exec('"'.PHP_BINARY . '" -l ' . $file, $out, $var);
if ($var) {
continue;
}
echo $file . " updated and reload\n";
// send SIGUSR1 signal to master process for reload
if (DIRECTORY_SEPARATOR === '/' && $this->ppid > 1) {
posix_kill($this->ppid, SIGUSR1);
} else {
return true;
}
break;
}
}
if (!$tooManyFilesCheck && $count > 1000) {
echo "Monitor: There are too many files ($count files) in $monitorDir which makes file monitoring very slow\n";
$tooManyFilesCheck = 1;
}
return false;
}
/**
* @return bool
*/
public function checkAllFilesChange(): bool
{
if (static::isPaused()) {
return false;
}
foreach ($this->paths as $path) {
if ($this->checkFilesChange($path)) {
return true;
}
}
return false;
}
/**
* @param $memoryLimit
* @return void
*/
public function checkMemory($memoryLimit): void
{
if (static::isPaused() || $memoryLimit <= 0) {
return;
}
$ppid = $this->ppid;
if ($ppid <= 1) {
return;
}
$processPath = "/proc/$ppid";
if (!is_dir($processPath)) {
// Process not exist
$this->ppid = 0;
return;
}
$childrenFile = "/proc/$ppid/task/$ppid/children";
if (!is_file($childrenFile) || !($children = file_get_contents($childrenFile))) {
return;
}
foreach (explode(' ', $children) as $pid) {
$pid = (int)$pid;
$statusFile = "/proc/$pid/status";
if (!is_file($statusFile) || !($status = file_get_contents($statusFile))) {
continue;
}
$mem = 0;
if (preg_match('/VmRSS\s*?:\s*?(\d+?)\s*?kB/', $status, $match)) {
$mem = $match[1];
}
$mem = (int)($mem / 1024);
if ($mem >= $memoryLimit) {
posix_kill($pid, SIGINT);
}
}
}
/**
* Get memory limit
* @param $memoryLimit
* @return int
*/
protected function getMemoryLimit($memoryLimit): int
{
if ($memoryLimit === 0) {
return 0;
}
$usePhpIni = false;
if (!$memoryLimit) {
$memoryLimit = ini_get('memory_limit');
$usePhpIni = true;
}
if ($memoryLimit == -1) {
return 0;
}
$unit = strtolower($memoryLimit[strlen($memoryLimit) - 1]);
$memoryLimit = (int)$memoryLimit;
if ($unit === 'g') {
$memoryLimit = 1024 * $memoryLimit;
} else if ($unit === 'k') {
$memoryLimit = ($memoryLimit / 1024);
} else if ($unit === 'm') {
$memoryLimit = (int)($memoryLimit);
} else if ($unit === 't') {
$memoryLimit = (1024 * 1024 * $memoryLimit);
} else {
$memoryLimit = ($memoryLimit / (1024 * 1024));
}
if ($memoryLimit < 50) {
$memoryLimit = 50;
}
if ($usePhpIni) {
$memoryLimit = (0.8 * $memoryLimit);
}
return (int)$memoryLimit;
}
}
+55
View File
@@ -0,0 +1,55 @@
<?php
namespace app\service;
use OSS\OssClient;
use OSS\Core\OssException;
class OssService
{
private $accessKeyId;
private $accessKeySecret;
private $bucket;
private $endpoint;
private $ossClient;
public function __construct()
{
$this->accessKeyId = 'LTAI5tAGiH7bkVkmrniXnfkA';
$this->accessKeySecret = 'nqklJBft6t3S0A4ZvxF4ci9ni91kmm';
$this->bucket = 'vehicle-album';
$this->endpoint = 'https://oss-cn-beijing.aliyuncs.com';
$this->ossClient = new OssClient($this->accessKeyId, $this->accessKeySecret, $this->endpoint);
}
/**
* 上传图片到 OSS
* @param string $filePath 本地文件路径
* @param string $objectKey OSS上存储的对象名称
* @return string 图片的 URL
*/
public function uploadImage($filePath, $objectKey)
{
try {
// 上传文件到 OSS
$this->ossClient->uploadFile($this->bucket, $objectKey, $filePath);
// 构造图片的私有 URL
$url = $this->generatePrivateUrl($objectKey);
return $url;
} catch (OssException $e) {
// 错误处理
throw new \RuntimeException('OSS Error: ' . $e->getMessage());
}
}
/**
* 生成图片的私有访问 URL
* @param string $objectKey
* @return string
*/
public function generatePrivateUrl($objectKey, $expireTime = 3600)
{
// 生成 OSS 私有 URL(有效期为 3600 秒)
return $this->ossClient->signUrl($this->bucket, $objectKey, $expireTime);
}
}
+14
View File
@@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/favicon.ico"/>
<title>webman</title>
</head>
<body>
hello <?=htmlspecialchars($name)?>
</body>
</html>