fixed number formats, added rollback new endpoint

This commit is contained in:
FIRST_NAME LAST_NAME 2025-04-06 12:29:45 +03:00
parent efced51852
commit 31e5c04e0e
9 changed files with 130 additions and 57 deletions

View File

@ -22,7 +22,7 @@ function defaultDataResponseProcessor(data) {
export const API_PATH_MAIN = "https://hostapay.trade/api/v1/";
export const API_PATH_TEST = "https://test.0x000f.ru/api/v1/";
export const API_PATH_VALUE = API_PATH_MAIN;
export const API_PATH_VALUE = API_PATH_TEST;
async function makePost(
url,

View File

@ -1,23 +1,40 @@
export function isStringEmptyOrSpaces(str) {
if (typeof str === "string") return str == null || str?.trim() === "";
else if (typeof str === "object") {
if (Array.isArray(str)) {
for (const i of str) {
if (i == null || i?.trim() === "") return true;
}
}
if (typeof str === "string") return str == null || str?.trim() === "";
else if (typeof str === "object") {
if (Array.isArray(str)) {
for (const i of str) {
if (i == null || i?.trim() === "") return true;
}
}
return false;
}
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; // Соединяем с "..."
}
if (str.length <= 2 * n) {
return str; // Если длина строки меньше или равна 2n, то ничего не обрезаем
}
const leftPart = str.slice(0, n); // Первые n символов
const rightPart = str.slice(-n); // Последние n символов
return leftPart + "..." + rightPart; // Соединяем с "..."
}
/**
*
* @param {string | number} number
* @returns
*/
export function toValidNumberFormat(number) {
if (isNaN(Number(number))) {
return "0.00";
}
return Number(number)
.toLocaleString("ru-RU", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
.replace(/,/g, ".");
}

View File

@ -10,6 +10,7 @@
import Pagination from "$lib/ui-components/pagination.svelte";
import { redirect } from "$lib/tools/url/URLTools";
import axios from "axios";
import { toValidNumberFormat } from "$lib/tools/strings/Strings";
const disputesStatusMap = {
"4": "Требует проверки",
@ -261,7 +262,7 @@
<td>{dispute["requisite_cardnumber"]}</td>
<td>{dispute["requisite_phone"]}</td>
<!-- <td>{dispute["order_rate"]}</td> -->
<td>{dispute["amount"]}</td>
<td>{toValidNumberFormat(dispute["amount"])}</td>
<td>{dispute["order_creationtime"]}</td>
<td
on:click={() => {
@ -312,14 +313,14 @@
<div class="rounded-box flex flex-col bg-base-100 p-4 gap-1 mt-4">
<p class="text-lg font-bold">Сумма в споре</p>
<p>
{Number(selectedDispute.new_amount)}
{toValidNumberFormat(selectedDispute.new_amount)}
{selectedDispute.out_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">Сумма в заявке</p>
<p>
{Number(selectedDispute.amount)}
{toValidNumberFormat(selectedDispute.amount)}
{selectedDispute.out_code}
</p>
</div>

View File

@ -24,7 +24,7 @@
totpValid = true;
showLoadingSpinner = true;
const result = await makePost("client/login", {
user_token: input_token.value,
user_token: input_token.value.trim(),
totp: input_totp.value,
});
if (result.error) {

View File

@ -7,7 +7,10 @@
import Pagination from "$lib/ui-components/pagination.svelte";
import { redirect } from "$lib/tools/url/URLTools";
import axios from "axios";
import { isStringEmptyOrSpaces } from "$lib/tools/strings/Strings";
import {
isStringEmptyOrSpaces,
toValidNumberFormat,
} from "$lib/tools/strings/Strings";
import {
ChevronLeftIcon,
ChevronRightIcon,
@ -299,7 +302,7 @@
<td class="font-semibold">{merch["code"]}</td>
<td>{merch["is_active"] === "t" ? "Активен" : "Отключен"}</td>
<td
>{merch["balance"]}
>{toValidNumberFormat(merch["balance"])}
{merch["balance_type"] === "0" ? "USDT" : merch["code"]}</td
>
<!-- <td>{merch["balance_type"] === "0" ? "crypto":"fiat"}</td> -->
@ -423,10 +426,10 @@
{settle["code"]}
</td>
<td>
{settle["amount"]} USDT
{toValidNumberFormat(settle["amount"])} USDT
</td>
<td>
{settle["merchant_amount"]} USDT
{toValidNumberFormat(settle["merchant_amount"])} USDT
</td>
<td class="">
<p>{settle["settle_address"]}</p>

View File

@ -3,6 +3,7 @@
import { getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import { makePost } from "$lib/tools/requests/requests";
import { toValidNumberFormat } from "$lib/tools/strings/Strings";
import { sayError, sayInfo } from "$lib/tools/toaster/Toaster";
const orderStatusMap = {
@ -113,6 +114,29 @@
showChangeSum = false;
showFoundedOrderWindow = false;
}
async function changeSumWithoutBalance(uuid) {
showLoadingChangeSum = true;
const res = await makePost(
"admin/rollbackOrderWithoutBalance",
{
id: uuid,
summa: newSum.toString(),
},
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
if (res.error) {
if (res.status == 401) {
sayError("Данные авторизации устарели!");
}
sayError("Не удалось изменить сумму");
showLoadingChangeSum = false;
return;
}
sayInfo("Сумма успешно изменена!");
showLoadingChangeSum = false;
showChangeSum = false;
showFoundedOrderWindow = false;
}
</script>
<div class="w-full flex flex-col gap-8">
@ -182,7 +206,7 @@
{/if}
<p class="text-sm mt-3">Сумма</p>
<p>
{foundedDispute["summa"]}
{toValidNumberFormat(foundedDispute["summa"])}
{foundedDispute["currency_code"]}
<!-- ({(
Number(foundedDispute["summa"]) / Number(foundedDispute["rate"])
@ -241,7 +265,7 @@
<div
class="fixed inset-0 z-[1001] bg-black bg-opacity-50 flex justify-center items-center"
>
<div class="flex flex-col p-4 bg-base-100 rounded-md">
<div class="flex flex-col p-4 bg-base-100 rounded-md gap-1">
<p>Укажите новую сумму ({foundedDispute["currency_code"]})</p>
<input
bind:value={newSum}
@ -260,6 +284,18 @@
{"Изменить сумму ручками"}
{/if}
</button>
<button
on:click={() => {
changeSumWithoutBalance(foundedDispute["uuid"]);
}}
class="btn btn-outline btn-info"
>
{#if showLoadingChangeSum}
<span class="loading loading-dots loading-xs"></span>
{:else}
{"Изменить сумму ручками (без списания баланса)"}
{/if}
</button>
<button
on:click={() => {
showChangeSum = false;

View File

@ -12,7 +12,10 @@
import Pagination from "$lib/ui-components/pagination.svelte";
import { redirect } from "$lib/tools/url/URLTools";
import axios from "axios";
import { isStringEmptyOrSpaces } from "$lib/tools/strings/Strings";
import {
isStringEmptyOrSpaces,
toValidNumberFormat,
} from "$lib/tools/strings/Strings";
import { CopyIcon, SearchIcon, XCircleIcon } from "svelte-feather-icons";
const payoutsStatusMap = {
@ -566,7 +569,8 @@
>{payoutsStatusMap[payout["status"]]}</td
>
<!-- <td>{payout["is_sbp"] === "t" ? "да" : "нет"}</td> -->
<td>{payout["amount"]} {payout["code"]}</td>
<td>{toValidNumberFormat(payout["amount"])} {payout["code"]}</td
>
<td>{payout["pan"]}</td>
<!-- <td>{payout["rate"]} {payout["code"]}</td> -->
<!-- <td>{payout["amount"]}</td> -->
@ -626,7 +630,7 @@
<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.amount}
{toValidNumberFormat(selectedPayout.amount)}
{selectedPayout.code}
</p>
</div>

View File

@ -2,6 +2,7 @@
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 Pagination from "$lib/ui-components/pagination.svelte";
@ -212,7 +213,10 @@
</div>
<div class="flex gap-2 p-2 items-center text-lg">
<p class="font-bold">Баланс:</p>
<p class="text-info">{Number(userData.balance)} {userData?.code}</p>
<p class="text-info">
{toValidNumberFormat(userData.balance)}
{userData?.code}
</p>
</div>
<div class="flex gap-2 p-2 items-center text-lg">
<p class="font-bold">Страховка:</p>
@ -315,8 +319,8 @@
<td>{requisite["phone"]}</td>
<td>{requisite["name"]}</td>
<td>{requisite["device_uuid"]}</td>
<td>{requisite["total_volume"]}</td>
<td>{requisite["daily_volume_limit"]}</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/" +
@ -401,7 +405,7 @@
<td class="font-semibold">{order["uuid"]}</td>
<td class="font-semibold">{order["external_user_id"]}</td>
<td class="">{order["status"]}</td>
<td>{order["summa"]} {userData?.code}</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> -->
@ -457,7 +461,7 @@
{#each userDeposits as depo}
<tr class="hover:bg-neutral group">
<td class="">{depoStatusMap[depo["pending"]]}</td>
<td>{Number(depo["amount"]).toFixed(4)} USDT</td>
<td>{toValidNumberFormat(depo["amount"])} USDT</td>
<td>{depo["creationtime"]}</td>
<!-- <td class="flex gap-2">
<a href="" class="btn btn-info">Изменить</a>

View File

@ -1,7 +1,12 @@
<script>
import { browser } from "$app/environment";
import { checkAuthSync, getAuthInfo, makeAuthHeaderForAxios } from "$lib/auth/Auth";
import {
checkAuthSync,
getAuthInfo,
makeAuthHeaderForAxios,
} from "$lib/auth/Auth";
import { makeGet } 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";
@ -9,15 +14,15 @@
let usersReady = false;
async function getUsers() {
if(checkAuthSync())
{
const result = await makeGet("getUsers", makeAuthHeaderForAxios(getAuthInfo()?.a));
users = result.data;
usersReady = true;
// console.log(result);
}
else
{
if (checkAuthSync()) {
const result = await makeGet(
"getUsers",
makeAuthHeaderForAxios(getAuthInfo()?.a)
);
users = result.data;
usersReady = true;
// console.log(result);
} else {
sayError("Данные авторизации устарели");
// window.location.href = "/";
redirect("/admin/");
@ -25,8 +30,7 @@
}
}
if(browser)
{
if (browser) {
getUsers();
}
</script>
@ -51,23 +55,27 @@
</thead>
<tbody>
<!-- row 1 -->
{#each users as user}
<tr class="hover:bg-neutral group">
{#each users as user}
<tr class="hover:bg-neutral group">
<th class="font-normal">{user["token"]}</th>
<td class="font-semibold">{user["name"]} {user["surname"]}</td>
<td>{(Number(user["balance"]))} {user["code"]}</td>
<td>{toValidNumberFormat(user["balance"])} {user["code"]}</td>
<td>
<a href={"/admin/user/profile/"+user["token"]} class="btn btn-outline btn-info group-hover:btn-warning">Профиль</a>
<a
href={"/admin/user/profile/" + user["token"]}
class="btn btn-outline btn-info group-hover:btn-warning"
>Профиль</a
>
</td>
</tr>
{/each}
{/each}
</tbody>
</table>
{:else}
{:else}
<div class="flex p-4 w-full justify-center items-center">
<span class="loading loading-spinner"></span>
</div>
{/if}
</div>
{/if}
</div>
</div>
</div>