Compare commits
112 Commits
feature/mzl授权
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| ac35fccbbf | |||
| fa4ade4b35 | |||
| 1ccaced113 | |||
| bfd458aeb7 | |||
| d42167bf14 | |||
| 7711b76ac3 | |||
| c9674a6ad9 | |||
| 7ab9151e4a | |||
| a8041c4785 | |||
| 0d59666ca4 | |||
| c3d9527532 | |||
| c954218088 | |||
| 88dc849bd5 | |||
| 00c8bb9c50 | |||
| f9175f7dd4 | |||
| b2b96dd1bd | |||
| 3a5c8b4304 | |||
| 85009b64ef | |||
| 541fbd8557 | |||
| 698448dcc6 | |||
| 012cc4d5aa | |||
| 25aed90f46 | |||
| 6baf3dd44f | |||
| 6247d8cf4d | |||
| 40fff988ce | |||
| facbae2a95 | |||
| 833d82c19a | |||
| aa1d458467 | |||
| a2d10d1a1c | |||
| de7dcdf011 | |||
| 7595e24cef | |||
| 522183cb71 | |||
| 8bb0826b06 | |||
| fa54dcca48 | |||
| 7b5be3e732 | |||
| c0ff3916ee | |||
| ba5c874c74 | |||
| 4934e4482c | |||
| b9b3f49964 | |||
| 4e0e8cf264 | |||
| 76466db0fb | |||
| bc270c8c24 | |||
| 4aaf782633 | |||
| 77e38a2883 | |||
| 47a7aa345a | |||
| 0011443a04 | |||
| 5b297966e5 | |||
| eed1968f92 | |||
| c79bb1f8af | |||
| bbe494400f | |||
| 3d68efed14 | |||
| 64d294f3c8 | |||
| 2cf5eacfe7 | |||
| a005d98532 | |||
| c1fb19dbf7 | |||
| 4cde16f76a | |||
| d9f6ee8ea2 | |||
| ee51bc3899 | |||
| 8b19071d1c | |||
| a9e83695ae | |||
| aae930a16e | |||
| 7f6bf16440 | |||
| 1e890f8f06 | |||
| fa27b28ca8 | |||
| 2ce58106f7 | |||
| 80a7541d0c | |||
| 4d28cd88ca | |||
| 16a7ea2976 | |||
| a908619084 | |||
| aff152e40d | |||
| eeca83c3df | |||
| 9a68f72826 | |||
| 6e79dd47c4 | |||
| 9f3bfacc2f | |||
| 90ec9a7ad8 | |||
| af3398fa70 | |||
| 1a263900e8 | |||
| aaf8981369 | |||
| 1a947df500 | |||
| 4742b37391 | |||
| a643694bfa | |||
| 1833eb012d | |||
| d511b2fdb5 | |||
| 8cbf82fb2d | |||
| 23ffdab0f6 | |||
| d5c9d1a7a5 | |||
| 68eb23e316 | |||
| cef8472965 | |||
| fc1825a1c7 | |||
| 6184f69ddd | |||
| 06f2531ec0 | |||
| fc6e7c2063 | |||
| 1773ab9863 | |||
| d14945e546 | |||
| 8cee9fa81b | |||
| d8d790f96e | |||
| b7775cafcf | |||
| b9f5e671bc | |||
| a1f20d4877 | |||
| 656733c00a | |||
| b6409a69ed | |||
| 97250ca23e | |||
| 3fd7183b70 | |||
| 625b5123bb | |||
| 504bf7885c | |||
| e58ed1ee14 | |||
| b6d2e285d2 | |||
| 3c313b4f34 | |||
| c0c5138ac8 | |||
| e2e506a91f | |||
| 6e1eb75bb1 | |||
| eae3e9c09f |
+8
-1
@@ -16,4 +16,11 @@ JWT_SECRET_KEY = 'Hj3$kLm8NpQrStUvXwZ1y2C4D6E8G'
|
||||
JWT_ALGORITHM = 'HS256'
|
||||
JWT_EXPIRATION = 2592000
|
||||
|
||||
WEBMAN_LISTEN = 'http://0.0.0.0:9007'
|
||||
WEBMAN_LISTEN = 'http://0.0.0.0:9007'
|
||||
WEBMAN_COUNT = 8
|
||||
|
||||
# 公共服务
|
||||
RPC_DOMAIN = http://219.157.255.213:25015
|
||||
|
||||
# 前端域名
|
||||
WEB_DOMAIN = http://219.157.255.213:8085
|
||||
Generated
-20
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/webman/." isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/webman/./app" isTestSource="false" packagePrefix="app\" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/webman/./app/view/components" isTestSource="false" packagePrefix="app\View\Components\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/monolog/monolog" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/nikic/fast-route" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/psr/log" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/workerman/coroutine" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/workerman/webman-framework" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/webman/vendor/workerman/workerman" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\admin\model\Admin;
|
||||
use app\util\Util;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use support\Request;
|
||||
use app\model\User;
|
||||
use app\admin\model\Role;
|
||||
|
||||
class AdminController
|
||||
{
|
||||
public function list(Request $request,)
|
||||
{
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$admin = Admin::with('roles')->paginate($perPage, ['*'], 'page', $page);
|
||||
return Util::success($admin);
|
||||
}
|
||||
// 获取用户角色列表
|
||||
public function roles(Request $request, $id)
|
||||
{
|
||||
$admin = Admin::with('roles')->findOrFail($id);
|
||||
$allRoles = Role::all();
|
||||
|
||||
$res = [
|
||||
'admin' => $admin,
|
||||
'all_roles' => $allRoles,
|
||||
'assigned_roles' => $admin->roles->pluck('id')->toArray()
|
||||
];
|
||||
return Util::success($res);
|
||||
}
|
||||
|
||||
// 更新用户角色
|
||||
public function updateRoles(Request $request, $id)
|
||||
{
|
||||
// $request->validate([
|
||||
// 'roles' => 'required|array',
|
||||
// 'roles.*' => 'exists:roles,id'
|
||||
// ]);
|
||||
// 验证规则
|
||||
$rules = [
|
||||
'roles' => 'required|array',
|
||||
'roles.*' => 'exists:roles,id'
|
||||
];
|
||||
|
||||
// 自定义错误消息(可选)
|
||||
$messages = [
|
||||
'roles.required' => '角色不能为空',
|
||||
'roles.exists' => '角色id不存在',
|
||||
];
|
||||
|
||||
// 执行验证
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
|
||||
$admin = Admin::findOrFail($id);
|
||||
|
||||
$res = $admin->roles()->sync($request->input('roles'));
|
||||
|
||||
return Util::success($res,'角色更新成功');
|
||||
}
|
||||
|
||||
// 创建管理员
|
||||
public function create(Request $request)
|
||||
{
|
||||
$rules = [
|
||||
'username' => ['required', 'string', 'min:5', 'regex:/^[a-zA-Z0-9\-\_\.]+$/'],
|
||||
'password' => 'required|string|min:6',
|
||||
'nickname' => 'required|string',
|
||||
'email' => 'nullable|email',
|
||||
'status' => 'in:0,1'
|
||||
];
|
||||
|
||||
$messages = [
|
||||
'username.required' => '账号不能为空',
|
||||
'username.min' => '账号长度不能少于5位',
|
||||
'username.regex' => '账号只能包含字母、数字、下划线、连字符和点号',
|
||||
'password.required' => '密码不能为空',
|
||||
'password.min' => '密码长度不能少于6位',
|
||||
'nickname.required' => '姓名不能为空',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'status.in' => '状态值不正确'
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
if ($validator->fails()) {
|
||||
return Util::fail('',$validator->errors()->first());
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
if (Admin::where('username', $request->input('username'))->exists()) {
|
||||
return Util::fail('','账号已存在');
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在
|
||||
if ($request->input('email') && Admin::where('email', $request->input('email'))->exists()) {
|
||||
return Util::fail('','邮箱已存在');
|
||||
}
|
||||
|
||||
$admin = new Admin();
|
||||
$admin->username = $request->input('username');
|
||||
$admin->password = password_hash($request->input('password'), PASSWORD_DEFAULT);
|
||||
$admin->nickname = $request->input('nickname');
|
||||
$admin->email = $request->input('email', null);
|
||||
$admin->status = $request->input('status', 1);
|
||||
$admin->save();
|
||||
|
||||
if ($request->input('roles')) {
|
||||
$res = $admin->roles()->sync($request->input('roles'));
|
||||
}
|
||||
|
||||
return Util::success($admin, '管理员创建成功');
|
||||
}
|
||||
|
||||
// 修改管理员信息
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$admin = Admin::findOrFail($id);
|
||||
|
||||
$rules = [
|
||||
'password' => ['string', 'min:6', 'regex:/^[a-zA-Z0-9\-\_\.]+$/'],
|
||||
'nickname' => 'string',
|
||||
'email' => 'email',
|
||||
'status' => 'in:0,1',
|
||||
'old_password' => 'required_with:password|string',
|
||||
'avatar' => 'string',
|
||||
'mobile' => 'string'
|
||||
];
|
||||
|
||||
$messages = [
|
||||
'password.min' => '密码长度不能少于6位',
|
||||
'password.regex' => '密码只能包含字母、数字、下划线、连字符和点号',
|
||||
'email.email' => '邮箱格式不正确',
|
||||
'status.in' => '状态值不正确',
|
||||
'old_password.required_with' => '请提供旧密码',
|
||||
'old_password.string' => '旧密码格式不正确'
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
if ($validator->fails()) {
|
||||
return Util::fail('',$validator->errors()->first());
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在(排除当前管理员)
|
||||
if ($request->input('email') && Admin::where('email', $request->input('email'))->where('id', '!=', $id)->exists()) {
|
||||
return Util::fail('','邮箱已存在');
|
||||
}
|
||||
|
||||
// 准备要更新的数据
|
||||
$updateData = $request->only(['nickname', 'email', 'status', 'avatar', 'mobile']);
|
||||
|
||||
// 如果修改密码,验证旧密码
|
||||
if ($request->input('password')) {
|
||||
if (!$request->input('old_password')) {
|
||||
return Util::fail('','请提供旧密码');
|
||||
}
|
||||
if (!password_verify($request->input('old_password'), $admin->password)) {
|
||||
return Util::fail('','旧密码不正确');
|
||||
}
|
||||
$updateData['password'] = password_hash($request->input('password'), PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
// 只填充前端传递的字段
|
||||
$admin->fill($updateData);
|
||||
$admin->save();
|
||||
|
||||
return Util::success($admin, '管理员信息更新成功');
|
||||
}
|
||||
|
||||
// 禁用/启用管理员
|
||||
public function toggleStatus(Request $request, $id)
|
||||
{
|
||||
$admin = Admin::findOrFail($id);
|
||||
$admin->status = $admin->status == 1 ? 0 : 1;
|
||||
$admin->save();
|
||||
|
||||
$statusText = $admin->status == 1 ? '启用' : '禁用';
|
||||
return Util::success($admin, "管理员{$statusText}成功");
|
||||
}
|
||||
|
||||
// 重置管理员密码
|
||||
public function resetPassword(Request $request, $id)
|
||||
{
|
||||
$rules = [
|
||||
'new_password' => 'required|string|min:6',
|
||||
// 'confirm_password' => 'required|string|same:new_password'
|
||||
];
|
||||
|
||||
$messages = [
|
||||
'new_password.required' => '新密码不能为空',
|
||||
'new_password.min' => '新密码长度不能少于6位',
|
||||
// 'confirm_password.required' => '确认密码不能为空',
|
||||
// 'confirm_password.same' => '两次输入的密码不一致'
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
if ($validator->fails()) {
|
||||
return Util::fail('',$validator->errors()->first());
|
||||
}
|
||||
|
||||
$admin = Admin::findOrFail($id);
|
||||
$admin->password = password_hash($request->input('new_password'), PASSWORD_DEFAULT);
|
||||
$admin->save();
|
||||
|
||||
return Util::success(null, '密码重置成功');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\admin\model\Admin;
|
||||
use app\admin\model\Menu;
|
||||
use app\util\Util;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
use app\util\JwtUtil;
|
||||
|
||||
class AuthController
|
||||
{
|
||||
/**
|
||||
* 不需要登录的方法
|
||||
*/
|
||||
protected $noNeedLogin = ['login'];
|
||||
public function login(Request $request)
|
||||
{
|
||||
$username = Util::getParam($request, 'username');
|
||||
if (Util::isEmpty($username)) {
|
||||
return Util::fail([], trans('required_not_null'));
|
||||
}
|
||||
$password = Util::getParam($request, 'password');
|
||||
if (Util::isEmpty($password)) {
|
||||
return Util::fail([], trans('required_not_null'));
|
||||
}
|
||||
|
||||
$admin = Admin::where('status', 1)
|
||||
->where('username', $username)
|
||||
->first();
|
||||
if (!$admin) {
|
||||
return Util::fail(['user' => $admin], trans('user_none'));
|
||||
}
|
||||
|
||||
$userPassword = $admin->password;
|
||||
$user = $admin->toArray();
|
||||
|
||||
//加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
//验证密码
|
||||
if (!password_verify($password, $userPassword)) {
|
||||
return Util::fail([], trans('password_error'));
|
||||
}
|
||||
$userId = $user['id']; // 实际从数据库获取
|
||||
|
||||
|
||||
Redis::set('admin_' . $userId, $user);
|
||||
|
||||
//密码验证成功后加密生成 Token
|
||||
$token = JwtUtil::generateToken('admin_'.$userId);
|
||||
$result = $user;
|
||||
unset($result['password']);
|
||||
$result['token'] = $token;
|
||||
|
||||
return Util::success($result, trans('login_success'));
|
||||
}
|
||||
|
||||
public function menus(Request $request)
|
||||
{
|
||||
$user = $request->user;
|
||||
$menus = Menu::with(['child.child' => function($query) {
|
||||
$query->where('status', 1)->orderBy('sort');
|
||||
}])
|
||||
->where('parent_id', 0)
|
||||
->where('status', 1)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->filter(function($menu) use ($user) {
|
||||
if (empty($menu->permission_slug)) {
|
||||
return true;
|
||||
}
|
||||
return $user->hasPermission($menu->permission_slug);
|
||||
});
|
||||
|
||||
return Util::success($menus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\model\Customer;
|
||||
use app\model\User;
|
||||
use app\util\Util;
|
||||
use support\Request;
|
||||
|
||||
class CustomerController
|
||||
{
|
||||
/**
|
||||
* 客户列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$where = [];
|
||||
$user_id = $request->input('user_id');
|
||||
if(empty($user_id) || $user_id == 0){
|
||||
$where[] = ['user_id', '=', $request->input('user_id')];
|
||||
}
|
||||
$user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page);
|
||||
$user = $user->toArray();
|
||||
foreach ($user['data'] as &$item) {
|
||||
unset($item['password']);
|
||||
}
|
||||
return Util::success($user);
|
||||
}
|
||||
|
||||
public function follow(Request $request)
|
||||
{
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$where = [];
|
||||
if($request->input('user_id')){
|
||||
$where[] = ['user_id', '=', $request->input('user_id')];
|
||||
}
|
||||
$user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page);
|
||||
$user = $user->toArray();
|
||||
foreach ($user['data'] as &$item) {
|
||||
unset($item['password']);
|
||||
}
|
||||
return Util::success($user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\admin\model\Permission;
|
||||
use app\admin\model\Role;
|
||||
use app\util\Util;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use support\Request;
|
||||
|
||||
class RoleController
|
||||
{
|
||||
public function all(Request $request,)
|
||||
{
|
||||
$admin = Role::with('permissions')->where([['status',1]])->get();
|
||||
return Util::success($admin);
|
||||
}
|
||||
|
||||
/*
|
||||
* 角色列表
|
||||
*/
|
||||
public function list(Request $request,)
|
||||
{
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$admin = Role::with('permissions')->paginate($perPage, ['*'], 'page', $page);
|
||||
return Util::success($admin);
|
||||
}
|
||||
|
||||
// 获取角色权限列表
|
||||
public function permissions(Request $request, $id)
|
||||
{
|
||||
$role = Role::with('permissions')->findOrFail($id);
|
||||
$allPermissions = Permission::all();
|
||||
|
||||
return json([
|
||||
'code' => 0,
|
||||
'data' => [
|
||||
'role' => $role,
|
||||
'all_permissions' => $allPermissions,
|
||||
'assigned_permissions' => $role->permissions->pluck('id')->toArray()
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
// 更新角色权限
|
||||
public function updatePermissions(Request $request, $id)
|
||||
{
|
||||
// 验证规则
|
||||
$rules = [
|
||||
'permissions' => 'required|array',
|
||||
'permissions.*' => 'exists:permissions,id'
|
||||
];
|
||||
|
||||
// 自定义错误消息(可选)
|
||||
$messages = [
|
||||
'permissions.required' => '角色不能为空',
|
||||
'permissions.exists' => '角色id不存在',
|
||||
];
|
||||
|
||||
// 执行验证
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
|
||||
$role = Role::with('permissions')->findOrFail($id);
|
||||
$role->permissions()->sync($request->input('permissions'));
|
||||
|
||||
return Util::success($role,'角色更新成功');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\model\User;
|
||||
use app\util\Util;
|
||||
use support\Request;
|
||||
|
||||
class UserController
|
||||
{
|
||||
|
||||
public function list(Request $request,)
|
||||
{
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$user = User::paginate($perPage, ['*'], 'page', $page);
|
||||
$user = $user->toArray();
|
||||
foreach ($user['data'] as &$item) {
|
||||
unset($item['password']);
|
||||
}
|
||||
return Util::success($user);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\controller;
|
||||
|
||||
use app\admin\model\Menu;
|
||||
use support\Request;
|
||||
|
||||
class menus
|
||||
{
|
||||
public function menus(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
$menus = Menu::with('children')
|
||||
->where('parent_id', 0)
|
||||
->where('status', 1)
|
||||
->orderBy('sort')
|
||||
->get()
|
||||
->filter(function($menu) use ($user) {
|
||||
if (empty($menu->permission_slug)) {
|
||||
return true;
|
||||
}
|
||||
return $user->hasPermission($menu->permission_slug);
|
||||
});
|
||||
|
||||
return json($menus);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
namespace app\admin\middleware;
|
||||
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
|
||||
class AuthMiddleware implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler): Response
|
||||
{
|
||||
try {
|
||||
$token = $this->getTokenFromRequest($request);
|
||||
|
||||
if (!$token) {
|
||||
return $this->unauthorized('缺少访问令牌');
|
||||
}
|
||||
|
||||
if (!$user = auth('api')->setToken($token)->user()) {
|
||||
return $this->unauthorized('用户不存在');
|
||||
}
|
||||
|
||||
// 将用户信息存入请求
|
||||
$request->user = $user;
|
||||
|
||||
} catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
|
||||
return $this->unauthorized('令牌已过期');
|
||||
} catch (JWTException $e) {
|
||||
return $this->unauthorized('令牌无效');
|
||||
}
|
||||
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
private function getTokenFromRequest(Request $request)
|
||||
{
|
||||
$header = $request->header('Authorization', '');
|
||||
if (preg_match('/Bearer\s+(\S+)/', $header, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
return $request->input('token');
|
||||
}
|
||||
|
||||
private function unauthorized($msg)
|
||||
{
|
||||
return json(['code' => 401, 'msg' => $msg]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\middleware;
|
||||
|
||||
use app\util\Util;
|
||||
use ReflectionClass;
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
|
||||
class PermissionCheck implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler): Response
|
||||
{
|
||||
$user = $request->user;
|
||||
// $route = $request->route;
|
||||
$route = $request->path();
|
||||
|
||||
// 通过反射获取控制器哪些方法不需要登录
|
||||
$controller = new ReflectionClass($request->controller);
|
||||
$noNeedLogin = $controller->getDefaultProperties()['noNeedLogin'] ?? [];
|
||||
|
||||
$isLogin = !in_array($request->action, $noNeedLogin);
|
||||
|
||||
$permission = substr($route,7);
|
||||
|
||||
$is_auth = str_starts_with($permission, 'auth');
|
||||
$permissions = $user?$user->permissions():true;
|
||||
if($isLogin && $permission && (empty($permissions) && !$is_auth) && !$user->isPermission($permission)){
|
||||
return Util::fail('','无权访问该资源',401);
|
||||
}
|
||||
// // 检查角色
|
||||
// $requiredRoles = $request->route->param('roles', []);
|
||||
// if (!empty($requiredRoles) && !$user->hasAnyRole($requiredRoles)) {
|
||||
// return $this->forbidden('需要特定角色才能访问');
|
||||
// }
|
||||
//
|
||||
// // 检查权限
|
||||
// $requiredPermission = $route->param('permission');
|
||||
// if ($requiredPermission && !$user->hasPermission($requiredPermission)) {
|
||||
// return $this->forbidden('无权访问该资源');
|
||||
// }
|
||||
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
private function forbidden($msg)
|
||||
{
|
||||
return json(['code' => 403, 'msg' => $msg]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use support\Model;
|
||||
class Admin extends Model
|
||||
{
|
||||
protected $table = 'admins';
|
||||
protected $hidden = ['password'];
|
||||
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(Role::class, 'admin_roles', 'user_id', 'role_id');
|
||||
}
|
||||
|
||||
public function hasRole($role)
|
||||
{
|
||||
return $this->roles()->where('name', $role)->exists();
|
||||
}
|
||||
|
||||
public function getJWTIdentifier()
|
||||
{
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
public function getJWTCustomClaims()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function hasAnyRole($roles)
|
||||
{
|
||||
return $this->roles()->whereIn('name', (array)$roles)->exists();
|
||||
}
|
||||
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
return $this->permissions()->contains('slug', $permission);
|
||||
}
|
||||
public function isPermission($permission)
|
||||
{
|
||||
$permissions = $this->permissions();
|
||||
return in_array($permission, array_column($permissions->toArray(), 'slug'));
|
||||
}
|
||||
public function permissions()
|
||||
{
|
||||
return $this->roles()
|
||||
->with('permissions')
|
||||
->get()
|
||||
->pluck('permissions')
|
||||
->flatten()
|
||||
->unique('id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Menu extends Model
|
||||
{
|
||||
protected $table = 'menus';
|
||||
|
||||
public function child()
|
||||
{
|
||||
return $this->hasMany(Menu::class, 'parent_id')->orderBy('sort');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Permission extends Model
|
||||
{
|
||||
protected $table = 'permissions';
|
||||
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(Role::class, 'role_permissions', 'permission_id', 'role_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\admin\model;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Role extends Model
|
||||
{
|
||||
protected $table = 'roles';
|
||||
|
||||
public function users()
|
||||
{
|
||||
return $this->belongsToMany(Admin::class, 'user_roles', 'role_id', 'user_id');
|
||||
}
|
||||
|
||||
public function permissions()
|
||||
{
|
||||
return $this->belongsToMany(Permission::class, 'role_permissions', 'role_id', 'permission_id');
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,11 @@ namespace app\controller;
|
||||
|
||||
use app\model\Area;
|
||||
use app\model\Country;
|
||||
use app\util\HttpClient;
|
||||
use app\util\RedisHelper;
|
||||
use app\util\Util;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
class AreaController
|
||||
@@ -41,10 +45,26 @@ class AreaController
|
||||
|
||||
public function getCountry (Request $request)
|
||||
{
|
||||
$level = Util::getParam($request,'level')?:1;
|
||||
$list = RedisHelper::get("rpc_country");
|
||||
$list = null;
|
||||
// if(!$list){
|
||||
// $res = HttpClient::get(config('const.rpc_domain') . '/country/all');
|
||||
// if ($res['code'] != 200 && $res['data']['code'] != 0){
|
||||
// Log::info('register_rpc',$res);
|
||||
// return Util::fail($res, trans('register_fail'));
|
||||
// }
|
||||
// $list = $res['data']['data']['data'];
|
||||
// RedisHelper::set("rpc_country", $list, 600);
|
||||
// }
|
||||
|
||||
$list = Country::get()->toArray();
|
||||
$language = 'en_addr';
|
||||
if($request->user['language'] == 'zh_CN'){
|
||||
$language = 'cn_addr';
|
||||
}
|
||||
|
||||
foreach ($list as &$row) {
|
||||
$row['name'] = $row['cn_addr'];
|
||||
$row['name'] = $row[$language];
|
||||
}
|
||||
return Util::success($list);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,17 @@ class CarTypeController
|
||||
public function getAll(Request $request)
|
||||
{
|
||||
$list = CarType::getAll();
|
||||
|
||||
if($request->user['language'] != 'zh_CN'){
|
||||
foreach ($list as &$value) {
|
||||
$value['name'] = $value['name_en'];
|
||||
}
|
||||
}elseif ($request->user['language'] == 'ru'){
|
||||
foreach ($list as &$value) {
|
||||
$value['name'] = $value['name_ru'];
|
||||
}
|
||||
}
|
||||
|
||||
return Util::success($list);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ namespace app\controller;
|
||||
|
||||
use app\model\Channel;
|
||||
use app\model\Customer;
|
||||
use app\model\CustomerHis;
|
||||
use app\model\Follow;
|
||||
use app\model\User;
|
||||
use app\service\UserService;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Log;
|
||||
@@ -12,6 +15,13 @@ use support\Request;
|
||||
|
||||
class CustomerController
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 不需要登录的方法
|
||||
*/
|
||||
protected $noNeedLogin = ['collect'];
|
||||
|
||||
/**
|
||||
* 客户分级
|
||||
* @param Request $request
|
||||
@@ -20,7 +30,13 @@ class CustomerController
|
||||
public function getGrade(Request $request)
|
||||
{
|
||||
$grade = [];
|
||||
foreach (Constants::GRADE as $key => $value) {
|
||||
$gradeConstants = Constants::GRADE_EN;
|
||||
if($request->user['language'] == 'zh_CN'){
|
||||
$gradeConstants = Constants::GRADE;
|
||||
}elseif ($request->user['language'] == 'ru'){
|
||||
$gradeConstants = Constants::GRADE_RU;
|
||||
}
|
||||
foreach ($gradeConstants as $key => $value) {
|
||||
$grade[] = [
|
||||
'id' => $key,
|
||||
'name' => $value,
|
||||
@@ -37,7 +53,13 @@ class CustomerController
|
||||
public function getMagnitude(Request $request)
|
||||
{
|
||||
$grade = [];
|
||||
foreach (Constants::MAGNITUDE as $key => $value) {
|
||||
$magnitudeConstants = Constants::MAGNITUDE_EN;
|
||||
if($request->user['language'] == 'zh_CN'){
|
||||
$magnitudeConstants = Constants::MAGNITUDE;
|
||||
}elseif ($request->user['language'] == 'ru'){
|
||||
$magnitudeConstants = Constants::MAGNITUDE_RU;
|
||||
}
|
||||
foreach ($magnitudeConstants as $key => $value) {
|
||||
$grade[] = [
|
||||
'id' => $key,
|
||||
'name' => $value,
|
||||
@@ -54,10 +76,56 @@ class CustomerController
|
||||
public function getChannel(Request $request)
|
||||
{
|
||||
$list = Channel::getAll();
|
||||
|
||||
if($request->user['language'] != 'zh_CN'){
|
||||
foreach ($list as &$value) {
|
||||
$value['name'] = $value['name_en'];
|
||||
}
|
||||
}elseif ($request->user['language'] == 'ru'){
|
||||
foreach ($list as &$value) {
|
||||
$value['name'] = $value['name_ru'];
|
||||
}
|
||||
}
|
||||
|
||||
return Util::success($list);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 待跟进客户列表
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function waitFollow(Request $request)
|
||||
{
|
||||
$userId = $request->user['id'];
|
||||
$filter = Util::getParam($request, 'filter');
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$where = [
|
||||
['user_id', '=', $userId],
|
||||
['follow_next', '<>', 0],
|
||||
];
|
||||
|
||||
if($filter == 0){
|
||||
$where[] = ['follow_next', '<=', time() + 3600 * 24];
|
||||
}elseif($filter == 1){
|
||||
$where[] = ['follow_next', '<=', time() + 3600 * 24*3];
|
||||
}elseif($filter == 2){
|
||||
$where[] = ['follow_next', '<=', time() + 3600 * 24*7];
|
||||
}
|
||||
$customer = Customer::where($where)
|
||||
->whereNotNull('follow_next')
|
||||
->orderBy('follow_next')
|
||||
->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
foreach ($customer as &$item) {
|
||||
$item['follow_remaining'] = $item->follow_next-time();
|
||||
$item['follow_next'] = date('Y-m-d H:i:s',$item->follow_next);
|
||||
}
|
||||
return Util::page($customer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户列表
|
||||
* @param Request $request
|
||||
@@ -68,9 +136,11 @@ class CustomerController
|
||||
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
$follow = $request->input('follow',''); //跟进状态
|
||||
$keyword = $request->input('keyword',''); //follow_last
|
||||
$follow_last = $request->input('follow_last',''); //最后跟进:1:当天跟进客户,2:近三天跟进客户,3:近七天跟进客户
|
||||
$follow = $request->input('follow', ''); //跟进状态
|
||||
$keyword = $request->input('keyword', ''); //follow_last
|
||||
$follow_last = $request->input('follow_last', ''); //最后跟进:1:当天跟进客户,2:近三天跟进客户,3:近七天跟进客户
|
||||
$tagId = $request->input('tag_id', ''); //打有某个标签的客户
|
||||
$seas = $request->input('seas', ''); //公海客户
|
||||
|
||||
$where = [];
|
||||
|
||||
@@ -78,54 +148,97 @@ class CustomerController
|
||||
if (Util::isEmpty($userId)) {
|
||||
return Util::fail(['user_id' => $userId], trans('user_none'));
|
||||
}
|
||||
$where[] =['user_id',$userId] ;
|
||||
// $where[] = ['type', 0];
|
||||
if($seas == 'seas'){
|
||||
$where[] = ['user_id', 0];
|
||||
}else{
|
||||
$where[] = ['user_id', $userId];
|
||||
}
|
||||
//验证权限
|
||||
// if ($request->user['role'] != 1) {
|
||||
// $where[] =['user_id',$userId] ;
|
||||
// }
|
||||
$grade = [];
|
||||
if (!Util::isEmpty($follow) && $follow == 0) {
|
||||
$where[] = ['grade','<=', 2];
|
||||
$where[] = ['grade', '<=', 2];
|
||||
} elseif (!Util::isEmpty($follow) && $follow == 1) {
|
||||
$grade = [3, 4];
|
||||
$grade = [3, 4];
|
||||
} elseif (!Util::isEmpty($follow) && $follow == 2) {
|
||||
$where[] = ['grade','=', 5];
|
||||
$where[] = ['grade', '=', 5];
|
||||
}
|
||||
|
||||
if (!Util::isEmpty($follow_last) && $follow_last == 0) {
|
||||
$where[] = ['follow_last','>', strtotime('-1 day')];
|
||||
}elseif (!Util::isEmpty($follow_last) && $follow_last == 1) {
|
||||
$where[] = ['follow_last','>', strtotime('-3 day')];
|
||||
}elseif (!Util::isEmpty($follow_last) && $follow_last == 2) {
|
||||
$where[] = ['follow_last','>', strtotime('-7 day')];
|
||||
$where[] = ['follow_last', '>', strtotime('-1 day')];
|
||||
} elseif (!Util::isEmpty($follow_last) && $follow_last == 1) {
|
||||
$where[] = ['follow_last', '>', strtotime('-3 day')];
|
||||
} elseif (!Util::isEmpty($follow_last) && $follow_last == 2) {
|
||||
$where[] = ['follow_last', '>', strtotime('-7 day')];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 执行分页查询
|
||||
$query = Customer::where($where)
|
||||
->orderBy('id', 'desc');
|
||||
// 执行分页查询 //关联标签tags //关联标签及分组tags.group
|
||||
$query = Customer::with('tags')->where($where)
|
||||
->orderBy('customer.id', 'desc');
|
||||
if(!empty($tagId)){
|
||||
// $query->with(['tags' => function($query) use ($tagId){
|
||||
// $query->where('tag.id', $tagId);
|
||||
// }]);
|
||||
$query->whereHas('tags', function($query) use ($tagId){
|
||||
$query->where('tag.id', $tagId);
|
||||
});
|
||||
}
|
||||
if (!Util::isEmpty($keyword)) {
|
||||
$query->where(function ($query) use ($keyword) {
|
||||
$query->where('contacts', 'like', "%{$keyword}%")
|
||||
->orWhere('phone', 'like', "%{$keyword}%");
|
||||
});
|
||||
|
||||
}
|
||||
if (!Util::isEmpty($grade)) {
|
||||
$query->whereIn('grade', $grade);
|
||||
|
||||
}
|
||||
// return Util::success($query->toSql().serialize($where),$follow);
|
||||
|
||||
$recycle = Util::getParam($request,'recycle', '');
|
||||
if ($recycle == 'recycle' || $seas == 'seas') {
|
||||
$query->onlyTrashed();
|
||||
}
|
||||
|
||||
$data = $query->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
foreach ($data->items() as &$value) {
|
||||
$value = Customer::getCustomer($value);
|
||||
$value = Customer::getCustomer($value, $request);
|
||||
if($seas == 'seas'){
|
||||
$value['seas_time'] = time()-strtotime($value['deleted_at']);
|
||||
}
|
||||
}
|
||||
|
||||
return Util::page($data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 客户恢复
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function restore(Request $request)
|
||||
{
|
||||
$id = Util::getParam($request,'id', '');
|
||||
if (Util::isEmpty($id)) {
|
||||
return Util::fail([], trans('id_empty'));
|
||||
}
|
||||
$userId = $request->user['id'];
|
||||
$where = [
|
||||
'id' => $id,
|
||||
'user_id' => $userId,
|
||||
];
|
||||
$res = Customer::where($where)->restore();
|
||||
if($res){
|
||||
return Util::success($res, trans('success'));
|
||||
}else{
|
||||
return Util::fail([], trans('fail'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户详情
|
||||
* @param Request $request
|
||||
@@ -138,7 +251,7 @@ class CustomerController
|
||||
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', 'address', 'lat', 'lng', 'follow_next', 'follow_remark', 'sex')
|
||||
$res = Customer::with('tags')->select('id', 'user_id', 'grade', 'channel_id', 'car_type_id', 'country_id', 'magnitude', 'email', 'phone', 'WhatsApp', 'contacts', 'describe', 'address', 'lat', 'lng', 'follow_next', 'follow_remark', 'sex')
|
||||
->where('id', $id)
|
||||
->first();
|
||||
if ($res) {
|
||||
@@ -147,7 +260,7 @@ class CustomerController
|
||||
return Util::fail([], '记录不存在');
|
||||
}
|
||||
|
||||
$res = Customer::getCustomer($res);
|
||||
$res = Customer::getCustomer($res, $request, true);
|
||||
|
||||
return Util::success($res);
|
||||
}
|
||||
@@ -176,7 +289,7 @@ class CustomerController
|
||||
$email = Util::getParam($request, 'email');
|
||||
$phone = Util::getParam($request, 'phone');
|
||||
if (Util::isEmpty($contacts) && Util::isEmpty($email) && Util::isEmpty($phone)) {
|
||||
return Util::fail([], trans('contacts_not_null'));
|
||||
return Util::fail([], trans('contacts_not_null'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
@@ -214,6 +327,92 @@ class CustomerController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取公海客户
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function claim(Request $request)
|
||||
{
|
||||
$customerId = Util::getParam($request, 'customer_id');
|
||||
$userId = $request->user['id'];
|
||||
if (Util::isEmpty($customerId)) {
|
||||
return Util::fail([], trans('customer_id').trans('not_null'));
|
||||
}
|
||||
$data = [
|
||||
'user_id' => $request->user['id']
|
||||
];
|
||||
$customer= Customer::withTrashed()->find($customerId);
|
||||
|
||||
if(empty($customer) || $customer->user_id != 0){
|
||||
return Util::fail('', trans('claim_fail'));
|
||||
}
|
||||
|
||||
$customer->restore();
|
||||
$res = $customer->update($data);
|
||||
|
||||
//记录客户关系变化
|
||||
$his = CustomerHis::create([
|
||||
'customer_id' => $customerId,
|
||||
'user_his' => 0,
|
||||
'user_id' => $userId,
|
||||
]);
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res, trans('success'));
|
||||
} else {
|
||||
return Util::fail($res, trans('fail'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量转让
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function cede(Request $request)
|
||||
{
|
||||
$customerId = Util::getParam($request, 'customer_id');
|
||||
$user_sn = Util::getParam($request, 'user_sn');
|
||||
$userId = $request->user['id'];
|
||||
if (Util::isEmpty($user_sn)) {
|
||||
return Util::fail([], 'ID'.trans('not_null'));
|
||||
}
|
||||
|
||||
$user = User::where(['sn' => $user_sn])->first();
|
||||
if (Util::isEmpty($user)) {
|
||||
return Util::fail(null, trans('user_none'));
|
||||
}
|
||||
|
||||
if(Util::isEmpty($customerId)){
|
||||
$data = [
|
||||
'user_id' => $userId
|
||||
];
|
||||
$query= Customer::where($data);
|
||||
}else{
|
||||
$query= Customer::whereIn('id',explode(',',$customerId));
|
||||
}
|
||||
$customer = $query->get();
|
||||
|
||||
foreach ($customer as $item) {
|
||||
//记录客户关系变化
|
||||
$his = CustomerHis::create([
|
||||
'customer_id' => $item->id,
|
||||
'user_his' => $item->user_id,
|
||||
'user_id' => $user['id'],
|
||||
]);
|
||||
}
|
||||
$res = $query->update(['user_id' => $user->id]);
|
||||
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res, trans('success'));
|
||||
} else {
|
||||
return Util::fail($res, trans('fail'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跟进状态
|
||||
* @param Request $request
|
||||
@@ -256,10 +455,11 @@ class CustomerController
|
||||
$data = [
|
||||
'follow_next' => Util::getParam($request, 'follow_next', 0),
|
||||
'follow_remark' => Util::getParam($request, 'follow_remark', 0),
|
||||
'warn' => 0,
|
||||
];
|
||||
|
||||
$res = Customer::where('id', $id)
|
||||
->update($data);
|
||||
->update($data);
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res, trans('save_success'));
|
||||
@@ -276,8 +476,22 @@ class CustomerController
|
||||
public function delete(Request $request)
|
||||
{
|
||||
$id = Util::getParam($request, 'id');
|
||||
$customer = Customer::where('id', $id)->first();
|
||||
$res = $customer->delete();
|
||||
$force = Util::getParam($request, 'force','');
|
||||
|
||||
$userId = $request->user['id'];
|
||||
$where = [
|
||||
'id' => $id,
|
||||
'user_id' => $userId,
|
||||
];
|
||||
$customer = Customer::where($where)->withTrashed()->first();
|
||||
if(empty($customer)){
|
||||
return Util::fail('', trans('fail'));
|
||||
}
|
||||
if($force == 'force'){
|
||||
$res = $customer->forceDelete();
|
||||
}else{
|
||||
$res = $customer->delete();
|
||||
}
|
||||
if ($res) {
|
||||
return Util::success($res, trans('success'));
|
||||
} else {
|
||||
@@ -298,19 +512,19 @@ class CustomerController
|
||||
}
|
||||
$userId = $request->user['id'];
|
||||
$created_at = $request->user['created_at'];
|
||||
$day = ceil((time()-$created_at+1)/60/60/24);
|
||||
$day = ceil((time() - $created_at + 1) / 60 / 60 / 24);
|
||||
$where[] = ['user_id', '=', $userId];
|
||||
$start = strtotime($created.'-01');
|
||||
$start = strtotime($created . '-01');
|
||||
$year = date('Y', $start);
|
||||
$month = date('n',$start); //获取月份
|
||||
$end = mktime(00, 00, 00, $month+1, 1, $year);
|
||||
$month = date('n', $start); //获取月份
|
||||
$end = mktime(00, 00, 00, $month + 1, 1, $year);
|
||||
$where[] = ['created_at', '>=', $start];
|
||||
$where[] = ['created_at', '<', $end];
|
||||
$customer = Customer::where($where)->count();
|
||||
|
||||
//初步接触
|
||||
$whereGrade = $where;
|
||||
$whereGrade[] = ['grade','<=', 2];
|
||||
$whereGrade[] = ['grade', '<=', 2];
|
||||
$customerInit = Customer::where($whereGrade)->count();
|
||||
|
||||
//跟进中
|
||||
@@ -318,7 +532,7 @@ class CustomerController
|
||||
|
||||
//已成交
|
||||
$whereGrade = $where;
|
||||
$whereGrade[] = ['grade','=', 5];
|
||||
$whereGrade[] = ['grade', '=', 5];
|
||||
$customerDeal = Customer::where($whereGrade)->count();
|
||||
|
||||
//拜访数
|
||||
@@ -332,13 +546,13 @@ class CustomerController
|
||||
$follow = Follow::where($whereVisit)->distinct('customer_id')->count();
|
||||
|
||||
$res = [
|
||||
'customer'=>$customer, //客户数
|
||||
'visit'=>$visit, //拜访
|
||||
'follow'=>$follow, //跟进
|
||||
'day'=>$day, //注册天数
|
||||
'customer_init'=>$customerInit, //初步接触
|
||||
'customero_fllow'=>$customeroFllow, //跟进中
|
||||
'customer_deal'=>$customerDeal, //已成交
|
||||
'customer' => $customer, //客户数
|
||||
'visit' => $visit, //拜访
|
||||
'follow' => $follow, //跟进
|
||||
'day' => $day, //注册天数
|
||||
'customer_init' => $customerInit, //初步接触
|
||||
'customero_fllow' => $customeroFllow, //跟进中
|
||||
'customer_deal' => $customerDeal, //已成交
|
||||
];
|
||||
if ($res) {
|
||||
return Util::success($res, trans('success'));
|
||||
@@ -347,4 +561,63 @@ class CustomerController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 线索分配
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function collect(Request $request)
|
||||
{
|
||||
Log::info('receive collect start',$request->all());
|
||||
$user_sn = Util::getParam($request, 'user_sn'); //用户sn
|
||||
// $user_email = Util::getParam($request, 'user_email'); //邮箱
|
||||
$user_id = Util::getParam($request, 'user_id'); //邮箱
|
||||
$sn = Util::getParam($request, 'order_no'); //客户sn验证客户唯一性
|
||||
$channel_id = Util::getParam($request, 'channel_id'); //渠道
|
||||
$country_id = Util::getParam($request, 'country_id'); //国家
|
||||
$magnitude = Util::getParam($request, 'magnitude'); //商机
|
||||
$describe = Util::getParam($request, 'describe'); //客户详情
|
||||
$phone = Util::getParam($request, 'phone'); //用户详情
|
||||
$email = Util::getParam($request, 'email'); //用户详情
|
||||
$WhatsApp = Util::getParam($request, 'WhatsApp');
|
||||
$contacts = Util::getParam($request, 'contacts'); //联系人
|
||||
|
||||
|
||||
if (Util::isEmpty($user_sn)) {
|
||||
return Util::fail([], '用户sn不能为空');
|
||||
}
|
||||
if (Util::isEmpty($sn)) {
|
||||
return Util::fail([], '客户sn不能为空');
|
||||
}
|
||||
|
||||
// $user = UserService::updateSn($user_sn, $user_email);
|
||||
|
||||
// if(!$user){
|
||||
// return Util::fail($user, $user_email.'用户不存在');
|
||||
// }
|
||||
|
||||
$res = Customer::firstOrCreate(
|
||||
['sn' => $sn],
|
||||
[
|
||||
'user_sn' => $user_sn,
|
||||
'user_id' => $user_id,
|
||||
'type' => 0,
|
||||
'channel_id' => $channel_id,
|
||||
'country_id' => $country_id,
|
||||
'magnitude' => $magnitude,
|
||||
'desc_collect' => $describe,
|
||||
'phone' => $phone,
|
||||
'email' => $email,
|
||||
'WhatsApp' => $WhatsApp,
|
||||
'contacts' => $contacts,
|
||||
]
|
||||
);
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res, trans('success'));
|
||||
} else {
|
||||
return Util::fail($res, trans('fail'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\middleware\DataTracker;
|
||||
use app\model\Daily;
|
||||
use app\model\FeishuUser;
|
||||
use app\model\User;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class DailyController
|
||||
{
|
||||
|
||||
/**
|
||||
* 日报列表
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function list(Request $request)
|
||||
{
|
||||
|
||||
$page = $request->input('page', 1);
|
||||
$perPage = $request->input('per_page', 10);
|
||||
|
||||
//id
|
||||
$userId = $request->user['id'];
|
||||
if(Util::isEmpty($userId)){
|
||||
return Util::fail([],'user_id'.trans('not_null'));
|
||||
}
|
||||
|
||||
$where = [];
|
||||
|
||||
//判断领导
|
||||
$mast = config('const.daily_group_2');
|
||||
if ($userId == $mast['master']) {
|
||||
$where['leader_id'] = $mast['master'];
|
||||
}else{
|
||||
$where['user_id'] = $userId;
|
||||
}
|
||||
|
||||
// 执行分页查询
|
||||
$data = Daily::with('user')->where($where)
|
||||
->orderBy('id', 'desc')
|
||||
->paginate($perPage, ['*'], 'page', $page);
|
||||
|
||||
return Util::success($data,trans('success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日报列表
|
||||
* @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'));
|
||||
}
|
||||
|
||||
$where = [];
|
||||
$where['id'] = $id;
|
||||
|
||||
// 执行分页查询
|
||||
$data = Daily::with('user')->where($where)
|
||||
->first();
|
||||
|
||||
$data['self'] = 0;
|
||||
|
||||
return Util::success($data,trans('success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 日报编辑
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$id = Util::getParam($request, 'id');
|
||||
$text = Util::getParam($request, 'text');
|
||||
|
||||
if (empty($id)) {
|
||||
return Util::fail([], '日报id' . trans('not_null'));
|
||||
}
|
||||
if (Util::isEmpty($text)) {
|
||||
return Util::fail([], 'text' . trans('not_null'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'text' => $text,
|
||||
'remark' => Util::getParam($request, 'remark', '')
|
||||
];
|
||||
|
||||
$res = Daily::where(['id' => $id])->update($data);
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res,trans('save_success'));
|
||||
} else {
|
||||
return Util::fail($res,trans('save_fail'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace app\controller;
|
||||
use app\model\FeishuUser;
|
||||
use app\model\User;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Log;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
@@ -25,13 +26,18 @@ class FeishuController
|
||||
*/
|
||||
public function getinfo(Request $request)
|
||||
{
|
||||
$config = Util::getParam($request, 'config');
|
||||
if (Util::isEmpty($config)) {
|
||||
$config = $this->config;
|
||||
// $config = Util::getParam($request, 'config');
|
||||
// if (Util::isEmpty($config)) {
|
||||
// $config = $this->config;
|
||||
// }
|
||||
$userId = $request->user['id'];
|
||||
$config = User::where('id',$userId)->value('sign');
|
||||
if(Util::isEmpty($config)){
|
||||
return Util::fail(null,trans('sign_not_null'));
|
||||
}
|
||||
|
||||
|
||||
// 获取凭证
|
||||
$certificate = config($config);
|
||||
$certificate = config('feishu.'.$config);
|
||||
$arr = [
|
||||
'app_id' => $certificate['appId'],
|
||||
'redirect_uri' => $certificate['rUrl'],
|
||||
@@ -48,13 +54,10 @@ class FeishuController
|
||||
public function getSign(Request $request)
|
||||
{
|
||||
|
||||
// 获取凭证
|
||||
$certificate = config('feishu');
|
||||
|
||||
$res = [];
|
||||
foreach ($certificate as $k => $v) {
|
||||
$res []=$k;
|
||||
}
|
||||
$res = Constants::SIGN;
|
||||
// foreach ($certificate as $k => $v) {
|
||||
// $res []=['id'=>$k,'name'=>$k];
|
||||
// }
|
||||
return Util::success($res,trans('success'));
|
||||
}
|
||||
|
||||
@@ -70,8 +73,14 @@ class FeishuController
|
||||
public function auth(Request $request)
|
||||
{
|
||||
$param = $request->all();
|
||||
$userId = $request->user['id'];
|
||||
$config = User::where('id',$userId)->value('sign');
|
||||
if(Util::isEmpty($config)){
|
||||
return Util::fail(null,trans('sign_not_null'));
|
||||
}
|
||||
|
||||
// 获取凭证
|
||||
$certificate = config($this->config);
|
||||
$certificate = config('feishu.'.$config);
|
||||
|
||||
// 飞书服务
|
||||
$class = new \app\service\FeishuService($certificate['appId'], $certificate['appSecret'], $certificate['state']);
|
||||
@@ -89,54 +98,33 @@ class FeishuController
|
||||
}
|
||||
|
||||
Log::info('feishu user_info', ['res' => $rst]);
|
||||
$state = explode(",", $param['state']);
|
||||
$state = explode("_", $param['state']);
|
||||
//$userId = $request->user['id'];
|
||||
$userId = $state[2];
|
||||
$user = FeishuUser::where('id', $userId)->first();
|
||||
$userId = $state[1];
|
||||
// $user = FeishuUser::where('id', $userId)->first();
|
||||
// $user = FeishuUser::create();
|
||||
|
||||
//保存用户open_id
|
||||
$user->user_id = $userId;
|
||||
$user->sign = $state[0];
|
||||
$user->tenant_key = $rst['data']['tenant_key'];
|
||||
$user->open_id = $rst['data']['open_id'];
|
||||
$user->feishu_user_id = $rst['data']['user_id'];
|
||||
$user->union_id = $rst['data']['union_id'];
|
||||
$user->save();
|
||||
// //保存用户open_id
|
||||
// $user->user_id = $userId;
|
||||
// $user->sign = $state[0];
|
||||
// $user->tenant_key = $rst['data']['tenant_key'];
|
||||
// $user->open_id = $rst['data']['open_id'];
|
||||
// $user->feishu_user_id = $rst['data']['user_id'];
|
||||
// $user->union_id = $rst['data']['union_id'];
|
||||
// $user->save();
|
||||
|
||||
// var_dump($rst);
|
||||
// array(3) {
|
||||
// ["code"]=>
|
||||
// int(0)
|
||||
// ["data"]=>
|
||||
// array(11) {
|
||||
// ["avatar_big"]=>
|
||||
// string(168) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=640x640&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||
// ["avatar_middle"]=>
|
||||
// string(168) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=240x240&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||
// ["avatar_thumb"]=>
|
||||
// string(166) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=72x72&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||
// ["avatar_url"]=>
|
||||
// string(166) "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00ie_7cc82f38-0a89-43d4-8b2c-d90fc9d9176g~?image_size=72x72&cut_type=&quality=&format=image&sticker_format=.webp"
|
||||
// ["en_name"]=>
|
||||
// string(9) "李佳博"
|
||||
// ["mobile"]=>
|
||||
// string(14) "+8615738985690"
|
||||
// ["name"]=>
|
||||
// string(9) "李佳博"
|
||||
// ["open_id"]=>
|
||||
// string(35) "ou_37bb7cfc4311c858ea32461700fa1a43"
|
||||
// ["tenant_key"]=>
|
||||
// string(16) "14e7bc0fe5985740"
|
||||
// ["union_id"]=>
|
||||
// string(35) "on_a3fdbca48cd9477a140c7f2167a63691"
|
||||
// ["user_id"]=>
|
||||
// string(8) "481g947d"
|
||||
// }
|
||||
// ["msg"]=>
|
||||
// string(7) "success"
|
||||
// }
|
||||
$user = new FeishuUser();
|
||||
$user->firstOrCreate([
|
||||
'user_id' => $userId,
|
||||
'sign' => $state[0],
|
||||
'tenant_key' => $rst['data']['tenant_key'],
|
||||
'open_id' => $rst['data']['open_id'],
|
||||
'feishu_user_id' => $rst['data']['user_id'],
|
||||
'union_id' => $rst['data']['union_id']
|
||||
]);
|
||||
|
||||
return json($rst);
|
||||
// return json($rst);
|
||||
return Util::success($rst['data'], trans('success'));
|
||||
} else {
|
||||
//需要登录并且未提供token
|
||||
if (!Util::isEmpty($request->user['id'])) {
|
||||
@@ -153,17 +141,18 @@ class FeishuController
|
||||
|
||||
|
||||
/**
|
||||
* @param $receiveId openid
|
||||
* @param $title 推送标题
|
||||
* @param $content 推送内容
|
||||
* @param $href 详情链接
|
||||
* @param $receiveId //openid
|
||||
* @param $title //推送标题
|
||||
* @param $content //推送内容
|
||||
* @param $href //详情链接
|
||||
* @param $msgType = 'post'; //卡片消息:interactive,富文本消息:post
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function send($receiveId,$title,$content,$href)
|
||||
public static function send($config='xinyouhe',$receiveId='ou_e33bb3017ada6c4781398a68e55a4696',$content = '' , $msgType = 'post')
|
||||
{
|
||||
Log::info('feishu send', ['receiveId' => $receiveId, 'title' => $title, 'content' => $content, 'href' => $href]);
|
||||
// 获取凭证
|
||||
$certificate = config($this->config);
|
||||
$certificate = config('feishu.'.$config);
|
||||
Log::info('feishu send', [$certificate,'config'=>$config,'receiveId' => $receiveId, 'content' => $content]);
|
||||
|
||||
// 飞书服务
|
||||
$class = new \app\service\FeishuService($certificate['appId'], $certificate['appSecret'], $certificate['state']);
|
||||
@@ -172,7 +161,7 @@ class FeishuController
|
||||
// $receiveId = 'ou_a3b97543acbf1b28d978356bb08f85dd';
|
||||
|
||||
// 富文本 类型
|
||||
$content = "{
|
||||
/*$content = "{
|
||||
\"zh_cn\":{
|
||||
\"title\":\"$title\",
|
||||
\"content\":[
|
||||
@@ -191,10 +180,10 @@ class FeishuController
|
||||
}]
|
||||
]
|
||||
}
|
||||
}";
|
||||
}";*/
|
||||
|
||||
// 卡片 类型
|
||||
/* $content = "{
|
||||
/*$content = "{
|
||||
\"config\":{
|
||||
\"wide_screen_mode\":true
|
||||
},
|
||||
@@ -223,13 +212,89 @@ class FeishuController
|
||||
}
|
||||
}
|
||||
}";*/
|
||||
$msgType = 'interactive';
|
||||
// $msgType = 'interactive';
|
||||
// $msgType = 'post'; //卡片消息:interactive,富文本消息:post
|
||||
$receiveIdtype = 'open_id';
|
||||
|
||||
$result = $class->sendMessages($receiveId, $content, $msgType, $receiveIdtype);
|
||||
return json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 富文本消息
|
||||
* @param $title
|
||||
* @param $content
|
||||
* @param $href
|
||||
* @return string
|
||||
*/
|
||||
public static function postMsg($title,$content,$href)
|
||||
{
|
||||
// 富文本 类型
|
||||
$content = "{
|
||||
\"zh_cn\":{
|
||||
\"title\":\"$title\",
|
||||
\"content\":[
|
||||
[{
|
||||
\"tag\":\"text\",
|
||||
\"text\":\"$content\",
|
||||
\"style\":[\"bold\"]
|
||||
}],
|
||||
[{
|
||||
\"tag\":\"hr\"
|
||||
}],
|
||||
[{
|
||||
\"tag\":\"a\",
|
||||
\"href\":\"$href\",
|
||||
\"text\":\"查看详情\"
|
||||
}]
|
||||
]
|
||||
}
|
||||
}";
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡片消息
|
||||
* @param $title
|
||||
* @param $content
|
||||
* @param $href
|
||||
* @return string
|
||||
*/
|
||||
public static function interactiveMsg($title,$content,$href)
|
||||
{
|
||||
// 富文本 类型
|
||||
$content = "{
|
||||
\"config\":{
|
||||
\"wide_screen_mode\":true
|
||||
},
|
||||
\"elements\":[{
|
||||
\"tag\":\"div\",
|
||||
\"text\":{
|
||||
\"content\":\"$content \",
|
||||
\"tag\":\"lark_md\"
|
||||
}},{
|
||||
\"actions\":[{
|
||||
\"tag\":\"button\",
|
||||
\"text\":{
|
||||
\"content\":\"立即查看\",
|
||||
\"tag\":\"plain_text\"
|
||||
},
|
||||
\"type\":\"primary\",
|
||||
\"url\":\"$href\"
|
||||
}],
|
||||
\"tag\":\"action\"
|
||||
}],
|
||||
\"header\":{
|
||||
\"template\":\"turquoise\",
|
||||
\"title\":{
|
||||
\"content\":\"📚$title\",
|
||||
\"tag\":\"plain_text\"
|
||||
}
|
||||
}
|
||||
}";
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function show()
|
||||
{
|
||||
return '<div>查看详情 - 示例页面</div>';
|
||||
|
||||
@@ -123,10 +123,13 @@ class FollowController
|
||||
if(Util::isEmpty($type)){
|
||||
return Util::fail([],'type'.trans('not_null'));
|
||||
}
|
||||
$picture = Util::getParam($request,'picture');
|
||||
if(Util::isEmpty($picture)){
|
||||
return Util::fail([],trans('picture_not_null'));
|
||||
}
|
||||
|
||||
$picture = Util::getParam($request,'picture');
|
||||
$audio_text = Util::getParam($request,'audio_text');
|
||||
$remark = Util::getParam($request,'remark');
|
||||
if(Util::isEmpty($picture) && Util::isEmpty($audio_text) && Util::isEmpty($remark)){
|
||||
return Util::fail([],trans('follow_not_null'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'user_id'=>$request->user['id'],
|
||||
@@ -135,7 +138,7 @@ class FollowController
|
||||
'picture'=>$picture,
|
||||
'remark'=>Util::getParam($request,'remark',''),
|
||||
'audio'=>Util::getParam($request,'audio',''),
|
||||
'audio_text'=>Util::getParam($request,'audio',''),
|
||||
'audio_text'=>Util::getParam($request,'audio_text',''),
|
||||
'lat'=>Util::getParam($request,'lat',0),
|
||||
'lng'=>Util::getParam($request,'lng',0),
|
||||
'address'=>Util::getParam($request,'address'),
|
||||
@@ -146,6 +149,8 @@ class FollowController
|
||||
|
||||
$customer = Customer::find($customer_id);
|
||||
$customer->follow_last = strtotime($res->created_at);
|
||||
$customer->follow_next = null;
|
||||
$customer->warn = 0;
|
||||
$customer->save();
|
||||
|
||||
if ($res) {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\CustomerTag;
|
||||
use app\model\TagGroup;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Request;
|
||||
|
||||
class TagGroupController
|
||||
{
|
||||
|
||||
// 列表
|
||||
public function list(Request $request)
|
||||
{
|
||||
$list = TagGroup::with('tags')->get();
|
||||
$languageArr = Constants::LANGUAGE;
|
||||
$language = $request->user['language'];
|
||||
foreach ($list as &$item) {
|
||||
$item['names'] = unserialize($item['names']);
|
||||
if (in_array($language, $languageArr)) {
|
||||
$item['name'] = $item['names'][$language];
|
||||
}
|
||||
foreach ($item['tags'] as &$tag) {
|
||||
$tag['names'] = unserialize($tag['names']);
|
||||
if (in_array($language, $languageArr)) {
|
||||
$tag['name'] = $tag['names'][$language];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Util::success($list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新客户标签关系
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
*/
|
||||
public function updatePivot(Request $request)
|
||||
{
|
||||
$customerId = Util::getParam($request, 'customer_id');
|
||||
$groupId = Util::getParam($request, 'group_id');
|
||||
$tagId = Util::getParam($request, 'tag_id');
|
||||
if (Util::isEmpty($customerId)) {
|
||||
return Util::fail([], trans('customer_id') . trans('not_null'));
|
||||
}
|
||||
if (Util::isEmpty($groupId)) {
|
||||
return Util::fail([], trans('tag_group_id') . trans('not_null'));
|
||||
}
|
||||
|
||||
if(empty($tagId)){
|
||||
$res = CustomerTag::where(['customer_id' => $customerId, 'group_id' => $groupId])->delete();
|
||||
}else{
|
||||
$res = CustomerTag::updateOrCreate(['customer_id' => $customerId, 'group_id' => $groupId], ['tag_id' => $tagId]);
|
||||
}
|
||||
|
||||
if($res){
|
||||
return Util::success($res, trans('success'));
|
||||
}else{
|
||||
return Util::fail($res, trans('fail'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,11 @@ use support\Request;
|
||||
|
||||
class UploadController
|
||||
{
|
||||
|
||||
/**
|
||||
* 不需要登录的方法
|
||||
*/
|
||||
protected $noNeedLogin = ['uploadImage'];
|
||||
// 允许的文件类型
|
||||
protected $allowedMimeTypes = [
|
||||
'image/jpeg',
|
||||
@@ -110,7 +115,7 @@ class UploadController
|
||||
}
|
||||
|
||||
$result = Storage::adapter('oss')
|
||||
->path('vehicle_album/'.date('Ymd'))
|
||||
->path('lingke_crm/'.date('Ymd'))
|
||||
->size(1024*1024*5)
|
||||
->extYes(['image/jpeg','image/png'])
|
||||
->extNo(['image/gif'])
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\model\Country;
|
||||
use app\model\FeishuUser;
|
||||
use app\model\User;
|
||||
use app\model\UserSn;
|
||||
use app\service\MailService;
|
||||
use app\service\UserService;
|
||||
use app\util\HttpClient;
|
||||
use app\util\JwtUtil;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use support\Request;
|
||||
|
||||
@@ -15,7 +21,7 @@ class UserController
|
||||
/**
|
||||
* 不需要登录的方法
|
||||
*/
|
||||
protected $noNeedLogin = ['login', 'sendCode', 'register'];
|
||||
protected $noNeedLogin = ['login', 'sendCode', 'register', 'step'];
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
@@ -41,11 +47,12 @@ class UserController
|
||||
$userPassword = $user['password'];
|
||||
|
||||
//加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
// $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
//验证密码
|
||||
// if (!password_verify($userPassword, $hashedPassword)) {
|
||||
if ($userPassword == $hashedPassword) {
|
||||
// if ($userPassword == $hashedPassword) {
|
||||
if (!password_verify($password, $userPassword)) {
|
||||
locale($language);
|
||||
return Util::fail([], trans('password_error'));
|
||||
}
|
||||
@@ -61,7 +68,7 @@ class UserController
|
||||
$result['token'] = $token;
|
||||
$result['feishu_openid'] = FeishuUser::where('user_id', $userId)->value('open_id');
|
||||
|
||||
if (Util::isEmpty($language)) {
|
||||
if (!Util::isEmpty($language)) {
|
||||
User::where('id', $userId)
|
||||
->update(['language' => $language]);
|
||||
locale($language);
|
||||
@@ -80,7 +87,7 @@ class UserController
|
||||
{
|
||||
$email = Util::getParam($request, 'email');
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
return Util::fail([], trans('required_not_null'));
|
||||
return Util::fail([], trans('email_error'));
|
||||
}
|
||||
|
||||
// 生成验证码
|
||||
@@ -124,9 +131,9 @@ class UserController
|
||||
$res = User::select('id', 'email')
|
||||
->where('email', $email)
|
||||
->first();
|
||||
// if (!Util::isEmpty($res)) {
|
||||
// return Util::fail([], trans('email_repeat'));
|
||||
// }
|
||||
if (!empty($res)) {
|
||||
return Util::fail($res, trans('email_repeat'));
|
||||
}
|
||||
|
||||
if (Util::isEmpty($name)) {
|
||||
// return Util::fail([], trans('required_not_null'));
|
||||
@@ -137,6 +144,9 @@ class UserController
|
||||
if ($code != $verification_code) {
|
||||
return Util::fail([], trans('code_error'));
|
||||
}
|
||||
if(strlen($password) < 6) {
|
||||
return Util::fail([], trans('password_short'));
|
||||
}
|
||||
|
||||
//加密
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
@@ -144,15 +154,28 @@ class UserController
|
||||
$data = [
|
||||
'mobile' => $mobile,
|
||||
'email' => $email,
|
||||
'name' => $name,
|
||||
'name' => '用户_'.rand(111111, 999999),
|
||||
'sex' => $sex,
|
||||
'role' => 1,
|
||||
'password' => $hashedPassword,
|
||||
'status' => 0,
|
||||
'avatar' => 'lingke_crm/logo.png'
|
||||
];
|
||||
|
||||
|
||||
if (Util::isEmpty($id)) {
|
||||
$res = User::create($data);
|
||||
$option = ['email' => $email];
|
||||
$userService = new UserService;
|
||||
$res = $userService->createOrquery($option);
|
||||
Log::info('register_rpc',$res);
|
||||
// return Util::fail($res, trans('register_fail'));
|
||||
if ($res['code'] != 200 && $res['data']['code'] != 0){
|
||||
return Util::fail($res, trans('register_fail'));
|
||||
}
|
||||
$data['sn'] = $res['data']['data']['sn'];
|
||||
$data['id'] = $res['data']['data']['uid'];
|
||||
$res = User::firstOrCreate(['sn' => $data['sn']],$data);
|
||||
$res['id'] = $data['id'];
|
||||
} else {
|
||||
$res = User::where('id', $id)
|
||||
->update($data);
|
||||
@@ -169,6 +192,28 @@ class UserController
|
||||
}
|
||||
}
|
||||
|
||||
public function step()
|
||||
{
|
||||
$users = User::where(['sn'=>0])->get();
|
||||
$r = [];
|
||||
foreach ($users as $user) {
|
||||
$option = ['email' => $user->email];
|
||||
$userService = new UserService;
|
||||
$res = $userService->createOrquery($option);
|
||||
Log::info('register_rpc',$res);
|
||||
// return Util::fail($res, trans('register_fail'));
|
||||
if ($res['code'] != 200 && $res['data']['code'] != 0){
|
||||
return Util::fail($res, trans('register_fail'));
|
||||
}
|
||||
$data[] = [];
|
||||
$data['sn'] = $res['data']['data']['sn'];
|
||||
$data['id'] = $res['data']['data']['uid'];
|
||||
$res = User::where('id',$user->id)->update(['sn' => $data['sn'],'id' => $data['id']]);
|
||||
$r[]=$data;
|
||||
}
|
||||
return Util::success($r, trans('register_success'));
|
||||
}
|
||||
|
||||
|
||||
public function getInfo(Request $request)
|
||||
{
|
||||
@@ -178,8 +223,15 @@ class UserController
|
||||
$user->toArray();
|
||||
unset($user->password);
|
||||
$user['feishu_openid'] = FeishuUser::where('user_id', $userId)->value('open_id');
|
||||
$user['country_name'] = Country::where('id', $user['country_id'])->value('cn_addr');
|
||||
$ossservice = new \app\service\OssService();
|
||||
$user['avatar_url'] = $user['avatar'] ? $ossservice->generatePrivateUrl($user['avatar']) : '';
|
||||
$user['socialize_pic_url'] = $user['socialize_pic'] ? $ossservice->generatePrivateUrl($user['socialize_pic']) : '';
|
||||
|
||||
return Util::success($user, trans('save_success'));
|
||||
// 重构数组
|
||||
$sign = array_column(Constants::SIGN, 'name', 'id');
|
||||
$user['company'] = isset($sign[$user['sign']])?$sign[$user['sign']]:'';
|
||||
return Util::success($user, trans('success'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,23 +242,32 @@ class UserController
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
$name = Util::getParam($request, 'name');
|
||||
$sex = Util::getParam($request, 'sex');
|
||||
$position = Util::getParam($request, 'position');
|
||||
$country_id = Util::getParam($request, 'country_id');
|
||||
$sign = Util::getParam($request, 'sign');
|
||||
$id = $request->user['id'];
|
||||
$avatar = Util::getParam($request, 'avatar');
|
||||
$socializePic = Util::getParam($request, 'socialize_pic');
|
||||
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'sex' => $sex,
|
||||
'position' => $position,
|
||||
'country_id' => $country_id,
|
||||
'sign' => $sign,
|
||||
];
|
||||
$user = User::where('id', $id)->first();
|
||||
// 只填充前端传递的字段
|
||||
$user->fill($request->only(['name', 'sex', 'position', 'country_id', 'sign', 'mobile', 'address', 'socialize', 'socialize_pic']));
|
||||
|
||||
$res = User::where('id', $id)
|
||||
->update($data);
|
||||
if(!Util::isEmpty($avatar)){
|
||||
$user->avatar = $avatar;
|
||||
}
|
||||
if(!Util::isEmpty($socializePic)){
|
||||
$user->socialize_pic = $socializePic;
|
||||
}
|
||||
|
||||
$mobile = $user->isDirty('mobile');
|
||||
$name = $user->isDirty('name');
|
||||
$sign = $user->isDirty('sign');
|
||||
if($mobile || $name || $sign){
|
||||
$userService = new UserService;
|
||||
$option = ['uid' => $user->id, 'phone' => $user->mobile, 'name' => $user->name, 'sign' => $user->sign, ];
|
||||
$res = $userService->update($option);
|
||||
Log::info('register_rpc',$res);
|
||||
}
|
||||
|
||||
$res = $user->save();
|
||||
|
||||
if ($res) {
|
||||
return Util::success($res, trans('save_success'));
|
||||
@@ -270,7 +331,7 @@ class UserController
|
||||
if (Util::isEmpty($language)) {
|
||||
return Util::fail([], 'language' . trans('not_null'));
|
||||
}
|
||||
if (!in_array($language, ['en', 'zh_CN'])) {
|
||||
if (!in_array($language, Constants::LANGUAGE)) {
|
||||
return Util::fail([], trans('param_error'));
|
||||
}
|
||||
$data = [
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace app\middleware;
|
||||
|
||||
|
||||
use app\admin\model\Admin;
|
||||
use app\model\User;
|
||||
use app\util\JwtUtil;
|
||||
use app\util\Util;
|
||||
@@ -54,11 +55,15 @@ class AuthMiddleware implements MiddlewareInterface
|
||||
// 从 Header 获取 Token
|
||||
$token = $request->header('Authorization');
|
||||
|
||||
$language = Util::getParam($request, 'language');
|
||||
$language = $language=='zh_CN'?:'en';
|
||||
//需要登录并且未提供token
|
||||
if ($isLogin && (!$token || !str_starts_with($token, 'Bearer '))) {
|
||||
return Util::fail('','请先登录',401);
|
||||
locale($language);
|
||||
return Util::fail('',trans('user_login'),401);
|
||||
// throw new BusinessException('未提供 Token'.$isLogin, 401);
|
||||
}elseif(!$isLogin){
|
||||
locale($language);
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
@@ -68,19 +73,32 @@ class AuthMiddleware implements MiddlewareInterface
|
||||
// 验证 Token 并获取用户ID
|
||||
$decoded = JwtUtil::verifyToken($token);
|
||||
|
||||
$userId = $decoded->sub;
|
||||
|
||||
$user = User::select(['id','name','sex','role','avatar','email','password','language','created_at'])
|
||||
->find($userId);
|
||||
if(!$user){
|
||||
return Util::fail(['user'=>$user],trans('user_none'));
|
||||
if (!isset($decoded->sub)) {
|
||||
return Util::fail('', trans('user_login'),401);
|
||||
}
|
||||
|
||||
$userId = $decoded->sub;
|
||||
if(str_starts_with($userId,'admin_')){
|
||||
$userId = substr($userId,6);
|
||||
$user = Admin::find($userId);
|
||||
if(!$user){
|
||||
return Util::fail(['user'=>$user],trans('user_none'));
|
||||
}
|
||||
// $user = $user->toArray();
|
||||
|
||||
}else{
|
||||
$user = User::select(['id','name','sex','role','avatar','email','password','language','created_at'])
|
||||
->find($userId);
|
||||
if(!$user){
|
||||
return Util::fail(['user'=>$user],trans('user_none'));
|
||||
}
|
||||
$user = $user->toArray();
|
||||
locale($user['language']);
|
||||
}
|
||||
$user = $user->toArray();
|
||||
|
||||
// 将用户ID存入请求对象,供后续使用
|
||||
// $request->user = ['id' => $userId];
|
||||
$request->user = $user;
|
||||
locale($user['language']);
|
||||
return $handler($request);
|
||||
} catch (BusinessException $e) {
|
||||
return json(['code' => 401, 'msg' => $e->getMessage()]);
|
||||
|
||||
@@ -7,19 +7,36 @@ use Webman\MiddlewareInterface;
|
||||
|
||||
class CrossDomain implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $next): Response
|
||||
{
|
||||
// 动态允许请求来源(支持携带Cookie)
|
||||
$origin = $request->header('origin', '*');
|
||||
$response = $next($request);
|
||||
// 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;
|
||||
// }
|
||||
|
||||
// 设置跨域响应头
|
||||
public function process(Request $request, callable $handler) : Response
|
||||
{
|
||||
// 如果是options请求则返回一个空响应,否则继续向洋葱芯穿越,并得到一个响应
|
||||
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
|
||||
|
||||
// 给响应添加跨域相关的http头
|
||||
$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, // 预检请求缓存时间(秒)
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Allow-Origin' => $request->header('origin', '*'),
|
||||
'Access-Control-Allow-Methods' => $request->header('access-control-request-method', '*'),
|
||||
'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'),
|
||||
'Vary' => 'Origin' // 避免缓存干扰
|
||||
]);
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
namespace app\middleware;
|
||||
|
||||
use app\model\RequestTracks;
|
||||
|
||||
class DataTracker
|
||||
{
|
||||
// 不需要埋点的路径
|
||||
protected $excludePaths = [
|
||||
'/user/login'
|
||||
];
|
||||
|
||||
public function process($request, \Closure $next)
|
||||
{
|
||||
if ($this->shouldSkipTracking($request)) {
|
||||
return $next($request);
|
||||
}
|
||||
// 前置处理
|
||||
$this->logRequestData($request);
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
// 后置处理
|
||||
// $this->logResponseData($response);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
protected function shouldSkipTracking($request)
|
||||
{
|
||||
$currentPath = $request->path();
|
||||
|
||||
$eventTracking = config('const.event_tracking');
|
||||
|
||||
// 检查是否在排除列表中
|
||||
// foreach ($this->excludePaths as $path) {
|
||||
// if (str_starts_with($currentPath, $path)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (in_array($currentPath, $eventTracking)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function logRequestData($request)
|
||||
{
|
||||
$trackData = [
|
||||
'app_id' => 'crm/api',
|
||||
'user_id' => $request->user['id']??0,
|
||||
'ip' => $request->getRealIp(),
|
||||
'method' => $request->method(),
|
||||
'path' => $request->path(),
|
||||
'params' => json_encode($request->all()),
|
||||
'header' => json_encode($request->header()),
|
||||
'uuid' => $this->generateTraceId(),
|
||||
'user_agent' => $request->header('user-agent'),
|
||||
'referer' => $request->header('referer'),
|
||||
];
|
||||
$requestTrack = RequestTracks::create($trackData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function generateTraceId()
|
||||
{
|
||||
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class CarType extends Model
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','name','status')->where('status',0)->toArray();
|
||||
$list = self::get()->select('id','name','name_en','status')->where('status',0)->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ class Channel extends Model
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$list = self::get()->select('id','name','status')->where('status',0)->toArray();
|
||||
$list = self::get()->select('id','name','name_en','status')->where('status',0)->toArray();
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
+48
-10
@@ -59,21 +59,28 @@ class Customer extends Model
|
||||
return $date->format(Carbon::parse($date)->toDateTimeString());
|
||||
}
|
||||
|
||||
public static function getCustomer($customer)
|
||||
/**
|
||||
* @param $customer
|
||||
* @param $request
|
||||
* @param $tag 是否返回客户标签
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getCustomer($customer, $request, $tag = false)
|
||||
{
|
||||
$customer['grade_txt'] = Constants::GRADE[$customer['grade']];
|
||||
$customer['magnitude_txt'] = Constants::MAGNITUDE[$customer['magnitude']];
|
||||
$customer['sex_txt'] = Constants::SEX[$customer['sex']];
|
||||
$language = $request->user['language'] ?: 'en';
|
||||
$customer['grade_txt'] = Util::language($language, Constants::GRADE_EN[$customer['grade']], Constants::GRADE[$customer['grade']], Constants::GRADE_RU[$customer['grade']]);
|
||||
$customer['magnitude_txt'] = Util::language($language, Constants::MAGNITUDE_EN[$customer['magnitude']], Constants::MAGNITUDE[$customer['magnitude']], Constants::MAGNITUDE_RU[$customer['magnitude']]);
|
||||
$customer['sex_txt'] = Util::language($language, Constants::SEX_EN[$customer['sex']], Constants::SEX[$customer['sex']], Constants::SEX_RU[$customer['sex']]);
|
||||
|
||||
if ($customer['grade']<=2) {
|
||||
$customer['follow'] = 0;
|
||||
$customer['follow_txt'] = '跟进中';
|
||||
$customer['follow_txt'] = Util::language($language,'Following','跟进中','Продолжение');
|
||||
}elseif ($customer['grade']<5) {
|
||||
$customer['follow'] = 1;
|
||||
$customer['follow_txt'] = '已成交';
|
||||
$customer['follow_txt'] = Util::language($language,'transacted','已成交','Транзакция завершена');
|
||||
}else{
|
||||
$customer['follow'] = 2;
|
||||
$customer['follow_txt'] = '已流失';
|
||||
$customer['follow_txt'] = Util::language($language,'lost','已流失','Потерянный');
|
||||
}
|
||||
|
||||
$where = [
|
||||
@@ -89,11 +96,42 @@ class Customer extends Model
|
||||
// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']);
|
||||
|
||||
$customer = Util::formatDate($customer,['follow_last']);
|
||||
$customer['car_type_name'] = empty($customer['car_type_id'])?'':CarType::where(['id'=>$customer['car_type_id']])->value('name');
|
||||
$customer['country_name'] = empty($customer['country_id'])?'':Country::where(['id'=>$customer['country_id']])->value('cn_addr');
|
||||
$customer['channel_name'] = empty($customer['channel_id'])?'':Channel::where(['id'=>$customer['channel_id']])->value('name');
|
||||
$nameLang = $language=='en'?'name_en':($language=='ru'?'name_ru':'name');
|
||||
$countryLang = $language=='en'?'en_addr':'cn_addr';
|
||||
$customer['car_type_name'] = empty($customer['car_type_id'])?'':CarType::where(['id'=>$customer['car_type_id']])->value($nameLang);
|
||||
$customer['country_name'] = empty($customer['country_id'])?'':Country::where(['id'=>$customer['country_id']])->value($countryLang);
|
||||
$customer['channel_name'] = empty($customer['channel_id'])?'':Channel::where(['id'=>$customer['channel_id']])->value($nameLang);
|
||||
// $customer['last_follow'] = $last_follow;
|
||||
|
||||
if ($tag) {
|
||||
foreach ($customer['tags'] as &$tag) {
|
||||
$tag['names'] = unserialize($tag['names']);
|
||||
$tag['name'] = $tag['names'][$language];
|
||||
}
|
||||
}
|
||||
|
||||
return $customer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户的标签
|
||||
*/
|
||||
public function tags()
|
||||
{
|
||||
return $this->belongsToMany(Tag::class, 'customer_tag', 'customer_id', 'tag_id')
|
||||
->withTimestamps(); // 如果需要记录关联时间
|
||||
}
|
||||
|
||||
|
||||
// 定义与 变更历史 的一对多关系
|
||||
public function his()
|
||||
{
|
||||
return $this->hasMany(CustomerHis::class, 'customer_id', 'id');
|
||||
}
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CustomerHis extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'customer_his';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
// 'created_at' => 'timestamp', // 指定序列化格式
|
||||
];
|
||||
|
||||
/**
|
||||
* 重新格式化时间
|
||||
* @param DateTimeInterface $date
|
||||
* @return string
|
||||
*/
|
||||
protected function serializeDate(DateTimeInterface $date): string
|
||||
{
|
||||
return $date->format(Carbon::parse($date)->toDateTimeString());
|
||||
}
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function customer()
|
||||
{
|
||||
return $this->belongsTo(Customer::class, 'customer_id', 'id');
|
||||
}
|
||||
|
||||
// 禁用 updated_at 的自动更新
|
||||
public function setUpdatedAt($value)
|
||||
{
|
||||
return $this; // 不做任何操作
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use app\util\Util;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CustomerTag extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'customer_tag';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id', 'created_at'];
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
|
||||
class Daily extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'daily';
|
||||
|
||||
/**
|
||||
* 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 $dates = ['deleted_at'];
|
||||
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
];
|
||||
|
||||
/**
|
||||
* 重新格式化时间
|
||||
* @param DateTimeInterface $date
|
||||
* @return string
|
||||
*/
|
||||
protected function serializeDate(DateTimeInterface $date): string
|
||||
{
|
||||
return $date->format(Carbon::parse($date)->toDateTimeString());
|
||||
}
|
||||
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id', 'id');
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -3,6 +3,7 @@
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use app\service\OssService;
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use support\Model;
|
||||
@@ -37,8 +38,6 @@ class Follow extends Model
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $dates = ['created_at', 'updated_at', 'follow_time'];
|
||||
|
||||
protected $casts = [
|
||||
'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
@@ -50,8 +49,16 @@ class Follow extends Model
|
||||
public static function getFollow($follow,$domain = 'https://vehicle-album.oss-cn-beijing.aliyuncs.com')
|
||||
{
|
||||
$follow['type_txt'] = Constants::FOLLOW[$follow['type']];
|
||||
$follow['firstFollowtime'] = $follow['follow_time'];
|
||||
$follow['oss_picture'] = $domain.'/'.$follow['picture'];
|
||||
$follow['firstFollowtime'] = $follow['follow_time'];
|
||||
if (isset($follow['picture']) && !empty($follow['picture'])) {
|
||||
$ossservice = new OssService();
|
||||
$oss_picture = $ossservice->generatePrivateUrl($follow['picture'],86400);
|
||||
$follow['oss_picture'] = $oss_picture;
|
||||
}else {
|
||||
$follow['oss_picture'] = '';
|
||||
}
|
||||
$follow['created_at'] = date('Y-m-d H:i:s',strtotime($follow['created_at'])+(3600*8));
|
||||
$follow['updated_at'] = date('Y-m-d H:i:s',strtotime($follow['updated_at'])+(3600*8));
|
||||
// $follow = Util::formatDate($follow);
|
||||
return $follow;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
|
||||
class RequestTracks extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'request_tracks';
|
||||
|
||||
/**
|
||||
* The primary key associated with the table.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $primaryKey = 'id';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at'];
|
||||
|
||||
// 指定日期字段存储格式为时间戳
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
];
|
||||
|
||||
/**
|
||||
* 重新格式化时间
|
||||
* @param DateTimeInterface $date
|
||||
* @return string
|
||||
*/
|
||||
protected function serializeDate(DateTimeInterface $date): string
|
||||
{
|
||||
return $date->format(Carbon::parse($date)->toDateTimeString());
|
||||
}
|
||||
|
||||
// 禁用 updated_at 的自动更新
|
||||
public function setUpdatedAt($value)
|
||||
{
|
||||
return $this; // 不做任何操作
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Tag extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'tag';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
// 定义反向多对一关联
|
||||
public function group()
|
||||
{
|
||||
return $this->belongsTo(TagGroup::class, 'group_id', 'id');
|
||||
}
|
||||
|
||||
public function customers()
|
||||
{
|
||||
return $this->belongsToMany(Customer::class, 'customer_tag', 'tag_id', 'customer_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
use app\util\Util;
|
||||
use config\constants\Constants;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Carbon;
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class TagGroup extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'tag_group';
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
use SoftDeletes;
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
// 定义与 Tag 的一对多关系
|
||||
public function tags()
|
||||
{
|
||||
return $this->hasMany(Tag::class, 'group_id', 'id');
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -34,7 +34,7 @@ class User extends Model
|
||||
protected $dateFormat = 'U';
|
||||
|
||||
//设置黑名单
|
||||
protected $guarded = ['id','created_at','updated_at'];
|
||||
protected $guarded = ['created_at','updated_at'];
|
||||
|
||||
protected $casts = [
|
||||
// 'updated_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式
|
||||
@@ -50,4 +50,10 @@ class User extends Model
|
||||
->toArray();
|
||||
return $user;
|
||||
}
|
||||
|
||||
// 定义与 Customer 的一对多关系
|
||||
public function customer()
|
||||
{
|
||||
return $this->hasMany(Customer::class, 'user_id', 'id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace app\model;
|
||||
|
||||
|
||||
|
||||
use support\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class UserSn extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user_sn';
|
||||
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
}
|
||||
+156
-9
@@ -1,37 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace process;
|
||||
namespace app\process;
|
||||
|
||||
use app\controller\FeishuController;
|
||||
use app\model\Customer;
|
||||
use app\model\CustomerHis;
|
||||
use app\model\Daily;
|
||||
use app\model\FeishuUser;
|
||||
use app\model\RequestTracks;
|
||||
use app\model\User;
|
||||
use support\Log;
|
||||
use Webman\App;
|
||||
use Workerman\Crontab\Crontab;
|
||||
|
||||
class Task
|
||||
{
|
||||
|
||||
public function onWorkerStart()
|
||||
{
|
||||
// 每半小时执行一次
|
||||
new Crontab('30/* * * * *', function () {
|
||||
new Crontab('0 */30 * * * *', function () {
|
||||
echo date('Y-m-d H:i:s') . "\n";
|
||||
$customer = Customer::where(['follow_next', '<=', time() + 3600])
|
||||
->where(['follow_next', '>', time()])
|
||||
->where(['warn', '<', 1])
|
||||
->get();
|
||||
Log::info('send follow start', [time()]);
|
||||
// FeishuController::send('xinyouhe','ou_e33bb3017ada6c4781398a68e55a4696', '跟进提醒', '您有新的跟进提醒', '');
|
||||
// $customer = Customer::where(['follow_next', '<=', time() + 3600])
|
||||
// ->where(['follow_next', '>', time()])
|
||||
// ->where(['warn', '<', 1])
|
||||
// ->get();
|
||||
// foreach ($customer as $item) {
|
||||
// $feishuUser = FeishuUser::where(['user_id' => $item->user_id])->first();
|
||||
// if ($feishuUser) {
|
||||
// // 获取凭证
|
||||
// $certificate = config($this->config);
|
||||
// // 使用parse_url解析URL
|
||||
// $parsedUrl = parse_url($certificate['rUrl']);
|
||||
// // 获取域名和端口
|
||||
// $host = $parsedUrl['host'];
|
||||
// $port = isset($parsedUrl['port']) ? ':' . $parsedUrl['port'] : '';
|
||||
// $url = $host .$port. '/pages/customer/detile?id='.$customer->id;
|
||||
// $item->warn = 1;
|
||||
// $item->update();
|
||||
// $user = User::first()->where('id', $item->user_id);
|
||||
// Log::info('send',['open_id'=>$item['open_id'],'url'=>$url]);
|
||||
// // FeishuController::send('xinyouhe','ou_e33bb3017ada6c4781398a68e55a4696', '跟进提醒', '您有新的跟进提醒', $url);
|
||||
// FeishuController::send($user->sign,$feishuUser->open_id, '跟进提醒', '您有新的跟进提醒', $url);
|
||||
// }
|
||||
// }
|
||||
|
||||
$where = [
|
||||
['follow_next', '<=', time() + 3600],
|
||||
['follow_next', '>', time()],
|
||||
['warn', '<', 1]
|
||||
];
|
||||
$customer = Customer::where($where)->get();
|
||||
foreach ($customer as $item) {
|
||||
$feishuUser = FeishuUser::where(['user_id' => $item->user_id])->first();
|
||||
if ($feishuUser) {
|
||||
// 获取凭证
|
||||
$certificate = config($this->config);
|
||||
$certificate = config('feishu.' . $feishuUser->sign);
|
||||
// 使用parse_url解析URL
|
||||
$parsedUrl = parse_url($certificate['rUrl']);
|
||||
// 获取域名和端口
|
||||
$host = $parsedUrl['host'];
|
||||
$port = isset($parsedUrl['port']) ? ':' . $parsedUrl['port'] : '';
|
||||
$url = $host .$port. '/pages/customer/detile?id='.$customer->id;
|
||||
FeishuController::class->send($feishuUser->open_id, '跟进提醒', '您有新的跟进提醒', $url);
|
||||
$url = 'http://' . $host . $port . '/pages/customer/detile?id=' . $item->id;
|
||||
$item->warn = 1;
|
||||
$item->update();
|
||||
Log::info('send', ['open_id' => $item['open_id'], 'url' => $url]);
|
||||
$content = FeishuController::postMsg('跟进提醒', '您有新的跟进提醒', $url);
|
||||
FeishuController::send($feishuUser->sign, $feishuUser->open_id, $content, 'post');
|
||||
}
|
||||
}
|
||||
|
||||
Log::info('send follow start', [time()]);
|
||||
});
|
||||
|
||||
|
||||
//回收站客户转向公海 每小时执行一次
|
||||
new Crontab('0 10 * * * *', function () {
|
||||
echo date('Y-m-d H:i:s') . "\n";
|
||||
Log::info('send high seas start', [time()]);
|
||||
|
||||
$where = [
|
||||
['deleted_at', '<=', time() - 3600],
|
||||
['user_id', '<>', 0],
|
||||
];
|
||||
$customer = Customer::where($where)->onlyTrashed()->get();
|
||||
foreach ($customer as $item) {
|
||||
$item->update(['user_id' => 0, 'deleted_at' => time()]);
|
||||
CustomerHis::create([
|
||||
'customer_id' => $item->_id,
|
||||
'user_his' => $item->user_id,
|
||||
'user_id' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
Log::info('send high seas end', [time()]);
|
||||
});
|
||||
|
||||
//总结日报, 每天执行一次
|
||||
new Crontab('0 30 17 * * *', function () {
|
||||
echo date('Y-m-d H:i:s') . " start daily \n";
|
||||
Log::info('start daily', [time()]);
|
||||
$where[] = ["user_id", ">", 0];
|
||||
$where = [
|
||||
['created_at', '<=', time() - (3600 * 24)],
|
||||
];
|
||||
$eventTracking = config('const.event_tracking');
|
||||
$requestTracks = RequestTracks::selectRaw('user_id,path, COUNT(*) as count',)
|
||||
// select('*',' COUNT(*) as count')
|
||||
->where($where)
|
||||
->whereIn('path', $eventTracking)
|
||||
->groupBy('user_id', 'path')
|
||||
// ->orderBy('user_id', 'asc')
|
||||
->get();
|
||||
|
||||
$statistics = [];
|
||||
$users = [];
|
||||
$content = '';
|
||||
foreach ($requestTracks as $item) {
|
||||
$statistics[$item->user_id][$item->path] = $item->count;
|
||||
$users[] = $item->user_id;
|
||||
}
|
||||
|
||||
foreach ($users as $userId) {
|
||||
$data = [
|
||||
'user_id' => $userId,
|
||||
'customer_claim' => $statistics[$userId]['customer/claim'] ?? 0,
|
||||
'customer_save' => $statistics[$userId]['customer/save'] ?? 0,
|
||||
'follow_add' => $statistics[$userId]['follow/save'] ?? 0,
|
||||
'customer_collect' => $statistics[$userId]['customer/collect'] ?? 0,
|
||||
'content' => '',
|
||||
];
|
||||
|
||||
//判断领导
|
||||
$mast = config('const.daily_group_2');
|
||||
if (in_array($userId, $mast['member'])) {
|
||||
$data['leader_id'] = $mast['master'];
|
||||
}else{
|
||||
$data['leader_id'] = 5;
|
||||
}
|
||||
|
||||
$content .= date('Y-m-d') . "\n";
|
||||
$data['content'] .= '领取客户' . ($statistics[$userId]['customer/claim'] ?? 0) . '位\n';
|
||||
$data['content'] .= '创建或修改客户' . ($statistics[$userId]['customer/save'] ?? 0) . '位\n';
|
||||
$data['content'] .= '添加跟进' . ($statistics[$userId]['follow/save'] ?? 0) . '次\n';
|
||||
$data['content'] .= '询盘跟单客户' . ($statistics[$userId]['customer/collect'] ?? 0) . '位\n';
|
||||
$content .= $data['content'];
|
||||
|
||||
$daily = Daily::create($data);
|
||||
|
||||
$content .= '请及时查看,30分钟后将向主管发送';
|
||||
|
||||
$feishuUser = FeishuUser::where(['user_id' => $userId])->first();
|
||||
if ($feishuUser) {
|
||||
$url = config('const.web_domain') . '/pages/mine/workreportdetil?id=' . $daily->id;
|
||||
$content = FeishuController::postMsg(date('Y-m-d') . '日报', $content, $url);
|
||||
FeishuController::send($feishuUser->sign, $feishuUser->open_id, $content, 'post');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Log::info('send high seas end', [time()]);
|
||||
});
|
||||
|
||||
|
||||
//向领导发送日报 每天执行一次
|
||||
new Crontab('0 0 18 * * *', function () {
|
||||
echo date('Y-m-d H:i:s') . "\n";
|
||||
Log::info('send daily to leader', [time()]);
|
||||
$where = [];
|
||||
$where[] = ['send', '=', 0];
|
||||
$where[] = ['created_at', '>=', strtotime(date('Y-m-d 00:00:00'))];
|
||||
$daily = Daily::select('leader_id')->where($where)->groupBy('leader_id')->get();
|
||||
foreach ($daily as $item) {
|
||||
$feishuUser = FeishuUser::where(['user_id' => $item->leader_id])->first();
|
||||
if ($feishuUser) {
|
||||
$url = config('const.web_domain') . '/pages/mine/workreport';
|
||||
$content = FeishuController::postMsg(date('Y-m-d') . '日报已汇总', '请点击查看', $url);
|
||||
FeishuController::send($feishuUser->sign, $feishuUser->open_id, $content, 'post');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -192,7 +192,7 @@ class FeishuService
|
||||
"client_id" => $this->appId,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"redirect_uri" => 'http://219.157.255.213:8085/pages/index/webview'
|
||||
"redirect_uri" => $redirect_uri
|
||||
];
|
||||
return $this->requestResult('authen/v2/oauth/token');
|
||||
}
|
||||
|
||||
@@ -19,10 +19,18 @@ class MailService
|
||||
{
|
||||
// SMTP 配置
|
||||
$this->mailer->isSMTP();
|
||||
$this->mailer->Host = 'smtp.gmail.com';
|
||||
// $this->mailer->Host = 'smtp.gmail.com';
|
||||
$this->mailer->Host = 'smtp.feishu.cn';
|
||||
$this->mailer->SMTPAuth = true;
|
||||
$this->mailer->Username = 'xinyouhe25@gmail.com'; // 替换为你的 Gmail
|
||||
$this->mailer->Password = 'zhjkkaplncykzymo'; // 替换为应用专用密码
|
||||
|
||||
// $this->mailer->Username = 'xinyouhe25@gmail.com'; // 替换为你的 Gmail
|
||||
// $this->mailer->Password = 'zhjkkaplncykzymo'; // 替换为应用专用密码
|
||||
|
||||
// $this->mailer->Username = 'linyang0618@gmail.com'; // 替换为你的 Gmail
|
||||
// $this->mailer->Password = 'mrjefuahbwbpqakb'; // 替换为应用专用密码
|
||||
|
||||
$this->mailer->Username = 'app@hnxinyouhe.com'; // 替换为你的 Gmail
|
||||
$this->mailer->Password = 'akyIUFJ6ihGGjI5h'; // 替换为应用专用密码
|
||||
// $this->mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 使用 TLS
|
||||
$this->mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // SSL 加密
|
||||
// $this->mailer->Port = 587;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use app\model\User;
|
||||
use app\model\UserSn;
|
||||
use app\util\HttpClient;
|
||||
|
||||
class UserService
|
||||
{
|
||||
protected $domain;
|
||||
|
||||
|
||||
public function __construct(){
|
||||
$this->domain = config('const.rpc_domain');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户sn
|
||||
* @param $sn
|
||||
* @param $email
|
||||
*/
|
||||
public static function updateSn($sn, $email)
|
||||
{
|
||||
$user = User::first()
|
||||
->where('email', $email)
|
||||
->first();
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
if ($user->sn != $sn) {
|
||||
UserSn::where(['sn' => $user->sn])->update(['user_id' => 0]);
|
||||
UserSn::where(['sn' => $sn])->update(['user_id' => $user->id]);
|
||||
$user->sn = $sn;
|
||||
$user->save();
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或查询用户
|
||||
* @param array $data ['email'=>'','phone'=>'','company_tag'=>'','name'=>''];
|
||||
* @return array
|
||||
*/
|
||||
public function createOrquery(array $data)
|
||||
{
|
||||
|
||||
$result = HttpClient::post($this->domain . '/user/create/query', $data);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建或查询用户
|
||||
* @param array $data ['email'=>'','phone'=>'','company_tag'=>'','name'=>''];
|
||||
* @return array
|
||||
*/
|
||||
public function update(array $data)
|
||||
{
|
||||
|
||||
$result = HttpClient::post($this->domain . '/user/update', $data);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
|
||||
namespace app\util;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class HttpClient
|
||||
{
|
||||
/**
|
||||
* @var Client Guzzle客户端实例
|
||||
*/
|
||||
private static $client;
|
||||
|
||||
/**
|
||||
* 获取Guzzle客户端单例
|
||||
* @return Client
|
||||
*/
|
||||
private static function getClient(): Client
|
||||
{
|
||||
if (!self::$client) {
|
||||
self::$client = new Client([
|
||||
'timeout' => 10, // 默认超时时间10秒
|
||||
'verify' => false, // 不验证SSL证书(生产环境建议设为true)
|
||||
'http_errors' => false, // 不抛出HTTP异常,自己处理
|
||||
]);
|
||||
}
|
||||
return self::$client;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送GET请求
|
||||
* @param string $url 请求地址
|
||||
* @param array $query 查询参数
|
||||
* @param array $headers 请求头
|
||||
* @return array
|
||||
*/
|
||||
public static function get(string $url, array $query = [], array $headers = []): array
|
||||
{
|
||||
$options = [
|
||||
'query' => $query,
|
||||
'headers' => $headers
|
||||
];
|
||||
return self::request('GET', $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送POST请求
|
||||
* @param string $url 请求地址
|
||||
* @param array|string $data 请求数据
|
||||
* @param array $headers 请求头
|
||||
* @param string $contentType 内容类型(form/json/xml)
|
||||
* @return array
|
||||
*/
|
||||
public static function post(string $url, $data = [], array $headers = [], string $contentType = 'form'): array
|
||||
{
|
||||
$options = ['headers' => $headers];
|
||||
|
||||
switch ($contentType) {
|
||||
case 'json':
|
||||
$options['json'] = $data;
|
||||
$options['headers']['Content-Type'] = 'application/json';
|
||||
break;
|
||||
/*case 'xml':
|
||||
$options['body'] = is_array($data) ? self::arrayToXml($data) : $data;
|
||||
$options['headers']['Content-Type'] = 'application/xml';
|
||||
break;*/
|
||||
default: // form
|
||||
$options['form_params'] = $data;
|
||||
$options['headers']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
return self::request('POST', $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送PUT请求
|
||||
* @param string $url 请求地址
|
||||
* @param array|string $data 请求数据
|
||||
* @param array $headers 请求头
|
||||
* @return array
|
||||
*/
|
||||
public static function put(string $url, $data = [], array $headers = []): array
|
||||
{
|
||||
$options = [
|
||||
'json' => $data,
|
||||
'headers' => $headers
|
||||
];
|
||||
return self::request('PUT', $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送DELETE请求
|
||||
* @param string $url 请求地址
|
||||
* @param array $data 请求数据
|
||||
* @param array $headers 请求头
|
||||
* @return array
|
||||
*/
|
||||
public static function delete(string $url, array $data = [], array $headers = []): array
|
||||
{
|
||||
$options = [
|
||||
'json' => $data,
|
||||
'headers' => $headers
|
||||
];
|
||||
return self::request('DELETE', $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP请求
|
||||
* @param string $method 请求方法
|
||||
* @param string $url 请求地址
|
||||
* @param array $options 请求选项
|
||||
* @return array
|
||||
*/
|
||||
public static function request(string $method, string $url, array $options = []): array
|
||||
{
|
||||
try {
|
||||
$response = self::getClient()->request($method, $url, $options);
|
||||
return self::formatResponse($response);
|
||||
} catch (GuzzleException $e) {
|
||||
return [
|
||||
'status' => false,
|
||||
'code' => $e->getCode(),
|
||||
'message' => $e->getMessage(),
|
||||
'data' => null
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param string $url 请求地址
|
||||
* @param array $files 文件数组 [['name' => 'field_name', 'path' => 'file_path']]
|
||||
* @param array $form 其他表单数据
|
||||
* @param array $headers 请求头
|
||||
* @return array
|
||||
*/
|
||||
public static function upload(string $url, array $files, array $form = [], array $headers = []): array
|
||||
{
|
||||
$multipart = [];
|
||||
|
||||
// 添加文件
|
||||
foreach ($files as $file) {
|
||||
if (file_exists($file['path'])) {
|
||||
$multipart[] = [
|
||||
'name' => $file['name'],
|
||||
'contents' => fopen($file['path'], 'r'),
|
||||
'filename' => basename($file['path'])
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 添加其他表单数据
|
||||
foreach ($form as $name => $value) {
|
||||
$multipart[] = [
|
||||
'name' => $name,
|
||||
'contents' => $value
|
||||
];
|
||||
}
|
||||
|
||||
$options = [
|
||||
'multipart' => $multipart,
|
||||
'headers' => $headers
|
||||
];
|
||||
|
||||
return self::request('POST', $url, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化响应
|
||||
* @param ResponseInterface $response
|
||||
* @return array
|
||||
*/
|
||||
private static function formatResponse(ResponseInterface $response): array
|
||||
{
|
||||
$contents = $response->getBody()->getContents();
|
||||
$contentType = $response->getHeaderLine('Content-Type');
|
||||
|
||||
$data = $contents;
|
||||
if (strpos($contentType, 'application/json') !== false) {
|
||||
$data = json_decode($contents, true) ?? $contents;
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => $response->getStatusCode() === 200,
|
||||
'code' => $response->getStatusCode(),
|
||||
'message' => $response->getReasonPhrase(),
|
||||
'data' => $data,
|
||||
'headers' => $response->getHeaders()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 数组转XML
|
||||
* @param array $data
|
||||
* @param string $rootNode
|
||||
* @return string
|
||||
*/
|
||||
private static function arrayToXml(array $data, string $rootNode = 'root'): string
|
||||
{
|
||||
$xml = new \SimpleXMLElement('<' . $rootNode . '/>');
|
||||
self::addDataToXml($xml, $data);
|
||||
return $xml->asXML();
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归添加数据到XML
|
||||
* @param \SimpleXMLElement $xml
|
||||
* @param array $data
|
||||
*/
|
||||
private static function addDataToXml(\SimpleXMLElement $xml, array $data)
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
if (is_numeric($key)) {
|
||||
$key = 'item';
|
||||
}
|
||||
$subNode = $xml->addChild($key);
|
||||
self::addDataToXml($subNode, $value);
|
||||
} else {
|
||||
$xml->addChild($key, htmlspecialchars($value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
namespace app\util;
|
||||
|
||||
use support\Redis;
|
||||
use support\Log;
|
||||
|
||||
class RedisHelper
|
||||
{
|
||||
/**
|
||||
* 存储数据(自动序列化数组)
|
||||
* @param string $key 键名
|
||||
* @param mixed $value 值
|
||||
* @param int|null $ttl 过期时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public static function set(string $key, $value, ?int $ttl = null): bool
|
||||
{
|
||||
try {
|
||||
$storageValue = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
|
||||
|
||||
if ($ttl !== null) {
|
||||
return Redis::setex($key, $ttl, $storageValue);
|
||||
}
|
||||
return Redis::set($key, $storageValue);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis存储失败: {$e->getMessage()}", ['key' => $key]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据(自动反序列化数组)
|
||||
* @param string $key 键名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get(string $key, $default = null)
|
||||
{
|
||||
try {
|
||||
$value = Redis::get($key);
|
||||
|
||||
if ($value === false || $value === null) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
// 尝试JSON解码
|
||||
$decoded = json_decode($value, true);
|
||||
return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis读取失败: {$e->getMessage()}", ['key' => $key]);
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除键
|
||||
* @param string|array $keys 键名或键名数组
|
||||
* @return int 删除的键数量
|
||||
*/
|
||||
public static function del($keys): int
|
||||
{
|
||||
try {
|
||||
return Redis::del(...(array)$keys);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis删除失败: {$e->getMessage()}", ['keys' => $keys]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查键是否存在
|
||||
* @param string $key 键名
|
||||
* @return bool
|
||||
*/
|
||||
public static function exists(string $key): bool
|
||||
{
|
||||
try {
|
||||
return (bool)Redis::exists($key);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis检查存在失败: {$e->getMessage()}", ['key' => $key]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置带过期时间的缓存
|
||||
* @param string $key 键名
|
||||
* @param mixed $value 值
|
||||
* @param int $ttl 过期时间(秒)
|
||||
* @return bool
|
||||
*/
|
||||
public static function setex(string $key, $value, int $ttl): bool
|
||||
{
|
||||
return self::set($key, $value, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 哈希表设置字段值
|
||||
* @param string $key 键名
|
||||
* @param string $field 字段名
|
||||
* @param mixed $value 值
|
||||
* @return bool
|
||||
*/
|
||||
public static function hSet(string $key, string $field, $value): bool
|
||||
{
|
||||
try {
|
||||
$storageValue = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
|
||||
return Redis::hSet($key, $field, $storageValue);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis哈希设置失败: {$e->getMessage()}", ['key' => $key, 'field' => $field]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 哈希表获取字段值
|
||||
* @param string $key 键名
|
||||
* @param string $field 字段名
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function hGet(string $key, string $field, $default = null)
|
||||
{
|
||||
try {
|
||||
$value = Redis::hGet($key, $field);
|
||||
|
||||
if ($value === false) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$decoded = json_decode($value, true);
|
||||
return json_last_error() === JSON_ERROR_NONE ? $decoded : $value;
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis哈希获取失败: {$e->getMessage()}", ['key' => $key, 'field' => $field]);
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自增计数器
|
||||
* @param string $key 键名
|
||||
* @param int $increment 增量
|
||||
* @return int|false
|
||||
*/
|
||||
public static function incr(string $key, int $increment = 1)
|
||||
{
|
||||
try {
|
||||
return $increment === 1
|
||||
? Redis::incr($key)
|
||||
: Redis::incrBy($key, $increment);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis自增失败: {$e->getMessage()}", ['key' => $key]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取剩余过期时间
|
||||
* @param string $key 键名
|
||||
* @return int 剩余秒数(-2表示键不存在,-1表示没有设置过期时间)
|
||||
*/
|
||||
public static function ttl(string $key): int
|
||||
{
|
||||
try {
|
||||
return Redis::ttl($key);
|
||||
} catch (\Throwable $e) {
|
||||
Log::error("Redis获取TTL失败: {$e->getMessage()}", ['key' => $key]);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,4 +105,17 @@ class Util
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化创建时间
|
||||
*/
|
||||
public static function language($language,$en,$zh_CN,$ru)
|
||||
{
|
||||
if ($language == 'zh_CN'){
|
||||
return $zh_CN;
|
||||
}elseif ($language == 'ru'){
|
||||
return $ru;
|
||||
}
|
||||
return $en;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,7 +43,7 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>隐私协议</h1>
|
||||
<p><strong>生效日期:</strong>[2025-03]</p>
|
||||
<p><strong>生效日期:</strong>[2024-06]</p>
|
||||
|
||||
<h2>一、引言</h2>
|
||||
<p>欢迎使用 [领客](以下简称“本应用”)。我们非常重视您的隐私保护,并致力于通过本隐私协议(以下简称“本协议”)向您说明我们如何收集、使用、存储和保护您的个人信息。请您在使用本应用前仔细阅读并理解本协议。</p>
|
||||
@@ -92,13 +92,12 @@
|
||||
<h2>八、联系我们</h2>
|
||||
<p>如您对本协议或隐私保护有任何疑问,请联系我们:</p>
|
||||
<ul>
|
||||
<li>邮箱:[app@hnxinyouhe.com]</li>
|
||||
<li>电话:[18137110386]</li>
|
||||
<li>公司:[河南新友合科技有限公司]</li>
|
||||
<li>公司:[河南晋海科技环保有限公司]</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2025 河南新友合科技有限公司. 保留所有权利。</p>
|
||||
<p>© 2024 河南新友合科技环保有限公司. 保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -43,10 +43,10 @@
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>用户协议</h1>
|
||||
<p><strong>生效日期:</strong>[2025-03]</p>
|
||||
<p><strong>生效日期:</strong>[2024-06]</p>
|
||||
|
||||
<h2>一、总则</h2>
|
||||
<p>1. 欢迎使用 [领客](以下简称“本应用”)。本应用由 [河南新友合科技有限公司](以下简称“我们”或“本公司”)提供。</p>
|
||||
<p>1. 欢迎使用 [领客](以下简称“本应用”)。本应用由 [河南晋海科技环保有限公司](以下简称“我们”或“本公司”)提供。</p>
|
||||
<p>2. 在注册或使用本应用前,请仔细阅读本《用户协议》(以下简称“本协议”)。您一旦注册、登录或使用本应用,即表示您已充分阅读、理解并同意接受本协议的全部条款。</p>
|
||||
|
||||
<h2>二、服务内容</h2>
|
||||
@@ -90,7 +90,7 @@
|
||||
<p>2. 如因本协议产生争议,双方应友好协商解决;协商不成的,任何一方可向 管辖地 有管辖权的人民法院提起诉讼。</p>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2025 河南新友合科技有限公司. 保留所有权利。</p>
|
||||
<p>© 2024 河南新友合科技有限公司. 保留所有权利。</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
+3
-1
@@ -41,7 +41,9 @@
|
||||
"vlucas/phpdotenv": "^5.6",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"webman/cache": "^2.1",
|
||||
"workerman/crontab": "^1.0"
|
||||
"workerman/crontab": "^1.0",
|
||||
"illuminate/validation": "^11.44",
|
||||
"illuminate/container": "^11.44"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-event": "For better performance. "
|
||||
|
||||
Generated
+781
-2
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "a1bdf8bacc564776f13b4f4634c1b4c9",
|
||||
"content-hash": "611cb43c328188aa7f01631e69f47567",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aliyuncs/oss-sdk-php",
|
||||
@@ -277,6 +277,162 @@
|
||||
],
|
||||
"time": "2024-02-18T20:23:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/lexer",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/lexer.git",
|
||||
"reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd",
|
||||
"reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/coding-standard": "^12",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"psalm/plugin-phpunit": "^0.18.3",
|
||||
"vimeo/psalm": "^5.21"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Lexer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
||||
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"docblock",
|
||||
"lexer",
|
||||
"parser",
|
||||
"php"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/lexer/issues",
|
||||
"source": "https://github.com/doctrine/lexer/tree/3.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/phpdoctrine",
|
||||
"type": "patreon"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-05T11:56:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "egulias/email-validator",
|
||||
"version": "4.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/egulias/EmailValidator.git",
|
||||
"reference": "b115554301161fa21467629f1e1391c1936de517"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517",
|
||||
"reference": "b115554301161fa21467629f1e1391c1936de517",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"doctrine/lexer": "^2.0 || ^3.0",
|
||||
"php": ">=8.1",
|
||||
"symfony/polyfill-intl-idn": "^1.26"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^10.2",
|
||||
"vimeo/psalm": "^5.12"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Egulias\\EmailValidator\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eduardo Gulias Davis"
|
||||
}
|
||||
],
|
||||
"description": "A library for validating emails against several RFCs",
|
||||
"homepage": "https://github.com/egulias/EmailValidator",
|
||||
"keywords": [
|
||||
"email",
|
||||
"emailvalidation",
|
||||
"emailvalidator",
|
||||
"validation",
|
||||
"validator"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/egulias/EmailValidator/issues",
|
||||
"source": "https://github.com/egulias/EmailValidator/tree/4.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/egulias",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-27T00:36:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "firebase/php-jwt",
|
||||
"version": "v6.11.0",
|
||||
@@ -957,7 +1113,13 @@
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/container/zipball/4dcc3fcbab92e734fc0c08d9cfd97f5a1aef18ca",
|
||||
"reference": "4dcc3fcbab92e734fc0c08d9cfd97f5a1aef18ca",
|
||||
"shasum": ""
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "^11.0",
|
||||
@@ -1168,6 +1330,79 @@
|
||||
},
|
||||
"time": "2025-01-31T17:44:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/filesystem",
|
||||
"version": "v11.44.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/filesystem.git",
|
||||
"reference": "c79a54ebc61ad4e1665ca7610f276ff8a92f48f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/c79a54ebc61ad4e1665ca7610f276ff8a92f48f7",
|
||||
"reference": "c79a54ebc61ad4e1665ca7610f276ff8a92f48f7",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"illuminate/collections": "^11.0",
|
||||
"illuminate/contracts": "^11.0",
|
||||
"illuminate/macroable": "^11.0",
|
||||
"illuminate/support": "^11.0",
|
||||
"php": "^8.2",
|
||||
"symfony/finder": "^7.0.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-fileinfo": "Required to use the Filesystem class.",
|
||||
"ext-ftp": "Required to use the Flysystem FTP driver.",
|
||||
"ext-hash": "Required to use the Filesystem class.",
|
||||
"illuminate/http": "Required for handling uploaded files (^7.0).",
|
||||
"league/flysystem": "Required to use the Flysystem local driver (^3.25.1).",
|
||||
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).",
|
||||
"league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).",
|
||||
"league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).",
|
||||
"psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
|
||||
"symfony/filesystem": "Required to enable support for relative symbolic links (^7.0).",
|
||||
"symfony/mime": "Required to enable support for guessing extensions (^7.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "11.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Illuminate\\Filesystem\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Filesystem package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2025-02-19T20:17:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/macroable",
|
||||
"version": "v11.44.2",
|
||||
@@ -1443,6 +1678,130 @@
|
||||
},
|
||||
"time": "2025-02-23T14:20:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/translation",
|
||||
"version": "v11.44.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/translation.git",
|
||||
"reference": "de64584470b1d4bfc30f2c291585b873ce844ecf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/translation/zipball/de64584470b1d4bfc30f2c291585b873ce844ecf",
|
||||
"reference": "de64584470b1d4bfc30f2c291585b873ce844ecf",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"illuminate/collections": "^11.0",
|
||||
"illuminate/contracts": "^11.0",
|
||||
"illuminate/filesystem": "^11.0",
|
||||
"illuminate/macroable": "^11.0",
|
||||
"illuminate/support": "^11.0",
|
||||
"php": "^8.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "11.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Translation\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Translation package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2025-02-14T15:47:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/validation",
|
||||
"version": "v11.44.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/validation.git",
|
||||
"reference": "0abcf721a46d3c2a94f225dce82f3c00070f6121"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/validation/zipball/0abcf721a46d3c2a94f225dce82f3c00070f6121",
|
||||
"reference": "0abcf721a46d3c2a94f225dce82f3c00070f6121",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.9.3|^0.10.2|^0.11|^0.12",
|
||||
"egulias/email-validator": "^3.2.5|^4.0",
|
||||
"ext-filter": "*",
|
||||
"ext-mbstring": "*",
|
||||
"illuminate/collections": "^11.0",
|
||||
"illuminate/container": "^11.0",
|
||||
"illuminate/contracts": "^11.0",
|
||||
"illuminate/macroable": "^11.0",
|
||||
"illuminate/support": "^11.0",
|
||||
"illuminate/translation": "^11.0",
|
||||
"php": "^8.2",
|
||||
"symfony/http-foundation": "^7.0",
|
||||
"symfony/mime": "^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/database": "Required to use the database presence verifier (^11.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "11.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Validation\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Validation package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2025-03-11T08:51:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/serializable-closure",
|
||||
"version": "v2.0.3",
|
||||
@@ -2953,6 +3312,250 @@
|
||||
],
|
||||
"time": "2024-09-25T14:20:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/6de263e5868b9a137602dd1e33e4d48bfae99c49",
|
||||
"reference": "6de263e5868b9a137602dd1e33e4d48bfae99c49",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/filesystem": "^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Finder\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-23T06:56:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/62d1a43796ca3fea3f83a8470dfe63a4af3bc588",
|
||||
"reference": "62d1a43796ca3fea3f83a8470dfe63a4af3bc588",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/deprecation-contracts": "^2.5|^3.0",
|
||||
"symfony/polyfill-mbstring": "~1.1",
|
||||
"symfony/polyfill-php83": "^1.27"
|
||||
},
|
||||
"conflict": {
|
||||
"doctrine/dbal": "<3.6",
|
||||
"symfony/cache": "<6.4.12|>=7.0,<7.1.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/dbal": "^3.6|^4",
|
||||
"predis/predis": "^1.1|^2.0",
|
||||
"symfony/cache": "^6.4.12|^7.1.5",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/expression-language": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0",
|
||||
"symfony/mime": "^6.4|^7.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\HttpFoundation\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.2.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-30T19:00:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
"version": "v7.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/mime.git",
|
||||
"reference": "2fc3b4bd67e4747e45195bc4c98bea4628476204"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/mime/zipball/2fc3b4bd67e4747e45195bc4c98bea4628476204",
|
||||
"reference": "2fc3b4bd67e4747e45195bc4c98bea4628476204",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/polyfill-intl-idn": "^1.10",
|
||||
"symfony/polyfill-mbstring": "^1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"egulias/email-validator": "~3.0.0",
|
||||
"phpdocumentor/reflection-docblock": "<3.2.2",
|
||||
"phpdocumentor/type-resolver": "<1.4.0",
|
||||
"symfony/mailer": "<6.4",
|
||||
"symfony/serializer": "<6.4.3|>7.0,<7.0.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"egulias/email-validator": "^2.1.10|^3.1|^4",
|
||||
"league/html-to-markdown": "^5.0",
|
||||
"phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/process": "^6.4|^7.0",
|
||||
"symfony/property-access": "^6.4|^7.0",
|
||||
"symfony/property-info": "^6.4|^7.0",
|
||||
"symfony/serializer": "^6.4.3|^7.0.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Mime\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Allows manipulating MIME messages",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"mime",
|
||||
"mime-type"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/mime/tree/v7.2.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-01-27T11:08:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.31.0",
|
||||
@@ -3038,6 +3641,182 @@
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-idn",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773",
|
||||
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"symfony/polyfill-intl-normalizer": "^1.10"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Idn\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Laurent Bassin",
|
||||
"email": "laurent@bassin.info"
|
||||
},
|
||||
{
|
||||
"name": "Trevor Rowbotham",
|
||||
"email": "trevor.rowbotham@pm.me"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"idn",
|
||||
"intl",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-normalizer",
|
||||
"version": "v1.31.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
|
||||
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
|
||||
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-intl": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill for intl's Normalizer class and related functions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"intl",
|
||||
"normalizer",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-09T11:45:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.31.0",
|
||||
|
||||
@@ -12,6 +12,24 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
// 初始化 Laravel 容器
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
$container = Container::getInstance();
|
||||
|
||||
// 将容器设置为 Facade 的根
|
||||
Facade::setFacadeApplication($container);
|
||||
|
||||
// 注册验证器服务(关键步骤)
|
||||
$container->singleton('validator', function () {
|
||||
return new \Illuminate\Validation\Factory(
|
||||
new \Illuminate\Translation\Translator(
|
||||
new \Illuminate\Translation\ArrayLoader(), 'en' // 默认语言
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
return [
|
||||
support\bootstrap\Session::class,
|
||||
];
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'rpc_domain' => getenv('RPC_DOMAIN'),
|
||||
'event_tracking' => [
|
||||
'/follow/save',
|
||||
'/customer/claim',
|
||||
'/customer/save',
|
||||
'/customer/collect',
|
||||
'/user/login',
|
||||
],
|
||||
'web_domain' => getenv('WEB_DOMAIN'),
|
||||
'daily_group_2' => [
|
||||
'master' => 28, //组长
|
||||
'member' => [22, 23, 28, 34, 44, 46, 77, 87] //组员
|
||||
],
|
||||
];
|
||||
@@ -19,6 +19,22 @@ class Constants
|
||||
self::CUSTOMER_GRADE_SALES => '售后阶段',
|
||||
self::CUSTOMER_GRADE_LOSS => '停滞或流失',
|
||||
];
|
||||
public const GRADE_EN = [
|
||||
self::CUSTOMER_GRADE_INITIAL => 'Initial contact',
|
||||
self::CUSTOMER_GRADE_COMMUNICATE => 'Demand Chat',
|
||||
self::CUSTOMER_GRADE_PLAN => 'promotion of the plan',
|
||||
self::CUSTOMER_GRADE_DEAL => 'Transaction Stage',
|
||||
self::CUSTOMER_GRADE_SALES => 'After Sales',
|
||||
self::CUSTOMER_GRADE_LOSS => 'Stagnation or loss',
|
||||
];
|
||||
public const GRADE_RU = [
|
||||
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; // 金牌商机
|
||||
@@ -30,6 +46,17 @@ class Constants
|
||||
self::CUSTOMER_MAGNITUDE_COMMUNICATE => '银牌商机',
|
||||
self::CUSTOMER_MAGNITUDE_PLAN => '铜牌商机',
|
||||
];
|
||||
public const MAGNITUDE_EN = [
|
||||
self::CUSTOMER_MAGNITUDE_INITIAL => 'Gold Medal',
|
||||
self::CUSTOMER_MAGNITUDE_COMMUNICATE => 'Silver Medal',
|
||||
self::CUSTOMER_MAGNITUDE_PLAN => 'Bronze Medal',
|
||||
];
|
||||
|
||||
public const MAGNITUDE_RU = [
|
||||
self::CUSTOMER_MAGNITUDE_INITIAL => 'Золотой бизнес',
|
||||
self::CUSTOMER_MAGNITUDE_COMMUNICATE => 'Серебряный бизнес',
|
||||
self::CUSTOMER_MAGNITUDE_PLAN => 'Бронзовый бизнес.',
|
||||
];
|
||||
|
||||
|
||||
//跟进类型
|
||||
@@ -40,6 +67,10 @@ class Constants
|
||||
self::CUSTOMER_FOLLOW_VISIT => '线下拜访',
|
||||
self::CUSTOMER_FOLLOW_UP => '线上跟进',
|
||||
];
|
||||
public const FOLLOW_EN = [
|
||||
self::CUSTOMER_FOLLOW_VISIT => 'Visit',
|
||||
self::CUSTOMER_FOLLOW_UP => 'On line',
|
||||
];
|
||||
|
||||
//跟进类型
|
||||
public const CUSTOMER_SEX_UNKNOWN = 0; // 未知
|
||||
@@ -51,4 +82,22 @@ class Constants
|
||||
self::CUSTOMER_SEX_MAN => '男',
|
||||
self::CUSTOMER_SEX_WOMAN => '女',
|
||||
];
|
||||
public const SEX_EN = [
|
||||
self::CUSTOMER_SEX_UNKNOWN => 'unknown',
|
||||
self::CUSTOMER_SEX_MAN => 'man',
|
||||
self::CUSTOMER_SEX_WOMAN => 'woman',
|
||||
];
|
||||
|
||||
public const SEX_RU = [
|
||||
self::CUSTOMER_SEX_UNKNOWN => 'неизвестный',
|
||||
self::CUSTOMER_SEX_MAN => 'мужской',
|
||||
self::CUSTOMER_SEX_WOMAN => 'женский',
|
||||
];
|
||||
|
||||
public const SIGN = [
|
||||
['id' => 'xinyouhe', 'name' => '新友合'],
|
||||
['id' => 'mbaf', 'name' => 'MAGIC BRIDGE AUTO FZE']
|
||||
];
|
||||
|
||||
public const LANGUAGE = ['en', 'zh_CN','ru'];
|
||||
}
|
||||
+2
-2
@@ -13,8 +13,8 @@ return [
|
||||
'username' => getenv('DB_USER'),
|
||||
'password' => getenv('DB_PASSWORD'),
|
||||
'unix_socket' => '',
|
||||
'charset' => 'utf8',
|
||||
'collation' => 'utf8_unicode_ci',
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'prefix' => '',
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ return [
|
||||
'xinyouhe' => [
|
||||
'appId' => "cli_a73e1e6406fa501c",
|
||||
'appSecret' => "9cMfxujjGG9JPmNfNcOwUdCoIXqaM1wY",
|
||||
'rUrl' => "http://219.157.255.213:25321/feishu/auth",
|
||||
'rUrl' => "http://219.157.255.213:8085/pages/index/webview",
|
||||
'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
|
||||
'state' => "xinyouhe",
|
||||
'baseUri' => "https://open.feishu.cn/open-apis/"
|
||||
@@ -12,7 +12,7 @@ return [
|
||||
'mbaf' => [
|
||||
'appId' => "cli_a75839fb4ff85028",
|
||||
'appSecret' => "VsqLvwsRzpmisBVbrTIuKdNCvRCO447d",
|
||||
'rUrl' => "http://219.157.255.213:25321/feishu/auth",
|
||||
'rUrl' => "http://219.157.255.213:8085/pages/index/webview",
|
||||
'scope' => "contact:user.base:readonly contact:contact.base:readonly contact:user.employee_id:readonly im:message:send_as_bot",
|
||||
'state' => "mbaf",
|
||||
'baseUri' => "https://open.larksuite.com/open-apis/"
|
||||
|
||||
@@ -17,5 +17,13 @@ return [
|
||||
'' => [
|
||||
app\middleware\CrossDomain::class, // 全局跨域中间件
|
||||
app\middleware\AuthMiddleware::class, // 鉴权中间件
|
||||
app\middleware\DataTracker::class, //埋点
|
||||
app\admin\middleware\PermissionCheck::class, // 后端权限
|
||||
],
|
||||
|
||||
// 路由中间件
|
||||
'route' => [
|
||||
'track' => app\middleware\DataTracker::class,
|
||||
]
|
||||
|
||||
];
|
||||
+2
-2
@@ -22,7 +22,7 @@ return [
|
||||
'webman' => [
|
||||
'handler' => Http::class,
|
||||
'listen' => getenv('WEBMAN_LISTEN'),
|
||||
'count' => cpu_count() * 4,
|
||||
'count' => getenv('WEBMAN_COUNT'),
|
||||
'user' => '',
|
||||
'group' => '',
|
||||
'reusePort' => false,
|
||||
@@ -60,6 +60,6 @@ return [
|
||||
]
|
||||
],
|
||||
'task' => [
|
||||
'handler' => process\Task::class
|
||||
'handler' => app\process\Task::class
|
||||
],
|
||||
];
|
||||
|
||||
@@ -6,10 +6,13 @@ return [
|
||||
'login_success' => ' login success',
|
||||
'password_error' => ' password error',
|
||||
'user_none' => ' user none',
|
||||
'user_id' => ' user ID',
|
||||
'user_login' => ' Please log in first',
|
||||
'not_null' => ' not null',
|
||||
'code_error' => ' code error',
|
||||
'format_error' => ' format error',
|
||||
'email_repeat' => ' email repeat',
|
||||
'email_error' => ' Email format error',
|
||||
'save_success' => ' save success',
|
||||
'save_fail' => ' save fail',
|
||||
'register_success' => ' register success',
|
||||
@@ -19,8 +22,15 @@ return [
|
||||
'param_error' => ' param error',
|
||||
'required_not_null' => ' required not_ ull',
|
||||
'picture_not_null' => ' picture not null',
|
||||
'follow_not_null' => ' The image and follow-up content cannot be empty at the same time',
|
||||
'contacts_not_null' => ' Contact person, email, and phone cannot be empty at the same time',
|
||||
'car_type_not_null' => ' preference_not_null',
|
||||
'channel_not_null' => ' channel not null',
|
||||
'email_consistent' => ' Inconsistent email addresses',
|
||||
'sign_not_null' => ' No affiliated company has been set',
|
||||
'password_short' => ' Password cannot be less than 6 characters',
|
||||
'id_empty' => ' ID cannot be empty',
|
||||
'customer_id' => ' customer ID',
|
||||
'tag_group_id' => ' tag group ID',
|
||||
'claim_fail' => ' Cannot claim ownership of customers',
|
||||
];
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'success' => ' Успех',
|
||||
'fail' => ' Неудача',
|
||||
'login_success' => ' Регистрация завершена',
|
||||
'password_error' => ' Ошибка пароля',
|
||||
'user_none' => ' Пользователь не существует',
|
||||
'user_id' => ' Идентификатор пользователя',
|
||||
'user_login' => ' Пожалуйста, войдите.',
|
||||
'not_null' => ' Нельзя быть пустым',
|
||||
'code_error' => ' Ошибка кода проверки',
|
||||
'format_error' => ' Ошибка формата',
|
||||
'email_repeat' => ' Почтовый ящик повторяется',
|
||||
'email_error' => ' Ошибка формата почтового ящика',
|
||||
'save_success' => ' Сохранить успешно',
|
||||
'save_fail' => ' Ошибка сохранения',
|
||||
'register_success' => ' Регистрация успешно',
|
||||
'register_fail' => ' Ошибка регистрации',
|
||||
'language_success' => ' Переключить язык успешно',
|
||||
'language_fail' => ' Ошибка переключения языка',
|
||||
'param_error' => ' Ошибка параметра',
|
||||
'required_not_null' => ' Обязательное заполнение не может быть пустым.',
|
||||
'picture_not_null' => ' Фотографии не могут быть пустыми',
|
||||
'follow_not_null' => ' Изображение и последующий контент не могут быть пустыми одновременно.X',
|
||||
'contacts_not_null' => ' Контакты, почтовый ящик, телефон не может быть одновременно пустым',
|
||||
'car_type_not_null' => ' Предпочтения не могут быть пустыми',
|
||||
'channel_not_null' => ' Каналы не могут быть пустыми',
|
||||
'email_consistent' => ' Почтовый ящик не совпадает',
|
||||
'sign_not_null' => ' Компания не создана',
|
||||
'password_short' => ' Пароль не может быть меньше 6.',
|
||||
'id_empty' => ' ID не может быть пустым',
|
||||
'customer_id' => ' Идентификатор клиента',
|
||||
'tag_group_id' => ' Идентификатор группы меток',
|
||||
'claim_fail' => ' Невозможность получения принадлежащего клиенту',
|
||||
];
|
||||
@@ -6,10 +6,13 @@ return [
|
||||
'login_success' => ' 登录成功',
|
||||
'password_error' => ' 密码错误',
|
||||
'user_none' => ' 用户不存在',
|
||||
'user_id' => ' 用户ID',
|
||||
'user_login' => ' 请先登录',
|
||||
'not_null' => ' 不能为空',
|
||||
'code_error' => ' 验证码错误',
|
||||
'format_error' => ' 格式错误',
|
||||
'email_repeat' => ' 邮箱重复',
|
||||
'email_error' => ' 邮箱格式错误',
|
||||
'save_success' => ' 保存成功',
|
||||
'save_fail' => ' 保存失败',
|
||||
'register_success' => ' 注册成功',
|
||||
@@ -19,8 +22,15 @@ return [
|
||||
'param_error' => ' 参数错误',
|
||||
'required_not_null' => ' 必填项不能为空',
|
||||
'picture_not_null' => ' 图片不能为空',
|
||||
'follow_not_null' => ' 图片与跟进内容不能同时为空',
|
||||
'contacts_not_null' => ' 联系人,邮箱,电话不能同时为空',
|
||||
'car_type_not_null' => ' 偏好不能为空',
|
||||
'channel_not_null' => ' 渠道不能为空',
|
||||
'email_consistent' => ' 邮箱不一致',
|
||||
'sign_not_null' => ' 未设置所属公司',
|
||||
'password_short' => ' 密码不能少于6位',
|
||||
'id_empty' => ' id不能为空',
|
||||
'customer_id' => ' 客户ID',
|
||||
'tag_group_id' => ' 标签组ID',
|
||||
'claim_fail' => ' 不能领取有归属客户',
|
||||
];
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user