DrawController.class.php 10.9 KB
<?php
/**
 * 【积分抽奖-手机端】立即抽奖
 *
 * @author: heyuelong
 * @date: 2018年3月26日11:18:11
 */

namespace Api\Controller\Activity;

use Common\Common\Constant;
use Common\Common\Integral;
use Common\Service\ActivityService;
use Common\Service\PrizeService;
use Common\Service\RecordService;
use Common\Service\RightService;
use Think\Log;
use VcySDK\Config;
use VcySDK\Service;

class DrawController extends \Api\Controller\AbstractController
{

    /** @var ActivityService */
    protected $_activity_service;
    /** @var RightService */
    protected $_right_service;
    /** @var PrizeService */
    protected $_prize_service;
    /** @var RecordService */
    protected $_record_service;

    public function before_action($action = '')
    {

        if (!parent::before_action($action)) {

            return false;
        }

        // 实例化活动
        $this->_activity_service = new ActivityService();
        // 实例化权限表
        $this->_right_service = new RightService();
        // 实例化商品表
        $this->_prize_service = new PrizeService();
        // 实例抽奖记录表
        $this->_record_service = new RecordService();
        return true;
    }

    /**
     * @return bool
     */
    public function Index_get()
    {
        $ac_id = I('get.ac_id', 0);

        // 验证
        $info = $this->validator($ac_id);
        $prize_info = $this->get_draw_good_info($ac_id);

        // 初始化记录信息
        $data = [
            'ac_id' => $ac_id,
            'lp_id' => $prize_info['lp_id'],
            'lp_name' => $prize_info['name'],
            'is_prize' => $prize_info['is_prize'],
            'cover_id' => $prize_info['cover_id'],
            'uid' => $this->uid,
            'username' => $this->_login->user['memUsername'],
            'dp_name' => implode(',', array_column($this->_login->user['dpName'], 'dpName')),
            'job' => strval($this->_login->user['memJob']),
            'role' => strval($this->_login->user['memRole']),
            'mobile' => strval($this->_login->user['memMobile'])
        ];

        try {
            $this->_record_service->start_trans();

            $lr_id = $this->_record_service->insert($data);
            $uid_list = $this->_record_service->list_by_conds(['ac_id' => $ac_id], null, [], 'uid');
            $uids = array_unique(array_column($uid_list, 'uid'));

            // 查询中奖次数
            $won_total = $this->_record_service->count_by_conds(['ac_id' => $ac_id, 'is_prize' => Constant::HAVE_PRIZE]);

            // 如果已中奖且库存大于0则更新库存
            if (Constant::HAVE_PRIZE == $prize_info['is_prize'] && $prize_info['stock_num'] > 0) {
                // 更新库存
                $prize_total = $this->_prize_service->update_by_conds(['lp_id' => $prize_info['lp_id']], ['stock_num=stock_num - ?' => 1]);

                if (!$prize_total) {
                    $this->_record_service->rollback();
                    E('_ERR_ACTIVITY_LOTTERY');
                    return false;
                }
            }

            // 更新已参与人数
            $update_total = $this->_activity_service->update($ac_id, [
                'join_people' => count($uids),
                'already_num' => count($uid_list),
                'won_num' => $won_total,
            ]);

            if (!$update_total || !$lr_id) {
                $this->_record_service->rollback();
                E('_ERR_ACTIVITY_LOTTERY');
                return false;
            }

            $this->_record_service->commit();
        } catch (\Exception $e) {
            \Think\Log::record($e);
            $this->_record_service->rollback();
            E('_ERR_ACTIVITY_LOTTERY');
            return false;
        }

        $change_params = [
            // 用户id
            'memUid' => $this->uid,
            // 积分类型 (默认mi_type0)
            'miType' => 'mi_type0',
            // 积分策略key,integral不为空时,传业务自己的积分规则key
            'irKey' => 'lottery',
            // 积分变更说明
            'remark' => '积分抽奖-' . $info['title'],
            // 变更的积分值
            'integral' => !empty($info['integral']) ? -intval($info['integral']) : 0,
            // 应用标识(消息推送必要)
            'msgIdentifier' => Config::instance()->pluginIdentifier,
            'businessKey' => 'integral_center',
            'businessAct' => 'lottery',
        ];

        try {
            $result = Integral::instance()->asynUpdateIntegral($change_params);
        } catch (\Exception $e) {
            Log::record('trigger integral strategy fail: ' . $e->getMessage(), Log::ERR);
        }
        // 获取当前用户积分
        $sdk = new \VcySDK\Integral(Service::instance());
        $integral_info = $sdk->detail(['memUid' => $this->uid]);

        // 格式化详情数据
        $this->_result = [
            'available' => $integral_info['available'],
            'lr_id' => $lr_id,
            'lp_id' => $prize_info['lp_id'],
            'name' => $prize_info['name'],
            'is_prize' => $prize_info['is_prize'],
            'img_url' => imgUrl($prize_info['cover_id'])
        ];

        return true;
    }

