经理中心
This commit is contained in:
parent
12ebb29f02
commit
d82aec3805
@ -1,21 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<title>经理中心</title>
|
||||
<link rel="stylesheet" href="./style.css?v=20260511-0102" />
|
||||
<title>Manager Center</title>
|
||||
<link rel="stylesheet" href="./style.css?v=20260511-0107" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="manager-center" data-loading="true">
|
||||
<div class="manager-center" aria-label="Manager Center" data-i18n-aria="page_label" data-loading="true">
|
||||
<nav class="title-bar">
|
||||
<button class="back-button" type="button" aria-label="返回">
|
||||
<button class="back-button" type="button" aria-label="Back" data-i18n-aria="back">
|
||||
<svg viewBox="0 0 32 32" aria-hidden="true">
|
||||
<path d="M20 8 12 16l8 8" />
|
||||
</svg>
|
||||
</button>
|
||||
<h1>经理中心</h1>
|
||||
<span class="title-spacer" aria-hidden="true"></span>
|
||||
<h1 data-i18n="title">Manager Center</h1>
|
||||
<div class="language-switcher">
|
||||
<button class="language-button" type="button" aria-label="Change language" data-i18n-aria="language_button_aria" aria-expanded="false">EN</button>
|
||||
<div class="language-menu" hidden>
|
||||
<button type="button" data-lang="en">EN</button>
|
||||
<button type="button" data-lang="ar">AR</button>
|
||||
<button type="button" data-lang="tr">TR</button>
|
||||
<button type="button" data-lang="id">ID</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="content">
|
||||
@ -25,7 +33,7 @@
|
||||
<span id="managerAvatarFallback">M</span>
|
||||
</div>
|
||||
<div class="profile-copy">
|
||||
<div class="eyebrow">当前经理</div>
|
||||
<div class="eyebrow" data-i18n="current_manager">Current Manager</div>
|
||||
<div class="name" id="managerName">-</div>
|
||||
<div class="meta" id="managerUid">UID: -</div>
|
||||
</div>
|
||||
@ -33,11 +41,11 @@
|
||||
|
||||
<section class="card search-card">
|
||||
<div class="section-head">
|
||||
<h2>用户</h2>
|
||||
<h2 data-i18n="user">User</h2>
|
||||
</div>
|
||||
<form class="search-form" id="searchForm" autocomplete="off">
|
||||
<input id="accountInput" type="text" inputmode="text" placeholder="输入用户 ID 或账号" />
|
||||
<button id="searchButton" type="submit">搜索</button>
|
||||
<input id="accountInput" type="text" inputmode="text" placeholder="Enter user ID or account" data-i18n-placeholder="user_search_placeholder" />
|
||||
<button id="searchButton" type="submit" data-i18n="search">Search</button>
|
||||
</form>
|
||||
<div class="form-status" id="searchStatus" role="status" hidden></div>
|
||||
</section>
|
||||
@ -48,50 +56,64 @@
|
||||
<span id="targetAvatarFallback">U</span>
|
||||
</div>
|
||||
<div class="profile-copy">
|
||||
<div class="eyebrow">目标用户</div>
|
||||
<div class="eyebrow" data-i18n="target_user">Target User</div>
|
||||
<div class="name" id="targetName">-</div>
|
||||
<div class="meta" id="targetUid">UID: -</div>
|
||||
<div class="pill-row">
|
||||
<span class="status-pill" id="targetAccountStatus">-</span>
|
||||
<span class="status-pill" id="targetRechargeStatus">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card gift-card">
|
||||
<div class="section-head">
|
||||
<h2>赠送道具</h2>
|
||||
<h2 data-i18n="gift_props">Gift Props</h2>
|
||||
</div>
|
||||
<label class="field-label" id="propsTypeLabelText" data-i18n="gift_type">Gift Type</label>
|
||||
<div class="custom-select" id="propsTypeSelect" data-value="RIDE">
|
||||
<button
|
||||
class="custom-select-button"
|
||||
id="propsTypeButton"
|
||||
type="button"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="listbox"
|
||||
aria-labelledby="propsTypeLabelText propsTypeSelectedLabel"
|
||||
>
|
||||
<span id="propsTypeSelectedLabel">Ride</span>
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="m7 9 5 5 5-5" />
|
||||
</svg>
|
||||
</button>
|
||||
<div class="custom-select-menu" id="propsTypeMenu" role="listbox" aria-labelledby="propsTypeLabelText" hidden>
|
||||
<button type="button" role="option" data-value="RIDE" data-i18n="prop_type_ride">Ride</button>
|
||||
<button type="button" role="option" data-value="NOBLE_VIP" data-i18n="prop_type_noble_vip">Noble VIP</button>
|
||||
<button type="button" role="option" data-value="AVATAR_FRAME" data-i18n="prop_type_avatar_frame">Avatar Frame</button>
|
||||
<button type="button" role="option" data-value="CHAT_BUBBLE" data-i18n="prop_type_chat_bubble">Chat Bubble</button>
|
||||
<button type="button" role="option" data-value="DATA_CARD" data-i18n="prop_type_data_card">Profile Card</button>
|
||||
</div>
|
||||
</div>
|
||||
<label class="field-label" for="propsTypeSelect">礼物类型</label>
|
||||
<select id="propsTypeSelect">
|
||||
<option value="RIDE">座驾</option>
|
||||
<option value="NOBLE_VIP">贵族</option>
|
||||
<option value="AVATAR_FRAME">头像框</option>
|
||||
<option value="CHAT_BUBBLE">聊天气泡</option>
|
||||
<option value="DATA_CARD">资料卡</option>
|
||||
</select>
|
||||
<div class="props-status" id="propsStatus" role="status" hidden></div>
|
||||
<div class="props-list" id="propsList"></div>
|
||||
<button class="primary-action" id="sendPropsButton" type="button" disabled>赠送</button>
|
||||
<button class="primary-action" id="sendPropsButton" type="button" disabled data-i18n="send">Send</button>
|
||||
</section>
|
||||
|
||||
<section class="card ban-card" id="banCard" hidden>
|
||||
<div class="section-head">
|
||||
<h2>封禁用户</h2>
|
||||
<h2 data-i18n="ban_user">Ban User</h2>
|
||||
<span class="danger-chip" id="banEligibility">-</span>
|
||||
</div>
|
||||
<textarea id="banReason" maxlength="200" rows="3" placeholder="封禁原因"></textarea>
|
||||
<button class="danger-action" id="banButton" type="button" disabled>封禁</button>
|
||||
<textarea id="banReason" maxlength="200" rows="3" placeholder="Ban reason" data-i18n-placeholder="ban_reason"></textarea>
|
||||
<button class="danger-action" id="banButton" type="button" disabled data-i18n="ban">Ban</button>
|
||||
<div class="form-status" id="banStatus" role="status" hidden></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div class="loading-mask" id="loadingMask" role="status" aria-live="polite">
|
||||
<div class="loader" aria-hidden="true"></div>
|
||||
<span>加载中...</span>
|
||||
<span data-i18n="loading">Loading...</span>
|
||||
</div>
|
||||
<div class="toast" id="toast" role="status" hidden></div>
|
||||
</div>
|
||||
<script src="./script.js?v=20260511-0104" defer></script>
|
||||
<script src="./script.js?v=20260511-0108" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
47
h5/hyapp/manager-center/locales/ar.json
Normal file
47
h5/hyapp/manager-center/locales/ar.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"document_title": "مركز المدير",
|
||||
"page_label": "مركز المدير",
|
||||
"back": "رجوع",
|
||||
"title": "مركز المدير",
|
||||
"language_button_aria": "تغيير اللغة",
|
||||
"current_manager": "المدير الحالي",
|
||||
"user": "المستخدم",
|
||||
"user_search_placeholder": "أدخل معرّف المستخدم أو الحساب",
|
||||
"search": "بحث",
|
||||
"searching": "جار البحث...",
|
||||
"target_user": "المستخدم المستهدف",
|
||||
"gift_props": "إرسال العناصر",
|
||||
"gift_type": "نوع الهدية",
|
||||
"prop_type_ride": "مركبة",
|
||||
"prop_type_noble_vip": "VIP نبيل",
|
||||
"prop_type_avatar_frame": "إطار الصورة",
|
||||
"prop_type_chat_bubble": "فقاعة الدردشة",
|
||||
"prop_type_data_card": "بطاقة الملف",
|
||||
"no_giftable_props": "لا توجد عناصر قابلة للإهداء",
|
||||
"send": "إرسال",
|
||||
"sending": "جار الإرسال...",
|
||||
"confirm_send": "هل تريد إرسال هذا العنصر؟",
|
||||
"send_success": "تم الإرسال بنجاح",
|
||||
"ban_user": "حظر المستخدم",
|
||||
"ban_reason": "سبب الحظر",
|
||||
"ban": "حظر",
|
||||
"confirm_ban": "هل تريد حظر هذا المستخدم؟",
|
||||
"submitting": "جار الإرسال...",
|
||||
"ban_success": "تم حظر المستخدم",
|
||||
"loading": "جار التحميل...",
|
||||
"uid_label": "UID",
|
||||
"days": "{count} يوم",
|
||||
"recharged": "تم الشحن",
|
||||
"not_recharged": "لم يتم الشحن",
|
||||
"recharge_unknown": "حالة الشحن غير معروفة",
|
||||
"can_ban": "يمكن الحظر",
|
||||
"cannot_ban": "لا يمكن الحظر",
|
||||
"missing_token": "رمز الدخول مفقود",
|
||||
"not_manager": "الحساب الحالي ليس مديرًا",
|
||||
"user_not_found": "المستخدم غير موجود",
|
||||
"user_recharged": "لدى هذا المستخدم سجلات شحن ولا يمكن حظره",
|
||||
"prop_not_giftable": "هذا العنصر غير متاح كهديّة من المدير",
|
||||
"vip_not_giftable": "لا يمكن إهداء عنصر VIP هذا",
|
||||
"request_failed": "فشل الطلب",
|
||||
"enter_user": "أدخل معرّف المستخدم أو الحساب"
|
||||
}
|
||||
47
h5/hyapp/manager-center/locales/en.json
Normal file
47
h5/hyapp/manager-center/locales/en.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"document_title": "Manager Center",
|
||||
"page_label": "Manager Center",
|
||||
"back": "Back",
|
||||
"title": "Manager Center",
|
||||
"language_button_aria": "Change language",
|
||||
"current_manager": "Current Manager",
|
||||
"user": "User",
|
||||
"user_search_placeholder": "Enter user ID or account",
|
||||
"search": "Search",
|
||||
"searching": "Searching...",
|
||||
"target_user": "Target User",
|
||||
"gift_props": "Gift Props",
|
||||
"gift_type": "Gift Type",
|
||||
"prop_type_ride": "Ride",
|
||||
"prop_type_noble_vip": "Noble VIP",
|
||||
"prop_type_avatar_frame": "Avatar Frame",
|
||||
"prop_type_chat_bubble": "Chat Bubble",
|
||||
"prop_type_data_card": "Profile Card",
|
||||
"no_giftable_props": "No giftable props",
|
||||
"send": "Send",
|
||||
"sending": "Sending...",
|
||||
"confirm_send": "Send this prop?",
|
||||
"send_success": "Sent successfully",
|
||||
"ban_user": "Ban User",
|
||||
"ban_reason": "Ban reason",
|
||||
"ban": "Ban",
|
||||
"confirm_ban": "Ban this user?",
|
||||
"submitting": "Submitting...",
|
||||
"ban_success": "User banned",
|
||||
"loading": "Loading...",
|
||||
"uid_label": "UID",
|
||||
"days": "{count} days",
|
||||
"recharged": "Recharged",
|
||||
"not_recharged": "Not recharged",
|
||||
"recharge_unknown": "Recharge unknown",
|
||||
"can_ban": "Can ban",
|
||||
"cannot_ban": "Cannot ban",
|
||||
"missing_token": "Missing token",
|
||||
"not_manager": "Current account is not a manager",
|
||||
"user_not_found": "User not found",
|
||||
"user_recharged": "This user has recharge records and cannot be banned",
|
||||
"prop_not_giftable": "This prop is not available for manager gifting",
|
||||
"vip_not_giftable": "This noble prop cannot be gifted",
|
||||
"request_failed": "Request failed",
|
||||
"enter_user": "Enter user ID or account"
|
||||
}
|
||||
47
h5/hyapp/manager-center/locales/id.json
Normal file
47
h5/hyapp/manager-center/locales/id.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"document_title": "Pusat Manajer",
|
||||
"page_label": "Pusat Manajer",
|
||||
"back": "Kembali",
|
||||
"title": "Pusat Manajer",
|
||||
"language_button_aria": "Ubah bahasa",
|
||||
"current_manager": "Manajer Saat Ini",
|
||||
"user": "Pengguna",
|
||||
"user_search_placeholder": "Masukkan ID pengguna atau akun",
|
||||
"search": "Cari",
|
||||
"searching": "Mencari...",
|
||||
"target_user": "Pengguna Target",
|
||||
"gift_props": "Kirim Properti",
|
||||
"gift_type": "Jenis Hadiah",
|
||||
"prop_type_ride": "Kendaraan",
|
||||
"prop_type_noble_vip": "Noble VIP",
|
||||
"prop_type_avatar_frame": "Bingkai Avatar",
|
||||
"prop_type_chat_bubble": "Gelembung Chat",
|
||||
"prop_type_data_card": "Kartu Profil",
|
||||
"no_giftable_props": "Tidak ada properti yang dapat dikirim",
|
||||
"send": "Kirim",
|
||||
"sending": "Mengirim...",
|
||||
"confirm_send": "Kirim properti ini?",
|
||||
"send_success": "Berhasil dikirim",
|
||||
"ban_user": "Blokir Pengguna",
|
||||
"ban_reason": "Alasan blokir",
|
||||
"ban": "Blokir",
|
||||
"confirm_ban": "Blokir pengguna ini?",
|
||||
"submitting": "Mengirim...",
|
||||
"ban_success": "Pengguna diblokir",
|
||||
"loading": "Memuat...",
|
||||
"uid_label": "UID",
|
||||
"days": "{count} hari",
|
||||
"recharged": "Sudah isi ulang",
|
||||
"not_recharged": "Belum isi ulang",
|
||||
"recharge_unknown": "Status isi ulang tidak diketahui",
|
||||
"can_ban": "Dapat diblokir",
|
||||
"cannot_ban": "Tidak dapat diblokir",
|
||||
"missing_token": "Token tidak ditemukan",
|
||||
"not_manager": "Akun saat ini bukan manajer",
|
||||
"user_not_found": "Pengguna tidak ditemukan",
|
||||
"user_recharged": "Pengguna ini memiliki riwayat isi ulang dan tidak dapat diblokir",
|
||||
"prop_not_giftable": "Properti ini tidak tersedia untuk hadiah manajer",
|
||||
"vip_not_giftable": "Properti noble ini tidak dapat dikirim",
|
||||
"request_failed": "Permintaan gagal",
|
||||
"enter_user": "Masukkan ID pengguna atau akun"
|
||||
}
|
||||
47
h5/hyapp/manager-center/locales/tr.json
Normal file
47
h5/hyapp/manager-center/locales/tr.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"document_title": "Yönetici Merkezi",
|
||||
"page_label": "Yönetici Merkezi",
|
||||
"back": "Geri",
|
||||
"title": "Yönetici Merkezi",
|
||||
"language_button_aria": "Dili değiştir",
|
||||
"current_manager": "Mevcut Yönetici",
|
||||
"user": "Kullanıcı",
|
||||
"user_search_placeholder": "Kullanıcı ID veya hesap gir",
|
||||
"search": "Ara",
|
||||
"searching": "Aranıyor...",
|
||||
"target_user": "Hedef Kullanıcı",
|
||||
"gift_props": "Eşya Gönder",
|
||||
"gift_type": "Hediye Türü",
|
||||
"prop_type_ride": "Araç",
|
||||
"prop_type_noble_vip": "Noble VIP",
|
||||
"prop_type_avatar_frame": "Avatar Çerçevesi",
|
||||
"prop_type_chat_bubble": "Sohbet Balonu",
|
||||
"prop_type_data_card": "Profil Kartı",
|
||||
"no_giftable_props": "Gönderilebilir eşya yok",
|
||||
"send": "Gönder",
|
||||
"sending": "Gönderiliyor...",
|
||||
"confirm_send": "Bu eşyayı göndermek istiyor musun?",
|
||||
"send_success": "Başarıyla gönderildi",
|
||||
"ban_user": "Kullanıcıyı Yasakla",
|
||||
"ban_reason": "Yasaklama nedeni",
|
||||
"ban": "Yasakla",
|
||||
"confirm_ban": "Bu kullanıcıyı yasaklamak istiyor musun?",
|
||||
"submitting": "Gönderiliyor...",
|
||||
"ban_success": "Kullanıcı yasaklandı",
|
||||
"loading": "Yükleniyor...",
|
||||
"uid_label": "UID",
|
||||
"days": "{count} gün",
|
||||
"recharged": "Yükleme yaptı",
|
||||
"not_recharged": "Yükleme yapmadı",
|
||||
"recharge_unknown": "Yükleme durumu bilinmiyor",
|
||||
"can_ban": "Yasaklanabilir",
|
||||
"cannot_ban": "Yasaklanamaz",
|
||||
"missing_token": "Token eksik",
|
||||
"not_manager": "Mevcut hesap yönetici değil",
|
||||
"user_not_found": "Kullanıcı bulunamadı",
|
||||
"user_recharged": "Bu kullanıcının yükleme kaydı var, yasaklanamaz",
|
||||
"prop_not_giftable": "Bu eşya yönetici hediyesi için açık değil",
|
||||
"vip_not_giftable": "Bu noble eşyası gönderilemez",
|
||||
"request_failed": "İstek başarısız",
|
||||
"enter_user": "Kullanıcı ID veya hesap gir"
|
||||
}
|
||||
@ -1,9 +1,207 @@
|
||||
(function () {
|
||||
const supportedLanguages = ["en", "ar", "tr", "id"];
|
||||
const languageLabels = {
|
||||
en: "EN",
|
||||
ar: "AR",
|
||||
tr: "TR",
|
||||
id: "ID"
|
||||
};
|
||||
const API_BASE_URL = "https://jvapi.haiyihy.com";
|
||||
const GO_API_PATH_PREFIX = "/go";
|
||||
const LOCAL_GO_API_BASE_URL = "http://127.0.0.1:1100";
|
||||
const defaultPropsType = "RIDE";
|
||||
|
||||
const fallbackMessages = {
|
||||
en: {
|
||||
document_title: "Manager Center",
|
||||
page_label: "Manager Center",
|
||||
back: "Back",
|
||||
title: "Manager Center",
|
||||
language_button_aria: "Change language",
|
||||
current_manager: "Current Manager",
|
||||
user: "User",
|
||||
user_search_placeholder: "Enter user ID or account",
|
||||
search: "Search",
|
||||
searching: "Searching...",
|
||||
target_user: "Target User",
|
||||
gift_props: "Gift Props",
|
||||
gift_type: "Gift Type",
|
||||
prop_type_ride: "Ride",
|
||||
prop_type_noble_vip: "Noble VIP",
|
||||
prop_type_avatar_frame: "Avatar Frame",
|
||||
prop_type_chat_bubble: "Chat Bubble",
|
||||
prop_type_data_card: "Profile Card",
|
||||
no_giftable_props: "No giftable props",
|
||||
send: "Send",
|
||||
sending: "Sending...",
|
||||
confirm_send: "Send this prop?",
|
||||
send_success: "Sent successfully",
|
||||
ban_user: "Ban User",
|
||||
ban_reason: "Ban reason",
|
||||
ban: "Ban",
|
||||
confirm_ban: "Ban this user?",
|
||||
submitting: "Submitting...",
|
||||
ban_success: "User banned",
|
||||
loading: "Loading...",
|
||||
uid_label: "UID",
|
||||
days: "{count} days",
|
||||
recharged: "Recharged",
|
||||
not_recharged: "Not recharged",
|
||||
recharge_unknown: "Recharge unknown",
|
||||
can_ban: "Can ban",
|
||||
cannot_ban: "Cannot ban",
|
||||
missing_token: "Missing token",
|
||||
not_manager: "Current account is not a manager",
|
||||
user_not_found: "User not found",
|
||||
user_recharged: "This user has recharge records and cannot be banned",
|
||||
prop_not_giftable: "This prop is not available for manager gifting",
|
||||
vip_not_giftable: "This noble prop cannot be gifted",
|
||||
request_failed: "Request failed",
|
||||
enter_user: "Enter user ID or account"
|
||||
},
|
||||
ar: {
|
||||
document_title: "مركز المدير",
|
||||
page_label: "مركز المدير",
|
||||
back: "رجوع",
|
||||
title: "مركز المدير",
|
||||
language_button_aria: "تغيير اللغة",
|
||||
current_manager: "المدير الحالي",
|
||||
user: "المستخدم",
|
||||
user_search_placeholder: "أدخل معرّف المستخدم أو الحساب",
|
||||
search: "بحث",
|
||||
searching: "جار البحث...",
|
||||
target_user: "المستخدم المستهدف",
|
||||
gift_props: "إرسال العناصر",
|
||||
gift_type: "نوع الهدية",
|
||||
prop_type_ride: "مركبة",
|
||||
prop_type_noble_vip: "VIP نبيل",
|
||||
prop_type_avatar_frame: "إطار الصورة",
|
||||
prop_type_chat_bubble: "فقاعة الدردشة",
|
||||
prop_type_data_card: "بطاقة الملف",
|
||||
no_giftable_props: "لا توجد عناصر قابلة للإهداء",
|
||||
send: "إرسال",
|
||||
sending: "جار الإرسال...",
|
||||
confirm_send: "هل تريد إرسال هذا العنصر؟",
|
||||
send_success: "تم الإرسال بنجاح",
|
||||
ban_user: "حظر المستخدم",
|
||||
ban_reason: "سبب الحظر",
|
||||
ban: "حظر",
|
||||
confirm_ban: "هل تريد حظر هذا المستخدم؟",
|
||||
submitting: "جار الإرسال...",
|
||||
ban_success: "تم حظر المستخدم",
|
||||
loading: "جار التحميل...",
|
||||
uid_label: "UID",
|
||||
days: "{count} يوم",
|
||||
recharged: "تم الشحن",
|
||||
not_recharged: "لم يتم الشحن",
|
||||
recharge_unknown: "حالة الشحن غير معروفة",
|
||||
can_ban: "يمكن الحظر",
|
||||
cannot_ban: "لا يمكن الحظر",
|
||||
missing_token: "رمز الدخول مفقود",
|
||||
not_manager: "الحساب الحالي ليس مديرًا",
|
||||
user_not_found: "المستخدم غير موجود",
|
||||
user_recharged: "لدى هذا المستخدم سجلات شحن ولا يمكن حظره",
|
||||
prop_not_giftable: "هذا العنصر غير متاح كهديّة من المدير",
|
||||
vip_not_giftable: "لا يمكن إهداء عنصر VIP هذا",
|
||||
request_failed: "فشل الطلب",
|
||||
enter_user: "أدخل معرّف المستخدم أو الحساب"
|
||||
},
|
||||
tr: {
|
||||
document_title: "Yönetici Merkezi",
|
||||
page_label: "Yönetici Merkezi",
|
||||
back: "Geri",
|
||||
title: "Yönetici Merkezi",
|
||||
language_button_aria: "Dili değiştir",
|
||||
current_manager: "Mevcut Yönetici",
|
||||
user: "Kullanıcı",
|
||||
user_search_placeholder: "Kullanıcı ID veya hesap gir",
|
||||
search: "Ara",
|
||||
searching: "Aranıyor...",
|
||||
target_user: "Hedef Kullanıcı",
|
||||
gift_props: "Eşya Gönder",
|
||||
gift_type: "Hediye Türü",
|
||||
prop_type_ride: "Araç",
|
||||
prop_type_noble_vip: "Noble VIP",
|
||||
prop_type_avatar_frame: "Avatar Çerçevesi",
|
||||
prop_type_chat_bubble: "Sohbet Balonu",
|
||||
prop_type_data_card: "Profil Kartı",
|
||||
no_giftable_props: "Gönderilebilir eşya yok",
|
||||
send: "Gönder",
|
||||
sending: "Gönderiliyor...",
|
||||
confirm_send: "Bu eşyayı göndermek istiyor musun?",
|
||||
send_success: "Başarıyla gönderildi",
|
||||
ban_user: "Kullanıcıyı Yasakla",
|
||||
ban_reason: "Yasaklama nedeni",
|
||||
ban: "Yasakla",
|
||||
confirm_ban: "Bu kullanıcıyı yasaklamak istiyor musun?",
|
||||
submitting: "Gönderiliyor...",
|
||||
ban_success: "Kullanıcı yasaklandı",
|
||||
loading: "Yükleniyor...",
|
||||
uid_label: "UID",
|
||||
days: "{count} gün",
|
||||
recharged: "Yükleme yaptı",
|
||||
not_recharged: "Yükleme yapmadı",
|
||||
recharge_unknown: "Yükleme durumu bilinmiyor",
|
||||
can_ban: "Yasaklanabilir",
|
||||
cannot_ban: "Yasaklanamaz",
|
||||
missing_token: "Token eksik",
|
||||
not_manager: "Mevcut hesap yönetici değil",
|
||||
user_not_found: "Kullanıcı bulunamadı",
|
||||
user_recharged: "Bu kullanıcının yükleme kaydı var, yasaklanamaz",
|
||||
prop_not_giftable: "Bu eşya yönetici hediyesi için açık değil",
|
||||
vip_not_giftable: "Bu noble eşyası gönderilemez",
|
||||
request_failed: "İstek başarısız",
|
||||
enter_user: "Kullanıcı ID veya hesap gir"
|
||||
},
|
||||
id: {
|
||||
document_title: "Pusat Manajer",
|
||||
page_label: "Pusat Manajer",
|
||||
back: "Kembali",
|
||||
title: "Pusat Manajer",
|
||||
language_button_aria: "Ubah bahasa",
|
||||
current_manager: "Manajer Saat Ini",
|
||||
user: "Pengguna",
|
||||
user_search_placeholder: "Masukkan ID pengguna atau akun",
|
||||
search: "Cari",
|
||||
searching: "Mencari...",
|
||||
target_user: "Pengguna Target",
|
||||
gift_props: "Kirim Properti",
|
||||
gift_type: "Jenis Hadiah",
|
||||
prop_type_ride: "Kendaraan",
|
||||
prop_type_noble_vip: "Noble VIP",
|
||||
prop_type_avatar_frame: "Bingkai Avatar",
|
||||
prop_type_chat_bubble: "Gelembung Chat",
|
||||
prop_type_data_card: "Kartu Profil",
|
||||
no_giftable_props: "Tidak ada properti yang dapat dikirim",
|
||||
send: "Kirim",
|
||||
sending: "Mengirim...",
|
||||
confirm_send: "Kirim properti ini?",
|
||||
send_success: "Berhasil dikirim",
|
||||
ban_user: "Blokir Pengguna",
|
||||
ban_reason: "Alasan blokir",
|
||||
ban: "Blokir",
|
||||
confirm_ban: "Blokir pengguna ini?",
|
||||
submitting: "Mengirim...",
|
||||
ban_success: "Pengguna diblokir",
|
||||
loading: "Memuat...",
|
||||
uid_label: "UID",
|
||||
days: "{count} hari",
|
||||
recharged: "Sudah isi ulang",
|
||||
not_recharged: "Belum isi ulang",
|
||||
recharge_unknown: "Status isi ulang tidak diketahui",
|
||||
can_ban: "Dapat diblokir",
|
||||
cannot_ban: "Tidak dapat diblokir",
|
||||
missing_token: "Token tidak ditemukan",
|
||||
not_manager: "Akun saat ini bukan manajer",
|
||||
user_not_found: "Pengguna tidak ditemukan",
|
||||
user_recharged: "Pengguna ini memiliki riwayat isi ulang dan tidak dapat diblokir",
|
||||
prop_not_giftable: "Properti ini tidak tersedia untuk hadiah manajer",
|
||||
vip_not_giftable: "Properti noble ini tidak dapat dikirim",
|
||||
request_failed: "Permintaan gagal",
|
||||
enter_user: "Masukkan ID pengguna atau akun"
|
||||
}
|
||||
};
|
||||
|
||||
const state = {
|
||||
manager: null,
|
||||
target: null,
|
||||
@ -13,6 +211,8 @@
|
||||
};
|
||||
|
||||
const params = readURLParams();
|
||||
let currentLang = normalizeLanguage(params.get("lang"));
|
||||
let currentMessages = fallbackMessages[currentLang] || fallbackMessages.en;
|
||||
|
||||
function readURLParams() {
|
||||
const result = new URLSearchParams(window.location.search);
|
||||
@ -51,6 +251,129 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
function normalizeLanguage(lang) {
|
||||
const value = String(lang || "en").toLowerCase();
|
||||
return supportedLanguages.includes(value) ? value : "en";
|
||||
}
|
||||
|
||||
async function loadMessages(lang) {
|
||||
const normalizedLang = normalizeLanguage(lang);
|
||||
if (window.location.protocol === "file:") return fallbackMessages[normalizedLang];
|
||||
|
||||
try {
|
||||
const response = await fetch(`./locales/${normalizedLang}.json?v=20260511-0105`, { cache: "no-store" });
|
||||
if (response.ok) return await response.json();
|
||||
} catch (error) {
|
||||
return fallbackMessages[normalizedLang];
|
||||
}
|
||||
|
||||
return fallbackMessages[normalizedLang];
|
||||
}
|
||||
|
||||
function localizedValue(messages, key) {
|
||||
return messages?.[key] || fallbackMessages[currentLang]?.[key] || fallbackMessages.en[key] || "";
|
||||
}
|
||||
|
||||
function message(key, fallback = "") {
|
||||
return localizedValue(currentMessages, key) || fallback || key;
|
||||
}
|
||||
|
||||
function renderMessages(messages) {
|
||||
document.querySelectorAll("[data-i18n]").forEach((node) => {
|
||||
const value = localizedValue(messages, node.dataset.i18n);
|
||||
if (value) node.textContent = value;
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-i18n-aria]").forEach((node) => {
|
||||
const value = localizedValue(messages, node.dataset.i18nAria);
|
||||
if (value) node.setAttribute("aria-label", value);
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-i18n-placeholder]").forEach((node) => {
|
||||
const value = localizedValue(messages, node.dataset.i18nPlaceholder);
|
||||
if (value) node.setAttribute("placeholder", value);
|
||||
});
|
||||
}
|
||||
|
||||
function setLanguageMenuOpen(open) {
|
||||
const languageButton = $(".language-button");
|
||||
const languageMenu = $(".language-menu");
|
||||
if (!languageButton || !languageMenu) return;
|
||||
|
||||
languageMenu.hidden = !open;
|
||||
languageButton.setAttribute("aria-expanded", String(open));
|
||||
}
|
||||
|
||||
function renderLanguageControls(messages) {
|
||||
const languageButton = $(".language-button");
|
||||
if (languageButton) {
|
||||
languageButton.textContent = languageLabels[currentLang];
|
||||
languageButton.setAttribute("aria-label", localizedValue(messages, "language_button_aria") || "Change language");
|
||||
}
|
||||
|
||||
document.querySelectorAll(".language-menu [data-lang]").forEach((button) => {
|
||||
const isActive = button.dataset.lang === currentLang;
|
||||
button.classList.toggle("is-active", isActive);
|
||||
button.setAttribute("aria-pressed", String(isActive));
|
||||
});
|
||||
}
|
||||
|
||||
function setPropsTypeMenuOpen(open) {
|
||||
const root = $("#propsTypeSelect");
|
||||
const button = $("#propsTypeButton");
|
||||
const menu = $("#propsTypeMenu");
|
||||
if (!root || !button || !menu) return;
|
||||
|
||||
root.classList.toggle("is-open", open);
|
||||
menu.hidden = !open;
|
||||
button.setAttribute("aria-expanded", String(open));
|
||||
}
|
||||
|
||||
function renderPropsTypeSelect() {
|
||||
const root = $("#propsTypeSelect");
|
||||
const label = $("#propsTypeSelectedLabel");
|
||||
if (root) root.dataset.value = state.propsType;
|
||||
if (label) label.textContent = propTypeLabel(state.propsType);
|
||||
|
||||
document.querySelectorAll("#propsTypeMenu [data-value]").forEach((button) => {
|
||||
const isSelected = button.dataset.value === state.propsType;
|
||||
button.classList.toggle("is-selected", isSelected);
|
||||
button.setAttribute("aria-selected", String(isSelected));
|
||||
});
|
||||
}
|
||||
|
||||
async function choosePropsType(value) {
|
||||
const nextValue = String(value || defaultPropsType);
|
||||
setPropsTypeMenuOpen(false);
|
||||
if (nextValue === state.propsType) {
|
||||
renderPropsTypeSelect();
|
||||
return;
|
||||
}
|
||||
state.propsType = nextValue;
|
||||
renderPropsTypeSelect();
|
||||
try {
|
||||
await loadProps();
|
||||
} catch (error) {
|
||||
setStatus($("#propsStatus"), friendlyError(error), "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function applyLanguage(lang) {
|
||||
currentLang = normalizeLanguage(lang);
|
||||
const messages = await loadMessages(currentLang);
|
||||
currentMessages = messages;
|
||||
|
||||
document.documentElement.lang = currentLang;
|
||||
document.documentElement.dir = currentLang === "ar" ? "rtl" : "ltr";
|
||||
document.title = message("document_title", "Manager Center");
|
||||
renderMessages(messages);
|
||||
renderLanguageControls(messages);
|
||||
renderPropsTypeSelect();
|
||||
renderManager(state.manager);
|
||||
renderTarget();
|
||||
renderProps();
|
||||
}
|
||||
|
||||
function $(selector) {
|
||||
return document.querySelector(selector);
|
||||
}
|
||||
@ -95,7 +418,7 @@
|
||||
const sysOrigin = params.get("sysOrigin") || params.get("origin") || "ATYOU";
|
||||
return {
|
||||
Authorization: normalizeAuthorization(token),
|
||||
"req-lang": params.get("lang") || "zh-CN",
|
||||
"req-lang": currentLang,
|
||||
"req-client": "H5",
|
||||
"req-version": "V2",
|
||||
"req-zone": Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Shanghai",
|
||||
@ -107,7 +430,7 @@
|
||||
async function requestGoJSON(path, options = {}) {
|
||||
const token = readRawParam("token");
|
||||
if (!token) {
|
||||
const error = new Error("缺少登录信息");
|
||||
const error = new Error(message("missing_token"));
|
||||
error.code = "missing_token";
|
||||
throw error;
|
||||
}
|
||||
@ -226,17 +549,30 @@
|
||||
return String(user?.userId || user?.id || "-");
|
||||
}
|
||||
|
||||
function displayAccount(user) {
|
||||
return user?.account ? ` (${user.account})` : "";
|
||||
function displayShortID(user) {
|
||||
return String(user?.actualAccount || user?.account || user?.shortId || user?.userId || user?.id || "-");
|
||||
}
|
||||
|
||||
function canBanTarget(target) {
|
||||
return Boolean(target) && target.canBan !== false && !target.hasRecharge;
|
||||
}
|
||||
|
||||
function userIDText(user) {
|
||||
return `${message("uid_label", "UID")}: ${displayShortID(user)}`;
|
||||
}
|
||||
|
||||
function propTypeLabel(type) {
|
||||
const key = `prop_type_${String(type || "").toLowerCase()}`;
|
||||
return message(key, type || "-");
|
||||
}
|
||||
|
||||
function formatDays(days) {
|
||||
return message("days", "{count} days").replace("{count}", String(days || 0));
|
||||
}
|
||||
|
||||
function renderManager(manager) {
|
||||
$("#managerName").textContent = displayName(manager);
|
||||
$("#managerUid").textContent = `UID: ${displayUserID(manager)}${displayAccount(manager)}`;
|
||||
$("#managerUid").textContent = userIDText(manager);
|
||||
renderAvatar("#managerAvatar", "#managerAvatarFallback", manager?.userAvatar, displayName(manager), "M");
|
||||
}
|
||||
|
||||
@ -254,14 +590,11 @@
|
||||
card.hidden = false;
|
||||
banCard.hidden = false;
|
||||
$("#targetName").textContent = displayName(target);
|
||||
$("#targetUid").textContent = `UID: ${displayUserID(target)}${displayAccount(target)}`;
|
||||
$("#targetUid").textContent = userIDText(target);
|
||||
$("#targetAccountStatus").textContent = target.accountStatus || "-";
|
||||
const rechargeStatus = $("#targetRechargeStatus");
|
||||
const canBan = canBanTarget(target);
|
||||
rechargeStatus.textContent = target.hasRecharge ? "已充值" : (canBan ? "未充值" : "充值状态未知");
|
||||
rechargeStatus.classList.toggle("is-danger", Boolean(target.hasRecharge) || !canBan);
|
||||
const banEligibility = $("#banEligibility");
|
||||
banEligibility.textContent = canBan ? "可封禁" : "不可封禁";
|
||||
banEligibility.textContent = canBan ? message("can_ban") : message("cannot_ban");
|
||||
banEligibility.classList.toggle("is-danger", !canBan);
|
||||
renderAvatar("#targetAvatar", "#targetAvatarFallback", target.userAvatar, displayName(target), "U");
|
||||
updateActionState();
|
||||
@ -272,7 +605,7 @@
|
||||
if (!list) return;
|
||||
list.replaceChildren();
|
||||
if (!state.props.length) {
|
||||
setStatus($("#propsStatus"), "没有可赠送道具");
|
||||
setStatus($("#propsStatus"), message("no_giftable_props"));
|
||||
updateActionState();
|
||||
return;
|
||||
}
|
||||
@ -307,12 +640,12 @@
|
||||
name.textContent = item.name || `ID ${item.id}`;
|
||||
const meta = document.createElement("span");
|
||||
meta.className = "prop-meta";
|
||||
meta.textContent = item.vipLevel ? `${item.type} · VIP ${item.vipLevel}` : item.type;
|
||||
meta.textContent = item.vipLevel ? `${propTypeLabel(item.type)} · VIP ${item.vipLevel}` : propTypeLabel(item.type);
|
||||
copy.append(name, meta);
|
||||
|
||||
const days = document.createElement("span");
|
||||
days.className = "prop-days";
|
||||
days.textContent = `${item.days || 0}天`;
|
||||
days.textContent = formatDays(item.days);
|
||||
|
||||
button.append(cover, copy, days);
|
||||
button.addEventListener("click", () => {
|
||||
@ -339,10 +672,10 @@
|
||||
}
|
||||
|
||||
async function loadProps() {
|
||||
setStatus($("#propsStatus"), "加载中...");
|
||||
state.props = [];
|
||||
state.selectedPropsId = "";
|
||||
renderProps();
|
||||
setStatus($("#propsStatus"), message("loading"));
|
||||
|
||||
const body = await requestGoJSON(endpointProps(state.propsType));
|
||||
state.props = Array.isArray(body?.records) ? body.records : [];
|
||||
@ -355,12 +688,12 @@
|
||||
const input = $("#accountInput");
|
||||
const account = String(input?.value || "").trim();
|
||||
if (!account) {
|
||||
setStatus($("#searchStatus"), "请输入用户 ID 或账号", "error");
|
||||
setStatus($("#searchStatus"), message("enter_user"), "error");
|
||||
return;
|
||||
}
|
||||
|
||||
$("#searchButton").disabled = true;
|
||||
setStatus($("#searchStatus"), "搜索中...");
|
||||
setStatus($("#searchStatus"), message("searching"));
|
||||
try {
|
||||
const body = await requestGoJSON(endpointSearchUser(account));
|
||||
state.target = body?.user || body || null;
|
||||
@ -377,7 +710,7 @@
|
||||
|
||||
async function sendProps() {
|
||||
if (!state.target || !state.selectedPropsId) return;
|
||||
if (!window.confirm("确认赠送该道具?")) return;
|
||||
if (!window.confirm(message("confirm_send"))) return;
|
||||
|
||||
const button = $("#sendPropsButton");
|
||||
button.disabled = true;
|
||||
@ -389,7 +722,7 @@
|
||||
propsId: state.selectedPropsId
|
||||
}
|
||||
});
|
||||
showToast("赠送成功");
|
||||
showToast(message("send_success"));
|
||||
} catch (error) {
|
||||
showToast(friendlyError(error));
|
||||
} finally {
|
||||
@ -399,11 +732,11 @@
|
||||
|
||||
async function banUser() {
|
||||
if (!canBanTarget(state.target)) return;
|
||||
if (!window.confirm("确认封禁该用户?")) return;
|
||||
if (!window.confirm(message("confirm_ban"))) return;
|
||||
|
||||
const button = $("#banButton");
|
||||
button.disabled = true;
|
||||
setStatus($("#banStatus"), "提交中...");
|
||||
setStatus($("#banStatus"), message("submitting"));
|
||||
try {
|
||||
await requestGoJSON(endpointBanUser(), {
|
||||
method: "POST",
|
||||
@ -415,7 +748,7 @@
|
||||
state.target.accountStatus = "ARCHIVE";
|
||||
renderTarget();
|
||||
setStatus($("#banStatus"), "");
|
||||
showToast("封禁成功");
|
||||
showToast(message("ban_success"));
|
||||
} catch (error) {
|
||||
setStatus($("#banStatus"), friendlyError(error), "error");
|
||||
} finally {
|
||||
@ -425,36 +758,60 @@
|
||||
|
||||
function friendlyError(error) {
|
||||
const code = error?.code || error?.response?.code || error?.response?.errorCodeName || "";
|
||||
if (code === "missing_token") return "缺少登录信息";
|
||||
if (code === "not_manager") return "当前账号不是经理";
|
||||
if (code === "user_not_found") return "用户不存在";
|
||||
if (code === "user_recharged") return "该用户已有充值记录,不能封禁";
|
||||
if (code === "prop_not_giftable") return "该道具未开放经理赠送";
|
||||
if (code === "vip_not_giftable") return "该贵族道具不可赠送";
|
||||
return error?.message || "请求失败";
|
||||
if (code === "missing_token") return message("missing_token");
|
||||
if (code === "not_manager") return message("not_manager");
|
||||
if (code === "user_not_found") return message("user_not_found");
|
||||
if (code === "user_recharged") return message("user_recharged");
|
||||
if (code === "prop_not_giftable") return message("prop_not_giftable");
|
||||
if (code === "vip_not_giftable") return message("vip_not_giftable");
|
||||
return error?.message || message("request_failed");
|
||||
}
|
||||
|
||||
function bindEvents() {
|
||||
$(".back-button")?.addEventListener("click", closePage);
|
||||
$("#searchForm")?.addEventListener("submit", searchUser);
|
||||
$("#propsTypeSelect")?.addEventListener("change", async (event) => {
|
||||
state.propsType = event.target.value || defaultPropsType;
|
||||
try {
|
||||
await loadProps();
|
||||
} catch (error) {
|
||||
setStatus($("#propsStatus"), friendlyError(error), "error");
|
||||
}
|
||||
$(".language-button")?.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
setLanguageMenuOpen(Boolean($(".language-menu")?.hidden));
|
||||
});
|
||||
document.querySelectorAll(".language-menu [data-lang]").forEach((button) => {
|
||||
button.addEventListener("click", async (event) => {
|
||||
event.stopPropagation();
|
||||
setLanguageMenuOpen(false);
|
||||
await applyLanguage(button.dataset.lang);
|
||||
});
|
||||
});
|
||||
document.addEventListener("click", () => {
|
||||
setLanguageMenuOpen(false);
|
||||
setPropsTypeMenuOpen(false);
|
||||
});
|
||||
$("#propsTypeButton")?.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
setLanguageMenuOpen(false);
|
||||
setPropsTypeMenuOpen(Boolean($("#propsTypeMenu")?.hidden));
|
||||
});
|
||||
document.querySelectorAll("#propsTypeMenu [data-value]").forEach((button) => {
|
||||
button.addEventListener("click", async (event) => {
|
||||
event.stopPropagation();
|
||||
await choosePropsType(button.dataset.value);
|
||||
});
|
||||
});
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key !== "Escape") return;
|
||||
setLanguageMenuOpen(false);
|
||||
setPropsTypeMenuOpen(false);
|
||||
});
|
||||
$("#searchForm")?.addEventListener("submit", searchUser);
|
||||
$("#sendPropsButton")?.addEventListener("click", sendProps);
|
||||
$("#banButton")?.addEventListener("click", banUser);
|
||||
}
|
||||
|
||||
async function init() {
|
||||
bindEvents();
|
||||
$("#propsTypeSelect").value = state.propsType;
|
||||
renderPropsTypeSelect();
|
||||
await applyLanguage(currentLang);
|
||||
if (!readRawParam("token")) {
|
||||
setLoading(false);
|
||||
setStatus($("#searchStatus"), "缺少登录信息", "error");
|
||||
setStatus($("#searchStatus"), message("missing_token"), "error");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,6 @@ body {
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font: inherit;
|
||||
}
|
||||
@ -110,6 +109,58 @@ button:disabled {
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.language-switcher {
|
||||
position: relative;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.language-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 42px;
|
||||
height: 30px;
|
||||
border: 1px solid rgba(35, 40, 46, 0.12);
|
||||
border-radius: 15px;
|
||||
background: rgba(255, 255, 255, 0.76);
|
||||
color: var(--text);
|
||||
font-size: 13px;
|
||||
font-weight: 900;
|
||||
box-shadow: 0 4px 14px rgba(32, 36, 42, 0.08);
|
||||
}
|
||||
|
||||
.language-menu {
|
||||
position: absolute;
|
||||
z-index: 8;
|
||||
top: calc(100% + 7px);
|
||||
right: 0;
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
min-width: 58px;
|
||||
padding: 5px;
|
||||
border: 1px solid rgba(35, 40, 46, 0.1);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow: 0 10px 26px rgba(36, 46, 60, 0.14);
|
||||
}
|
||||
|
||||
.language-menu button {
|
||||
min-height: 28px;
|
||||
border-radius: 6px;
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.language-menu button.is-active {
|
||||
background: #e7f8f4;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.language-menu[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@ -245,7 +296,6 @@ button:disabled {
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: 1px solid var(--line);
|
||||
@ -256,8 +306,11 @@ textarea {
|
||||
}
|
||||
|
||||
input,
|
||||
select {
|
||||
button.custom-select-button {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
@ -268,7 +321,6 @@ textarea {
|
||||
}
|
||||
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
border-color: var(--primary);
|
||||
background: #fff;
|
||||
@ -312,22 +364,120 @@ textarea:focus {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.custom-select-button {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 24px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border: 1px solid var(--primary);
|
||||
border-radius: 8px;
|
||||
padding: 0 12px 0 14px;
|
||||
background: #fff;
|
||||
color: var(--text);
|
||||
text-align: left;
|
||||
box-shadow: 0 0 0 5px rgba(24, 184, 159, 0.1);
|
||||
}
|
||||
|
||||
.custom-select-button span {
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.custom-select-button svg {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
fill: none;
|
||||
justify-self: end;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2.2;
|
||||
transition: transform 0.16s ease;
|
||||
}
|
||||
|
||||
.custom-select.is-open .custom-select-button svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.custom-select-menu {
|
||||
position: absolute;
|
||||
z-index: 12;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
left: 0;
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid rgba(35, 40, 46, 0.1);
|
||||
border-radius: 8px;
|
||||
padding: 6px;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
box-shadow: 0 16px 36px rgba(32, 36, 42, 0.18);
|
||||
}
|
||||
|
||||
.custom-select-menu button {
|
||||
min-height: 36px;
|
||||
border-radius: 6px;
|
||||
padding: 0 11px;
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.custom-select-menu button.is-selected {
|
||||
background: #e7f8f4;
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.custom-select-menu button:active {
|
||||
background: #dff4ef;
|
||||
}
|
||||
|
||||
.custom-select-menu[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.props-list {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
gap: 6px;
|
||||
max-height: 330px;
|
||||
margin-top: 10px;
|
||||
overflow-y: auto;
|
||||
padding-right: 2px;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(24, 184, 159, 0.45) transparent;
|
||||
}
|
||||
|
||||
.props-list::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
.props-list::-webkit-scrollbar-thumb {
|
||||
border-radius: 999px;
|
||||
background: rgba(24, 184, 159, 0.42);
|
||||
}
|
||||
|
||||
.prop-option {
|
||||
display: grid;
|
||||
grid-template-columns: 52px 1fr auto;
|
||||
grid-template-columns: 42px minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-height: 68px;
|
||||
min-height: 54px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
padding: 6px 8px;
|
||||
background: #fff;
|
||||
color: inherit;
|
||||
text-align: left;
|
||||
@ -339,10 +489,10 @@ textarea:focus {
|
||||
}
|
||||
|
||||
.prop-cover {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
border-radius: 7px;
|
||||
background: #eef2f5;
|
||||
}
|
||||
|
||||
@ -364,29 +514,32 @@ textarea:focus {
|
||||
}
|
||||
|
||||
.prop-copy {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.prop-name {
|
||||
overflow: hidden;
|
||||
font-size: 15px;
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
line-height: 18px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.prop-meta {
|
||||
margin-top: 4px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.prop-days {
|
||||
border-radius: 999px;
|
||||
padding: 5px 8px;
|
||||
padding: 4px 8px;
|
||||
background: #f2f4f7;
|
||||
color: #596273;
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
@ -447,6 +600,28 @@ textarea:focus {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[dir="rtl"] .back-button svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
[dir="rtl"] .language-menu {
|
||||
right: auto;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
[dir="rtl"] .profile-copy,
|
||||
[dir="rtl"] input,
|
||||
[dir="rtl"] textarea,
|
||||
[dir="rtl"] .custom-select-button,
|
||||
[dir="rtl"] .custom-select-menu button,
|
||||
[dir="rtl"] .prop-option {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
[dir="rtl"] .custom-select-button {
|
||||
padding: 0 14px 0 12px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user