目录结构调整
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\Area;
|
||||
use app\util\Util;
|
||||
use support\Request;
|
||||
|
||||
class AreaController
|
||||
{
|
||||
|
||||
public function getAll (Request $request)
|
||||
{
|
||||
$parentId = Util::getParam($request,'parent_id');
|
||||
$level = Util::getParam($request,'level')?:1;
|
||||
$list = $this->getRegions($parentId, $level);
|
||||
return Util::success($list);
|
||||
}
|
||||
|
||||
//递归查询
|
||||
function getRegions($parentId = null, $level = 1, $child = true) {
|
||||
$regions = [];
|
||||
|
||||
$where= array();
|
||||
if(!Util::isEmpty($parentId)){
|
||||
$where['parent_id'] = $parentId;
|
||||
}
|
||||
$where['level'] = $level;
|
||||
$results = Area::where($where)->get();
|
||||
|
||||
foreach ($results as $row) {
|
||||
if($child){
|
||||
$row['children'] = $this->getRegions($row['id'], $row['level'] + 1);
|
||||
}
|
||||
$regions[] = $row;
|
||||
}
|
||||
|
||||
return $regions;
|
||||
}
|
||||
|
||||
public function getCountry (Request $request)
|
||||
{
|
||||
$level = Util::getParam($request,'level')?:1;
|
||||
$list = $this->getRegions(null, $level,false);
|
||||
return Util::success($list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\CarType;
|
||||
use app\model\Customer;
|
||||
use app\util\Util;
|
||||
use PDO;
|
||||
use support\Db;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class CarTypeController
|
||||
{
|
||||
|
||||
public function getAll(Request $request)
|
||||
{
|
||||
$list = CarType::getAll();
|
||||
return Util::success($list);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\Channel;
|
||||
use app\model\Customer;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
|
||||
class CustomerController
|
||||
{
|
||||
/**
|
||||
* 客户分级
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getGrade(Request $request)
|
||||
{
|
||||
$grade = [];
|
||||
foreach (Constants::GRADE as $key => $value) {
|
||||
$grade[] = [
|
||||
'id' => $key,
|
||||
'name' => $value,
|
||||
];
|
||||
}
|
||||
return Util::success($grade);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商机
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getMagnitude(Request $request)
|
||||
{
|
||||
$grade = [];
|
||||
foreach (Constants::MAGNITUDE as $key => $value) {
|
||||
$grade[] = [
|
||||
'id' => $key,
|
||||
'name' => $value,
|
||||
];
|
||||
}
|
||||
return Util::success($grade);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户渠道
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getChannel(Request $request)
|
||||
{
|
||||
$list = Channel::getAll();
|
||||
return Util::success($list);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
|
||||
$where = [];
|
||||
|
||||
$userId = $request->user['id'];
|
||||
if (Util::isEmpty($userId)) {
|
||||
return Util::fail(['user_id' => $userId], trans('user_none'));
|
||||
}
|
||||
if ($request->user['role'] != 1) {
|
||||
$where['user_id'] = $userId;
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
$data = Customer::where($where)
|
||||
->orderBy('id', 'desc')
|
||||
->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
foreach ($data->items() as &$value) {
|
||||
$value = Customer::getCustomer($value);
|
||||
}
|
||||
|
||||
return Util::page($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户详情
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function detail(Request $request)
|
||||
{
|
||||
$id = Util::getParam($request, 'id');
|
||||
if (Util::isEmpty($id)) {
|
||||
return Util::fail([], 'id' . trans('not_null'));
|
||||
}
|
||||
|
||||
$res = Customer::select('id', 'user_id', 'grade', 'channel_id','car_type_id', 'country_id', 'magnitude', 'email', 'phone', 'WhatsApp', 'contacts', 'describe')
|
||||
->where('id', $id)
|
||||
->first();
|
||||
if ($res) {
|
||||
$res->toArray();
|
||||
} else {
|
||||
return Util::fail([], '记录不存在');
|
||||
}
|
||||
|
||||
$res = Customer::getCustomer($res);
|
||||
|
||||
return Util::success($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户录入
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$id = Util::getParam($request, 'id');
|
||||
$channel_id = Util::getParam($request, 'channel_id');
|
||||
if (Util::isEmpty($channel_id)) {
|
||||
return Util::fail([], 'channel_id' . trans('not_null'));
|
||||
}
|
||||
$country_id = Util::getParam($request, 'country_id');
|
||||
if (Util::isEmpty($country_id)) {
|
||||
// return Util::fail([],'country_id'.trans('not_null'));
|
||||
}
|
||||
$car_type_id = Util::getParam($request, 'car_type_id');
|
||||
if (Util::isEmpty($car_type_id)) {
|
||||
return Util::fail([], 'car_type_id' . trans('not_null'));
|
||||
}
|
||||
$contacts = Util::getParam($request, 'contacts');
|
||||
$email = Util::getParam($request, 'email');
|
||||
$phone = Util::getParam($request, 'phone');
|
||||
if (Util::isEmpty($contacts) && Util::isEmpty($email) && Util::isEmpty($phone)) {
|
||||
return Util::fail([], 'country_id' . trans('not_null'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'user_id' => $request->user['id'],
|
||||
'grade' => Util::getParam($request, 'grade', 0),
|
||||
'channel_id' => $channel_id,
|
||||
'country_id' => $country_id,
|
||||
'car_type_id' => $car_type_id,
|
||||
'magnitude' => Util::getParam($request, 'magnitude', 0),
|
||||
'email' => $email,
|
||||
'phone' => $phone,
|
||||
'WhatsApp' => Util::getParam($request, 'WhatsApp',''),
|
||||
'contacts' => $contacts,
|
||||
'describe' => Util::getParam($request, 'describe'),
|
||||
'lat' => Util::getParam($request, 'lat',0),
|
||||
'lng' => Util::getParam($request, 'lng',0),
|
||||
'address' => Util::getParam($request, 'address',''),
|
||||
];
|
||||
|
||||
if (Util::isEmpty($id)) {
|
||||
$res = Customer::create($data);
|
||||
} else {
|
||||
$res = Customer::where('id', $id)
|
||||
->update($data);
|
||||
// Log::info('update', ['res' => $res]);
|
||||
(!$res)?: $res=Customer::find($id)->toArray();
|
||||
}
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res,trans('save_success'));
|
||||
} else {
|
||||
return Util::fail($res,trans('save_fail'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\Customer;
|
||||
use app\model\Follow;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use Google\Cloud\Speech\V2\Client\SpeechClient;
|
||||
use Google\Cloud\Speech\V2\RecognitionConfig;
|
||||
use support\Request;
|
||||
|
||||
class FollowController
|
||||
{
|
||||
/**
|
||||
* 客户分级
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function getFollowType(Request $request)
|
||||
{
|
||||
$grade = [];
|
||||
foreach (Constants::FOLLOW as $key => $value) {
|
||||
$grade[] = [
|
||||
'status' => $key,
|
||||
'text' => $value,
|
||||
];
|
||||
}
|
||||
return Util::success($grade);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 跟进列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
|
||||
//客户id
|
||||
$customer_id = Util::getParam($request,'customer_id');
|
||||
if(Util::isEmpty($customer_id)){
|
||||
return Util::fail([],'customer_id'.trans('not_null'));
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$where['customer_id'] = $customer_id;
|
||||
|
||||
//用户角色
|
||||
$userId = $request->user['id'];
|
||||
if(Util::isEmpty($userId)){
|
||||
return Util::fail(['user_id'=>$userId],trans('user_none'));
|
||||
}
|
||||
if($request->user['role']!=1){
|
||||
$where['user_id'] = $userId;
|
||||
}
|
||||
|
||||
//跟进id
|
||||
$id = Util::getParam($request,'id');
|
||||
if(!Util::isEmpty($id)){
|
||||
$where['id'] = $id;
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
$data = Follow::where($where)
|
||||
->orderBy('id', 'desc')
|
||||
->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
|
||||
// $host = $request->host();
|
||||
$url = 'http:'.$request->url();
|
||||
foreach ($data->items() as &$value){
|
||||
$value = Follow::getFollow($value,$url);
|
||||
}
|
||||
|
||||
return Util::page($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 跟进详情
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function detail(Request $request)
|
||||
{
|
||||
//跟进id
|
||||
$id = Util::getParam($request,'id');
|
||||
if(Util::isEmpty($id)){
|
||||
return Util::fail([],'id'.trans('not_null'));
|
||||
}
|
||||
|
||||
$res = Follow::select('id','user_id','customer_id','type','picture','remark','audio','audio_text','lat','lng','address')
|
||||
->where('id',$id)
|
||||
->first();
|
||||
if($res){
|
||||
$res->toArray();
|
||||
}else{
|
||||
return Util::fail([],'记录不存在');
|
||||
}
|
||||
|
||||
$res = Follow::getFollow($res);
|
||||
|
||||
return Util::success($res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户录入
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$customer_id = Util::getParam($request,'customer_id');
|
||||
|
||||
if(Util::isEmpty($customer_id)){
|
||||
return Util::fail([],'customer_id'.trans('not_null'));
|
||||
}
|
||||
$type = Util::getParam($request,'type');
|
||||
if(Util::isEmpty($type)){
|
||||
return Util::fail([],'type'.trans('not_null'));
|
||||
}
|
||||
$picture = Util::getParam($request,'picture');
|
||||
if(Util::isEmpty($picture)){
|
||||
return Util::fail([],'picture'.trans('not_null'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'user_id'=>$request->user['id'],
|
||||
'customer_id'=>$customer_id,
|
||||
'type'=>$type,
|
||||
'picture'=>$picture,
|
||||
'remark'=>Util::getParam($request,'remark',''),
|
||||
'audio'=>Util::getParam($request,'audio',''),
|
||||
'audio_text'=>Util::getParam($request,'audio',''),
|
||||
'lat'=>Util::getParam($request,'lat',0),
|
||||
'lng'=>Util::getParam($request,'lng',0),
|
||||
'address1'=>Util::getParam($request,'address'),
|
||||
];
|
||||
|
||||
$res = Follow::create($data);
|
||||
|
||||
$customer = Customer::find($customer_id);
|
||||
$customer->follow_last = $res->created_at;
|
||||
$customer->save();
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res,trans('save_success'));
|
||||
} else {
|
||||
return Util::fail($res,trans('save_fail'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
//use support\Request;
|
||||
//use support\Log;
|
||||
//use Webman\Http\Response;
|
||||
|
||||
use app\util\Util;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
|
||||
class UploadController
|
||||
{
|
||||
// 允许的文件类型
|
||||
protected $allowedMimeTypes = [
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/png',
|
||||
'image/gif',
|
||||
'application/pdf',
|
||||
'text/plain'
|
||||
];
|
||||
|
||||
// 最大文件大小(5MB)
|
||||
protected $maxFileSize = 5 * 1024 * 1024;
|
||||
|
||||
public function upload(Request $request): \support\Response
|
||||
{
|
||||
try {
|
||||
// 获取上传的文件(支持多文件)
|
||||
$files = $request->file('files');
|
||||
|
||||
// 如果没有文件上传
|
||||
if (!$files) {
|
||||
throw new \Exception('未上传任何文件');
|
||||
}
|
||||
|
||||
// 单文件转换为数组统一处理
|
||||
if (!is_array($files)) {
|
||||
$files = [$files];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($files as $file) {
|
||||
// 检查文件是否上传成功
|
||||
if (!$file->isValid()) {
|
||||
throw new \Exception($file->getUploadErrorMessage());
|
||||
}
|
||||
|
||||
// 校验文件类型
|
||||
if (!in_array($file->getUploadMineType(), $this->allowedMimeTypes)) {
|
||||
throw new \Exception('不支持的文件类型: ' . $file->getUploadMineType());
|
||||
}
|
||||
|
||||
// 校验文件大小
|
||||
$fileSize = $file->getSize();
|
||||
if ($fileSize > $this->maxFileSize) {
|
||||
throw new \Exception('文件大小超过限制');
|
||||
}
|
||||
|
||||
// 生成唯一文件名(防止覆盖)
|
||||
$filename = uniqid() . '.' . $file->getUploadExtension();
|
||||
|
||||
// 保存路径(例如:runtime/uploads/202310)
|
||||
$savePath = runtime_path('uploads/' . date('Ym/d'));
|
||||
if (!is_dir($savePath)) {
|
||||
mkdir($savePath, 0755, true);
|
||||
}
|
||||
|
||||
// 移动文件到目标路径
|
||||
$file->move($savePath . '/' . $filename);
|
||||
|
||||
// 记录上传信息
|
||||
Log::info('文件上传成功', [
|
||||
'original_name' => $file->getUploadName(),
|
||||
'saved_path' => $savePath . '/' . $filename,
|
||||
'size' => $fileSize
|
||||
]);
|
||||
|
||||
$result = [
|
||||
'original_name' => $file->getUploadName(),
|
||||
'saved_name' => $filename,
|
||||
'path' => 'uploads/' . date('Ym') . '/' . $filename,
|
||||
'size' => $fileSize,
|
||||
'mime_type' => $file->getUploadMineType()
|
||||
];
|
||||
}
|
||||
|
||||
return Util::success($result,'上传成功');
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('文件上传失败: ' . $e->getMessage());
|
||||
|
||||
return Util::fail([],$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\User;
|
||||
use app\service\MailService;
|
||||
use app\util\JwtUtil;
|
||||
use app\util\Util;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class UserController
|
||||
{
|
||||
/**
|
||||
* 不需要登录的方法
|
||||
*/
|
||||
protected $noNeedLogin = ['login', 'sendCode', 'register'];
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
$email = Util::getParam($request, 'email');
|
||||
if (Util::isEmpty($email)) {
|
||||
return Util::fail([], 'email' . trans('not_null'));
|
||||
}
|
||||
$password = Util::getParam($request, 'password');
|
||||
if (Util::isEmpty($password)) {
|
||||
return Util::fail([], 'password' . trans('not_null'));
|
||||
}
|
||||
$user = User::select(['id', 'name', 'sex', 'role', 'avatar', 'email', 'password'])
|
||||
->where('status', 0)
|
||||
->where('email', $request->post('email'))
|
||||
->first();
|
||||
if (!$user) {
|
||||
return Util::fail(['user' => $user], trans('user_none'));
|
||||
}
|
||||
$user = $user->toArray();
|
||||
|
||||
$userPassword = $user['password'];
|
||||
|
||||
//加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
//验证密码
|
||||
if (!password_verify($userPassword, $hashedPassword)) {
|
||||
return Util::fail([], trans('password_error'));
|
||||
}
|
||||
$userId = $user['id']; // 实际从数据库获取
|
||||
|
||||
|
||||
Redis::set('user_' . $userId, $user);
|
||||
|
||||
//密码验证成功后加密生成 Token
|
||||
$token = JwtUtil::generateToken($userId);
|
||||
$result = $user;
|
||||
unset($result['password']);
|
||||
$result['token'] = $token;
|
||||
|
||||
return Util::success($result, trans('login_success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮箱验证码
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \Random\RandomException
|
||||
*/
|
||||
public function sendCode(Request $request)
|
||||
{
|
||||
$email = Util::getParam($request,'email');
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
return Util::fail([], 'email' . trans('not_null'));
|
||||
}
|
||||
|
||||
// 生成验证码
|
||||
$code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
|
||||
|
||||
// 发送邮件
|
||||
$mailService = new MailService();
|
||||
if ($mailService->sendVerificationCode($email, $code)) {
|
||||
// 存储验证码到 Redis
|
||||
Redis::set("verification_code:{$email}", $code, 300);
|
||||
return Util::success([], '验证码已发送');
|
||||
}
|
||||
|
||||
return Util::fail([], '邮件发送失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \Random\RandomException
|
||||
*/
|
||||
public function register(Request $request)
|
||||
{
|
||||
$email = Util::getParam($request,'email','asdf');
|
||||
$code = Util::getParam($request,'code');
|
||||
$sex = Util::getParam($request,'sex',0);
|
||||
$name = Util::getParam($request,'name',0);
|
||||
$password = Util::getParam($request,'password');
|
||||
$mobile = Util::getParam($request,'mobile');
|
||||
$id = Util::getParam($request,'id');
|
||||
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
return Util::fail([], 'email'.$email . trans('not_null'));
|
||||
}
|
||||
|
||||
$res = User::select('id', 'email')
|
||||
->where('email', $email)
|
||||
->first();
|
||||
// if (!Util::isEmpty($res)) {
|
||||
// return Util::fail([], trans('email_repeat'));
|
||||
// }
|
||||
|
||||
if (Util::isEmpty($name)) {
|
||||
return Util::fail([], 'name' . trans('not_null'));
|
||||
}
|
||||
|
||||
$verification_code = Redis::get("verification_code:{$email}");
|
||||
|
||||
if ($code != $verification_code) {
|
||||
return Util::fail([], trans('code_error'));
|
||||
}
|
||||
|
||||
//加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$data = [
|
||||
'mobile' => $mobile,
|
||||
'email' => $email,
|
||||
'name' => $name,
|
||||
'sex' => $sex,
|
||||
'role' => 1,
|
||||
'password' => $hashedPassword,
|
||||
];
|
||||
|
||||
if (Util::isEmpty($id)) {
|
||||
$res = User::create($data);
|
||||
} else {
|
||||
$res = User::where('id', $id)
|
||||
->update($data);
|
||||
// Log::info('update', ['res' => $res]);
|
||||
(!$res)?: $res=User::find($id)->toArray();
|
||||
}
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res);
|
||||
} else {
|
||||
return Util::fail($res);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Here is your custom functions.
|
||||
*/
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace app\middleware;
|
||||
|
||||
|
||||
use app\model\User;
|
||||
use app\util\JwtUtil;
|
||||
use app\util\Util;
|
||||
use ReflectionClass;
|
||||
use support\Redis;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Webman\MiddlewareInterface;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
//class AuthMiddleware implements MiddlewareInterface
|
||||
//{
|
||||
// public function process(Request $request, callable $handler) : Response
|
||||
// {
|
||||
// //'这里是请求穿越阶段,也就是请求处理前';
|
||||
//
|
||||
// //$response = $handler($request); // 继续向洋葱芯穿越,直至执行控制器得到响应
|
||||
//
|
||||
// //composer require symfony/translation'这里是响应穿出阶段,也就是请求处理后';
|
||||
//
|
||||
// $result = Redis::set('user_id',time());
|
||||
//
|
||||
// $response = $handler($request); // 继续向洋葱芯穿越,直至执行控制器得到响应
|
||||
//
|
||||
// echo '这里是响应穿出阶段,也就是请求处理后';
|
||||
//
|
||||
// return $response;
|
||||
// }
|
||||
//}
|
||||
|
||||
class AuthMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler): Response
|
||||
{
|
||||
// 跳过不需要鉴权的路由(如登录接口)
|
||||
// if ($request->path() === '/api/login') {
|
||||
// return $handler($request);
|
||||
// }
|
||||
// 通过反射获取控制器哪些方法不需要登录
|
||||
$controller = new ReflectionClass($request->controller);
|
||||
$noNeedLogin = $controller->getDefaultProperties()['noNeedLogin'] ?? [];
|
||||
|
||||
$isLogin = !in_array($request->action, $noNeedLogin);
|
||||
// 访问的方法需要登录
|
||||
// if ($isLogin) {
|
||||
// // 拦截请求,返回一个重定向响应,请求停止向洋葱芯穿越
|
||||
// throw new BusinessException('请先登录', 302);
|
||||
// }
|
||||
|
||||
// 从 Header 获取 Token
|
||||
$token = $request->header('Authorization');
|
||||
|
||||
//需要登录并且未提供token
|
||||
if ($isLogin && (!$token || !str_starts_with($token, 'Bearer '))) {
|
||||
throw new BusinessException('请先登录', 302);
|
||||
// throw new BusinessException('未提供 Token'.$isLogin, 401);
|
||||
}elseif(!$isLogin){
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
|
||||
$token = substr($token, 7);
|
||||
try {
|
||||
// 验证 Token 并获取用户ID
|
||||
$decoded = JwtUtil::verifyToken($token);
|
||||
|
||||
$userId = $decoded->sub;
|
||||
|
||||
$user = User::select(['id','name','sex','role','avatar','email','password'])
|
||||
->find($userId);
|
||||
if(!$user){
|
||||
return Util::fail(['user'=>$user],trans('user_none'));
|
||||
}
|
||||
$user = $user->toArray();
|
||||
|
||||
// 将用户ID存入请求对象,供后续使用
|
||||
// $request->user = ['id' => $userId];
|
||||
$request->user = $user;
|
||||
return $handler($request);
|
||||
} catch (BusinessException $e) {
|
||||
return json(['code' => 401, 'msg' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
namespace app\middleware;
|
||||
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Webman\MiddlewareInterface;
|
||||
|
||||
class CrossDomain implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $next): Response
|
||||
{
|
||||
// 动态允许请求来源(支持携带Cookie)
|
||||
$origin = $request->header('origin', '*');
|
||||
$response = $next($request);
|
||||
|
||||
// 设置跨域响应头
|
||||
$response->withHeaders([
|
||||
'Access-Control-Allow-Origin' => $origin,
|
||||
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With',
|
||||
'Access-Control-Allow-Credentials' => 'true', // 允许携带Cookie
|
||||
'Access-Control-Max-Age' => 86400, // 预检请求缓存时间(秒)
|
||||
'Vary' => 'Origin' // 避免缓存干扰
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Area extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'area';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
|
||||
use support\Model;
|
||||
class CarType extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'car_type';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','name','status')->where('status',0)->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use support\Model;
|
||||
|
||||
class Channel extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'channel';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
// 'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'updated_at' => 'timestamp', // 指定序列化格式
|
||||
'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','name','status')->where('status',0)->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Customer extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'customer';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
// 'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'updated_at' => 'timestamp', // 指定序列化格式
|
||||
'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
public static function getCustomer($customer)
|
||||
{
|
||||
$customer['grade_txt'] = Constants::GRADE[$customer['grade']];
|
||||
$customer['magnitude_txt'] = Constants::MAGNITUDE[$customer['magnitude']];
|
||||
$customer['sex_txt'] = Constants::SEX[$customer['sex']];
|
||||
|
||||
if ($customer['grade']<=2) {
|
||||
$customer['follow'] = 0;
|
||||
$customer['follow_txt'] = '跟进中';
|
||||
}elseif ($customer['grade']<=5) {
|
||||
$customer['follow'] = 1;
|
||||
$customer['follow_txt'] = '已成交';
|
||||
}else{
|
||||
$customer['follow'] = 2;
|
||||
$customer['follow_txt'] = '已流失';
|
||||
}
|
||||
|
||||
$where = [
|
||||
'customer_id' => $customer['id']
|
||||
];
|
||||
$begin_follow = Follow::select('id','created_at','updated_at')
|
||||
->where($where)
|
||||
->min('created_at');
|
||||
$customer['begin_follow'] = $begin_follow;
|
||||
$customer['created_at'] = Util::timeTotDate($customer['created_at']);
|
||||
$customer['updated_at'] = Util::timeTotDate($customer['updated_at']);
|
||||
// $customer['last_follow'] = $last_follow;
|
||||
|
||||
return $customer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use config\constants\Constants;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Follow extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'follow';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
// 'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'updated_at' => 'timestamp', // 指定序列化格式
|
||||
'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
public static function getFollow($follow,$domain)
|
||||
{
|
||||
$follow['type_txt'] = Constants::FOLLOW[$follow['type']];
|
||||
$follow['oss_picture'] = $domain.'/'.$follow['picture'];
|
||||
return $follow;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class User extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
|
||||
protected $casts = [
|
||||
// 'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'updated_at' => 'timestamp', // 指定序列化格式
|
||||
'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
public static function getUser($userId)
|
||||
{
|
||||
$user = User::first()->select(['id','name','sex','role','avatar','email','password'])
|
||||
->where('status',0)
|
||||
->toArray();
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace app\process;
|
||||
|
||||
use Webman\App;
|
||||
|
||||
class Http extends App
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
<?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 $paths = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $extensions = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $loadedFiles = [];
|
||||
|
||||
/**
|
||||
* Pause monitor
|
||||
* @return void
|
||||
*/
|
||||
public static function pause()
|
||||
{
|
||||
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 = [])
|
||||
{
|
||||
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 === '/') {
|
||||
posix_kill(posix_getppid(), 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)
|
||||
{
|
||||
if (static::isPaused() || $memoryLimit <= 0) {
|
||||
return;
|
||||
}
|
||||
$ppid = posix_getppid();
|
||||
$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
|
||||
* @return float
|
||||
*/
|
||||
protected function getMemoryLimit($memoryLimit)
|
||||
{
|
||||
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]);
|
||||
if ($unit === 'g') {
|
||||
$memoryLimit = 1024 * (int)$memoryLimit;
|
||||
} else if ($unit === 'm') {
|
||||
$memoryLimit = (int)$memoryLimit;
|
||||
} else if ($unit === 'k') {
|
||||
$memoryLimit = ((int)$memoryLimit / 1024);
|
||||
} else {
|
||||
$memoryLimit = ((int)$memoryLimit / (1024 * 1024));
|
||||
}
|
||||
if ($memoryLimit < 30) {
|
||||
$memoryLimit = 30;
|
||||
}
|
||||
if ($usePhpIni) {
|
||||
$memoryLimit = (int)(0.8 * $memoryLimit);
|
||||
}
|
||||
return $memoryLimit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace app\service;
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
use support\Log;
|
||||
|
||||
class MailService
|
||||
{
|
||||
protected $mailer;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->mailer = new PHPMailer(true);
|
||||
$this->configure();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
// SMTP 配置
|
||||
$this->mailer->isSMTP();
|
||||
$this->mailer->Host = 'smtp.qq.com';
|
||||
$this->mailer->SMTPAuth = true;
|
||||
$this->mailer->Username = '1696136552@qq.com'; // 替换为你的 Gmail
|
||||
$this->mailer->Password = 'jhqkgjwzqqzgdcfd'; // 替换为应用专用密码
|
||||
// $this->mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 使用 TLS
|
||||
$this->mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // SSL 加密
|
||||
// $this->mailer->Port = 587;
|
||||
$this->mailer->Port = 465;
|
||||
$this->mailer->CharSet = 'UTF-8';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码邮件
|
||||
* @param string $toEmail 收件邮箱
|
||||
* @param string $code 验证码
|
||||
* @return bool
|
||||
*/
|
||||
public function sendVerificationCode(string $toEmail, string $code): bool
|
||||
{
|
||||
try {
|
||||
$this->mailer->setFrom('1696136552@qq.com', 'XinYouHe'); // 发件人
|
||||
$this->mailer->addAddress($toEmail);
|
||||
|
||||
// 邮件内容
|
||||
$this->mailer->isHTML(true);
|
||||
$this->mailer->Subject = '您的验证码';
|
||||
$this->mailer->Body = "您的CRM验证码是:<strong>{$code}</strong>,5分钟内有效。";
|
||||
|
||||
$this->mailer->send();
|
||||
Log::info("邮件发送成功: {$toEmail}");
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
Log::error("邮件发送失败: " . $this->mailer->ErrorInfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace app\util;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class JwtUtil
|
||||
{
|
||||
/**
|
||||
* 生成 JWT Token
|
||||
* @param int|string $userId
|
||||
* @return string
|
||||
*/
|
||||
public static function generateToken($userId): string
|
||||
{
|
||||
$config = config('jwt');
|
||||
$payload = [
|
||||
'iss' => 'webman', // 签发者
|
||||
'aud' => 'client', // 接收方
|
||||
'iat' => time(), // 签发时间
|
||||
'exp' => time() + $config['expire'], // 过期时间
|
||||
'sub' => $userId // 用户标识
|
||||
];
|
||||
return JWT::encode($payload, $config['secret'], $config['algorithm']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并解析 Token
|
||||
* @param string $token
|
||||
* @return object
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public static function verifyToken(string $token)
|
||||
{
|
||||
$config = config('jwt');
|
||||
try {
|
||||
return JWT::decode($token, new Key($config['secret'], $config['algorithm']));
|
||||
} catch (ExpiredException $e) {
|
||||
throw new BusinessException('Token 已过期', 401);
|
||||
} catch (SignatureInvalidException $e) {
|
||||
throw new BusinessException('Token 无效', 401);
|
||||
} catch (\Exception $e) {
|
||||
throw new BusinessException('鉴权失败', 401);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace app\util;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Firebase\JWT\ExpiredException;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
use support\exception\BusinessException;
|
||||
use support\Request;
|
||||
|
||||
class Util
|
||||
{
|
||||
/**
|
||||
* 参数是否为空
|
||||
*/
|
||||
public static function isEmpty($param)
|
||||
{
|
||||
if(!empty($param) || $param == 0){
|
||||
$result = false;
|
||||
}else{
|
||||
$result = true;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数是否为空
|
||||
*/
|
||||
public static function getParam(Request $request,$param,$default='')
|
||||
{
|
||||
$param = $request->input($param,$default);
|
||||
if(empty($default)&&$default!==''){
|
||||
$param = $default;
|
||||
}
|
||||
return $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
public static function fail($data = [],$message = '', $code = -1)
|
||||
{
|
||||
$result = [
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
public static function success($data = [],$message = '', $code = 0)
|
||||
{
|
||||
$result = [
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
'data' => $data
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询返回
|
||||
*/
|
||||
public static function page($data,$message = '', $code = 0)
|
||||
{
|
||||
$result = [
|
||||
'code' => $code,
|
||||
'message' => $message
|
||||
];
|
||||
|
||||
$result['data'] = [
|
||||
'list' => $data->items(), // 当前页数据
|
||||
'total' => $data->total(), // 总记录数
|
||||
'current_page' => $data->currentPage(),
|
||||
'per_page' => $data->perPage(),
|
||||
'last_page' => $data->lastPage()
|
||||
];
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功日期
|
||||
*/
|
||||
public static function timeTotDate($time = 0, $format = 'Y-m-d H:i:s')
|
||||
{
|
||||
if (empty($time)) {
|
||||
return '';
|
||||
}
|
||||
return date($format, $time);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user