all(); $mobile = trim((string)($all['mobile'] ?? '')); $idcard = trim((string)($all['idcard'] ?? '')); if ($mobile === '' && $idcard === '') { return $this->fail([ResponseCode::ERROR_PARAMETER, '手机号或证件号至少填写一个']); } $latest = Visit::where('user_id', $this->getUserId()) ->where(function ($q) use ($mobile, $idcard) { if ($mobile !== '') { $q->orWhere('mobile', $mobile); } if ($idcard !== '') { $q->orWhere('idcard', $idcard); } }) ->orderByDesc('id') ->first(); if (empty($latest)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '未找到过往拜访记录']); } return $this->success([ 'name' => $latest->name ?? '', 'mobile' => $latest->mobile ?? '', 'credent' => $latest->credent ?? 1, 'idcard' => $latest->idcard ?? '', 'company_name' => $latest->company_name ?? '', 'cda' => $latest->cda ?? '', 'cars' => $latest->cars ?? [], ]); } /** * @OA\Post( * path="/api/mobile/visit/visit-save", * tags={"小程序-保存拜访"}, * summary="更新", * description="", * @OA\Parameter(name="id", in="query", @OA\Schema(type="int"), required=true, description="Id(存在更新,不存在新增)"), * @OA\Parameter(name="date", in="query", @OA\Schema(type="string"), required=true, description="到访日期"), * @OA\Parameter(name="visit_time_id", in="query", @OA\Schema(type="string"), required=false, description="时间段id"), * @OA\Parameter(name="visit_area_id", in="query", @OA\Schema(type="string"), required=false, description="区域id"), * @OA\Parameter(name="reason", in="query", @OA\Schema(type="string"), required=false, description="事由"), * @OA\Parameter(name="remark", in="query", @OA\Schema(type="string"), required=false, description="备注"), * @OA\Parameter(name="name", in="query", @OA\Schema(type="string"), required=false, description="名字"), * @OA\Parameter(name="mobile", in="query", @OA\Schema(type="string"), required=false, description="电话"), * @OA\Parameter(name="credent", in="query", @OA\Schema(type="string"), required=false, description="证件类型1身份证2护照"), * @OA\Parameter(name="idcard", in="query", @OA\Schema(type="string"), required=false, description="证件号码"), * @OA\Parameter(name="company_name", in="query", @OA\Schema(type="string"), required=false, description="单位名称"), * @OA\Parameter(name="follw_people", in="query", @OA\Schema(type="string"), required=false, description="随访人员"), * @OA\Parameter(name="cars", in="query", @OA\Schema(type="string"), required=false, description="到访车辆"), * @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string"), required=false, description="开始时间"), * @OA\Parameter(name="end_date", in="query", @OA\Schema(type="string"), required=false, description="结束时间"), * @OA\Parameter(name="accpet_department_id", in="query", @OA\Schema(type="string"), required=false, description="接待部门"), * @OA\Parameter(name="accept_admin_id", in="query", @OA\Schema(type="string"), required=false, description="接待人员"), * @OA\Parameter(name="accompany_id", in="query", @OA\Schema(type="string"), required=false, description="陪同人id"), * @OA\Parameter(name="accompany_department_id", in="query", @OA\Schema(type="string"), required=false, description="陪同人部门id"), * @OA\Parameter(name="plate", in="query", @OA\Schema(type="string"), required=false, description="车牌号"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=false, description="类型1访客2施工3车辆"), * @OA\Parameter(name="long_time", in="query", @OA\Schema(type="string"), required=false, description="是否长期0否1是"), * @OA\Parameter(name="audit_status", in="query", @OA\Schema(type="string"), required=false, description="审核状态-1待学习0待审核1通过(待进厂)2驳回3已进厂4已离厂"), * @OA\Parameter(name="file", in="query", @OA\Schema(type="string"), required=false, description="附件数组"), * @OA\Parameter(name="accept_goods_admin_id", in="query", @OA\Schema(type="string"), required=false, description="收货人id"), * @OA\Parameter(name="work_start_time", in="query", @OA\Schema(type="string"), required=false, description="施工开始时间"), * @OA\Parameter(name="work_end_time", in="query", @OA\Schema(type="string"), required=false, description="施工结束时间"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function visitSave() { $all = \request()->all(); $messages = [ 'name.required' => '名称必填', 'visit_area_id.required' => '区域id必填', 'accept_admin_id.required' => '接待人必填' ]; $validator = Validator::make($all, [ 'name' => 'required', 'visit_area_id' => 'required', 'accept_admin_id' => 'required', 'accompany_id' => 'required' ], $messages); if ($validator->fails()) { return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } DB::beginTransaction(); try { if (isset($all['id'])) { $model = Visit::find($all['id']); } else { $model = new Visit(); $all['user_id'] = $this->getUserId(); $all['code'] = randStr(6, true); } $model->fill($all); $model->save(); // 创建时候审核流程写入 $area = VisitArea::find($all['visit_area_id']); if ($area->audit_admin && !isset($all['id'])) { // 被访问做第一级审核 VisitAudit::create([ 'visit_id' => $model->id, 'audit_admin_id' => $all['accompany_id'], 'status' => 0, 'level' => 0 ]); // 其他按设置审核 $audit_admin = collect($area->audit_admin)->sortBy('level'); foreach ($audit_admin as $key => $item) { if (empty($item['admin_id'])) { // 上级审核 $admin = Admin::find($all['accept_admin_id']); if (empty($admin->department_id)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '接待人部门不存在']); } $department = Department::find($admin->department_id); if (empty($department->manager_id)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '接待人部门不存在负责人']); } $item['admin_id'] = $department->manager_id; } // 判断不能重复 if ($item['admin_id'] == $all['accept_admin_id']) { continue; } VisitAudit::create([ 'visit_id' => $model->id, 'audit_admin_id' => $item['admin_id'], 'status' => 0, 'level' => $item['level'] + 1 ]); } } VisitLog::add('', $this->getUser(), $model->id, isset($all['id']) ? '更新拜访记录' : '新增拜访记录'); // 通知,发订阅消息给当前用户 $visitTime = VisitTime::find($all['visit_time_id']); // 被访人信息 $acceptAdmin = Admin::find($all['accept_admin_id']); $accpetDepartment = Department::find($all['accpet_department_id']); $templateData = [ 'date1' => [ 'value' => $all['date'] ], 'name2' => [ 'value' => $all['name'] ], 'phone_number3' => [ 'value' => $all['mobile'] ], 'name4' => [ 'value' => $acceptAdmin->name ?? '', ], 'thing6' => [ 'value' => $accpetDepartment->name ?? '' ], ]; Visit::subMsg('DmzNRREPFdZrMWconNDdbj_ebtVPRWufq27kRQ25eNg', $this->getUser()->openid, $templateData, $model->id); // 短信通知被访人 $vars = ['date' => $all['date'], 'name' => $all['name'], 'uname' => ($acceptAdmin->name ?? '')]; $template_id = 'QXPs33'; sms($acceptAdmin->mobile, $vars, $template_id); // 短信通知第一个审核人 VisitAudit::smsNextAudit($model, -1); DB::commit(); return $this->success('更新成功'); } catch (\Exception $exception) { DB::rollBack(); return $this->fail([$exception->getCode(), $exception->getMessage()]); } } /** * @OA\Get( * path="/api/mobile/visit/get-ask", * tags={"小程序-获取学习内容"}, * summary="列表", * description="", * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=false, description="类型1访客2施工3车辆"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function getAsk() { $all = \request()->all(); $messages = [ 'type.required' => '类型必填' ]; $validator = Validator::make($all, [ 'type' => 'required' ], $messages); if ($validator->fails()) { return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } $detail = Study::with('asks')->where('type', $all['type'])->first(); if (empty($detail)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '该访客类型暂无学习资料,请联系管理员配置']); } $mobile = trim((string)($all['mobile'] ?? '')); if ($mobile === '') { $mobile = trim((string)(optional(User::find($this->getUserId()))->mobile ?? '')); } $isVip = $mobile !== '' && VipCustomer::where('mobile', $mobile)->where('status', 1)->exists(); $payload = $detail->toArray(); $payload['is_vip'] = $isVip ? 1 : 0; // VIP:仅观看资料,不参与问答;非 VIP:必须答题 $payload['quiz_required'] = $isVip ? 0 : 1; return $this->success($payload); } /** * @OA\Get( * path="/api/mobile/visit/visit-area", * tags={"小程序-拜访区域"}, * summary="列表", * description="", * @OA\Parameter(name="keyword", in="query", @OA\Schema(type="string"), required=false, description="关键词"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function visitArea() { $all = request()->all(); $list = VisitArea::where(function ($query) use ($all) { if (isset($all['keyword'])) { $query->where('name', 'like', '%' . $all['keyword'] . '%'); } })->get(); return $this->success($list); } /** * @OA\Get( * path="/api/mobile/visit/visit-time", * tags={"小程序-拜访时间段"}, * summary="列表", * description="", * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function visitTime() { $all = request()->all(); $list = VisitTime::where(function ($query) use ($all) { })->get(); return $this->success($list); } /** * @OA\Get( * path="/api/mobile/visit/ask-log", * tags={"小程序-学习"}, * summary="获取学习记录", * description="", * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=true, description="类型"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function askLog() { $type = request('type'); // 按「访客类型」分别记录:type=1/2/3 各自一条有效学习;过期后需重新学习并答题(VIP 为仅观看记录) $log = StudyLog::where('type', $type)->where('user_id', $this->getUserId())->orderBy('id', 'desc')->first(); if (empty($log)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '未学习']); } $diff = Carbon::parse($log->created_at)->diffInDays(Carbon::now()); if ($diff > $log->expire_day) { return $this->fail([ResponseCode::ERROR_BUSINESS, '学习已过期,请重新学习']); } return $this->success("学习有效中"); } /** * @OA\Post( * path="/api/mobile/visit/ask-save", * tags={"小程序-学习"}, * summary="保存学习记录", * description="", * @OA\Parameter(name="content", in="query", @OA\Schema(type="string"), required=true, description="内容json"), * @OA\Parameter(name="ask", in="query", @OA\Schema(type="string"), required=true, description="问题json"), * @OA\Parameter(name="expire_day", in="query", @OA\Schema(type="string"), required=true, description="有效天数"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=true, description="类型 init型"), * @OA\Parameter(name="name", in="query", @OA\Schema(type="string"), required=true, description="名字"), * @OA\Parameter(name="idcard", in="query", @OA\Schema(type="string"), required=true, description="身份证"), * @OA\Parameter(name="mobile", in="query", @OA\Schema(type="string"), required=true, description="手机号"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="暂无" * ) * ) */ public function askSave() { $all = request()->all(); $type = $all['type'] ?? null; if ($type === null || $type === '') { return $this->fail([ResponseCode::ERROR_PARAMETER, '类型必填']); } $study = Study::where('type', $type)->first(); if (empty($study)) { return $this->fail([ResponseCode::ERROR_BUSINESS, '该访客类型暂无学习资料配置']); } $mobile = trim((string)($all['mobile'] ?? '')); if ($mobile === '') { $mobile = trim((string)(optional(User::find($this->getUserId()))->mobile ?? '')); } $isVip = $mobile !== '' && VipCustomer::where('mobile', $mobile)->where('status', 1)->exists(); // 有效期以资料配置为准(天),不信任客户端篡改 $expireDay = $study->expire_day; if ($expireDay === null || $expireDay === '') { $expireDay = $all['expire_day'] ?? 180; } $all['expire_day'] = (int) $expireDay; if (isset($all['ask']) && is_string($all['ask'])) { $all['ask'] = json_decode($all['ask'], true); } if (isset($all['content']) && is_string($all['content'])) { $all['content'] = json_decode($all['content'], true); } if ($isVip) { $all['watch_only'] = 1; $all['ask'] = []; $all['content'] = $all['content'] ?? []; } else { $all['watch_only'] = 0; $ask = $all['ask'] ?? null; if (empty($ask) || !is_array($ask) || count($ask) === 0) { return $this->fail([ResponseCode::ERROR_BUSINESS, '请完成答题后再提交']); } } $model = new StudyLog(); $all['user_id'] = $this->getUserId(); $model->fill($all); $model->save(); return $this->success($model); } /** * @OA\Post( * path="/api/mobile/visit/idcard-check", * tags={"小程序-学习"}, * summary="按类型校验证件学习有效性", * description="", * @OA\Parameter(name="idcard", in="query", @OA\Schema(type="string"), required=true, description="身份证数组"), * @OA\Parameter(name="type", in="query", @OA\Schema(type="string"), required=true, description="访客类型1普通2施工3物流"), * @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"), * @OA\Response( * response="200", * description="返回 missing(未学习), expired(已过期), invalid(合并) 三个数组" * ) * ) */ public function idcardCheck() { $all = request()->all(); $messages = [ 'idcard.required' => '身份证数组必填', 'type.required' => '访客类型必填', ]; $validator = Validator::make($all, [ 'idcard' => 'required', 'type' => 'required', ], $messages); if ($validator->fails()) { return $this->fail([ResponseCode::ERROR_PARAMETER, implode(',', $validator->errors()->all())]); } $type = $all['type']; $missingIdcards = []; $expiredIdcards = []; foreach ((array)$all['idcard'] as $idcard) { $idcard = trim((string)$idcard); if ($idcard === '') { continue; } $log = StudyLog::where('idcard', $idcard) ->where('type', $type) ->orderBy('id', 'desc') ->first(); if (empty($log)) { $missingIdcards[] = $idcard; continue; } $diff = Carbon::parse($log->created_at)->diffInDays(Carbon::now()); if ($diff > (int)$log->expire_day) { $expiredIdcards[] = $idcard; } } $missingIdcards = array_values(array_unique($missingIdcards)); $expiredIdcards = array_values(array_unique($expiredIdcards)); return $this->success([ 'missing' => $missingIdcards, 'expired' => $expiredIdcards, // 兼容旧前端判断 'invalid' => array_values(array_unique(array_merge($missingIdcards, $expiredIdcards))), ]); } }