    /**
     * 获取抽中的奖品详情
     * @param int $ac_id 活动ID
     * @return mixed
     */
    protected function get_draw_good_info($ac_id = 0)
    {
        // 需要查询的字段
        $fields = 'lp_id,name,cover_id,num,percent,lottery_max,lottery_min,is_prize,stock_num';
        // 获取奖品列表
        $prize_list = $this->_prize_service->get_prize_list(['ac_id' => $ac_id], $fields);
        $prize_list = array_combine_by_key($prize_list, 'lp_id');
        // 奖品数组
        $data = [];
        $argc = 0;
        // 不是中奖奖品的IDS集合
        $ids = [];
        foreach ($prize_list as $v) {
            // 如果是有库存的中奖奖品且有概率
            if ($v['stock_num'] > 0 && Constant::HAVE_PRIZE == $v['is_prize'] && $v['percent']) {
                $max = $argc + $v['percent'] * 100;
                $data[$v['lp_id']] = [
                    'min' => $argc + 1,
                    'max' => $max,
                ];
                $argc = $max;
            } else if (Constant::NO_PRIZE == $v['is_prize']) {
                $ids[] = $v['lp_id'];
            }

        }
        // 奖品记录ID
        $prize_id = 0;
        $num = rand(1, 10000);
        foreach ($data as $key => $item) {
            if ($num >= $item['min'] && $num <= $item['max']) {
                $prize_id = $key;
                break;
            }
        }

        if (!empty($prize_id)) {
            // 奖品详情
            $prize_info = $this->_prize_service->get($prize_id);
            // 获取当前用户已抽中该奖项次数
            $total = $this->_record_service->count_by_conds(['ac_id' => $ac_id, 'uid' => $this->uid, 'lp_id' => $prize_id]);
            // 获取此活动总的抽奖次数
            $lottery_total = $this->_record_service->count_by_conds(['ac_id' => $ac_id]);
            // 如果超过该奖品的最大中奖次数则设置为不中奖 || 小于最小抽奖次数抽中该奖品则设置为不中奖 || 没有奖品了则显示未中奖
            if ((!empty($prize_info['lottery_max']) && $prize_info['lottery_max'] <= $total)
                ||
                (!empty($prize_info['lottery_min']) && $prize_info['lottery_min'] > $lottery_total)
                ||
                ($prize_info['stock_num'] == 0)
            ) {
                $prize_key = array_rand($ids, 1);
                $prize_id = $ids[$prize_key];
            }
        } else {
            $prize_key = array_rand($ids, 1);
            $prize_id = $ids[$prize_key];
        }

        return $prize_list[$prize_id];
    }

    /**
     * 活动抽奖验证
     * @param int $ac_id 活动ID
     * @return mixed
     */
    protected function validator($ac_id = 0)
    {

        if (empty($ac_id)) {
            // 验证参数
            E('_EMPTY_ACTIVITY_ID');
        }

        // 获取活动详细内容
        $info = $this->_activity_service->get_by_conds(
            [
                'ac_id' => $ac_id,
                'activity_status > ?' => 0
            ]
        );

        if (empty($info)) {
            // 数据不存在时抛错
            E('_ERR_DATA_NOT_EXIST');
        }

        // 如果不是全公司
        if (Constant::IS_ALL_FALSE == $info['is_all']) {
            // 获取用户权限ID
            $ids = $this->_right_service->getUserRight($this->_login->user);
            sort($ids);
            // 统计用户是否有权限
            $total = $this->_right_service->count_by_conds(['ac_id' => $ac_id, 'obj_id' => $ids]);

            // 如果没有权限
            if (empty($total)) {
                E('_ERR_ACTIVITY_NOT_AUTH');
            }
        }

        // 活动状态
        $status = $this->_prize_service->activity_status($info['activity_status'], $info['start_time'], $info['end_time']);

        // 活动未开始不能抽奖
        if (Constant::STATUS_NOT_START == $status) {
            E('_ERR_ACTIVITY_STATUS_NOT_START');
        }
        // 活动已结束不能抽奖
        if (Constant::STATUS_END == $status) {
            E('_ERR_ACTIVITY_STATUS_END');
        }
        // 活动已终止不能抽奖
        if (Constant::STATUS_STOP == $status) {
            E('_ERR_ACTIVITY_STATUS_STOP');
        }

        // 获取当前用户积分
        $sdk = new \VcySDK\Integral(Service::instance());
        $integral_info = $sdk->detail(['memUid' => $this->uid]);

        // 如果积分不足则不能抽奖
        if ($info['integral'] > $integral_info['available']) {
            E('_ERR_LACK_OF_INTEGRAL');
        }

        if (Constant::DAY_LOTTERY_TYPE == $info['limit_type'] && $info['num_limit'] > 0) {
            // 每天限制抽奖类型

            $start_time = rstrtotime(rgmdate((string)NOW_TIME, 'Y-m-d 0:0:0'), 1);
            $end_time = rstrtotime(rgmdate((string)NOW_TIME, 'Y-m-d 23:59:59'), 1);

            $conds = [
                'ac_id' => $ac_id,
                'created >=?' => $start_time,
                'created <=?' => $end_time,
                'uid' => $this->uid
            ];

            $total = $this->_record_service->count_by_conds($conds);
            if ($total >= $info['num_limit']) {
                E('当天抽奖次数已用完(' . $info['num_limit'] . '次),请明天继续参与!', '4201001');
            }

        } else if (Constant::TOTAL_LOTTERY_TYPE == $info['limit_type'] && $info['num_limit'] > 0) {

            // 总体限制抽奖类型
            $total = $this->_record_service->count_by_conds(['ac_id' => $ac_id, 'uid' => $this->uid]);
            if ($total >= $info['num_limit']) {
                E('该活动抽奖次数已用完(' . $info['num_limit'] . '次),无法继续参与抽奖!', '4201002');
            }
        }

        return $info;
    }
}