196 行
6.2 KiB
PHP
可执行文件
196 行
6.2 KiB
PHP
可执行文件
<?php
|
||
|
||
namespace Common\Model;
|
||
|
||
use Think\Model;
|
||
|
||
/**
|
||
* 门店服务区域模型
|
||
* Class StoreServiceAreaModel
|
||
* @package Common\Model
|
||
*/
|
||
class StoreServiceAreaModel extends BaseModel
|
||
{
|
||
protected $tableName = 'store_service_area';
|
||
|
||
protected $fields = array(
|
||
'id', // int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID'
|
||
'store_id', // int(11) NOT NULL COMMENT '门店ID,关联ls_retail_store表'
|
||
'merchant_id', // int(11) NOT NULL COMMENT '商户ID'
|
||
'area_name', // varchar(100) NOT NULL DEFAULT '' COMMENT '服务区域名称'
|
||
'polygon_data', // text NOT NULL COMMENT '多边形坐标数据,JSON格式存储经纬度数组'
|
||
'center_lat', // decimal(10,7) DEFAULT NULL COMMENT '区域中心点纬度'
|
||
'center_lng', // decimal(10,7) DEFAULT NULL COMMENT '区域中心点经度'
|
||
'area_size', // decimal(15,2) DEFAULT '0.00' COMMENT '服务区域面积(平方公里)'
|
||
'delivery_fee', // decimal(8,2) DEFAULT '0.00' COMMENT '该区域配送费用'
|
||
'min_order_amount', // decimal(8,2) DEFAULT '0.00' COMMENT '该区域最低起送金额'
|
||
'status', // tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1=启用,0=禁用'
|
||
'priority', // int(3) NOT NULL DEFAULT '0' COMMENT '优先级,数字越大优先级越高'
|
||
'create_time', // int(11) NOT NULL DEFAULT '0' COMMENT '创建时间'
|
||
'update_time', // int(11) NOT NULL DEFAULT '0' COMMENT '更新时间'
|
||
'operator_id', // int(11) DEFAULT '0' COMMENT '操作员ID'
|
||
'remarks', // varchar(500) DEFAULT '' COMMENT '备注说明'
|
||
);
|
||
|
||
/**
|
||
* 获取门店的服务区域列表
|
||
* @param int $storeId 门店ID
|
||
* @param int $status 状态筛选,null为全部
|
||
* @return array
|
||
*/
|
||
public function getStoreServiceAreas($storeId, $status = null)
|
||
{
|
||
$map = array('store_id' => $storeId);
|
||
if ($status !== null) {
|
||
$map['status'] = $status;
|
||
}
|
||
|
||
return $this->where($map)
|
||
->order('priority DESC, id ASC')
|
||
->select();
|
||
}
|
||
|
||
/**
|
||
* 保存服务区域数据
|
||
* @param array $data 区域数据
|
||
* @return bool|int
|
||
*/
|
||
public function saveServiceArea($data)
|
||
{
|
||
$data['update_time'] = time();
|
||
|
||
if (isset($data['id']) && $data['id'] > 0) {
|
||
// 更新
|
||
$id = $data['id'];
|
||
unset($data['id']);
|
||
return $this->where(array('id' => $id))->save($data);
|
||
} else {
|
||
// 新增
|
||
$data['create_time'] = time();
|
||
return $this->add($data);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 删除服务区域
|
||
* @param int $id 区域ID
|
||
* @param int $storeId 门店ID(安全验证)
|
||
* @return bool
|
||
*/
|
||
public function deleteServiceArea($id, $storeId)
|
||
{
|
||
return $this->where(array('id' => $id, 'store_id' => $storeId))->delete();
|
||
}
|
||
|
||
/**
|
||
* 更新区域状态
|
||
* @param int $id 区域ID
|
||
* @param int $storeId 门店ID
|
||
* @param int $status 状态
|
||
* @return bool
|
||
*/
|
||
public function updateStatus($id, $storeId, $status)
|
||
{
|
||
$data = array(
|
||
'status' => $status,
|
||
'update_time' => time()
|
||
);
|
||
|
||
return $this->where(array('id' => $id, 'store_id' => $storeId))->save($data);
|
||
}
|
||
|
||
/**
|
||
* 检查坐标点是否在服务区域内
|
||
* @param float $lat 纬度
|
||
* @param float $lng 经度
|
||
* @param int $storeId 门店ID
|
||
* @return array|false 返回匹配的区域信息,无匹配返回false
|
||
*/
|
||
public function checkPointInServiceArea($lat, $lng, $storeId)
|
||
{
|
||
$areas = $this->getStoreServiceAreas($storeId, 1); // 只获取启用的区域
|
||
|
||
foreach ($areas as $area) {
|
||
if ($this->isPointInPolygon($lat, $lng, $area['polygon_data'])) {
|
||
return $area;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 判断点是否在多边形内(射线法)
|
||
* @param float $lat 纬度
|
||
* @param float $lng 经度
|
||
* @param string $polygonData JSON格式的多边形坐标数据
|
||
* @return bool
|
||
*/
|
||
private function isPointInPolygon($lat, $lng, $polygonData)
|
||
{
|
||
$polygon = json_decode($polygonData, true);
|
||
if (!$polygon || count($polygon) < 3) {
|
||
return false;
|
||
}
|
||
|
||
$x = $lng;
|
||
$y = $lat;
|
||
$inside = false;
|
||
|
||
$j = count($polygon) - 1;
|
||
for ($i = 0; $i < count($polygon); $i++) {
|
||
$xi = $polygon[$i]['lng'];
|
||
$yi = $polygon[$i]['lat'];
|
||
$xj = $polygon[$j]['lng'];
|
||
$yj = $polygon[$j]['lat'];
|
||
|
||
if ((($yi > $y) != ($yj > $y)) && ($x < ($xj - $xi) * ($y - $yi) / ($yj - $yi) + $xi)) {
|
||
$inside = !$inside;
|
||
}
|
||
$j = $i;
|
||
}
|
||
|
||
return $inside;
|
||
}
|
||
|
||
/**
|
||
* 获取区域详情
|
||
* @param int $id 区域ID
|
||
* @param int $storeId 门店ID
|
||
* @return array|null
|
||
*/
|
||
public function getServiceAreaDetail($id, $storeId)
|
||
{
|
||
return $this->where(array('id' => $id, 'store_id' => $storeId))->find();
|
||
}
|
||
|
||
/**
|
||
* 计算多边形面积(简单估算,单位:平方公里)
|
||
* @param string $polygonData JSON格式的多边形坐标数据
|
||
* @return float
|
||
*/
|
||
public function calculatePolygonArea($polygonData)
|
||
{
|
||
$polygon = json_decode($polygonData, true);
|
||
if (!$polygon || count($polygon) < 3) {
|
||
return 0;
|
||
}
|
||
|
||
// 使用鞋带公式计算面积(简化版本)
|
||
$area = 0;
|
||
$j = count($polygon) - 1;
|
||
|
||
for ($i = 0; $i < count($polygon); $i++) {
|
||
$area += ($polygon[$j]['lng'] + $polygon[$i]['lng']) * ($polygon[$j]['lat'] - $polygon[$i]['lat']);
|
||
$j = $i;
|
||
}
|
||
|
||
$area = abs($area) / 2;
|
||
|
||
// 转换为平方公里(粗略估算)
|
||
// 1度经纬度约等于111公里
|
||
$areaKm2 = $area * 111 * 111;
|
||
|
||
return round($areaKm2, 2);
|
||
}
|
||
} |