FIRST_NAME LAST_NAME 9eb577750f fixesss
2025-10-16 13:59:20 +03:00

556 lines
19 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
import { browser } from "$app/environment";
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth.js";
import { makePost } from "$lib/tools/requests/requests.js";
import { toValidNumberFormat } from "$lib/tools/strings/Strings.js";
import { sayError } from "$lib/tools/toaster/Toaster.js";
import { redirect } from "$lib/tools/url/URLTools.js";
import CopyButton from "$lib/ui-components/CopyButton.svelte";
import Pagination from "$lib/ui-components/pagination.svelte";
export let data;
let { userData } = data;
let { token } = data;
let userInfoReloading = false;
const orderStatusMap = {
"1": "Ожидает исполнения",
"2": "Время заявки истекло",
"3": "Исполнена",
};
async function deleteUser() {
const result = await makePost(
"deleteUser",
{
token: token,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
// window.location.href = "/";
redirect("/admin/");
return;
}
if (result.error) {
sayError("Не удалось удалить пользователя");
return;
}
redirect("/admin/userslist");
}
async function reloadUserInfo() {
userInfoReloading = true;
const userResult = await makePost(
"getUser",
{
token: token,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (userResult.status === 401) {
userInfoReloading = false;
sayError("Данные авторизации устарели");
redirect("/admin/");
return;
}
if (userResult.error) {
userInfoReloading = false;
sayError("Не удалось настроить пользователя");
return;
}
userData = userResult.data;
userInfoReloading = false;
}
let userOrders = [];
let numPagesUserOrders = 1;
let currentPageUserOrders = 1;
let disablePagesUserOrders = false;
let ordersFilter = "1";
async function getUserOrders() {
disablePagesUserOrders = true;
const result = await makePost(
"admin/getUserOrders",
{
token: token,
page: currentPageUserOrders,
// orderBy: "uuid",
statuses_to_send: Number(ordersFilter),
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
// window.location.href = "/";
redirect("/admin/");
disablePagesUserOrders = false;
return;
}
if (result.error) {
sayError("Не удалось получить ордеры пользователя");
disablePagesUserOrders = false;
return;
}
userOrders = result.data.data;
if (!Array.isArray(userOrders)) userOrders = [];
numPagesUserOrders = Number(result.data?.pages);
if (numPagesUserOrders === 0) numPagesUserOrders = 1;
console.log(result.data);
disablePagesUserOrders = false;
}
let reqsCurrentPage = 1;
let reqsMaxPage = 1;
let userRequisites = [];
async function getUserRequisites() {
const result = await makePost(
"admin/getRequisite",
{
page: Number(reqsCurrentPage),
token: token,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
return;
}
if (result.error) {
sayError("Не удалось получить реквизиты пользователя");
return;
}
userRequisites = result.data.data;
if (!Array.isArray(userDeposits)) userRequisites = [];
reqsMaxPage = Number(result.data.pages);
console.log(result.data);
}
let userDeposits = [];
let numOfPagesUserDeposits = 1;
let currentPageUserDeposits = 1;
let disablePagesUserDeposits = false;
const depoStatusMap = {
"0": "Активна",
"1": "Завершена",
"2": "Отклонена",
};
///api/v1/admin/getUserDeposits
async function getUserDeposits() {
disablePagesUserDeposits = true;
const result = await makePost(
"admin/getUserDeposits",
{
token: token,
page: 1,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
disablePagesUserDeposits = false;
return;
}
if (result.error) {
sayError("Не удалось получить депозиты пользователя");
disablePagesUserDeposits = false;
return;
}
userDeposits = result.data.deposits;
if (!Array.isArray(userDeposits)) userDeposits = [];
numPagesUserOrders = result.data.pages;
disablePagesUserDeposits = false;
// console.log(result.data, 'depos');
}
$: if (browser || Number(ordersFilter) > -999) getUserOrders();
if (browser) {
getUserOrders();
getUserRequisites();
getUserDeposits();
}
let findFieldValue = "";
let showLoadingFind = false;
let showFoundedOrderWindow = false;
async function findOrder() {
showLoadingFind = true;
const res = await makePost(
"admin/find",
{},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
}
showLoadingFind = false;
const orderTypesMap = {
card: "Карта",
sbp: "СБП",
clearing_account: "По номеру счёта",
};
let showAddRef = 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 flex-col w-full gap-2">
<div class="w-full grid grid-cols-1 lg:grid-cols-2 gap-2">
<div class="w-full flex flex-col">
<div
class="bg-base-300 rounded-t-box p-4 pb-2 border-2 border-b-0 border-base-300"
>
<p class="text-lg font-semibold leading-none">Основная информация</p>
</div>
<div
class="flex flex-col p-4 gap-2 border-2 border-t-0 rounded-b-box border-base-300"
>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Токен</p>
<div class="flex gap-2">
<p class="text-accent font-semibold">{token}</p>
<CopyButton data={token} />
</div>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Имя и фамилия</p>
<p class="text-accent font-semibold">
{userData.name}
{userData.surname}
</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Валюта</p>
<p class="text-accent font-semibold">{userData?.code}</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Торговля</p>
<p
class={userData["can_trade"] === "t"
? "text-primary font-semibold"
: "text-error font-semibold"}
>
{userData["can_trade"] === "t" ? "Активна" : "Отключена"}
</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Доступ к выплатам</p>
<p
class={userData["is_withdrawal_available"] === "t"
? "text-primary font-semibold"
: "text-error font-semibold"}
>
{userData["is_withdrawal_available"] === "t"
? "Активен"
: "Отключен"}
</p>
</div>
</div>
</div>
<div class="w-full flex flex-col">
<div
class="bg-base-300 rounded-t-box p-4 pb-2 border-2 border-b-0 border-base-300"
>
<p class="text-lg font-semibold leading-none">
Информация о финансах
</p>
</div>
<div
class="flex flex-col p-4 gap-2 border-2 border-t-0 rounded-b-box border-base-300"
>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Баланс</p>
<p class="text-accent font-semibold">
{toValidNumberFormat(userData.balance)}
{userData?.code}
</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Страховка</p>
<p class="text-accent font-semibold">{userData?.insurance} USDT</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Ставка</p>
<p class="text-accent font-semibold">{userData.bid}%</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Ставка на выплаты</p>
<p class="text-accent font-semibold">{userData.payout_bid}%</p>
</div>
<div class="flex flex-col">
<p class="opacity-50 text-xs">Кошелёк пополнения</p>
<div class="flex gap-2">
<p class="text-accent font-semibold">
{userData.deposit_address}
</p>
<CopyButton data={userData.deposit_address} />
</div>
</div>
</div>
</div>
</div>
<div class="w-full flex justify-start gap-2 overflow-auto">
<button
class="btn btn-neutral w-[100px] btn-outline rounded-lg btn-sm"
on:click={() => {
reloadUserInfo();
}}
disabled={userInfoReloading}
>
{#if !userInfoReloading}
{"Обновить"}
{:else}
<span class="loading loading-spinner"></span>
{/if}
</button>
<a
href={window.location.pathname.replace("profile", "change")}
class="btn btn-info btn-outline rounded-lg btn-sm">Изменить</a
>
<a
href={`/admin/change-balance/${token}`}
class="btn btn-neutral btn-outline rounded-lg btn-sm">Изменить баланс</a
>
<button
on:click={() => {
if (confirm("Вы уверены, что хотите удалить пользователя?"))
deleteUser();
}}
class="btn btn-error btn-outline rounded-lg btn-sm">Удалить</button
>
</div>
</div>
<div class="flex items-center gap-4">
<div class="bg-accent rounded-[4px] w-[10px] h-full"></div>
<h1 class="text-2xl font-semibold">Реквизиты пользователя</h1>
<button disabled class="btn btn-accent">Добавить реквизит</button>
</div>
<div class="w-full flex flex-col p-4 rounded-box bg-base-300">
<div class="w-full flex flex-col justify-center items-center">
<Pagination
totalPages={reqsMaxPage}
pageChangedCallback={(n) => {
reqsCurrentPage = n;
getUserRequisites();
}}
disableButtons={false}
css={"btn-neutral mt-2"}
/>
<p class="opacity-50 text-xs mt-1">Всего страниц: {reqsMaxPage}</p>
</div>
</div>
<div class="w-full flex flex-col p-4 rounded-box bg-base-300">
<div class="overflow-x-auto mt-4">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>ID</th>
<th>Статус</th>
<th>Банк</th>
<th>СБП</th>
<th>Карта</th>
<th>Телефон</th>
<th>Имя</th>
<th>Девайс</th>
<th>Объем {userData.code}</th>
<th>Лимит {userData.code}</th>
<th>Опции</th>
<!-- <th></th> -->
</tr>
</thead>
<tbody>
{#each userRequisites as requisite}
<tr class="hover:bg-neutral group">
<td class="font-semibold">{requisite["uuid"]}</td>
<td class=""
>{requisite["status"] === "t" ? "активен" : "отключен"}</td
>
<td>{requisite["bank_name"]}</td>
<td>{requisite["is_sbp"] === "t" ? "да" : "нет"}</td>
<td>{requisite["cardnumber"]}</td>
<td>{requisite["phone"]}</td>
<td>{requisite["name"]}</td>
<td>{requisite["device_uuid"]}</td>
<td>{toValidNumberFormat(requisite["total_volume"])}</td>
<td>{toValidNumberFormat(requisite["daily_volume_limit"])}</td>
<td class="flex gap-2">
<a
href={"/admin/user/edit/req/" +
token +
"/" +
requisite["uuid"] +
"_" +
userData.code}
class="btn btn-info">Изменить</a
>
<button class="btn btn-error">Удалить</button>
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
<!-- <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="w-full flex flex-col p-4 rounded-box bg-base-300"></div> -->
<div class="flex items-center gap-4">
<div class="bg-accent rounded-[4px] w-[10px] h-full"></div>
<h1 class="text-2xl font-semibold">Текущие заявки</h1>
<!-- <button href={"/user/neworder/"+token} disabled class="btn btn-accent">Добавить заявку</button> -->
</div>
<div class="w-full flex flex-col p-4 rounded-box bg-base-300">
<div class="w-full flex flex-col justify-center items-center">
<!-- <div class="flex items-center gap-2">
<input bind:value={findFieldValue} type="text" class="input input-bordered">
<button on:click={()=>{showFoundedOrderWindow = true;}} class="btn btn-outline">Найти</button>
</div> -->
<Pagination
totalPages={numPagesUserOrders}
pageChangedCallback={(n) => {
currentPageUserOrders = n;
getUserOrders();
}}
disableButtons={disablePagesUserOrders}
css={"btn-neutral mt-2"}
/>
<p class="opacity-50 text-xs mt-1">Всего страниц: {numPagesUserOrders}</p>
<select
bind:value={ordersFilter}
class="select select-bordered min-w-[230px] mt-2"
>
<!-- <option value="-1"> Все выплаты </option> -->
<option value="1"> {orderStatusMap["1"]} </option>
<option value="2"> {orderStatusMap["2"]} </option>
<option value="3"> {orderStatusMap["3"]} </option>
</select>
</div>
<div class="overflow-x-auto mt-4">
<table class="table">
<!-- head -->
<thead>
<tr>
<!-- <th>ID заявки</th> -->
<th>UUID</th>
<th>ID клиента</th>
<th>Статус</th>
<th>Сумма</th>
<th>Тип заявки</th>
<!-- <th>Курс</th> -->
<!-- <th>Название реквизита</th> -->
<!-- <th>СБП</th> -->
<th>Мерчант</th>
<th>Время создания</th>
<th>Время закрытия</th>
<!-- <th>Опции</th> -->
<!-- <th></th> -->
</tr>
</thead>
<tbody>
{#each userOrders as order}
<tr class="hover:bg-neutral group">
<!-- <td class="font-semibold">{order["id"]}</td> -->
<td class="font-semibold">{order["uuid"]}</td>
<td class="font-semibold">{order["external_user_id"]}</td>
<td class="">{order["status"]}</td>
<td>{toValidNumberFormat(order["summa"])} {userData?.code}</td>
<td>{orderTypesMap[order["order_type"]]}</td>
<!-- <td>{order["rate"]} {userData?.code}</td> -->
<!-- <td>{order["is_sbp"] === "t" ? "да" : "нет"}</td> -->
<td>{order["merchant"]}</td>
<td>{order["creation_time"]}</td>
<td>{order["closetime"]}</td>
<!-- <td>
<button class="btn btn-outline">Закрыть ручками</button>
</td> -->
<!-- <td class="flex gap-2">
<a href="" class="btn btn-info">Изменить</a>
<button class="btn btn-error">Удалить</button>
</td> -->
</tr>
{/each}
</tbody>
</table>
</div>
</div>
<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="w-full flex flex-col p-4 rounded-box bg-base-300">
<div class="w-full flex flex-col justify-center items-center">
<Pagination
totalPages={numOfPagesUserDeposits}
pageChangedCallback={(n) => {
currentPageUserDeposits = n;
getUserDeposits();
}}
disableButtons={disablePagesUserDeposits}
css={"btn-neutral"}
/>
<p class="opacity-50 text-xs mt-1">
Всего страниц: {numOfPagesUserDeposits}
</p>
</div>
<div class="overflow-x-auto mt-4">
<table class="table">
<!-- head -->
<thead>
<tr>
<th>Статус</th>
<th>Сумма</th>
<th>Время создания</th>
<!-- <th>Опции</th> -->
<!-- <th></th> -->
</tr>
</thead>
<tbody>
{#each userDeposits as depo}
<tr class="hover:bg-neutral group">
<td class="">{depoStatusMap[depo["pending"]]}</td>
<td>{toValidNumberFormat(depo["amount"])} USDT</td>
<td>{depo["creationtime"]}</td>
<!-- <td class="flex gap-2">
<a href="" class="btn btn-info">Изменить</a>
<button class="btn btn-error">Удалить</button>
</td> -->
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</div>
{#if showAddRef}
<div class="fixed inset-0 bg-black opacity-60"></div>
<div class="fixed inset-0 bg-transparent flex justify-center items-center">
<div class="bg-base-300 rounded-md p-4 w-full max-w-[400px]"></div>
</div>
{/if}
<!-- {#if showFoundedOrderWindow}
<div class="fixed z-[1000] inset-0 flex justify-center items-center bg-black bg-opacity-50">
<div class="bg-base-100 rounded-md p-4 flex flex-col">
<button class="btn btn-outline" on:click={()=>{showFoundedOrderWindow = false;}}>Закрыть</button>
<button class="btn btn-outline" on:click={()=>{showFoundedOrderWindow = false;}}>Закрыть</button>
</div>
</div>
{/if} -->