客户与跟进

This commit is contained in:
HESU\HESU 2025-03-14 14:27:33 +08:00
parent 0b95eb8bf0
commit 2dc378734f
23 changed files with 1102 additions and 22 deletions

View File

@ -0,0 +1,42 @@
<?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 json($list);
}
function getRegions($parentId = null, $level = 1) {
$regions = [];
$where= array();
if(!Util::isEmpty($parentId)){
$where['parent_id'] = $parentId;
}
$where['level'] = $level;
$results = Area::where($where)->get();
foreach ($results as $row) {
// $row['level'] = $level; // 添加层级信息
// $regions = array_merge($regions, $this->getRegions($row['id'], $level + 1)); // 递归调用
$row['children'] = $this->getRegions($row['id'], $row['level'] + 1);
$regions[] = $row;
}
return $regions;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace app\controller;
use app\model\CarType;
use app\model\Customer;
use PDO;
use support\Db;
use support\Redis;
use support\Request;
class CarTypeController
{
public function getAll(Request $request)
{
$list = CarType::getAll();
return json($list);
}
}

View File

@ -3,16 +3,165 @@
namespace app\controller; namespace app\controller;
use app\model\Customer; use app\model\Customer;
use app\util\Util;
use config\constants\Constants;
use support\Log;
use support\Request; use support\Request;
class CustomerController class CustomerController
{ {
public function list(Request $request) /**
* 客户分级
* @param Request $request
* @return \support\Response
*/
public function getGrade(Request $request)
{ {
$list = Customer::get()->toArray(); $grade = [];
return json($list); foreach (Constants::GRADE as $key => $value) {
$grade[] = [
'status' => $key,
'text' => $value,
];
}
return json($grade);
} }
/**
* 客户偏好
* @param Request $request
* @return \support\Response
*/
public function getCarType(Request $request)
{
$grade = [];
foreach (Constants::GRADE as $key => $value) {
$grade[] = [
'status' => $key,
'text' => $value,
];
}
return json($grade);
}
/**
* 客户列表
* @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);
} else {
return Util::fail($res);
}
}
} }

View File

@ -0,0 +1,153 @@
<?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);
foreach ($data->items() as &$value){
$value = Follow::getFollow($value);
}
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'),
'lng'=>Util::getParam($request,'lng'),
'address'=>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);
}else{
return Util::fail($res);
}
}
}

View File

@ -2,14 +2,61 @@
namespace app\controller; namespace app\controller;
use app\model\User;
use app\util\JwtUtil;
use app\util\Util;
use support\Redis;
use support\Request; use support\Request;
class UserController class UserController
{ {
/**
* 不需要登录的方法
*/
protected $noNeedLogin = ['login'];
public function login(Request $request) public function login(Request $request)
{ {
return json([]); // Util::isEmpty($request->post('email'));
$email = Util::getParam($request,'email');
if(Util::isEmpty($email)){
return Util::fail([],'email'.trans('not_null'));
}
// Util::isEmpty($request->post('password'));
$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'));
} }

View File

@ -0,0 +1,84 @@
<?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);
}
$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()]);
}
}
}

25
webman/app/model/Area.php Normal file
View File

@ -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';
}

View File

@ -0,0 +1,38 @@
<?php
namespace app\model;
use support\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
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 = CarType::get()->select('id','name','status')->where('status',0)->toArray();
return $list;
}
}

View File

@ -3,7 +3,10 @@
namespace app\model; namespace app\model;
use Illuminate\Database\Eloquent\Model; use app\util\Util;
use config\constants\Constants;
use support\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Customer extends Model class Customer extends Model
{ {
@ -21,10 +24,51 @@ class Customer extends Model
*/ */
protected $primaryKey = 'id'; protected $primaryKey = 'id';
//设置黑名单
protected $guarded = ['id','created_at','updated_at'];
// 指定日期字段存储格式为时间戳
protected $dateFormat = 'U';
/** /**
* Indicates if the model should be timestamped. * Indicates if the model should be timestamped.
* *
* @var bool * @var bool
*/ */
public $timestamps = false; 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']];
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['last_follow'] = $last_follow;
return $customer;
}
} }

