Merge pull request #401 from specialpointcentral/php8

feat: add notice lead time for global promotions
This commit is contained in:
xiaomlove
2025-12-11 11:46:02 +07:00
committed by GitHub
6 changed files with 88 additions and 1 deletions

View File

@@ -60,6 +60,13 @@ class TorrentStateResource extends Resource
->validationMessages([
'after' => __('label.torrent_state.deadline_after_begin'),
]),
Select::make('notice_days')
->label(__('label.torrent_state.notice_days'))
->options(TorrentState::noticeOptions())
->required()
->default(TorrentState::NOTICE_NONE)
->dehydrated(true)
->native(false),
Textarea::make('remark')
->label(__('label.comment'))
->rows(2)
@@ -121,6 +128,8 @@ class TorrentStateResource extends Resource
default => 'heroicon-o-check-circle',
})
->iconPosition('before'),
TextColumn::make('notice_days_text')
->label(__('label.torrent_state.notice_days')),
TextColumn::make('remark')->label(__('label.comment'))->limit(50),
])
->filters([

View File

@@ -16,13 +16,17 @@ class TorrentState extends NexusModel
{
use NexusActivityLogTrait;
protected $fillable = ['global_sp_state', 'deadline', 'begin', 'remark'];
public const NOTICE_NONE = 0;
public const NOTICE_UNLIMITED = -1;
protected $fillable = ['global_sp_state', 'deadline', 'begin', 'remark', 'notice_days'];
protected $table = 'torrents_state';
protected $casts = [
'begin' => 'datetime',
'deadline' => 'datetime',
'notice_days' => 'integer',
];
protected static function booted()
@@ -48,6 +52,11 @@ class TorrentState extends NexusModel
return Torrent::$promotionTypes[$this->global_sp_state]['text'] ?? '';
}
public function getNoticeDaysTextAttribute(): string
{
return self::noticeOptions()[$this->notice_days] ?? '';
}
public function scopeActive(Builder $query, ?Carbon $moment = null): Builder
{
$moment = $moment ?? Carbon::now();
@@ -117,6 +126,7 @@ class TorrentState extends NexusModel
foreach ($states as $state) {
$begin = self::parseDateTimeValue($state['begin'] ?? null);
$deadline = self::parseDateTimeValue($state['deadline'] ?? null);
$noticeDays = (int)($state['notice_days'] ?? self::NOTICE_NONE);
$hasBegun = !$begin || $begin->lessThanOrEqualTo($moment);
$notExpired = !$deadline || $deadline->greaterThanOrEqualTo($moment);
@@ -129,6 +139,9 @@ class TorrentState extends NexusModel
}
if ($begin && $begin->greaterThan($moment)) {
if (!self::isWithinNoticeWindow($begin, $noticeDays, $moment)) {
continue;
}
if (!$upcoming) {
$upcoming = $state;
continue;
@@ -282,4 +295,31 @@ class TorrentState extends NexusModel
'end' => $deadlineText,
]);
}
public static function noticeOptions(): array
{
return [
self::NOTICE_NONE => __('label.torrent_state.notice_none'),
1 => __('label.torrent_state.notice_day', ['days' => 1]),
3 => __('label.torrent_state.notice_day', ['days' => 3]),
7 => __('label.torrent_state.notice_day', ['days' => 7]),
15 => __('label.torrent_state.notice_day', ['days' => 15]),
30 => __('label.torrent_state.notice_day', ['days' => 30]),
self::NOTICE_UNLIMITED => __('label.torrent_state.notice_unlimited'),
];
}
protected static function isWithinNoticeWindow(?Carbon $begin, int $noticeDays, Carbon $now): bool
{
if (!$begin) {
return true;
}
if ($noticeDays === self::NOTICE_NONE) {
return false;
}
if ($noticeDays === self::NOTICE_UNLIMITED) {
return true;
}
return $begin->copy()->subDays($noticeDays)->lessThanOrEqualTo($now);
}
}

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('torrents_state', function (Blueprint $table) {
if (!Schema::hasColumn('torrents_state', 'notice_days')) {
$table->integer('notice_days')->default(0)->after('remark');
}
});
}
public function down(): void
{
Schema::table('torrents_state', function (Blueprint $table) {
if (Schema::hasColumn('torrents_state', 'notice_days')) {
$table->dropColumn('notice_days');
}
});
}
};

View File

@@ -335,6 +335,10 @@ return [
'status_upcoming' => 'Upcoming',
'time_overlaps' => 'Time overlaps with another promotion. Please adjust the window.',
'time_overlaps_with' => 'Overlaps with promotion ID :id (time: :begin ~ :end).',
'notice_days' => 'Pre-announcement',
'notice_day' => ':days day before',
'notice_none' => 'No pre-announcement',
'notice_unlimited' => 'Always announce',
],
'role' => [
'class' => 'Relate user class',

View File

@@ -377,6 +377,10 @@ return [
'status_upcoming' => '未开始',
'time_overlaps' => '时间与已有活动重叠,请调整时间段。',
'time_overlaps_with' => '与活动 ID :id (时间::begin ~ :end重叠请调整时间段。',
'notice_days' => '提前预告',
'notice_day' => '提前 :days 天',
'notice_none' => '不预告',
'notice_unlimited' => '不限时预告',
],
'role' => [
'class' => '关联用户等级',

View File

@@ -334,6 +334,10 @@ return [
'status_upcoming' => '未開始',
'time_overlaps' => '時間與已有活動重疊,請調整時間段。',
'time_overlaps_with' => '與活動 ID :id (時間::begin ~ :end重疊請調整時間段。',
'notice_days' => '提前預告',
'notice_day' => '提前 :days 天',
'notice_none' => '不預告',
'notice_unlimited' => '不限時預告',
],
'role' => [
'class' => '關聯用户等級',