mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-03 14:10:57 +08:00
bonus logs
This commit is contained in:
@@ -16,5 +16,6 @@ enum PermissionEnum: string {
|
||||
case MANAGE_USER_BASIC_INFO = "prfmanage";
|
||||
case MANAGE_USER_CONFIDENTIAL_INFO = "cruprfmanage";
|
||||
case VIEW_USER_CONFIDENTIAL_INFO = "userprofile";
|
||||
case VIEW_USER_HISTORY = "viewhistory";
|
||||
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class BonusLogResource extends Resource
|
||||
})
|
||||
,
|
||||
SelectFilter::make('business_type')
|
||||
->options(BonusLogs::listStaticProps(Arr::except(BonusLogs::$businessTypes, BonusLogs::$businessTypeBonus), 'bonus-log.business_types', true))
|
||||
->options(BonusLogs::listBusinessTypeOptions(BonusLogs::CATEGORY_COMMON))
|
||||
->label(__('bonus-log.fields.business_type'))
|
||||
->searchable(true)
|
||||
,
|
||||
|
||||
@@ -4,14 +4,17 @@ namespace App\Models;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class BonusLogs extends NexusModel
|
||||
{
|
||||
protected $table = 'bonus_logs';
|
||||
|
||||
protected $fillable = ['uid', 'business_type', 'old_total_value', 'value', 'new_total_value', 'comment'];
|
||||
protected $fillable = ['uid', 'business_type', 'old_total_value', 'value', 'new_total_value', 'comment', 'created_at', 'updated_at'];
|
||||
|
||||
public $timestamps = true;
|
||||
const CATEGORY_COMMON = 'common';
|
||||
const CATEGORY_SEEDING = 'seeding';
|
||||
|
||||
const DEFAULT_BONUS_CANCEL_ONE_HIT_AND_RUN = 10000;
|
||||
const DEFAULT_BONUS_BUY_ATTENDANCE_CARD = 1000;
|
||||
@@ -100,7 +103,7 @@ class BonusLogs extends NexusModel
|
||||
self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION => ['text' => 'Seeding medal addition'],
|
||||
];
|
||||
|
||||
public static array $businessTypeBonus = [
|
||||
public static array $businessTypeSeeding = [
|
||||
self::BUSINESS_TYPE_SEEDING_BASIC,
|
||||
self::BUSINESS_TYPE_SEEDING_DONOR_ADDITION,
|
||||
self::BUSINESS_TYPE_SEEDING_OFFICIAL_ADDITION,
|
||||
@@ -108,6 +111,28 @@ class BonusLogs extends NexusModel
|
||||
self::BUSINESS_TYPE_SEEDING_MEDAL_ADDITION
|
||||
];
|
||||
|
||||
public static function listBusinessTypeOptions($category = ''): array
|
||||
{
|
||||
$source = BonusLogs::$businessTypes;
|
||||
if ($category == self::CATEGORY_COMMON) {
|
||||
$source = Arr::except(BonusLogs::$businessTypes, BonusLogs::$businessTypeSeeding);
|
||||
} else if ($category == self::CATEGORY_SEEDING) {
|
||||
$source = Arr::only(BonusLogs::$businessTypes, BonusLogs::$businessTypeSeeding);
|
||||
}
|
||||
return self::listStaticProps($source, 'bonus-log.business_types', true);
|
||||
}
|
||||
|
||||
public static function listCategoryOptions(bool $includeSeeding): array
|
||||
{
|
||||
$result = [
|
||||
self::CATEGORY_COMMON => nexus_trans('bonus-log.category_common')
|
||||
];
|
||||
if ($includeSeeding) {
|
||||
$result[self::CATEGORY_SEEDING] = nexus_trans('bonus-log.category_seeding');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getBusinessTypeTextAttribute()
|
||||
{
|
||||
return nexus_trans('bonus-log.business_types.' . $this->business_type);
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Models\UserMedal;
|
||||
use App\Models\UserMeta;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Nexus\Database\ClickHouse;
|
||||
use Nexus\Database\NexusDB;
|
||||
|
||||
class BonusRepository extends BaseRepository
|
||||
@@ -362,5 +363,51 @@ class BonusRepository extends BaseRepository
|
||||
});
|
||||
}
|
||||
|
||||
public function getCount(int $userId, string $category, int $businessType = 0): int
|
||||
{
|
||||
if ($category == BonusLogs::CATEGORY_COMMON) {
|
||||
$query = BonusLogs::query()->where('uid', $userId);
|
||||
if ($businessType > 0) {
|
||||
$query->where('business_type', $businessType);
|
||||
}
|
||||
return $query->count();
|
||||
} else if ($category == BonusLogs::CATEGORY_SEEDING) {
|
||||
$whereStr = "uid = :uid";
|
||||
$binds = ["uid" => $userId];
|
||||
if ($businessType > 0) {
|
||||
$whereStr .= " AND business_type = :business_type";
|
||||
$binds["business_type"] = $businessType;
|
||||
}
|
||||
return ClickHouse::count("bonus_logs", $whereStr, $binds);
|
||||
}
|
||||
throw new \InvalidArgumentException("Invalid category: $category");
|
||||
}
|
||||
|
||||
public function getList(int $userId, string $category, int $businessType = 0, int $page = 1, int $perPage = 50)
|
||||
{
|
||||
if ($category == BonusLogs::CATEGORY_COMMON) {
|
||||
$query = BonusLogs::query()->where('uid', $userId);
|
||||
if ($businessType > 0) {
|
||||
$query->where('business_type', $businessType);
|
||||
}
|
||||
return $query->orderBy("id", "desc")->forPage($page, $perPage)->get();
|
||||
} else if ($category == BonusLogs::CATEGORY_SEEDING) {
|
||||
$sql = "select * from bonus_logs where uid = :uid";
|
||||
$binds = ["uid" => $userId];
|
||||
if ($businessType > 0) {
|
||||
$sql .= " AND business_type = :business_type";
|
||||
$binds["business_type"] = $businessType;
|
||||
}
|
||||
$offset = ($page - 1) * $perPage;
|
||||
$rows = ClickHouse::list("$sql order by created_at desc limit $offset, $perPage", $binds);
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$result[] = new BonusLogs($row);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
throw new \InvalidArgumentException("Invalid category: $category");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -24,12 +24,12 @@ return [
|
||||
*/
|
||||
|
||||
'connection' => [
|
||||
'host' => env('CLICKHOUSE_HOST', 'localhost'),
|
||||
'port' => env('CLICKHOUSE_HTTP_PORT', 8123),
|
||||
'username' => env('CLICKHOUSE_USER', 'default'),
|
||||
'password' => env('CLICKHOUSE_PASSWORD', ''),
|
||||
'host' => nexus_env('CLICKHOUSE_HOST', 'localhost'),
|
||||
'port' => nexus_env('CLICKHOUSE_HTTP_PORT', 8123),
|
||||
'username' => nexus_env('CLICKHOUSE_USER', 'default'),
|
||||
'password' => nexus_env('CLICKHOUSE_PASSWORD', ''),
|
||||
'options' => [
|
||||
'database' => env('CLICKHOUSE_DATABASE', 'default'),
|
||||
'database' => nexus_env('CLICKHOUSE_DATABASE', 'default'),
|
||||
'timeout' => 1,
|
||||
'connectTimeOut' => 2,
|
||||
],
|
||||
@@ -42,7 +42,7 @@ return [
|
||||
*/
|
||||
|
||||
'migrations' => [
|
||||
'table' => env('CLICKHOUSE_MIGRATION_TABLE', 'migrations'),
|
||||
'path' => database_path('clickhouse-migrations'),
|
||||
'table' => nexus_env('CLICKHOUSE_MIGRATION_TABLE', 'migrations'),
|
||||
'path' => __DIR__ . '/../database/clickhouse-migrations',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -301,6 +301,7 @@ function nexus_config($key, $default = null)
|
||||
ROOT_PATH . 'config/nexus.php',
|
||||
ROOT_PATH . 'config/emoji.php',
|
||||
ROOT_PATH . 'config/captcha.php',
|
||||
ROOT_PATH . 'config/clickhouse.php',
|
||||
];
|
||||
foreach ($files as $file) {
|
||||
$basename = basename($file);
|
||||
|
||||
54
nexus/Database/ClickHouse.php
Normal file
54
nexus/Database/ClickHouse.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Nexus\Database;
|
||||
|
||||
use ClickHouseDB\Client;
|
||||
|
||||
class ClickHouse
|
||||
{
|
||||
private static ?Client $client = null;
|
||||
public static function getClient(): Client
|
||||
{
|
||||
if (is_null(self::$client)) {
|
||||
$config = nexus_config('clickhouse.connection');
|
||||
$client = new Client($config);
|
||||
$options = $config['options'];
|
||||
$client->database($options['database']);
|
||||
// $client->setTimeout($options['timeout']);
|
||||
$client->setConnectTimeOut($options['connectTimeOut']);
|
||||
self::$client = $client;
|
||||
}
|
||||
return self::$client;
|
||||
}
|
||||
|
||||
public static function count(string $table, string $whereStr = '', array $binds = []): int
|
||||
{
|
||||
$start = microtime(true);
|
||||
$countAlias = "count";
|
||||
$sql = "select count(*) as $countAlias from $table";
|
||||
$whereStr = strtolower(trim($whereStr));
|
||||
if ($whereStr) {
|
||||
if (!str_starts_with($whereStr, 'where')) {
|
||||
$whereStr = "where $whereStr";
|
||||
}
|
||||
$sql .= " $whereStr";
|
||||
}
|
||||
$stat = self::getClient()->select($sql, $binds);
|
||||
$result = $stat->fetchOne($countAlias) ?? 0;
|
||||
$costTime = number_format(microtime(true) - $start, 3);
|
||||
do_log("table: $table, whereStr: $whereStr, binds: " . json_encode($binds) . ", result: $result, cost time: $costTime sec.");
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function list(string $sql, array $binds = []): array
|
||||
{
|
||||
$start = microtime(true);
|
||||
$stat = self::getClient()->select($sql, $binds);
|
||||
$result = $stat->rows();
|
||||
$costTime = number_format(microtime(true) - $start, 3);
|
||||
do_log("sql: $sql, binds: " . json_encode($binds) . ", result count: " . count($result) . ", cost time: $costTime sec.");
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
110
public/bonus-log.php
Normal file
110
public/bonus-log.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
require "../include/bittorrent.php";
|
||||
dbconn();
|
||||
loggedinorreturn();
|
||||
$uid = $_REQUEST['uid'] ?? $CURUSER['id'] ?? 0;
|
||||
int_check($uid,true);
|
||||
$user = \App\Models\User::query()->where('id', $uid)->first(\App\Models\User::$commonFields);
|
||||
if (!$user) {
|
||||
stderr("Error", "Invalid uid: $uid");
|
||||
}
|
||||
if ($uid != $CURUSER['id']) {
|
||||
user_can(\App\Enums\Permission\PermissionEnum::VIEW_USER_HISTORY->value, true, $CURUSER['id']);
|
||||
}
|
||||
$isRecordSeedingBonusLog = \App\Models\Setting::getIsRecordSeedingBonusLog();
|
||||
$defaultCategory = \App\Models\BonusLogs::CATEGORY_COMMON;
|
||||
$category = $_REQUEST['category'] ?? $defaultCategory;
|
||||
$categoryOptions = \App\Models\BonusLogs::listCategoryOptions($isRecordSeedingBonusLog);
|
||||
if (!isset($categoryOptions[$category])) {
|
||||
stderr("Error", "Invalid category: $category");
|
||||
}
|
||||
$businessType = $_REQUEST['business_type'] ?? 0;
|
||||
$businessTypeOptions = \App\Models\BonusLogs::listBusinessTypeOptions($isRecordSeedingBonusLog ? '' : $defaultCategory);
|
||||
if ($businessType && !isset($businessTypeOptions[$businessType])) {
|
||||
stderr("Error", "Invalid business_type: $businessType");
|
||||
}
|
||||
|
||||
stdhead(nexus_trans('bonus-log.title_for_user'));
|
||||
$pagerParam = "?uid=$uid&category=$category&business_type=$businessType";
|
||||
print("<h1 align=center>".nexus_trans('bonus-log.title_for_user') . "<a href=userdetails.php?id=" . htmlspecialchars($uid) . "><b> ".htmlspecialchars($user->username)."</b></a></h1>");
|
||||
|
||||
$textSelectOnePlease = nexus_trans('nexus.select_one_please');
|
||||
$categoryOptionsText = $businessTypeOptionsText = '';
|
||||
foreach ($categoryOptions as $name => $text) {
|
||||
$categoryOptionsText .= sprintf(
|
||||
'<option value="%s"%s>%s</option>',
|
||||
$name, isset($_REQUEST['category']) && $_REQUEST['category'] == $name ? ' selected' : '', $text
|
||||
);
|
||||
}
|
||||
foreach ($businessTypeOptions as $name => $text) {
|
||||
$businessTypeOptionsText .= sprintf(
|
||||
'<option value="%s"%s>%s</option>',
|
||||
$name, isset($_REQUEST['business_type']) && $_REQUEST['business_type'] == $name ? ' selected' : '', $text
|
||||
);
|
||||
}
|
||||
|
||||
$resetText = nexus_trans('label.reset');
|
||||
$submitText = nexus_trans('label.submit');
|
||||
$categoryText = nexus_trans('bonus-log.category');
|
||||
$businessTypeText = nexus_trans('bonus-log.fields.business_type');
|
||||
$filterForm = <<<FORM
|
||||
<div>
|
||||
<form id="filterForm" action="{$_SERVER['REQUEST_URI']}" method="get">
|
||||
<input type="hidden" name="uid" value="{$uid}" />
|
||||
<span>{$categoryText}:</span>
|
||||
<select name="category">
|
||||
{$categoryOptionsText}
|
||||
</select>
|
||||
|
||||
<span>{$businessTypeText}:</span>
|
||||
<select name="business_type">
|
||||
<option value="0">-{$textSelectOnePlease}-</option>
|
||||
{$businessTypeOptionsText}
|
||||
</select>
|
||||
|
||||
<input type="submit" value="{$submitText}">
|
||||
<input type="button" id="reset" value="{$resetText}">
|
||||
</form>
|
||||
</div>
|
||||
FORM;
|
||||
$resetJs = <<<JS
|
||||
jQuery("#reset").on('click', function () {
|
||||
jQuery("select[name=category]").val('')
|
||||
jQuery("select[name=business_type]").val('')
|
||||
})
|
||||
JS;
|
||||
\Nexus\Nexus::js($resetJs, 'footer', false);
|
||||
|
||||
$rep = new \App\Repositories\BonusRepository();
|
||||
$total = $rep->getCount($uid, $category, $businessType);
|
||||
list($pagertop, $pagerbottom, $limit, $offset, $pageSize, $page) = pager(50, $total, "$pagerParam&");
|
||||
$list = $rep->getList($uid, $category, $businessType, $page + 1, $pageSize);
|
||||
begin_main_frame();
|
||||
print($filterForm);
|
||||
print("<table id='bonus-log-table' width='100%' cellpadding='5'>");
|
||||
print("<tr>
|
||||
<td class='colhead' align='left'>".nexus_trans('bonus-log.fields.business_type')."</td>
|
||||
<td class='colhead' align='left'>".nexus_trans('bonus-log.fields.old_total_value')."</td>
|
||||
<td class='colhead' align='left'>".nexus_trans('bonus-log.fields.value')."</td>
|
||||
<td class='colhead' align='left'>".nexus_trans('bonus-log.fields.new_total_value')."</td>
|
||||
<td class='colhead' align='left'>".nexus_trans('label.comment')."</td>
|
||||
<td class='colhead' align='left'>".nexus_trans('label.created_at')."</td>
|
||||
</tr>");
|
||||
foreach ($list as $row) {
|
||||
print("<tr>
|
||||
<td class='rowfollow nowrap' align='left'>" . $row->businessTypeText . "</td>
|
||||
<td class='rowfollow nowrap' align='left'>" . ($row->old_total_value > 0 ? number_format($row->old_total_value, 1) : '-') . "</td>
|
||||
<td class='rowfollow nowrap' align='left'>" . ($row->old_total_value < $row->new_total_value ? "+" . number_format($row->value, 1) : "-" . number_format($row->value, 1)) . "</td>
|
||||
<td class='rowfollow nowrap' align='left'>" . ($row->new_total_value > 0 ? number_format($row->new_total_value, 1) : '-') . "</td>
|
||||
<td class='rowfollow nowrap' align='left'>" . $row->comment . "</td>
|
||||
<td class='rowfollow nowrap' align='left'>" . $row->created_at . "</td>
|
||||
</tr>");
|
||||
}
|
||||
|
||||
print("</table>");
|
||||
print($pagerbottom);
|
||||
end_main_frame();
|
||||
stdfoot();
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ if ($sort == 'seed_time') {
|
||||
}
|
||||
$list = $query->selectRaw("claims.*")->get();
|
||||
print($filterForm);
|
||||
print("<table id='claim-table' width='100%'>");
|
||||
print("<table id='claim-table' width='100%' cellpadding='5'>");
|
||||
print("<tr>
|
||||
<td class='colhead' align='center'>".nexus_trans('claim.th_id')."</td>
|
||||
<td class='colhead' align='center'>".nexus_trans('claim.th_username')."</td>
|
||||
|
||||
@@ -400,7 +400,8 @@ if ($user["id"] == $CURUSER["id"] || user_can('viewhistory')) {
|
||||
$states = (new \App\Repositories\ClaimRepository())->getStats($user['id']);
|
||||
tr_small($lang_functions['menu_claim'], sprintf('<a href="claim.php?uid=%s" target="_blank">%s</a>', $user['id'], $states), 1);
|
||||
}
|
||||
tr_small($lang_userdetails['row_karma_points'], number_format($user['seedbonus'], 1), 1);
|
||||
$bonusLogText = sprintf(' <a href="bonus-log.php?uid=%s" target="_blank" class="altlink">[%s]</a>', $user['id'], nexus_trans("bonus-log.view_detail"));
|
||||
tr_small($lang_userdetails['row_karma_points'], number_format($user['seedbonus'], 1) . $bonusLogText, 1);
|
||||
tr_small($lang_functions['text_seed_points'], number_format($user['seed_points'], 1) . " <span class='text-muted'>(" . nexus_trans('label.updated_at') . ": " . $user['seed_points_updated_at'] . ")</span>", 1);
|
||||
}
|
||||
|
||||
@@ -511,7 +512,7 @@ if (user_can('prfmanage') && $user["class"] < get_user_class())
|
||||
tr($lang_userdetails['row_comment'], "<textarea cols=\"60\" rows=\"6\" name=\"modcomment\">".$modcomment."</textarea>", 1);
|
||||
$bonuscomment = \App\Models\BonusLogs::query()
|
||||
->where("uid", $user["id"])
|
||||
->whereNotIn("business_type", \App\Models\BonusLogs::$businessTypeBonus)
|
||||
->whereNotIn("business_type", \App\Models\BonusLogs::$businessTypeSeeding)
|
||||
->orderBy("id", "desc")
|
||||
->limit(20)
|
||||
->get()
|
||||
|
||||
@@ -45,4 +45,9 @@ return [
|
||||
'new_total_value' => 'Post-trade value',
|
||||
],
|
||||
'exclude_seeding_bonus' => 'Exclude seeding bonus',
|
||||
'title_for_user' => 'User bonus details',
|
||||
'category' => 'Category',
|
||||
'category_common' => 'Common',
|
||||
'category_seeding' => 'Seeding',
|
||||
'view_detail' => 'Details',
|
||||
];
|
||||
|
||||
@@ -47,4 +47,9 @@ return [
|
||||
'new_total_value' => '交易后值',
|
||||
],
|
||||
'exclude_seeding_bonus' => '不包含做种魔力',
|
||||
'title_for_user' => '用户魔力明细',
|
||||
'category' => '分类',
|
||||
'category_common' => '普通',
|
||||
'category_seeding' => '做种',
|
||||
'view_detail' => '明细',
|
||||
];
|
||||
|
||||
@@ -45,4 +45,9 @@ return [
|
||||
'new_total_value' => '交易後值',
|
||||
],
|
||||
'exclude_seeding_bonus' => '不包含做種魔力',
|
||||
'title_for_user' => '用戶魔力明細',
|
||||
'category' => '分類',
|
||||
'category_common' => '普通',
|
||||
'category_seeding' => '做種',
|
||||
'view_detail' => '明細',
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user