View File

@ -0,0 +1,51 @@
<?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)
{
$follow['type_txt'] = Constants::FOLLOW[$follow['type']];
return $follow;
}
}

40
webman/app/model/User.php Normal file
View File

@ -0,0 +1,40 @@
<?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;
public static function getUser($userId)
{
$user = User::first()->select(['id','name','sex','role','avatar','email','password'])
->where('status',0)
->toArray();
return $user;
}
}

View File

@ -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);
}
}
}

83
webman/app/util/Util.php Normal file
View File

@ -0,0 +1,83 @@
<?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);
return $param;
}
/**
* 失败
*/
public static function fail($data = [],$message = '', $code = '500')
{
$result = [
'code' => $code,
'message' => $message,
'data' => $data
];
return json($result);
}
/**
* 成功
*/
public static function success($data = [],$message = '', $code = '200')
{
$result = [
'code' => $code,
'message' => $message,
'data' => $data
];
return json($result);
}
/**
* 分页查询返回
*/
public static function page($data,$message = '', $code = '200')
{
$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);
}
}

View File

@ -30,7 +30,11 @@
"illuminate/events": "^11.44", "illuminate/events": "^11.44",
"webman/database": "^2.1", "webman/database": "^2.1",
"illuminate/pagination": "^11.44", "illuminate/pagination": "^11.44",
"symfony/var-dumper": "^7.2" "symfony/var-dumper": "^7.2",
"webman/redis": "^2.1",
"symfony/translation": "^7.2",
"firebase/php-jwt": "^6.11",
"illuminate/database": "^11.44"
}, },
"suggest": { "suggest": {
"ext-event": "For better performance. " "ext-event": "For better performance. "

165
webman/composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "4e20de5533cd343aeb926809636ce49a", "content-hash": "f3ffc56f1691457e45c7053ac636e4be",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@ -226,6 +226,69 @@
], ],
"time": "2024-02-18T20:23:39+00:00" "time": "2024-02-18T20:23:39+00:00"
}, },
{
"name": "firebase/php-jwt",
"version": "v6.11.0",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/8f718f4dfc9c5d5f0c994cdfd103921b43592712",
"reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"guzzlehttp/guzzle": "^7.4",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"psr/cache": "^2.0||^3.0",
"psr/http-client": "^1.0",
"psr/http-factory": "^1.0"
},
"suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
},
"type": "library",
"autoload": {
"psr-4": {
"Firebase\\JWT\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Neuman Vong",
"email": "neuman+pear@twilio.com",
"role": "Developer"
},
{
"name": "Anant Narayanan",
"email": "anant@php.net",
"role": "Developer"
}
],
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt",
"keywords": [
"jwt",
"php"
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.11.0"
},
"time": "2025-01-23T05:11:06+00:00"
},
{ {
"name": "illuminate/bus", "name": "illuminate/bus",
"version": "v11.44.1", "version": "v11.44.1",
@ -482,16 +545,16 @@
}, },
{ {
"name": "illuminate/database", "name": "illuminate/database",
"version": "v11.44.1", "version": "v11.44.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/illuminate/database.git", "url": "https://github.com/illuminate/database.git",
"reference": "131dcdfcc6c838115d5e58c77d4fe816f735dff8" "reference": "a63391e43a6d38beb40fa21fc020d16c9b5352ea"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/illuminate/database/zipball/131dcdfcc6c838115d5e58c77d4fe816f735dff8", "url": "https://api.github.com/repos/illuminate/database/zipball/a63391e43a6d38beb40fa21fc020d16c9b5352ea",
"reference": "131dcdfcc6c838115d5e58c77d4fe816f735dff8", "reference": "a63391e43a6d38beb40fa21fc020d16c9b5352ea",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -547,7 +610,7 @@
"issues": "https://github.com/laravel/framework/issues", "issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework" "source": "https://github.com/laravel/framework"
}, },
"time": "2025-02-21T13:01:45+00:00" "time": "2025-03-12T14:13:54+00:00"
}, },
{ {
"name": "illuminate/events", "name": "illuminate/events",
@ -748,6 +811,60 @@
}, },
"time": "2025-02-17T16:02:42+00:00" "time": "2025-02-17T16:02:42+00:00"
}, },
{
"name": "illuminate/redis",
"version": "v11.44.1",
"source": {
"type": "git",
"url": "https://github.com/illuminate/redis.git",
"reference": "21eb42b3d3271b3365a3685cb552b31cda1de255"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/redis/zipball/21eb42b3d3271b3365a3685cb552b31cda1de255",
"reference": "21eb42b3d3271b3365a3685cb552b31cda1de255",
"shasum": ""
},
"require": {
"illuminate/collections": "^11.0",
"illuminate/contracts": "^11.0",
"illuminate/macroable": "^11.0",
"illuminate/support": "^11.0",
"php": "^8.2"
},
"suggest": {
"ext-redis": "Required to use the phpredis connector (^4.0|^5.0|^6.0).",
"predis/predis": "Required to use the predis connector (^2.3)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "11.x-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Redis\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "The Illuminate Redis package.",
"homepage": "https://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2025-02-17T15:53:37+00:00"
},
{ {
"name": "illuminate/support", "name": "illuminate/support",
"version": "v11.44.1", "version": "v11.44.1",
@ -2010,6 +2127,42 @@
}, },
"time": "2025-02-24T07:14:57+00:00" "time": "2025-02-24T07:14:57+00:00"
}, },
{
"name": "webman/redis",
"version": "v2.1.2",
"source": {
"type": "git",
"url": "https://github.com/webman-php/redis.git",
"reference": "83893f0931e07906ba9dbf976126ad8338f40624"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webman-php/redis/zipball/83893f0931e07906ba9dbf976126ad8338f40624",
"reference": "83893f0931e07906ba9dbf976126ad8338f40624",
"shasum": ""
},
"require": {
"illuminate/redis": "^10.0 || ^11.0",
"workerman/webman-framework": "^2.1 || dev-master"
},
"type": "library",
"autoload": {
"psr-4": {
"support\\": "src/support",
"Webman\\Redis\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Webman redis",
"support": {
"issues": "https://github.com/webman-php/redis/issues",
"source": "https://github.com/webman-php/redis/tree/v2.1.2"
},
"time": "2025-02-14T11:36:24+00:00"
},
{ {
"name": "workerman/coroutine", "name": "workerman/coroutine",
"version": "v1.1.3", "version": "v1.1.3",

View File

@ -0,0 +1,43 @@
<?php
namespace config\constants;
class Constants
{
//客户分级
public const CUSTOMER_GRADE_INITIAL = 0; // 初步接触
public const CUSTOMER_GRADE_COMMUNICATE = 1; // 需求沟通
public const CUSTOMER_GRADE_PLAN = 2; // 方案推进
public const CUSTOMER_GRADE_DEAL = 3; // 成交阶段
public const CUSTOMER_GRADE_SALES = 4; // 售后阶段
public const CUSTOMER_GRADE_LOSS = 5; // 停滞或流失
public const GRADE = [
self::CUSTOMER_GRADE_INITIAL => '初步接触',
self::CUSTOMER_GRADE_COMMUNICATE => '需求沟通',
self::CUSTOMER_GRADE_PLAN => '方案推进',
self::CUSTOMER_GRADE_DEAL => '成交阶段',
self::CUSTOMER_GRADE_SALES => '售后阶段',
self::CUSTOMER_GRADE_LOSS => '停滞或流失',
];
//客户重要性
public const CUSTOMER_MAGNITUDE_INITIAL = 0; // 金牌商机
public const CUSTOMER_MAGNITUDE_COMMUNICATE = 1; // 银牌商机
public const CUSTOMER_MAGNITUDE_PLAN = 2; // 铜牌商机
public const MAGNITUDE = [
self::CUSTOMER_MAGNITUDE_INITIAL => '金牌商机',
self::CUSTOMER_MAGNITUDE_COMMUNICATE => '银牌商机',
self::CUSTOMER_MAGNITUDE_PLAN => '铜牌商机',
];
//跟进类型
public const CUSTOMER_FOLLOW_VISIT = 0; // 线下拜访
public const CUSTOMER_FOLLOW_UP = 1; // 线上跟进
public const FOLLOW = [
self::CUSTOMER_FOLLOW_VISIT => '线下拜访',
self::CUSTOMER_FOLLOW_UP => '线上跟进',
];
}

View File

@ -9,12 +9,12 @@ return [
'driver' => 'mysql', 'driver' => 'mysql',
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'port' => 3306, 'port' => 3306,
'database' => 'root', 'database' => 'xyh_crm',
'username' => 'root', 'username' => 'root',
'password' => '', 'password' => 'root',
'unix_socket' => '', 'unix_socket' => '',
'charset' => 'utf8', 'charset' => 'utf8',
'collation' => 'utf8mb4_general_ci', 'collation' => 'utf8_unicode_ci',
'prefix' => '', 'prefix' => '',
'strict' => true, 'strict' => true,
'engine' => null, 'engine' => null,
@ -27,7 +27,7 @@ return [
], ],
], ],
'sqlite' => [ /*'sqlite' => [
'driver' => 'sqlite', 'driver' => 'sqlite',
'database' => '', 'database' => '',
'prefix' => '', 'prefix' => '',
@ -76,6 +76,6 @@ return [
'idle_timeout' => 60, // 连接池中连接最大空闲时间超时后会关闭回收直到连接数为min_connections 'idle_timeout' => 60, // 连接池中连接最大空闲时间超时后会关闭回收直到连接数为min_connections
'heartbeat_interval' => 50, // 连接池心跳检测时间单位秒建议小于60秒 'heartbeat_interval' => 50, // 连接池心跳检测时间单位秒建议小于60秒
], ],
], ],*/
], ],
]; ];

