mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
@@ -83,6 +83,8 @@ export interface TariffDetail {
|
|||||||
// Дневной тариф
|
// Дневной тариф
|
||||||
is_daily: boolean
|
is_daily: boolean
|
||||||
daily_price_kopeks: number
|
daily_price_kopeks: number
|
||||||
|
// Режим сброса трафика
|
||||||
|
traffic_reset_mode: string | null // 'DAY', 'WEEK', 'MONTH', 'NO_RESET', null = глобальная настройка
|
||||||
created_at: string
|
created_at: string
|
||||||
updated_at: string | null
|
updated_at: string | null
|
||||||
}
|
}
|
||||||
@@ -117,6 +119,8 @@ export interface TariffCreateRequest {
|
|||||||
// Дневной тариф
|
// Дневной тариф
|
||||||
is_daily?: boolean
|
is_daily?: boolean
|
||||||
daily_price_kopeks?: number
|
daily_price_kopeks?: number
|
||||||
|
// Режим сброса трафика
|
||||||
|
traffic_reset_mode?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TariffUpdateRequest {
|
export interface TariffUpdateRequest {
|
||||||
@@ -150,6 +154,8 @@ export interface TariffUpdateRequest {
|
|||||||
// Дневной тариф
|
// Дневной тариф
|
||||||
is_daily?: boolean
|
is_daily?: boolean
|
||||||
daily_price_kopeks?: number
|
daily_price_kopeks?: number
|
||||||
|
// Режим сброса трафика
|
||||||
|
traffic_reset_mode?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TariffToggleResponse {
|
export interface TariffToggleResponse {
|
||||||
|
|||||||
@@ -155,6 +155,9 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri
|
|||||||
tariff?.traffic_topup_packages || {}
|
tariff?.traffic_topup_packages || {}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Режим сброса трафика
|
||||||
|
const [trafficResetMode, setTrafficResetMode] = useState<string | null>(tariff?.traffic_reset_mode || null)
|
||||||
|
|
||||||
// Новый период для добавления
|
// Новый период для добавления
|
||||||
const [newPeriodDays, setNewPeriodDays] = useState(30)
|
const [newPeriodDays, setNewPeriodDays] = useState(30)
|
||||||
const [newPeriodPrice, setNewPeriodPrice] = useState(300)
|
const [newPeriodPrice, setNewPeriodPrice] = useState(300)
|
||||||
@@ -185,6 +188,7 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri
|
|||||||
max_topup_traffic_gb: maxTopupTrafficGb,
|
max_topup_traffic_gb: maxTopupTrafficGb,
|
||||||
is_daily: false,
|
is_daily: false,
|
||||||
daily_price_kopeks: 0,
|
daily_price_kopeks: 0,
|
||||||
|
traffic_reset_mode: trafficResetMode,
|
||||||
}
|
}
|
||||||
onSave(data)
|
onSave(data)
|
||||||
}
|
}
|
||||||
@@ -579,6 +583,44 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Режим сброса трафика */}
|
||||||
|
<div className="p-4 bg-dark-700/50 rounded-lg">
|
||||||
|
<h4 className="text-sm font-medium text-dark-200 mb-3">Режим сброса трафика</h4>
|
||||||
|
<p className="text-xs text-dark-500 mb-3">
|
||||||
|
Определяет, когда сбрасывается использованный трафик у подписчиков этого тарифа
|
||||||
|
</p>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{[
|
||||||
|
{ value: null, label: '🌐 Глобальная настройка', desc: 'Использовать значение из конфига бота' },
|
||||||
|
{ value: 'DAY', label: '📅 Ежедневно', desc: 'Сброс каждый день' },
|
||||||
|
{ value: 'WEEK', label: '📆 Еженедельно', desc: 'Сброс каждую неделю' },
|
||||||
|
{ value: 'MONTH', label: '🗓️ Ежемесячно', desc: 'Сброс каждый месяц' },
|
||||||
|
{ value: 'NO_RESET', label: '🚫 Никогда', desc: 'Трафик не сбрасывается' },
|
||||||
|
].map(option => (
|
||||||
|
<button
|
||||||
|
key={option.value || 'global'}
|
||||||
|
type="button"
|
||||||
|
onClick={() => setTrafficResetMode(option.value)}
|
||||||
|
className={`w-full p-3 rounded-lg text-left transition-colors ${
|
||||||
|
trafficResetMode === option.value
|
||||||
|
? 'bg-accent-500/20 border border-accent-500'
|
||||||
|
: 'bg-dark-600 border border-dark-500 hover:border-dark-400'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<span className="text-sm text-dark-100">{option.label}</span>
|
||||||
|
<p className="text-xs text-dark-400 mt-0.5">{option.desc}</p>
|
||||||
|
</div>
|
||||||
|
{trafficResetMode === option.value && (
|
||||||
|
<span className="text-accent-400"><CheckIcon /></span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -635,6 +677,9 @@ function DailyTariffModal({ tariff, servers, onSave, onClose, isLoading }: Daily
|
|||||||
tariff?.traffic_topup_packages || {}
|
tariff?.traffic_topup_packages || {}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Режим сброса трафика
|
||||||
|
const [trafficResetMode, setTrafficResetMode] = useState<string | null>(tariff?.traffic_reset_mode || null)
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<'basic' | 'servers' | 'extra'>('basic')
|
const [activeTab, setActiveTab] = useState<'basic' | 'servers' | 'extra'>('basic')
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
@@ -661,6 +706,7 @@ function DailyTariffModal({ tariff, servers, onSave, onClose, isLoading }: Daily
|
|||||||
max_topup_traffic_gb: maxTopupTrafficGb,
|
max_topup_traffic_gb: maxTopupTrafficGb,
|
||||||
is_daily: true,
|
is_daily: true,
|
||||||
daily_price_kopeks: dailyPriceKopeks,
|
daily_price_kopeks: dailyPriceKopeks,
|
||||||
|
traffic_reset_mode: trafficResetMode,
|
||||||
}
|
}
|
||||||
onSave(data)
|
onSave(data)
|
||||||
}
|
}
|
||||||
@@ -969,6 +1015,44 @@ function DailyTariffModal({ tariff, servers, onSave, onClose, isLoading }: Daily
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Режим сброса трафика */}
|
||||||
|
<div className="p-4 bg-dark-700/50 rounded-lg">
|
||||||
|
<h4 className="text-sm font-medium text-dark-200 mb-3">Режим сброса трафика</h4>
|
||||||
|
<p className="text-xs text-dark-500 mb-3">
|
||||||
|
Определяет, когда сбрасывается использованный трафик у подписчиков этого тарифа
|
||||||
|
</p>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{[
|
||||||
|
{ value: null, label: '🌐 Глобальная настройка', desc: 'Использовать значение из конфига бота' },
|
||||||
|
{ value: 'DAY', label: '📅 Ежедневно', desc: 'Сброс каждый день' },
|
||||||
|
{ value: 'WEEK', label: '📆 Еженедельно', desc: 'Сброс каждую неделю' },
|
||||||
|
{ value: 'MONTH', label: '🗓️ Ежемесячно', desc: 'Сброс каждый месяц' },
|
||||||
|
{ value: 'NO_RESET', label: '🚫 Никогда', desc: 'Трафик не сбрасывается' },
|
||||||
|
].map(option => (
|
||||||
|
<button
|
||||||
|
key={option.value || 'global'}
|
||||||
|
type="button"
|
||||||
|
onClick={() => setTrafficResetMode(option.value)}
|
||||||
|
className={`w-full p-3 rounded-lg text-left transition-colors ${
|
||||||
|
trafficResetMode === option.value
|
||||||
|
? 'bg-amber-500/20 border border-amber-500'
|
||||||
|
: 'bg-dark-600 border border-dark-500 hover:border-dark-400'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<span className="text-sm text-dark-100">{option.label}</span>
|
||||||
|
<p className="text-xs text-dark-400 mt-0.5">{option.desc}</p>
|
||||||
|
</div>
|
||||||
|
{trafficResetMode === option.value && (
|
||||||
|
<span className="text-amber-400"><CheckIcon /></span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user