feat: add sub coin seller management
This commit is contained in:
parent
572c4cee1b
commit
08ae81d5a8
@ -120,6 +120,15 @@ export function searchFreightUser(account) {
|
|||||||
return get(`/wallet/freight/search-user?account=${account}`)
|
return get(`/wallet/freight/search-user?account=${account}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经销商搜索已有 coin seller
|
||||||
|
* @param {string} account - 用户账号
|
||||||
|
* @returns {Promise} 返回 coin seller 用户信息
|
||||||
|
*/
|
||||||
|
export function searchDealerFreightUser(account) {
|
||||||
|
return get(`/wallet/freight/dealer/search-user?account=${account}`)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 金币充值
|
* 金币充值
|
||||||
* @param {Object} data - 充值数据
|
* @param {Object} data - 充值数据
|
||||||
@ -131,6 +140,35 @@ export function freightRecharge(data) {
|
|||||||
return post('/wallet/freight/ship', data)
|
return post('/wallet/freight/ship', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前超级经销商的子 coin seller 列表
|
||||||
|
* @returns {Promise} 返回子 coin seller 列表
|
||||||
|
*/
|
||||||
|
export function getFreightSubSellers() {
|
||||||
|
return get('/wallet/freight/super/sub-sellers')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定已有 coin seller 为当前超级经销商的子 coin seller
|
||||||
|
* @param {Object} data
|
||||||
|
* @param {number|string} data.userId - 子 coin seller 用户ID
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
export function addFreightSubSeller(data) {
|
||||||
|
return post('/wallet/freight/super/sub-sellers', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从当前超级经销商币商钱包转账给子 coin seller 币商钱包
|
||||||
|
* @param {Object} data
|
||||||
|
* @param {number|string} data.acceptUserId - 子 coin seller 用户ID
|
||||||
|
* @param {number|string} data.quantity - 转账金币数量
|
||||||
|
* @returns {Promise} 返回当前超级经销商剩余余额
|
||||||
|
*/
|
||||||
|
export function transferFreightSubSeller(data) {
|
||||||
|
return post('/wallet/freight/super/sub-sellers/transfer', data)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取金币交易流水
|
* 获取金币交易流水
|
||||||
* @param {string} data
|
* @param {string} data
|
||||||
|
|||||||
@ -92,7 +92,20 @@
|
|||||||
"join_team_steps": "انا>مركز>طلب الانضمام إلى الفريق",
|
"join_team_steps": "انا>مركز>طلب الانضمام إلى الفريق",
|
||||||
"enter_team_id": "أدخل id الفريق وانقر على إرسال للانضمام",
|
"enter_team_id": "أدخل id الفريق وانقر على إرسال للانضمام",
|
||||||
"recharge_agency": "وكيل الشحن",
|
"recharge_agency": "وكيل الشحن",
|
||||||
|
"invite_sub_coin_seller": "Invite sub coin seller",
|
||||||
"my_coins": "عملاتي الذهبية",
|
"my_coins": "عملاتي الذهبية",
|
||||||
|
"current_balance": "الرصيد الحالي",
|
||||||
|
"balance": "الرصيد",
|
||||||
|
"refresh": "تحديث",
|
||||||
|
"sub_coin_sellers": "بائعو العملات الفرعيون",
|
||||||
|
"sub_coin_seller_list": "قائمة بائعي العملات الفرعيين",
|
||||||
|
"enter_coin_seller_id": "أدخل معرف بائع العملات",
|
||||||
|
"bind_sub_coin_seller": "ربط",
|
||||||
|
"sub_coin_seller_bound": "تمت إضافة بائع العملات الفرعي",
|
||||||
|
"no_sub_coin_sellers": "لا يوجد بائعو عملات فرعيون",
|
||||||
|
"transfer_to_sub_coin_seller": "تحويل إلى بائع العملات الفرعي",
|
||||||
|
"enter_transfer_amount": "أدخل مبلغ التحويل",
|
||||||
|
"sub_coin_seller_transfer_success": "تم التحويل بنجاح",
|
||||||
"user": "مستخدم",
|
"user": "مستخدم",
|
||||||
"search_user": "البحث عن المستخدم",
|
"search_user": "البحث عن المستخدم",
|
||||||
"enter_user_id": "يرجى إدخال id المستخدم",
|
"enter_user_id": "يرجى إدخال id المستخدم",
|
||||||
@ -290,6 +303,7 @@
|
|||||||
"prowide_income": "الدخل المقدم",
|
"prowide_income": "الدخل المقدم",
|
||||||
"copied_successfully": "تم النسخ بنجاح",
|
"copied_successfully": "تم النسخ بنجاح",
|
||||||
"please_enter_valid_invitation_code": "يرجى إدخال رمز دعوة صالح.",
|
"please_enter_valid_invitation_code": "يرجى إدخال رمز دعوة صالح.",
|
||||||
|
"please_enter_valid_amount": "يرجى إدخال مبلغ صالح.",
|
||||||
"invitation_code_bound_successfully": "تم ربط رمز الدعوة بنجاح!",
|
"invitation_code_bound_successfully": "تم ربط رمز الدعوة بنجاح!",
|
||||||
"invitation_code_binding_failed": "فشل ربط رمز الدعوة.",
|
"invitation_code_binding_failed": "فشل ربط رمز الدعوة.",
|
||||||
"user_id_prefix": "المعرف:",
|
"user_id_prefix": "المعرف:",
|
||||||
|
|||||||
@ -92,7 +92,20 @@
|
|||||||
"join_team_steps": "আমি > হোস্ট সেন্টার > দলে যোগদানের জন্য আবেদন করুন।",
|
"join_team_steps": "আমি > হোস্ট সেন্টার > দলে যোগদানের জন্য আবেদন করুন।",
|
||||||
"enter_team_id": "দল আইডি লিখুন, যোগদান করতে পাঠান এ ক্লিক করুন।",
|
"enter_team_id": "দল আইডি লিখুন, যোগদান করতে পাঠান এ ক্লিক করুন।",
|
||||||
"recharge_agency": "রিচার্জ এজেন্সি",
|
"recharge_agency": "রিচার্জ এজেন্সি",
|
||||||
|
"invite_sub_coin_seller": "Invite sub coin seller",
|
||||||
"my_coins": "আমার মুদ্রা:",
|
"my_coins": "আমার মুদ্রা:",
|
||||||
|
"current_balance": "বর্তমান ব্যালেন্স",
|
||||||
|
"balance": "ব্যালেন্স",
|
||||||
|
"refresh": "রিফ্রেশ",
|
||||||
|
"sub_coin_sellers": "সাব coin seller",
|
||||||
|
"sub_coin_seller_list": "সাব coin seller তালিকা",
|
||||||
|
"enter_coin_seller_id": "coin seller ID লিখুন",
|
||||||
|
"bind_sub_coin_seller": "বাইন্ড",
|
||||||
|
"sub_coin_seller_bound": "সাব coin seller যোগ করা হয়েছে",
|
||||||
|
"no_sub_coin_sellers": "কোনো সাব coin seller নেই",
|
||||||
|
"transfer_to_sub_coin_seller": "সাব coin seller-এ ট্রান্সফার",
|
||||||
|
"enter_transfer_amount": "ট্রান্সফার পরিমাণ লিখুন",
|
||||||
|
"sub_coin_seller_transfer_success": "ট্রান্সফার সফল",
|
||||||
"user": "ব্যবহারকারী:",
|
"user": "ব্যবহারকারী:",
|
||||||
"search_user": "ব্যবহারকারী অনুসন্ধান",
|
"search_user": "ব্যবহারকারী অনুসন্ধান",
|
||||||
"enter_user_id": "দয়া করে ব্যবহারকারী আইডি লিখুন",
|
"enter_user_id": "দয়া করে ব্যবহারকারী আইডি লিখুন",
|
||||||
@ -290,6 +303,7 @@
|
|||||||
"prowide_income": "প্রোওয়াইড আয়",
|
"prowide_income": "প্রোওয়াইড আয়",
|
||||||
"copied_successfully": "সফলভাবে কপি করা হয়েছে",
|
"copied_successfully": "সফলভাবে কপি করা হয়েছে",
|
||||||
"please_enter_valid_invitation_code": "দয়া করে একটি বৈধ আমন্ত্রণ কোড লিখুন।",
|
"please_enter_valid_invitation_code": "দয়া করে একটি বৈধ আমন্ত্রণ কোড লিখুন।",
|
||||||
|
"please_enter_valid_amount": "একটি বৈধ পরিমাণ লিখুন।",
|
||||||
"invitation_code_bound_successfully": "আমন্ত্রণ কোড সফলভাবে বাউন্ড হয়েছে!",
|
"invitation_code_bound_successfully": "আমন্ত্রণ কোড সফলভাবে বাউন্ড হয়েছে!",
|
||||||
"invitation_code_binding_failed": "আমন্ত্রণ কোড বাউন্ডিং ব্যর্থ।",
|
"invitation_code_binding_failed": "আমন্ত্রণ কোড বাউন্ডিং ব্যর্থ।",
|
||||||
"user_id_prefix": "আইডি:",
|
"user_id_prefix": "আইডি:",
|
||||||
|
|||||||
@ -92,7 +92,20 @@
|
|||||||
"join_team_steps": "Me > Host Center >Apply to join the team.",
|
"join_team_steps": "Me > Host Center >Apply to join the team.",
|
||||||
"enter_team_id": "Enter the team ID,click send to join.",
|
"enter_team_id": "Enter the team ID,click send to join.",
|
||||||
"recharge_agency": "Recharge agency",
|
"recharge_agency": "Recharge agency",
|
||||||
|
"invite_sub_coin_seller": "Invite sub coin seller",
|
||||||
"my_coins": "My coins:",
|
"my_coins": "My coins:",
|
||||||
|
"current_balance": "Current balance",
|
||||||
|
"balance": "Balance",
|
||||||
|
"refresh": "Refresh",
|
||||||
|
"sub_coin_sellers": "Sub coin sellers",
|
||||||
|
"sub_coin_seller_list": "Sub coin seller list",
|
||||||
|
"enter_coin_seller_id": "Enter coin seller ID",
|
||||||
|
"bind_sub_coin_seller": "Bind",
|
||||||
|
"sub_coin_seller_bound": "Sub coin seller added",
|
||||||
|
"no_sub_coin_sellers": "No sub coin sellers",
|
||||||
|
"transfer_to_sub_coin_seller": "Transfer to sub coin seller",
|
||||||
|
"enter_transfer_amount": "Enter transfer amount",
|
||||||
|
"sub_coin_seller_transfer_success": "Transfer successful",
|
||||||
"user": "User :",
|
"user": "User :",
|
||||||
"search_user": "Search user",
|
"search_user": "Search user",
|
||||||
"enter_user_id": "Please enter the user ID",
|
"enter_user_id": "Please enter the user ID",
|
||||||
@ -290,6 +303,7 @@
|
|||||||
"prowide_income": "Prowide income",
|
"prowide_income": "Prowide income",
|
||||||
"copied_successfully": "Copied successfully",
|
"copied_successfully": "Copied successfully",
|
||||||
"please_enter_valid_invitation_code": "Please enter a valid invitation code.",
|
"please_enter_valid_invitation_code": "Please enter a valid invitation code.",
|
||||||
|
"please_enter_valid_amount": "Please enter a valid amount.",
|
||||||
"invitation_code_bound_successfully": "Invitation code bound successfully!",
|
"invitation_code_bound_successfully": "Invitation code bound successfully!",
|
||||||
"invitation_code_binding_failed": "Invitation code binding failed.",
|
"invitation_code_binding_failed": "Invitation code binding failed.",
|
||||||
"user_id_prefix": "ID:",
|
"user_id_prefix": "ID:",
|
||||||
|
|||||||
@ -92,7 +92,20 @@
|
|||||||
"join_team_steps": "Ben > Host Merkezi > Takıma katılmak için başvur.",
|
"join_team_steps": "Ben > Host Merkezi > Takıma katılmak için başvur.",
|
||||||
"enter_team_id": "Takım ID'sini girin, katılmak için gönder'e tıklayın.",
|
"enter_team_id": "Takım ID'sini girin, katılmak için gönder'e tıklayın.",
|
||||||
"recharge_agency": "Yükleme acentesi",
|
"recharge_agency": "Yükleme acentesi",
|
||||||
|
"invite_sub_coin_seller": "Invite sub coin seller",
|
||||||
"my_coins": "Coinlerim:",
|
"my_coins": "Coinlerim:",
|
||||||
|
"current_balance": "Mevcut bakiye",
|
||||||
|
"balance": "Bakiye",
|
||||||
|
"refresh": "Yenile",
|
||||||
|
"sub_coin_sellers": "Alt coin seller",
|
||||||
|
"sub_coin_seller_list": "Alt coin seller listesi",
|
||||||
|
"enter_coin_seller_id": "Coin seller ID girin",
|
||||||
|
"bind_sub_coin_seller": "Bağla",
|
||||||
|
"sub_coin_seller_bound": "Alt coin seller eklendi",
|
||||||
|
"no_sub_coin_sellers": "Alt coin seller yok",
|
||||||
|
"transfer_to_sub_coin_seller": "Alt coin seller'a transfer",
|
||||||
|
"enter_transfer_amount": "Transfer tutarını girin",
|
||||||
|
"sub_coin_seller_transfer_success": "Transfer başarılı",
|
||||||
"user": "Kullanıcı:",
|
"user": "Kullanıcı:",
|
||||||
"search_user": "Kullanıcı ara",
|
"search_user": "Kullanıcı ara",
|
||||||
"enter_user_id": "Lütfen kullanıcı ID'sini girin",
|
"enter_user_id": "Lütfen kullanıcı ID'sini girin",
|
||||||
@ -290,6 +303,7 @@
|
|||||||
"prowide_income": "Prowide geliri",
|
"prowide_income": "Prowide geliri",
|
||||||
"copied_successfully": "Başarıyla kopyalandı",
|
"copied_successfully": "Başarıyla kopyalandı",
|
||||||
"please_enter_valid_invitation_code": "Lütfen geçerli bir davet kodu girin.",
|
"please_enter_valid_invitation_code": "Lütfen geçerli bir davet kodu girin.",
|
||||||
|
"please_enter_valid_amount": "Lütfen geçerli bir miktar girin.",
|
||||||
"invitation_code_bound_successfully": "Davet kodu başarıyla bağlandı!",
|
"invitation_code_bound_successfully": "Davet kodu başarıyla bağlandı!",
|
||||||
"invitation_code_binding_failed": "Davet kodu bağlama başarısız.",
|
"invitation_code_binding_failed": "Davet kodu bağlama başarısız.",
|
||||||
"user_id_prefix": "ID:",
|
"user_id_prefix": "ID:",
|
||||||
|
|||||||
@ -92,7 +92,20 @@
|
|||||||
"join_team_steps": "我>主播中心>申请加入团队",
|
"join_team_steps": "我>主播中心>申请加入团队",
|
||||||
"enter_team_id": "输入团队ID,点击发送加入。",
|
"enter_team_id": "输入团队ID,点击发送加入。",
|
||||||
"recharge_agency": "充值代理",
|
"recharge_agency": "充值代理",
|
||||||
|
"invite_sub_coin_seller": "Invite sub coin seller",
|
||||||
"my_coins": "我的金币",
|
"my_coins": "我的金币",
|
||||||
|
"current_balance": "当前余额",
|
||||||
|
"balance": "余额",
|
||||||
|
"refresh": "刷新",
|
||||||
|
"sub_coin_sellers": "子 coin seller",
|
||||||
|
"sub_coin_seller_list": "子 coin seller 列表",
|
||||||
|
"enter_coin_seller_id": "请输入 coin seller ID",
|
||||||
|
"bind_sub_coin_seller": "绑定",
|
||||||
|
"sub_coin_seller_bound": "子 coin seller 已添加",
|
||||||
|
"no_sub_coin_sellers": "暂无子 coin seller",
|
||||||
|
"transfer_to_sub_coin_seller": "转账给子 coin seller",
|
||||||
|
"enter_transfer_amount": "请输入转账金额",
|
||||||
|
"sub_coin_seller_transfer_success": "转账成功",
|
||||||
"user": "用户",
|
"user": "用户",
|
||||||
"search_user": "搜索用户",
|
"search_user": "搜索用户",
|
||||||
"enter_user_id": "请输入用户id",
|
"enter_user_id": "请输入用户id",
|
||||||
@ -290,6 +303,7 @@
|
|||||||
"prowide_income": "提供收入",
|
"prowide_income": "提供收入",
|
||||||
"copied_successfully": "复制成功",
|
"copied_successfully": "复制成功",
|
||||||
"please_enter_valid_invitation_code": "请输入有效的邀请码。",
|
"please_enter_valid_invitation_code": "请输入有效的邀请码。",
|
||||||
|
"please_enter_valid_amount": "请输入有效金额。",
|
||||||
"invitation_code_bound_successfully": "邀请码绑定成功!",
|
"invitation_code_bound_successfully": "邀请码绑定成功!",
|
||||||
"invitation_code_binding_failed": "邀请码绑定失败。",
|
"invitation_code_binding_failed": "邀请码绑定失败。",
|
||||||
"user_id_prefix": "ID:",
|
"user_id_prefix": "ID:",
|
||||||
|
|||||||
@ -143,6 +143,12 @@ const router = createRouter({
|
|||||||
component: () => import('../views/RechargeAgency/SellerRecordsView.vue'),
|
component: () => import('../views/RechargeAgency/SellerRecordsView.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/coin-seller/sub-sellers',
|
||||||
|
name: 'coin-seller-sub-sellers',
|
||||||
|
component: () => import('../views/RechargeAgency/SubSellers.vue'),
|
||||||
|
meta: { requiresAuth: true, requiresSuperDealer: true },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/recharge-agency-recruit',
|
path: '/recharge-agency-recruit',
|
||||||
name: 'recharge-agency-recruit',
|
name: 'recharge-agency-recruit',
|
||||||
|
|||||||
@ -17,6 +17,7 @@ export const USER_ROLES = {
|
|||||||
// 页面路径常量
|
// 页面路径常量
|
||||||
export const PAGES = {
|
export const PAGES = {
|
||||||
COIN_SELLER: '/coin-seller',
|
COIN_SELLER: '/coin-seller',
|
||||||
|
COIN_SELLER_SUB_SELLERS: '/coin-seller/sub-sellers',
|
||||||
AGENCY_CENTER: '/agency-center',
|
AGENCY_CENTER: '/agency-center',
|
||||||
BD_LEADER_CENTER: '/bd-leader-center',
|
BD_LEADER_CENTER: '/bd-leader-center',
|
||||||
BD_CENTER: '/bd-center',
|
BD_CENTER: '/bd-center',
|
||||||
@ -146,6 +147,7 @@ export const ROLE_PERMISSIONS = {
|
|||||||
// Freight Agent (充值代理Rechange Agency/货运代理Freight Agent/金币代理Coin Seller)
|
// Freight Agent (充值代理Rechange Agency/货运代理Freight Agent/金币代理Coin Seller)
|
||||||
[USER_ROLES.FREIGHT_AGENT]: [
|
[USER_ROLES.FREIGHT_AGENT]: [
|
||||||
PAGES.COIN_SELLER, // 主页面
|
PAGES.COIN_SELLER, // 主页面
|
||||||
|
PAGES.COIN_SELLER_SUB_SELLERS, // 超级经销商子coin seller
|
||||||
'/seller-records',
|
'/seller-records',
|
||||||
'/coin-seller-search',
|
'/coin-seller-search',
|
||||||
],
|
],
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* 3. redirecting users to pages they can access
|
* 3. redirecting users to pages they can access
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getUserIdentity, getMemberProfile } from '../api/wallet.js'
|
import { apiGetFreightThreshold, getUserIdentity, getMemberProfile } from '../api/wallet.js'
|
||||||
import { isPublicPath } from '@/config/security.js'
|
import { isPublicPath } from '@/config/security.js'
|
||||||
import { isDebugMode } from './env.js'
|
import { isDebugMode } from './env.js'
|
||||||
import { permissionManager, PAGES, USER_ROLES } from './permissionManager.js'
|
import { permissionManager, PAGES, USER_ROLES } from './permissionManager.js'
|
||||||
@ -156,6 +156,15 @@ class IdentityChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SuperDealerRouteChecker {
|
||||||
|
async check(userId) {
|
||||||
|
if (!userId) return false
|
||||||
|
|
||||||
|
const response = await apiGetFreightThreshold(userId)
|
||||||
|
return Boolean(response?.status && response.body?.superDealer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PageRedirector {
|
class PageRedirector {
|
||||||
async redirectToCorrectPage(router, targetPath, currentPath) {
|
async redirectToCorrectPage(router, targetPath, currentPath) {
|
||||||
const hasPermission = permissionManager.hasPagePermission(targetPath)
|
const hasPermission = permissionManager.hasPagePermission(targetPath)
|
||||||
@ -183,6 +192,7 @@ class RouteGuard {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.appConnectionChecker = new AppConnectionChecker()
|
this.appConnectionChecker = new AppConnectionChecker()
|
||||||
this.identityChecker = new IdentityChecker()
|
this.identityChecker = new IdentityChecker()
|
||||||
|
this.superDealerRouteChecker = new SuperDealerRouteChecker()
|
||||||
this.pageRedirector = new PageRedirector()
|
this.pageRedirector = new PageRedirector()
|
||||||
this.isGuardActive = false
|
this.isGuardActive = false
|
||||||
}
|
}
|
||||||
@ -233,6 +243,16 @@ class RouteGuard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (permissionManager.hasPagePermission(to.path)) {
|
if (permissionManager.hasPagePermission(to.path)) {
|
||||||
|
if (to.meta?.requiresSuperDealer) {
|
||||||
|
// Super dealer pages need a second check because the base role only tells us the user is a coin seller.
|
||||||
|
const isSuperDealer = await this.superDealerRouteChecker.check(getUserId())
|
||||||
|
if (!isSuperDealer) {
|
||||||
|
console.groupEnd()
|
||||||
|
next(PAGES.COIN_SELLER)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
console.groupEnd()
|
console.groupEnd()
|
||||||
next()
|
next()
|
||||||
return
|
return
|
||||||
|
|||||||
566
src/views/RechargeAgency/SubSellers.vue
Normal file
566
src/views/RechargeAgency/SubSellers.vue
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
<template>
|
||||||
|
<div class="sub-sellers-page gradient-background-circles">
|
||||||
|
<GeneralHeader
|
||||||
|
:showLanguageList="true"
|
||||||
|
:title="t('sub_coin_sellers')"
|
||||||
|
color="black"
|
||||||
|
style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); z-index: 999"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div class="balance-card">
|
||||||
|
<div class="section-title">{{ t('current_balance') }}</div>
|
||||||
|
<div class="balance-row">
|
||||||
|
<img src="../../assets/icon/Azizi/coin.png" alt="" height="20" />
|
||||||
|
<span>{{ currentBalance }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="search-card">
|
||||||
|
<div class="section-title">{{ t('invite_sub_coin_seller') }}</div>
|
||||||
|
<div class="search-row">
|
||||||
|
<div class="search-box">
|
||||||
|
<img src="../../assets/icon/Azizi/search.png" alt="" />
|
||||||
|
<input
|
||||||
|
v-model="searchQuery"
|
||||||
|
:placeholder="t('enter_coin_seller_id')"
|
||||||
|
@keyup.enter="searchCoinSeller"
|
||||||
|
@input="onSearchInput"
|
||||||
|
dir="ltr"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button class="primary-btn compact" :disabled="isSearching" @click="searchCoinSeller">
|
||||||
|
{{ isSearching ? t('loading') : t('search') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="searchResultProfile" class="user-card">
|
||||||
|
<div class="profile-main">
|
||||||
|
<img
|
||||||
|
:src="searchResultProfile.userAvatar || ''"
|
||||||
|
alt=""
|
||||||
|
@error="handleAvatarImageError"
|
||||||
|
/>
|
||||||
|
<div class="profile-text">
|
||||||
|
<div class="profile-name">
|
||||||
|
{{ searchResultProfile.userNickname || searchResultProfile.name }}
|
||||||
|
</div>
|
||||||
|
<div class="profile-id">ID: {{ searchResultProfile.account }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="primary-btn" :disabled="isBinding" @click="bindSubSeller">
|
||||||
|
{{ isBinding ? t('loading') : t('bind_sub_coin_seller') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="list-header">
|
||||||
|
<div class="section-title">{{ t('sub_coin_seller_list') }}</div>
|
||||||
|
<button class="text-btn" :disabled="isLoadingList" @click="fetchSubSellers">
|
||||||
|
{{ t('refresh') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isLoadingList" class="empty-state">{{ t('loading') }}</div>
|
||||||
|
<div v-else-if="subSellers.length === 0" class="empty-state">
|
||||||
|
{{ t('no_sub_coin_sellers') }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="seller-list">
|
||||||
|
<div
|
||||||
|
v-for="seller in subSellers"
|
||||||
|
:key="seller.relationId || seller.childUserId"
|
||||||
|
class="seller-item"
|
||||||
|
>
|
||||||
|
<div class="profile-main">
|
||||||
|
<img
|
||||||
|
:src="profileOf(seller).userAvatar || ''"
|
||||||
|
alt=""
|
||||||
|
@error="handleAvatarImageError"
|
||||||
|
/>
|
||||||
|
<div class="profile-text">
|
||||||
|
<div class="profile-name">
|
||||||
|
{{ profileOf(seller).userNickname || profileOf(seller).name }}
|
||||||
|
</div>
|
||||||
|
<div class="profile-id">ID: {{ profileOf(seller).account }}</div>
|
||||||
|
<div class="profile-id">{{ t('balance') }}: {{ seller.balance || 0 }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="primary-btn" @click="openTransfer(seller)">
|
||||||
|
{{ t('transfer') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<maskLayer :maskLayerShow="Boolean(transferTarget)" @click="closeTransfer">
|
||||||
|
<div class="modal-wrap">
|
||||||
|
<div v-if="transferTarget" class="transfer-modal" @click.stop>
|
||||||
|
<div class="modal-title">{{ t('transfer_to_sub_coin_seller') }}</div>
|
||||||
|
<div class="modal-target">
|
||||||
|
{{ profileOf(transferTarget).userNickname || profileOf(transferTarget).account }}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="transferAmount"
|
||||||
|
class="amount-input"
|
||||||
|
:placeholder="t('enter_transfer_amount')"
|
||||||
|
inputmode="numeric"
|
||||||
|
dir="ltr"
|
||||||
|
@input="onAmountInput"
|
||||||
|
@keydown="onKeyDown"
|
||||||
|
/>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button class="ghost-btn" @click="closeTransfer">{{ t('cancel') }}</button>
|
||||||
|
<button class="primary-btn" :disabled="!canTransfer" @click="confirmTransfer">
|
||||||
|
{{ isTransferring ? t('loading') : t('confirm') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</maskLayer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { setDocumentDirection } from '@/locales/i18n'
|
||||||
|
import { showError, showSuccess } from '@/utils/toast.js'
|
||||||
|
import { useDebounce, useThrottle } from '@/utils/useDebounce'
|
||||||
|
import { handleAvatarImageError } from '@/utils/image/imageHandler.js'
|
||||||
|
import {
|
||||||
|
addFreightSubSeller,
|
||||||
|
getFreightBalance,
|
||||||
|
getFreightSubSellers,
|
||||||
|
searchDealerFreightUser,
|
||||||
|
transferFreightSubSeller,
|
||||||
|
} from '@/api/wallet.js'
|
||||||
|
|
||||||
|
import GeneralHeader from '@/components/GeneralHeader.vue'
|
||||||
|
import maskLayer from '@/components/MaskLayer.vue'
|
||||||
|
|
||||||
|
const { t, locale } = useI18n()
|
||||||
|
locale.value && setDocumentDirection(locale.value)
|
||||||
|
|
||||||
|
const currentBalance = ref('0')
|
||||||
|
const subSellers = ref([])
|
||||||
|
const isLoadingList = ref(false)
|
||||||
|
const searchQuery = ref('')
|
||||||
|
const searchResult = ref(null)
|
||||||
|
const searchResultAccount = ref('')
|
||||||
|
const isSearching = ref(false)
|
||||||
|
const isBinding = ref(false)
|
||||||
|
const transferTarget = ref(null)
|
||||||
|
const transferAmount = ref('')
|
||||||
|
const isTransferring = ref(false)
|
||||||
|
|
||||||
|
const searchResultProfile = computed(() => searchResult.value?.userProfile || null)
|
||||||
|
const positiveIntegerPattern = /^[1-9]\d*$/
|
||||||
|
const canTransfer = computed(() => {
|
||||||
|
return (
|
||||||
|
transferTarget.value &&
|
||||||
|
positiveIntegerPattern.test(transferAmount.value) &&
|
||||||
|
Number(transferAmount.value) <= Number(currentBalance.value || 0) &&
|
||||||
|
!isTransferring.value
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const profileOf = (seller) => seller?.userProfile || {}
|
||||||
|
|
||||||
|
const onKeyDown = (event) => {
|
||||||
|
if (['.', 'e', '+', '-'].includes(event.key)) {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAmountInput = (event) => {
|
||||||
|
const rawValue = event.target.value.trim()
|
||||||
|
if (rawValue === '') {
|
||||||
|
transferAmount.value = ''
|
||||||
|
event.target.value = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^\d+$/.test(rawValue)) {
|
||||||
|
event.target.value = transferAmount.value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = rawValue.replace(/^0+(?=\d)/, '')
|
||||||
|
if (value === '0') {
|
||||||
|
value = ''
|
||||||
|
}
|
||||||
|
const maxTransferAmount = Math.floor(Number(currentBalance.value || 0))
|
||||||
|
if (value !== '' && Number(value) > maxTransferAmount) {
|
||||||
|
value = maxTransferAmount > 0 ? String(maxTransferAmount) : ''
|
||||||
|
}
|
||||||
|
event.target.value = value
|
||||||
|
transferAmount.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSearchInput = () => {
|
||||||
|
const account = searchQuery.value.trim()
|
||||||
|
if (!account || account !== searchResultAccount.value) {
|
||||||
|
searchResult.value = null
|
||||||
|
searchResultAccount.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchBalance = async () => {
|
||||||
|
try {
|
||||||
|
const response = await getFreightBalance()
|
||||||
|
if (response?.status && response.body !== undefined) {
|
||||||
|
currentBalance.value = response.body.toString()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch freight balance:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSubSellers = async () => {
|
||||||
|
try {
|
||||||
|
isLoadingList.value = true
|
||||||
|
const response = await getFreightSubSellers()
|
||||||
|
subSellers.value = response?.status && response.body ? response.body : []
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch sub coin sellers:', error)
|
||||||
|
showError(error.response?.errorMsg || t('something_went_wrong'))
|
||||||
|
subSellers.value = []
|
||||||
|
} finally {
|
||||||
|
isLoadingList.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchCoinSeller = useDebounce(
|
||||||
|
async () => {
|
||||||
|
const account = searchQuery.value.trim()
|
||||||
|
if (!account || isSearching.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
isSearching.value = true
|
||||||
|
searchResult.value = null
|
||||||
|
searchResultAccount.value = ''
|
||||||
|
const response = await searchDealerFreightUser(account)
|
||||||
|
if (response?.status && response.body && searchQuery.value.trim() === account) {
|
||||||
|
searchResult.value = response.body
|
||||||
|
searchResultAccount.value = account
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError(error.response?.errorMsg || t('something_went_wrong'))
|
||||||
|
} finally {
|
||||||
|
isSearching.value = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
500,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
|
||||||
|
const bindSubSeller = async () => {
|
||||||
|
const userId = searchResultProfile.value?.id
|
||||||
|
if (!userId || isBinding.value || searchQuery.value.trim() !== searchResultAccount.value) {
|
||||||
|
searchResult.value = null
|
||||||
|
searchResultAccount.value = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
isBinding.value = true
|
||||||
|
await addFreightSubSeller({ userId })
|
||||||
|
showSuccess(t('sub_coin_seller_bound'))
|
||||||
|
searchQuery.value = ''
|
||||||
|
searchResult.value = null
|
||||||
|
searchResultAccount.value = ''
|
||||||
|
await fetchSubSellers()
|
||||||
|
} catch (error) {
|
||||||
|
showError(error.response?.errorMsg || t('something_went_wrong'))
|
||||||
|
} finally {
|
||||||
|
isBinding.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const openTransfer = (seller) => {
|
||||||
|
transferTarget.value = seller
|
||||||
|
transferAmount.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeTransfer = () => {
|
||||||
|
transferTarget.value = null
|
||||||
|
transferAmount.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmTransfer = useThrottle(async () => {
|
||||||
|
if (!canTransfer.value) return
|
||||||
|
|
||||||
|
const acceptUserId = transferTarget.value.childUserId || transferTarget.value.userProfile?.id
|
||||||
|
const quantity = Number(transferAmount.value)
|
||||||
|
try {
|
||||||
|
isTransferring.value = true
|
||||||
|
const response = await transferFreightSubSeller({ acceptUserId, quantity })
|
||||||
|
if (response?.status) {
|
||||||
|
if (response.body !== undefined) {
|
||||||
|
currentBalance.value = response.body.toString()
|
||||||
|
}
|
||||||
|
showSuccess(t('sub_coin_seller_transfer_success'))
|
||||||
|
closeTransfer()
|
||||||
|
await fetchSubSellers()
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showError(error.response?.errorMsg || t('something_went_wrong'))
|
||||||
|
} finally {
|
||||||
|
isTransferring.value = false
|
||||||
|
}
|
||||||
|
}, 2000)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchBalance()
|
||||||
|
fetchSubSellers()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
* {
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-sellers-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 16px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-card,
|
||||||
|
.search-card,
|
||||||
|
.seller-item {
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #ffb627;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-row span {
|
||||||
|
color: #ffb627;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 24px;
|
||||||
|
border: 1px solid #ffffff;
|
||||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box img {
|
||||||
|
width: 22px;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input,
|
||||||
|
.amount-input {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
background: transparent;
|
||||||
|
font-weight: 600;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box input {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card,
|
||||||
|
.seller-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-main img {
|
||||||
|
width: 44px;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-text {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-name {
|
||||||
|
font-weight: 800;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-id {
|
||||||
|
margin-top: 3px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-btn,
|
||||||
|
.ghost-btn,
|
||||||
|
.text-btn {
|
||||||
|
border: none;
|
||||||
|
font-weight: 800;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-btn {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 9px 14px;
|
||||||
|
background: linear-gradient(135deg, #bb92ff 2.82%, #8b45ff 99.15%);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-btn:disabled {
|
||||||
|
background: #d1d5db;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact {
|
||||||
|
min-width: 76px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-btn {
|
||||||
|
background: transparent;
|
||||||
|
color: #8b45ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ghost-btn {
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 9px 14px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seller-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seller-item {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 24px 12px;
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-wrap {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transfer-modal {
|
||||||
|
width: 82%;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 900;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-target {
|
||||||
|
text-align: center;
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount-input {
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||||
|
padding: 0 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 360px) {
|
||||||
|
* {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 360px) {
|
||||||
|
* {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
* {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -92,6 +92,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 超级经销商子 coin seller 管理入口 -->
|
||||||
|
<button v-if="isSuperDealer" class="sub-seller-entry" @click="goToSubSellers">
|
||||||
|
<span>{{ t('invite_sub_coin_seller') }}</span>
|
||||||
|
<span class="entry-arrow">›</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- 设置最小接收金额 -->
|
<!-- 设置最小接收金额 -->
|
||||||
<div
|
<div
|
||||||
style="
|
style="
|
||||||
@ -422,6 +428,7 @@ const hasRechargeRatio = computed(() => {
|
|||||||
Object.prototype.hasOwnProperty.call(freightThreshold.value, 'rechargeRatio')
|
Object.prototype.hasOwnProperty.call(freightThreshold.value, 'rechargeRatio')
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
const isSuperDealer = computed(() => Boolean(freightThreshold.value?.superDealer))
|
||||||
|
|
||||||
// 选项样式
|
// 选项样式
|
||||||
const amountStyle = (amountItem) => {
|
const amountStyle = (amountItem) => {
|
||||||
@ -647,6 +654,11 @@ const searchUser = () => {
|
|||||||
router.push('/coin-seller-search')
|
router.push('/coin-seller-search')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 超级经销商入口只做展示,绑定和转账权限由后端再次校验.
|
||||||
|
const goToSubSellers = () => {
|
||||||
|
router.push('/coin-seller/sub-sellers')
|
||||||
|
}
|
||||||
|
|
||||||
// 币商充值金币
|
// 币商充值金币
|
||||||
const rechargeNow = useThrottle(async () => {
|
const rechargeNow = useThrottle(async () => {
|
||||||
if (!canRecharge.value || isRecharging.value) return
|
if (!canRecharge.value || isRecharging.value) return
|
||||||
@ -820,6 +832,37 @@ onMounted(() => {})
|
|||||||
color: #d97706;
|
color: #d97706;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sub-seller-entry {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 14px 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-seller-entry span:first-child {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry-arrow {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: #8b45ff;
|
||||||
|
font-size: 1.6em;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* 用户搜索部分 */
|
/* 用户搜索部分 */
|
||||||
.user-section {
|
.user-section {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user