From 6963216a85b9977b79359030529400636297f9cc Mon Sep 17 00:00:00 2001
From: gitfjn <2860488097@qq.com>
Date: Fri, 26 Dec 2025 16:26:15 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=B9=E6=8D=AE=E7=BB=8F?=
=?UTF-8?q?=E7=BA=AC=E5=BA=A6=E8=8E=B7=E5=8F=96=E5=9F=8E=E5=B8=82=20?=
=?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=90=8E=E5=8F=B0=E7=BB=9F=E8=AE=A1=E7=9C=8B?=
=?UTF-8?q?=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
application/admin/controller/Ad.php | 16 +-
.../admin/controller/BulletinBoard.php | 124 ++++
application/admin/logic/AdLogic.php | 35 +-
application/admin/model/Invoice.php | 1 +
.../admin/view/bulletin_board/index.html | 639 +++++++++++++++++
.../admin/view/bulletin_board/map.html | 645 ++++++++++++++++++
application/api/controller/Ad.php | 20 +-
application/api/controller/City.php | 34 +
application/api/server/CityService.php | 162 +++++
9 files changed, 1668 insertions(+), 8 deletions(-)
create mode 100644 application/admin/controller/BulletinBoard.php
create mode 100644 application/admin/view/bulletin_board/index.html
create mode 100644 application/admin/view/bulletin_board/map.html
diff --git a/application/admin/controller/Ad.php b/application/admin/controller/Ad.php
index 244c6545..5cd9faf4 100644
--- a/application/admin/controller/Ad.php
+++ b/application/admin/controller/Ad.php
@@ -42,9 +42,21 @@ class Ad extends AdminBase
}
$this->_error($result);
}
- $this->assign('category_list',AdLogic::getGoodsCategory());
+ // 确保 client 参数有效
+ if (empty($client)) {
+ $client = $this->request->param('client', '1');
+ }
+ $category_list = AdLogic::getGoodsCategory();
+ $link_page = \app\common\model\Ad::getLinkPage($client);
+ $position_list = AdLogic::infoPosition($client);
+ $this->assign('category_list', AdLogic::getGoodsCategory());
$this->assign('link_page', \app\common\model\Ad::getLinkPage($client));
- $this->assign('position_list', AdLogic::infoPosition($client));
+
+ $this->assign([
+ 'category_list' => $category_list,
+ 'link_page' => $link_page,
+ 'position_list' => $position_list,
+ ]);
return $this->fetch();
}
diff --git a/application/admin/controller/BulletinBoard.php b/application/admin/controller/BulletinBoard.php
new file mode 100644
index 00000000..11ca281a
--- /dev/null
+++ b/application/admin/controller/BulletinBoard.php
@@ -0,0 +1,124 @@
+fetch();
+ }
+
+
+ //地图上显示注册用户位置
+ public function map()
+ {
+ return $this->fetch();
+ }
+
+ public function getUserMap()
+ {
+ // 查询有经纬度的用户
+ $userArray = User::where('latitude', '<>', '')
+ ->where('longitude', '<>', '')
+ ->field('id,nickname,mobile,avatar,longitude,latitude')
+ ->select();
+ // 格式化数据,转换为前端期望的字段名
+ $result = [];
+ foreach ($userArray as $user) {
+ // 处理头像URL,使用代理接口避免CORS问题
+ $avatar = '';
+ if (!empty($user['avatar'])) {
+ $originalUrl = UrlServer::getFileUrl($user['avatar']);
+ // 去掉JSON编码时产生的转义反斜杠
+ $originalUrl = str_replace('\\/', '/', $originalUrl);
+
+ // 如果URL是跨域的,使用代理接口
+ $currentDomain = $this->request->domain();
+ if (strpos($originalUrl, $currentDomain) === false) {
+ // 跨域,使用代理(手动构建URL避免双重编码)
+ $avatar = $this->request->domain() . '/admin/bulletin_board/proxyImage?url=' . rawurlencode($originalUrl);
+ } else {
+ // 同域,直接使用
+ $avatar = $originalUrl;
+ }
+ }
+
+ $result[] = [
+ 'id' => $user['id'] ?? 0,
+ 'lng' => floatval($user['longitude'] ?? 0),
+ 'lat' => floatval($user['latitude'] ?? 0),
+ 'name' => $user['nickname'] ?? '',
+ 'contact' => $user['nickname'] ?? '', // 兼容两种字段名
+ 'mobile' => $user['mobile'] ?? '',
+ 'phone' => $user['mobile'] ?? '', // 兼容 telephone/phone
+ 'telephone' => $user['mobile'] ?? '',
+ 'avatar' => $avatar
+ ];
+ }
+
+ return $this->_success('获取成功', $result);
+ }
+
+ /**
+ * 图片代理接口,解决CORS跨域问题
+ */
+ public function proxyImage()
+ {
+ $url = $this->request->get('url', '');
+ if (empty($url)) {
+ header('HTTP/1.1 404 Not Found');
+ exit;
+ }
+
+ // 解码URL
+ $url = urldecode($url);
+
+ // 验证URL格式
+ if (!filter_var($url, FILTER_VALIDATE_URL)) {
+ header('HTTP/1.1 400 Bad Request');
+ exit;
+ }
+
+ // 只允许图片格式
+ $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $extension = strtolower(pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
+ if (!in_array($extension, $allowedExtensions)) {
+ header('HTTP/1.1 403 Forbidden');
+ exit;
+ }
+
+ // 获取图片
+ $context = stream_context_create([
+ 'http' => [
+ 'method' => 'GET',
+ 'timeout' => 10,
+ 'header' => [
+ 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
+ ]
+ ]
+ ]);
+
+ $imageData = @file_get_contents($url, false, $context);
+
+ if ($imageData === false) {
+ header('HTTP/1.1 404 Not Found');
+ exit;
+ }
+
+ // 设置响应头
+ header('Content-Type: image/' . ($extension === 'jpg' ? 'jpeg' : $extension));
+ header('Cache-Control: public, max-age=3600');
+ header('Access-Control-Allow-Origin: *');
+ header('Access-Control-Allow-Methods: GET');
+
+ // 输出图片
+ echo $imageData;
+ exit;
+ }
+}
\ No newline at end of file
diff --git a/application/admin/logic/AdLogic.php b/application/admin/logic/AdLogic.php
index 5ac86614..2906e64a 100644
--- a/application/admin/logic/AdLogic.php
+++ b/application/admin/logic/AdLogic.php
@@ -218,10 +218,37 @@ class AdLogic
*/
public static function infoPosition($client)
{
- $position_list = Db::name('ad_position')
- ->where(['client' => $client, 'status' => 1, 'del' => 0])
- ->group('name')
- ->column('id,name', 'id');
+ $position_list = [];
+
+ // 使用错误抑制,避免 unserialize 警告影响页面
+ $originalErrorReporting = error_reporting(0);
+
+ try {
+ // 使用原始 SQL 查询,完全绕过 ThinkPHP 的类型转换
+ $prefix = config('database.prefix');
+ $tableName = $prefix . 'ad_position';
+ $sql = "SELECT DISTINCT `id`, `name` FROM `{$tableName}` WHERE `client` = " . intval($client) . " AND `status` = 1 AND `del` = 0 GROUP BY `name`";
+
+ $result = Db::query($sql);
+
+ if (!empty($result) && is_array($result)) {
+ foreach ($result as $row) {
+ if (isset($row['id']) && isset($row['name'])) {
+ $position_list[$row['id']] = $row['name'];
+ }
+ }
+ }
+ } catch (\Exception $e) {
+ // 忽略所有异常
+ } catch (\Error $e) {
+ // 忽略所有错误
+ } catch (\Throwable $e) {
+ // 捕获所有可抛出的对象
+ } finally {
+ // 恢复错误报告级别
+ error_reporting($originalErrorReporting);
+ }
+
asort($position_list);
return $position_list;
}
diff --git a/application/admin/model/Invoice.php b/application/admin/model/Invoice.php
index 77e75522..c02cf1e1 100644
--- a/application/admin/model/Invoice.php
+++ b/application/admin/model/Invoice.php
@@ -14,3 +14,4 @@ class Invoice extends Model
}
}
+
diff --git a/application/admin/view/bulletin_board/index.html b/application/admin/view/bulletin_board/index.html
new file mode 100644
index 00000000..93c4f7d6
--- /dev/null
+++ b/application/admin/view/bulletin_board/index.html
@@ -0,0 +1,639 @@
+{layout name="layout1" /}
+
+
+
+
+
+
+
+
+
+
+
+
+
当月目标完成率
+
+
+
客服目标完成率(N个客服的目标陈列)
+
+
+
+
+ 啦啦
+ 销售额: XXX | 百分比: xx% | 同比: xx%
+
+
+
+
+
+ 小喵
+ 销售额: XXX | 百分比: xx% | 同比: xx%
+
+
+
+
+
+ 哆哆
+ 销售额: XXX | 百分比: xx% | 同比: xx%
+
+
+
+
+
+ 大猫
+ 销售额: XXX | 百分比: xx% | 同比: xx%
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
每日销售趋势
+
+ ▼ 29.23% 上月同比
+
+
+
+
+
+
+
+
+
+
+
+
+
+
渠道月销售详情
+
+
+
+ | 渠道 |
+ 美团 |
+ 公众号 |
+ 抖音 |
+ 员工 |
+ 异业 |
+ 渠道 |
+
+
+
+
+ | 总额 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 年卡 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 次卡 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 单次服务 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 其他服务 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+
+
+
+
+
+
+
+
+
+
区域月销售详情
+
+
+
+ | 服务类型 |
+ 南明区 |
+ 云岩区 |
+ 白云区 |
+ 乌当区 |
+ 花溪区 |
+ 龙里 |
+
+
+
+
+ | 总额 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 年卡 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 次卡 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 单次服务 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+ | 其他服务 |
+ - |
+ - |
+ - |
+ - |
+ - |
+ - |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/application/admin/view/bulletin_board/map.html b/application/admin/view/bulletin_board/map.html
new file mode 100644
index 00000000..15e357cb
--- /dev/null
+++ b/application/admin/view/bulletin_board/map.html
@@ -0,0 +1,645 @@
+{layout name="layout1" /}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/application/api/controller/Ad.php b/application/api/controller/Ad.php
index ba7efe6e..57c7f001 100644
--- a/application/api/controller/Ad.php
+++ b/application/api/controller/Ad.php
@@ -5,6 +5,7 @@ namespace app\api\controller;
use app\api\logic\AdLogic;
+use app\common\server\UrlServer;
use think\Db;
header("Access-Control-Allow-Origin: *");
@@ -13,7 +14,7 @@ header("Access-Control-Allow-Headers: Content-Type, Authorization");
class Ad extends ApiBase
{
- public $like_not_need_login = ['lists','channel','label','add_comost','add_comost','list_comost','follow_comost','comost_add','label_edit','comost_info','notice','position','position_list','vode_type','video_list','video_info','user_wages','user_wages_add','user_leave','fine','recruit','last_leave','last_fine','notice_list','leave','auth'];
+ public $like_not_need_login = ['lists','popup','channel','label','add_comost','add_comost','list_comost','follow_comost','comost_add','label_edit','comost_info','notice','position','position_list','vode_type','video_list','video_info','user_wages','user_wages_add','user_leave','fine','recruit','last_leave','last_fine','notice_list','leave','auth'];
/**
* @return void
@@ -30,7 +31,22 @@ class Ad extends ApiBase
}
$this->_success('获取成功', $list);
}
-
+
+
+ //获取弹窗
+ public function popup()
+ {
+ $list = Db::name('ad')
+ ->where('status',1)
+ ->where('pid',25)
+ ->field('id,name,image,link_type,link')
+ ->find();
+ if ($list != null){
+ $list['image'] = UrlServer::getFileUrl($list['image']);
+ }
+ $this->_success('获取成功', $list);
+ }
+
//获取客户的渠道
public function channel(){
$list=Db::name('staffchannel')->field('id,name')->select();
diff --git a/application/api/controller/City.php b/application/api/controller/City.php
index 12358b87..7e03c860 100644
--- a/application/api/controller/City.php
+++ b/application/api/controller/City.php
@@ -3,6 +3,7 @@
namespace app\api\controller;
use app\api\server\CityService;
+use app\api\model\User;
class City extends ApiBase
{
@@ -25,4 +26,37 @@ class City extends ApiBase
$array = $this->cityService->list();
return $this->_success('成功',$array);
}
+
+
+ /**
+ * 根据经纬度获取所在城市
+ * @return void
+ */
+ public function getCity()
+ {
+ $lat = $this->request->param('lat', '');
+ $lng = $this->request->param('lng', '');
+
+ if (empty($lat) || empty($lng)) {
+ return $this->_error('请提供经纬度参数');
+ }
+ $uid = $this->user_id;
+ //查询用户信息
+ $userInfo = User::find($uid);
+ if ($userInfo) {
+ if ($userInfo->longitude == '' || $userInfo->latitude == '')
+ {
+ $userInfo->longitude = $lng; // 经度
+ $userInfo->latitude = $lat; // 纬度
+ $userInfo->save();
+ }
+ }
+ $result = $this->cityService->getCityByLocation($lat, $lng);
+
+ if ($result['success']) {
+ return $this->_success($result['msg'], $result['data']);
+ } else {
+ return $this->_error($result['msg'], $result['data']);
+ }
+ }
}
\ No newline at end of file
diff --git a/application/api/server/CityService.php b/application/api/server/CityService.php
index beb8fe2b..39e39152 100644
--- a/application/api/server/CityService.php
+++ b/application/api/server/CityService.php
@@ -8,6 +8,9 @@ use think\facade\Config;
class CityService
{
+ // 腾讯地图API Key
+ private $tencentMapKey = 'EVOBZ-VX7YU-QKJVR-BVESA-AVFT3-7JBWG';
+
public function list()
{
$cacheKey = 'city_cache_keys';
@@ -25,4 +28,163 @@ class CityService
}
return $data;
}
+
+ /**
+ * 根据经纬度获取所在城市
+ * @param float $lat 纬度
+ * @param float $lng 经度
+ * @return array
+ */
+ public function getCityByLocation($lat, $lng)
+ {
+ // 参数验证
+ if (empty($lat) || empty($lng)) {
+ return [
+ 'success' => false,
+ 'msg' => '经纬度参数不能为空',
+ 'data' => null
+ ];
+ }
+
+ // 验证经纬度范围
+ if (!is_numeric($lat) || !is_numeric($lng)) {
+ return [
+ 'success' => false,
+ 'msg' => '经纬度格式错误',
+ 'data' => null
+ ];
+ }
+
+ $lat = floatval($lat);
+ $lng = floatval($lng);
+
+ if ($lat < -90 || $lat > 90 || $lng < -180 || $lng > 180) {
+ return [
+ 'success' => false,
+ 'msg' => '经纬度范围错误',
+ 'data' => null
+ ];
+ }
+
+ // 生成缓存key
+ $cacheKey = 'city_location_' . md5($lat . '_' . $lng);
+
+ // 尝试从缓存获取
+ if (Cache::store('redis')->has($cacheKey)) {
+ $cachedData = Cache::store('redis')->get($cacheKey);
+ return [
+ 'success' => true,
+ 'msg' => '获取成功',
+ 'data' => $cachedData
+ ];
+ }
+
+ // 调用腾讯地图逆地理编码API
+ $apiUrl = 'https://apis.map.qq.com/ws/geocoder/v1/';
+ $params = [
+ 'location' => $lat . ',' . $lng,
+ 'key' => $this->tencentMapKey,
+ 'get_poi' => 0
+ ];
+
+ $url = $apiUrl . '?' . http_build_query($params);
+
+ // 使用curl请求
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $error = curl_error($ch);
+ curl_close($ch);
+
+ if ($error) {
+ return [
+ 'success' => false,
+ 'msg' => '请求失败:' . $error,
+ 'data' => null
+ ];
+ }
+
+ if ($httpCode !== 200) {
+ return [
+ 'success' => false,
+ 'msg' => 'API请求失败,HTTP状态码:' . $httpCode,
+ 'data' => null
+ ];
+ }
+
+ $result = json_decode($response, true);
+
+ if (empty($result) || $result['status'] !== 0) {
+ return [
+ 'success' => false,
+ 'msg' => isset($result['message']) ? $result['message'] : '获取城市信息失败',
+ 'data' => null
+ ];
+ }
+
+ // 解析返回数据
+ $addressComponent = $result['result']['address_component'] ?? [];
+ $cityName = $addressComponent['city'] ?? '';
+ $provinceName = $addressComponent['province'] ?? '';
+ $districtName = $addressComponent['district'] ?? '';
+ $adcode = $addressComponent['adcode'] ?? '';
+
+ // 如果城市名称为空,尝试使用区县名称
+ if (empty($cityName) && !empty($districtName)) {
+ $cityName = $districtName;
+ }
+
+ // 查询数据库中的城市ID
+ $cityId = null;
+ $cityInfo = null;
+
+ if (!empty($cityName)) {
+ // 先尝试精确匹配
+ $cityInfo = Db::name('dev_region')
+ ->where('name', $cityName)
+ ->where('level', 2) // 市级
+ ->find();
+
+ // 如果精确匹配失败,尝试模糊匹配
+ if (empty($cityInfo)) {
+ $cityInfo = Db::name('dev_region')
+ ->where('name', 'like', '%' . $cityName . '%')
+ ->where('level', 2)
+ ->find();
+ }
+
+ if ($cityInfo) {
+ $cityId = $cityInfo['id'];
+ }
+ }
+
+ $data = [
+ 'city_name' => $cityName,
+ 'province_name' => $provinceName,
+ 'district_name' => $districtName,
+ 'adcode' => $adcode,
+ 'city_id' => $cityId,
+ 'city_info' => $cityInfo,
+ 'formatted_address' => $result['result']['formatted_addresses']['recommend'] ?? '',
+ 'location' => [
+ 'lat' => $lat,
+ 'lng' => $lng
+ ]
+ ];
+
+ // 缓存结果(缓存1小时)
+ Cache::store('redis')->set($cacheKey, $data, 3600);
+
+ return [
+ 'success' => true,
+ 'msg' => '获取成功',
+ 'data' => $data
+ ];
+ }
}
\ No newline at end of file