aslan-h5/src/views/CoinSellerView.vue
2025-08-25 11:30:11 +08:00

587 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="coin-seller gradient-background-circles">
<MobileHeader title="Coin Seller" />
<!-- 权限校验加载状态 -->
<div v-if="checkingAccess" class="loading-container">
<div class="loading-spinner"></div>
<p>Verifying permissions...</p>
</div>
<!-- 主要内容 -->
<div v-else-if="dealerAccess" class="content">
<!-- 用户信息卡片 -->
<div class="user-card">
<div class="user-info">
<div class="avatar">
<img
v-if="userInfo.userAvatar"
:src="userInfo.userAvatar"
:alt="userInfo.userNickname || userInfo.name"
class="avatar-image"
@error="handleAvatarError"
/>
<span v-else class="avatar-text">{{ (userInfo.userNickname || userInfo.name).charAt(0) }}</span>
</div>
<div class="user-details">
<h3>{{ userInfo.userNickname || userInfo.name }}</h3>
<p>ID: {{ userInfo.id || userInfo.id }}</p>
</div>
<button class="settings-btn" @click="goToSettings">
<span>📈</span>
</button>
</div>
<!-- 账户状态标签 -->
<div class="account-tags">
<span class="tag seller-tag">🪙 Salary</span>
</div>
</div>
<!-- 我的金币 -->
<div class="coins-section">
<h3>My coins:</h3>
<div class="coins-display">
<span class="coin-icon">🪙</span>
<span v-if="loadingBalance" class="coins-loading">Loading...</span>
<span v-else class="coins-amount">{{ coinsAmount }}</span>
</div>
</div>
<!-- 用户搜索部分 -->
<div class="user-section">
<h3>User:</h3>
<div v-if="selectedUser.id" class="selected-user">
<div class="user-info">
<div class="user-avatar">
<span>{{ selectedUser.name.charAt(0) }}</span>
</div>
<div class="user-details">
<div class="user-name">{{ selectedUser.name }}</div>
<div class="user-id">ID: {{ selectedUser.id }}</div>
</div>
</div>
<button class="change-btn" @click="searchUser">Change</button>
</div>
<div v-else class="search-placeholder" @click="searchUser">
<span>Search</span>
</div>
</div>
<!-- 充值部分 -->
<div class="recharge-section">
<h3>Recharge:</h3>
<div class="recharge-input">
<input
v-model="rechargeAmount"
type="number"
placeholder="Please Enter The Amount Of Gold Coins To Transfer"
class="amount-input"
/>
</div>
<button
class="recharge-btn"
:disabled="!canRecharge || isRecharging"
@click="rechargeNow"
>
{{ isRecharging ? 'Processing...' : 'Recharge now' }}
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue'
import { getSelectedUser } from '../utils/coinSellerStore.js'
import { checkFreightDealer, getFreightBalance, freightRecharge } from '../api/wallet.js'
import {showError, showSuccess} from "@/utils/toast.js";
import {usePageInitializationWithConfig} from "@/utils/pageConfig.js";
const router = useRouter()
// 权限校验状态
const dealerAccess = ref(false)
const checkingAccess = ref(true)
// 金币数量
const coinsAmount = ref('0')
const loadingBalance = ref(false)
// 选中的用户
const selectedUser = ref({
id: '',
name: ''
})
// 校验销售商权限
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('You do not have gold coin seller rights.')
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 handleAvatarError = () => {
userInfo.value.userAvatar = null
}
// 初始化用户信息
const initializeUser = () => {
const savedUser = getSelectedUser()
if (savedUser && savedUser.id) {
selectedUser.value = { ...savedUser }
}
}
// 充值金额
const rechargeAmount = ref('')
const isRecharging = ref(false)
// 是否可以充值
const canRecharge = computed(() => {
return selectedUser.value.id && rechargeAmount.value && parseFloat(rechargeAmount.value) > 0 && !isRecharging.value
})
// 跳转到设置
const goToSettings = () => {
router.push('/seller-records')
}
// 搜索用户
const searchUser = () => {
router.push('/coin-seller-search')
}
// 立即充值
const rechargeNow = async () => {
if (!canRecharge.value || isRecharging.value) return
const amount = parseFloat(rechargeAmount.value)
if (amount <= 0) {
showError('Please enter the correct recharge amount')
return
}
// 需要获取接收用户的ID从用户搜索结果中获取
const acceptUserId = selectedUser.value.userId || selectedUser.value.id
if (!acceptUserId) {
showError('The user ID cannot be obtained. Please select the user again')
return
}
try {
isRecharging.value = true
const rechargeData = {
acceptUserId: parseInt(acceptUserId),
quantity: amount
}
const response = await freightRecharge(rechargeData)
if (response && response.status) {
// 充值成功,更新余额
if (response.body !== undefined) {
coinsAmount.value = response.body.toString()
}
showSuccess(`成功向 ${selectedUser.value.name} 充值 ${amount} 金币`)
// 重置表单
rechargeAmount.value = ''
} else {
showError('充值失败,请重试')
}
} catch (error) {
console.error('充值失败:', error)
showError('充值失败,请检查网络后重试')
} finally {
isRecharging.value = false
}
}
const {
userInfo
} = usePageInitializationWithConfig('COIN_SELLER', {
onDataLoaded: (data) => {
checkDealerAccess()
fetchFreightBalance()
initializeUser()
}
})
</script>
<style scoped>
.coin-seller {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
/* 加载状态 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
color: #666;
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid #f3f3f3;
border-top: 3px solid #F59E0B;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 12px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.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 {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 25px;
background-color: #F59E0B;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: 600;
margin-right: 12px;
overflow: hidden;
position: relative;
}
.avatar-image {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 25px;
}
.avatar-text {
color: white;
font-size: 20px;
font-weight: 600;
}
.user-details {
flex: 1;
}
.user-details h3 {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.user-details p {
margin: 0;
font-size: 14px;
color: #666;
}
.settings-btn {
width: 32px;
height: 32px;
border: none;
background: none;
font-size: 16px;
cursor: pointer;
}
.account-tags {
display: flex;
gap: 8px;
}
.tag {
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 600;
}
.seller-tag {
background-color: #FEF3C7;
color: #D97706;
}
/* 金币部分 */
.coins-section {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.coins-section h3 {
margin: 0 0 12px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.coins-display {
display: flex;
align-items: center;
gap: 8px;
}
.coin-icon {
font-size: 24px;
}
.coins-amount {
font-size: 20px;
font-weight: 600;
color: #F59E0B;
}
.coins-loading {
font-size: 16px;
color: #9ca3af;
font-style: italic;
}
/* 用户搜索部分 */
.user-section {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.user-section h3 {
margin: 0 0 12px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.selected-user {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
}
.selected-user .user-info {
display: flex;
align-items: center;
margin-bottom: 0;
}
.user-avatar {
width: 40px;
height: 40px;
border-radius: 20px;
background-color: #8B5CF6;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 16px;
font-weight: 600;
margin-right: 12px;
}
.selected-user .user-details {
flex: 1;
}
.user-name {
font-size: 14px;
font-weight: 600;
color: #333;
margin-bottom: 2px;
}
.user-id {
font-size: 12px;
color: #666;
}
.change-btn {
background-color: #C084FC;
color: white;
border: none;
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
}
.change-btn:active {
background-color: #A855F7;
}
.search-placeholder {
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
border: 2px dashed #ddd;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
background-color: #fafafa;
}
.search-placeholder:hover {
border-color: #F59E0B;
background-color: #fef5e7;
}
.search-placeholder span {
color: #666;
font-size: 14px;
font-weight: 500;
}
/* 充值部分 */
.recharge-section {
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.recharge-section h3 {
margin: 0 0 12px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.recharge-input {
position: relative;
margin-bottom: 16px;
}
.amount-input {
width: 100%;
padding: 12px 16px;
border: 1px solid #e5e7eb;
border-radius: 8px;
font-size: 14px;
background-color: #f9fafb;
box-sizing: border-box;
}
.amount-input:focus {
outline: none;
border-color: #F59E0B;
background-color: white;
}
.amount-input::placeholder {
color: #9ca3af;
}
.currency-suffix {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
color: #666;
}
.recharge-btn {
width: 100%;
padding: 14px;
background-color: #8B5CF6;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.recharge-btn:not(:disabled):hover {
background-color: #7C3AED;
}
.recharge-btn:not(:disabled):active {
background-color: #6D28D9;
}
.recharge-btn:disabled {
background-color: #D1D5DB;
cursor: not-allowed;
}
</style>