电商活动唯一排序时间冲突检测,活动时间区块检测冲突

其实很多电商活动时间排序的时候需要唯一,比如秒杀活动,必须唯一时间段

正常来说活动开始之后,应该不能修改活动时间,可以修改内容或者活动商品,如果修改时间冲突问题会很大,活动时间检测就会很麻烦

这里给一个穷举规则的解决办法,开发框架是laravel

下面是demo

数据表

CREATE TABLE `mao_free_delivery` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `title` varchar(50) NOT NULL COMMENT '活动标题',
 `sum_money` decimal(10,2) unsigned NOT NULL COMMENT '满包邮的金额',
 `shop_id` int(10) unsigned NOT NULL COMMENT '创建者门店ID',
 `user_id` int(10) unsigned NOT NULL COMMENT '创建者用户ID',
 `start_time` timestamp NULL DEFAULT NULL COMMENT '活动开始时间',
 `end_time` timestamp NULL DEFAULT NULL COMMENT '活动结束时间',
 `division_method` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '1是全场,2是部分商品,3是按品类划分',
 `ids` varchar(5000) DEFAULT NULL COMMENT 'ID集合',
 `created_at` timestamp NULL DEFAULT NULL COMMENT '活动创建时间',
 `updated_at` timestamp NULL DEFAULT NULL COMMENT '活动操作更新时间',
 `is_enabled` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '上下架,1是默认,2是下架',
 `is_del` tinyint(1) unsigned NOT NULL DEFAULT '1' COMMENT '是否删除,1是默认,2是删除',
 `sort` int(10) unsigned NOT NULL DEFAULT '255' COMMENT '排序',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='包邮活动表';

 

 

 //包邮检查活动编辑,会和其他的活动时间冲突
    public static function check_time_conflict($shop_id =null,$start_time = null,$end_time = null,$id = null,&$error = null)
    {
          if(empty($start_time)){
            $error = '开始时间不能为空';
            return FALSE;
        }
        if(empty($end_time)){
            $error = '结束时间不能为空';
            return FALSE;
        }
        if(strtotime($start_time) > strtotime($end_time)){
            $error = '开始时间不能大于结束时间';
            return FALSE;
        }
        if(strtotime($start_time) == strtotime($end_time)){
            $error = '开始时间不能等于结束时间';
            return FALSE;
        }
        $condition[]=['is_del', '=', self::IS_DEL];
    $condition[]=['is_enabled', '=', self::IS_ENABLED];
        $condition[]=['shop_id', '=', $shop_id];
        $result = self::getFreeDeliveryInfo($condition);
        if(empty($result)){//没有数据就直接加入
            return true;
        }
        if($id){//编辑时候剔除当前编辑的数据,在进行处理
            foreach ($result as $k1 => $v1) {
                if(in_array($id,$v1)){
                    unset($result[$k1]);
                }
            }
        }
//        pp($result);
         //首先进行时间区块排序,然后进行进行区块比较
        $need = [];
        foreach ($result as $key => &$value) {//转成时间,防止其他php版本出错
            $need[] = $value['start_time'] = strtotime($value['start_time']);
            $need[] = $value['end_time'] = strtotime($value['end_time']);
        }
        //先冒泡排序,在校验进入数组和原数组,防止数据错误
        $bubble_sort_result =  self::bubbleSort($need);
        foreach ($result as $k=> $v) {//数据校验,把原数组的start_time,end_time进行查找如果,如果2个键名的key相等或者相差大于1就是数据出错
          if(!in_array($v['start_time'],$bubble_sort_result)){
              $error = '数据校验出错,没有检测到开始时间';
              return FALSE;
          }
          if(!in_array($v['end_time'],$bubble_sort_result)){
              $error = '数据校验出错,没有检测到结束时间';
              return FALSE;
          }
          
          $start = array_search($v['start_time'],$bubble_sort_result);
          $end   = array_search($v['end_time'],$bubble_sort_result);
          
          if($start == $end){
              $error = '数据校验出错,开始时间和结束时间相同';
              return FALSE;
          }
          
          if($end - $start >1){
              $error = '数据校验出错,时间排序出错';
              return FALSE;
          }
        }

        //首先进行边界判断,在循环判断
        if(strtotime($start_time) < $bubble_sort_result['0'] && strtotime($end_time) < $bubble_sort_result['0']){//结束时间必须小于对比数组第一个元素,否侧冲突
                  return true;
        }
        if(strtotime($start_time) > $bubble_sort_result[(count($bubble_sort_result)-1)] && strtotime($end_time) > $bubble_sort_result[(count($bubble_sort_result)-1)] ){
                  return true;
        }
        foreach ($bubble_sort_result as $kk => $vv) {
            //其他中间元素必须在01   23  45  67  89中间
              if($kk % 2 == 1){
                  if(strtotime($start_time) > $bubble_sort_result[$kk] && strtotime($end_time) < $bubble_sort_result[$kk+1]){
                         return true;
                   }
              }
        }
        $error = '时间排序错误,请不要输入与他活动开始或结束活动相同的时间';
        return FALSE;
    }
    public static function bubbleSort(array $arr = []){
            $len=count($arr);
          //设置一个空数组 用来接收冒出来的泡
          //该层循环控制 需要冒泡的轮数
          for($i=1;$i<$len;$i++)
          { //该层循环用来控制每轮 冒出一个数 需要比较的次数
            for($k=0;$k<$len-$i;$k++)
            {
               if($arr[$k]>$arr[$k+1])
                {
                    $tmp=$arr[$k+1];
                    $arr[$k+1]=$arr[$k];
                    $arr[$k]=$tmp;
                }
            }
          }
          return $arr;
    }
    
    public static function getFreeDeliveryInfo(array $condition = []){
        if(empty($condition)){
            return FALSE;
        }
        $freedeliveryM = new freedeliveryM();
        $res = $freedeliveryM->where($condition)->get();
        if ($res) {
            return $res->toArray();
        }
        return FALSE;
    }

 

 

