where([ 'is_delete' => 0, 'store_id' => $store_id, ]) ->andWhere(['and', ['<=', 'start_time', $now], ['>', 'end_time', $now]]) ->orderBy(['start_time' => SORT_DESC]); $count = (clone $query)->count(); // 避免污染 $pagination = new Pagination([ 'totalCount' => $count, 'pageSize' => $limit, 'page' => $page - 1, ]); $list = $query ->limit($pagination->limit) ->offset($pagination->offset) ->asArray() ->all(); foreach ($list as &$item) { // 查询已报名人数 $item['count'] = EventUser::find() ->where(['event_id' => $item['event_id'], 'is_delete' => 0]) ->count(); $event_user = EventUser::findOne(['user_id' => $user_id, 'is_delete' => 0, 'event_id' => $item['id']]); if (!$event_user) { $is_apply = -1; } else { $is_apply = $event_user->apply_status; } $item['is_apply'] = (int)$is_apply; } // 三种状态的统计 $apply_num = $this->getUserEventCount($user_id, 0, 'start_time', '>', $now); // 申请中 $underway_num = $this->getUserEventCount($user_id, 1, 'end_time', '>=', $now); // 进行中 $finished_num = $this->getUserEventCount($user_id, 1, 'end_time', '<', $now); // 已结束 return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'list' => $list, 'row_count' => (int)$count, 'page_count' => (int)$pagination->getPageCount(), 'apply_num' => (int)$apply_num, 'underway_num' => (int)$underway_num, 'finished_num' => (int)$finished_num, ], ]); } /** * 模块名:getUserEventCount * 代码描述:获取某用户某一状态的报名活动数量 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/14 10:49:38 * * @param int $user_id 用户ID * @param int $apply_status 报名状态:0=申请中,1=已通过 * @param string $time_field 时间字段名(start_time 或 end_time) * @param string $operator 比较操作符:>、>=、< * @param int $timestamp 当前时间 * @return int */ private function getUserEventCount($user_id, $apply_status, $time_field, $operator, $timestamp) { return EventUser::find()->alias('eu') ->select('eu.id') // 提高 count 性能 ->leftJoin(['e' => Event::tableName()], 'e.id = eu.event_id') ->where([ 'eu.user_id' => $user_id, 'eu.is_delete' => 0, 'e.is_delete' => 0, 'eu.apply_status' => $apply_status, ]) ->andWhere([$operator, "e.{$time_field}", $timestamp]) ->count(); } /** * 模块名:event-apply-form * 代码描述:报名自定义表单 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/14 11:31:46 * @param int id 活动ID */ public function actionEventApplyForm() { $user_id = get_user_id(); $store_id = get_store_id(); $id = (int)get_params('id'); if (!$id) { return $this->asJson(['code' => 1, 'msg' => '活动ID不能为空']); } // 查询活动是否存在 $event = Event::find() ->where([ 'id' => $id, 'store_id' => $store_id, 'is_delete' => 0 ]) ->asArray() ->one(); if (!$event) { return $this->asJson(['code' => 1, 'msg' => '活动不存在']); } // 查询用户是否已报名 $eventUser = EventUser::find() ->where([ 'user_id' => $user_id, 'event_id' => $id, 'is_delete' => 0 ]) ->orderBy('id DESC') // 保证拿到最新一条 ->asArray() ->one(); // 情况 1:已报名,审核中或通过审核admin if ($eventUser && $eventUser['apply_status'] == 0) { return $this->asJson(['code' => 1, 'msg' => '您已提交报名,正在审核中', 'eventUser' => $eventUser]); } if ($eventUser && $eventUser['apply_status'] == 1) { return $this->asJson(['code' => 1, 'msg' => '您已提交报名,审核成功']); } // 查询所有表单结构,按 form_type 分组返回 $forms = EventForm::find() ->where([ 'event_id' => $id, 'is_delete' => 0 ]) ->orderBy('sort ASC') ->asArray() ->all(); // 构造分组结构:1=企业,2=机构 $form_group = []; foreach ($forms as $form) { $form_group[$form['form_type']][] = $form; } // 情况 2:首次报名(没有任何报名记录) if (!$eventUser) { return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ // 'event' => $event, 'form' => $form_group, ], 'setting' => $this->getSetting() ]); } // 情况 3:报名被拒绝 → 需要回填 if ($eventUser['apply_status'] == 2) { // 回填数据查询 $details = EventFormDetail::find() ->where([ 'event_id' => $id, 'event_user_id' => $eventUser['id'], 'user_id' => $user_id, 'is_delete' => 0 ]) ->asArray() ->all(); // 组装回填数据映射(按 form_type + key) $detail_map = []; foreach ($details as $item) { $detail_map[$item['form_type']][$item['key']] = $item['value']; } // 将回填数据合并到 form 结构中 foreach ($form_group as $form_type => &$items) { foreach ($items as &$field) { $field['value'] = $detail_map[$form_type][$field['name']] ?? ''; } } return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'form' => $form_group, // 每个字段中已附带 value 'event_user' => $eventUser, 'reason_refusal' => $eventUser['reason_refusal'], ], 'setting' => $this->getSetting() ]); } // 其他未定义情况,兜底处理 return $this->asJson(['code' => 1, 'msg' => '无法处理的报名状态']); } /** * 模块名:event-apply-form-post * 代码描述: 提交活动报名表单 * 作者:WPing丶 * 请求方式: POST * 创建时间:2025/07/14 15:58:20 * @param int id 活动ID * @param int form_type 表单类型(1=企业,2=机构) * @param array form_data 用户填写的表单(字段名为中文名称) * @param string company_code 统一社会信息代码 * @param string company_name 公司名称 * @param string company_address 公司地址 * @param string real_name 姓名 * @param string phone 电话 * @param string identity_card 身份证 */ public function actionEventApplyFormPost() { $user_id = get_user_id(); $store_id = get_store_id(); $id = (int)post_params('id'); $form_type = (int)post_params('form_type', 1); $form_data = post_params('form_data', []); $company_code = post_params('company_code'); $company_name = post_params('company_name'); $company_address = post_params('company_address'); $real_name = post_params('real_name'); $phone = post_params('phone'); $identity_card = post_params('identity_card'); if (!$id || !$form_type || empty($form_data || !$company_code || !$company_name || $company_address || $real_name || $phone || $identity_card)) { return $this->asJson(['code' => 1, 'msg' => '参数不完整']); } // 检查活动是否存在 $event = Event::findOne([ 'id' => $id, 'store_id' => $store_id, 'is_delete' => 0 ]); if (!$event) { return $this->asJson(['code' => 1, 'msg' => '活动不存在']); } if ($event->end_time < time()) { return $this->asJson(['code' => 1, 'msg' => '活动报名已结束无法报名']); } // 检查是否已报名 $exist = EventUser::findOne([ 'event_id' => $id, 'user_id' => $user_id, 'is_delete' => 0, 'apply_status' => [0, 1] ]); if ($exist) { return $this->asJson(['code' => 1, 'msg' => '您已报名,请勿重复提交']); } $phone_exist = EventUser::findOne([ 'event_id' => $id, 'phone' => $phone, 'is_delete' => 0, 'apply_status' => [0, 1] ]); if ($phone_exist) { return $this->asJson(['code' => 1, 'msg' => '此手机号已报名,请勿重复提交']); } // 检查限制人数 attendance = 0 不限制 if ($event->attendance > 0) { $attendance = EventUser::find() ->where([ 'event_id' => $id, 'is_delete' => 0, 'apply_status' => 1, 'company_code' => $company_code ])->count(); if ($attendance >= $event->attendance) { return $this->asJson(['code' => 1, 'msg' => '【' . $company_name . '】报名已达到限制人数,请与活动主办方联系。']); } } // 开启事务 $transaction = Yii::$app->db->beginTransaction(); try { // 写入 event_user 表 $eventUser = EventUser::findOne([ 'event_id' => $id, 'user_id' => $user_id, 'is_delete' => 0, 'apply_status' => 2, 'store_id' => $store_id ]); if (!$eventUser) { $eventUser = new EventUser(); $eventUser->store_id = $store_id; $eventUser->event_id = $id; $eventUser->user_id = $user_id; } $eventUser->company_code = $company_code; $eventUser->company_name = $company_name; $eventUser->company_address = $company_address; $eventUser->real_name = $real_name; $eventUser->phone = $phone; $eventUser->identity_card = $identity_card; $eventUser->apply_status = 0; $eventUser->created_at = time(); $eventUser->updated_at = time(); $eventUser->is_delete = 0; $eventUser->hotel = '{"title":"","data":[]}'; $eventUser->restaurant = '{"title":"","data":[]}'; $eventUser->itinerary = '{"title":"","data":[]}'; $eventUser->form_type = $form_type; if (!$eventUser->save()) { throw new \Exception('保存报名主表失败'); } // 查询字段定义 $formList = EventForm::find() ->where([ 'event_id' => $id, 'form_type' => $form_type, 'is_delete' => 0 ]) ->asArray() ->all(); $formNameMap = []; // name => type foreach ($formList as $item) { $formNameMap[$item['name']] = $item['type'] ?? 'text'; } // 写入表单明细 EventFormDetail::updateAll(['is_delete' => 1], ['event_user_id' => $eventUser->id]); foreach ($form_data as $name => $value) { if (!isset($formNameMap[$name])) { continue; } $detail = new EventFormDetail(); $detail->store_id = $store_id; $detail->event_user_id = $eventUser->id; $detail->event_id = $id; $detail->user_id = $user_id; $detail->form_type = $form_type; $detail->key = $name; $detail->value = $value; $detail->type = $formNameMap[$name]; $detail->is_delete = 0; if (!$detail->save()) { throw new \Exception("保存表单字段【{$name}】失败"); } } $transaction->commit(); return $this->asJson(['code' => 0, 'msg' => '报名成功,等待审核']); } catch (\Exception $e) { $transaction->rollBack(); return $this->asJson(['code' => 1, 'msg' => '报名失败:' . $e->getMessage()]); } } /** * 模块名:user-event-list * 代码描述: 我的报名 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/14 18:09:26 * @param int page * @param int limit * @param string status 活动状态:all 全部 | audit 审核中 | underway 进行中 | done 已结束 * @param string lng 经度 * @param string lat 纬度 */ public function actionUserEventList() { $user_id = get_user_id(); $store_id = get_store_id(); $status = get_params('status', 'all'); // all | audit | underway | done $page = (int)get_params('page', 1); $limit = (int)get_params('limit', 10); $limit = ($limit <= 0) ? 10 : min($limit, 100); //用户当前的经纬度,如果未传经纬度,说明用户拒绝定位,则后续酒店、饭店、行程信息处理时距离返回空即可 $lng = get_params('lng'); $lat = get_params('lat'); $query = EventUser::find()->alias('eu') ->leftJoin(['e' => Event::tableName()], 'e.id = eu.event_id') ->where([ 'eu.user_id' => $user_id, 'eu.is_delete' => 0, 'e.is_delete' => 0, 'e.store_id' => $store_id, ]); // 状态筛选 $now = time(); if ($status === 'audit') { $query->andWhere(['eu.apply_status' => [0, 2]]); $query->andWhere(['>', 'e.start_time', $now]); } elseif ($status === 'underway') { $query->andWhere(['eu.apply_status' => 1]); $query->andWhere(['>=', 'e.end_time', $now]); } elseif ($status === 'done') { $query->andWhere(['eu.apply_status' => 1]); $query->andWhere(['<', 'e.end_time', $now]); } $count = $query->count(); $pagination = new Pagination([ 'totalCount' => $count, 'pageSize' => $limit, 'page' => $page - 1 ]); $list = $query->select([ 'eu.id', 'e.id AS event_id', 'e.name', 'e.start_time', 'e.end_time', 'e.cover_pic', 'eu.reason_refusal', 'eu.apply_status', 'eu.hotel', 'eu.restaurant', 'eu.itinerary', ]) ->orderBy('e.start_time DESC') ->limit($pagination->limit) ->offset($pagination->offset) ->asArray() ->all(); // 补充 status_text 和报名人数 foreach ($list as &$item) { $apply_status = (int)$item['apply_status']; $start = (int)$item['start_time']; $end = (int)$item['end_time']; if ($apply_status === 0) { $item['status_text'] = '报名中·待审核'; } elseif ($apply_status === 1 && $end >= $now) { $item['status_text'] = '进行中'; } elseif ($apply_status === 1 && $end < $now) { $item['status_text'] = '已结束'; } elseif ($apply_status === 2) { $item['status_text'] = '报名中·已驳回'; } else { $item['status_text'] = '未知状态'; } //酒店、饭店、行程数组处理 //code... $has_location = $lat && $lng; // 计算距离(单位:米) $calcDistance = function ($lat1, $lng1, $lat2, $lng2) { $earthRadius = 6371000; // 米 $lat1 = deg2rad($lat1); $lng1 = deg2rad($lng1); $lat2 = deg2rad($lat2); $lng2 = deg2rad($lng2); $dlat = $lat2 - $lat1; $dlng = $lng2 - $lng1; $a = sin($dlat / 2) ** 2 + cos($lat1) * cos($lat2) * sin($dlng / 2) ** 2; $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); return round($earthRadius * $c, 2); }; // 格式化距离显示 $formatDistance = function ($distance) { if ($distance < 1000) { return (int)$distance . 'm'; } return round($distance / 1000, 1) . 'km'; }; // 转换 json + 加入距离 $parseJsonWithDistance = function ($json_str, $user_lat, $user_lng) use ($has_location, $calcDistance, $formatDistance) { $result = json_decode($json_str, true); if (!is_array($result) || !isset($result['data'])) { return null; } foreach ($result['data'] as &$item) { if (!$has_location || !isset($item['lat']) || !isset($item['lng'])) { $item['distance'] = null; continue; } $distance_val = $calcDistance((float)$user_lat, (float)$user_lng, (float)$item['lat'], (float)$item['lng']); $item['distance'] = $formatDistance($distance_val); } return $result; }; // 应用处理 $item['hotel'] = $parseJsonWithDistance($item['hotel'], $lat, $lng); $item['restaurant'] = $parseJsonWithDistance($item['restaurant'], $lat, $lng); $item['itinerary'] = $parseJsonWithDistance($item['itinerary'], $lat, $lng); // 查询已报名人数 $item['count'] = EventUser::find() ->where(['event_id' => $item['event_id'], 'is_delete' => 0]) ->count(); } return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'list' => $list, 'row_count' => $count, 'page_count' => $pagination->pageCount ], 'setting' => $this->getSetting() ]); } /** * 模块名:get-event-user-qr * 代码描述:签到二维码 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/14 19:14:25 * @param int id */ public function actionGetEventUserQr() { $user_id = get_user_id(); $store_id = get_store_id(); $id = (int)get_params('id'); if (!$id) { return $this->asJson(['code' => 1, 'msg' => '缺少参数:id']); } // 查询报名记录 $eventUser = EventUser::find() ->where([ 'id' => $id, 'user_id' => $user_id, 'store_id' => $store_id, 'is_delete' => 0, 'apply_status' => 1, // 只允许通过审核的用户查看二维码 ]) ->asArray() ->one(); if (!$eventUser) { return $this->asJson(['code' => 1, 'msg' => '报名记录不存在或未审核通过']); } return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'real_name' => $eventUser['real_name'] ?? '', 'phone' => $eventUser['phone'] ?? '', 'identity_card' => $eventUser['identity_card'] ?? '', ] ]); } /** * 模块名:getSetting * 代码描述:获取设置项 * 作者:WPing丶 * 请求方式:private * 创建时间:2025/07/16 10:45:11 */ private function getSetting() { $store_id = get_store_id(); $setting = EventSetting::findOne(['store_id' => $store_id, 'is_delete' => 0]); return [ 'banner' => json_decode($setting->banner, true) ]; } /** * 模块名:do-sign-by-staff * 代码描述:确认签到 * 作者:WPing丶 * 请求方式:POST * 创建时间:2025/07/16 11:28:38 * @param int user_id * @param int event_id */ public function actionDoSignByStaff() { $store_id = get_store_id(); $staff_id = get_user_id(); // 当前登录用户(签到员) $user_id = (int)post_params('user_id'); // 被签到用户 $event_id = (int)post_params('event_id'); if (!$user_id || !$event_id) { return $this->asJson(['code' => 1, 'msg' => '参数错误']); } // 检查当前用户是否是有效的签到员 $staff = EventSignStaff::findOne(['user_id' => $staff_id, 'is_delete' => 0]); if (!$staff) { return $this->asJson(['code' => 1, 'msg' => '无权限']); } // 查找报名记录 $eventUser = EventUser::findOne([ 'user_id' => $user_id, 'event_id' => $event_id, 'is_delete' => 0, 'apply_status' => 1 ]); if (!$eventUser) { return $this->asJson(['code' => 1, 'msg' => '报名记录不存在或未通过审核']); } // 检查是否已签到 if ($eventUser->sign_time > 0) { return $this->asJson(['code' => 1, 'msg' => '用户已签到']); } $transaction = Yii::$app->db->beginTransaction(); try { $time = time(); // 写入签到日志表 $log = new EventSignLog(); $log->store_id = $store_id; $log->is_delete = 0; $log->staff_id = $staff->id; $log->user_id = $user_id; $log->event_id = $event_id; $log->event_user_id = $eventUser->id; if (!$log->save()) { throw new \Exception('签到记录保存失败'); } // 更新报名表中的签到时间 $eventUser->sign_time = $time; if (!$eventUser->save()) { throw new \Exception('签到时间更新失败'); } $transaction->commit(); return $this->asJson(['code' => 0, 'msg' => '签到成功']); } catch (\Exception $e) { $transaction->rollBack(); return $this->asJson(['code' => 1, 'msg' => '签到失败:' . $e->getMessage()]); } } /** * 模块名:my-sign-record * 代码描述:签到员记录 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/16 14:17:38 * @param int page * @param int limit */ public function actionMySignRecord() { $store_id = get_store_id(); $staff_id = EventSignStaff::findOne(['user_id' => get_user_id(), 'is_delete' => 0])->id; $page = (int)get_params('page', 1); $limit = (int)get_params('limit', 10); if (!$staff_id) { return $this->asJson(['code' => 1, 'msg' => '当前用户不是签到员']); } $query = EventSignLog::find()->alias('l') ->leftJoin(['u' => EventUser::tableName()], 'u.id = l.event_user_id') ->leftJoin(['e' => Event::tableName()], 'e.id = l.event_id') ->where([ 'l.store_id' => $store_id, 'l.is_delete' => 0, 'l.staff_id' => $staff_id ]); $count = $query->count(); $pagination = new Pagination([ 'totalCount' => $count, 'pageSize' => $limit, 'page' => $page - 1 ]); $list = $query->select([ 'u.sign_time', 'u.real_name', 'u.phone', 'e.name AS event_name' ]) ->orderBy('l.created_at DESC') ->offset($pagination->offset) ->limit($pagination->limit) ->asArray() ->all(); return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'list' => $list, 'row_count' => $count, 'page_count' => $pagination->pageCount, ] ]); } /** * 模块名: sign-preview * 代码描述: 签到员预览页 * 请求方式: GET * @param int id event_user主键ID */ public function actionSignPreview() { $store_id = get_store_id(); $id = (int)get_params('id'); if (!$id) { return $this->asJson(['code' => 1, 'msg' => '缺少报名记录ID']); } $staff_id = get_user_id(); // 当前登录用户(签到员) // 检查当前用户是否是有效的签到员 $staff = EventSignStaff::findOne(['user_id' => $staff_id, 'is_delete' => 0]); if (!$staff) { return $this->asJson(['code' => 1, 'msg' => '无权限']); } // 联查 event_user 和 event 表(主表 event_user) $info = EventUser::find() ->alias('eu') ->leftJoin(['e' => Event::tableName()], 'e.id = eu.event_id') ->where([ 'eu.id' => $id, 'eu.is_delete' => 0, 'eu.store_id' => $store_id, 'e.is_delete' => 0, ]) ->select([ 'eu.id', 'eu.real_name', 'eu.phone', 'eu.identity_card', 'eu.company_code', 'eu.company_name', 'eu.company_address', 'eu.event_id', 'e.name', 'e.address', 'e.start_time', 'e.end_time' ]) ->asArray() ->one(); if (!$info) { return $this->asJson(['code' => 1, 'msg' => '记录不存在,id=【' . $id . '】']); } // 查询自定义表单字段(event_form_detail) $formDetail = EventFormDetail::find() ->where([ 'event_user_id' => $id, 'is_delete' => 0 ]) ->select(['key', 'value']) ->orderBy('id ASC') ->asArray() ->all(); return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'info' => $info, 'form_detail' => $formDetail ] ]); } /** * 模块名:get-event-sign-qrcode * 代码描述:获取签到二维码 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/16 16:28:11 * @param int event_id */ public function actionGetEventSignQrcode() { $event_id = (int)get_params('event_id'); $user_id = get_user_id(); if (!$event_id) { return $this->asJson(['code' => 1, 'msg' => '参数缺失']); } // 查询报名记录 $eventUser = EventUser::find() ->where([ 'event_id' => $event_id, 'is_delete' => 0, 'user_id' => $user_id, 'apply_status' => 1, // 只允许通过审核的用户查看二维码 ]) ->asArray() ->one(); if (!$eventUser) { return $this->asJson(['code' => 1, 'msg' => '报名记录不存在或未审核通过']); } $event_user_id = $eventUser['id']; $page = "eventPlanning/verifyCodeResult/verifyCodeResult"; $scene = "event_user_id:{$event_user_id}"; $file_name = [ 'url_path' => '' ]; if (is_wechat_platform()) { // 微信平台小程序码 $file_name = ShareQrcode::wxQrcode($page, $scene); if ($file_name['code'] != 0) { return $this->asJson($file_name); } } if (is_alipay_platform()) { // 支付宝小程序码 $request = new AlipayOpenAppQrcodeCreateRequest(); $param = [ 'url_param' => $page, 'query_param' => $scene, 'describe' => "签到预览页二维码" ]; $aliConfigQr = $this->aliConfigQr($request, $param); if ($aliConfigQr->code === "10000") { $file_name['url_path'] = $aliConfigQr->qr_code_url_circle_blue; } } if (is_h5() || is_app_platform()) { $fileName = md5($page . $scene . get_store_id()); $dir = \Yii::$app->runtimePath . '/image/wx_qrcode'; if (!is_dir($dir)) { mkdir($dir, 0777, true); } $save_path = $dir . '/' . $fileName . '.jpg'; $url = \Yii::$app->request->hostInfo . '/h5/#/' . $page . '?scene=' . urlencode($scene); QrCode::image($url, 600, false, 'L', 'JPEG', 0, ['255,255,255', '0,0,0'], 1, false, $save_path); $file_name['url_path'] = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . '/runtime/image/wx_qrcode/' . $fileName . '.jpg'); } return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => [ 'qr_code' => $file_name['url_path'], 'real_name' => $eventUser['real_name'] ?? '', 'phone' => $eventUser['phone'] ?? '', 'identity_card' => $eventUser['identity_card'] ?? '', ] ]); } /** * 模块名:get-event-detail * 代码描述:获取报名详情 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/21 11:55:40 * @param int event_user_id * @param int event_id * @param int lng 经度 * @param int lat 纬度 */ public function actionGetEventDetail() { $event_user_id = (int)get_params('event_user_id'); $event_id = (int)get_params('event_id'); $user_id = get_user_id(); //用户当前的经纬度,如果未传经纬度,说明用户拒绝定位,则后续酒店、饭店、行程信息处理时距离返回空即可 $lng = get_params('lng'); $lat = get_params('lat'); $store_id = get_store_id(); if (!$event_user_id && !$event_id) { return $this->asJson(['code' => 1, 'msg' => '参数缺失']); } // 查询报名记录 $query = EventUser::find() ->where([ 'store_id' => $store_id, 'is_delete' => 0, 'apply_status' => 1, // 只允许通过审核的用户查看二维码 ]); if ($event_user_id) { $query->andWhere(['id' => $event_user_id]); } elseif ($event_id) { $query->andWhere(['event_id' => $event_id, 'user_id' => $user_id]); } $eventUser = $query ->asArray() ->one(); if (!$eventUser) { return $this->asJson(['code' => 1, 'msg' => '报名记录不存在或未审核通过']); } $data = []; foreach ($eventUser as $k => $item) { if ($k == 'hotel' || $k == 'restaurant' || $k == 'itinerary') { /* begin 2025/07/24 16:00:21 WPing丶 */ //酒店、饭店、行程数组处理 //code... $has_location = $lat && $lng; // 计算距离(单位:米) $calcDistance = function ($lat1, $lng1, $lat2, $lng2) { $earthRadius = 6371000; // 米 $lat1 = deg2rad($lat1); $lng1 = deg2rad($lng1); $lat2 = deg2rad($lat2); $lng2 = deg2rad($lng2); $dlat = $lat2 - $lat1; $dlng = $lng2 - $lng1; $a = sin($dlat / 2) ** 2 + cos($lat1) * cos($lat2) * sin($dlng / 2) ** 2; $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); return round($earthRadius * $c, 2); }; // 格式化距离显示 $formatDistance = function ($distance) { if ($distance < 1000) { return (int)$distance . 'm'; } return round($distance / 1000, 1) . 'km'; }; // 转换 json + 加入距离 $parseJsonWithDistance = function ($json_str, $user_lat, $user_lng) use ($has_location, $calcDistance, $formatDistance) { $result = json_decode($json_str, true); if (!is_array($result) || !isset($result['data'])) { return null; } foreach ($result['data'] as &$item) { if (!$has_location || !isset($item['lat']) || !isset($item['lng'])) { $item['distance'] = null; continue; } $distance_val = $calcDistance((float)$user_lat, (float)$user_lng, (float)$item['lat'], (float)$item['lng']); $item['distance'] = $formatDistance($distance_val); } return $result; }; // $arr = json_decode($item, true); // 应用处理 $arr = $parseJsonWithDistance($item, $lat, $lng); /* end */ if (count($arr['data']) == 0) { $data[$k] = []; } else { $data[$k] = $arr; } } else { $data[$k] = $item; } } $setting = EventSetting::findOne(['store_id' => $store_id, 'is_delete' => 0]); return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => $data, 'banner' => json_decode($setting->banner, true) ]); } /** * 模块名:event-msg-list * 代码描述:活动信息列表页 * 作者:WPing丶 * 请求方式:GET * 创建时间:2025/07/24 14:21:14 * @param int event_id 活动ID * @param string type 信息类型:sign=签到;hotel=住宿信息;restaurant=用餐信息;itinerary=行程信息; */ public function actionEventMsgList() { $user_id = get_user_id(); $store_id = get_store_id(); $event_id = get_params('event_id'); $list = EventUser::find()->alias('eu') ->leftJoin(['e' => Event::tableName()], 'eu.event_id = e.id') ->where([ 'eu.user_id' => $user_id, 'eu.store_id' => $store_id, 'eu.is_delete' => 0, 'e.is_delete' => 0, 'eu.apply_status' => 1, ]) ->select('eu.id as event_user_id, e.name') ->asArray() ->all(); return $this->asJson([ 'code' => 0, 'msg' => 'success', 'data' => $list ]); } }