|
|
@@ -0,0 +1,616 @@
|
|
|
+<template>
|
|
|
+ <view class="page-team-system">
|
|
|
+ <!-- 头部:体系信息 -->
|
|
|
+ <view class="system-header" v-if="systemInfo">
|
|
|
+ <view class="system-info">
|
|
|
+ <view class="system-icon">🏢</view>
|
|
|
+ <view class="system-detail">
|
|
|
+ <text class="system-name">{{ systemInfo.name || '我的供应商体系' }}</text>
|
|
|
+ <text class="system-desc">服务商团队管理</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="system-status" :class="systemInfo.status">
|
|
|
+ <text>{{ systemInfo.status === 'active' ? '活跃' : '未激活' }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 层级关系 -->
|
|
|
+ <view class="section" v-if="hierarchyInfo">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">层级关系</text>
|
|
|
+ </view>
|
|
|
+ <view class="hierarchy-grid">
|
|
|
+ <!-- 上级 -->
|
|
|
+ <view class="hierarchy-item" v-if="hierarchyInfo.parent">
|
|
|
+ <view class="hierarchy-label">上级服务商</view>
|
|
|
+ <view class="hierarchy-person">
|
|
|
+ <image v-if="hierarchyInfo.parent.avatar" class="avatar-img" :src="hierarchyInfo.parent.avatar" mode="aspectFill"></image>
|
|
|
+ <text v-else class="avatar-placeholder">👤</text>
|
|
|
+ <view class="person-info">
|
|
|
+ <text class="person-name">{{ hierarchyInfo.parent.nickname || '服务商' }}</text>
|
|
|
+ <text class="person-level">上级</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 下级 -->
|
|
|
+ <view class="hierarchy-item" v-else>
|
|
|
+ <view class="hierarchy-label">下级服务商</view>
|
|
|
+ <view class="hierarchy-empty">
|
|
|
+ <text>暂无下级</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 团队规模 -->
|
|
|
+ <view class="hierarchy-stat">
|
|
|
+ <text class="stat-value">{{ hierarchyInfo.totalChildren || 0 }}</text>
|
|
|
+ <text class="stat-label">团队成员</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 团队统计 -->
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">团队数据</text>
|
|
|
+ </view>
|
|
|
+ <view class="stats-grid">
|
|
|
+ <view class="stat-card">
|
|
|
+ <text class="stat-num">{{ teamStats.memberCount || 0 }}</text>
|
|
|
+ <text class="stat-name">团队成员</text>
|
|
|
+ </view>
|
|
|
+ <view class="stat-card">
|
|
|
+ <text class="stat-num">{{ teamStats.customerCount || 0 }}</text>
|
|
|
+ <text class="stat-name">客户归属</text>
|
|
|
+ </view>
|
|
|
+ <view class="stat-card">
|
|
|
+ <text class="stat-num">{{ teamStats.orderCount || 0 }}</text>
|
|
|
+ <text class="stat-name">关联订单</text>
|
|
|
+ </view>
|
|
|
+ <view class="stat-card">
|
|
|
+ <text class="stat-num">{{ teamStats.amount || 0 }}</text>
|
|
|
+ <text class="stat-name">关联金额(元)</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 团队成员列表 -->
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">团队成员</text>
|
|
|
+ <text class="section-action" @click="goToMembers">查看全部</text>
|
|
|
+ </view>
|
|
|
+ <view class="member-list">
|
|
|
+ <view class="member-item" v-for="member in teamMembers.slice(0, 5)" :key="member.userId">
|
|
|
+ <image v-if="member.avatar" class="member-avatar" :src="member.avatar" mode="aspectFill"></image>
|
|
|
+ <text v-else class="member-avatar-placeholder">👤</text>
|
|
|
+ <view class="member-info">
|
|
|
+ <text class="member-name">{{ member.nickname || '微信用户' }}</text>
|
|
|
+ <text class="member-role">{{ member.role || '成员' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="member-stats">
|
|
|
+ <text class="member-count">{{ member.customerCount || 0 }}</text>
|
|
|
+ <text class="member-label">客户</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="empty-tip" v-if="teamMembers.length === 0">
|
|
|
+ <text>暂无团队成员</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 团队客户列表 -->
|
|
|
+ <view class="section">
|
|
|
+ <view class="section-header">
|
|
|
+ <text class="section-title">团队客户</text>
|
|
|
+ <text class="section-action" @click="goToCustomers">查看全部</text>
|
|
|
+ </view>
|
|
|
+ <view class="customer-list">
|
|
|
+ <view class="customer-item" v-for="customer in teamCustomers.slice(0, 5)" :key="customer.id">
|
|
|
+ <view class="customer-avatar">
|
|
|
+ <text class="customer-icon">👥</text>
|
|
|
+ </view>
|
|
|
+ <view class="customer-info">
|
|
|
+ <text class="customer-name">{{ customer.familyName || '未知家庭' }}</text>
|
|
|
+ <text class="customer-meta">{{ customer.source === 'manual' ? '人工绑定' : customer.source === 'order' ? '下单自动' : '推荐码' }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="customer-stats">
|
|
|
+ <text class="customer-orders">{{ customer.orderCount || 0 }}</text>
|
|
|
+ <text class="customer-label">订单</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="empty-tip" v-if="teamCustomers.length === 0">
|
|
|
+ <text>暂无客户数据</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 操作按钮 -->
|
|
|
+ <view class="action-bar">
|
|
|
+ <button class="btn-manage" @click="goToManage">团队管理</button>
|
|
|
+ <button class="btn-customers" @click="goToCustomers">客户列表</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ systemInfo: null,
|
|
|
+ hierarchyInfo: null,
|
|
|
+ teamStats: {
|
|
|
+ memberCount: 0,
|
|
|
+ customerCount: 0,
|
|
|
+ orderCount: 0,
|
|
|
+ amount: 0
|
|
|
+ },
|
|
|
+ teamMembers: [],
|
|
|
+ teamCustomers: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ onLoad() {
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+
|
|
|
+ onShow() {
|
|
|
+ this.loadData()
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ async loadData() {
|
|
|
+ try {
|
|
|
+ // 并发获取所有数据
|
|
|
+ const [systemRes, hierarchyRes, membersRes, customersRes] = await Promise.all([
|
|
|
+ this.fetchSystemInfo(),
|
|
|
+ this.fetchHierarchyInfo(),
|
|
|
+ this.fetchTeamMembers(),
|
|
|
+ this.fetchTeamCustomers()
|
|
|
+ ])
|
|
|
+
|
|
|
+ if (systemRes) {
|
|
|
+ this.systemInfo = systemRes
|
|
|
+ }
|
|
|
+ if (hierarchyRes) {
|
|
|
+ this.hierarchyInfo = hierarchyRes
|
|
|
+ }
|
|
|
+ if (membersRes) {
|
|
|
+ this.teamMembers = membersRes
|
|
|
+ }
|
|
|
+ if (customersRes) {
|
|
|
+ this.teamCustomers = customersRes
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新统计
|
|
|
+ this.updateStats()
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载团队数据失败:', error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取体系信息
|
|
|
+ async fetchSystemInfo() {
|
|
|
+ try {
|
|
|
+ const res = await this.$http.get('/api/admin/supply-system/my-system', {})
|
|
|
+ return res.data || null
|
|
|
+ } catch (e) {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取层级关系
|
|
|
+ async fetchHierarchyInfo() {
|
|
|
+ try {
|
|
|
+ const res = await this.$http.get('/api/admin/supply-hierarchy/my', {})
|
|
|
+ return res.data || null
|
|
|
+ } catch (e) {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取团队成员
|
|
|
+ async fetchTeamMembers() {
|
|
|
+ try {
|
|
|
+ const res = await this.$http.get('/api/admin/supply-team/members', {
|
|
|
+ systemId: this.systemInfo?.id
|
|
|
+ })
|
|
|
+ return res.data || []
|
|
|
+ } catch (e) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取团队客户
|
|
|
+ async fetchTeamCustomers() {
|
|
|
+ try {
|
|
|
+ const res = await this.$http.get('/api/admin/supply-team/customers', {
|
|
|
+ systemId: this.systemInfo?.id,
|
|
|
+ parentId: null,
|
|
|
+ page: 1,
|
|
|
+ size: 50
|
|
|
+ })
|
|
|
+ return res.data || []
|
|
|
+ } catch (e) {
|
|
|
+ return []
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 更新统计数据
|
|
|
+ updateStats() {
|
|
|
+ this.teamStats.memberCount = this.teamMembers.length
|
|
|
+ this.teamStats.customerCount = this.teamCustomers.length
|
|
|
+ },
|
|
|
+
|
|
|
+ // 跳转管理页面
|
|
|
+ goToManage() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/vendor/team-manage/team-manage'
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 跳转客户列表
|
|
|
+ goToCustomers() {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/vendor/team-customers/team-customers'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+.page-team-system {
|
|
|
+ background-color: #FFF7ED;
|
|
|
+ min-height: 100vh;
|
|
|
+ padding-bottom: 100rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 体系头部 */
|
|
|
+.system-header {
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 30rpx;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(249,115,22,0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.system-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.system-icon {
|
|
|
+ font-size: 64rpx;
|
|
|
+ margin-right: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.system-name {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.system-desc {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+ margin-top: 4rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.system-status {
|
|
|
+ padding: 8rpx 20rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.system-status.active {
|
|
|
+ background-color: #E6F7EE;
|
|
|
+ color: #65C29A;
|
|
|
+}
|
|
|
+
|
|
|
+.system-status.inactive {
|
|
|
+ background-color: #FFF7EE;
|
|
|
+ color: #F97316;
|
|
|
+}
|
|
|
+
|
|
|
+/* 区块 */
|
|
|
+.section {
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ margin: 0 30rpx 24rpx;
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(249,115,22,0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.section-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 24rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.section-action {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #F97316;
|
|
|
+}
|
|
|
+
|
|
|
+/* 层级关系 */
|
|
|
+.hierarchy-grid {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.hierarchy-item {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 48%;
|
|
|
+ padding: 20rpx;
|
|
|
+ background-color: #FFF7ED;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ margin-bottom: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.hierarchy-label {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 12rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.hierarchy-person {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-img {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.avatar-placeholder {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background-color: #F5FAFE;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 32rpx;
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.person-info {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.person-name {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.person-level {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+}
|
|
|
+
|
|
|
+.hierarchy-empty {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+}
|
|
|
+
|
|
|
+.hierarchy-stat {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 48%;
|
|
|
+ padding: 20rpx;
|
|
|
+ background-color: #F5FAFE;
|
|
|
+ border-radius: 12rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-value {
|
|
|
+ font-size: 40rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #2F5496;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-label {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+/* 统计网格 */
|
|
|
+.stats-grid {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card {
|
|
|
+ width: 50%;
|
|
|
+ padding: 20rpx;
|
|
|
+ text-align: center;
|
|
|
+ border-right: 1rpx solid #FED7AA;
|
|
|
+ border-bottom: 1rpx solid #FED7AA;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-num {
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #F97316;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-name {
|
|
|
+ font-size: 22rpx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+/* 成员列表 */
|
|
|
+.member-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 16rpx 0;
|
|
|
+ border-bottom: 1rpx solid #FED7AA;
|
|
|
+}
|
|
|
+
|
|
|
+.member-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.member-avatar {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.member-avatar-placeholder {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background-color: #F5FAFE;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 32rpx;
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.member-info {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.member-name {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.member-role {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+}
|
|
|
+
|
|
|
+.member-stats {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.member-count {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #F97316;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.member-label {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-tip {
|
|
|
+ text-align: center;
|
|
|
+ padding: 40rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+ font-size: 26rpx;
|
|
|
+}
|
|
|
+
|
|
|
+/* 客户列表 */
|
|
|
+.customer-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 16rpx 0;
|
|
|
+ border-bottom: 1rpx solid #FED7AA;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-item:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-avatar {
|
|
|
+ width: 64rpx;
|
|
|
+ height: 64rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background-color: #F5FAFE;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ margin-right: 16rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-icon {
|
|
|
+ font-size: 32rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-info {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-name {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-meta {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #94A3B8;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-stats {
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-orders {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #F97316;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.customer-label {
|
|
|
+ font-size: 20rpx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+/* 操作按钮 */
|
|
|
+.action-bar {
|
|
|
+ position: fixed;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ background-color: #fff;
|
|
|
+ padding: 20rpx 30rpx;
|
|
|
+ display: flex;
|
|
|
+ gap: 20rpx;
|
|
|
+ box-shadow: 0 -2rpx 12rpx rgba(0,0,0,0.05);
|
|
|
+}
|
|
|
+
|
|
|
+.btn-manage, .btn-customers {
|
|
|
+ flex: 1;
|
|
|
+ height: 80rpx;
|
|
|
+ line-height: 80rpx;
|
|
|
+ border-radius: 40rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-manage {
|
|
|
+ background-color: #F97316;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.btn-customers {
|
|
|
+ background-color: #fff;
|
|
|
+ color: #F97316;
|
|
|
+ border: 2rpx solid #F97316;
|
|
|
+}
|
|
|
+</style>
|