'婚恋咨询', 'teen' => '青少年心理', 'career' => '职场人际', 'emotion' => '情绪疏导', 'life' => '人生卡点', 'growth' => '成长迷茫', 'single' => '脱单指导', 'breakup' => '分手挽回', 'social' => '社恐咨询', 'depress' => '抑郁焦虑', 'pressure' => '情绪压力', ]; /** * 咨询分类(无需登录,供表单下拉) */ public function categories() { $list = []; foreach (self::$categories as $key => $text) { $list[] = ['key' => $key, 'name' => $text]; } $this->success('', ['list' => $list]); } /** * 心理服务总览:分类 + 我的预约 + 可做测评 + 危机信息 */ public function index() { $userId = $this->auth->id; $this->success('', [ 'categories' => $this->categoriesData(), 'bookings' => $this->bookingList($userId, 5), 'assessments' => AssessmentService::lists('mood', $userId), 'crisis' => AssessmentService::crisis(), 'member' => MemberService::status($userId), 'notice' => '提交后 1 个工作日内,咨询助理会通过电话或微信与你联系', ]); } /** * 提交咨询预约表单 * POST name, mobile, category, prefer_time, description */ public function booking() { $userId = $this->auth->id; $name = mb_substr(trim((string)$this->request->post('name', '')), 0, 30); $mobile = trim((string)$this->request->post('mobile', '')); $category = trim((string)$this->request->post('category', '')); $preferTime = mb_substr(trim((string)$this->request->post('prefer_time', '')), 0, 40); $description = mb_substr(trim((string)$this->request->post('description', '')), 0, 500); if (!$name) { $this->error('请填写你的称呼'); } if (!preg_match('/^1\d{10}$/', $mobile)) { $this->error('请填写正确的 11 位手机号'); } if (!isset(self::$categories[$category])) { $this->error('请选择咨询分类'); } if (!$preferTime) { $this->error('请填写方便联系的时间'); } if (mb_strlen($description) < 5) { $this->error('请简单描述一下你的困扰(至少 5 个字)'); } // 同一用户 10 分钟内不允许重复提交 $recent = Db::name('consult_booking') ->where('user_id', $userId) ->where('createtime', '>', time() - 600) ->where('status', 'pending') ->count(); if ($recent > 0) { $this->error('你已提交过预约,请等待咨询助理联系'); } $id = Db::name('consult_booking')->insertGetId([ 'user_id' => $userId, 'name' => $name, 'mobile' => $mobile, 'category' => $category, 'prefer_time' => $preferTime, 'description' => $description, 'status' => 'pending', 'createtime' => time(), 'updatetime' => time(), ]); $this->success('预约已提交', [ 'id' => (int)$id, 'category' => self::$categories[$category], 'status_text' => '待联系', 'notice' => '咨询助理会在 1 个工作日内联系你,请保持电话畅通', 'hotline' => '12356', ]); } /** * 我的预约列表 */ public function bookings() { $this->success('', ['list' => $this->bookingList($this->auth->id, 20)]); } /** * 取消预约 */ public function bookingCancel() { $id = (int)$this->request->post('id', 0); $row = Db::name('consult_booking')->where('id', $id)->where('user_id', $this->auth->id)->find(); if (!$row) { $this->error('预约不存在'); } if ($row['status'] === 'finished') { $this->error('已完成的预约无法取消'); } Db::name('consult_booking')->where('id', $id)->update([ 'status' => 'canceled', 'updatetime' => time(), ]); $this->success('已取消', ['list' => $this->bookingList($this->auth->id, 20)]); } /** * 测评列表(含价格、是否已购买) */ public function assessments() { $scope = $this->request->param('scope', ''); $this->success('', ['list' => AssessmentService::lists($scope, $this->auth->id)]); } /** * 测评详情(题库) */ public function assessmentDetail() { $data = AssessmentService::detail($this->request->param('id', 0), $this->auth->id); if (!$data) { $this->error('量表不存在'); } $this->success('', $data); } /** * 创建测评订单(付费后解锁) * POST id */ public function assessmentOrder() { $userId = $this->auth->id; $id = (int)$this->request->post('id', 0); $item = Db::name('assessment')->where('id', $id)->where('status', 'normal')->find(); if (!$item) { $this->error('量表不存在'); } $price = (float)($item['price'] ?? 0); if ($item['access'] !== 'pay' || $price <= 0) { $this->success('该测评无需付费', ['paid' => true, 'need_pay' => false]); } if (AssessmentService::isPaid($userId, $id)) { $this->success('已购买,可直接开始测评', ['paid' => true, 'need_pay' => false]); } // 复用未支付订单,避免重复下单 $exist = Db::name('assessment_order') ->where('user_id', $userId) ->where('assessment_id', $id) ->where('pay_status', 'unpaid') ->order('id', 'desc') ->find(); if ($exist) { $orderNo = $exist['order_no']; $orderId = (int)$exist['id']; } else { $orderNo = 'HA' . date('YmdHis') . Random::numeric(4); $orderId = Db::name('assessment_order')->insertGetId([ 'order_no' => $orderNo, 'user_id' => $userId, 'assessment_id' => $id, 'amount' => $price, 'pay_status' => 'unpaid', 'createtime' => time(), ]); } $this->success('订单已创建', [ 'order_id' => $orderId, 'order_no' => $orderNo, 'amount' => $price, 'title' => $item['title'], 'pay_hint' => '支付通道接入中:可联系客服完成支付,支付后即可开始测评', 'paid' => false, 'need_pay' => true, ]); } /** * 提交测评(需先付费) * POST id, answers=[0,1,2...] */ public function assessmentSubmit() { $userId = $this->auth->id; $id = (int)$this->request->post('id', 0); $item = Db::name('assessment')->where('id', $id)->where('status', 'normal')->find(); if (!$item) { $this->error('量表不存在'); } $price = (float)($item['price'] ?? 0); $needPay = $item['access'] === 'pay' && $price > 0; if ($needPay && !AssessmentService::isPaid($userId, $id)) { $this->error('该测评需付费后开始', [ 'need_pay' => 1, 'price' => $price, 'title' => $item['title'], 'pay_hint' => '支付后即可开始测评', ]); } $answers = $this->request->post('answers', ''); $answers = is_array($answers) ? $answers : json_decode(htmlspecialchars_decode((string)$answers, ENT_QUOTES), true); if (!is_array($answers)) { $this->error('请完成全部题目'); } $result = AssessmentService::submit($userId, $id, $answers); if (isset($result['error'])) { $this->error($result['error']); } $this->success('测评完成', $result); } /** * 危机干预信息 */ public function crisis() { $this->success('', AssessmentService::crisis()); } /* ============================================================ * 兼容旧接口:咨询师列表与咨询订单(前台已改为预约表单) * ============================================================ */ public function counselors() { $rows = Db::name('counselor') ->where('status', 'on') ->where('cert_verify', 'passed') ->order('weigh', 'desc') ->limit(20) ->select(); $member = MemberService::can($this->auth->id, 'consult.discount'); $list = array_map(function ($row) use ($member) { return [ 'id' => (int)$row['id'], 'name' => $row['name'], 'emoji' => $row['avatar_emoji'], 'title' => $row['title'], 'intro' => $row['intro'], 'tags' => array_filter(explode(',', $row['tags'])), 'price' => [ 'text' => (float)$row['price_text'], 'voice' => (float)$row['price_voice'], 'video' => (float)$row['price_video'], ], 'discount' => $member ? 0.9 : 1, ]; }, $rows); $this->success('', ['list' => $list]); } /* ============================================================ * 内部方法 * ============================================================ */ protected function categoriesData() { $list = []; foreach (self::$categories as $key => $text) { $list[] = ['key' => $key, 'name' => $text]; } return $list; } protected function bookingList($userId, $limit = 20) { $rows = Db::name('consult_booking') ->where('user_id', $userId) ->order('id', 'desc') ->limit($limit) ->select(); $statusText = ['pending' => '待联系', 'contacted' => '已联系', 'finished' => '已完成', 'canceled' => '已取消']; $list = []; foreach ($rows as $row) { $list[] = [ 'id' => (int)$row['id'], 'name' => $row['name'], 'mobile' => substr($row['mobile'], 0, 3) . '****' . substr($row['mobile'], -2), 'category' => $row['category'], 'category_text' => self::$categories[$row['category']] ?? $row['category'], 'prefer_time' => $row['prefer_time'], 'description' => $row['description'], 'status' => $row['status'], 'status_text' => $statusText[$row['status']] ?? $row['status'], 'create_time' => date('Y-m-d H:i', (int)$row['createtime']), ]; } return $list; } }