diff --git a/webapp/controller/DailySelectionController.class.php b/webapp/controller/DailySelectionController.class.php new file mode 100644 index 00000000..39811766 --- /dev/null +++ b/webapp/controller/DailySelectionController.class.php @@ -0,0 +1,429 @@ +_getAccountId(); + + $costs = mt\Parameter::getByName('daily_selection_refresh_cost'); + $arrCosts = explode('|', $costs['param_value']); + $maxCount = count($arrCosts); + + $count = $this->countTodayRefreshTimes($address); + if ($count >= $maxCount) { + $this->_rspErr(2, 'The maximum number of refreshes has been reached'); + return; + } + + $cost = $arrCosts[$count]; + $costItemId = $this->getCostItemIdByTokenType(ShopController::TOKEN_TYPE_GOLD); + $costItems = $this->makeCostItems($costItemId, $cost); + $lackItem = null; + if (!$this->_hasEnoughItems($costItems, $lackItem)) { + $this->_rspErr(2, $this->_getLackItemErrMsg($lackItem)); + return; + } + + $chk = $this->refreshDailySelectionWithMode($address, 1); + if ($chk) { + $this->_decItems($costItems); + + // error_log("refreshDailySelection-------" . $address . "---" . $cost); + $this->_rspData( + array( + 'cost' => $cost, + ) + ); + } else { + $this->_rspErr(3, 'refresh failed'); + } + } + + public function getDailySelectionList() + { + $address = $this->_getAccountId(); + + // 不清除过期的每日精选可以避免跨日操作错误 + // $chk = $this->clearBeforeTodayDailySelections(); + + $chk = $this->getTodayLastDailySelection($address); + if (!$chk) { + $chk = $this->refreshDailySelectionWithMode($address, 0); + $chk = $this->getTodayLastDailySelection($address); + } + + // 预检查是否有表格更新,未必能检测准确,但是可以避免大部分情况下的错误 + $check = true; + $selection = $chk[0]; + $pre_goodsList = array(); + for ($i = 1; $i <= 6; $i++) { + $pre_goodsList[$i] = mt\Dailyselection::get($selection['grid_' . $i]); + if (!$pre_goodsList[$i]) { + $check = false; + break; + } + } + if (!$check) { + $chk = $this->refreshDailySelectionWithMode($address, 0); + $chk = $this->getTodayLastDailySelection($address); + $selection = $chk[0]; + } + + $selection = $chk[0]; + $goodsList = array(); + for ($i = 1; $i <= 6; $i++) { + $goodsList[$i] = mt\Dailyselection::get($selection['grid_' . $i]); + if ($goodsList[$i]) { + $goodsList[$i]['count'] = $selection['count_' . $i]; + // $goodsList[$i]['pending'] = $this->checkPendingBuyGoodsDS($address, $goodsList[$i]['goods_id'], $selection['idx'], $i); + $goodsList[$i]['pending'] = 0; + } + } + + $count = $this->countTodayRefreshTimes($address); + $costs = mt\Parameter::getByName('daily_selection_refresh_cost'); + $arrCosts = explode('|', $costs['param_value']); + + $max_count = count($arrCosts); + $cost = $count < $max_count ? $arrCosts[$count] : -1; + + $this->_rspData( + array( + 'idx' => $selection['idx'], + 'refresh_info' => "{$count}/{$max_count}", + 'cost' => $cost, + 'goods_list' => $goodsList, + ) + ); + } + + public function buyGoodsDS() + { + $idx = getReqVal('idx', 0); + if ($idx <= 0) { + $this->_rspErr(2, 'idx is invalid'); + return; + } + + $grid = getReqVal('grid', 0); + if ($grid < 1 || $grid > 6) { + $this->_rspErr(2, 'grid is invalid'); + return; + } + + $count = getReqVal('count', 0); + if ($count<=0) { + $this->_rspErr(2, 'count is invalid'); + return; + } + + $token_type = getReqVal('token_type', '4'); + switch ($token_type) { + case ShopController::TOKEN_TYPE_GOLD: + case ShopController::TOKEN_TYPE_DIAMOND: + break; + default: + $this->_rspErr(1, "token_type is unsupport, {$token_type}"); + return; + } + + $conn = $this->_getMysql(''); + + $row = SqlHelper::selectOne( + $conn, + 't_shop_dailyselection', + array( + 'idx', + 'address', + 'grid_' . $grid, + 'count_' . $grid, + ), + array('idx' => $idx) + ); + + if (!$row) { + $this->_rspErr(2, 'idx is invalid'); + return; + } + + if ($row['grid_' . $grid] == 0) { + $this->_rspErr(2, 'grid is invalid'); + return; + } + + if ($row['count_' . $grid] < $count) { + $this->_rspErr(2, 'count is invalid'); + return; + } + + $sel_id = $row['grid_' . $grid]; + + $goods = mt\Dailyselection::get($sel_id); + + $desired_token_type = $goods['token_type']; + $check_token_type = splitStr1($desired_token_type); + if (!in_array($token_type, $check_token_type)) { + $this->_rspErr(1, "token_type parameter error, desired_token_type: {$desired_token_type}"); + return; + } + $token_pos = array_search($token_type, $check_token_type, true); + + $price_array = splitStr1($goods['price']); + $discount_array = splitStr1($goods['discount']); + + $need_price = $price_array[$token_pos]; + $discount = $discount_array[$token_pos]; + + $costItemId = $this->getCostItemIdByTokenType($token_type); + + $costItems = $this->makeCostItems($costItemId, $count * $need_price); + + error_log("buyGoodsDS costItems " . json_encode($costItems)); + + $lackItem = null; + if (!$this->_hasEnoughItems($costItems, $lackItem)) { + $this->_rspErr(2, $this->_getLackItemErrMsg($lackItem)); + return; + } + + $item_id = $goods['goods_id']; + $item_num = $goods['goods_num']; + + $sql = "UPDATE t_shop_dailyselection SET count_$grid = count_$grid - $count WHERE idx = $idx"; + $chk = $conn->execScript($sql); + + $itemMeta = mt\Item::get($item_id); + $propertyChgService = new services\PropertyChgService(); + for ($i = 0; $i < $count; $i++) { + $this->internalAddItem($propertyChgService, $itemMeta, $item_num, 0); + } + $awardService = new services\AwardService(); + $awardService->addItem($goods['goods_id'], $count * $item_num); + + $this->_decItems($costItems); + $event = [ + 'name' => LogService::SHOP_BUY_ITEM_DAILY, + 'val' => $costItems[0]['item_num'] + ]; + switch ($token_type) { + case ShopController::TOKEN_TYPE_GOLD: + LogService::consumeGold($event); + break; + case ShopController::TOKEN_TYPE_DIAMOND: + LogService::consumeDiamond($event); + break; + default: + // 这里不应该出现,出现了说明配置表新增了一种货币,但是这里没有处理 + error_log("buyGoodsDS token_type is invalid, token_type: {$token_type}"); + return; + } + + $goodsDto = array( + 'goods_id' => $sel_id, + 'item_id' => $goods['goods_id'], + 'price_info' => array( + 'item_id' => $goods['goods_id'], + 'cost_list' => array(), + ), + 'bought_times' => 0, + 'total_buy_times' => 0, + ); + { + $priceInfo = mt\Item::getPriceInfo($itemMeta); + if (!empty($priceInfo)) { + $goodsDto['price_info'] = $priceInfo['price_info']; + } + } + + $propertyChgService->addUserChg(); + + $this->_rspData( + array( + 'idx' => $idx, + 'grid' => $grid, + 'count' => $count, + 'award' => $awardService->toDto(), + 'property_chg' => $propertyChgService->toDto(), + ) + ); + } + + private function buyGoodsFree() + { + } + + private function decDailySelectionItem($idx, $grid, $count) + { + $self = myself(); + if (!$self) return false; + + $conn = $self->_getMysql(''); + $sql = "SELECT count_$grid FROM t_shop_dailyselection WHERE idx = $idx"; + $chk = $conn->execQuery($sql); + if (!$chk) return false; + if ($chk[0]['count_' . $grid] < $count) return false; + + $sql = "UPDATE t_shop_dailyselection SET count_$grid = count_$grid - $count WHERE idx = $idx"; + $chk = $conn->execScript($sql); + return $chk; + } + + private function clearBeforeTodayDailySelections() + { + $self = myself(); + if (!$self) return; + + $conn = $self->_getMysql(''); + $nowTime = $this->_getNowTime(); + $dayTime = $this->_getDaySeconds($nowTime); + + $sql = "DELETE FROM t_shop_dailyselection WHERE refresh_time < $dayTime"; + $chk = $conn->execScript($sql); + return $chk; + } + + private function countTodayRefreshTimes($address) + { + $self = myself(); + if (!$self) return; + + $conn = $self->_getMysql(''); + $nowTime = $this->_getNowTime(); + $dayTime = $this->_getDaySeconds($nowTime); + + $sql = "SELECT COUNT(idx) AS cnt FROM t_shop_dailyselection WHERE address = '$address' AND refresh_mode = 1 AND refresh_time >= $dayTime"; + + $row = $conn->execQuery($sql); + + return $row[0]['cnt']; + } + + private function getTodayLastDailySelection($address) + { + $self = myself(); + if (!$self) return; + + $conn = $self->_getMysql(''); + $nowTime = $this->_getNowTime(); + $dayTime = $this->_getDaySeconds($nowTime); + + $sql = "SELECT * FROM t_shop_dailyselection WHERE address = '$address' AND refresh_time >= $dayTime ORDER BY idx DESC LIMIT 1"; + + $row = $conn->execQuery($sql); + + return $row; + } + + private function refreshDailySelectionWithMode($address, $mode) + { + $selection = $this->randomNewDailySelection(); + + $self = myself(); + if (!$self) return; + + $conn = $self->_getMysql(''); + $nowTime = $this->_getNowTime(); + + $chk = SqlHelper::insert( + $conn, + 't_shop_dailyselection', + array( + 'address' => $address, + 'refresh_mode' => $mode, + 'refresh_time' => $nowTime, + 'grid_1' => $selection[1]['id'], + 'grid_2' => $selection[2]['id'], + 'grid_3' => $selection[3]['id'], + 'grid_4' => $selection[4]['id'], + 'grid_5' => $selection[5]['id'], + 'grid_6' => $selection[6]['id'], + 'count_1' => 1, + 'count_2' => 1, + 'count_3' => 1, + 'count_4' => 1, + 'count_5' => 1, + 'count_6' => 1, + ) + ); + + return $chk; + } + + private function randomNewDailySelection() + { + $newDailySelection = array(); + for ($i = 1; $i <= 6; $i++) { + $store = mt\Dailyselection::getBySlot($i); + $newDailySelection[$i] = $this->weighted_random($store); + } + return $newDailySelection; + } + + private function weighted_random($array) + { + // 计算数组元素的总权重 + $total_weight = array_sum(array_column($array, "weight")); + // 生成一个随机数 + $rand = mt_rand(1, $total_weight); + // 遍历数组,找到随机数对应的元素 + foreach ($array as $item) { + // 如果随机数小于或等于当前元素的权重,返回该元素 + if ($rand <= $item["weight"]) { + return $item; + } + // 否则,减去当前元素的权重,继续循环 + $rand -= $item["weight"]; + } + } + +}