foreach ($bubble_sort_result as $kk => $vv) {
            //其他中间元素必须在01   23  45  67  89中间
              if($kk % 2 == 1){
                  if(strtotime($start_time) > $bubble_sort_result[$kk] && strtotime($end_time) < $bubble_sort_result[$kk+1]){
                         return true;
                   }
              }
        }

 

 最难理解就是这里,其实就是在01   23     45    67    89中间,K=1的就是检查 1和2中间,适不适合插入新的开始时间和结束时间,合适就返回true

我是穷举,如果中了一个就可以插入,不能就返回false,还有注意不能在新插入的时间,不能和其他任意一个活动的开始或者结束时间相同,因为要冒泡排序,

相同就会在检测数据出错,在前端使用插件插入时间的时候,提示用户加一秒就可以

 

2021年7月5日17:01:51

因为又用到这个时间冲突检测,好几年了,优化了一个版本

<?php

namespace App\Service\V1;

use App\Service\V1\BaseService;
use Exception;

class CheckTimeConflictService extends BaseService
{
    /**
     * 检查活动时间段冲突
     * @param string|null $start_time 活动开始时间
     * @param string|null $end_time 活动结束时间
     * @param array $array 待检查所有数据的数组集合,注意少一些字段,这样检查的性能会更好,必要字段就是[[id,start_time,end_time],[id,start_time,end_time]]
     * @param null $id 编辑时,待检查的id
     * @return bool
     * @throws Exception
     */
    public static function check(string $start_time = null, string $end_time = null, array $array = [], $id = null)
    {
        if (empty($start_time)) {
            throw new Exception('开始时间不能为空');
        }
        if (empty($end_time)) {
            throw new Exception('结束时间不能为空');
        }
        if (strtotime($start_time) > strtotime($end_time)) {
            throw new Exception('开始时间不能大于结束时间');
        }
        if (strtotime($start_time) == strtotime($end_time)) {
            throw new Exception('开始时间不能等于结束时间');
        }
        //如果没有其他数据炬直接返回true
        if (empty($array)) {
            return true;
        } else {
            if ($id) {//编辑时候剔除当前编辑的数据,在进行处理
                foreach ($array as $k1 => $v1) {
                    if (in_array($id, $v1)) {
                        unset($array[$k1]);
                    }
                }
            }
        }

//        pp($array);
        //首先进行时间区块排序,然后进行进行区块比较
        $need = [];
        foreach ($array as $key => &$value) {//转成时间,防止其他php版本出错
            $need[] = $value['start_time'] = strtotime($value['start_time']);
            $need[] = $value['end_time'] = strtotime($value['end_time']);
        }
        //先冒泡排序,在校验进入数组和原数组,防止数据错误
        $bubble_sort_result = self::bubbleSort($need);
        foreach ($array as $k => $v) {//数据校验,把原数组的start_time,end_time进行查找如果,如果2个键名的key相等或者相差大于1就是数据出错
            if (!in_array($v['start_time'], $bubble_sort_result)) {
                throw new Exception('数据校验出错,没有检测到开始时间');
            }
            if (!in_array($v['end_time'], $bubble_sort_result)) {
                throw new Exception('数据校验出错,没有检测到结束时间');
            }
            $start = array_search($v['start_time'], $bubble_sort_result);
            $end = array_search($v['end_time'], $bubble_sort_result);

            if ($start == $end) {
                throw new Exception('数据校验出错,开始时间和结束时间相同');
            }
            if ($end - $start > 1) {
                throw new Exception('数据校验出错,时间排序出错');
            }
        }
        //首先进行边界判断,在循环判断
        if (strtotime($start_time) < $bubble_sort_result['0'] && strtotime($end_time) < $bubble_sort_result['0']) {//结束时间必须小于对比数组第一个元素,否侧冲突
            return true;
        }
        if (strtotime($start_time) > $bubble_sort_result[(count($bubble_sort_result) - 1)] && strtotime($end_time) > $bubble_sort_result[(count($bubble_sort_result) - 1)]) {
            return true;
        }
        foreach ($bubble_sort_result as $kk => $vv) {
            //其他中间元素必须在01   23  45  67  89中间
            if ($kk % 2 == 1) {
                if (strtotime($start_time) > $bubble_sort_result[$kk] && strtotime($end_time) < $bubble_sort_result[$kk + 1]) {
                    return true;
                }
            }
        }
        throw new Exception('时间排序错误,请不要输入与他活动开始或结束活动相同的时间');
    }


