This commit is contained in:
FIRST_NAME LAST_NAME 2025-10-17 13:03:06 +03:00
parent 9eb577750f
commit 938d345769
10 changed files with 366 additions and 139 deletions

View File

@ -18,7 +18,7 @@
showMenu = !showMenu;
}}
tabindex="0"
class="btn btn-ghost 2xl:hidden w-[54px] max-w-[54px] p-1"
class="btn btn-ghost w-[54px] max-w-[54px] p-1"
>
{#if !showMenu}
<svg
@ -45,7 +45,7 @@
{jwtDecode(getAuthInfo()?.a)?.role == "4" ? "Admin" : "Moder"}
</p>
</div>
<div class="navbar-center hidden 2xl:flex font-semibold">
<div class="navbar-center hidden font-semibold">
<ul class="menu menu-horizontal px-1">
<li>
<a href="/admin/userslist">Пользователи</a>
@ -64,7 +64,6 @@
<li><a href="/admin/change-balance/0">Управление балансом</a></li>
<li><a href="/admin/refs">Рефералы</a></li>
{/if}
<!-- <li><a>Item 3</a></li> -->
</ul>
</div>
<div class="navbar-end">
@ -85,7 +84,7 @@
</div>
<div
class={"fixed inset-0 top-16 z-50 px-5 flex flex-col items-center justify-center bg-base-100 transition-all duration-150 2xl:hidden " +
class={"fixed inset-0 top-16 z-50 px-5 flex flex-col items-center justify-center bg-base-100 transition-all duration-150 " +
(showMenu ? "" : "-translate-x-full")}
>
<ul
@ -254,6 +253,21 @@
<ChevronRightIcon />
</div>
</li>
<div
class="h-[1px] w-full bg-neutral flex-shrink-0 opacity-50 my-[5px]"
></div>
<li class="relative">
<a
class="text-lg"
on:click={() => {
showMenu = false;
}}
href="/admin/req">Реквизиты</a
>
<div class="absolute right-0 top-[2px] pointer-events-none">
<ChevronRightIcon />
</div>
</li>
{/if}
</ul>
</div>

View File

@ -1,4 +1,4 @@
export const prerender = true;
export const ssr = false;
// console.log = () => {};
console.log = () => {};

View File

@ -35,7 +35,7 @@
<div
class="flex justify-center flex-shrink-0 w-full h-[calc(100vh-52px-68px)] mt-[68px] overflow-auto p-4"
>
<div class="flex w-full md:max-w-[90%] lg:max-w-[1080px]">
<div class="flex w-full md:max-w-[90%] lg:max-w-[1560px]">
<slot />
</div>
</div>

View File

@ -37,8 +37,8 @@
let external_user_idValue = "";
let searchValue = "";
async function findDispute() {
if (searchValue.length < 5 || showLoadingFind) return;
async function findDeposit() {
if (searchValue.length < 1 || showLoadingFind) return;
showLoadingFind = true;
let sData = {
@ -89,6 +89,7 @@
sayInfo("Заявка закрыта!");
showLoadingRollback = false;
showFoundedOrderWindow = false;
findDeposit();
}
let showChangeSum = false;
@ -119,6 +120,7 @@
showLoadingChangeSum = false;
showChangeSum = false;
showFoundedOrderWindow = false;
findDeposit();
}
async function changeSumWithoutBalance(uuid) {
showLoadingChangeSum = true;
@ -142,6 +144,7 @@
showLoadingChangeSum = false;
showChangeSum = false;
showFoundedOrderWindow = false;
findDeposit();
}
let showLoadingSendCallback = false;
@ -190,12 +193,14 @@
sayInfo("Команда изменена");
changingTeam = false;
showChangeTeamWindow = false;
showFoundedOrderWindow = false;
findDeposit();
}
let img64 = "";
let qrCode = false;
$: if (selectedDispute && selectedDispute["cardnumber"].length > 16) {
$: if (selectedDispute && selectedDispute["requisite_type"] === "p2p_qr") {
qrCode = true;
QRCode.toDataURL(selectedDispute["cardnumber"], {
type: "image/jpeg",
@ -215,7 +220,7 @@
<div class="w-full flex flex-col p-4 rounded-box bg-base-300">
<input
bind:value={searchValue}
placeholder="UUID, External UUID или External User ID"
placeholder="UUID, External UUID, Токен или External User ID"
type="text"
class="input input-bordered"
/>
@ -224,7 +229,7 @@
on:click={() => {
maxDepositSearchPages = 1;
currentDepositSearchPage = 1;
findDispute();
findDeposit();
}}
class="btn btn-outline mt-2"
>
@ -242,7 +247,7 @@
on:click={() => {
if (currentDepositSearchPage <= 1) return;
currentDepositSearchPage -= 1;
findDispute();
findDeposit();
}}
>
&lt;
@ -256,7 +261,7 @@
on:click={() => {
if (currentDepositSearchPage >= maxDepositSearchPages) return;
currentDepositSearchPage += 1;
findDispute();
findDeposit();
}}
>
&gt;
@ -360,8 +365,8 @@
<p>{selectedDispute["name"]}</p>
{/if}
{#if selectedDispute["cardnumber"] !== ""}
{#if selectedDispute["cardnumber"].length <= 16}
<p class="text-sm mt-3">Карта</p>
{#if selectedDispute["requisite_type"] !== "p2p_qr"}
<p class="text-sm mt-3">Карта/CVU</p>
<p>{selectedDispute["cardnumber"]}</p>
{:else}
<p class="text-sm mt-3">QR</p>

View File

@ -496,7 +496,7 @@
bind:value={searchFilter}
type="text"
class="input input-bordered max-w-full w-full rounded-[10px]"
placeholder="UUID, External ID или Реквизит"
placeholder="UUID, External UUID, Токен или External User ID"
/>
<div class="flex gap-[5px]">
<button

133
src/routes/req/+page.svelte Normal file
View File

@ -0,0 +1,133 @@
<script>
import { makeAuthHeaderForAxios, getAuthInfo } from "$lib/auth/Auth";
import { makePost } from "$lib/tools/requests/requests";
import { toValidNumberFormat } from "$lib/tools/strings/Strings";
import { sayError } from "$lib/tools/toaster/Toaster";
import { redirect } from "$lib/tools/url/URLTools";
import Pagination from "$lib/ui-components/pagination.svelte";
let searchValue = "";
let showLoadingFind = false;
let reqsCurrentPage = 1;
let reqsMaxPage = 1;
let userRequisites = [];
async function getUserRequisites() {
if (showLoadingFind) return;
showLoadingFind = true;
const result = await makePost(
"admin/getRequisite",
{
page: Number(reqsCurrentPage),
token: searchValue,
},
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
redirect("/admin/");
showLoadingFind = false;
return;
}
if (result.error) {
sayError("Не удалось получить реквизиты пользователя");
showLoadingFind = false;
return;
}
userRequisites = result.data.data;
if (!Array.isArray(userRequisites)) userRequisites = [];
reqsMaxPage = Number(result.data.pages);
console.log(result.data);
showLoadingFind = false;
}
</script>
<div class="w-full flex flex-col gap-8">
<div class="w-full flex flex-col p-4 rounded-box bg-base-300">
<input
bind:value={searchValue}
placeholder="Токен пользователя"
type="text"
class="input input-bordered"
/>
<button
on:click={() => {
reqsMaxPage = 1;
reqsCurrentPage = 1;
getUserRequisites();
}}
class="btn btn-outline mt-2"
>
{#if showLoadingFind}
<span class="loading loading-dots loading-xs"></span>
{:else}
{"Найти реквизиты"}
{/if}
</button>
<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">
{#if showLoadingFind}
<span class="loading loading-md self-center"></span>
{:else}
<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></th> -->
</tr>
</thead>
<tbody>
{#each userRequisites as requisite}
<tr class="hover:bg-neutral group">
<td class="font-semibold">{requisite["uuid"]}</td>
<td class=""
>{requisite["is_hidden"] !== "t" ? "активен" : "отключен"}</td
>
<td>{requisite["bank_name"]}</td>
<td>{requisite["requisite_type"]}</td>
<td>{requisite["requisite"] ?? "-"}</td>
<td>{requisite["name"]}</td>
<td>{requisite["device_uuid"]}</td>
<!-- <td class="flex gap-2"> -->
<!-- <a
href={"/admin/user/edit/req/" +
requisite["token"] +
"/" +
requisite["uuid"] +
"_" +
requisite["code"]}
class="btn btn-info">Изменить</a
> -->
<!-- <button class="btn btn-error">Удалить</button> -->
<!-- </td> -->
</tr>
{/each}
</tbody>
</table>
</div>
{/if}
</div>
</div>

View File

@ -1,129 +1,129 @@
<script>
// @ts-nocheck
import { browser } from "$app/environment";
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth.js";
import { makeGet, makePost } from "$lib/tools/requests/requests.js";
import { sayError } from "$lib/tools/toaster/Toaster.js";
import { redirect } from "$lib/tools/url/URLTools.js";
// import { browser } from "$app/environment";
// import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth.js";
// import { makeGet, makePost } from "$lib/tools/requests/requests.js";
// import { sayError } from "$lib/tools/toaster/Toaster.js";
// import { redirect } from "$lib/tools/url/URLTools.js";
export let data;
let { reqID } = data;
let {currency} = data;
let { token } = data;
// export let data;
// let { reqID } = data;
// let { currency } = data;
// let { token } = data;
let reqInfo = [];
let value_bankName;
let value_cardNumber;
let value_phone;
let value_status;
let value_limit;
// let reqInfo = [];
// let value_bankName;
// let value_cardNumber;
// let value_phone;
// let value_status;
// let value_limit;
let canChange = false;
// let canChange = false;
$: reqInfo, bindValues();
$: value_cardNumber, value_phone, value_status, checkFields();
// $: reqInfo, bindValues();
// $: value_cardNumber, value_phone, value_status, checkFields();
function bindValues() {
value_bankName = reqInfo[0]?.bank_name;
value_cardNumber = reqInfo[0]?.cardnumber;
value_phone = reqInfo[0]?.phone;
value_status = reqInfo[0]?.status === "t";
value_limit = Number(reqInfo[0]?.daily_volume_limit);
value_bankName = reqInfo[0]?.bank_id;
}
// function bindValues() {
// value_bankName = reqInfo[0]?.bank_name;
// value_cardNumber = reqInfo[0]?.cardnumber;
// value_phone = reqInfo[0]?.phone;
// value_status = reqInfo[0]?.status === "t";
// value_limit = Number(reqInfo[0]?.daily_volume_limit);
// value_bankName = reqInfo[0]?.bank_id;
// }
function checkFields() {
if (value_cardNumber?.length !== 16) {
canChange = false;
return;
}
if (value_phone?.length < 6) {
canChange = false;
return;
}
if (value_limit < 0) {
canChange = false;
return;
}
// function checkFields() {
// if (value_cardNumber?.length !== 16) {
// canChange = false;
// return;
// }
// if (value_phone?.length < 6) {
// canChange = false;
// return;
// }
// if (value_limit < 0) {
// canChange = false;
// return;
// }
canChange = true;
}
async function getReqInfo() {
const result = await makePost(
"getRequisite",
{
token: token,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
// window.location.href = "/";
redirect("/admin/");
return;
}
if (result.error) {
sayError("Не удалось получить реквизиты пользователя");
return;
}
console.log(result.data);
reqInfo = result.data.filter((s) => s.id === reqID);
}
async function changeRequisite() {
//changeRequisite
canChange = false;
const result = await makePost(
"changeRequisite",
{
...reqInfo[0],
bankname: value_bankName,
cardnumber: value_cardNumber,
phone: value_phone,
status: value_status ? "true" : "false",
limit: value_limit.toString(),
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (result.status === 401) {
sayError("Данные авторизации устарели");
// window.location.href = "/";
redirect("/admin/");
// canChange = true;
return;
}
if (result.error) {
sayError("Не удалось изменить реквизит пользователя");
canChange = true;
return;
}
document.getElementById("ref")?.click();
// }
// async function getReqInfo() {
// const result = await makePost(
// "getRequisite",
// {
// token: token,
// },
// makeAuthHeaderForAxios(getAuthInfo()?.a)
// );
// if (result.status === 401) {
// sayError("Данные авторизации устарели");
// // window.location.href = "/";
// redirect("/admin/");
// return;
// }
// if (result.error) {
// sayError("Не удалось получить реквизиты пользователя");
// return;
// }
// console.log(result.data, reqID);
// reqInfo = result.data.filter((s) => s.uuid === reqID);
// }
// async function changeRequisite() {
// //changeRequisite
// canChange = false;
// const result = await makePost(
// "changeRequisite",
// {
// ...reqInfo[0],
// bankname: value_bankName,
// cardnumber: value_cardNumber,
// phone: value_phone,
// status: value_status ? "true" : "false",
// limit: value_limit.toString(),
// },
// makeAuthHeaderForAxios(getAuthInfo()?.a)
// );
// if (result.status === 401) {
// sayError("Данные авторизации устарели");
// // window.location.href = "/";
// redirect("/admin/");
// // canChange = true;
// return;
// }
// if (result.error) {
// sayError("Не удалось изменить реквизит пользователя");
// canChange = true;
}
// return;
// }
// document.getElementById("ref")?.click();
// // canChange = true;
// }
let activeBanks = [];
async function getActiveBanks() {
let res = await makeGet(
"client/banksList",
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (res.error) {
sayError("Не удалось получить банки. Ошибка #4143");
} else {
console.log(res.data);
activeBanks = res.data;
}
}
// let activeBanks = [];
// async function getActiveBanks() {
// let res = await makeGet(
// "client/banksList",
// makeAuthHeaderForAxios(getAuthInfo()?.a)
// );
// if (res.error) {
// sayError("Не удалось получить банки. Ошибка #4143");
// } else {
// console.log(res.data);
// activeBanks = res.data;
// }
// }
if (browser) {
getReqInfo();
getActiveBanks();
}
// if (browser) {
// getReqInfo();
// getActiveBanks();
// }
</script>
<div class="w-full flex flex-col gap-8">
<!-- <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">Изменение реквизита (ID: {reqID})</h1>
@ -138,9 +138,6 @@
{#each activeBanks as bank}
<option value={bank.id}>{bank.name}</option>
{/each}
<!-- <option value="sber">Сбер</option> -->
<!-- <option value="2">Модератор</option>
<option value="4">Администратор</option> -->
</select>
<label class="input input-bordered flex items-center gap-2">
Номер карты
@ -176,4 +173,4 @@
<a href={"/admin/user/profile/" + token} class="hidden" id="ref"></a>
{/each}
</div>
</div>
</div> -->

View File

@ -330,7 +330,7 @@
</div>
</div>
<div class="flex items-center gap-4">
<!-- <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>
@ -352,7 +352,6 @@
<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>
@ -366,7 +365,6 @@
<th>Объем {userData.code}</th>
<th>Лимит {userData.code}</th>
<th>Опции</th>
<!-- <th></th> -->
</tr>
</thead>
<tbody>
@ -401,7 +399,7 @@
</tbody>
</table>
</div>
</div>
</div> -->
<!-- <div class="flex gap-4">
<div class="bg-accent rounded-[4px] w-[10px] h-full"></div>

View File

@ -5,32 +5,66 @@
getAuthInfo,
makeAuthHeaderForAxios,
} from "$lib/auth/Auth";
import { makeGet } from "$lib/tools/requests/requests";
import { makeGet, makePost } from "$lib/tools/requests/requests";
import { toValidNumberFormat } from "$lib/tools/strings/Strings";
import { sayError } from "$lib/tools/toaster/Toaster";
import { redirect } from "$lib/tools/url/URLTools";
import Pagination from "$lib/ui-components/pagination.svelte";
let users = [];
let usersReady = false;
let searchValue = "";
let showLoadingFind = false;
let maxPage = 1;
let currentPage = 1;
let selectedCur = "";
async function getUsers() {
if (showLoadingFind) return;
showLoadingFind = true;
if (checkAuthSync()) {
const result = await makeGet(
const result = await makePost(
"getUsers",
{
...(searchValue !== "" ? { search_data: searchValue } : {}),
...(selectedCur === "" ? {} : { currency: selectedCur }),
page: currentPage,
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
users = result.data;
users = result.data.data ?? [];
console.log(result);
usersReady = true;
maxPage = Number(result.data.pages);
showLoadingFind = false;
// console.log(result);
} else {
sayError("Данные авторизации устарели");
// window.location.href = "/";
redirect("/admin/");
showLoadingFind = false;
return;
}
}
let currencies = [];
async function getCurrencies() {
const res = await makeGet(
"admin/getCurrencies",
// @ts-ignore
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
res.data.forEach((e) => {
currencies = [...currencies, e.code];
});
console.log(currencies);
}
if (browser) {
getCurrencies();
getUsers();
}
</script>
@ -40,9 +74,51 @@
<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="grid grid-cols-2 gap-4">
<input
bind:value={searchValue}
placeholder="Поиск..."
type="text"
class="input input-bordered"
/>
<select bind:value={selectedCur} class="select select-bordered">
<option value="">Все валюты</option>
{#each currencies as c}
<option value={c}>{c}</option>
{/each}
</select>
</div>
<button
on:click={() => {
maxPage = 1;
currentPage = 1;
getUsers();
}}
class="btn btn-outline mt-2"
>
{#if showLoadingFind}
<span class="loading loading-dots loading-xs"></span>
{:else}
{"Применить"}
{/if}
</button>
<div class="w-full flex flex-col justify-center items-center">
<Pagination
totalPages={maxPage}
pageChangedCallback={(n) => {
currentPage = n;
getUsers();
}}
disableButtons={false}
css={"btn-neutral mt-2"}
/>
<p class="opacity-50 text-xs mt-1">Всего страниц: {maxPage}</p>
</div>
</div>
<div class="w-full flex flex-col p-4 rounded-box bg-base-300">
<div class="overflow-x-auto">
{#if usersReady}
{#if usersReady && !showLoadingFind}
<table class="table">
<!-- head -->
<thead>
@ -59,7 +135,10 @@
<tr class="hover:bg-neutral group">
<th class="font-normal">{user["token"]}</th>
<td class="font-semibold">{user["name"]} {user["surname"]}</td>
<td>{toValidNumberFormat(user["balance"])} {user["code"]}</td>
<td
>{toValidNumberFormat(user["total_balance"])}
{user["code"]}</td
>
<td>
<a
href={"/admin/user/profile/" + user["token"]}

View File

@ -37,6 +37,7 @@ const config = {
"/sms",
"/withdrawals",
"/refs",
"/req",
],
},
},