959 lines
23 KiB
Vue
959 lines
23 KiB
Vue
<template>
|
||
<div class="coin-seller gradient-background-circles">
|
||
<!-- 使用 GeneralHeader 替换 MobileHeader -->
|
||
<GeneralHeader
|
||
:isHomePage="true"
|
||
:showLanguageList="true"
|
||
:title="t('recharge_agency')"
|
||
color="black"
|
||
style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); z-index: 999"
|
||
/>
|
||
|
||
<!-- 权限校验加载状态 -->
|
||
<div v-if="checkingAccess" class="loading-container">
|
||
<LoadingSpinner />
|
||
<p>{{ t('checking_permissions') }}...</p>
|
||
</div>
|
||
|
||
<!-- 主要内容 -->
|
||
<div v-else-if="dealerAccess" class="content">
|
||
<!-- 身份 -->
|
||
<div style="display: flex; justify-content: space-between">
|
||
<div
|
||
style="
|
||
margin: 0 1%;
|
||
margin-bottom: 12px;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 1.3em;
|
||
"
|
||
>
|
||
{{ t('my_account') }}
|
||
<img
|
||
src="../../assets/icon/identity/coinSeller.png"
|
||
alt=""
|
||
height="20px"
|
||
style="display: block; margin-left: 10px"
|
||
/>
|
||
</div>
|
||
<img
|
||
@click="goToRecords"
|
||
src="../../assets/icon/Azizi/records.png"
|
||
height="20px"
|
||
alt=""
|
||
style="display: block; object-fit: cover"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 用户信息卡片 -->
|
||
<div class="user-card">
|
||
<!-- 个人信息 -->
|
||
<div class="user-info">
|
||
<div class="avatar">
|
||
<img
|
||
:src="userInfo.userAvatar || ''"
|
||
alt=""
|
||
style="
|
||
display: block;
|
||
object-fit: cover;
|
||
width: 100%;
|
||
aspect-ratio: 1/1;
|
||
border-radius: 50%;
|
||
"
|
||
@error="handleAvatarImageError"
|
||
/>
|
||
</div>
|
||
<div class="user-details">
|
||
<h3>{{ userInfo.userNickname || userInfo.name }}</h3>
|
||
<p>
|
||
<span style="display: flex; align-items: center">
|
||
<span>ID</span>
|
||
<span style="margin: 0 2px">:</span>
|
||
<span>{{ userInfo.id }}</span>
|
||
</span>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 我的金币 -->
|
||
<div>
|
||
<div style="font-weight: 600">{{ t('my_coins') }}</div>
|
||
<div style="margin-top: 12px; width: 100%; display: flex; align-items: center">
|
||
<img
|
||
src="../../assets/icon/Azizi/coin.png"
|
||
alt=""
|
||
height="20px"
|
||
style="display: block"
|
||
/>
|
||
<div style="color: #ffb627; font-weight: 590; margin-left: 5px">
|
||
{{ coinsAmount }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 设置最小接收金额 -->
|
||
<div
|
||
style="
|
||
background-color: white;
|
||
padding: 16px;
|
||
border-radius: 12px;
|
||
margin-bottom: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
"
|
||
>
|
||
<div style="display: flex; justify-content: space-between; align-items: center; gap: 4px">
|
||
<div style="font-weight: 600">{{ t('min_transfer_amount') }}</div>
|
||
<img
|
||
src="../../assets/icon/Azizi/help.png"
|
||
height="20px"
|
||
alt=""
|
||
style="display: block; object-fit: cover"
|
||
@click="showHelpTip = true"
|
||
/>
|
||
</div>
|
||
<div style="display: flex; justify-content: space-around; align-items: center; gap: 10px">
|
||
<div
|
||
v-for="amountItem in AmountList"
|
||
style="
|
||
flex: 1;
|
||
min-width: 0;
|
||
align-self: stretch;
|
||
|
||
border-radius: 12px;
|
||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||
|
||
padding: 10px;
|
||
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
"
|
||
:style="amountStyle(amountItem)"
|
||
@click="selectAmount(amountItem)"
|
||
>
|
||
<div style="font-weight: 700">{{ amountItem.type }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 用户搜索部分 -->
|
||
<div class="user-section">
|
||
<div style="margin-bottom: 12px; font-weight: 600; color: #333">
|
||
{{ t('user') }}
|
||
</div>
|
||
<!-- 有用户 -->
|
||
<div v-if="selectedUser.id" class="selected-user">
|
||
<div class="user-info">
|
||
<div class="user-avatar">
|
||
<img
|
||
:src="selectedUser.userAvatar || ''"
|
||
alt=""
|
||
style="
|
||
display: block;
|
||
object-fit: cover;
|
||
width: 100%;
|
||
aspect-ratio: 1/1;
|
||
border-radius: 50%;
|
||
"
|
||
@error="handleAvatarImageError"
|
||
/>
|
||
</div>
|
||
<div class="user-details">
|
||
<div class="user-name">
|
||
{{ selectedUser.name }}
|
||
</div>
|
||
<div class="user-id">
|
||
<span style="display: flex; align-items: center">
|
||
<span>ID</span>
|
||
<span style="margin: 0 2px">:</span>
|
||
<span>{{ selectedUser.account }}</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button class="change-btn" @click="searchUser">{{ t('change') }}</button>
|
||
</div>
|
||
<!-- 无用户 -->
|
||
<div v-else style="display: flex; justify-content: center; align-items: center">
|
||
<div class="search-placeholder" @click="searchUser">
|
||
<span>{{ t('search') }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 充值部分 -->
|
||
<div v-if="selectedUser.id" style="margin-top: 12px">
|
||
<div style="margin-bottom: 12px; font-weight: 600; color: #333">
|
||
{{ t('recharge') }}
|
||
</div>
|
||
<div></div>
|
||
<!-- 输入金额 -->
|
||
<div
|
||
style="
|
||
background-color: white;
|
||
padding: 10px 16px;
|
||
border-radius: 12px;
|
||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||
"
|
||
>
|
||
<input
|
||
v-model="rechargeAmount"
|
||
:placeholder="t('enter_recharge_amount')"
|
||
class="amount-input"
|
||
@input="preventDecimalInput"
|
||
@keydown="onKeyDown"
|
||
dir="ltr"
|
||
inputmode="decimal"
|
||
/>
|
||
</div>
|
||
|
||
<div style="margin: 10px 0 16px; display: flex; flex-direction: column; gap: 4px">
|
||
<div
|
||
v-if="rechargeCoinsNeeded == 0"
|
||
style="color: rgba(0, 0, 0, 0.4); font-weight: 600; font-size: 0.9em"
|
||
>
|
||
{{ t('recharge_auto_convert_tip') }}
|
||
</div>
|
||
<div v-else style="width: 100%; display: flex; align-items: center">
|
||
<img
|
||
src="../../assets/icon/Azizi/coin.png"
|
||
alt=""
|
||
height="15px"
|
||
style="display: block"
|
||
/>
|
||
<div style="color: #ffb627; font-weight: 590; margin-left: 5px">
|
||
{{ rechargeCoinsNeeded }}
|
||
</div>
|
||
</div>
|
||
<div style="color: rgba(0, 0, 0, 0.4); font-weight: 600; font-size: 0.9em">
|
||
{{ t('recharge_ratio_text', { ratio: rechargeRatio }) }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 按钮 -->
|
||
<div style="display: flex; justify-content: center">
|
||
<button
|
||
class="recharge-btn"
|
||
:disabled="!canRecharge || isRecharging"
|
||
@click="rechargeNow"
|
||
>
|
||
{{ isRecharging ? t('loading') : t('recharge_now') }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 遮罩层 -->
|
||
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
|
||
<div
|
||
style="
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
"
|
||
>
|
||
<!-- 帮助提示弹窗 -->
|
||
<div
|
||
v-if="showHelpTip"
|
||
style="
|
||
width: 80%;
|
||
border-radius: 12px;
|
||
background: #fff;
|
||
padding: 20px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8px;
|
||
"
|
||
@click.stop
|
||
>
|
||
<div style="position: relative; width: 100%">
|
||
<div style="text-align: center; color: rgba(0, 0, 0, 0.8); font-weight: 800">
|
||
{{ t('tips') }}
|
||
</div>
|
||
|
||
<!-- 关闭按钮 -->
|
||
<div style="position: absolute; top: 0; right: 0" @click="closedPopup">X</div>
|
||
</div>
|
||
<div style="color: rgba(0, 0, 0, 0.5); font-weight: 600; text-align: center">
|
||
{{ t('min_transfer_amount_tip') }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 设置转账确认弹窗 -->
|
||
<div
|
||
v-if="showTransfersTip"
|
||
style="
|
||
width: 80%;
|
||
border-radius: 12px;
|
||
background: #fff;
|
||
padding: 20px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8px;
|
||
"
|
||
@click.stop
|
||
>
|
||
<div style="color: rgba(0, 0, 0, 0.8); font-weight: 800">{{ t('tips') }}</div>
|
||
<div style="color: rgba(0, 0, 0, 0.5); font-weight: 600; text-align: center">
|
||
{{ t('confirm_transfer_limit') }}
|
||
</div>
|
||
<div
|
||
style="width: 100%; display: flex; justify-content: space-around; align-items: center"
|
||
>
|
||
<div
|
||
style="
|
||
padding: 12px 20px;
|
||
border-radius: 12px;
|
||
border: 1px solid #e6e6e6;
|
||
color: rgba(0, 0, 0, 0.4);
|
||
font-weight: 800;
|
||
"
|
||
@click="Cancel"
|
||
>
|
||
{{ t('cancel') }}
|
||
</div>
|
||
<div
|
||
style="
|
||
padding: 12px 20px;
|
||
border-radius: 12px;
|
||
background: linear-gradient(
|
||
152deg,
|
||
rgba(198, 112, 255, 0.6) 7.01%,
|
||
rgba(119, 38, 255, 0.6) 92.99%
|
||
);
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-weight: 800;
|
||
"
|
||
@click="Confirm"
|
||
>
|
||
{{ t('confirm') }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</maskLayer>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { useI18n } from 'vue-i18n'
|
||
import { getUserId } from '@/utils/userStore.js'
|
||
import { setDocumentDirection } from '@/locales/i18n'
|
||
import { getSelectedUser } from '@/utils/coinSellerStore.js'
|
||
import { showError, showSuccess } from '@/utils/toast.js'
|
||
import { usePageInitializationWithConfig } from '@/utils/pageConfig.js'
|
||
import { handleAvatarImageError } from '@/utils/image/imageHandler.js'
|
||
import { useDebounce, useThrottle } from '@/utils/useDebounce'
|
||
|
||
import {
|
||
checkFreightDealer,
|
||
getFreightBalance,
|
||
freightRecharge,
|
||
apiGetFreightThreshold, //获取金币代理最小收入金额
|
||
apiSetThreshold, // 金币代理设置最小收入金额
|
||
} from '@/api/wallet.js'
|
||
|
||
import GeneralHeader from '@/components/GeneralHeader.vue'
|
||
import maskLayer from '@/components/MaskLayer.vue'
|
||
|
||
const { t, locale } = useI18n()
|
||
const router = useRouter()
|
||
|
||
// 监听语言变化并设置文档方向
|
||
locale.value && setDocumentDirection(locale.value)
|
||
|
||
// 权限校验状态
|
||
const dealerAccess = ref(false)
|
||
const checkingAccess = ref(true)
|
||
|
||
// 金币数量
|
||
const coinsAmount = ref('0')
|
||
const loadingBalance = ref(false)
|
||
|
||
const freightThreshold = ref(null)
|
||
|
||
const AmountList = computed(() => {
|
||
return [
|
||
{
|
||
id: 1,
|
||
type: '>$0',
|
||
value: 0,
|
||
selectedStatus: freightThreshold.value?.deliveryThreshold == 0,
|
||
},
|
||
{
|
||
id: 2,
|
||
type: '>=$10',
|
||
value: 10,
|
||
selectedStatus: freightThreshold.value?.deliveryThreshold == 10,
|
||
},
|
||
{
|
||
id: 3,
|
||
type: '>=$50',
|
||
value: 50,
|
||
selectedStatus: freightThreshold.value?.deliveryThreshold == 50,
|
||
},
|
||
]
|
||
})
|
||
|
||
const selectedAmount = ref({})
|
||
|
||
const isAbleSelect = ref(false) // 是否可以设置
|
||
const rechargeRatio = ref(0) // 充值比例,1美元兑换多少金币
|
||
|
||
// 选项样式
|
||
const amountStyle = (amountItem) => {
|
||
if (amountItem.selectedStatus) {
|
||
return 'border: 1px solid #7726ff;background: #fff;'
|
||
} else if (isAbleSelect.value) {
|
||
return 'border: 1px solid transparent;background: transparent;'
|
||
} else {
|
||
return 'border: 1px solid transparent;background: rgba(0, 0, 0, 0.2);'
|
||
}
|
||
}
|
||
|
||
// 弹窗提示
|
||
const showHelpTip = ref(false) //帮助提示弹窗
|
||
const showTransfersTip = ref(false) //设置转账确认弹窗
|
||
const maskLayerShow = computed(() => {
|
||
return showHelpTip.value || showTransfersTip.value
|
||
})
|
||
|
||
// 选中的用户
|
||
const selectedUser = ref({
|
||
id: '',
|
||
name: '',
|
||
})
|
||
|
||
// 关闭弹窗
|
||
const closedPopup = () => {
|
||
showHelpTip.value = false
|
||
showTransfersTip.value = false
|
||
}
|
||
|
||
// 选择限制转账金额
|
||
const selectAmount = (amountItem) => {
|
||
// 不可选择或者已选择
|
||
if (!isAbleSelect.value || amountItem.selectedStatus) return
|
||
|
||
console.log('选择限制转账金额', amountItem)
|
||
selectedAmount.value = amountItem //设置选中的金额
|
||
showTransfersTip.value = true //展示确认弹窗
|
||
}
|
||
|
||
// 取消选择
|
||
const Cancel = () => {
|
||
console.log('取消选择')
|
||
|
||
selectedAmount.value = {} //清空选中的金额
|
||
closedPopup()
|
||
}
|
||
|
||
// 确认选择
|
||
const Confirm = () => {
|
||
console.log('确认选择')
|
||
|
||
// 发送接口
|
||
setThreshold()
|
||
|
||
closedPopup()
|
||
}
|
||
|
||
// 键盘按下事件,阻止某些按键
|
||
const onKeyDown = (event) => {
|
||
// 阻止小数点、e、+、- 等特殊字符
|
||
if (['.', 'e', '+', '-'].includes(event.key)) {
|
||
event.preventDefault()
|
||
}
|
||
}
|
||
|
||
// 校验销售商权限
|
||
const checkDealerAccess = async () => {
|
||
try {
|
||
checkingAccess.value = true
|
||
const response = await checkFreightDealer()
|
||
|
||
if (response && response.status !== undefined) {
|
||
dealerAccess.value = response.body === true
|
||
|
||
if (!dealerAccess.value) {
|
||
// 没有权限,跳转回上一页或首页
|
||
showError(t('not_authorized'))
|
||
router.go(-1)
|
||
return
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('Permission verification failed:', error)
|
||
dealerAccess.value = false
|
||
router.go(-1)
|
||
} finally {
|
||
checkingAccess.value = false
|
||
}
|
||
}
|
||
|
||
// 获取金币余额
|
||
const fetchFreightBalance = async () => {
|
||
try {
|
||
loadingBalance.value = true
|
||
const response = await getFreightBalance()
|
||
|
||
if (response && response.status && response.body !== undefined) {
|
||
coinsAmount.value = response.body.toString()
|
||
}
|
||
} catch (error) {
|
||
console.error('获取金币余额失败:', error)
|
||
} finally {
|
||
loadingBalance.value = false
|
||
}
|
||
}
|
||
|
||
// 获取金币代理最小收入金额
|
||
const getFreightThreshold = async () => {
|
||
const resFreightThreshold = await apiGetFreightThreshold(userInfo.id)
|
||
console.log('任务列表:', resFreightThreshold)
|
||
if (resFreightThreshold.status && resFreightThreshold.body) {
|
||
freightThreshold.value = resFreightThreshold.body
|
||
isAbleSelect.value = !resFreightThreshold.body?.settinged //是否可以设置
|
||
rechargeRatio.value = resFreightThreshold.body?.rechargeRatio || 0 //充值比例
|
||
}
|
||
}
|
||
|
||
// 金币代理设置最小收入金额
|
||
const setThreshold = async () => {
|
||
try {
|
||
let data = {
|
||
deliveryThreshold: selectedAmount.value.value,
|
||
}
|
||
await apiSetThreshold(data) // 金币代理设置最小收入金额
|
||
selectedAmount.value = {}
|
||
getFreightThreshold() //获取金币代理最小收入金额
|
||
} catch (error) {
|
||
console.log('设置失败:', error)
|
||
}
|
||
}
|
||
|
||
// 初始化用户信息
|
||
const initializeUser = () => {
|
||
const savedUser = getSelectedUser()
|
||
if (savedUser && savedUser.id) {
|
||
selectedUser.value = { ...savedUser }
|
||
}
|
||
}
|
||
|
||
// 充值金额
|
||
const rechargeAmount = ref('')
|
||
const isRecharging = ref(false)
|
||
const currentCoinBalance = computed(() => {
|
||
return Number(coinsAmount.value) || 0
|
||
})
|
||
const rechargeDollarAmount = computed(() => {
|
||
return Number(rechargeAmount.value) || 0
|
||
})
|
||
const rechargeCoinsNeeded = computed(() => {
|
||
return rechargeDollarAmount.value * (Number(rechargeRatio.value) || 0)
|
||
})
|
||
|
||
// 是否可以充值
|
||
const canRecharge = computed(() => {
|
||
return (
|
||
selectedUser.value.id &&
|
||
rechargeAmount.value &&
|
||
rechargeDollarAmount.value > 0 &&
|
||
Number(rechargeRatio.value) > 0 &&
|
||
rechargeCoinsNeeded.value > 0 &&
|
||
rechargeCoinsNeeded.value <= currentCoinBalance.value &&
|
||
!isRecharging.value
|
||
)
|
||
})
|
||
|
||
// 防止输入小数点的函数
|
||
const preventDecimalInput = (event) => {
|
||
let value = event.target.value
|
||
|
||
// 移除小数点和其他非整数字符
|
||
value = value.replace(/[^0-9]/g, '')
|
||
|
||
// 确保最小值为1
|
||
if (value === '' || parseInt(value) < 1) {
|
||
value = ''
|
||
}
|
||
|
||
// 更新输入框的值
|
||
event.target.value = value
|
||
|
||
rechargeAmount.value = parseFloat(value) || 0
|
||
}
|
||
|
||
// 跳转到设置
|
||
const goToRecords = () => {
|
||
router.push('/seller-records')
|
||
}
|
||
|
||
// 搜索用户
|
||
const searchUser = () => {
|
||
router.push('/coin-seller-search')
|
||
}
|
||
|
||
// 币商充值金币
|
||
const rechargeNow = useThrottle(async () => {
|
||
if (!canRecharge.value || isRecharging.value) return
|
||
|
||
const amount = rechargeDollarAmount.value
|
||
const quantity = rechargeCoinsNeeded.value
|
||
if (amount <= 0) {
|
||
showError(t('please_enter_valid_amount'))
|
||
return
|
||
}
|
||
|
||
if (quantity <= 0 || quantity > currentCoinBalance.value) {
|
||
return
|
||
}
|
||
|
||
// 需要获取接收用户的ID(从用户搜索结果中获取)
|
||
const acceptUserId = selectedUser.value.id
|
||
if (!acceptUserId) {
|
||
showError(t('user_not_found_or_search_failed'))
|
||
return
|
||
}
|
||
|
||
try {
|
||
isRecharging.value = true
|
||
|
||
const rechargeData = {
|
||
acceptUserId: acceptUserId,
|
||
quantity: quantity,
|
||
amount: amount,
|
||
}
|
||
|
||
const response = await freightRecharge(rechargeData)
|
||
|
||
if (response && response.status) {
|
||
// 充值金币成功,更新余额
|
||
if (response.body !== undefined) {
|
||
coinsAmount.value = response.body.toString()
|
||
}
|
||
|
||
showSuccess(
|
||
t('transfer_coin_success', {
|
||
amount: quantity,
|
||
name: selectedUser.value.name,
|
||
}),
|
||
)
|
||
|
||
// 重置表单
|
||
rechargeAmount.value = ''
|
||
} else {
|
||
showError(
|
||
t('transfer_coin_failed', {
|
||
amount: quantity,
|
||
}),
|
||
)
|
||
}
|
||
} catch (error) {
|
||
console.error('币商充值金币失败:', error)
|
||
showError(
|
||
error.response.errorMsg ||
|
||
t('transfer_coin_failed', {
|
||
amount: quantity,
|
||
}),
|
||
)
|
||
} finally {
|
||
isRecharging.value = false
|
||
}
|
||
}, 2000)
|
||
|
||
const { userInfo } = usePageInitializationWithConfig('COIN_SELLER', {
|
||
onDataLoaded: (data) => {
|
||
checkDealerAccess()
|
||
fetchFreightBalance()
|
||
initializeUser()
|
||
getFreightThreshold() //获取金币代理最小收入金额
|
||
},
|
||
})
|
||
|
||
onMounted(() => {})
|
||
</script>
|
||
|
||
<style scoped>
|
||
* {
|
||
color: rgba(0, 0, 0, 0.8);
|
||
}
|
||
|
||
/* 加载状态 */
|
||
.loading-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 40px 20px;
|
||
color: #666;
|
||
}
|
||
|
||
.content {
|
||
padding: 16px;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
|
||
/* 用户信息卡片 */
|
||
.user-card {
|
||
background-color: white;
|
||
padding: 16px;
|
||
border-radius: 12px;
|
||
margin-bottom: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.user-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.avatar {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 25px;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.user-details {
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.user-details h3 {
|
||
margin-bottom: 4px;
|
||
font-weight: 700;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.user-details p {
|
||
color: rgba(0, 0, 0, 0.4);
|
||
font-size: 0.9em;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.settings-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: none;
|
||
background: none;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.account-tags {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.tag {
|
||
padding: 4px 12px;
|
||
border-radius: 16px;
|
||
font-size: 0.8em;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.seller-tag {
|
||
background-color: #fef3c7;
|
||
color: #d97706;
|
||
}
|
||
|
||
/* 用户搜索部分 */
|
||
.user-section {
|
||
background-color: white;
|
||
padding: 16px;
|
||
border-radius: 12px;
|
||
margin-bottom: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.selected-user {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 12px;
|
||
border-radius: 12px;
|
||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||
}
|
||
|
||
.selected-user .user-info {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.selected-user .user-details {
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.user-name {
|
||
font-size: 0.9em;
|
||
font-weight: 700;
|
||
margin-bottom: 2px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.user-id {
|
||
font-size: 0.8em;
|
||
font-weight: 500;
|
||
color: rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
.change-btn {
|
||
border-radius: 12px;
|
||
background: linear-gradient(
|
||
152deg,
|
||
rgba(198, 112, 255, 0.6) 7.01%,
|
||
rgba(119, 38, 255, 0.6) 92.99%
|
||
);
|
||
color: white;
|
||
border: none;
|
||
padding: 6px 12px;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.change-btn:active {
|
||
background-color: #a855f7;
|
||
}
|
||
|
||
.search-placeholder {
|
||
padding: 12px 20px;
|
||
border: 1px solid #ddd;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.search-placeholder:hover {
|
||
border-color: #f59e0b;
|
||
background-color: #fef5e7;
|
||
}
|
||
|
||
.search-placeholder span {
|
||
color: #666;
|
||
font-size: 0.9em;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.amount-input {
|
||
width: 100%;
|
||
border: none;
|
||
font-size: 0.9em;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.amount-input:focus {
|
||
outline: none;
|
||
}
|
||
|
||
.amount-input::placeholder {
|
||
font-size: 0.7em;
|
||
color: rgba(0, 0, 0, 0.4);
|
||
font-weight: 500;
|
||
}
|
||
|
||
input[type='number'] {
|
||
font-family: 'Arial', sans-serif; /* 使用支持西方数字的字体 */
|
||
direction: ltr; /* 强制从左到右 */
|
||
}
|
||
|
||
.currency-suffix {
|
||
position: absolute;
|
||
right: 12px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
font-size: 0.8em;
|
||
color: #666;
|
||
}
|
||
|
||
.recharge-btn {
|
||
width: 80%;
|
||
padding: 12px;
|
||
border-radius: 32px;
|
||
background: linear-gradient(135deg, #bb92ff 2.82%, #8b45ff 99.15%);
|
||
color: white;
|
||
border: none;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.recharge-btn:not(:disabled):active {
|
||
background: linear-gradient(135deg, #b080ff 2.82%, #6302ff 99.15%);
|
||
}
|
||
|
||
.recharge-btn:disabled {
|
||
background: #d1d5db;
|
||
cursor: not-allowed;
|
||
}
|
||
|
||
@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: 24px;
|
||
}
|
||
}
|
||
|
||
/* RTL支持 */
|
||
[dir='rtl'] .records-icon {
|
||
transform: scaleX(-1);
|
||
}
|
||
|
||
[dir='rtl'] .avatar {
|
||
margin-right: 0;
|
||
margin-left: 12px;
|
||
}
|
||
|
||
[dir='rtl'] .user-avatar {
|
||
margin-right: 0;
|
||
margin-left: 12px;
|
||
}
|
||
|
||
[dir='rtl'] .change-btn {
|
||
margin-left: 0;
|
||
margin-right: 12px;
|
||
}
|
||
</style>
|