feat: Update BillingManager to replace 'nodeName' with 'purpose', add purpose formatting function, and enhance UI elements with consistent icon sizes
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 6m56s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 6m56s
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"hostName": "VDSINA",
|
"hostName": "VDSINA",
|
||||||
"nodeName": "VDSINA",
|
"purpose": "relay",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "VDSINA",
|
"provider": "VDSINA",
|
||||||
"loginUrl": "cp.vdsina.com",
|
"loginUrl": "cp.vdsina.com",
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
{
|
{
|
||||||
"id": "2",
|
"id": "2",
|
||||||
"hostName": "Macloud",
|
"hostName": "Macloud",
|
||||||
"nodeName": "Macloud",
|
"purpose": "bgp",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "Macloud",
|
"provider": "Macloud",
|
||||||
"loginUrl": "cp.macloud.ru",
|
"loginUrl": "cp.macloud.ru",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
{
|
{
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"hostName": "Hosting VDS",
|
"hostName": "Hosting VDS",
|
||||||
"nodeName": "Steal",
|
"purpose": "monitoring",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "Hosting VDS",
|
"provider": "Hosting VDS",
|
||||||
"loginUrl": "my.hosting-vds.com/",
|
"loginUrl": "my.hosting-vds.com/",
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
{
|
{
|
||||||
"id": "4",
|
"id": "4",
|
||||||
"hostName": "Waicore",
|
"hostName": "Waicore",
|
||||||
"nodeName": "Waicore",
|
"purpose": "dns",
|
||||||
"country": "DE",
|
"country": "DE",
|
||||||
"provider": "Waicore",
|
"provider": "Waicore",
|
||||||
"loginUrl": "my.waicore.com/billmgr",
|
"loginUrl": "my.waicore.com/billmgr",
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
{
|
{
|
||||||
"id": "5",
|
"id": "5",
|
||||||
"hostName": "IHOR",
|
"hostName": "IHOR",
|
||||||
"nodeName": "Ihore",
|
"purpose": "proxy",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "IHOR",
|
"provider": "IHOR",
|
||||||
"loginUrl": "billing.ihor-hosting.ru/billmgr",
|
"loginUrl": "billing.ihor-hosting.ru/billmgr",
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ function BillingManager() {
|
|||||||
// Новый элемент для добавления
|
// Новый элемент для добавления
|
||||||
const [newItem, setNewItem] = useState({
|
const [newItem, setNewItem] = useState({
|
||||||
hostName: '',
|
hostName: '',
|
||||||
nodeName: '',
|
purpose: '',
|
||||||
country: '',
|
country: '',
|
||||||
provider: '',
|
provider: '',
|
||||||
loginUrl: '',
|
loginUrl: '',
|
||||||
@@ -70,7 +70,7 @@ function BillingManager() {
|
|||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"hostName": "VDSINA",
|
"hostName": "VDSINA",
|
||||||
"nodeName": "VDSINA",
|
"purpose": "relay",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "VDSINA",
|
"provider": "VDSINA",
|
||||||
"loginUrl": "cp.vdsina.com",
|
"loginUrl": "cp.vdsina.com",
|
||||||
@@ -84,7 +84,7 @@ function BillingManager() {
|
|||||||
{
|
{
|
||||||
"id": "2",
|
"id": "2",
|
||||||
"hostName": "Macloud",
|
"hostName": "Macloud",
|
||||||
"nodeName": "Macloud",
|
"purpose": "bgp",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "Macloud",
|
"provider": "Macloud",
|
||||||
"loginUrl": "cp.macloud.ru",
|
"loginUrl": "cp.macloud.ru",
|
||||||
@@ -98,7 +98,7 @@ function BillingManager() {
|
|||||||
{
|
{
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"hostName": "Hosting VDS",
|
"hostName": "Hosting VDS",
|
||||||
"nodeName": "Steal",
|
"purpose": "monitoring",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "Hosting VDS",
|
"provider": "Hosting VDS",
|
||||||
"loginUrl": "my.hosting-vds.com/",
|
"loginUrl": "my.hosting-vds.com/",
|
||||||
@@ -112,7 +112,7 @@ function BillingManager() {
|
|||||||
{
|
{
|
||||||
"id": "4",
|
"id": "4",
|
||||||
"hostName": "Waicore",
|
"hostName": "Waicore",
|
||||||
"nodeName": "Waicore",
|
"purpose": "dns",
|
||||||
"country": "DE",
|
"country": "DE",
|
||||||
"provider": "Waicore",
|
"provider": "Waicore",
|
||||||
"loginUrl": "my.waicore.com/billmgr",
|
"loginUrl": "my.waicore.com/billmgr",
|
||||||
@@ -126,7 +126,7 @@ function BillingManager() {
|
|||||||
{
|
{
|
||||||
"id": "5",
|
"id": "5",
|
||||||
"hostName": "IHOR",
|
"hostName": "IHOR",
|
||||||
"nodeName": "Ihore",
|
"purpose": "proxy",
|
||||||
"country": "RU",
|
"country": "RU",
|
||||||
"provider": "IHOR",
|
"provider": "IHOR",
|
||||||
"loginUrl": "billing.ihor-hosting.ru/billmgr",
|
"loginUrl": "billing.ihor-hosting.ru/billmgr",
|
||||||
@@ -281,6 +281,19 @@ function BillingManager() {
|
|||||||
}).format(amount);
|
}).format(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatPurpose(purpose) {
|
||||||
|
const purposeMap = {
|
||||||
|
'relay': 'Relay VPS',
|
||||||
|
'bgp': 'BGP сервер',
|
||||||
|
'monitoring': 'Мониторинг',
|
||||||
|
'dns': 'DNS сервер',
|
||||||
|
'proxy': 'Прокси сервер',
|
||||||
|
'backup': 'Backup сервер',
|
||||||
|
'other': 'Другое'
|
||||||
|
};
|
||||||
|
return purposeMap[purpose] || purpose || 'Не указано';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* Заголовок страницы */}
|
{/* Заголовок страницы */}
|
||||||
@@ -297,14 +310,14 @@ function BillingManager() {
|
|||||||
onClick={fetchBillingData}
|
onClick={fetchBillingData}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<IconRefresh className="icon" />
|
<IconRefresh size={16} />
|
||||||
Обновить
|
Обновить
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
onClick={handleAddItem}
|
onClick={handleAddItem}
|
||||||
>
|
>
|
||||||
<IconPlus className="icon" />
|
<IconPlus size={16} />
|
||||||
Добавить
|
Добавить
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -414,7 +427,7 @@ function BillingManager() {
|
|||||||
onClick={handleSaveChanges}
|
onClick={handleSaveChanges}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<IconDatabase className="icon" />
|
<IconDatabase size={16} />
|
||||||
Сохранить
|
Сохранить
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -425,7 +438,7 @@ function BillingManager() {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Имя хостера</th>
|
<th>Имя хостера</th>
|
||||||
<th>Нода</th>
|
<th>Назначение</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -441,10 +454,10 @@ function BillingManager() {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
<span className="avatar avatar-sm me-2">
|
<span className="badge bg-blue-lt text-blue me-2">
|
||||||
{countryToFlag(item.country)}
|
{formatPurpose(item.purpose)}
|
||||||
</span>
|
</span>
|
||||||
{item.nodeName}
|
{formatPurpose(item.purpose)}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -480,7 +493,7 @@ function BillingManager() {
|
|||||||
{providers.map(provider => {
|
{providers.map(provider => {
|
||||||
const providerItems = billingData.filter(item => item.provider === provider);
|
const providerItems = billingData.filter(item => item.provider === provider);
|
||||||
const totalCost = providerItems.reduce((sum, item) => sum + item.monthlyCost, 0);
|
const totalCost = providerItems.reduce((sum, item) => sum + item.monthlyCost, 0);
|
||||||
const servers = providerItems.map(item => item.nodeName).join(', ');
|
const servers = providerItems.map(item => formatPurpose(item.purpose)).join(', ');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={provider}>
|
<tr key={provider}>
|
||||||
@@ -533,7 +546,7 @@ function BillingManager() {
|
|||||||
className="btn btn-outline-primary btn-sm"
|
className="btn btn-outline-primary btn-sm"
|
||||||
onClick={handleAddItem}
|
onClick={handleAddItem}
|
||||||
>
|
>
|
||||||
<IconPlus className="icon" />
|
<IconPlus size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -560,18 +573,18 @@ function BillingManager() {
|
|||||||
<td>
|
<td>
|
||||||
<div className="btn-list">
|
<div className="btn-list">
|
||||||
<button
|
<button
|
||||||
className="btn btn-icon btn-sm"
|
className="btn btn-icon btn-sm btn-outline-primary"
|
||||||
onClick={() => handleEditItem(item)}
|
onClick={() => handleEditItem(item)}
|
||||||
title="Редактировать"
|
title="Редактировать"
|
||||||
>
|
>
|
||||||
<IconEdit className="icon" />
|
<IconEdit size={16} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-icon btn-sm"
|
className="btn btn-icon btn-sm btn-outline-danger"
|
||||||
onClick={() => handleDeleteItem(item)}
|
onClick={() => handleDeleteItem(item)}
|
||||||
title="Удалить"
|
title="Удалить"
|
||||||
>
|
>
|
||||||
<IconTrash className="icon" />
|
<IconTrash size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -609,18 +622,18 @@ function BillingManager() {
|
|||||||
<td>
|
<td>
|
||||||
<div className="btn-list">
|
<div className="btn-list">
|
||||||
<button
|
<button
|
||||||
className="btn btn-icon btn-sm"
|
className="btn btn-icon btn-sm btn-outline-primary"
|
||||||
onClick={() => handleEditItem(item)}
|
onClick={() => handleEditItem(item)}
|
||||||
title="Редактировать"
|
title="Редактировать"
|
||||||
>
|
>
|
||||||
<IconEdit className="icon" />
|
<IconEdit size={16} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-icon btn-sm"
|
className="btn btn-icon btn-sm btn-outline-danger"
|
||||||
onClick={() => handleDeleteItem(item)}
|
onClick={() => handleDeleteItem(item)}
|
||||||
title="Удалить"
|
title="Удалить"
|
||||||
>
|
>
|
||||||
<IconTrash className="icon" />
|
<IconTrash size={16} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -698,14 +711,22 @@ function AddBillingModal({ show, item, onItemChange, onSubmit, onClose }) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label className="form-label">Нода</label>
|
<label className="form-label">Назначение</label>
|
||||||
<input
|
<select
|
||||||
type="text"
|
className="form-select"
|
||||||
className="form-control"
|
value={item.purpose || ''}
|
||||||
value={item.nodeName}
|
onChange={(e) => handleChange('purpose', e.target.value)}
|
||||||
onChange={(e) => handleChange('nodeName', e.target.value)}
|
|
||||||
required
|
required
|
||||||
/>
|
>
|
||||||
|
<option value="">Выберите назначение</option>
|
||||||
|
<option value="relay">Relay VPS</option>
|
||||||
|
<option value="bgp">BGP сервер</option>
|
||||||
|
<option value="monitoring">Мониторинг</option>
|
||||||
|
<option value="dns">DNS сервер</option>
|
||||||
|
<option value="proxy">Прокси сервер</option>
|
||||||
|
<option value="backup">Backup сервер</option>
|
||||||
|
<option value="other">Другое</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label className="form-label">Страна</label>
|
<label className="form-label">Страна</label>
|
||||||
@@ -812,6 +833,7 @@ function AddBillingModal({ show, item, onItemChange, onSubmit, onClose }) {
|
|||||||
Отмена
|
Отмена
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" className="btn btn-primary">
|
<button type="submit" className="btn btn-primary">
|
||||||
|
<IconPlus size={16} className="me-1" />
|
||||||
Добавить
|
Добавить
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -857,14 +879,22 @@ function EditBillingModal({ show, item, onItemChange, onSubmit, onClose }) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label className="form-label">Нода</label>
|
<label className="form-label">Назначение</label>
|
||||||
<input
|
<select
|
||||||
type="text"
|
className="form-select"
|
||||||
className="form-control"
|
value={item.purpose || ''}
|
||||||
value={item.nodeName || ''}
|
onChange={(e) => handleChange('purpose', e.target.value)}
|
||||||
onChange={(e) => handleChange('nodeName', e.target.value)}
|
|
||||||
required
|
required
|
||||||
/>
|
>
|
||||||
|
<option value="">Выберите назначение</option>
|
||||||
|
<option value="relay">Relay VPS</option>
|
||||||
|
<option value="bgp">BGP сервер</option>
|
||||||
|
<option value="monitoring">Мониторинг</option>
|
||||||
|
<option value="dns">DNS сервер</option>
|
||||||
|
<option value="proxy">Прокси сервер</option>
|
||||||
|
<option value="backup">Backup сервер</option>
|
||||||
|
<option value="other">Другое</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label className="form-label">Страна</label>
|
<label className="form-label">Страна</label>
|
||||||
@@ -971,6 +1001,7 @@ function EditBillingModal({ show, item, onItemChange, onSubmit, onClose }) {
|
|||||||
Отмена
|
Отмена
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" className="btn btn-primary">
|
<button type="submit" className="btn btn-primary">
|
||||||
|
<IconCheck size={16} className="me-1" />
|
||||||
Сохранить
|
Сохранить
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1002,6 +1033,7 @@ function DeleteBillingModal({ show, item, onDelete, onClose }) {
|
|||||||
Отмена
|
Отмена
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="btn btn-danger" onClick={onDelete}>
|
<button type="button" className="btn btn-danger" onClick={onDelete}>
|
||||||
|
<IconTrash size={16} className="me-1" />
|
||||||
Удалить
|
Удалить
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user