FIRST_NAME LAST_NAME 938d345769 fixes
2025-10-17 13:03:06 +03:00

863 lines
27 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>
// @ts-nocheck
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import {
API_PATH_TEST,
API_PATH_MAIN,
makePost,
API_PATH_VALUE,
} 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";
import axios from "axios";
import {
isStringEmptyOrSpaces,
toValidNumberFormat,
} from "$lib/tools/strings/Strings";
import { CopyIcon, SearchIcon, XCircleIcon } from "svelte-feather-icons";
const payoutsStatusMap = {
"0": "Открыта",
"1": "Ожидает оплаты",
"2": "Оплачена",
"3": "Отказано",
"4": "Требует проверки",
};
const payoutsStatusMapColors = {
"0": "text-white",
"1": "text-warning",
"2": "text-success",
"3": "text-error",
"4": "text-warning",
};
//admin/getDisputes
// @ts-ignore
let payouts = [];
let numOfPagesPayouts = 1;
let currentPagePayouts = 1;
let disablePagesPayouts = false;
let currentPayoutsFilter = -1;
let searchFilter = "";
let searchNoResults = false;
async function getPayouts() {
disablePagesPayouts = true;
if (searchFilter === "") {
const result = await makePost(
"admin/payouts",
{
type: 0,
page: currentPagePayouts - 1,
filter: currentPayoutsFilter,
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
console.log(result);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
disablePagesPayouts = false;
// disablePagesUserDeposits = false;
return;
}
if (result.error) {
sayError("Не удалось получить выплаты");
disablePagesPayouts = false;
// disablePagesUserDeposits = false;
return;
}
payouts = result.data.payouts;
console.log(payouts);
numOfPagesPayouts = result.data.pages === 0 ? 1 : result.data?.pages;
disablePagesPayouts = false;
} else {
let s = searchFilter.trim();
let useUUID = true;
if (useUUID) {
const result = await makePost(
"admin/payout/search",
{
page: currentPagePayouts,
uuid: s,
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
console.log(result);
if (result.error) {
payouts = [];
numOfPagesPayouts = 1;
disablePagesPayouts = false;
sayError("Ошибка поиска");
return;
}
if (typeof result.data !== "string") {
payouts = result.data.data;
numOfPagesPayouts = result.data.pages === 0 ? 1 : result.data?.pages;
disablePagesPayouts = false;
} else {
payouts = [];
numOfPagesPayouts = 1;
disablePagesPayouts = false;
}
}
}
}
getPayouts();
let selectedPayout = {
amount: "",
code: "",
creation_time: "",
currency_id: "",
customer_ip: "",
pan: "",
rate: "",
receipt: "",
status: "0",
uuid: "",
};
let showFullInfo = false;
// async function acceptPayout() {
// //admin/changeDispute
// const result = await makePost(
// "admin/changeDispute",
// {
// action: selectedPayout.order_status === "8" ? 3 : 1,
// order_id: selectedPayout.order_id,
// dispute_uuid: selectedPayout.dispute_uuid,
// },
// // @ts-ignore
// makeAuthHeaderForAxios(getAuthInfo()?.a),
// );
// console.log(result);
// if (result.status === 401) {
// sayError("Данные авторизации устарели");
// redirect("/admin/");
// // disablePagesUserDeposits = false;
// return;
// }
// if (result.error) {
// sayError("Не удалось принять выплату");
// // disablePagesUserDeposits = false;
// return;
// }
// sayInfo("Выплата одобрена!");
// showFullInfo = false;
// getPayouts();
// }
// async function rejectPayout() {
// const result = await makePost(
// "admin/changeDispute",
// {
// action: selectedPayout.order_status === "8" ? 4 : 2,
// order_id: selectedPayout.order_id,
// dispute_uuid: selectedPayout.dispute_uuid,
// },
// // @ts-ignore
// makeAuthHeaderForAxios(getAuthInfo()?.a),
// );
// console.log(result);
// if (result.status === 401) {
// sayError("Данные авторизации устарели");
// redirect("/admin/");
// // disablePagesUserDeposits = false;
// return;
// }
// if (result.error) {
// sayError("Не удалось отклонить выплату");
// // disablePagesUserDeposits = false;
// return;
// }
// sayInfo("Выплата отклонена!");
// showFullInfo = false;
// getPayouts();
// }
// @ts-ignore
function mimeToExtension(mimeType) {
const mimeTypes = {
"application/pdf": "pdf",
"application/zip": "zip",
"image/jpeg": "jpg",
"image/jpg": "jpg",
"image/png": "png",
"text/plain": "txt",
"application/msword": "doc",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document":
"docx",
// Добавьте дополнительные MIME-типы по необходимости
};
// @ts-ignore
return mimeTypes[mimeType] || "bin"; // Если тип неизвестен, возвращаем .bin
}
function checkFields() {
if (
!isStringEmptyOrSpaces(newPayoutTraderUUID) &&
newPayoutTraderUUID.length > 10
) {
allowToSave = true;
return;
}
if (newPayoutStatus !== selectedPayout.status) {
allowToSave = true;
return;
}
allowToSave = false;
}
let newPayoutTraderUUID = "";
let newPayoutStatus = selectedPayout.status;
let allowToSave = false;
// $: selectedPayout, newPayoutStatus = selectedPayout.status;
$: newPayoutTraderUUID, newPayoutStatus, checkFields();
let awaitChanging = false;
async function changePayout() {
awaitChanging = true;
const result = await makePost(
"admin/payouts",
{
type: 1,
uuid: selectedPayout.uuid,
trader_uuid:
isStringEmptyOrSpaces(newPayoutTraderUUID) ||
newPayoutTraderUUID.length < 10
? selectedPayout.trader_uuid
: newPayoutTraderUUID,
status: Number(newPayoutStatus),
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
console.log(result);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
// disablePagesUserDeposits = false;
awaitChanging = false;
return;
}
if (result.error) {
sayError("Не удалось изменить выплату");
// disablePagesUserDeposits = false;
awaitChanging = false;
return;
}
sayInfo("Выплата успешно изменена!");
showFullInfo = false;
getPayouts();
awaitChanging = false;
}
let numOfOpened = 0;
let numOfAccepted = 0;
let numOfCanceled = 0;
let numOfPayed = 0;
async function getStats() {
const result = await makePost(
"admin/payouts",
{
type: 3,
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
console.log(result);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
// disablePagesUserDeposits = false;
awaitChanging = false;
return;
}
if (result.error) {
sayError("Не удалось получить статистику выплат");
// disablePagesUserDeposits = false;
// awaitChanging = false;
return;
}
numOfOpened = result.data?.opened;
numOfAccepted = result.data?.accepted;
numOfCanceled = result.data?.canceled;
numOfPayed = result.data?.payed;
// sayInfo("Выплата успешно изменена!");
// showFullInfo = false;
// getPayouts();
// awaitChanging = false;
}
getStats();
let awaitChangingNull = false;
async function nullificatePayout() {
if (awaitChangingNull) return;
awaitChangingNull = true;
const result = await makePost(
"admin/payouts",
{
type: 2,
uuid: selectedPayout.uuid,
// trader_uuid: (isStringEmptyOrSpaces(newPayoutTraderUUID) || newPayoutTraderUUID.length < 10) ? selectedPayout.trader_uuid:newPayoutTraderUUID,
// status: Number(newPayoutStatus)
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
console.log(result);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
// disablePagesUserDeposits = false;
awaitChangingNull = false;
return;
}
if (result.error) {
sayError("Не удалось изменить выплату");
// disablePagesUserDeposits = false;
awaitChangingNull = false;
return;
}
sayInfo("Выплата успешно обнулена!");
showFullInfo = false;
getPayouts();
awaitChangingNull = false;
}
let awaitAccepting = false;
async function acceptPayout() {
if (awaitAccepting) return;
awaitAccepting = true;
const result = await makePost(
"admin/payouts",
{
type: 4,
uuid: selectedPayout.uuid,
status: 2,
// trader_uuid: (isStringEmptyOrSpaces(newPayoutTraderUUID) || newPayoutTraderUUID.length < 10) ? selectedPayout.trader_uuid:newPayoutTraderUUID,
// status: Number(newPayoutStatus)
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.error) {
sayError("Не удалось принять выплату");
// disablePagesUserDeposits = false;
awaitAccepting = false;
return;
}
sayInfo("Выплата успешно принята!");
showFullInfo = false;
getPayouts();
awaitAccepting = false;
}
let awaitDecline = false;
async function declinePayout() {
if (awaitDecline) return;
awaitDecline = true;
const result = await makePost(
"admin/payouts",
{
type: 4,
uuid: selectedPayout.uuid,
status: 0,
// trader_uuid: (isStringEmptyOrSpaces(newPayoutTraderUUID) || newPayoutTraderUUID.length < 10) ? selectedPayout.trader_uuid:newPayoutTraderUUID,
// status: Number(newPayoutStatus)
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.error) {
sayError("Не удалось отклонить выплату");
// disablePagesUserDeposits = false;
awaitDecline = false;
return;
}
sayInfo("Выплата успешно отклонена!");
showFullInfo = false;
getPayouts();
awaitDecline = false;
}
let awaitCancel = false;
async function cancelPayout() {
if (awaitCancel) return;
awaitCancel = true;
const result = await makePost(
"admin/payouts",
{
type: 5,
uuid: selectedPayout.uuid,
// trader_uuid: (isStringEmptyOrSpaces(newPayoutTraderUUID) || newPayoutTraderUUID.length < 10) ? selectedPayout.trader_uuid:newPayoutTraderUUID,
// status: Number(newPayoutStatus)
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.error) {
sayError("Не удалось отменить выплату");
// disablePagesUserDeposits = false;
awaitCancel = false;
return;
}
sayInfo("Выплата успешно отменена!");
showFullInfo = false;
getPayouts();
awaitCancel = false;
}
let awaitGoodCallback = false;
async function sendGoodCallback(uuid) {
if (awaitGoodCallback) return;
awaitGoodCallback = true;
const response = await makePost(
"admin/sendPayoutsCallback",
{ type: 1, uuid },
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (response.error) {
sayError("Ошибка отправки коллбэка");
} else {
sayInfo("Успешно!");
}
awaitGoodCallback = false;
}
let awaitBadCallback = false;
async function sendBadCallback(uuid) {
if (awaitBadCallback) return;
awaitBadCallback = true;
const response = await makePost(
"admin/sendPayoutsCallback",
{ type: 2, uuid },
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (response.error) {
sayError("Ошибка отправки коллбэка");
} else {
sayInfo("Успешно!");
}
awaitBadCallback = false;
}
</script>
<div class="w-full flex flex-col gap-8">
<div class="w-full flex justify-center flex-wrap">
<div class="stats shadow">
<div class="stat">
<div class="stat-title text-warning">Открыто выплат</div>
<div class="stat-value text-warning text-6xl">{numOfOpened}</div>
<!-- <div class="stat-desc">21% more than last month</div> -->
</div>
</div>
<div class="stats shadow">
<div class="stat">
<div class="stat-title text-info">Принято выплат</div>
<div class="stat-value text-info text-6xl">{numOfAccepted}</div>
<!-- <div class="stat-desc">21% more than last month</div> -->
</div>
</div>
<div class="stats shadow">
<div class="stat">
<div class="stat-title text-success">Оплачено сегодня</div>
<div class="stat-value text-success text-6xl">{numOfPayed}</div>
<!-- <div class="stat-desc">21% more than last month</div> -->
</div>
</div>
<div class="stats shadow">
<div class="stat">
<div class="stat-title text-error">Отказов сегодня</div>
<div class="stat-value text-error text-6xl">{numOfCanceled}</div>
<!-- <div class="stat-desc">21% more than last month</div> -->
</div>
</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 bg-base-300 p-4 rounded-box">
<div class="flex flex-col p-0 gap-2.5">
<div class="flex gap-2.5">
<input
bind:value={searchFilter}
type="text"
class="input input-bordered max-w-full w-full rounded-[10px]"
placeholder="UUID, External UUID, Токен или External User ID"
/>
<div class="flex gap-[5px]">
<button
on:click={() => {
numOfPagesPayouts = 1;
currentPagePayouts = 1;
getPayouts();
}}
class="btn btn-neutral rounded-[10px]"
>
<SearchIcon />
</button>
<button
on:click={() => {
searchFilter = "";
currentPagePayouts = 1;
numOfPagesPayouts = 1;
getPayouts();
}}
class="btn btn-neutral rounded-[10px]"
>
<XCircleIcon />
</button>
</div>
</div>
<select
on:change={(e) => {
currentPayoutsFilter = Number(e.target.value);
if (searchFilter === "") {
getPayouts();
}
}}
class="select select-bordered w-full text-base"
disabled={searchFilter !== ""}
>
<option selected value="-1">Показать все выплаты</option>
<option value="2">Оплаченные</option>
<option value="3">Отклонённые</option>
<option value="1">Принятые</option>
<option value="4">Требуют проверки</option>
<!-- <option value="4">Требует проверки</option> -->
</select>
</div>
<div class="w-full flex flex-col justify-center items-center mt-2">
<Pagination
currentPage={currentPagePayouts}
totalPages={numOfPagesPayouts}
pageChangedCallback={(n) => {
currentPagePayouts = n;
getPayouts();
}}
disableButtons={disablePagesPayouts}
css={"btn-neutral"}
/>
<p class="opacity-50 text-xs mt-1">
Всего страниц: {numOfPagesPayouts}
</p>
</div>
<div class="overflow-x-auto mt-4 flex flex-col">
{#if !disablePagesPayouts}
<table class="table">
<!-- head -->
<thead>
<tr>
<th>ID</th>
<th>Статус</th>
<th>Сумма</th>
<th>Карта</th>
<!-- <th>Курс</th> -->
<th>Время создания</th>
<th>Время принятия</th>
<th>Мерчант</th>
<th>Опции</th>
<!-- <th></th> -->
</tr>
</thead>
<tbody>
{#each payouts as payout}
<tr class="hover:bg-neutral group">
<td class="font-semibold">{payout["uuid"]}</td>
<td class={payoutsStatusMapColors[payout["status"]]}
>{payoutsStatusMap[payout["status"]]}</td
>
<!-- <td>{payout["is_sbp"] === "t" ? "да" : "нет"}</td> -->
<td>{toValidNumberFormat(payout["amount"])} {payout["code"]}</td
>
<td>{payout["pan"]}</td>
<!-- <td>{payout["rate"]} {payout["code"]}</td> -->
<!-- <td>{payout["amount"]}</td> -->
<td>{payout["creation_time"]}</td>
<td>{payout["accept_time"]}</td>
<td>{payout["merchant_name"]}</td>
<td
on:click={() => {
selectedPayout = payout;
newPayoutStatus = payout.status;
showFullInfo = true;
}}
class="flex gap-2"
>
<button class="btn btn-info">Подробнее</button>
</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<span class="loading loading-spinner self-center"></span>
{/if}
</div>
</div>
</div>
{#if showFullInfo}
<div
class="fixed inset-0 overflow-auto flex flex-col items-center md:p-32 p-8 pt-[68px] bg-black bg-opacity-50"
>
<div class="flex flex-col w-full max-w-[600px] p-4 rounded-box bg-base-300">
<p class="self-center opacity-60 text-center">
ID: {selectedPayout.uuid}
</p>
<p
class={"self-center text-3xl " +
payoutsStatusMapColors[selectedPayout["status"]]}
>
Выплата {payoutsStatusMap[selectedPayout["status"]]}
</p>
<p class="self-center opacity-60">{selectedPayout.creation_time}</p>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<!-- <p class="text-lg font-bold">{selectedPayout.name}</p> -->
<p class="">
IP заказчика: <span class="font-medium"
>{selectedPayout.customer_ip}</span
>
</p>
<p class="">
Карта: <span class="font-medium">{selectedPayout.pan}</span>
</p>
<!-- <p class="">
ID трейдера: {selectedPayout.trader_uuid === ""
? "---"
: selectedPayout.trader_uuid}
</p> -->
</div>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold opacity-50">Сумма</p>
<p>
{toValidNumberFormat(selectedPayout.amount)}
{selectedPayout.code}
</p>
</div>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold opacity-50">Время принятия</p>
<p>
{selectedPayout.accept_time}
</p>
</div>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold opacity-50">Мерчант</p>
<p>
{selectedPayout.merchant_name}
</p>
</div>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold opacity-50">Заказчик</p>
<p>
{selectedPayout.customer_name}
{selectedPayout.customer_surname}
</p>
</div>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold opacity-50">Команда трейдеров</p>
<p class="font-medium text-lg">
{selectedPayout.name}
</p>
<div class="flex gap-[10px]">
<p>{selectedPayout["trader_uuid"]}</p>
<button
class="px-1 border-[#333]"
on:click={(e) => {
navigator.clipboard.writeText(selectedPayout["trader_uuid"]);
e.target.style.color = "#00ab75";
}}
>
<CopyIcon size={"18"} />
</button>
</div>
</div>
<!-- <div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold">Курс</p>
<p>{selectedPayout.rate} {selectedPayout.code}</p>
</div> -->
{#if selectedPayout["status"] !== "4"}
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold">ID нового трейдера:</p>
<p class="text-sm opacity-50">
Оставьте пустым, чтобы оставить прежнего трейдера
</p>
<input
bind:value={newPayoutTraderUUID}
type="text"
placeholder="1a02045f-c681-4d05-84aa-18e8a351daa7"
class="input input-bordered w-full max-w-xs"
/>
</div>
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold">Изменить статус:</p>
<select
bind:value={newPayoutStatus}
class="select select-bordered w-full text-base"
>
<option value="0">Открыта</option>
<option value="2">Оплачена</option>
<option value="3">Отклонена</option>
<option value="4">Требует проверки</option>
<option value="1">Принята</option>
</select>
</div>
{/if}
{#if selectedPayout["status"] === "2" || selectedPayout["status"] === "4"}
<button
on:click={() => {
axios
.get(
API_PATH_VALUE +
"admin/loadFile?payout=" +
selectedPayout["uuid"],
{
responseType: "blob",
headers: makeAuthHeaderForAxios(getAuthInfo()?.a).headers,
}
)
.then(function (response) {
// Создаем ссылку для скачивания
const url = window.URL.createObjectURL(
new Blob([response.data])
);
const contentType = response?.data?.type; // Извлекаем MIME-тип из Blob
let extension = mimeToExtension(contentType); // Получаем расширение из функции
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = ек_${Date.now()}.${extension}`;
document.body.appendChild(a);
a.click();
// Очищаем
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
})
.catch(function (error) {
console.error("Error:", error);
});
}}
class="btn btn-outline btn-info mt-4"
>
Скачать чек
</button>
{/if}
{#if selectedPayout["status"] !== "4"}
<button
on:click={() => {
changePayout();
// showFullInfo = false;
}}
class="btn btn-outline btn-ghost mt-4 btn-success disabled:bg-transparent"
disabled={!allowToSave}
>
Сорханить
{#if awaitChanging}
<span class="loading loading-spinner loading-md"></span>
{/if}
</button>
{/if}
{#if selectedPayout["status"] === "4"}
<button
on:click={() => {
acceptPayout();
// changePayout();
// showFullInfo = false;
}}
class="btn btn-outline btn-ghost mt-4 btn-success disabled:bg-transparent"
>
Принять
{#if awaitAccepting}
<span class="loading loading-spinner loading-md"></span>
{/if}
</button>
<button
on:click={() => {
declinePayout();
// changePayout();
// showFullInfo = false;
}}
class="btn btn-outline btn-ghost mt-4 btn-error disabled:bg-transparent"
>
Отклонить
{#if awaitDecline}
<span class="loading loading-spinner loading-md"></span>
{/if}
</button>
{/if}
<button
on:click={() => {
sendGoodCallback(selectedPayout["uuid"]);
}}
class="btn btn-outline text-lime-500 hover:bg-lime-400 hover:text-black hover:border-lime-400 mt-4"
>
{#if awaitGoodCallback}
<span class="loading loading-spinner loading-md"></span>
{:else}
Отправить успешный коллбэк
{/if}
</button>
<button
on:click={() => {
sendBadCallback(selectedPayout["uuid"]);
}}
class="btn btn-outline text-orange-500 hover:bg-orange-400 hover:text-black hover:border-orange-400 mt-4"
>
{#if awaitBadCallback}
<span class="loading loading-spinner loading-md"></span>
{:else}
Отправить неуспешный коллбэк
{/if}
</button>
<button
on:click={() => {
cancelPayout();
// changePayout();
// showFullInfo = false;
}}
class="btn btn-outline btn-ghost mt-4 btn-error disabled:bg-transparent"
>
Отменить выплату
{#if awaitCancel}
<span class="loading loading-spinner loading-md"></span>
{/if}
</button>
{#if selectedPayout["status"] !== "4"}
<button
on:click={() => {
nullificatePayout();
}}
class="btn btn-outline btn-error mt-4"
>
Обнулить выплату
{#if awaitChangingNull}
<span class="loading loading-spinner loading-md"></span>
{/if}
</button>
{/if}
<button
on:click={() => {
showFullInfo = false;
}}
class="btn btn-outline btn-ghost mt-4"
>
Закрыть
</button>
</div>
</div>
{/if}