test-server

This commit is contained in:
you 2024-10-25 01:13:16 +03:00
parent fb146659c8
commit a764948bc7
10 changed files with 469 additions and 9 deletions

View File

@ -13,10 +13,10 @@ function defaultDataResponseProcessor(data) {
}
export const API_PATH_MAIN = "https://hostapay.trade/api/v1/";
export const API_PATH_TEST = "https://test.0x000f.ru/api/v1/";
let BasicURLValue = "https://hostapay.trade/api/v1/";
let BasicURLValue = API_PATH_TEST;
async function makePost(url, data, options = undefined,
responseProcessor = defaultResponseProcessor,

View File

@ -9,4 +9,15 @@ export function isStringEmptyOrSpaces(str) {
}
}
return false;
}
export function truncateMiddle(str, n) {
if (str.length <= 2 * n) {
return str; // Если длина строки меньше или равна 2n, то ничего не обрезаем
}
const leftPart = str.slice(0, n); // Первые n символов
const rightPart = str.slice(-n); // Последние n символов
return leftPart + '...' + rightPart; // Соединяем с "..."
}

View File

@ -47,6 +47,8 @@
{#if jwtDecode(getAuthInfo()?.a)?.role == "4"}
<li><a href="/admin/merchants">Мерчанты</a></li>
<li><a href="/admin/currencies">Валюты</a></li>
<li><a href="/admin/sms">СМС</a></li>
<li><a href="/admin/withdrawals">Вывод средств</a></li>
{/if}
<!-- <li><a>Item 3</a></li> -->
</ul>
@ -78,6 +80,8 @@
{#if jwtDecode(getAuthInfo()?.a)?.role == "4"}
<li><a on:click={()=>{showMenu = false;}} href="/admin/merchants">Мерчанты</a></li>
<li><a on:click={()=>{showMenu = false;}} href="/admin/currencies">Валюты</a></li>
<li><a on:click={()=>{showMenu = false;}} href="/admin/sms">СМС</a></li>
<li><a on:click={()=>{showMenu = false;}} href="/admin/withdrawals">Вывод средств</a></li>
{/if}
</ul>
</div>

View File

@ -1,6 +1,6 @@
<script>
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import { makePost } from "$lib/tools/requests/requests";
import { API_PATH_TEST, API_PATH_MAIN, makePost } from "$lib/tools/requests/requests";
import { sayError, sayInfo } from "$lib/tools/toaster/Toaster";
import Pagination from "$lib/ui-components/pagination.svelte";
import { redirect } from "$lib/tools/url/URLTools";
@ -161,7 +161,7 @@
try {
const response = await axios.get(
"https://hostapay.trade/api/v1/loadFile?dispute=" +
API_PATH_TEST + "loadFile?dispute=" +
selectedDispute["order_id"],
// "17731",
{
@ -338,7 +338,7 @@
on:click={() => {
axios
.get(
"https://hostapay.trade/api/v1/loadFile?dispute=" +
API_PATH_TEST + "loadFile?dispute=" +
selectedDispute["order_id"],
{
responseType: "blob",

View File

@ -220,6 +220,7 @@
<option value="1">Пользователь</option>
<option value="2">Модератор</option>
<option value="4">Администратор</option>
<option value="5">Тим лид</option>
</select>
<select
bind:value={value_currency_code}

View File

@ -54,6 +54,7 @@
return;
}
foundedDispute = res.data;
console.log(foundedDispute);
showFoundedOrderWindow = true;
showLoadingFind = false;
}
@ -174,8 +175,12 @@
</p>
<p class="text-sm mt-3">Курс</p>
<p>{foundedDispute["rate"]} {foundedDispute["currency_code"]}</p>
<p class="text-sm mt-3">Владелец</p>
<p>{foundedDispute["name"]}</p>
<p class="text-sm mt-3">Карта</p>
<p>{foundedDispute["cardnumber"]}</p>
<p class="text-sm mt-3">Телефон</p>
<p>{foundedDispute["phone"]}</p>
<p class="text-sm mt-3">Время создания</p>
<p>{foundedDispute["creationtime"]}</p>
<!-- <p>{foundedDispute["closetime"]}</p> -->

View File

@ -2,7 +2,7 @@
// @ts-nocheck
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import { makePost } from "$lib/tools/requests/requests";
import { API_PATH_TEST, API_PATH_MAIN, makePost } from "$lib/tools/requests/requests";
import { sayError, sayInfo } from "$lib/tools/toaster/Toaster";
import Pagination from "$lib/ui-components/pagination.svelte";
import { redirect } from "$lib/tools/url/URLTools";
@ -451,7 +451,7 @@
on:click={() => {
axios
.get(
"https://hostapay.trade/api/v1/loadFile?dispute=" +
API_PATH_TEST + "loadFile?dispute=" +
selectedPayout["order_id"],
{
responseType: "blob",

242
src/routes/sms/+page.svelte Normal file
View File

@ -0,0 +1,242 @@
<script>
// @ts-nocheck
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import { makePost } from "$lib/tools/requests/requests";
import { sayError, sayInfo } from "$lib/tools/toaster/Toaster";
import Pagination from "$lib/ui-components/pagination.svelte";
const headNamesMap = {
amount: "Сумма",
balance: "Баланс",
card_currency: "Валюта карты",
card_number: "Номер карты",
comment: "Комментарий",
currency: "Валюта",
date_of_message_creation: "Время создания сообщения",
from_bank_name: "Название банка",
from_to: "Получатель",
got_from_device_uuid: "Девайс UUID",
initial_text:
"Текст сообщения",
matched_order_uuid: "Совпадение с заявкой",
on_device_msg_creation: "Время сообщения на устройство",
to_bank_id: "ID банка",
type: "Тип",
uuid: "UUID",
requisite_type: "Тип реквизита"
};
let selectedNotificationType = "push";
let value_startTime = "";
let value_endTime = "";
let totalPages = 1;
let currentPage = 1;
let disabledPages = false;
let showLoadingNotifies = false;
let notifications = [];
let tableHeads = [];
let noData = false;
let value_token = "";
async function getNotifications() {
if (value_endTime === "" || value_startTime === "") {
return;
}
noData = false;
showLoadingNotifies = true;
const res = await makePost(
"admin/loadNotifications",
{
notification_type: selectedNotificationType === "push" ? 1 : 2,
fromDate: formatDateTime(value_startTime),
toDate: formatDateTime(value_endTime),
token: (value_token.length >= 36 ? value_token:undefined),
page: currentPage,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
// console.log(res);
// console.log(formatDateTime(value_startTime));
// console.log(value_endTime);
if (res.error) {
showLoadingNotifies = false;
sayError("Не удалось получить уведомления");
return;
}
if (Array.isArray(res.data.data) && res.data.data.length > 0) {
let o = res.data.data[0];
tableHeads = [...Object.keys(o)];
notifications = [...res.data.data];
totalPages = res.data.pages;
if (notifications.length < 1) noData = true;
} else {
tableHeads = [];
notifications = [];
noData = true;
}
showLoadingNotifies = false;
}
$: if(selectedNotificationType) {
currentPage = 1;
}
$: if (value_startTime !== "" && value_endTime !== "") {
currentPage = 1;
getNotifications();
}
$: if(typeof value_token === 'string' && value_token.length >= 36 || value_token.length === 0) {
currentPage = 1;
getNotifications();
}
function formatDateForStartup(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
}
// Сегодняшняя дата
const today = new Date();
value_endTime = formatDateForStartup(today);
// Вчерашняя дата
const yesterday = new Date(today);
yesterday.setDate(today.getDate() - 1);
value_startTime = formatDateForStartup(yesterday);
function formatDateTime(input) {
// Создаем объект Date из значения инпута
let date = new Date(input);
// Получаем значения
let year = date.getFullYear();
let month = String(date.getMonth() + 1).padStart(2, "0");
let day = String(date.getDate()).padStart(2, "0");
let hours = String(date.getHours()).padStart(2, "0");
let minutes = String(date.getMinutes()).padStart(2, "0");
let seconds = String(date.getSeconds()).padStart(2, "0");
let milliseconds = String(date.getMilliseconds()).padStart(3, "0");
// Форматируем строку с временной зоной +03:00
let timezoneOffsetMinutes = -date.getTimezoneOffset(); // инвертируем для правильного отображения
let sign = timezoneOffsetMinutes >= 0 ? "+" : "-";
let offsetHours = String(
Math.floor(Math.abs(timezoneOffsetMinutes) / 60)
).padStart(2, "0");
let offsetMinutes = String(Math.abs(timezoneOffsetMinutes) % 60).padStart(
2,
"0"
);
let timezoneOffset = `${sign}${offsetHours}:${offsetMinutes}`;
// Собираем финальную строку
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds} ${timezoneOffset}`;
}
</script>
<div class="w-full flex flex-col gap-8">
<div class="flex gap-4">
<div class="bg-accent rounded-[4px] w-[10px] h-full"></div>
<h1 class="text-2xl font-semibold">Сообщения</h1>
</div>
<div
class="flex w-full flex-col items-center bg-base-300 p-4 rounded-box overflow-x-auto"
>
<div class="flex flex-wrap w-full gap-8">
<!-- toggle -->
<div class="flex gap-2 items-center">
<p
class={(selectedNotificationType === "sms"
? "text-primary"
: "opacity-60") + " text-lg font-bold"}
>
SMS
</p>
<input
on:change={(e) => {
if (e.currentTarget.checked) {
selectedNotificationType = "push";
} else {
selectedNotificationType = "sms";
}
getNotifications();
}}
type="checkbox"
class="toggle border-base-content bg-base-content hover:bg-base-content"
checked="checked"
/>
<p
class={(selectedNotificationType === "push"
? "text-primary"
: "opacity-60") + " text-lg font-bold"}
>
Push
</p>
</div>
<div class="flex items-center gap-2">
<p>С:</p>
<input
bind:value={value_startTime}
type="datetime-local"
class="input input-bordered input-sm max-w-[200px]"
/>
</div>
<div class="flex items-center gap-2">
<p>По:</p>
<input
bind:value={value_endTime}
type="datetime-local"
class="input input-bordered input-sm max-w-[200px]"
/>
</div>
<div class="flex items-center gap-2">
<p>Токен:</p>
<input type="text" bind:value={value_token} class="input input-sm input-bordered">
</div>
</div>
<Pagination
{totalPages}
pageChangedCallback={(n) => {
currentPage = n;
getNotifications();
}}
disableButtons={disabledPages}
css={"btn-neutral self-center mt-8"}
/>
<div class="overflow-x-auto mt-4 flex flex-col w-full">
{#if showLoadingNotifies}
<span class="loading self-center"></span>
{:else if noData}
<p class="self-center">Нет данных</p>
{:else}
<table class="table">
<thead>
<tr>
{#each tableHeads as head}
<th>{headNamesMap[head]}</th>
{/each}
</tr>
</thead>
<tbody>
{#each notifications as noti}
<tr class="hover:bg-neutral group border-t-[2px] border-neutral">
{#each tableHeads as head}
<td class={head === "initial_text" ? "text-xs" : ""}
>{noti[head]}</td
>
{/each}
</tr>
{/each}
</tbody>
</table>
{/if}
</div>
</div>
</div>

View File

@ -0,0 +1,195 @@
<script>
// @ts-nocheck
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import { makePost } from "$lib/tools/requests/requests";
import { truncateMiddle } from "$lib/tools/strings/Strings";
import { sayError, sayInfo, sayWarning } from "$lib/tools/toaster/Toaster";
import Pagination from "$lib/ui-components/pagination.svelte";
const headNamesMap = {
address: "Адрес",
amount: "Сумма",
closetime: "Время закрытия",
creationtime: "Время создания",
is_active: "Статус",
token: "Токен",
tx_hash: "Хэш",
uuid: "UUID",
opt: "Опции",
};
// let selectedNotificationType = "push";
// let value_startTime = "";
// let value_endTime = "";
let totalPages = 1;
let currentPage = 1;
let disabledPages = false;
let showLoadingWithdrawals = false;
let withdrawals = [];
let tableHeads = [];
let noData = false;
// let value_token = "";
async function getWithdrawals() {
noData = false;
showLoadingWithdrawals = true;
const res = await makePost(
"admin/getWithdrawals",
{
page: currentPage,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
// console.log(res);
// console.log(formatDateTime(value_startTime));
// console.log(value_endTime);
if (res.error) {
showLoadingWithdrawals = false;
sayError("Не удалось получить уведомления");
return;
}
if (Array.isArray(res.data.data) && res.data.data.length > 0) {
let o = res.data.data[0];
tableHeads = [...Object.keys(o), "opt"];
withdrawals = [...res.data.data];
totalPages = res.data.pages;
if (withdrawals.length < 1) noData = true;
} else {
tableHeads = [];
withdrawals = [];
noData = true;
}
showLoadingWithdrawals = false;
}
getWithdrawals();
let txHash_value = "";
let uuid_value = "";
let showClosingWindow = false;
let showLoadingClosing = false;
async function closeWithdrawal() {
if (txHash_value.length <= 10 && uuid_value.length <= 10) {
sayWarning("Проверьте введенные данные");
return;
}
showLoadingClosing = true;
const res = await makePost(
"admin/closeWithrawal",
{
tx_hash: txHash_value,
uuid: uuid_value,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (res.error) {
sayError("Не удалось закрыть заявку");
showLoadingClosing = false;
return;
}
showClosingWindow = false;
showLoadingClosing = false;
}
</script>
<div class="w-full flex flex-col gap-8">
<div class="flex gap-4">
<div class="bg-accent rounded-[4px] w-[10px] h-full"></div>
<h1 class="text-2xl font-semibold">Вывод средств</h1>
</div>
<div
class="flex w-full flex-col items-center bg-base-300 p-4 rounded-box overflow-x-auto"
>
<Pagination
{totalPages}
pageChangedCallback={(n) => {
currentPage = n;
getWithdrawals();
}}
disableButtons={disabledPages}
css={"btn-neutral self-center mt-8"}
/>
<div class="overflow-x-auto mt-4 flex flex-col w-full">
{#if showLoadingWithdrawals}
<span class="loading self-center"></span>
{:else if noData}
<p class="self-center">Нет данных</p>
{:else}
<table class="table">
<thead>
<tr>
{#each tableHeads as head}
<th>{headNamesMap[head]}</th>
{/each}
</tr>
</thead>
<tbody>
{#each withdrawals as noti}
<tr class="hover:bg-neutral group border-t-[2px] border-neutral">
{#each tableHeads as head}
{#if head === "tx_hash" || head === "address"}
<td class={head === "initial_text" ? "text-xs" : ""}
>{truncateMiddle(noti[head], 4)}</td
>
{:else if head === "is_active"}
<td
class={noti[head] === "t" ? "text-success" : "text-error"}
>{noti[head] === "t" ? "Активна" : "Неактивна"}</td
>
{:else if head === "amount"}
<td>{(Number(noti[head]) / 1e6).toFixed(0)} USDT</td>
{:else if head === "opt" && noti["is_active"] === "t"}
<td>
<button on:click={()=>{showClosingWindow = true;}} class="btn btn-info">Закрыть заявку</button>
</td>
{:else}
<td class={head === "initial_text" ? "text-xs" : ""}
>{noti[head]}</td
>
{/if}
{/each}
</tr>
{/each}
</tbody>
</table>
{/if}
</div>
</div>
</div>
{#if showClosingWindow}
<div class="fixed inset-0 flex justify-center items-center z-[1000] bg-base-100 bg-opacity-50">
<div class="bg-base-300 p-4 rounded-lg flex flex-col">
<p>Хэш</p>
<input
type="text"
class="input input-bordered"
bind:value={txHash_value}
/>
<p class="mt-1">UUID</p>
<input type="text" class="input input-bordered" bind:value={uuid_value} />
<button
on:click={() => {
closeWithdrawal();
}}
class="btn btn-success mt-4"
>
{#if !showLoadingClosing}
{"Закрыть"}
{:else}
<span class="loading loading-xs"></span>
{/if}
</button>
<button
on:click={() => {
showClosingWindow = false;
txHash_value = "";
uuid_value = "";
}}
class="btn">Отмена</button
>
</div>
</div>
{/if}

View File

@ -32,7 +32,9 @@ const config = {
"/payouts",
"/merchants",
"/orders",
"/currencies"
"/currencies",
"/sms",
"/withdrawals"
],
},
},