From f19efd85b060f011e3f61f9dc9aca43a119f3b23 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Wed, 9 Jul 2025 15:10:14 +0800 Subject: [PATCH 01/25] 1 --- app/crm/controller/BaseController.php | 51 ++++++++ app/crm/controller/CarTypeController.php | 34 ++++++ app/crm/controller/CustomerController.php | 49 ++++++++ app/crm/controller/FollowController.php | 127 ++++++++++++++++++++ app/crm/controller/TagGroupController.php | 67 +++++++++++ app/crm/logic/CustomerLogic.php | 8 ++ app/crm/logic/FollowLogic.php | 8 ++ app/crm/model/CarType.php | 36 ++++++ app/crm/model/Channel.php | 48 ++++++++ app/crm/model/Country.php | 41 +++++++ app/crm/model/Customer.php | 135 ++++++++++++++++++++++ app/crm/model/CustomerHis.php | 68 +++++++++++ app/crm/model/CustomerTag.php | 36 ++++++ app/crm/model/Follow.php | 61 ++++++++++ app/crm/model/Tag.php | 55 +++++++++ app/crm/model/TagGroup.php | 50 ++++++++ app/crm/service/CustomerService.php | 27 +++++ app/crm/service/FollowService.php | 53 +++++++++ app/crm/utils/Util.php | 121 +++++++++++++++++++ app/crm/validate/FollowValidate.php | 21 ++++ config/constants/Constants.php | 100 ++++++++++++++++ 21 files changed, 1196 insertions(+) create mode 100644 app/crm/controller/BaseController.php create mode 100644 app/crm/controller/CarTypeController.php create mode 100644 app/crm/controller/CustomerController.php create mode 100644 app/crm/controller/FollowController.php create mode 100644 app/crm/controller/TagGroupController.php create mode 100644 app/crm/logic/CustomerLogic.php create mode 100644 app/crm/logic/FollowLogic.php create mode 100644 app/crm/model/CarType.php create mode 100644 app/crm/model/Channel.php create mode 100644 app/crm/model/Country.php create mode 100644 app/crm/model/Customer.php create mode 100644 app/crm/model/CustomerHis.php create mode 100644 app/crm/model/CustomerTag.php create mode 100644 app/crm/model/Follow.php create mode 100644 app/crm/model/Tag.php create mode 100644 app/crm/model/TagGroup.php create mode 100644 app/crm/service/CustomerService.php create mode 100644 app/crm/service/FollowService.php create mode 100644 app/crm/utils/Util.php create mode 100644 app/crm/validate/FollowValidate.php diff --git a/app/crm/controller/BaseController.php b/app/crm/controller/BaseController.php new file mode 100644 index 0000000..1b824e0 --- /dev/null +++ b/app/crm/controller/BaseController.php @@ -0,0 +1,51 @@ +scene($scene); + } + // 执行数据验证 + if (!$validator->check($data)) { + // 验证失败,抛出业务异常,异常信息为验证器返回的错误信息 + throw new BusinessException($validator->getError()); + } + // 验证成功,返回原始数据 + return $data; + } + + public function page($result){ + $current = $result->currentPage(); + $total = $result->total(); + $size = $result->perPage(); + $result = $result->toArray(); + $result['current'] = $current; + $result['total'] = $total; + $result['size'] = $size; + return $result; + } +} \ No newline at end of file diff --git a/app/crm/controller/CarTypeController.php b/app/crm/controller/CarTypeController.php new file mode 100644 index 0000000..6156876 --- /dev/null +++ b/app/crm/controller/CarTypeController.php @@ -0,0 +1,34 @@ +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 $this->success($list); + } + +} \ No newline at end of file diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php new file mode 100644 index 0000000..9844dc3 --- /dev/null +++ b/app/crm/controller/CustomerController.php @@ -0,0 +1,49 @@ +list($request->all()); + return $this->success($this->page($result)); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + public function follow(Request $request) + { +// try { +// $result = (new CustomerService())->follow($request->all()); +// return $this->success($this->page($result)); +// } catch (\Throwable $e) { +// return $this->error($e->getMessage()); +// } + $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 $this->success($user); + } +} \ No newline at end of file diff --git a/app/crm/controller/FollowController.php b/app/crm/controller/FollowController.php new file mode 100644 index 0000000..7f08e7d --- /dev/null +++ b/app/crm/controller/FollowController.php @@ -0,0 +1,127 @@ + $value) { + $grade[] = [ + 'status' => $key, + 'text' => $value, + ]; + } + return $this->success($grade); + } + + + /** + * 跟进列表 + * @param Request $request + * @return \support\Response + */ + public function list(Request $request) + { + try { + $data = $this->validate(new FollowValidate(), $request->get(), 'upwd_list'); + $result = (new FollowService())->list($request->all()); + return $this->success($this->page($result)); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + /** + * 跟进详情 + * @param Request $request + * @return \support\Response + */ + public function detail(Request $request) + { + //跟进id + $id = Util::getParam($request,'id'); + if(Util::isEmpty($id)){ + return $this->error('id'.trans('not_null')); + } + + $res = Follow::select('id','user_id','customer_id','type','picture','remark','audio','audio_text','lat','lng','address') + ->where('id',$id) + ->first(); + if($res){ + $res->toArray(); + }else{ + return $this->error('记录不存在'); + } + + $res = Follow::getFollow($res); + + return $this->success($res); + } + + /** + * 客户录入 + * @param Request $request + * @return \support\Response + */ + public function save(Request $request) + { + $customer_id = Util::getParam($request,'customer_id'); + + if(Util::isEmpty($customer_id)){ + return $this->error('customer_id'.trans('not_null')); + } + $type = Util::getParam($request,'type'); + if(Util::isEmpty($type)){ + return $this->error('type'.trans('not_null')); + } + $picture = Util::getParam($request,'picture'); + if(Util::isEmpty($picture)){ + return $this->error(trans('picture_not_null')); + } + + $data = [ + 'user_id'=>$request->user['id'], + 'customer_id'=>$customer_id, + 'type'=>$type, + 'picture'=>$picture, + 'remark'=>Util::getParam($request,'remark',''), + 'audio'=>Util::getParam($request,'audio',''), + 'audio_text'=>Util::getParam($request,'audio_text',''), + 'lat'=>Util::getParam($request,'lat',0), + 'lng'=>Util::getParam($request,'lng',0), + 'address'=>Util::getParam($request,'address'), + 'follow_time'=>strtotime(Util::getParam($request,'firstFollowtime',0)), + ]; + + $res = Follow::create($data); + + $customer = Customer::find($customer_id); + $customer->follow_last = strtotime($res->created_at); + $customer->follow_next = null; + $customer->warn = 0; + $customer->save(); + + if ($res) { + return $this->success($res,trans('save_success')); + } else { + return $this->error(trans('save_fail')); + } + } + +} \ No newline at end of file diff --git a/app/crm/controller/TagGroupController.php b/app/crm/controller/TagGroupController.php new file mode 100644 index 0000000..7e5dff1 --- /dev/null +++ b/app/crm/controller/TagGroupController.php @@ -0,0 +1,67 @@ +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 $this->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 $this->error( trans('customer_id') . trans('not_null')); + } + if (Util::isEmpty($groupId)) { + return $this->error( 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 $this->success($res, trans('success')); + }else{ + return $this->error( trans('fail')); + } + } +} \ No newline at end of file diff --git a/app/crm/logic/CustomerLogic.php b/app/crm/logic/CustomerLogic.php new file mode 100644 index 0000000..0e6b1a0 --- /dev/null +++ b/app/crm/logic/CustomerLogic.php @@ -0,0 +1,8 @@ +select('id','name','name_en','status')->where('status',0)->toArray(); + return $list; + } +} \ No newline at end of file diff --git a/app/crm/model/Channel.php b/app/crm/model/Channel.php new file mode 100644 index 0000000..59f9237 --- /dev/null +++ b/app/crm/model/Channel.php @@ -0,0 +1,48 @@ + 'datetime:Y-m-d H:i:s', // 指定序列化格式 +// 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式 + 'updated_at' => 'timestamp', // 指定序列化格式 + 'created_at' => 'timestamp', // 指定序列化格式 + ]; + + public static function getAll() + { + $list = self::get()->select('id','name','name_en','status')->where('status',0)->toArray(); + return $list; + } +} \ No newline at end of file diff --git a/app/crm/model/Country.php b/app/crm/model/Country.php new file mode 100644 index 0000000..29ba895 --- /dev/null +++ b/app/crm/model/Country.php @@ -0,0 +1,41 @@ +select('id','cn_addr','en_addr')->get()->toArray(); + return $list; + } +} \ No newline at end of file diff --git a/app/crm/model/Customer.php b/app/crm/model/Customer.php new file mode 100644 index 0000000..7db2f1e --- /dev/null +++ b/app/crm/model/Customer.php @@ -0,0 +1,135 @@ + '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()); + } + + /** + * @param $customer + * @param $request + * @param $tag 是否返回客户标签 + * @return mixed + */ + public static function getCustomer($customer, $request, $tag = false) + { + $language = $request->user['language'] ?: 'en'; + $customer['grade_txt'] = Util::language($language, Constants::GRADE_EN[$customer['grade']], Constants::GRADE_ZH[$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'] = Util::language($language,'Following','跟进中','Продолжение'); + }elseif ($customer['grade']<5) { + $customer['follow'] = 1; + $customer['follow_txt'] = Util::language($language,'transacted','已成交','Транзакция завершена'); + }else{ + $customer['follow'] = 2; + $customer['follow_txt'] = Util::language($language,'lost','已流失','Потерянный'); + } + + $where = [ + 'customer_id' => $customer['id'] + ]; + $begin_follow = Follow::select('id','created_at','updated_at') + ->where($where) + ->min('created_at'); + + + $customer['begin_follow'] = Util::timeTotDate($begin_follow); +// $customer['created_at'] = Util::timeTotDate($customer['created_at']); +// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']); + + $customer = Util::formatDate($customer,['follow_last']); + $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'); + } +} \ No newline at end of file diff --git a/app/crm/model/CustomerHis.php b/app/crm/model/CustomerHis.php new file mode 100644 index 0000000..b7039dd --- /dev/null +++ b/app/crm/model/CustomerHis.php @@ -0,0 +1,68 @@ + '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; // 不做任何操作 + } +} \ No newline at end of file diff --git a/app/crm/model/CustomerTag.php b/app/crm/model/CustomerTag.php new file mode 100644 index 0000000..b6a26bf --- /dev/null +++ b/app/crm/model/CustomerTag.php @@ -0,0 +1,36 @@ + 'datetime:Y-m-d H:i:s', // 指定序列化格式 + 'created_at' => 'datetime:Y-m-d H:i:s', // 指定序列化格式 + 'follow_time' => 'datetime:Y-m-d H:i:s', // 指定序列化格式 +// 'updated_at' => 'timestamp', // 指定序列化格式 +// 'created_at' => 'timestamp', // 指定序列化格式 + ]; + + 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']; + $ossservice = new OssService(); + $oss_picture = $ossservice->generatePrivateUrl($follow['picture'],86400); + $follow['oss_picture'] = $oss_picture; +// $follow = Util::formatDate($follow); + return $follow; + } +} \ No newline at end of file diff --git a/app/crm/model/Tag.php b/app/crm/model/Tag.php new file mode 100644 index 0000000..4b00471 --- /dev/null +++ b/app/crm/model/Tag.php @@ -0,0 +1,55 @@ +belongsTo(TagGroup::class, 'group_id', 'id'); + } + + public function customers() + { + return $this->belongsToMany(Customer::class, 'customer_tag', 'tag_id', 'customer_id'); + } +} \ No newline at end of file diff --git a/app/crm/model/TagGroup.php b/app/crm/model/TagGroup.php new file mode 100644 index 0000000..9c2e419 --- /dev/null +++ b/app/crm/model/TagGroup.php @@ -0,0 +1,50 @@ +hasMany(Tag::class, 'group_id', 'id'); + } +} \ No newline at end of file diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php new file mode 100644 index 0000000..d21d460 --- /dev/null +++ b/app/crm/service/CustomerService.php @@ -0,0 +1,27 @@ +input('page', 1); +// $perPage = $request->input('per_page', 10); + $perPage = $params['size'] ?? 10; + $page = $params['current'] ?? 1; + $where = []; + $user_id =$params['user_id']; + if(empty($user_id) || $user_id == 0){ + $where[] = ['user_id', '=', $user_id]; + } + $user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page); + $user = $user->toArray(); + foreach ($user['data'] as &$item) { + unset($item['password']); + } + return $user; + } +} \ No newline at end of file diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php new file mode 100644 index 0000000..b870416 --- /dev/null +++ b/app/crm/service/FollowService.php @@ -0,0 +1,53 @@ +input('page', 1); +// $perPage = $request->input('per_page', 10); + + //客户id + $customer_id =$param['customer_id']; + + $where = []; + $where['customer_id'] = $customer_id; + + //用户角色 + $userId = $request->user['id']; + if(Util::isEmpty($userId)){ + return $this->error(trans('user_none')); + } + if($request->user['role']!=1){ + $where['user_id'] = $userId; + } + + //跟进id + $id = Util::getParam($request,'id'); + if(!Util::isEmpty($id)){ + $where['id'] = $id; + } + + // 执行分页查询 + $data = Follow::where($where) + ->orderBy('id', 'desc')->get(); +// ->paginate($perPage, ['*'], 'page', $page); + + +// $host = $request->host(); + $url = 'http:'.$request->url(); + foreach ($data as &$value){ + $value = Follow::getFollow($value); + } + + return $this->success($data,trans('success')); + } +} \ No newline at end of file diff --git a/app/crm/utils/Util.php b/app/crm/utils/Util.php new file mode 100644 index 0000000..db6743b --- /dev/null +++ b/app/crm/utils/Util.php @@ -0,0 +1,121 @@ +input($param,$default); + if(empty($param) && $default!==''){ + $param = $default; + } + return $param; + } + + /** + * 失败 + */ + public static function fail($data = [],$message = '', $code = -1) + { + $result = [ + 'code' => $code, + 'message' => $message, + 'data' => $data + ]; + return json($result); + } + + /** + * 成功 + */ + public static function success($data = [],$message = '', $code = 0) + { + $result = [ + 'code' => $code, + 'message' => $message, + 'data' => $data + ]; + return json($result); + } + + /** + * 分页查询返回 + */ + public static function page($data,$message = '', $code = 0) + { + $result = [ + 'code' => $code, + 'message' => $message + ]; + + $result['data'] = [ + 'list' => $data->items(), // 当前页数据 + 'total' => $data->total(), // 总记录数 + 'current_page' => $data->currentPage(), + 'per_page' => $data->perPage(), + 'last_page' => $data->lastPage() + ]; + return json($result); + } + + /** + * 日期格式转化 + */ + public static function timeTotDate($time = 0, $format = 'Y-m-d H:i:s') + { + if (empty($time)) { + return ''; + } + return date($format, $time); + } + + /** + * 格式化创建时间 + */ + public static function formatDate($value,$key = ['created_at','updated_at']) + { + foreach ($key as $k){ + $value[$k]= self::timeTotDate($value[$k]); + } + 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; + } + +} \ No newline at end of file diff --git a/app/crm/validate/FollowValidate.php b/app/crm/validate/FollowValidate.php new file mode 100644 index 0000000..2ed6e71 --- /dev/null +++ b/app/crm/validate/FollowValidate.php @@ -0,0 +1,21 @@ + 'require', + ]; + + protected $message = [ + 'customer_id.require' => '用户id不能为空', + ]; + + protected $scene = [ + 'upwd_list' => ['customer_id'], + ]; +} \ No newline at end of file diff --git a/config/constants/Constants.php b/config/constants/Constants.php index 1e77a2b..6797078 100644 --- a/config/constants/Constants.php +++ b/config/constants/Constants.php @@ -34,4 +34,104 @@ class Constants self::TICKET_STATUS['REJECTED'] => 'Закрыть', ]; + //客户分级 USTOMER_GRADE + + public const GRADE = [ + 'INITIAL' => 0, // 初步接触 + 'COMMUNICATE' => 1, // 需求沟通 + 'PLAN' => 2, // 方案推进 + 'DEAL' => 3, // 成交阶段 + 'SALES' => 4, // 售后阶段 + 'LOSS' => 5, // 停滞或流失 + ]; + + public const GRADE_ZH = [ + self::GRADE['INITIAL'] => '初步接触', + self::GRADE['COMMUNICATE'] => '需求沟通', + self::GRADE['PLAN'] => '方案推进', + self::GRADE['DEAL'] => '成交阶段', + self::GRADE['SALES'] => '售后阶段', + self::GRADE['LOSS'] => '停滞或流失', + ]; + public const GRADE_EN = [ + self::GRADE['INITIAL'] => 'Initial contact', + self::GRADE['COMMUNICATE'] => 'Demand Chat', + self::GRADE['PLAN'] => 'promotion of the plan', + self::GRADE['DEAL'] => 'Transaction Stage', + self::GRADE['SALES'] => 'After Sales', + self::GRADE['LOSS'] => 'Stagnation or loss', + ]; + public const GRADE_RU = [ + self::GRADE['INITIAL'] => 'Первоначальные контакты', + self::GRADE['COMMUNICATE'] => 'Потребности в общении', + self::GRADE['PLAN'] => 'Продвижение программы', + self::GRADE['DEAL'] => 'Этап сделки', + self::GRADE['SALES'] => 'Послепродажный этап', + self::GRADE['LOSS'] => 'Застой или потеря', + ]; + + //客户重要性 + public const CUSTOMER_MAGNITUDE_INITIAL = 0; // 金牌商机 + public const CUSTOMER_MAGNITUDE_COMMUNICATE = 1; // 银牌商机 + public const CUSTOMER_MAGNITUDE_PLAN = 2; // 铜牌商机 + + public const MAGNITUDE = [ + self::CUSTOMER_MAGNITUDE_INITIAL => '金牌商机', + self::CUSTOMER_MAGNITUDE_COMMUNICATE => '银牌商机', + self::CUSTOMER_MAGNITUDE_PLAN => '铜牌商机', + ]; + public const 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 => 'Бронзовый бизнес.', + ]; + + + //跟进类型 + public const CUSTOMER_FOLLOW_VISIT = 0; // 线下拜访 + public const CUSTOMER_FOLLOW_UP = 1; // 线上跟进 + + public const FOLLOW = [ + 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; // 未知 + public const CUSTOMER_SEX_MAN = 1; // 男 + public const CUSTOMER_SEX_WOMAN = 2; // 女 + + public const SEX = [ + self::CUSTOMER_SEX_UNKNOWN => '未知', + 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']; } \ No newline at end of file From a45d586f07d58ee9f04c2605523e540962838947 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 10 Jul 2025 14:27:56 +0800 Subject: [PATCH 02/25] crm --- app/crm/controller/FollowController.php | 22 ++++++++++++---- app/crm/model/Customer.php | 2 +- app/crm/model/CustomerHis.php | 2 +- app/crm/model/Follow.php | 13 +-------- app/crm/model/Tag.php | 2 +- app/crm/model/TagGroup.php | 2 +- app/crm/service/FollowService.php | 35 ++++++++++++++++--------- app/crm/validate/FollowValidate.php | 2 +- config/route.php | 9 +++++++ resource/translations/ar/messages.php | 31 ++++++++++++++++++++++ resource/translations/en/messages.php | 31 ++++++++++++++++++++++ resource/translations/ru/messages.php | 31 ++++++++++++++++++++++ resource/translations/zh/messages.php | 31 ++++++++++++++++++++++ 13 files changed, 179 insertions(+), 34 deletions(-) diff --git a/app/crm/controller/FollowController.php b/app/crm/controller/FollowController.php index 7f08e7d..7ee34a4 100644 --- a/app/crm/controller/FollowController.php +++ b/app/crm/controller/FollowController.php @@ -39,9 +39,9 @@ class FollowController extends BaseController public function list(Request $request) { try { - $data = $this->validate(new FollowValidate(), $request->get(), 'upwd_list'); - $result = (new FollowService())->list($request->all()); - return $this->success($this->page($result)); + $data = $this->validate(new FollowValidate(), $request->get(), 'list'); + $result = (new FollowService())->list($request->all(),$request->user->uid); + return $this->success($result); } catch (\Throwable $e) { return $this->error($e->getMessage()); } @@ -69,7 +69,7 @@ class FollowController extends BaseController return $this->error('记录不存在'); } - $res = Follow::getFollow($res); + $res = FollowService::getFollow($res); return $this->success($res); } @@ -96,7 +96,7 @@ class FollowController extends BaseController } $data = [ - 'user_id'=>$request->user['id'], + 'user_id'=>$request->user->uid, 'customer_id'=>$customer_id, 'type'=>$type, 'picture'=>$picture, @@ -117,6 +117,18 @@ class FollowController extends BaseController $customer->warn = 0; $customer->save(); + $follow_next = Util::getParam($request, 'follow_next', 0); + $follow_remark = Util::getParam($request, 'follow_remark', 0); + if($res && (!empty($follow_next))){ + $data = [ + 'follow_next' => $follow_next, + 'follow_remark' => $follow_remark, + 'warn' => 0, + ]; + $res = Customer::where('id', $customer_id) + ->update($data); + } + if ($res) { return $this->success($res,trans('save_success')); } else { diff --git a/app/crm/model/Customer.php b/app/crm/model/Customer.php index 7db2f1e..c03d4ac 100644 --- a/app/crm/model/Customer.php +++ b/app/crm/model/Customer.php @@ -17,7 +17,7 @@ class Customer extends Model * * @var string */ - protected $table = 'customer'; + protected $table = 'crm_customer'; /** * The primary key associated with the table. diff --git a/app/crm/model/CustomerHis.php b/app/crm/model/CustomerHis.php index b7039dd..65d7de6 100644 --- a/app/crm/model/CustomerHis.php +++ b/app/crm/model/CustomerHis.php @@ -17,7 +17,7 @@ class CustomerHis extends Model * * @var string */ - protected $table = 'customer_his'; + protected $table = 'crm_customer_his'; /** * The primary key associated with the table. diff --git a/app/crm/model/Follow.php b/app/crm/model/Follow.php index e44c08b..778b669 100644 --- a/app/crm/model/Follow.php +++ b/app/crm/model/Follow.php @@ -16,7 +16,7 @@ class Follow extends Model * * @var string */ - protected $table = 'follow'; + protected $table = 'crm_follow'; /** * The primary key associated with the table. @@ -47,15 +47,4 @@ class Follow extends Model // 'updated_at' => 'timestamp', // 指定序列化格式 // 'created_at' => 'timestamp', // 指定序列化格式 ]; - - 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']; - $ossservice = new OssService(); - $oss_picture = $ossservice->generatePrivateUrl($follow['picture'],86400); - $follow['oss_picture'] = $oss_picture; -// $follow = Util::formatDate($follow); - return $follow; - } } \ No newline at end of file diff --git a/app/crm/model/Tag.php b/app/crm/model/Tag.php index 4b00471..3e7ec25 100644 --- a/app/crm/model/Tag.php +++ b/app/crm/model/Tag.php @@ -17,7 +17,7 @@ class Tag extends Model * * @var string */ - protected $table = 'tag'; + protected $table = 'crm_tag'; /** * The primary key associated with the table. diff --git a/app/crm/model/TagGroup.php b/app/crm/model/TagGroup.php index 9c2e419..5b5e28e 100644 --- a/app/crm/model/TagGroup.php +++ b/app/crm/model/TagGroup.php @@ -17,7 +17,7 @@ class TagGroup extends Model * * @var string */ - protected $table = 'tag_group'; + protected $table = 'crm_tag_group'; /** * The primary key associated with the table. diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php index b870416..89b7c2b 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -2,13 +2,15 @@ namespace app\crm\service; +use app\common\service\OssService; use app\crm\model\Follow; use app\crm\utils\Util; +use config\constants\Constants; class FollowService { - public function list($param) + public function list($param, $userId) { @@ -22,16 +24,9 @@ class FollowService $where['customer_id'] = $customer_id; //用户角色 - $userId = $request->user['id']; - if(Util::isEmpty($userId)){ - return $this->error(trans('user_none')); - } - if($request->user['role']!=1){ - $where['user_id'] = $userId; - } //跟进id - $id = Util::getParam($request,'id'); + $id = $param['id']??null; if(!Util::isEmpty($id)){ $where['id'] = $id; } @@ -43,11 +38,27 @@ class FollowService // $host = $request->host(); - $url = 'http:'.$request->url(); +// $url = 'http:'.$request->url(); foreach ($data as &$value){ - $value = Follow::getFollow($value); + $value = self::getFollow($value); } - return $this->success($data,trans('success')); + return $data; + } + + + + 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']; + $oss_picture = ''; + if(!empty($follow['picture'])){ + $ossservice = new OssService(); + $oss_picture = $ossservice->generatePrivateUrl($follow['picture'],86400); + } + $follow['oss_picture'] = $oss_picture; +// $follow = Util::formatDate($follow); + return $follow; } } \ No newline at end of file diff --git a/app/crm/validate/FollowValidate.php b/app/crm/validate/FollowValidate.php index 2ed6e71..a92c4a0 100644 --- a/app/crm/validate/FollowValidate.php +++ b/app/crm/validate/FollowValidate.php @@ -16,6 +16,6 @@ class FollowValidate extends Validate ]; protected $scene = [ - 'upwd_list' => ['customer_id'], + 'list' => ['customer_id'], ]; } \ No newline at end of file diff --git a/config/route.php b/config/route.php index db2c831..0e25da4 100644 --- a/config/route.php +++ b/config/route.php @@ -65,3 +65,12 @@ Route::group('/ticket', function () { }); +//crm +Route::group('/crm', function () { + Route::any('/follow/list', [app\crm\controller\FollowController::class, 'list']); + Route::any('/follow/detail', [app\crm\controller\FollowController::class, 'detail']); + Route::any('/follow/add', [app\crm\controller\FollowController::class, 'save']); + Route::any('/follow/getFollowType', [app\crm\controller\FollowController::class, 'getFollowType']); + Route::any('/follow/getFollowType', [app\crm\controller\FollowController::class, 'getFollowType']); +}); + diff --git a/resource/translations/ar/messages.php b/resource/translations/ar/messages.php index a701f87..7430697 100644 --- a/resource/translations/ar/messages.php +++ b/resource/translations/ar/messages.php @@ -2,4 +2,35 @@ return [ 'status_not_modified' => 'الدولة لا يمكن تعديلها عكسيا', + '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' => ' لا يمكن أن تكون الصورة فارغة', + 'contacts_not_null' => ' لا يمكن أن يكون جهة الاتصال أو البريد الإلكتروني أو الهاتف فارغين جميعًا في نفس الوقت', + 'car_type_not_null' => ' لا يمكن أن تكون التفضيلات فارغة', + 'channel_not_null' => ' لا يمكن أن تكون القناة فارغة', + 'email_consistent' => ' البريد الإلكتروني غير متطابق', + 'sign_not_null' => ' لم يتم تعيين الشركة التابعة', + 'password_short' => ' لا يمكن أن تكون كلمة المرور أقل من 6 أحرف', + 'id_empty' => ' لا يمكن أن يكون المعرف فارغًا', + 'customer_id' => ' معرف العميل', + 'tag_group_id' => ' معرف مجموعة العلامات', + 'claim_fail' => ' لا يمكن استلام العملاء الذين لديهم مالك بالفعل', ]; \ No newline at end of file diff --git a/resource/translations/en/messages.php b/resource/translations/en/messages.php index c676eb2..342ffad 100644 --- a/resource/translations/en/messages.php +++ b/resource/translations/en/messages.php @@ -2,4 +2,35 @@ return [ 'status_not_modified' => 'The status cannot be reversed for modification', + 'success' => ' success', + 'fail' => ' fail', + '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', + 'register_fail' => ' register fail', + 'language_success' => ' Successfully switched languages', + 'language_fail' => ' Language switching failed', + 'param_error' => ' param error', + 'required_not_null' => ' required not_ ull', + 'picture_not_null' => ' picture not null', + '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', ]; \ No newline at end of file diff --git a/resource/translations/ru/messages.php b/resource/translations/ru/messages.php index 96ab3a4..3a1839f 100644 --- a/resource/translations/ru/messages.php +++ b/resource/translations/ru/messages.php @@ -2,4 +2,35 @@ return [ 'status_not_modified' => 'Статус не может быть изменен в обратном направлении', + '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' => ' Фотографии не могут быть пустыми', + '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' => ' Невозможность получения принадлежащего клиенту', ]; \ No newline at end of file diff --git a/resource/translations/zh/messages.php b/resource/translations/zh/messages.php index 229d7ee..96c3cb7 100644 --- a/resource/translations/zh/messages.php +++ b/resource/translations/zh/messages.php @@ -2,4 +2,35 @@ return [ 'status_not_modified' => '状态不能逆向修改', + 'success' => ' 成功', + 'fail' => ' 失败', + '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' => ' 注册成功', + 'register_fail' => ' 注册失败', + 'language_success' => ' 切换语言成功', + 'language_fail' => ' 切换语言失败', + 'param_error' => ' 参数错误', + 'required_not_null' => ' 必填项不能为空', + 'picture_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' => ' 不能领取有归属客户', ]; \ No newline at end of file From 72878f49eabec6e53e6ce15b41bd2dfa1eb92a31 Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 14 Jul 2025 10:08:29 +0800 Subject: [PATCH 03/25] Merge commit 'acd428f57bceb73ddc770cc6b59f8be7a237af90' --- app/common/model/Role.php | 2 +- app/common/model/User.php | 2 +- app/common/model/UserRoles.php | 47 ++++++++++++++++++++++++ app/common/model/UserSystems.php | 53 ++++++++++++++++++++++++++++ app/controller/IndexController.php | 39 +++++++++++++++++++- app/ticket/logic/TicketLogic.php | 4 +-- app/ticket/service/TicketService.php | 14 +++++++- config/route.php | 2 ++ config/whitelist.php | 2 ++ 9 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 app/common/model/UserRoles.php create mode 100644 app/common/model/UserSystems.php diff --git a/app/common/model/Role.php b/app/common/model/Role.php index ea84200..c9eaabd 100644 --- a/app/common/model/Role.php +++ b/app/common/model/Role.php @@ -53,6 +53,6 @@ class Role extends Model // 角色拥有的资源(权限点、菜单) public function resources() { - return $this->belongsToMany(Resource::class, 'role_resources', 'role_id', 'resource_id'); + return $this->belongsToMany(Resource::class, 'role_resources', 'role_id', 'resource_id')->orderBy('sort', 'asc'); } } diff --git a/app/common/model/User.php b/app/common/model/User.php index 4709b44..e9b4627 100644 --- a/app/common/model/User.php +++ b/app/common/model/User.php @@ -75,7 +75,7 @@ class User extends Model // 用户直接拥有的资源(用于特殊补权) public function resources() { - return $this->belongsToMany(Resource::class, 'user_resources', 'user_id', 'resource_id'); + return $this->belongsToMany(Resource::class, 'user_resources', 'user_id', 'resource_id')->orderBy('sort', 'asc'); } // 用户可访问的系统 diff --git a/app/common/model/UserRoles.php b/app/common/model/UserRoles.php new file mode 100644 index 0000000..97005ce --- /dev/null +++ b/app/common/model/UserRoles.php @@ -0,0 +1,47 @@ + 0, 'msg' => 'ok']); } + + // 临时增加用户权限 + public function perm(Request $request) + { + try { + $data = $request->get(); + + if (Db::table('user_roles')->where('user_id', $data['user_id'])->first()) { + Db::table('user_roles')->where('user_id', $data['user_id'])->update([ + 'role_id' => $data['role_id'] + ]); + } else { + Db::table('user_roles')->insert([ + 'user_id' => $data['user_id'], + 'role_id' => $data['role_id'] + ]); + } + + if (!Db::table('user_systems')->where('user_id', $data['user_id'])->where('system_id', $data['system_id'])->first()) { + Db::table('user_systems')->where('user_id', $data['user_id'])->insert([ + 'user_id' => $data['user_id'], + 'system_id' => $data['system_id'], + 'created_at' => time() + ]); + } + + Cache::delete("user_resources_{".$data['user_id']."}"); + return json(['code' => 0, 'msg' => 'success']); + } catch (\Throwable $e) { + return json(['code' => 1, 'msg' => $e->getMessage()]); + } + } } \ No newline at end of file diff --git a/app/ticket/logic/TicketLogic.php b/app/ticket/logic/TicketLogic.php index e7d098d..540e7c5 100644 --- a/app/ticket/logic/TicketLogic.php +++ b/app/ticket/logic/TicketLogic.php @@ -26,8 +26,8 @@ class TicketLogic if(!empty($params['status'])){ $where[] = ['status', '=', $params['status']]; } - $size = $params['size']; - $current = $params['current']; + $size = $params['size']??10; + $current = $params['current']??1; return Ticket::with('attachments')->with('categorie')->with('categorie.translation')->where($where)->orderBy('id','desc')->paginate($size, ['*'], 'page', $current); } diff --git a/app/ticket/service/TicketService.php b/app/ticket/service/TicketService.php index f5a0d72..6250b5f 100644 --- a/app/ticket/service/TicketService.php +++ b/app/ticket/service/TicketService.php @@ -55,8 +55,20 @@ class TicketService { try { Db::beginTransaction(); - $attachment = $data['attachment']??[]; $logic = new TicketLogic(); + $result = $logic->find($data['id']); + + if(empty($result)){ + throw new BusinessException('工单不存在'); + } + if($result['user_id'] != $data['user_id']){ + throw new BusinessException('只能编辑自己的工单'); + } + if($result['status'] != 1){ + throw new BusinessException('只能修改待受理工单'); + } + + $attachment = $data['attachment']??[]; $result = $logic->edit($data); if(!empty($attachment)){ diff --git a/config/route.php b/config/route.php index 94f8269..d970528 100644 --- a/config/route.php +++ b/config/route.php @@ -25,6 +25,8 @@ use Webman\Route; // POST /admin/user/{user_id}/kickout // body: {"tokens": ["..."]} // 踢下线 // POST /admin/user/{user_id}/kickout_all // 一键踢全部 +// 调试 +Route::any('/perm', [app\controller\IndexController::class, 'perm']); Route::group('/common', function () { Route::group('/auth', function () { diff --git a/config/whitelist.php b/config/whitelist.php index e601d30..1736876 100644 --- a/config/whitelist.php +++ b/config/whitelist.php @@ -5,6 +5,8 @@ return [ '/', // 首页 '/index/index', // 首页 '/index/view', // 飞书调试 + '/perm', // 调试-添加权限 + '/common/preset/corps', // 公司列表 '/common/preset/feishu/app', // 飞书应用信息 ] From c96d2f6478021814522e653151b217d67e10b9d8 Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 14 Jul 2025 12:00:36 +0800 Subject: [PATCH 04/25] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=B8=85=E7=90=86?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/IndexController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index 3f8485d..f9b026d 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -55,7 +55,7 @@ class IndexController ]); } - Cache::delete("user_resources_{".$data['user_id']."}"); + Cache::delete("user_resources_{$data['user_id']}"); return json(['code' => 0, 'msg' => 'success']); } catch (\Throwable $e) { return json(['code' => 1, 'msg' => $e->getMessage()]); From f915fd77a1d712be01f5e691ae962ecc3819da2f Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 14 Jul 2025 14:24:03 +0800 Subject: [PATCH 05/25] Merge commit '25e33cbbcf6d6b965148fc9da466cbfba4e9f73e' --- app/common/logic/PermLogic.php | 45 ++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index b4fe819..eca4b25 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -3,27 +3,68 @@ namespace app\common\logic; use app\common\model\User; +use app\common\model\Resource; class PermLogic { /** * 获取用户所有资源(合并角色+直接分配) */ + // public function getUserResources(int $userId) + // { + // $user = User::with(['roles.resources', 'resources'])->find($userId); + // if (!$user) { + // return collect(); + // } + + // $all = collect(); + // foreach ($user->roles as $role) { + // $all = $all->merge($role->resources); + // } + // $all = $all->merge($user->resources); + // return $all->unique('id')->values(); + // } + /** + * 获取用户所有资源(合并角色+直接分配),并加入公共菜单 + */ public function getUserResources(int $userId) { + // 获取用户及其关联角色资源和直接分配的资源 $user = User::with(['roles.resources', 'resources'])->find($userId); + if (!$user) { return collect(); } $all = collect(); + + // 合并角色资源,排除不需要权限认证的资源 foreach ($user->roles as $role) { - $all = $all->merge($role->resources); + $all = $all->merge( + $role->resources->filter(function ($resource) { + // 只保留需要权限认证的资源(或公共资源) + return !$resource->no_auth; + }) + ); } - $all = $all->merge($user->resources); + + // 合并用户直接分配的资源,排除不需要权限认证的资源 + $all = $all->merge( + $user->resources->filter(function ($resource) { + // 只保留需要权限认证的资源(或公共资源) + return !$resource->no_auth; + }) + ); + + // 加入公共菜单,公共菜单不管是否授权,所有人都能访问 + $publicResources = Resource::where('no_auth', 1)->get(); // 获取所有公共菜单 + $all = $all->merge($publicResources); + + // 返回唯一的资源列表,并按 id 排序 return $all->unique('id')->values(); } + /** * 构建目录/菜单树,节点包含权限与打开方式,拼接完整路径,并对子级菜单component处理 * @param \Illuminate\Support\Collection $resources From bf5339724a93b85ddc00ae0bcd839c2543ea8d6d Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 14 Jul 2025 18:55:59 +0800 Subject: [PATCH 06/25] Merge branch 'develop' # Conflicts: # app/common/logic/PermLogic.php --- app/common/logic/PermLogic.php | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index eca4b25..b4d38db 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -8,24 +8,7 @@ use app\common\model\Resource; class PermLogic { /** - * 获取用户所有资源(合并角色+直接分配) - */ - // public function getUserResources(int $userId) - // { - // $user = User::with(['roles.resources', 'resources'])->find($userId); - // if (!$user) { - // return collect(); - // } - - // $all = collect(); - // foreach ($user->roles as $role) { - // $all = $all->merge($role->resources); - // } - // $all = $all->merge($user->resources); - // return $all->unique('id')->values(); - // } - /** - * 获取用户所有资源(合并角色+直接分配),并加入公共菜单 + * 获取用户所有资源(合并角色+直接分配),并加入公共菜单,排序按sort字段 */ public function getUserResources(int $userId) { @@ -57,14 +40,16 @@ class PermLogic ); // 加入公共菜单,公共菜单不管是否授权,所有人都能访问 - $publicResources = Resource::where('no_auth', 1)->get(); // 获取所有公共菜单 + $publicResources = Resource::where('no_auth', 1) + ->orderBy('sort', 'asc') // 按 sort 字段升序排序 + ->get(); + $all = $all->merge($publicResources); // 返回唯一的资源列表,并按 id 排序 - return $all->unique('id')->values(); + return $all->unique('id')->values()->sortBy('sort'); // 最终根据sort排序 } - /** * 构建目录/菜单树,节点包含权限与打开方式,拼接完整路径,并对子级菜单component处理 * @param \Illuminate\Support\Collection $resources From 85861240c3006a66922e57700965fa423aa6f9ee Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 14 Jul 2025 19:01:42 +0800 Subject: [PATCH 07/25] Merge branch 'develop' # Conflicts: # app/common/logic/PermLogic.php --- app/common/logic/PermLogic.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index b4d38db..b30e6f8 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -44,12 +44,15 @@ class PermLogic ->orderBy('sort', 'asc') // 按 sort 字段升序排序 ->get(); + // 合并所有公共资源 $all = $all->merge($publicResources); // 返回唯一的资源列表,并按 id 排序 - return $all->unique('id')->values()->sortBy('sort'); // 最终根据sort排序 + // 使用 sortBy('sort') 来确保最终结果根据 'sort' 字段排序 + return $all->unique('id')->values()->sortBy('sort'); } + /** * 构建目录/菜单树,节点包含权限与打开方式,拼接完整路径,并对子级菜单component处理 * @param \Illuminate\Support\Collection $resources From a87ff09a35eb990d3a292f5b804fda3fba1df316 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Tue, 15 Jul 2025 09:13:25 +0800 Subject: [PATCH 08/25] =?UTF-8?q?=E5=B7=A5=E5=8D=95=E5=88=86=E7=B1=BB?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/ticket/service/CategorieService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/ticket/service/CategorieService.php b/app/ticket/service/CategorieService.php index 4954c85..67d1d74 100644 --- a/app/ticket/service/CategorieService.php +++ b/app/ticket/service/CategorieService.php @@ -14,7 +14,7 @@ class CategorieService public function list($params) { $result = (new CategorieLogic())->list($params); - $value=$result[0]->toArray(); +// $value=$result[0]->toArray(); foreach ($result as $key => &$value) { $value['name'] = isset($value['translation']) ? $value['translation']['name'] : ''; unset($value['translation']); From 584dfeffc375276ac5a5997712e18ab75199ee90 Mon Sep 17 00:00:00 2001 From: mzl Date: Tue, 15 Jul 2025 10:23:05 +0800 Subject: [PATCH 09/25] =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/IndexController.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php index f9b026d..0d7b7f7 100644 --- a/app/controller/IndexController.php +++ b/app/controller/IndexController.php @@ -61,4 +61,14 @@ class IndexController return json(['code' => 1, 'msg' => $e->getMessage()]); } } + + + // test function + public function test(Request $request) + { + $user = User::find(1); + $user->roles()->sync([1]); + $user->systems()->sync([1]); + return json(['code' => 0, 'msg' => 'success']); + } } \ No newline at end of file From 9a13c23788c97271ef79a24566eb471565dd33af Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Tue, 15 Jul 2025 13:52:31 +0800 Subject: [PATCH 10/25] =?UTF-8?q?=E5=AE=A2=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 1 + app/crm/model/Customer.php | 4 ++-- app/crm/model/CustomerTag.php | 2 +- app/crm/model/Tag.php | 2 +- app/crm/service/CustomerService.php | 11 ++++++----- config/route.php | 7 ++++++- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index d8b4887..9c9cd05 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -130,6 +130,7 @@ class CustomerController extends BaseController $param = $request->all(); $param['user_id'] = $request->user->uid; $result = (new CustomerService())->list($param); + return $this->success($this->page($result)); } catch (\Throwable $e) { return $this->error($e->getMessage()); diff --git a/app/crm/model/Customer.php b/app/crm/model/Customer.php index 3935a79..6c17787 100644 --- a/app/crm/model/Customer.php +++ b/app/crm/model/Customer.php @@ -66,7 +66,7 @@ class Customer extends Model */ public static function getCustomer($customer, $request, $tag = false) { - $language = $request->user['language'] ?: 'en'; + $language = 'zh_CN' ?: 'en'; $customer['grade_txt'] = Util::language($language, Constants::GRADE_EN[$customer['grade']], Constants::GRADE_ZH[$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']]); @@ -117,7 +117,7 @@ class Customer extends Model */ public function tags() { - return $this->belongsToMany(Tag::class, 'customer_tag', 'customer_id', 'tag_id') + return $this->belongsToMany(Tag::class, 'crm_customer_tag', 'customer_id', 'tag_id') ->withTimestamps(); // 如果需要记录关联时间 } diff --git a/app/crm/model/CustomerTag.php b/app/crm/model/CustomerTag.php index b6a26bf..3a0c567 100644 --- a/app/crm/model/CustomerTag.php +++ b/app/crm/model/CustomerTag.php @@ -14,7 +14,7 @@ class CustomerTag extends Model * * @var string */ - protected $table = 'customer_tag'; + protected $table = 'crm_customer_tag'; /** * The primary key associated with the table. diff --git a/app/crm/model/Tag.php b/app/crm/model/Tag.php index 3e7ec25..e58bb87 100644 --- a/app/crm/model/Tag.php +++ b/app/crm/model/Tag.php @@ -50,6 +50,6 @@ class Tag extends Model public function customers() { - return $this->belongsToMany(Customer::class, 'customer_tag', 'tag_id', 'customer_id'); + return $this->belongsToMany(Customer::class, 'crm_customer_tag', 'tag_id', 'customer_id'); } } \ No newline at end of file diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index d21d460..74baab2 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -17,11 +17,12 @@ class CustomerService if(empty($user_id) || $user_id == 0){ $where[] = ['user_id', '=', $user_id]; } - $user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page); - $user = $user->toArray(); - foreach ($user['data'] as &$item) { - unset($item['password']); - } + $user = Customer::where($where)->paginate($perPage, ['*'], 'page', $page); +// $user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page); +// $user = $user->toArray(); +// foreach ($user['data'] as &$item) { +// unset($item['password']); +// } return $user; } } \ No newline at end of file diff --git a/config/route.php b/config/route.php index e8af21a..4c29ced 100644 --- a/config/route.php +++ b/config/route.php @@ -81,10 +81,15 @@ Route::group('/ticket', function () { //crm Route::group('/crm', function () { + //跟进 Route::any('/follow/list', [app\crm\controller\FollowController::class, 'list']); Route::any('/follow/detail', [app\crm\controller\FollowController::class, 'detail']); Route::any('/follow/add', [app\crm\controller\FollowController::class, 'save']); Route::any('/follow/getFollowType', [app\crm\controller\FollowController::class, 'getFollowType']); - Route::any('/follow/getFollowType', [app\crm\controller\FollowController::class, 'getFollowType']); + + //客户 + Route::any('/customer/list', [app\crm\controller\CustomerController::class, 'list']); + Route::any('/customer/detail', [app\crm\controller\CustomerController::class, 'detail']); + Route::any('/customer/add', [app\crm\controller\CustomerController::class, 'save']); }); From 416050a387b4ffb76d0c55a06d93b3eab3ae6c4f Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 17 Jul 2025 09:36:46 +0800 Subject: [PATCH 11/25] crm --- app/crm/controller/CustomerController.php | 144 +++++++++++++--------- app/crm/controller/FollowController.php | 60 ++++----- app/crm/logic/CustomerLogic.php | 7 ++ app/crm/model/Channel.php | 4 +- app/crm/model/Country.php | 2 +- app/crm/model/Customer.php | 3 +- app/crm/service/CustomerService.php | 12 ++ app/crm/service/FollowService.php | 17 +-- config/route.php | 5 + 9 files changed, 156 insertions(+), 98 deletions(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 9c9cd05..5fc0750 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -2,11 +2,12 @@ namespace app\crm\controller; +use app\common\model\User; use app\crm\model\Channel; +use app\crm\model\Country; use app\crm\model\Customer; use app\crm\model\CustomerHis; use app\crm\model\Follow; -use app\crm\model\User; use app\crm\service\CustomerService; use app\crm\utils\Util; use config\constants\Constants; @@ -24,9 +25,9 @@ class CustomerController extends BaseController { $grade = []; $gradeConstants = Constants::GRADE_EN; - if($request->user['language'] == 'zh_CN'){ - $gradeConstants = Constants::GRADE; - }elseif ($request->user['language'] == 'ru'){ + if('zh_CN' == 'zh_CN'){ + $gradeConstants = Constants::GRADE_ZH; + }elseif ('zh_CN' == 'ru'){ $gradeConstants = Constants::GRADE_RU; } foreach ($gradeConstants as $key => $value) { @@ -35,7 +36,7 @@ class CustomerController extends BaseController 'name' => $value, ]; } - return Util::success($grade); + return $this->success($grade); } /** @@ -47,9 +48,9 @@ class CustomerController extends BaseController { $grade = []; $magnitudeConstants = Constants::MAGNITUDE_EN; - if($request->user['language'] == 'zh_CN'){ + if('zh_CN' == 'zh_CN'){ $magnitudeConstants = Constants::MAGNITUDE; - }elseif ($request->user['language'] == 'ru'){ + }elseif ('zh_CN' == 'ru'){ $magnitudeConstants = Constants::MAGNITUDE_RU; } foreach ($magnitudeConstants as $key => $value) { @@ -58,7 +59,7 @@ class CustomerController extends BaseController 'name' => $value, ]; } - return Util::success($grade); + return $this->success($grade); } /** @@ -70,17 +71,40 @@ class CustomerController extends BaseController { $list = Channel::getAll(); - if($request->user['language'] != 'zh_CN'){ + if('zh_CN' != 'zh_CN'){ foreach ($list as &$value) { $value['name'] = $value['name_en']; } - }elseif ($request->user['language'] == 'ru'){ + }elseif ('zh_CN' == 'ru'){ foreach ($list as &$value) { $value['name'] = $value['name_ru']; } } - return Util::success($list); + return $this->success($list); + + } + + /** + * 国家 + * @param Request $request + * @return \support\Response + */ + public function getCountry(Request $request) + { + $list = Country::getAll(); + + if('zh_CN' != 'zh_CN'){ + foreach ($list as &$value) { + $value['name'] = $value['name_en']; + } + }elseif ('zh_CN' == 'ru'){ + foreach ($list as &$value) { + $value['name'] = $value['name_ru']; + } + } + + return $this->success($list); } @@ -91,12 +115,13 @@ class CustomerController extends BaseController */ public function waitFollow(Request $request) { - $userId = $request->user['id']; + $userId = $request->user->uid; $filter = Util::getParam($request, 'filter'); $page = $request->input('page', 1); $perPage = $request->input('per_page', 10); $where = [ ['user_id', '=', $userId], + ['corp_abbr', '=', $request->basic_data['corp_abbr']], ['follow_next', '<>', 0], ]; @@ -116,7 +141,7 @@ class CustomerController extends BaseController $item['follow_remaining'] = $item->follow_next-time(); $item['follow_next'] = date('Y-m-d H:i:s',$item->follow_next); } - return Util::page($customer); + return $this->success($this->page($customer)); } /** @@ -129,6 +154,7 @@ class CustomerController extends BaseController try { $param = $request->all(); $param['user_id'] = $request->user->uid; + $param['corp_abbr'] = $request->basic_data['corp_abbr']; $result = (new CustomerService())->list($param); return $this->success($this->page($result)); @@ -146,18 +172,18 @@ class CustomerController extends BaseController { $id = Util::getParam($request,'id', ''); if (Util::isEmpty($id)) { - return Util::fail([], trans('id_empty')); + return $this->error(trans('id_empty')); } - $userId = $request->user['id']; + $userId = $request->user->uid; $where = [ 'id' => $id, 'user_id' => $userId, ]; $res = Customer::where($where)->restore(); if($res){ - return Util::success($res, trans('success')); + return $this->success($res, trans('success')); }else{ - return Util::fail([], trans('fail')); + return $this->error(trans('fail')); } } @@ -171,21 +197,22 @@ class CustomerController extends BaseController { $id = Util::getParam($request, 'id'); if (Util::isEmpty($id)) { - return Util::fail([], 'id' . trans('not_null')); + return $this->error('id' . trans('not_null')); } - $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(); +// $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(); + $res = (new CustomerService)->detail($request->all()); if ($res) { $res->toArray(); } else { - return Util::fail([], '记录不存在'); + return $this->error('记录不存在'); } $res = Customer::getCustomer($res, $request, true); - return Util::success($res); + return $this->success($res); } /** @@ -198,25 +225,26 @@ class CustomerController extends BaseController $id = Util::getParam($request, 'id'); $channel_id = Util::getParam($request, 'channel_id'); if (Util::isEmpty($channel_id)) { - return Util::fail([], trans('channel_not_null')); + return $this->error(trans('channel_not_null')); } $country_id = Util::getParam($request, 'country_id', 0); if (Util::isEmpty($country_id)) { -// return Util::fail([],'country_id'.trans('not_null')); +// return $this->error('country_id'.trans('not_null')); } $car_type_id = Util::getParam($request, 'car_type_id'); if (Util::isEmpty($car_type_id)) { - return Util::fail([], trans('car_type_not_null')); + return $this->error(trans('car_type_not_null')); } $contacts = Util::getParam($request, 'contacts'); $email = Util::getParam($request, 'email'); $phone = Util::getParam($request, 'phone'); if (Util::isEmpty($contacts) && Util::isEmpty($email) && Util::isEmpty($phone)) { - return Util::fail([], trans('contacts_not_null')); + return $this->error(trans('contacts_not_null')); } $data = [ - 'user_id' => $request->user['id'], + 'user_id' => $request->user->uid, + 'corp_abbr' => $request->basic_data['corp_abbr'], 'grade' => Util::getParam($request, 'grade', 0), 'channel_id' => $channel_id, 'country_id' => $country_id, @@ -244,9 +272,9 @@ class CustomerController extends BaseController } if ($res) { - return Util::success($res, trans('save_success')); + return $this->success($res, trans('save_success')); } else { - return Util::fail($res, trans('save_fail')); + return $this->error(trans('save_fail')); } } @@ -261,7 +289,7 @@ class CustomerController extends BaseController { $id = Util::getParam($request, 'id'); if (Util::isEmpty($id)) { - return Util::fail([], 'id' . trans('not_null')); + return $this->error('id' . trans('not_null')); } $data = [ 'follow_next' => Util::getParam($request, 'follow_next', 0), @@ -273,9 +301,9 @@ class CustomerController extends BaseController ->update($data); if ($res) { - return Util::success($res, trans('save_success')); + return $this->success($res, trans('save_success')); } else { - return Util::fail($res, trans('save_fail')); + return $this->error(trans('save_fail')); } } @@ -289,14 +317,14 @@ class CustomerController extends BaseController $id = Util::getParam($request, 'id'); $force = Util::getParam($request, 'force',''); - $userId = $request->user['id']; + $userId = $request->user->uid; $where = [ 'id' => $id, 'user_id' => $userId, ]; $customer = Customer::where($where)->withTrashed()->first(); if(empty($customer)){ - return Util::fail('', trans('fail')); + return $this->error( trans('fail')); } if($force == 'force'){ $res = $customer->forceDelete(); @@ -304,9 +332,9 @@ class CustomerController extends BaseController $res = $customer->delete(); } if ($res) { - return Util::success($res, trans('success')); + return $this->success($res, trans('success')); } else { - return Util::fail($res, trans('fail')); + return $this->error(trans('fail')); } } @@ -319,12 +347,14 @@ class CustomerController extends BaseController { $created = Util::getParam($request, 'created'); if (Util::isEmpty($created)) { - return Util::fail([], 'created' . trans('not_null')); + return $this->error('created' . trans('not_null')); } - $userId = $request->user['id']; - $created_at = $request->user['created_at']; + $userId = $request->user->uid; + //$created_at = $request->user['created_at']; + $created_at = User::find($userId)->created_at; $day = ceil((time() - $created_at + 1) / 60 / 60 / 24); $where[] = ['user_id', '=', $userId]; + $where[] = ['corp_abbr', '=', $request->basic_data['corp_abbr']]; $start = strtotime($created . '-01'); $year = date('Y', $start); $month = date('n', $start); //获取月份 @@ -366,9 +396,9 @@ class CustomerController extends BaseController 'customer_deal' => $customerDeal, //已成交 ]; if ($res) { - return Util::success($res, trans('success')); + return $this->success($res, trans('success')); } else { - return Util::fail($res, trans('fail')); + return $this->error(trans('fail')); } } @@ -380,17 +410,17 @@ class CustomerController extends BaseController public function claim(Request $request) { $customerId = Util::getParam($request, 'customer_id'); - $userId = $request->user['id']; + $userId = $request->user->uid; if (Util::isEmpty($customerId)) { - return Util::fail([], trans('customer_id').trans('not_null')); + return $this->error(trans('customer_id').trans('not_null')); } $data = [ - 'user_id' => $request->user['id'] + 'user_id' => $request->user->uid ]; $customer= Customer::withTrashed()->find($customerId); if(empty($customer) || $customer->user_id != 0){ - return Util::fail('', trans('claim_fail')); + return $this->error( trans('claim_fail')); } $customer->restore(); @@ -404,9 +434,9 @@ class CustomerController extends BaseController ]); if ($res) { - return Util::success($res, trans('success')); + return $this->success($res, trans('success')); } else { - return Util::fail($res, trans('fail')); + return $this->error(trans('fail')); } } @@ -421,14 +451,14 @@ class CustomerController extends BaseController { $customerId = Util::getParam($request, 'customer_id'); $user_sn = Util::getParam($request, 'user_sn'); - $userId = $request->user['id']; + $userId = $request->user->uid; if (Util::isEmpty($user_sn)) { - return Util::fail([], 'ID'.trans('not_null')); + return $this->error('ID'.trans('not_null')); } $user = User::where(['sn' => $user_sn])->first(); if (Util::isEmpty($user)) { - return Util::fail(null, trans('user_none')); + return $this->error( trans('user_none')); } if(Util::isEmpty($customerId)){ @@ -453,9 +483,9 @@ class CustomerController extends BaseController if ($res) { - return Util::success($res, trans('success')); + return $this->success($res, trans('success')); } else { - return Util::fail($res, trans('fail')); + return $this->error(trans('fail')); } } @@ -469,10 +499,10 @@ class CustomerController extends BaseController $id = Util::getParam($request, 'id'); $grade = Util::getParam($request, 'grade'); if (Util::isEmpty($id)) { - return Util::fail('', 'id' . trans('not_null')); + return $this->error( 'id' . trans('not_null')); } if (Util::isEmpty($id)) { - return Util::fail('', 'grade' . trans('not_null')); + return $this->error( 'grade' . trans('not_null')); } $data = [ 'grade' => $grade, @@ -481,9 +511,9 @@ class CustomerController extends BaseController ->update($data); if ($res) { - return Util::success($res, trans('save_success')); + return $this->success($res, trans('save_success')); } else { - return Util::fail($res, trans('save_fail')); + return $this->error(trans('save_fail')); } } } \ No newline at end of file diff --git a/app/crm/controller/FollowController.php b/app/crm/controller/FollowController.php index 7ee34a4..a23749c 100644 --- a/app/crm/controller/FollowController.php +++ b/app/crm/controller/FollowController.php @@ -40,7 +40,8 @@ class FollowController extends BaseController { try { $data = $this->validate(new FollowValidate(), $request->get(), 'list'); - $result = (new FollowService())->list($request->all(),$request->user->uid); + $request->setGet('corp_abbr', $request->basic_data['corp_abbr']); + $result = (new FollowService())->list($request->all(), $request->user->uid); return $this->success($result); } catch (\Throwable $e) { return $this->error($e->getMessage()); @@ -55,17 +56,17 @@ class FollowController extends BaseController public function detail(Request $request) { //跟进id - $id = Util::getParam($request,'id'); - if(Util::isEmpty($id)){ - return $this->error('id'.trans('not_null')); + $id = Util::getParam($request, 'id'); + if (Util::isEmpty($id)) { + return $this->error('id' . trans('not_null')); } - $res = Follow::select('id','user_id','customer_id','type','picture','remark','audio','audio_text','lat','lng','address') - ->where('id',$id) + $res = Follow::select('id', 'user_id', 'customer_id', 'type', 'picture', 'remark', 'audio', 'audio_text', 'lat', 'lng', 'address') + ->where('id', $id) ->first(); - if($res){ + if ($res) { $res->toArray(); - }else{ + } else { return $this->error('记录不存在'); } @@ -81,32 +82,33 @@ class FollowController extends BaseController */ public function save(Request $request) { - $customer_id = Util::getParam($request,'customer_id'); + $customer_id = Util::getParam($request, 'customer_id'); - if(Util::isEmpty($customer_id)){ - return $this->error('customer_id'.trans('not_null')); + if (Util::isEmpty($customer_id)) { + return $this->error('customer_id' . trans('not_null')); } - $type = Util::getParam($request,'type'); - if(Util::isEmpty($type)){ - return $this->error('type'.trans('not_null')); + $type = Util::getParam($request, 'type'); + if (Util::isEmpty($type)) { + return $this->error('type' . trans('not_null')); } - $picture = Util::getParam($request,'picture'); - if(Util::isEmpty($picture)){ + $picture = Util::getParam($request, 'picture'); + if (Util::isEmpty($picture)) { return $this->error(trans('picture_not_null')); } $data = [ - 'user_id'=>$request->user->uid, - 'customer_id'=>$customer_id, - 'type'=>$type, - 'picture'=>$picture, - 'remark'=>Util::getParam($request,'remark',''), - 'audio'=>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'), - 'follow_time'=>strtotime(Util::getParam($request,'firstFollowtime',0)), + 'user_id' => $request->user->uid, + 'corp_abbr' => $request->basic_data['corp_abbr'], + 'customer_id' => $customer_id, + 'type' => $type, + 'picture' => $picture, + 'remark' => Util::getParam($request, 'remark', ''), + 'audio' => 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'), + 'follow_time' => strtotime(Util::getParam($request, 'firstFollowtime', 0)), ]; $res = Follow::create($data); @@ -119,7 +121,7 @@ class FollowController extends BaseController $follow_next = Util::getParam($request, 'follow_next', 0); $follow_remark = Util::getParam($request, 'follow_remark', 0); - if($res && (!empty($follow_next))){ + if ($res && (!empty($follow_next))) { $data = [ 'follow_next' => $follow_next, 'follow_remark' => $follow_remark, @@ -130,7 +132,7 @@ class FollowController extends BaseController } if ($res) { - return $this->success($res,trans('save_success')); + return $this->success($res, trans('save_success')); } else { return $this->error(trans('save_fail')); } diff --git a/app/crm/logic/CustomerLogic.php b/app/crm/logic/CustomerLogic.php index 0e6b1a0..4e0619d 100644 --- a/app/crm/logic/CustomerLogic.php +++ b/app/crm/logic/CustomerLogic.php @@ -2,7 +2,14 @@ namespace app\crm\logic; +use app\crm\model\Customer; + class CustomerLogic { + public function find(int $id) + { + $customer = Customer::find($id); + return $customer; + } } \ No newline at end of file diff --git a/app/crm/model/Channel.php b/app/crm/model/Channel.php index 59f9237..ac02c71 100644 --- a/app/crm/model/Channel.php +++ b/app/crm/model/Channel.php @@ -11,7 +11,7 @@ class Channel extends Model * * @var string */ - protected $table = 'channel'; + protected $table = 'inquiry_channel'; /** * The primary key associated with the table. @@ -42,7 +42,7 @@ class Channel extends Model public static function getAll() { - $list = self::get()->select('id','name','name_en','status')->where('status',0)->toArray(); + $list = self::get()->select('id','name','name_en','status')->where('status',1)->toArray(); return $list; } } \ No newline at end of file diff --git a/app/crm/model/Country.php b/app/crm/model/Country.php index 29ba895..f1fffd1 100644 --- a/app/crm/model/Country.php +++ b/app/crm/model/Country.php @@ -35,7 +35,7 @@ class Country extends Model public static function getAll() { - $list = self::get()->select('id','cn_addr','en_addr')->get()->toArray(); + $list = self::select('id','cn_addr','en_addr')->get(); return $list; } } \ No newline at end of file diff --git a/app/crm/model/Customer.php b/app/crm/model/Customer.php index 6c17787..f28fb11 100644 --- a/app/crm/model/Customer.php +++ b/app/crm/model/Customer.php @@ -95,7 +95,8 @@ class Customer extends Model // $customer['updated_at'] = Util::timeTotDate($customer['updated_at']); $customer = Util::formatDate($customer,['follow_last']); - $nameLang = $language=='en'?'name_en':($language=='ru'?'name_ru':'name'); +// $nameLang = $language=='en'?'name_en':($language=='ru'?'name_ru':'name'); + $nameLang = '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); diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 74baab2..f085f44 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -2,6 +2,7 @@ namespace app\crm\service; +use app\crm\logic\CustomerLogic; use app\crm\model\Customer; class CustomerService @@ -25,4 +26,15 @@ class CustomerService // } return $user; } + + + public function detail($params) + { + $id =$params['id']; + $customer = 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(); + + return $customer; + } } \ No newline at end of file diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php index 89b7c2b..b97d5f1 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -18,16 +18,18 @@ class FollowService // $perPage = $request->input('per_page', 10); //客户id - $customer_id =$param['customer_id']; + $customer_id = $param['customer_id']; + $corp_abbr = $param['corp_abbr']; $where = []; $where['customer_id'] = $customer_id; + $where['corp_abbr'] = $corp_abbr; //用户角色 //跟进id - $id = $param['id']??null; - if(!Util::isEmpty($id)){ + $id = $param['id'] ?? null; + if (!Util::isEmpty($id)) { $where['id'] = $id; } @@ -39,7 +41,7 @@ class FollowService // $host = $request->host(); // $url = 'http:'.$request->url(); - foreach ($data as &$value){ + foreach ($data as &$value) { $value = self::getFollow($value); } @@ -47,15 +49,14 @@ class FollowService } - - public static function getFollow($follow,$domain = 'https://vehicle-album.oss-cn-beijing.aliyuncs.com') + public static function getFollow($follow) { $follow['type_txt'] = Constants::FOLLOW[$follow['type']]; $follow['firstFollowtime'] = $follow['follow_time']; $oss_picture = ''; - if(!empty($follow['picture'])){ + if (!empty($follow['picture'])) { $ossservice = new OssService(); - $oss_picture = $ossservice->generatePrivateUrl($follow['picture'],86400); + $oss_picture = $ossservice->generatePrivateUrl($follow['picture'], 86400); } $follow['oss_picture'] = $oss_picture; // $follow = Util::formatDate($follow); diff --git a/config/route.php b/config/route.php index 4c29ced..dd98cca 100644 --- a/config/route.php +++ b/config/route.php @@ -91,5 +91,10 @@ Route::group('/crm', function () { Route::any('/customer/list', [app\crm\controller\CustomerController::class, 'list']); Route::any('/customer/detail', [app\crm\controller\CustomerController::class, 'detail']); Route::any('/customer/add', [app\crm\controller\CustomerController::class, 'save']); + Route::any('/customer/claim', [app\crm\controller\CustomerController::class, 'claim']); + Route::any('/customer/restore', [app\crm\controller\CustomerController::class, 'restore']); + Route::any('/customer/delete', [app\crm\controller\CustomerController::class, 'delete']); + Route::any('/customer/waitFollow', [app\crm\controller\CustomerController::class, 'waitFollow']); + Route::any('/customer/getChannel', [app\crm\controller\CustomerController::class, 'getChannel']); }); From 92dc7b19a98986d90dc616108cc639f7b94948b1 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 17 Jul 2025 10:24:46 +0800 Subject: [PATCH 12/25] =?UTF-8?q?=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/route.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/route.php b/config/route.php index 8ff4261..413f864 100644 --- a/config/route.php +++ b/config/route.php @@ -64,10 +64,7 @@ Route::group('/ticket', function () { Route::any('/ticket/add', [app\ticket\controller\TicketController::class, 'add']); Route::any('/ticket/edit', [app\ticket\controller\TicketController::class, 'edit']); Route::any('/ticket/list', [app\ticket\controller\TicketController::class, 'index']); -<<<<<<< HEAD Route::any('/ticket/self', [app\ticket\controller\TicketController::class, 'self']); -======= ->>>>>>> feature/crmAdmin0715 Route::any('/ticket/status', [app\ticket\controller\TicketController::class, 'status']); Route::any('/ticket/getStatus', [app\ticket\controller\TicketController::class, 'getStatus']); From 59d81b4db454e884feb70d63f2152fc57430d9b0 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 17 Jul 2025 10:42:43 +0800 Subject: [PATCH 13/25] =?UTF-8?q?=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 1.sql | 3 - app/common/controller/PresetController.php | 36 +++++++++ app/common/logic/BaseLogic.php | 86 +++++++++++++++++++++ app/common/logic/CorpFeishuAppLogic.php | 16 ++++ app/common/logic/CorpLogic.php | 14 ++++ app/common/model/UserFeishuApp_bak.php | 69 +++++++++++++++++ app/common/model/UserRoles.php | 47 +++++++++++ app/common/model/UserSystems.php | 53 +++++++++++++ app/common/service/CorpFeishuAppService.php | 21 +++++ app/common/service/CorpService.php | 24 ++++++ 10 files changed, 366 insertions(+), 3 deletions(-) delete mode 100644 1.sql create mode 100644 app/common/controller/PresetController.php create mode 100644 app/common/logic/BaseLogic.php create mode 100644 app/common/logic/CorpFeishuAppLogic.php create mode 100644 app/common/logic/CorpLogic.php create mode 100644 app/common/model/UserFeishuApp_bak.php create mode 100644 app/common/model/UserRoles.php create mode 100644 app/common/model/UserSystems.php create mode 100644 app/common/service/CorpFeishuAppService.php create mode 100644 app/common/service/CorpService.php diff --git a/1.sql b/1.sql deleted file mode 100644 index ea1e67c..0000000 --- a/1.sql +++ /dev/null @@ -1,3 +0,0 @@ -User ← user_roles → Role ← role_resources → Resource (type=menu/button) - ↘︎ - role_permissions → Permission \ No newline at end of file diff --git a/app/common/controller/PresetController.php b/app/common/controller/PresetController.php new file mode 100644 index 0000000..964b2a6 --- /dev/null +++ b/app/common/controller/PresetController.php @@ -0,0 +1,36 @@ +getList(); + return $this->success($result, '获取公司列表'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + + + public function feishuApp(Request $request) + { + try { + $corpId = $request->get('corp_id'); + $result = (new CorpFeishuAppService())->getFeishuApp($corpId); + return $this->success($result, '获取飞书应用信息'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } +} \ No newline at end of file diff --git a/app/common/logic/BaseLogic.php b/app/common/logic/BaseLogic.php new file mode 100644 index 0000000..94beff3 --- /dev/null +++ b/app/common/logic/BaseLogic.php @@ -0,0 +1,86 @@ +paginate($params['per_page'], ['*'], 'page', $params['page']); + } + + return $query->get(); + } + + /** + * 获取单个记录 + */ + public function getDetail(int $id, string $modelClass) + { + $record = $modelClass::find($id); + if (!$record) { + throw new BusinessException("记录不存在", 404); + } + + return $record; + } + + /** + * 创建记录 + */ + public function create(array $data, string $modelClass) + { + $model = new $modelClass; + $model->fill($data); // 根据字段填充数据 + try { + $model->save(); + } catch (\Throwable $e) { + throw new BusinessException("创建记录失败: " . $e->getMessage(), 500); + } + + return $model; + } + + /** + * 更新记录 + */ + public function update(array $data, string $modelClass) + { + $record = $modelClass::find($data['id']); + if (!$record) { + throw new BusinessException("记录不存在", 404); + } + + $record->update($data); + return $record; + } + + /** + * 删除记录 + */ + public function delete(int $id, string $modelClass) + { + $record = $modelClass::find($id); + if (!$record) { + throw new BusinessException("记录不存在", 404); + } + + try { + $record->delete(); + } catch (\Throwable $e) { + throw new BusinessException("删除记录失败: " . $e->getMessage(), 500); + } + + return true; + } +} diff --git a/app/common/logic/CorpFeishuAppLogic.php b/app/common/logic/CorpFeishuAppLogic.php new file mode 100644 index 0000000..2073aac --- /dev/null +++ b/app/common/logic/CorpFeishuAppLogic.php @@ -0,0 +1,16 @@ +first(['id', 'corp_id', 'name', 'app_id', 'r_url', 'state']); + } + +} \ No newline at end of file diff --git a/app/common/logic/CorpLogic.php b/app/common/logic/CorpLogic.php new file mode 100644 index 0000000..cac9672 --- /dev/null +++ b/app/common/logic/CorpLogic.php @@ -0,0 +1,14 @@ +orderBy('sort', 'asc')->get(['id', 'name', 'abbr', 'tenant_key']); + } +} \ No newline at end of file diff --git a/app/common/model/UserFeishuApp_bak.php b/app/common/model/UserFeishuApp_bak.php new file mode 100644 index 0000000..9aa06c0 --- /dev/null +++ b/app/common/model/UserFeishuApp_bak.php @@ -0,0 +1,69 @@ +logic = (new CorpFeishuAppLogic()); + } + + public function getFeishuApp(int $corpId) + { + return $this->logic->getFeishuApp($corpId); + } +} \ No newline at end of file diff --git a/app/common/service/CorpService.php b/app/common/service/CorpService.php new file mode 100644 index 0000000..7d18d49 --- /dev/null +++ b/app/common/service/CorpService.php @@ -0,0 +1,24 @@ +logic = (new CorpLogic()); + } + + /** + * 获取公司list + */ + public function getList() + { + return $this->logic->getList(); + } +} \ No newline at end of file From 84cb69f9fe8964b0d7935767b9125d8e2764a733 Mon Sep 17 00:00:00 2001 From: mzl Date: Thu, 17 Jul 2025 14:49:55 +0800 Subject: [PATCH 14/25] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E5=8D=A0=E4=BD=8Durl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/logic/PermLogic.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index b30e6f8..703737c 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -102,7 +102,7 @@ class PermLogic // component 字段规则: // 1. 存在子菜单,固定 '/index/index' // 2. 否则为当前完整路径(或其它你想要的) - $componentValue = $hasChildrenMenu ? '/index/index' : $currentPath; + $componentValue = $hasChildrenMenu && !$node->url ? '/index/index' : $currentPath; $tree[] = [ 'id' => $node->id, From cb06f7a0e91903708c3edcb280911f9b95a2f918 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 17 Jul 2025 15:10:24 +0800 Subject: [PATCH 15/25] =?UTF-8?q?crm=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 7 +++++++ config/route.php | 2 ++ 2 files changed, 9 insertions(+) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 5fc0750..50e85b9 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -16,6 +16,13 @@ use support\Request; class CustomerController extends BaseController { + /** + * 不需要头信息的方法 + */ + protected $noNeedHeader = []; + + protected $noNeedLogin = ['getChannel', 'getCountry']; + /** * 客户分级 * @param Request $request diff --git a/config/route.php b/config/route.php index 413f864..4fd7025 100644 --- a/config/route.php +++ b/config/route.php @@ -101,6 +101,8 @@ Route::group('/crm', function () { Route::any('/customer/restore', [app\crm\controller\CustomerController::class, 'restore']); Route::any('/customer/delete', [app\crm\controller\CustomerController::class, 'delete']); Route::any('/customer/waitFollow', [app\crm\controller\CustomerController::class, 'waitFollow']); + Route::any('/customer/statistics', [app\crm\controller\CustomerController::class, 'statistics']); Route::any('/customer/getChannel', [app\crm\controller\CustomerController::class, 'getChannel']); + Route::any('/customer/getCountry', [app\crm\controller\CustomerController::class, 'getCountry']); }); From 02b752aa98e5094d10a0838cd2f3710b54ba72a5 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Thu, 17 Jul 2025 16:25:47 +0800 Subject: [PATCH 16/25] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/TagGroupController.php | 15 ++++++++++----- config/route.php | 3 +++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/crm/controller/TagGroupController.php b/app/crm/controller/TagGroupController.php index 7e5dff1..3cf24e1 100644 --- a/app/crm/controller/TagGroupController.php +++ b/app/crm/controller/TagGroupController.php @@ -17,7 +17,7 @@ class TagGroupController extends BaseController { $list = TagGroup::with('tags')->get(); $languageArr = Constants::LANGUAGE; - $language = $request->user['language']; + $language = 'zh_CN'; foreach ($list as &$item) { $item['names'] = unserialize($item['names']); if (in_array($language, $languageArr)) { @@ -52,10 +52,15 @@ class TagGroupController extends BaseController return $this->error( 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]); + + try { + 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]); + } + } catch (\Throwable $e) { + return $this->error($e->getMessage()); } if($res){ diff --git a/config/route.php b/config/route.php index 4fd7025..b694023 100644 --- a/config/route.php +++ b/config/route.php @@ -104,5 +104,8 @@ Route::group('/crm', function () { Route::any('/customer/statistics', [app\crm\controller\CustomerController::class, 'statistics']); Route::any('/customer/getChannel', [app\crm\controller\CustomerController::class, 'getChannel']); Route::any('/customer/getCountry', [app\crm\controller\CustomerController::class, 'getCountry']); + + Route::any('/tagGroup/list', [app\crm\controller\TagGroupController::class, 'list']); + Route::any('/tagGroup/updatePivot', [app\crm\controller\TagGroupController::class, 'updatePivot']); }); From 4988129503c310a764adb2a231eb14d1a025e39a Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 10:04:54 +0800 Subject: [PATCH 17/25] =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UserController.php | 19 +++++++++++++++++++ app/common/logic/UserLogic.php | 18 ++++++++++++++++++ app/common/model/User.php | 7 ++++++- app/common/service/UserService.php | 14 ++++++++++++++ config/route.php | 6 ++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/app/common/controller/UserController.php b/app/common/controller/UserController.php index efab4a1..2a55181 100644 --- a/app/common/controller/UserController.php +++ b/app/common/controller/UserController.php @@ -22,4 +22,23 @@ class UserController extends BaseController } } + /** + * 编辑用户 + */ + public function edit(Request $request) + { + try { + $uid = $request->user->uid; + $data = $request->all(); + $result = (new UserService())->edit($uid,$data); + unset($result['password']); + unset($result['union_id']); + unset($result['open_id']); + unset($result['tenant_key']); + return $this->success($result, '编辑成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + } \ No newline at end of file diff --git a/app/common/logic/UserLogic.php b/app/common/logic/UserLogic.php index 1d6dc93..28ebf6e 100644 --- a/app/common/logic/UserLogic.php +++ b/app/common/logic/UserLogic.php @@ -24,4 +24,22 @@ class UserLogic return $user; } + + /** + * 用户信息 + */ + public function edit(int $uid, array $data) + { + $user = User::find($uid); + + if (!$user) { + throw new BusinessException('账户不存在', 404); + } + + $user->fill($data); + $user->save(); + + return $user; + } + } \ No newline at end of file diff --git a/app/common/model/User.php b/app/common/model/User.php index e9b4627..5d1b8f0 100644 --- a/app/common/model/User.php +++ b/app/common/model/User.php @@ -54,6 +54,7 @@ class User extends Model 'sn', 'name', 'avatar', + 'sex', 'password', 'phone', 'email', @@ -63,7 +64,11 @@ class User extends Model 'union_id', 'user_id', 'open_id', - 'tenant_key' + 'tenant_key', + 'country_id', + 'position', + 'socialize', + 'socialize_pic', ]; // 用户所有角色 diff --git a/app/common/service/UserService.php b/app/common/service/UserService.php index 98375bc..b927c52 100644 --- a/app/common/service/UserService.php +++ b/app/common/service/UserService.php @@ -37,4 +37,18 @@ class UserService 'permissions' => $permissionCodes ]; } + + /** + * 获取用户信息(包括菜单和权限) + */ + public function edit(int $uid, array $data) + { + unset($data['password']); + unset($data['phone']); + unset($data['email']); + unset($data['sn']); + + $user = $this->logic->edit($uid,$data); + return $user; + } } \ No newline at end of file diff --git a/config/route.php b/config/route.php index b694023..3563589 100644 --- a/config/route.php +++ b/config/route.php @@ -104,8 +104,14 @@ Route::group('/crm', function () { Route::any('/customer/statistics', [app\crm\controller\CustomerController::class, 'statistics']); Route::any('/customer/getChannel', [app\crm\controller\CustomerController::class, 'getChannel']); Route::any('/customer/getCountry', [app\crm\controller\CustomerController::class, 'getCountry']); + Route::any('/customer/followNext', [app\crm\controller\CustomerController::class, 'followNext']); Route::any('/tagGroup/list', [app\crm\controller\TagGroupController::class, 'list']); Route::any('/tagGroup/updatePivot', [app\crm\controller\TagGroupController::class, 'updatePivot']); + + Route::any('/upload/image', [app\common\controller\UploadController::class, 'uploadImage']); + + + Route::any('/user/edit', [app\common\controller\UserController::class, 'edit']); }); From deb6a2db9778b528c3bc0aa2e5f93ca50252d111 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 14:07:04 +0800 Subject: [PATCH 18/25] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UserController.php | 14 ++++++++++++++ app/common/service/UserService.php | 24 ++++++++++++++++++++++++ config/route.php | 1 + 3 files changed, 39 insertions(+) diff --git a/app/common/controller/UserController.php b/app/common/controller/UserController.php index 2a55181..fc8413d 100644 --- a/app/common/controller/UserController.php +++ b/app/common/controller/UserController.php @@ -22,6 +22,20 @@ class UserController extends BaseController } } + /** + * 用户信息 + */ + public function getUser(Request $request) + { + try { + $uid = $request->user->uid; + $result = (new UserService())->getUser($uid); + return $this->success($result, '获取用户信息'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + /** * 编辑用户 */ diff --git a/app/common/service/UserService.php b/app/common/service/UserService.php index b927c52..f5daf14 100644 --- a/app/common/service/UserService.php +++ b/app/common/service/UserService.php @@ -3,6 +3,7 @@ namespace app\common\service; use app\common\logic\UserLogic; +use app\crm\model\Country; class UserService { @@ -38,6 +39,29 @@ class UserService ]; } + + /** + * 获取用户信息(包括菜单和权限) + */ + public function getUser(int $uid) + { + $user = $this->logic->userInfo($uid); + return [ + 'id' => $user->id, + 'name' => $user->name, + 'position' => $user->position, + 'socialize' => $user->socialize, + 'socialize_pic' => $user->socialize_pic, + 'country_id' => $user->country_id, + 'country_txt' => Country::where('id',$user->country_id)->value('cn_addr'), + 'avatar' => $user->avatar, + 'phone' => $user->phone, + 'email' => $user->email, + 'status' => $user->status, + 'roles' => $user->roles->pluck('name') + ]; + } + /** * 获取用户信息(包括菜单和权限) */ diff --git a/config/route.php b/config/route.php index 3563589..737ce1b 100644 --- a/config/route.php +++ b/config/route.php @@ -40,6 +40,7 @@ Route::group('/common', function () { Route::group('/user', function () { Route::any('/info', [app\common\controller\UserController::class, 'info']); + Route::any('/get', [app\common\controller\UserController::class, 'getUser']); }); Route::group('/preset', function () { From c09bf049fb3841332d31f3de9aaeaaeb3818b419 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 15:15:37 +0800 Subject: [PATCH 19/25] =?UTF-8?q?=E5=AE=A2=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UserController.php | 3 +- app/common/service/UserService.php | 8 +- app/crm/controller/CustomerController.php | 4 +- app/crm/model/Customer.php | 55 ----------- app/crm/service/CustomerService.php | 110 ++++++++++++++++++++-- 5 files changed, 114 insertions(+), 66 deletions(-) diff --git a/app/common/controller/UserController.php b/app/common/controller/UserController.php index fc8413d..c32f153 100644 --- a/app/common/controller/UserController.php +++ b/app/common/controller/UserController.php @@ -29,7 +29,8 @@ class UserController extends BaseController { try { $uid = $request->user->uid; - $result = (new UserService())->getUser($uid); + $corp_abbr = $request->basic_data['corp_abbr']; + $result = (new UserService())->getUser($uid,$corp_abbr); return $this->success($result, '获取用户信息'); } catch (\Throwable $e) { return $this->error($e->getMessage()); diff --git a/app/common/service/UserService.php b/app/common/service/UserService.php index f5daf14..c55c4cc 100644 --- a/app/common/service/UserService.php +++ b/app/common/service/UserService.php @@ -3,6 +3,7 @@ namespace app\common\service; use app\common\logic\UserLogic; +use app\common\model\Corp; use app\crm\model\Country; class UserService @@ -43,19 +44,24 @@ class UserService /** * 获取用户信息(包括菜单和权限) */ - public function getUser(int $uid) + public function getUser(int $uid, $corp_abbr) { $user = $this->logic->userInfo($uid); + $corp_name = Corp::where('abbr', $corp_abbr)->value('name'); + $ossservice = new OssService(); return [ 'id' => $user->id, 'name' => $user->name, 'position' => $user->position, 'socialize' => $user->socialize, 'socialize_pic' => $user->socialize_pic, + 'socialize_pic_full' => (!empty($user->socialize_pic))?$ossservice->generatePrivateUrl($user->socialize_pic):'', 'country_id' => $user->country_id, 'country_txt' => Country::where('id',$user->country_id)->value('cn_addr'), 'avatar' => $user->avatar, + 'avatar_full' => (!empty($user->avatar))?$ossservice->generatePrivateUrl($user->avatar):'', 'phone' => $user->phone, + 'corp_name' => $corp_name, 'email' => $user->email, 'status' => $user->status, 'roles' => $user->roles->pluck('name') diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 50e85b9..775666f 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -166,7 +166,7 @@ class CustomerController extends BaseController return $this->success($this->page($result)); } catch (\Throwable $e) { - return $this->error($e->getMessage()); + return $this->error($e->getMessage().$e->getFile().$e->getLine()); } } @@ -217,7 +217,7 @@ class CustomerController extends BaseController return $this->error('记录不存在'); } - $res = Customer::getCustomer($res, $request, true); + $res = CustomerService::getCustomer($res, 'zh_CN', true); return $this->success($res); } diff --git a/app/crm/model/Customer.php b/app/crm/model/Customer.php index f28fb11..af5c571 100644 --- a/app/crm/model/Customer.php +++ b/app/crm/model/Customer.php @@ -58,61 +58,6 @@ class Customer extends Model return $date->format(Carbon::parse($date)->toDateTimeString()); } - /** - * @param $customer - * @param $request - * @param $tag 是否返回客户标签 - * @return mixed - */ - public static function getCustomer($customer, $request, $tag = false) - { - $language = 'zh_CN' ?: 'en'; - $customer['grade_txt'] = Util::language($language, Constants::GRADE_EN[$customer['grade']], Constants::GRADE_ZH[$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'] = Util::language($language,'Following','跟进中','Продолжение'); - }elseif ($customer['grade']<5) { - $customer['follow'] = 1; - $customer['follow_txt'] = Util::language($language,'transacted','已成交','Транзакция завершена'); - }else{ - $customer['follow'] = 2; - $customer['follow_txt'] = Util::language($language,'lost','已流失','Потерянный'); - } - - $where = [ - 'customer_id' => $customer['id'] - ]; - $begin_follow = Follow::select('id','created_at','updated_at') - ->where($where) - ->min('created_at'); - - - $customer['begin_follow'] = Util::timeTotDate($begin_follow); -// $customer['created_at'] = Util::timeTotDate($customer['created_at']); -// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']); - - $customer = Util::formatDate($customer,['follow_last']); -// $nameLang = $language=='en'?'name_en':($language=='ru'?'name_ru':'name'); - $nameLang = '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; - } - /** * 客户的标签 */ diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index f085f44..648c0d8 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -3,7 +3,13 @@ namespace app\crm\service; use app\crm\logic\CustomerLogic; +use app\crm\model\CarType; +use app\crm\model\Channel; +use app\crm\model\Country; use app\crm\model\Customer; +use app\crm\model\Follow; +use app\crm\utils\Util; +use config\constants\Constants; class CustomerService { @@ -13,18 +19,108 @@ class CustomerService // $perPage = $request->input('per_page', 10); $perPage = $params['size'] ?? 10; $page = $params['current'] ?? 1; + $keyword = $params['keyword'] ?? ''; + $recycle = $params['recycle'] ?? ''; + $grade = $params['grade'] ?? ''; $where = []; $user_id =$params['user_id']; if(empty($user_id) || $user_id == 0){ $where[] = ['user_id', '=', $user_id]; } - $user = Customer::where($where)->paginate($perPage, ['*'], 'page', $page); -// $user = Customer::with('user')->where($where)->paginate($perPage, ['*'], 'page', $page); -// $user = $user->toArray(); -// foreach ($user['data'] as &$item) { -// unset($item['password']); -// } - return $user; + + $seas = $params['seas'] ?? ''; + if($seas == 'seas'){ + $where[] = ['user_id', 0]; + } + if($recycle == 'recycle'){ + $where[] = ['user_id', $user_id]; + } + + $query = Customer::where($where); + + if(!empty($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); + } + + if ($recycle == 'recycle' || $seas == 'seas') { + $query->onlyTrashed(); + } + + $customer = Customer::where($where)->paginate($perPage, ['*'], 'page', $page); + foreach ($customer as &$item) { + $item = $this->getCustomer($item); + if($seas == 'seas'){ + $item['seas_time'] = time()-strtotime($item['deleted_at']); + } + } + unset($item); + + return $customer; + } + + + /** + * @param $customer + * @param $request + * @param $tag 是否返回客户标签 + * @return mixed + */ + public static function getCustomer($customer, $language = 'zh_CN', $tag = false) + { + $customer['grade_txt'] = Util::language($language, Constants::GRADE_EN[$customer['grade']], Constants::GRADE_ZH[$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'] = Util::language($language,'Following','跟进中','Продолжение'); + }elseif ($customer['grade']<5) { + $customer['follow'] = 1; + $customer['follow_txt'] = Util::language($language,'transacted','已成交','Транзакция завершена'); + }else{ + $customer['follow'] = 2; + $customer['follow_txt'] = Util::language($language,'lost','已流失','Потерянный'); + } + + $where = [ + 'customer_id' => $customer['id'] + ]; + $begin_follow = Follow::select('id','created_at','updated_at') + ->where($where) + ->min('created_at'); + + + $customer['begin_follow'] = Util::timeTotDate($begin_follow); +// $customer['created_at'] = Util::timeTotDate($customer['created_at']); +// $customer['updated_at'] = Util::timeTotDate($customer['updated_at']); + + $customer = Util::formatDate($customer,['follow_last']); + $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; } From cc98a78ad6a17c576c1336919aba355d78f302ae Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 15:43:51 +0800 Subject: [PATCH 20/25] =?UTF-8?q?=E8=B7=9F=E8=BF=9B=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/FollowService.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/crm/service/FollowService.php b/app/crm/service/FollowService.php index b97d5f1..0d3fd8e 100644 --- a/app/crm/service/FollowService.php +++ b/app/crm/service/FollowService.php @@ -29,7 +29,7 @@ class FollowService //跟进id $id = $param['id'] ?? null; - if (!Util::isEmpty($id)) { + if (!empty($id)) { $where['id'] = $id; } @@ -58,7 +58,7 @@ class FollowService $ossservice = new OssService(); $oss_picture = $ossservice->generatePrivateUrl($follow['picture'], 86400); } - $follow['oss_picture'] = $oss_picture; + $follow['picture_full'] = $oss_picture; // $follow = Util::formatDate($follow); return $follow; } From edb8c5e9e2611796e3853f48899a2220461e5962 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 16:45:16 +0800 Subject: [PATCH 21/25] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AF=86=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UserController.php | 19 +++++++++++++++++++ app/common/logic/UserLogic.php | 11 +++++++++++ app/common/service/UserService.php | 20 +++++++++++++++++++- app/crm/service/CustomerService.php | 21 ++++++++++++++++++++- config/route.php | 1 + 5 files changed, 70 insertions(+), 2 deletions(-) diff --git a/app/common/controller/UserController.php b/app/common/controller/UserController.php index c32f153..2a22145 100644 --- a/app/common/controller/UserController.php +++ b/app/common/controller/UserController.php @@ -56,4 +56,23 @@ class UserController extends BaseController } } + /** + * 修改密码 + * @param Request $request + * @return \support\Response + * @throws \Random\RandomException + */ + public function savePassword(Request $request) + { + try { + $uid = $request->user->uid; + $data = $request->all(); + $result = (new UserService())->savePassword($uid,$data);; + return $this->success($result, '编辑成功'); + } catch (\Throwable $e) { + return $this->error($e->getMessage()); + } + } + + } \ No newline at end of file diff --git a/app/common/logic/UserLogic.php b/app/common/logic/UserLogic.php index 28ebf6e..4b58247 100644 --- a/app/common/logic/UserLogic.php +++ b/app/common/logic/UserLogic.php @@ -42,4 +42,15 @@ class UserLogic return $user; } + /** + * 修改密码 + */ + public function savePassword(int $uid, array $data) + { + $password = password_hash($data['password_new'], PASSWORD_DEFAULT); + $res = User::where('id',$uid)->update(['password' => $password]); + + return $res; + } + } \ No newline at end of file diff --git a/app/common/service/UserService.php b/app/common/service/UserService.php index c55c4cc..85684d3 100644 --- a/app/common/service/UserService.php +++ b/app/common/service/UserService.php @@ -4,7 +4,9 @@ namespace app\common\service; use app\common\logic\UserLogic; use app\common\model\Corp; +use app\common\model\User; use app\crm\model\Country; +use support\exception\BusinessException; class UserService { @@ -69,7 +71,7 @@ class UserService } /** - * 获取用户信息(包括菜单和权限) + * 编辑用户信息 */ public function edit(int $uid, array $data) { @@ -81,4 +83,20 @@ class UserService $user = $this->logic->edit($uid,$data); return $user; } + + /** + * 修改用户密码 + */ + public function savePassword(int $uid, array $data) + { + // 对密码进行哈希处理 + $password = $data['password']; + $user = User::find($uid); + if (!password_verify($password, $user->password)) { + throw new BusinessException('密码错误'); + } + + $user = $this->logic->savePassword($uid,$data); + return $user; + } } \ No newline at end of file diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 648c0d8..51737b1 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -21,7 +21,8 @@ class CustomerService $page = $params['current'] ?? 1; $keyword = $params['keyword'] ?? ''; $recycle = $params['recycle'] ?? ''; - $grade = $params['grade'] ?? ''; + $follow = $params['follow'] ?? ''; + $follow_last = $params['follow_last'] ?? ''; $where = []; $user_id =$params['user_id']; if(empty($user_id) || $user_id == 0){ @@ -36,6 +37,24 @@ class CustomerService $where[] = ['user_id', $user_id]; } + + $grade = []; + if (!Util::isEmpty($follow) && $follow == 0) { + $where[] = ['grade', '<=', 2]; + } elseif (!Util::isEmpty($follow) && $follow == 1) { + $grade = [3, 4]; + } elseif (!Util::isEmpty($follow) && $follow == 2) { + $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')]; + } + $query = Customer::where($where); if(!empty($tagId)){ diff --git a/config/route.php b/config/route.php index 737ce1b..d0c9db4 100644 --- a/config/route.php +++ b/config/route.php @@ -114,5 +114,6 @@ Route::group('/crm', function () { Route::any('/user/edit', [app\common\controller\UserController::class, 'edit']); + Route::any('/user/savePassword', [app\common\controller\UserController::class, 'savePassword']); }); From c87643c3ea50d7810a08ad20996762ac7cb054bb Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 17:08:58 +0800 Subject: [PATCH 22/25] =?UTF-8?q?=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/CustomerController.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/crm/controller/CustomerController.php b/app/crm/controller/CustomerController.php index 775666f..8eee3ac 100644 --- a/app/crm/controller/CustomerController.php +++ b/app/crm/controller/CustomerController.php @@ -238,10 +238,10 @@ class CustomerController extends BaseController if (Util::isEmpty($country_id)) { // return $this->error('country_id'.trans('not_null')); } - $car_type_id = Util::getParam($request, 'car_type_id'); - if (Util::isEmpty($car_type_id)) { - return $this->error(trans('car_type_not_null')); - } +// $car_type_id = Util::getParam($request, 'car_type_id'); +// if (Util::isEmpty($car_type_id)) { +// return $this->error(trans('car_type_not_null')); +// } $contacts = Util::getParam($request, 'contacts'); $email = Util::getParam($request, 'email'); $phone = Util::getParam($request, 'phone'); @@ -358,7 +358,8 @@ class CustomerController extends BaseController } $userId = $request->user->uid; //$created_at = $request->user['created_at']; - $created_at = User::find($userId)->created_at; + $created_at = User::find($userId)->value('created_at'); + $created_at = strtotime($created_at); $day = ceil((time() - $created_at + 1) / 60 / 60 / 24); $where[] = ['user_id', '=', $userId]; $where[] = ['corp_abbr', '=', $request->basic_data['corp_abbr']]; From f982dfee95083a70ba88c953fc66863e932ad2d8 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Fri, 18 Jul 2025 17:55:35 +0800 Subject: [PATCH 23/25] =?UTF-8?q?=E6=A0=87=E7=AD=BE=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E5=AE=A2=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/controller/TagGroupController.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/crm/controller/TagGroupController.php b/app/crm/controller/TagGroupController.php index 3cf24e1..2ac30e8 100644 --- a/app/crm/controller/TagGroupController.php +++ b/app/crm/controller/TagGroupController.php @@ -3,8 +3,10 @@ namespace app\crm\controller; use app\crm\controller\BaseController; +use app\crm\model\Customer; use app\crm\model\CustomerTag; use app\crm\model\TagGroup; +use app\crm\model\Tag; use app\crm\utils\Util; use config\constants\Constants; use support\Request; @@ -15,6 +17,8 @@ class TagGroupController extends BaseController // 列表 public function list(Request $request) { + $uid = $request->user->uid; + $scene = $request->input("scene"); $list = TagGroup::with('tags')->get(); $languageArr = Constants::LANGUAGE; $language = 'zh_CN'; @@ -28,6 +32,10 @@ class TagGroupController extends BaseController if (in_array($language, $languageArr)) { $tag['name'] = $tag['names'][$language]; } + if($scene == 'customers'){ + // 统计每个标签关联的客户数量,增加user_id条件 + $tag['count'] = $tag->customers()->where('user_id', $uid)->count(); + } } } From 81a6b17f809e87b026609b8fac2dd875fa35f2e9 Mon Sep 17 00:00:00 2001 From: "HESU\\HESU" <1696136552@qq.com> Date: Mon, 21 Jul 2025 14:29:58 +0800 Subject: [PATCH 24/25] =?UTF-8?q?=E6=A0=87=E7=AD=BE=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E5=AE=A2=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/crm/service/CustomerService.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/crm/service/CustomerService.php b/app/crm/service/CustomerService.php index 51737b1..e411984 100644 --- a/app/crm/service/CustomerService.php +++ b/app/crm/service/CustomerService.php @@ -23,6 +23,7 @@ class CustomerService $recycle = $params['recycle'] ?? ''; $follow = $params['follow'] ?? ''; $follow_last = $params['follow_last'] ?? ''; + $tagId = $params['tag_id'] ?? []; $where = []; $user_id =$params['user_id']; if(empty($user_id) || $user_id == 0){ @@ -58,9 +59,16 @@ class CustomerService $query = Customer::where($where); if(!empty($tagId)){ - $query->whereHas('tags', function($query) use ($tagId){ - $query->where('tag.id', $tagId); - }); + //查询有$tagId 里任意一个标签的客户 + //$query->whereHas('tags', function($query) use ($tagId){ + // $query->whereIn ('tag.id', $tagId); + //}); + //查询有$tagId 里所有标签的客户 + foreach ($tagId as $id) { + $query->whereHas('tags', function($query) use ($id){ + $query->where('tag.id', $id); + }); + } } if (!Util::isEmpty($keyword)) { $query->where(function ($query) use ($keyword) { From a57fb6132ca86c1c00e70f64dbcae6acb25e5717 Mon Sep 17 00:00:00 2001 From: mzl Date: Mon, 21 Jul 2025 14:50:16 +0800 Subject: [PATCH 25/25] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=8F=9C=E5=8D=95url?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/logic/PermLogic.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/common/logic/PermLogic.php b/app/common/logic/PermLogic.php index 703737c..674fbc8 100644 --- a/app/common/logic/PermLogic.php +++ b/app/common/logic/PermLogic.php @@ -102,7 +102,7 @@ class PermLogic // component 字段规则: // 1. 存在子菜单,固定 '/index/index' // 2. 否则为当前完整路径(或其它你想要的) - $componentValue = $hasChildrenMenu && !$node->url ? '/index/index' : $currentPath; + $componentValue = ($hasChildrenMenu && !$node->url && $node->type !== 'directory') ? '/index/index' : $currentPath; $tree[] = [ 'id' => $node->id,