Files
lilishop-uniapp/pages/mine/distribution/bank-accounts.vue
田香琪 c12c76f6f5 feat(distribution): 添加分销员状态检查与加载指示
- 在多个分销相关页面中引入分销员状态检查,确保用户在访问前具备有效分销资格。
- 增加加载指示器以改善用户体验,提示用户正在加载数据。
- 更新相关逻辑以处理分销员资格的不同状态,确保用户在不符合条件时获得适当反馈。
2026-09-09 13:21:53 +08:00

392 lines
11 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>
<view class="page" :style="themeStyle">
<view class="content">
<!-- 加载中 -->
<view v-if="loading" class="state-wrap">
<text class="state-text">加载中...</text>
</view>
<!-- 账户列表 -->
<view v-else-if="pageReady && accounts.length" class="account-list">
<view
class="account-item"
v-for="item in accounts"
:key="item.id"
@click="handleSelect(item)"
>
<view class="item-left">
<view v-if="isSelectMode" class="radio-circle" :class="{ active: item.id === selectedId }">
<view class="radio-dot" v-if="item.id === selectedId" />
</view>
<view class="item-info">
<text class="item-name">{{ item.holderName }}</text>
<view class="item-meta">
<text class="item-bank">{{ item.bankName }}</text>
<text class="item-card">{{ maskCard(item.cardNo) }}</text>
</view>
</view>
<view v-if="!isSelectMode && item.isDefault" class="default-tag">默认</view>
</view>
<view class="item-actions">
<view v-if="!isSelectMode && !item.isDefault" class="set-default-btn" @click.stop="handleSetDefault(item.id)">
<text class="set-default-text">设为默认</text>
</view>
<view class="item-delete" @click.stop="handleDelete(item.id)">
<u-icon name="trash" color="#ccc" size="18" />
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view v-else-if="pageReady" class="empty-wrap">
<text class="empty-text">暂无银行卡请添加</text>
</view>
<!-- 添加账户按钮 -->
<view v-if="pageReady" class="add-btn-wrap">
<view class="add-btn" @click="openAddPopup">+ 添加账户</view>
</view>
</view>
<!-- 添加账户 Popup -->
<u-popup v-model:show="addPopupVisible" mode="bottom" round="16">
<view class="popup-wrap">
<view class="popup-title">添加到账账户</view>
<view class="form-item">
<text class="form-label">姓名</text>
<input
class="form-input"
v-model="form.holderName"
placeholder="请输入收款人姓名"
placeholder-class="form-placeholder"
/>
</view>
<view class="form-divider" />
<view class="form-item">
<text class="form-label">银行</text>
<input
class="form-input"
v-model="form.bankName"
placeholder="如:中国工商银行"
placeholder-class="form-placeholder"
/>
</view>
<view class="form-divider" />
<view class="form-item">
<text class="form-label">卡号</text>
<input
class="form-input"
v-model="form.cardNo"
type="number"
placeholder="请输入银行卡号"
placeholder-class="form-placeholder"
/>
</view>
<view class="popup-actions">
<view class="popup-btn ghost" @click="addPopupVisible = false">取消</view>
<view class="popup-btn primary" :class="{ disabled: saveLoading }" @click="saveAccount">
{{ saveLoading ? '保存中...' : '保存' }}
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { getThemeStyle } from '@/utils/theme'
import { getBankCards, addBankCard, deleteBankCard, setDefaultBankCard } from '@/api/distribution'
import { assertActiveDistributor } from '@/utils/distributionStatus'
const store = useStore()
const themeStyle = computed(() => getThemeStyle(store.state.theme))
// 从 getStorageSync 读取上次选择的默认卡 id仅选择模式使用
const SELECTED_KEY = 'dist_selected_account_id'
const isSelectMode = ref(false)
const accounts = ref<any[]>([])
const selectedId = ref('')
const pageReady = ref(false)
const loading = ref(true)
const addPopupVisible = ref(false)
const saveLoading = ref(false)
const form = ref({ holderName: '', bankName: '', cardNo: '' })
onLoad((options: any) => {
isSelectMode.value = options?.mode === 'select'
uni.setNavigationBarTitle({ title: isSelectMode.value ? '选择账户' : '到账账户' })
if (isSelectMode.value) {
selectedId.value = uni.getStorageSync(SELECTED_KEY) || ''
}
})
onShow(() => {
loading.value = true
assertActiveDistributor().then((d) => {
if (!d) {
return
}
pageReady.value = true
loadAccounts()
})
})
function loadAccounts() {
loading.value = true
getBankCards()
.then((res: any) => {
accounts.value = res?.data?.result || []
// 如果选择模式没有已选卡,默认选中 isDefault=true 的卡
if (isSelectMode.value && !selectedId.value && accounts.value.length) {
const def = accounts.value.find((a: any) => a.isDefault)
selectedId.value = def ? def.id : accounts.value[0].id
}
})
.finally(() => {
loading.value = false
})
}
function handleSelect(item: any) {
if (!isSelectMode.value) return
selectedId.value = item.id
uni.setStorageSync(SELECTED_KEY, item.id)
uni.navigateBack()
}
function handleDelete(id: string) {
uni.showModal({
title: '删除账户',
content: '确认删除该银行卡?',
success: (res) => {
if (res.confirm) {
deleteBankCard(id)
.then(() => {
uni.showToast({ title: '已删除', icon: 'success' })
loadAccounts()
})
.catch((err: any) => {
const msg = err?.data?.message || '删除失败'
uni.showToast({ title: msg, icon: 'none' })
})
}
},
})
}
function handleSetDefault(id: string) {
setDefaultBankCard(id)
.then(() => {
uni.showToast({ title: '已设为默认', icon: 'success' })
loadAccounts()
})
.catch((err: any) => {
const msg = err?.data?.message || '操作失败'
uni.showToast({ title: msg, icon: 'none' })
})
}
function openAddPopup() {
form.value = { holderName: '', bankName: '', cardNo: '' }
addPopupVisible.value = true
}
function saveAccount() {
if (!form.value.holderName.trim()) {
uni.showToast({ title: '请输入姓名', icon: 'none' })
return
}
if (!form.value.bankName.trim()) {
uni.showToast({ title: '请输入银行名称', icon: 'none' })
return
}
if (form.value.cardNo.trim().length === 0) {
uni.showToast({ title: '请输入银行卡号', icon: 'none' })
return
}
saveLoading.value = true
addBankCard({
holderName: form.value.holderName.trim(),
bankName: form.value.bankName.trim(),
cardNo: form.value.cardNo.trim(),
})
.then((res: any) => {
const newCard = res?.data?.result
addPopupVisible.value = false
uni.showToast({ title: '添加成功', icon: 'success' })
loadAccounts()
// 如果是选择模式,自动选中刚添加的卡
if (isSelectMode.value && newCard?.id) {
selectedId.value = newCard.id
uni.setStorageSync(SELECTED_KEY, newCard.id)
}
})
.catch((err: any) => {
const msg = err?.data?.message || '添加失败,请重试'
uni.showToast({ title: msg, icon: 'none' })
})
.finally(() => {
saveLoading.value = false
})
}
function maskCard(cardNo: string) {
if (!cardNo || cardNo.length < 4) return cardNo
return '****' + cardNo.slice(-4)
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #f5f6f8;
}
.content { padding: 24rpx; }
/* ── 状态 ──────────────────────────────────── */
.state-wrap {
padding: 120rpx 0;
text-align: center;
}
.state-text { color: #999; font-size: 26rpx; }
/* ── 账户列表 ──────────────────────────────── */
.account-list { margin-bottom: 24rpx; }
.account-item {
background: #fff;
border-radius: 16rpx;
padding: 28rpx 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
}
.item-left {
display: flex;
align-items: center;
gap: 20rpx;
flex: 1;
min-width: 0;
}
.radio-circle {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid #ddd;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&.active { border-color: var(--theme-primary); }
}
.radio-dot {
width: 22rpx;
height: 22rpx;
border-radius: 50%;
background: var(--theme-primary);
}
.item-info {
display: flex;
flex-direction: column;
gap: 8rpx;
min-width: 0;
}
.item-name { font-size: 28rpx; font-weight: 500; color: #333; }
.item-meta { display: flex; align-items: center; gap: 12rpx; }
.item-bank { font-size: 24rpx; color: #666; }
.item-card { font-size: 24rpx; color: #999; }
.default-tag {
font-size: 20rpx;
color: var(--theme-primary);
border: 1rpx solid var(--theme-primary);
border-radius: 6rpx;
padding: 2rpx 10rpx;
flex-shrink: 0;
}
.item-actions {
display: flex;
align-items: center;
gap: 16rpx;
flex-shrink: 0;
}
.set-default-btn { padding: 4rpx 0; }
.set-default-text { font-size: 22rpx; color: #999; }
.item-delete { padding: 10rpx; }
/* ── 空状态 ────────────────────────────────── */
.empty-wrap { padding: 120rpx 0; text-align: center; }
.empty-text { font-size: 26rpx; color: #ccc; }
/* ── 添加按钮 ──────────────────────────────── */
.add-btn-wrap { padding-bottom: 40rpx; }
.add-btn {
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 16rpx;
border: 2rpx solid var(--theme-primary);
color: var(--theme-primary);
font-size: 30rpx;
font-weight: 500;
}
/* ── 弹窗 ──────────────────────────────────── */
.popup-wrap { padding: 32rpx 28rpx 48rpx; }
.popup-title {
text-align: center;
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 32rpx;
}
.form-item { display: flex; align-items: center; padding: 18rpx 0; }
.form-label { font-size: 28rpx; color: #333; width: 100rpx; flex-shrink: 0; }
.form-input { flex: 1; font-size: 28rpx; color: #333; height: 64rpx; }
.form-placeholder { color: #ccc; font-size: 26rpx; }
.form-divider { height: 1rpx; background: #f5f5f5; }
.popup-actions { display: flex; gap: 20rpx; margin-top: 32rpx; }
.popup-btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
text-align: center;
border-radius: 999rpx;
font-size: 28rpx;
font-weight: 500;
}
.popup-btn.ghost { color: #666; background: #f5f5f5; }
.popup-btn.primary { color: #fff; background: var(--theme-primary); }
.popup-btn.disabled { opacity: 0.5; }
</style>