6
webman/config/jwt.php Normal file
View File

@ -0,0 +1,6 @@
<?php
return [
'secret' => 'Hj3$kLm8NpQrStUvXwZ1y2C4D6E8G', // 替换为高强度的密钥
'algorithm' => 'HS256', // 加密算法
'expire' => 3600 * 24 * 7, // 过期时间7天
];

View File

@ -12,4 +12,9 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License * @license http://www.opensource.org/licenses/mit-license.php MIT License
*/ */
return []; return [
// 全局中间件
'' => [
app\middleware\AuthMiddleware::class,
]
];

30
webman/config/redis.php Normal file
View File

@ -0,0 +1,30 @@
<?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
*/
return [
'default' => [
'password' => '',
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
// Connection pool, supports only Swoole or Swow drivers.
'pool' => [
'max_connections' => 5,
'min_connections' => 1,
'wait_timeout' => 3,
'idle_timeout' => 60,
'heartbeat_interval' => 50,
],
]
];

View File

@ -16,10 +16,10 @@
* Multilingual configuration * Multilingual configuration
*/ */
return [ return [
// Default language // 默认语言
'locale' => 'zh_CN', 'locale' => 'zh_CN',
// Fallback language // 回退语言,当前语言中无法找到翻译时则尝试使用回退语言中的翻译
'fallback_locale' => ['zh_CN', 'en'], 'fallback_locale' => ['zh_CN', 'en'],
// Folder where language files are stored // Folder where language files are stored
'path' => base_path() . '/resource/translations', 'path' => base_path() . '/resource/translations',
]; ];

View File

@ -0,0 +1,11 @@
<?php
return [
'success' => '成功',
'fail' => '成功',
'login_success' => '登录成功',
'password_error' => '密码错误',
'user_none' => '用户不存在',
'not_null' => '不能为空',
];

View File

@ -2,4 +2,5 @@
<?php <?php
chdir(__DIR__); chdir(__DIR__);
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/config/constants/Constants.php';
support\App::run(); support\App::run();