分销列表
个人中心自愿委托出售
This commit is contained in:
2025-09-09 17:30:27 +08:00
parent acfb4c3c8d
commit 8190e8d689
3 changed files with 584 additions and 443 deletions

View File

@@ -1,5 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/stores/user'
import {createRouter, createWebHistory} from 'vue-router'
import {useUserStore} from '@/stores/user'
import NProgress from 'nprogress'
import api from '@/utils/api'
@@ -197,33 +197,33 @@ const routes = [
path: '/buydetail',
name: 'BuyDetail',
component: () => import('../views/BuyDetails.vue'),
meta: { title: '确认订单' }
meta: {title: '确认订单'}
},
{
path: '/pay/:orderId',
name: 'Pay',
component: () => import('@/views/Pay.vue'),
meta: { title: '确认支付' },
props: route => ({ orderId: route.query.orderId })
meta: {title: '确认支付'},
props: route => ({orderId: route.query.orderId})
},
{
path: '/cart',
name: 'Cart',
component: () => import('@/views/Cart.vue'),
meta: { title: '购物车' }
meta: {title: '购物车'}
},
{
path: '/address',
name: 'Address',
component: () => import('@/views/Address.vue'),
meta: { title: '地址管理', requiresAuth: true }
meta: {title: '地址管理', requiresAuth: true}
},
{
path: '/payloading',
name: 'PayLoading',
component: () => import('@/views/PayLoading.vue'),
meta: { title: '支付确认' },
props: route => ({ orderId: route.query.orderId })
meta: {title: '支付确认'},
props: route => ({orderId: route.query.orderId})
},
{
path: '/:pathMatch(.*)*',
@@ -242,7 +242,7 @@ const router = createRouter({
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
return {top: 0}
}
}
})
@@ -260,20 +260,20 @@ router.beforeEach(async (to, from, next) => {
// 检查维护模式
try {
const { data } = await api.get('/system/maintenance-status', { showLoading: false })
const {data} = await api.get('/system/maintenance-status', {showLoading: false})
console.log(data, 'data');
if (data.success) {
if (data.data.maintenance_mode) {
// 维护模式开启,且不在维护页面,跳转到维护页面
if (to.name !== 'Loading') {
next({ name: 'Loading' })
next({name: 'Loading'})
return
}
} else {
// 维护模式关闭,且在维护页面,跳转到首页
if (to.name === 'Loading') {
next({ name: 'MainPage' })
next({name: 'MainPage'})
return
}
}
@@ -294,13 +294,13 @@ router.beforeEach(async (to, from, next) => {
if (!agentInfo || !agentToken) {
next({
path: '/mylogin',
query: { redirect: to.fullPath }
query: {redirect: to.fullPath}
})
return
}
} else {
// 普通用户页面认证逻辑
console.log(userStore.isAuthenticated,'isAuthenticated');
console.log(userStore.isAuthenticated, 'isAuthenticated');
if (!userStore.isAuthenticated) {
// 尝试从本地存储恢复登录状态
@@ -309,7 +309,7 @@ router.beforeEach(async (to, from, next) => {
if (!userStore.isAuthenticated) {
next({
name: 'MyLogin',
query: { redirect: to.fullPath }
query: {redirect: to.fullPath}
})
return
}
@@ -325,7 +325,7 @@ router.beforeEach(async (to, from, next) => {
if (to.name !== 'Payment') {
next({
name: 'Payment',
query: { redirect: to.fullPath }
query: {redirect: to.fullPath}
})
return
} else {
@@ -337,7 +337,7 @@ router.beforeEach(async (to, from, next) => {
// 如果已登录用户访问登录/注册页面,重定向到转账管理(改成了主页)
if (to.meta.hideForAuth && userStore.isAuthenticated) {
next({ name: 'MainPage' })
next({name: 'MainPage'})
return
}

View File

@@ -4,11 +4,13 @@
<nav class="navbar">
<div class="nav-left">
<el-button
type="text"
:text="true"
@click="$router.go(-1)"
class="back-btn"
>
<el-icon><ArrowLeft /></el-icon>
<el-icon>
<ArrowLeft/>
</el-icon>
</el-button>
</div>
<div class="nav-center">
@@ -39,7 +41,9 @@
v-show="qrcodeGenerated"
></canvas>
<div v-show="!qrcodeGenerated" class="qrcode-loading">
<el-icon class="loading-icon"><Loading /></el-icon>
<el-icon class="loading-icon">
<Loading/>
</el-icon>
<span>生成中...</span>
</div>
</div>
@@ -68,21 +72,63 @@
</div>
</div>
<!-- 下级用户 -->
<el-button class="lower-users-btn" @click="handleLowerUser">查看下级用户</el-button>
<el-drawer
v-model="drawerLowerUsers"
title="下级用户"
direction="btt"
:lockScroll="false"
size="70%"
@open="requestLowerUsers"
@closed="closeScrollerLowerUsers"
>
<ul v-infinite-scroll="loadScrollerLowerUsers" class="users-list" style="overflow: auto"
:infinite-scroll-immediate="false"
:infinite-scroll-disabled="scrollLowerUsers">
<li v-for="(item, index) in lowerUsers" :key="item.id">
<el-divider v-if="index!=0" border-style="dashed" />
<div class="users-item">
<el-image
:src="getImageUrl(item.voucher_url)"
:preview-src-list="[getImageUrl(item.voucher_url)]"
class="user-avatar"
fit="cover"
>
<template #error>
<div class="image-slot">
<el-icon>
<Picture/>
</el-icon>
</div>
</template>
</el-image>
<div class="user-text">
<div class="user-username">用户名{{item.from_real_name}}</div>
<div class="user-date">时间{{ item.created_at }}</div>
</div>
</div>
</li>
<el-divider v-if="scrollLowerUsers" border-style="dashed" content-position="center">到底了~</el-divider>
</ul>
</el-drawer>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
import {ref, onMounted, nextTick} from 'vue'
import {useRouter} from 'vue-router'
import {useUserStore} from '@/stores/user'
import {ElMessage} from 'element-plus'
import {
ArrowLeft,
Loading
Loading, Picture
} from '@element-plus/icons-vue'
import QRCode from 'qrcode'
import api from "@/utils/api.js";
import {getImageUrl} from "@/config/index.js";
const router = useRouter()
const userStore = useUserStore()
@@ -92,7 +138,8 @@ const qrcodeCanvas = ref(null)
const qrcodeGenerated = ref(false)
const generating = ref(false)
const inviteLink = ref('')
// 下级用户
const drawerLowerUsers = ref(false)
// 生成邀请链接
const generateInviteLink = () => {
@@ -100,7 +147,7 @@ const generateInviteLink = () => {
console.log(userId)
const baseUrl = `${window.location.origin}/frontend`
// return `${baseUrl}/register?inviter=${userId}`// 实施用
return `http://192.168.1.124:5173/register?inviter=${userId}`// 测试用
return `http://192.168.1.250:5173/register?inviter=${userId}`// 测试用
}
// 生成二维码
@@ -138,7 +185,6 @@ const generateQRCode = async () => {
}
// 复制链接
const copyLink = async () => {
try {
@@ -156,6 +202,41 @@ const copyLink = async () => {
}
}
// 查看下级用户
const scrollLowerUsers = ref(false)
const lowerUsers = ref([])
const params = {
page: 1,
limit: 10
}
const pages = ref(0)
const handleLowerUser = async () => {
lowerUsers.value = []
drawerLowerUsers.value = true
}
const loadScrollerLowerUsers = async () => {
params.page += 1
await requestLowerUsers(params)
if (params.page > pages.value) {
scrollLowerUsers.value = true
}
}
const closeScrollerLowerUsers = () => {
lowerUsers.value = []
params.page = 0
scrollLowerUsers.value = false
}
const requestLowerUsers = async (params) => {
await api.get(`/transfers/user/3641`, {params}).then((res) => {
lowerUsers.value = lowerUsers.value.concat(res.data.data.transfers)
pages.value = res.data.data.pagination.pages
})
}
// 生命周期
onMounted(() => {
@@ -163,7 +244,7 @@ onMounted(() => {
})
</script>
<style scoped>
<style scoped lang="scss">
.distribution-page {
min-height: 100vh;
background: linear-gradient(to bottom, #72c9ffae, #f3f3f3);
@@ -266,8 +347,12 @@ onMounted(() => {
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.qrcode-tip {
@@ -318,4 +403,41 @@ onMounted(() => {
flex-direction: column;
}
}
.lower-users-btn {
width: 100%;
border-radius: 10px;
}
.users-list {
height: 100%;
padding: 0;
margin: 0;
list-style: none;
}
.users-list .users-item {
display: flex; /* 使用Flexbox布局 */
align-items: center; /* 垂直居中对齐 */
gap: 1rem; /* 图片与文字之间的间距 */
.user-avatar{
width: 50px;
height: 50px;
object-fit: cover;
}
.user-text{
.user-username{
margin-bottom: 5px;
}
.user-date{
color: #666;
font-size: 14px;
}
}
}
.users-list .users-item + .list-item {
margin-top: 10px;
}
</style>

View File

@@ -8,7 +8,9 @@
:src="avatarUrl"
class="avatar-img"
>
<el-icon><User /></el-icon>
<el-icon>
<User/>
</el-icon>
</el-avatar>
<el-button
type="primary"
@@ -123,8 +125,10 @@
:before-upload="beforeAvatarUpload"
:http-request="uploadAvatar"
>
<img v-if="newAvatar" :src="newAvatar" class="avatar-preview" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
<img v-if="newAvatar" :src="newAvatar" class="avatar-preview"/>
<el-icon v-else class="avatar-uploader-icon">
<Plus/>
</el-icon>
</el-upload>
<template #footer>
<span class="dialog-footer">
@@ -139,13 +143,13 @@
</template>
<script>
import { ref, onMounted } from 'vue';
import { useUserStore } from '@/stores/user';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { User, Plus } from '@element-plus/icons-vue';
import {ref, onMounted} from 'vue';
import {useUserStore} from '@/stores/user';
import {useRouter} from 'vue-router';
import {ElMessage, ElMessageBox} from 'element-plus';
import {User, Plus} from '@element-plus/icons-vue';
import api from '@/utils/api';
import { getImageUrl } from '@/config';
import {getImageUrl} from '@/config';
export default {
setup() {
@@ -155,26 +159,26 @@ export default {
const newAvatar = ref('');
const uploadedAvatarData = ref(null);
const showAvatarUpload = ref(false);
const accountInfo = ref({ balance: '0.00', is_distribute: false });
const accountInfo = ref({balance: '0.00', is_distribute: false});
const isLoading = ref(false);
const settings = ref([
{text:'账号安全',path:'/editpasswordpage'},
{text:'商户资料',path:'/editdetailspage'},
{text:'分销',path:'/distribution'},
{text: '账号安全', path: '/editpasswordpage'},
{text: '商户资料', path: '/editdetailspage'},
{text: '分销', path: '/distribution'},
// {text:'通知设置'},
// {text:'积分获取规则'},
// {text:'隐私协议'},
]);
const functionItems = ref([
{ image: "/imgs/mainpage/jiaoyijilu.png", text: "购物车", path: "/cart" },
{ image: "/imgs/mainpage/dingdanchaxun.png", text: "地址", path: "/address" },
{ image: "/imgs/mainpage/kefuzhongxin.png", text: "收藏", path: "" }
{image: "/imgs/mainpage/jiaoyijilu.png", text: "购物车", path: "/cart"},
{image: "/imgs/mainpage/dingdanchaxun.png", text: "地址", path: "/address"},
{image: "/imgs/mainpage/kefuzhongxin.png", text: "收藏", path: ""}
]);
// 加载账户信息
const loadAccountInfo = async () => {
try {
console.log(userStore.user,'userStore.user');
console.log(userStore.user, 'userStore.user');
if (userStore.user?.id) {
const response = await api.get(`/user/profile`);
@@ -192,7 +196,7 @@ export default {
const processedAvatarUrl = getImageUrl(response.data.user.avatar);
avatarUrl.value = processedAvatarUrl;
// 更新store中的头像
if(userStore.user) {
if (userStore.user) {
userStore.setUser({
...userStore.user,
avatar: processedAvatarUrl
@@ -210,11 +214,9 @@ export default {
const handleDistributeChange = async (value) => {
try {
// 判断融豆状态为0提示其余正常
if (accountInfo.value.balance==0){
if (accountInfo.value.balance == 0) {
ElMessageBox.alert(
'请获取融豆后,可开通此服务', '',{
confirmButtonText: 'OK',
}
'请获取融豆后,可开通此服务', '', {confirmButtonText: '确定',}
)
accountInfo.value.is_distribute = !value;
return
@@ -276,9 +278,24 @@ export default {
localStorage.setItem('hasCheckedDistribute', 'true');
}
} else {
// 如果更新失败,恢复原状态
accountInfo.value.is_distribute = !value;
ElMessage.error(response.data.message);
ElMessageBox.confirm(
'是否同意缴费',
response.data.message,
{
confirmButtonText: '同意',
cancelButtonText: '取消',
type: 'warning',
}
).then(async () => {
let response = await api.post(`/users/${userStore.user?.id}/deduct-service-fee`)
if (response.data.success) {
ElMessage.success(response.data.message);
loadAccountInfo()
}
}).catch(() => {
accountInfo.value.is_distribute = !value;
})
}
} catch (error) {
if (error === 'cancel') {
@@ -355,7 +372,7 @@ export default {
// 使用url作为显示地址
avatarUrl.value = uploadedAvatarData.value.url;
// 更新用户store中的头像信息
if(userStore.user) {
if (userStore.user) {
userStore.setUser({
...userStore.user,
avatar: uploadedAvatarData.value.url
@@ -421,6 +438,7 @@ export default {
avatarUrl.value = userStore.user.avatar;
}
loadAccountInfo();
});
return {
@@ -705,6 +723,7 @@ export default {
background-color: rgba(255, 255, 255, 0.9) !important;
border-color: rgba(255, 255, 255, 0.9) !important;
}
.el-checkbox__inner::after {
border-color: #2f89ff !important;
}