    public static function bubbleSort(array $arr = [])
    {
        $len = count($arr);
        //设置一个空数组 用来接收冒出来的泡
        //该层循环控制 需要冒泡的轮数
        for ($i = 1; $i < $len; $i++) { //该层循环用来控制每轮 冒出一个数 需要比较的次数
            for ($k = 0; $k < $len - $i; $k++) {
                if ($arr[$k] > $arr[$k + 1]) {
                    $tmp = $arr[$k + 1];
                    $arr[$k + 1] = $arr[$k];
                    $arr[$k] = $tmp;
                }
            }
        }
        return $arr;
    }

}

测试代码

  public function test(Request $request)
    {
        $data = [];
//        $data = [
//            ['id' => 0, 'start_time' => '2021-07-01 00:00:00', 'end_time' => '2021-07-03 00:00:00'],
//            ['id' => 1, 'start_time' => '2021-07-05 00:00:00', 'end_time' => '2021-07-06 00:00:00'],
//            ['id' => 2, 'start_time' => '2021-07-10 00:00:00', 'end_time' => '2021-07-12 00:00:00'],
//            ['id' => 3, 'start_time' => '2021-07-15 00:00:00', 'end_time' => '2021-07-20 00:00:00']
//        ];

        $start_time = '2021-07-03 00:00:01';
        $end_time = '2021-07-04 00:00:00';
        $id = '';
        try {
            $dd = CheckTimeConflictService::check($start_time, $end_time, $data, $id);
            p($dd);
        } catch (Exception $e) {
            p($e->getMessage() . $e->getFile() . $e->getLine() . $e->getCode());
        }

    }

 

posted on 2017-10-18 15:58  zh7314  阅读(764)  评论(0)    收藏  举报