This commit is contained in:
hujiabin 2024-10-11 12:07:23 +08:00
commit a3f5c50f1f
11 changed files with 575 additions and 1 deletions

View File

@ -0,0 +1,10 @@
<?php
return array(
'instance_id' => 1,
'host' => 'mysql-host',
'port' => 3306,
'user' => 'root',
'passwd' => 'keji178',
'dbname' => 'logdb_dev_1'
);

39
doc/HashRateShop.py Normal file
View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
import _common
class HashRateShop(object):
def __init__(self):
self.apis = [
{
'name': 'getGoodsList',
'desc': '获取商品列表',
'group': 'HashRateShop',
'url': 'webapp/index.php?c=HashRateShop&a=getGoodsList',
'params': [
_common.ReqHead(),
],
'response': [
_common.RspHead(),
['!goods_list', [_common.HashRateGoods()], '商品列表'],
]
},
{
'name': 'buyGoodsS',
'desc': '购买商品',
'group': 'HashRateShop',
'surl': 'webapp/index.php?c=HashRateShop&a=buyGoodsS',
'params': [
_common.ReqHead(),
['goods_id', '', '商品唯一id'],
['goods_num', '', '商品数量'],
],
'response': [
_common.RspHead(),
['goods_info', _common.HashRateGoods(), '商品信息(客户端刷新用)'],
['award', _common.Award(), '奖励信息'],
['property_chg', _common.PropertyChg(), '属性变更'],
]
}
]

View File

@ -1934,3 +1934,15 @@ class VipLevelInfo(object):
['curpoint', 0, '当前点数'],
['target', 0, '升级所需点数,如为-1则已是最高等级'],
]
class HashRateGoods(object):
def __init__(self):
self.fields = [
['goods_id', 0, '商品id'],
['item_id', 0, '道具id'],
['item_num', 0, '道具数量'],
['purchased_num', 0, '已购买数量'],
['max_num', 0, '最大数量(-1不限购)'],
['count_down', 0, '倒计时(单位秒,只有已售罄才有效)'],
]

View File

