$mall_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]] ]; if (!empty($params['user_id'])) { $where[] = ['user_id' => $params['user_id']]; } elseif (!empty($params['keyword'])) { $uids = User::find()->where(['mall_id' => $mall_id]) ->andWhere(['status' => StatusEnum::ENABLED]) ->andWhere(['or', ['like', 'nickname', $params['keyword']], ['like', 'mobile', $params['keyword']]]) ->select('id')->column(); if (!empty($uids)) { $where[] = ['user_id' => $uids]; } else { return []; } } // 指定多个用户 if (!empty($params['user_ids'])) { $where[] = ['user_id' => $params['user_ids']]; } if (isset($params['user_id_arr'])) { $where[] = ['user_id' => $params['user_id_arr']]; } // 真实姓名 if (!empty($params['name'])) { $where[] = ['like', 'name', $params['name']]; } // 手机号 if (!empty($params['mobile'])) { $where[] = ['like', 'mobile', $params['mobile']]; } // 所在地址 if (!empty($params['address'])) { $where[] = ['like', 'address', $params['address']]; } // 审核状态 if (!empty($params['check_status'])) $where[] = ['check_status' => $params['check_status']]; // 指定门店 if (!empty($params['store_id'])) { $where[] = ['store_id' => $params['store_id']]; } // 时间区间 if (!empty($params['date_start'])) $where[] = ['>=', 'created_at', strtotime($params['date_start'])]; if (!empty($params['date_end'])) $where[] = ['<=', 'created_at', strtotime($params['date_end'])]; if (!empty($params['is_store'])) { // 仅限门店 $where[] = ['>', 'store_id', '0']; } // 年龄区间 if (!empty($params['age_min'])) $where[] = ['>=', 'age', $params['age_min']]; if (!empty($params['age_max'])) $where[] = ['<=', 'age', $params['age_max']]; // 性别 if (!empty($params['gender'])) $where[] = ['gender' => $params['gender']]; if (!empty($params['store_status'])) $where[] = ['store_status' => $params['store_status']]; if (!empty($params['is_working'])) $where[] = ['is_working' => $params['is_working']]; // 字段 $select = 'id, mall_id, level, name, mobile, created_at, updated_at, idcard, idcard_front, idcard_back, address, longitude, latitude, '. 'qualification_certificate, commission, status, check_status, check_remark, store_id, store_status, service_rating, store_service_rating, store_lng, store_lat, ' . 'gender, age, desc, avatar, is_working, order_num, user_id, store_order_num'; $fields = explode(', ', $select); // 技师经纬度 if (!empty($params['lng']) && !empty($params['lat'])) { $lng = $params['lng']; $lat = $params['lat']; $lng_field = 'longitude'; $lat_field = 'latitude'; } // 门店经纬度 if (!empty($params['store_lng']) && !empty($params['store_lat'])) { $lng = $params['store_lng']; $lat = $params['store_lat']; $lng_field = 'store_lng'; $lat_field = 'store_lat'; } // 距离 if (!empty($lng)) { $fields[] = new Expression("round( 2 * 6378.137 * ASIN( SQRT( POW( SIN( PI() * ({$lng} - $lng_field) / 360 ), 2 ) + COS(PI() * {$lat} / 180) * COS($lat_field * PI() / 180) * POW( SIN( PI() * ({$lat} - $lat_field) / 360 ), 2 ) ) ) ,1) AS distance"); } $ret = ReservationServiceUser::listPage([ 'where' => $where, 'with' => ['user' => function($query) { $query->select(['id', 'nickname', 'avatar_url', 'mobile']); }, 'level' => function($query) { $query->select('id, level, name'); }], 'order' => $params['sort'] ?? 'id desc', // 排序 'limit' => $params['limit'] ?? 10, 'select'=> $fields, ]); $stats = ReservationServiceOrder::find() ->select(['staff_user_id', 'COUNT(*) as order_count']) ->where(['service_status' => 100, 'status' => StatusEnum::ENABLED]) ->groupBy('staff_user_id') ->indexBy('staff_user_id') ->asArray() ->all(); foreach($ret['list'] as $k => $v){ $ret['list'][$k]['order_count'] = $stats[$v['user_id']]['order_count']; } if (!empty(ReservationServiceUser::getStaticError())) return ReservationServiceUser::getStaticCodeError(); return $ret; } /** * @param int $mall_id * @param int $user_id * @param $store * @return true * @throws \Exception */ public function bindStore(int $mall_id, int $user_id, $store) { $user = $this->fetch($mall_id, $user_id); $user->store_id = $store->id; $user->store_lng = $store->longitude; $user->store_lat = $store->latitude; if (!$user->save()) throw new \Exception($user->getErrorMessage()); return true; } /** * @param int $mall_id * @param int $user_id * @param int $store_id * @return ReservationServiceUser * @throws \Exception */ public function fetch(int $mall_id, int $user_id, int $store_id = 0) { $where = [ ['mall_id' => $mall_id], ['user_id' => $user_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]], ['check_status' => StatusEnum::ENABLED] ]; if (!empty($store_id)) $where[] = ['store_id' => $store_id]; /** * @var $user ReservationServiceUser */ $user = ReservationServiceUser::getOne($where); if (empty($user)) throw new \Exception('技师不存在!'); return $user; } /** * @param int $mall_id * @param int $id * @return ReservationServiceUser|string */ public function fetchById(int $mall_id, int $id) { $where = [ ['mall_id' => $mall_id], ['id' => $id], ['status' => StatusEnum::ENABLED], ['check_status' => StatusEnum::ENABLED] ]; $user = ReservationServiceUser::getOne($where, true, [], 'id desc', 'id, created_at, user_id, name, idcard, address, longitude, latitude, qualification_certificate, store_id, gender, age, desc, avatar, is_working, order_num, service_rating,idcard_front,idcard_back'); if (empty($user)) return '技师记录不存在.'; $user['store'] = null; if (!empty($user['store_id'])) { $user['store'] = Store::getOne([ ['id' => $user['store_id']], ['status' => StatusEnum::ENABLED] ], true, [], 'id desc', 'id, store_name, logo_img'); } $user['created_at'] = date('Y-m-d H:i:s', $user['created_at']); $user['qualification_certificate'] = !empty($user['qualification_certificate']) ? Json::decode($user['qualification_certificate']) : []; // 隐藏身份证号码 // 是否可约 // 距离 $user['idcard'] = StringHelper::hideStr($user['idcard'], 1, 16); $is_real_name_authentication = 0;//实名认证 $is_qualification_certificate = 0;//资质证书 if(!empty($user['name']) && !empty($user['idcard']) && !empty($user['idcard_front']) && !empty($user['idcard_back'])){ $is_real_name_authentication = 1; } if(!empty($user['qualification_certificate'])){ $is_qualification_certificate= 1; } $user['is_real_name_authentication'] = $is_real_name_authentication; $user['is_qualification_certificate'] = $is_qualification_certificate; return $user; } /** * 详情 * @param int $mall_id * @param int $user_id * @param int $store_id * @param bool $is_settle * @return mixed * @throws \Exception */ public function detail(int $mall_id, int $user_id, int $store_id = 0, bool $is_settle = false) { $where = [ ['mall_id' => $mall_id], ['user_id' => $user_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]], ]; if (!empty($store_id)) $where[] = ['store_id' => $store_id]; $user = ReservationServiceUser::getOne($where, true, $is_settle ? [] : ['user' => function($query) { $query->select('id, nickname, mobile, avatar_url'); }, 'level' => function($query) { $query->select('id, level, name'); }]); if (empty($user) && !$is_settle) throw new \Exception('记录不存在!'); $is_real_name_authentication = 0;//实名认证 $is_qualification_certificate = 0;//资质证书 if(!empty($user['name']) && !empty($user['idcard']) && !empty($user['idcard_front']) && !empty($user['idcard_back'])){ $is_real_name_authentication = 1; } if(!empty($user['qualification_certificate'])){ $is_qualification_certificate= 1; } $user['is_real_name_authentication'] = $is_real_name_authentication; $user['is_qualification_certificate'] = $is_qualification_certificate; return $user; } /** * 获取基础详情 * @param int $mall_id * @param int $user_id * @return array|mixed * @throws \Exception */ public function customByUserId(int $mall_id, int $user_id) { $where = [ ['mall_id' => $mall_id], ['user_id' => $user_id], ['status' => StatusEnum::ENABLED], ]; $user = ReservationServiceUser::getOne($where, true, [ 'level' => function($query)use($mall_id) { $query->where(['mall_id'=>$mall_id,'status'=>[StatusEnum::ENABLED, StatusEnum::DISABLED]])->select('id, name'); } ], 'id asc', 'level, store_id, commission'); if (empty($user)) throw new \Exception("您还不是技师"); if (!empty($user['store_id'])) { $user['store'] = Store::getOne([ ['id' => $user['store_id']], ['status' => StatusEnum::ENABLED] ], true, [], 'id desc', 'id, store_name, logo_img'); } return $user; } /** * 统计数据 * @param int $mall_id * @param int $user_id * @param int $store_id * @return mixed|null */ public function frontStatisticsByMonth(int $mall_id, int $user_id, int $store_id = 0) { $where = [ ['mall_id' => $mall_id], ['staff_user_id' => $user_id], ['status' => StatusEnum::ENABLED], ['service_status' => [ReservationServiceEnum::RESERVE_ORDER_STATUS_FINISH, ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER]], ['>=', 'created_at', strtotime(date('Y-m', time()))] ]; if (!empty($store_id)) { $where[] = ['store_id' => $store_id]; } return ReservationServiceOrder::getOne($where, true, [], 'id asc', [new Expression("COUNT(*) as order_month")]); } /** * 移除绑定的门店 * @param int $mall_id * @param int $user_id * @param int $store_id * @return true * @throws \Exception */ public function removeStore(int $mall_id, int $user_id, int $store_id) { $where = [ ['mall_id' => $mall_id], ['user_id' => $user_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]], ['store_id' => $store_id] ]; /** * @var $user ReservationServiceUser */ $user = ReservationServiceUser::getOne($where); if (empty($user)) throw new \Exception("技师不存在"); $user->store_id = 0; if (!$user->save()) throw new \Exception($user->getErrorMessage()); return true; } /** * 设置门店上班状态 * @param int $mall_id * @param int $user_id * @param int $store_id * @return true * @throws \Exception */ public function setStoreStatus(int $mall_id, int $user_id, int $store_id = 0) { $user = $this->fetch($mall_id, $user_id, $store_id); $user->store_status = $user->store_status == StatusEnum::ENABLED ? StatusEnum::DISABLED : StatusEnum::ENABLED; if (!$user->save()) throw new \Exception($user->getErrorMessage()); return true; } /** * 创建/修改 * @param int $mall_id * @param int $user_id * @param array $data * @param bool $is_edit * @return mixed|string|true|null */ public function save(int $mall_id, int $user_id, array $data, bool $is_edit = false) { $where = [ ['mall_id' => $mall_id], ['user_id' => $user_id], ['status' => StatusEnum::ENABLED], ]; /** * @var $user ReservationServiceUser */ $user = ReservationServiceUser::getOne($where); if (empty($user)) { if ($is_edit) return '非法操作'; $user = new ReservationServiceUser(); $user->loadDefaultValues(); $user->mall_id = $mall_id; $user->user_id = $user_id; } else { if (!in_array($user->check_status, [ReservationServiceEnum::CHECK_FAILED, ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING])) return '当前状态不可修改'; } if (!$is_edit) { $user->check_status = StatusEnum::DISABLED; $user->created_at = time(); // 每次都设置为最新时间 } else { $user->avatar = $data['avatar']; } if (empty($data['id'])) { $user->idcard = $data['idcard']; $user->idcard_front = $data['idcard_front']; $user->idcard_back = $data['idcard_back']; $user->name = $data['name']; $user->age = $data['age'] ?? 0; $user->gender = $data['gender'] ?? 0; } if (!empty($data['desc'])) { $user->desc = $data['desc']; } $user->qualification_certificate = Json::encode(!empty($data['qualification_certificate']) ? $data['qualification_certificate'] : []); $user->address = $data['address']; $user->longitude = $data['longitude']; $user->latitude = $data['latitude']; $user->mobile = $data['mobile']; $user->avatar = $data['avatar'] ?? ''; if (!empty($data['province'])) { $user->province = $data['province']; } if (!empty($data['city'])) { $user->city = $data['city']; } if (!empty($data['district'])) { $user->district = $data['district']; } if (!$user->save()) return $user->getErrorMessage(); return true; } /** * @param int $mall_id * @param int $user_id * @return true * @throws \Exception */ public function setWorking(int $mall_id, int $user_id) { $user = $this->fetch($mall_id, $user_id); $user->is_working = $user->is_working == StatusEnum::ENABLED ? StatusEnum::DISABLED : StatusEnum::ENABLED; if (!$user->save()) throw new \Exception($user->getErrorMessage()); return true; } /** * 执行审核 * @param int $mall_id * @param array $params * @return true * @throws \Exception */ public function audit(int $mall_id, array $params) { $where = [ ['mall_id' => $mall_id], ['id' => $params['id']], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]], ['check_status' => StatusEnum::DISABLED] ]; /** * @var $user ReservationServiceUser */ $user = ReservationServiceUser::getOne($where); $user->check_status = $params['status']; $user->check_remark = !empty($params['remark']) ? $params['remark'] : ''; $user->level = 1; // 默认为第一个级别 if (!$user->save()) throw new \Exception($user->getErrorMessage()); return true; } /** * 保存接单时间 * @param int $mall_id * @param int $user_id * @param $times_arr * @return */ public function setWorkingTime(int $mall_id, int $user_id,$times_arr) { $trans = Yii::$app->db->beginTransaction(); try{ $user_times = ReservationServiceWorkTime::find()->where(['mall_id' => $mall_id,'user_id' => $user_id,'status'=>StatusEnum::ENABLED]) ->orderBy('week_day asc') ->asArray()->all(); $temp_times = []; foreach($user_times as $val){ $temp_times[$val['week_day']][$val['text']] = $val; } $rows = []; $times_arr_new = []; foreach($times_arr as $time){ $exist = $temp_times[$time['day']][$time['text']] ?? []; if(!$exist){ //新增 $rows[] = [ 'mall_id' => $mall_id, 'user_id' => $user_id, 'week_day' => $time['day'], 'start_time' => $time['start_time'], 'end_time' => $time['end_time'], 'text' => $time['text'], 'created_at' => time(), 'updated_at' => time() ]; } $times_arr_new[] = $time['day'].'_'.$time['text']; } $del_ids = []; foreach($user_times as $val){ $key = $val['week_day'].'_'.$val['text']; if(!in_array($key,$times_arr_new)){ $del_ids[] = $val['id']; } } if (!empty($rows)) { $field = ['mall_id','user_id','week_day','start_time','end_time','text','created_at','updated_at']; $res = \Yii::$app->db->createCommand()->batchInsert(ReservationServiceWorkTime::tableName(), $field, $rows)->execute(); if(!$res) throw new \Exception(ReservationServiceWorkTime::getStaticError()); } if($del_ids){ $res = ReservationServiceWorkTime::updateAll(['status' => StatusEnum::DELETE], ['id'=>$del_ids]); if(!$res) throw new \Exception(ReservationServiceWorkTime::getStaticError()); } $trans->commit(); return true; }catch(\Exception $e){ $trans->rollBack(); return $e->getMessage(); } } /** * 获取技师工作时间 * @param int $mall_id * @param int $user_id * @return array */ public function getWorkingTime(int $mall_id, int $user_id) { $user_times = ReservationServiceWorkTime::find()->where(['mall_id' => $mall_id,'user_id' => $user_id,'status'=>StatusEnum::ENABLED]) ->select('week_day,start_time,end_time,text') ->orderBy('week_day asc') ->asArray()->all(); $temp_times = []; foreach($user_times as $val){ $temp_times[$val['week_day']][] = $val; } return $temp_times; } /** * 技师的项目 * @param int $mall_id * @param int $id * @return array|false|mixed|string */ public function goods(int $mall_id, int $id) { /** * @var $user ReservationServiceUser */ $user = ReservationServiceUser::getOne([ ['mall_id' => $mall_id], ['id' => $id], ['status' => StatusEnum::ENABLED], ['check_status' => StatusEnum::ENABLED] ], false, [], 'id asc', 'user_id'); if (empty($user)) return '技师不存在'; return (new GoodsService())->goods($mall_id, $user->user_id); } /** * 接单排行榜 * @return array|false|mixed|null */ public function orderRank(int $mall_id, int $store_id = 0) { if (!empty($store_id)) $params['store_id'] = $store_id; $params['sort'] = 'order_num desc'; $params['limit'] = 10; $params['page'] = 1; return (new UserService())->page($mall_id, $params); } /** * 服务评分排行榜 * @return array|false|mixed|null */ public function ratingRand(int $mall_id, int $store_id = 0) { if (!empty($store_id)) $params['store_id'] = $store_id; $params['sort'] = 'service_rating desc'; $params['limit'] = 10; $params['page'] = 1; return (new UserService())->page($mall_id, $params); } /** * 数据统计 * @param int $mall_id * @param int $user_id * @param int $store_id * @return array */ public function statisticsByStaff(int $mall_id, int $user_id, int $store_id = 0) { $month = $this->frontStatisticsByMonth($mall_id, $user_id, $store_id); $where = ['mall_id' => $mall_id, 'user_id' => $user_id, 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]; $staff = ReservationServiceUser::findOne($where); $income_month = CommissionLog::find()->where(['user_id' => $user_id]) ->andWhere(['>=', 'created_at', strtotime(date('Y-m', time()))]) ->andWhere(['change_type' => 'add']) ->andWhere(['from_type' => ReservationServiceEnum::ADDONS_NAME]) ->sum('change_num'); return [ 'total_order' => !empty($store_id) ? $staff->store_order_num : $staff->order_num, 'total_commission'=> $staff->commission, 'month_order' => $month['order_month'], 'month_commission'=> !empty($income_month) ? bcmul($income_month, 1, 2) : 0 ]; } /** * @param int $user_id * @param $commission * @return void * @throws \Exception */ public function addCommission(int $user_id, $commission) { $user = ReservationServiceUser::findOne(['user_id' => $user_id]); if($user){ $user->commission += $commission; if (!$user->save()) throw new \Exception($user->getErrorMessage()); } } public function checkScan($params) { $reservation_service_user = ReservationServiceUser::getOne([ ['status' => StatusEnum::ENABLED], ['user_id'=>$params['user_id']], ['mall_id'=>$params['mall_id']], ]); if(empty($reservation_service_user)){ throw new \Exception('技师不存在'); } if(empty($reservation_service_user['store_id'])){ return true; } $store_reserve_settings = StoreReserveSetting::getOne([ ['status' => StatusEnum::ENABLED], ['store_id'=>$reservation_service_user['store_id']], ['mall_id'=>$params['mall_id']], ]); if(empty($store_reserve_settings['setting'])){ return true; } $store_reserve_settings = json_decode($store_reserve_settings['setting'],true); if(!empty($store_reserve_settings['technician_verification_switch'])){ return true; } //关闭后,需要验证技师在门店的排班时间内不能核销 todo $time = time(); $where = [ ['user_id'=>$params['user_id']], ['store_id'=>$reservation_service_user['store_id']], ['mall_id'=>$params['mall_id']], ['date_time'=>strtotime(date('Y-m-d',$time))] ]; $result = StoreReserveTechnicianScheduling::getOne($where); if (empty($result)) { return true; } if(!empty($result['is_all_day'])){ throw new \Exception('该时段无核销权限'); } $where = []; $where[] = [ 'sid'=>$result['id'], ]; $list = StoreReserveTechnicianSchedulingTime::lists([ 'where'=>$where ]); if(empty($list)){ return true; } foreach ($list as $item){ if($item['start_time']<=$time && $time<=$item['end_time']){ throw new \Exception('该时段无核销权限'); } } return true; } public function orderStastics($params) { $where = ['mall_id'=>$params['mall_id'], 'staff_user_id'=>$params['staff_user_id'], 'service_status'=>ReservationServiceEnum::RESERVE_ORDER_STATUS_NORMAL]; $pending_orders = ReservationServiceOrder::find()->where($where)->count(); $where['service_status'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_TALKING; $waiting_service = ReservationServiceOrder::find()->where($where)->count(); $where['service_status'] = ReservationServiceEnum::RESERVE_ORDER_STATUS_UNDERWRITER; $to_be_accepted = ReservationServiceOrder::find()->where($where)->count(); return ['pending_orders'=>$pending_orders??0,'waiting_service'=>$waiting_service??0,'to_be_accepted'=>$to_be_accepted??0]; } }