@ -2194,3 +2194,28 @@ CREATE TABLE `t_rookie_task_value` (
) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
/*!40101 SET character_set_client = @saved_cs_client */;
-- Table structure for table `t_hashrate_shop_buy_record`
--
DROP TABLE IF EXISTS `t_hashrate_shop_buy_record`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `t_hashrate_shop_buy_record` (
`idx` bigint NOT NULL AUTO_INCREMENT COMMENT '自增id',
`account_id` varchar(60) NOT NULL DEFAULT '' COMMENT '账号id',
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品id',
`item_id` int(11) NOT NULL DEFAULT '0' COMMENT '道具id',
`this_day_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '今日购买次数',
`this_week_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '本周购买次数',
`this_month_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '本月购买次数',
`total_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '总购买次数',
`last_buy_time` int(11) NOT NULL DEFAULT '0' COMMENT '最后一次购买时间',
`createtime` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`modifytime` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间',
PRIMARY KEY (`idx`),
KEY `account_id` (`account_id`),
UNIQUE KEY `account_id_goods_id` (`account_id`, `goods_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
/*!40101 SET character_set_client = @saved_cs_client */;

View File

@ -14,6 +14,7 @@ CREATE TABLE `t_user_bind_gold_record` (
PRIMARY KEY (`idx`)
) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `t_user_rookie_task_bind` (
`idx` bigint NOT NULL AUTO_INCREMENT COMMENT '自增id',
`account_id` varchar(60) NOT NULL DEFAULT '' COMMENT '账号id(channel + "_" + gameid + "_" + openid)',
@ -44,6 +45,24 @@ CREATE TABLE `t_rookie_task_value` (
UNIQUE KEY `account_id_task` (`account_id`, `task_type`)
) ENGINE=InnoDB AUTO_INCREMENT=10000 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `t_hashrate_shop_buy_record` (
`idx` bigint NOT NULL AUTO_INCREMENT COMMENT '自增id',
`account_id` varchar(60) NOT NULL DEFAULT '' COMMENT '账号id',
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品id',
`item_id` int(11) NOT NULL DEFAULT '0' COMMENT '道具id',
`this_day_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '今日购买次数',
`this_week_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '本周购买次数',
`this_month_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '本月购买次数',
`total_buy_times` int(11) NOT NULL DEFAULT '0' COMMENT '总购买次数',
`last_buy_time` int(11) NOT NULL DEFAULT '0' COMMENT '最后一次购买时间',
`createtime` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
`modifytime` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间',
PRIMARY KEY (`idx`),
KEY `account_id` (`account_id`),
UNIQUE KEY `account_id_goods_id` (`account_id`, `goods_id`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
insert into version (version) values(2024092401);
commit;

View File

@ -88,6 +88,26 @@ class BaseController {
return phpcommon\getMondaySeconds($time, $this->timeZone);
}
public function _getMonthFirstDaySeconds()
{
return phpcommon\getThisMonthFirstDaySeconds($this->_getNowTime(), $this->timeZone);
}
public function _getMonthFirstDaySecondsByTime($time)
{
return phpcommon\getThisMonthFirstDaySeconds($time, $this->timeZone);
}
public function _getNextMonthFirstDaySeconds()
{
return phpcommon\getNextMonthFirstDaySeconds($this->_getNowTime(), $this->timeZone);
}
public function _getNextMonthFirstDaySecondsByTime($time)
{
return phpcommon\getNextMonthFirstDaySeconds($time, $this->timeZone);
}
public function _inTimeRangeStr($beginTimeStr, $endTimeStr)
{
$beginTimeOffset = myself()->_getDaySecondsOffset(strtotime("2024-6-22 ". $beginTimeStr));

View File

@ -0,0 +1,121 @@
<?php
require_once('services/HashRateShopService.php');
require_once('services/AwardService.php');
require_once('services/PropertyChgService.php');
require_once('mt/HashRateShop.php');
require_once('mt/Item.php');
require_once('models/HashRate.php');
require_once('models/HashRateShopBuyRecord.php');
use phpcommon\SqlHelper;
use services\HashRateShopService;
class HashRateShopController extends BaseAuthedController {
public function getGoodsList()
{
$goodsList = HashRateShopService::getGoodsList();
myself()->_rspData(
array(
'goods_list' => $goodsList,
)
);
}
public function testBuyGoods()
{
if (SERVER_ENV != _ONLINE) {
$this->internalBuyGoods();
}
}
public function buyGoodsS()
{
$this->internalBuyGoods();
}
public function internalBuyGoods()
{
if (SERVER_ENV == _ONLINE) {
myself()->_verifySwitch('hashrate.shop.buy');
}
$goodsId = getReqVal('goods_id', 0);
$goodsNum = intval(getReqVal('goods_num', 0));
if ($goodsNum < 1) {
myself()->_rspErr(1, "goods_num parameter error, goods_num: {$goodsNum}");
return;
}
$goodsMeta = mt\HashRateShop::find($goodsId);
if (!$goodsMeta) {
myself()->_rspErr(1, 'goods not found');
return;
}
if ($goodsMeta['is_close']) {
myself()->_rspErr(1, 'no right to purchase');
return;
}
$itemMeta = mt\Item::get($goodsMeta['type']);
if (!$itemMeta) {
myself()->_rspErr(1, 'goods not found, goods_id: ' . $goodsMeta['goods_id']);
return;
}
$errCode = 0;
$errMsg = '';
if (!HashRateShopService::buyLimitCheck($goodsMeta, $goodsNum, $errCode, $errMsg)) {
myself()->_rspErr($errCode, $errMsg);
return;
}
$propertyChgService = new services\PropertyChgService();
$awardService = new services\AwardService();
$price = $goodsMeta['pile_price'];
if ($price < 1) {
myself()->_rspErr(1, "config error");
return;
}
if ($price * $goodsNum > models\HashRate::getMyCurrentHashRate()) {
myself()->_rspErr(2, "hashrate not enough");
return;
}
models\HashRate::decMyCurrentHashRate($price * $goodsNum);
error_log(models\HashRate::getMyCurrentHashRate());
models\HashRateShopBuyRecord::add($goodsMeta['id'], $goodsNum, $goodsMeta['type']);
for ($i = 0; $i < $goodsNum; $i++) {
$this->internalAddItem($awardService,
$propertyChgService,
$itemMeta,
$goodsMeta['item_num']
);
}
$propertyChgService->addUserChg();
$this->_rspData(
array(
'award' => $awardService->toDto(),
'property_chg' => $propertyChgService->toDto(),
)
);
}
private function internalAddItem($awardService,
$propertyChgService,
$itemMeta,
$count
)
{
myself()->_addItems(
array(
array(
'item_id' => $itemMeta['id'],
'item_num' => $count
)
),
$awardService,
$propertyChgService);
}
}

View File

@ -109,6 +109,46 @@ class HashRate extends BaseModel
return $myHashRate;
}
public static function getMyCurrentHashRate(){
$currentPeriod = myself()->_callMtStatic('AchievementsCycle', 'getCurrentPeriod');
if (empty($currentPeriod)) {
return 0;
}
$row = SqlHelper::ormSelectOne(
myself()->_getSelfMysql(),
't_hash_rate_reward',
array(
'account_id' => myself()->_getAccountId(),
'period' => $currentPeriod['id'],
)
);
$myHashRate = 0;
if ($row){
$myHashRate = $row['reward'];
}
return $myHashRate;
}
public static function decMyCurrentHashRate($val){
$val = intval($val);
$currentPeriod = myself()->_callMtStatic('AchievementsCycle', 'getCurrentPeriod');
if ($currentPeriod) {
SqlHelper::update(
myself()->_getSelfMysql(),
't_hash_rate_reward',
array(
'account_id' => myself()->_getAccountId(),
'period' => $currentPeriod['id'],
),
array(
'reward' => function () use($val) {
return "GREATEST(0, reward - ${val})";
},
)
);
}
}
public static function getTotalByAccount($accountId,$period){
$row = SqlHelper::ormSelectOne(
myself()->_getSelfMysql(),
@ -126,4 +166,4 @@ class HashRate extends BaseModel
}
}
}

View File

@ -0,0 +1,111 @@
<?php
namespace models;
use mt;
use phpcommon\SqlHelper;
class HashRateShopBuyRecord extends BaseModel
{
public static function find($goodsId)
{
$row = SqlHelper::ormSelectOne(
myself()->_getSelfMysql(),
't_hashrate_shop_buy_record',
array(
'account_id' => myself()->_getAccountId(),
'goods_id' => $goodsId,
)
);
return $row;
}
public static function all()
{
$rows = SqlHelper::ormSelect(
myself()->_getSelfMysql(),
't_hashrate_shop_buy_record',
array(
'account_id' => myself()->_getAccountId(),
)
);
return array_map(function ($row) {
$nowDaySeconds = myself()->_getNowDaySeconds();
if (!($row['last_buy_time'] >= $nowDaySeconds &&
$row['last_buy_time'] <= $nowDaySeconds + 3600 * 24)) {
$row['this_day_buy_times'] = 0;
}
$mondaySeconds = myself()->_getMondaySeconds();
if (!($row['last_buy_time'] >= $mondaySeconds &&
$row['last_buy_time'] <= $mondaySeconds + 3600 * 24 * 7)) {
$row['this_week_buy_times'] = 0;
}
$monthFirstDaySeconds = myself()->_getMonthFirstDaySeconds();
$nextMonthFirstDaySeconds = myself()->_getNextMonthFirstDaySeconds();
if (!($row['last_buy_time'] >= $monthFirstDaySeconds &&
$row['last_buy_time'] <= $nextMonthFirstDaySeconds)) {
$row['this_month_buy_times'] = 0;
}
return $row;
}, $rows);
}
public static function allToHash()
{
$rows = self::all();
$buyRecordHash = array();
array_walk($rows, function ($row) use (&$buyRecordHash) {
$buyRecordHash[$row['goods_id']] = $row;
});
return $buyRecordHash;
}
public static function add($goodsId, $goodsNum, $itemId)
{
$goodsNum = intval($goodsNum);
SqlHelper::upsert(
myself()->_getSelfMysql(),
't_hashrate_shop_buy_record',
array(
'account_id' => myself()->_getAccountId(),
'goods_id' => $goodsId,
),
array(
'this_day_buy_times' => function () use($goodsNum) {
$nowDaySeconds = myself()->_getNowDaySeconds();
$cond = " last_buy_time>=${nowDaySeconds} AND last_buy_time<=${nowDaySeconds} + 3600 * 24 ";
return "CASE WHEN (${cond}) THEN this_day_buy_times + ${goodsNum} ELSE 0 END";
},
'this_week_buy_times' => function () use($goodsNum) {
$mondaySeconds = myself()->_getMondaySeconds();
$cond = " last_buy_time>=${mondaySeconds} AND last_buy_time<=${mondaySeconds} + 3600 * 24 * 7 ";
return "CASE WHEN (${cond}) THEN this_week_buy_times + ${goodsNum} ELSE 0 END";
},
'this_month_buy_times' => function () use($goodsNum) {
$monthFirstDaySeconds = myself()->_getMonthFirstDaySeconds();
$cond = " last_buy_time>=${monthFirstDaySeconds} ";
return "CASE WHEN (${cond}) THEN this_month_buy_times + ${goodsNum} ELSE 0 END";
},
'total_buy_times' => function () use($goodsNum) {
return "total_buy_times + ${goodsNum}";
},
'last_buy_time' => myself()->_getNowTime(),
'modifytime' => myself()->_getNowTime(),
),
array(
'account_id' => myself()->_getAccountId(),
'goods_id' => $goodsId,
'item_id' => $itemId,
'this_day_buy_times' => $goodsNum,
'this_week_buy_times' => $goodsNum,
'this_month_buy_times' => $goodsNum,
'total_buy_times' => $goodsNum,
'last_buy_time' => myself()->_getNowTime(),
'createtime' => myself()->_getNowTime(),
'modifytime' => myself()->_getNowTime(),
)
);
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace mt;
use phpcommon;
class HashRateShop {
const TOTAL_BUY_LIMIT = 0;
const DAILY_BUY_LIMIT = 1;
const WEEKLY_BUY_LIMIT = 2;
const MONTH_BUY_LIMIT = 3;
public static function find($id){
return getXVal(self::getMetaList(), $id, null);
}
protected static function getMetaList()
{
if (!self::$metaList) {
self::$metaList = getMetaTable('hashrateshop@hashrateshop.php');
}
return self::$metaList;
}
public static function all()
{
return self::getMetaList();
}
protected static $metaList;
}

View File

@ -0,0 +1,144 @@
<?php
namespace services;
require_once('models/HashRateShopBuyRecord.php');
require_once('mt/HashRateShop.php');
require_once('mt/Item.php');
use mt;
use phpcommon;
use models\HashRateShopBuyRecord;
class HashRateShopService {
public static function getGoodsList()
{
$goodsMetaList = mt\HashRateShop::all();
$buyRecordHash = HashRateShopBuyRecord::allToHash();
$goodsList = array();
foreach ($goodsMetaList as $goodsMeta) {
if ($goodsMeta['is_close']) {
continue;
}
if ($goodsMeta['first_time'] > myself()->_getNowTime()) {
continue;
}
$goodsDto = array(
'goods_id' => $goodsMeta['id'],
'price' => $goodsMeta['pile_price'],
'item_id' => $goodsMeta['type'],
'item_num' => $goodsMeta['item_num'],
'purchased_num' => 0,
'max_num' => $goodsMeta['limit_num'],
'count_down' => 0,
);
switch ($goodsMeta['limit_type']) {
case mt\HashRateShop::DAILY_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsMeta['id']);
$goodsDto['purchased_num'] = $buyRecord ? $buyRecord['this_day_buy_times'] : 0;
if ($buyRecord && $goodsDto['purchased_num'] > 0 &&
$goodsDto['purchased_num'] >= $goodsDto['max_num']) {
$goodsDto['count_down'] = myself()->_getNowDaySeconds() + 3600 * 24 - myself()->_getNowTime();
}
}
break;
case mt\HashRateShop::WEEKLY_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsMeta['id']);
$goodsDto['purchased_num'] = $buyRecord ? $buyRecord['this_week_buy_times'] : 0;
if ($buyRecord && $goodsDto['purchased_num'] > 0 &&
$goodsDto['purchased_num'] >= $goodsDto['max_num']) {
$goodsDto['count_down'] = myself()->_getMondaySeconds() + 3600 * 24 * 7 - myself()->_getNowTime();
}
}
break;
case mt\HashRateShop::MONTH_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsMeta['id']);
$goodsDto['purchased_num'] = $buyRecord ? $buyRecord['this_week_buy_times'] : 0;
}
break;
case mt\HashRateShop::TOTAL_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsMeta['id']);
$goodsDto['purchased_num'] = $buyRecord ? $buyRecord['total_buy_times'] : 0;
}
break;
default: {
}
break;
}
array_push($goodsList, $goodsDto);
}
return $goodsList;
}
public static function buyLimitCheck($goodsMeta, $goodsNum, &$errCode, &$errMsg)
{
if ($goodsMeta['is_close']) {
$errCode = 1;
$errMsg = 'cant buy';
return;
}
if ($goodsMeta['first_time'] > myself()->_getNowTime()) {
$errCode = 1;
$errMsg = 'cant buy';
return;
}
$errCode = 0;
$errMsg = '';
$buyRecordHash = HashRateShopBuyRecord::allToHash();
$boughtTimes = 1;
$goodsId = $goodsMeta['id'];
{
switch ($goodsMeta['limit_type']) {
case mt\HashRateShop::DAILY_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsId);
$boughtTimes = $buyRecord ? $buyRecord['this_day_buy_times'] + $goodsNum : 1;
if ($buyRecord && getXVal($buyRecord, 'this_day_buy_times', 0) >= $goodsMeta['limit_num']) {
$errCode = 2;
$errMsg = 'Daily purchase limit';
return false;
}
}
break;
case mt\HashRateShop::WEEKLY_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsId);
$boughtTimes = $buyRecord ? $buyRecord['this_week_buy_times'] + $goodsNum : 1;
if ($buyRecord && getXVal($buyRecord, 'this_week_buy_times', 0) >= $goodsMeta['limit_num']) {
$errCode = 2;
$errMsg = 'Weekly purchase limit reached';
return false;
}
}
break;
case mt\HashRateShop::MONTH_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsId);
$boughtTimes = $buyRecord ? $buyRecord['this_month_buy_times'] + $goodsNum : 1;
if ($buyRecord && getXVal($buyRecord, 'this_month_buy_times', 0) >= $goodsMeta['limit_num']) {
$errCode = 2;
$errMsg = 'Month purchase limit reached';
return false;
}
}
break;
case mt\HashRateShop::TOTAL_BUY_LIMIT: {
$buyRecord = getXVal($buyRecordHash, $goodsId);
$boughtTimes = $buyRecord ? $buyRecord['total_buy_times'] + $goodsNum : 1;
if ($buyRecord && getXVal($buyRecord, 'total_buy_times', 0) >= $goodsMeta['limit_num']) {
$errCode = 2;
$errMsg = 'Purchase limit reached';
return false;
}
}
break;
default: {
}
break;
}
}
return true;
}
}