- 新增groupList属性支持动态加载组别数据 - 实现根据高级经理选择过滤组别功能 - 移除静态综合分显示并优化滚动条样式 - 添加数据处理逻辑支持嵌套API响应结构
970 lines
25 KiB
Vue
970 lines
25 KiB
Vue
<template>
|
||
<div class="senior-manager-dashboard">
|
||
<!-- Header -->
|
||
<header class="dashboard-header">
|
||
<div class="header-content">
|
||
<div class="logo-section">
|
||
<div class="header-text">
|
||
<h1>中心组长指挥台</h1>
|
||
<p>统筹多组运营,优化资源配置,驱动业绩增长,实现团队协同发展。</p>
|
||
</div>
|
||
|
||
<!-- 营期阶段信息 -->
|
||
<div class="stage-info" style="margin-left: 100px;">
|
||
<span class="stage-label">营期所属阶段:</span>
|
||
<span class="stage-value">接数据</span>
|
||
</div>
|
||
<div>
|
||
<!-- 用户下拉菜单 -->
|
||
<UserDropdown />
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</header>
|
||
<!-- Main Content -->
|
||
<main class="dashboard-main">
|
||
<!-- Top Section - Center Overview and Action Items -->
|
||
<div class="top-section">
|
||
<!-- Center Performance Overview -->
|
||
<CenterOverview :overall-data="overallCenterPerformance" />
|
||
|
||
<!-- Action Items (Compact) -->
|
||
<div class="action-items-compact">
|
||
<ActionItems :selected-group="selectedGroup" />
|
||
</div>
|
||
</div>
|
||
<div class="BB-section">
|
||
<!--客户类型占比-->
|
||
<CustomerType :customer-data="customerTypeDistribution" @category-change="handleCustomerTypeChange" />
|
||
<!-- 优秀录音 -->
|
||
<GoodMusic />
|
||
<!-- 客户问题排行 -->
|
||
<ProblemRanking :ranking-data="formattedUrgentNeedData" />
|
||
</div>
|
||
<!-- Bottom Section -->
|
||
<div class="bottom-section">
|
||
<!-- Left Section - Group Performance Ranking -->
|
||
<div class="left-section">
|
||
<GroupRanking :groups="groups" :selected-group="selectedGroup" @select-group="selectGroup" />
|
||
</div>
|
||
|
||
<!-- Right Section - Group Comparison -->
|
||
<div class="right-section">
|
||
<GroupComparison :groups="groups" :senior-manager-data="seniorManagerList" :group-list="groupList" @select-group="selectGroup" @manager-change="handleManagerChange" />
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- Team Members Detail Section -->
|
||
<div class="team-detail-section" v-if="selectedGroup">
|
||
<div class="team-detail-header">
|
||
<h2>{{ selectedGroup.name }} - 团队成员详情</h2>
|
||
<div class="team-summary">
|
||
<div class="summary-item">
|
||
<span class="label">组长:</span>
|
||
<span class="value">{{ selectedGroup.leader }}</span>
|
||
</div>
|
||
<div class="summary-item">
|
||
<span class="label">成员数:</span>
|
||
<span class="value">{{ selectedGroup.memberCount }}人</span>
|
||
</div>
|
||
<div class="summary-item">
|
||
<span class="label">今日业绩:</span>
|
||
<span class="value">{{ formatCurrency(selectedGroup.todayPerformance) }}</span>
|
||
</div>
|
||
<div class="summary-item">
|
||
<span class="label">转化率:</span>
|
||
<span class="value">{{ selectedGroup.conversionRate }}%</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="members-grid">
|
||
<div v-for="member in selectedGroup.members" :key="member.id" class="member-card"
|
||
:class="getStatusClass(member.status)">
|
||
<div class="member-header">
|
||
<div class="member-info">
|
||
<h3 class="member-name">{{ member.name }}</h3>
|
||
<p class="member-position">{{ member.position }}</p>
|
||
<p class="member-phone">{{ member.phone }}</p>
|
||
</div>
|
||
<div class="member-status">
|
||
<span class="status-badge" :class="member.status">{{ getStatusText(member.status) }}</span>
|
||
<span class="join-date">入职: {{ member.joinDate }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="member-metrics">
|
||
<div class="metric-row">
|
||
<div class="metric-item">
|
||
<span class="metric-label">今日业绩</span>
|
||
<span class="metric-value">{{ formatCurrency(member.todayPerformance) }}</span>
|
||
</div>
|
||
<div class="metric-item">
|
||
<span class="metric-label">月度业绩</span>
|
||
<span class="metric-value">{{ formatCurrency(member.monthlyPerformance) }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="metric-row">
|
||
<div class="metric-item">
|
||
<span class="metric-label">转化率</span>
|
||
<span class="metric-value">{{ member.conversionRate }}%</span>
|
||
</div>
|
||
<div class="metric-item">
|
||
<span class="metric-label">通话次数</span>
|
||
<span class="metric-value">{{ member.callCount }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="metric-row">
|
||
<div class="metric-item">
|
||
<span class="metric-label">新增客户</span>
|
||
<span class="metric-value">{{ member.newClients }}</span>
|
||
</div>
|
||
<div class="metric-item">
|
||
<span class="metric-label">成交订单</span>
|
||
<span class="metric-value">{{ member.deals }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, onMounted, computed } from 'vue'
|
||
|
||
import CenterOverview from './components/CenterOverview.vue'
|
||
import GroupComparison from './components/GroupComparison.vue'
|
||
import GroupRanking from './components/GroupRanking.vue'
|
||
import ActionItems from './components/ActionItems.vue'
|
||
import CustomerDetail from './components/CustomerDetail.vue'
|
||
import CustomerType from './components/CustomerType.vue'
|
||
import GoodMusic from './components/GoodMusic.vue'
|
||
import ProblemRanking from './components/ProblemRanking.vue'
|
||
import seniorManager from './components/seniorManager.vue'
|
||
import UserDropdown from '@/components/UserDropdown.vue'
|
||
import {
|
||
getOverallCenterPerformance, getTotalGroupCount, getCenterConversionRate, getTotalCallCount, getNewCustomer
|
||
, getDepositConversionRate, getCustomerTypeDistribution, getUrgentNeedToAddress, getCenterAdvancedManagerList, getTeamRanking, getTeamRankingInfo
|
||
} from '@/api/secondTop.js'
|
||
import { useRouter } from 'vue-router'
|
||
import { useUserStore } from '@/stores/user.js'
|
||
// 组别数据
|
||
const groups = ref([])
|
||
|
||
// 路由实例
|
||
const router = useRouter();
|
||
// 用户store实例
|
||
const userStore = useUserStore();
|
||
|
||
// 获取通用请求参数的函数
|
||
const getRequestParams = () => {
|
||
const params = {}
|
||
// 只从路由参数获取
|
||
const routeUserLevel = router.currentRoute.value.query.user_level || router.currentRoute.value.params.user_level
|
||
const routeUserName = router.currentRoute.value.query.user_name || router.currentRoute.value.params.user_name
|
||
// 如果路由有参数,使用路由参数
|
||
if (routeUserLevel) {
|
||
params.user_level = routeUserLevel.toString()
|
||
}
|
||
if (routeUserName) {
|
||
params.user_name = routeUserName
|
||
}
|
||
|
||
return params
|
||
}
|
||
// 中心整体概览
|
||
const overallCenterPerformance = ref({
|
||
CenterPerformance: {},
|
||
TotalGroupCount: {},
|
||
CenterConversionRate: {},
|
||
TotalCallCount: {},
|
||
NewCustomer: {},
|
||
DepositConversionRate: {}
|
||
})
|
||
// 客户类型
|
||
const customerTypeDistribution = ref({})
|
||
// 迫切解决的问题
|
||
const urgentNeedToAddress = ref({})
|
||
|
||
// 格式化迫切解决问题数据为组件所需格式
|
||
const formattedUrgentNeedData = computed(() => {
|
||
if (urgentNeedToAddress.value && urgentNeedToAddress.value.center_urgent_issue_ratio) {
|
||
return Object.entries(urgentNeedToAddress.value.center_urgent_issue_ratio).map(([name, value]) => ({
|
||
name,
|
||
value
|
||
}))
|
||
}
|
||
return []
|
||
})
|
||
|
||
|
||
// 中心总业绩
|
||
async function CenterOverallCenterPerformance() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getOverallCenterPerformance(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
overallCenterPerformance.value.CenterPerformance = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 活跃组数
|
||
async function CenterTotalGroupCount() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getTotalGroupCount(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
overallCenterPerformance.value.TotalGroupCount = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 中心转化率
|
||
async function CenterConversionRate() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getCenterConversionRate(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
overallCenterPerformance.value.CenterConversionRate = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 中心通话次数
|
||
async function CenterTotalCallCount() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getTotalCallCount(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
overallCenterPerformance.value.TotalCallCount = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 新增客户
|
||
async function CenterNewCustomer() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getNewCustomer(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
overallCenterPerformance.value.NewCustomer = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 定金转化率
|
||
async function CenterDepositConversionRate() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getDepositConversionRate(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
overallCenterPerformance.value.DepositConversionRate = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 客户类型
|
||
async function CenterCustomerType(distributionType = 'occupation') {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
// 添加distribution_type参数
|
||
const requestParams = hasParams ? { ...params, distribution_type: distributionType } : { distribution_type: distributionType }
|
||
try {
|
||
const res = await getCustomerTypeDistribution(requestParams)
|
||
if (res.code === 200) {
|
||
customerTypeDistribution.value = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取客户类型分布失败:', error)
|
||
}
|
||
}
|
||
|
||
// 处理客户类型选择变化
|
||
const handleCustomerTypeChange = (distributionType) => {
|
||
CenterCustomerType(distributionType)
|
||
}
|
||
// 客户迫切解决的问题
|
||
async function CenterUrgentNeedToAddress() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getUrgentNeedToAddress(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
urgentNeedToAddress.value = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
|
||
// 综合排名---高级经理列表
|
||
const seniorManagerList = ref([])
|
||
async function CenterSeniorManagerList() {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
try {
|
||
const res = await getCenterAdvancedManagerList(hasParams ? params : undefined)
|
||
if (res.code === 200) {
|
||
seniorManagerList.value = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取中心整体概览失败:', error)
|
||
}
|
||
}
|
||
// 综合排名---组别列表
|
||
const groupList = ref([])
|
||
async function CenterGroupList(selectedManagerId = 'all') {
|
||
const params = getRequestParams()
|
||
const hasParams = params.user_name
|
||
|
||
// 根据选择的经理构建请求参数
|
||
let requestParams = hasParams ? { ...params } : {}
|
||
|
||
if (selectedManagerId === 'all') {
|
||
requestParams.get_all = "true"
|
||
} else {
|
||
// 根据manager id找到对应的名字
|
||
const selectedManager = seniorManagerList.value?.center_advanced_managers?.find((name, index) => `manager_${index}` === selectedManagerId)
|
||
console.log('Found Manager:', selectedManager)
|
||
if (selectedManager) {
|
||
requestParams.team_leader_name = selectedManager
|
||
}
|
||
}
|
||
try {
|
||
const res = await getTeamRanking(requestParams)
|
||
console.log('API Response:', res)
|
||
if (res.code === 200) {
|
||
groupList.value = res.data
|
||
console.log('Updated groupList:', groupList.value)
|
||
}
|
||
} catch (error) {
|
||
console.error('获取团队排名失败:', error)
|
||
}
|
||
}
|
||
|
||
// 当前选中的组别,默认为第一个
|
||
const selectedGroup = ref(groups[0])
|
||
|
||
// 选择组别函数
|
||
const selectGroup = (group) => {
|
||
selectedGroup.value = group
|
||
}
|
||
|
||
// 处理高级经理选择变化
|
||
const handleManagerChange = (selectedManagerId) => {
|
||
CenterGroupList(selectedManagerId)
|
||
}
|
||
|
||
// 格式化货币
|
||
const formatCurrency = (value) => {
|
||
if (value >= 10000) {
|
||
return (value / 10000).toFixed(1) + '万'
|
||
}
|
||
return value.toLocaleString()
|
||
}
|
||
|
||
// 获取状态样式类
|
||
const getStatusClass = (status) => {
|
||
return `status-${status}`
|
||
}
|
||
|
||
// 获取状态文本
|
||
const getStatusText = (status) => {
|
||
const statusMap = {
|
||
excellent: '优秀',
|
||
good: '良好',
|
||
average: '一般',
|
||
attention: '需关注',
|
||
poor: '待提升'
|
||
}
|
||
return statusMap[status] || '未知'
|
||
}
|
||
onMounted(async () => {
|
||
await CenterOverallCenterPerformance()
|
||
await CenterTotalGroupCount()
|
||
await CenterConversionRate()
|
||
await CenterTotalCallCount()
|
||
await CenterNewCustomer()
|
||
await CenterDepositConversionRate()
|
||
await CenterCustomerType()
|
||
await CenterUrgentNeedToAddress()
|
||
await CenterSeniorManagerList()
|
||
await CenterGroupList('all') // 初始化加载全部高级经理数据
|
||
})
|
||
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
@import '@/assets/styles/main.scss';
|
||
|
||
.senior-manager-dashboard {
|
||
min-height: 100vh;
|
||
background-color: #f8fafc;
|
||
}
|
||
|
||
.dashboard-header {
|
||
background: white;
|
||
padding: 1.5rem 2rem;
|
||
border-bottom: 1px solid #e2e8f0;
|
||
|
||
.header-content {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.logo-section {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.header-text {
|
||
h1 {
|
||
font-size: 1.6rem;
|
||
font-weight: bold;
|
||
color: #1e293b;
|
||
margin: 0 0 0.25rem 0;
|
||
}
|
||
|
||
p {
|
||
color: #64748b;
|
||
margin: 0;
|
||
font-size: 0.95rem;
|
||
}
|
||
}
|
||
|
||
.stage-info {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.stage-label {
|
||
color: #64748b;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.stage-value {
|
||
color: #3b82f6;
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
background: #eff6ff;
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 1rem;
|
||
margin-left: 0.5rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.dashboard-main {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
padding: 1rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.top-section {
|
||
display: grid;
|
||
grid-template-columns: 2fr 1fr;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.bottom-section {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1rem;
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.left-section,
|
||
.right-section {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.right-section {
|
||
max-height: 600px;
|
||
overflow: auto;
|
||
}
|
||
|
||
.action-items-compact {
|
||
height: 380px;
|
||
overflow: hidden;
|
||
|
||
:deep(.action-items) {
|
||
height: 100%;
|
||
padding: 1rem;
|
||
|
||
.actions-header {
|
||
margin-bottom: 1rem;
|
||
|
||
h2 {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.header-controls {
|
||
gap: 0.5rem;
|
||
|
||
.priority-filter {
|
||
padding: 0.4rem;
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
.add-btn {
|
||
padding: 0.4rem 0.8rem;
|
||
font-size: 0.8rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.actions-summary {
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 0.5rem;
|
||
margin-bottom: 1rem;
|
||
|
||
.summary-item {
|
||
padding: 0.5rem;
|
||
|
||
.summary-count {
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 0.7rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.actions-list {
|
||
max-height: 230px;
|
||
overflow-y: auto;
|
||
|
||
.action-item {
|
||
padding: 0.75rem;
|
||
margin-bottom: 0.5rem;
|
||
|
||
.action-content {
|
||
.action-header {
|
||
margin-bottom: 0.25rem;
|
||
|
||
.action-title {
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.action-meta {
|
||
gap: 0.25rem;
|
||
|
||
.priority-badge {
|
||
padding: 0.2rem 0.4rem;
|
||
font-size: 0.7rem;
|
||
}
|
||
|
||
.due-date {
|
||
font-size: 0.7rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.action-description {
|
||
font-size: 0.8rem;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.action-details {
|
||
margin-bottom: 0.5rem;
|
||
|
||
.detail-item {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
|
||
.action-footer {
|
||
.action-buttons {
|
||
|
||
.btn-edit,
|
||
.btn-delete {
|
||
padding: 0.25rem 0.5rem;
|
||
font-size: 0.7rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.customer-detail-section {
|
||
padding: 1rem;
|
||
margin-top: 0.75rem;
|
||
}
|
||
}
|
||
|
||
// BB-section 布局
|
||
.BB-section {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
gap: 1rem;
|
||
margin-top: 1rem;
|
||
align-items: stretch;
|
||
|
||
>* {
|
||
height: 100%;
|
||
min-height: 400px;
|
||
}
|
||
}
|
||
|
||
// 团队成员详情区域
|
||
.team-detail-section {
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||
margin-top: 1rem;
|
||
|
||
.team-detail-header {
|
||
margin-bottom: 2rem;
|
||
|
||
h2 {
|
||
font-size: 1.4rem;
|
||
font-weight: 600;
|
||
color: #1e293b;
|
||
margin: 0 0 1rem 0;
|
||
}
|
||
|
||
.team-summary {
|
||
display: flex;
|
||
gap: 2rem;
|
||
flex-wrap: wrap;
|
||
|
||
.summary-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
|
||
.label {
|
||
font-size: 0.9rem;
|
||
color: #64748b;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.value {
|
||
font-size: 0.9rem;
|
||
color: #1e293b;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.members-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||
gap: 1rem;
|
||
|
||
.member-card {
|
||
background: #f8fafc;
|
||
border-radius: 10px;
|
||
padding: 1rem;
|
||
border: 1px solid #e2e8f0;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
&.status-excellent {
|
||
border-left: 4px solid #10b981;
|
||
background: linear-gradient(135deg, #ecfdf5 0%, #f0fdf4 100%);
|
||
}
|
||
|
||
&.status-good {
|
||
border-left: 4px solid #3b82f6;
|
||
background: linear-gradient(135deg, #eff6ff 0%, #f0f9ff 100%);
|
||
}
|
||
|
||
&.status-average {
|
||
border-left: 4px solid #f59e0b;
|
||
background: linear-gradient(135deg, #fffbeb 0%, #fefce8 100%);
|
||
}
|
||
|
||
&.status-attention {
|
||
border-left: 4px solid #f97316;
|
||
background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);
|
||
}
|
||
|
||
&.status-poor {
|
||
border-left: 4px solid #ef4444;
|
||
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
|
||
}
|
||
|
||
.member-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 1rem;
|
||
|
||
.member-info {
|
||
flex: 1;
|
||
|
||
.member-name {
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
color: #1e293b;
|
||
margin: 0 0 0.25rem 0;
|
||
}
|
||
|
||
.member-position {
|
||
font-size: 0.85rem;
|
||
color: #64748b;
|
||
margin: 0 0 0.25rem 0;
|
||
}
|
||
|
||
.member-phone {
|
||
font-size: 0.8rem;
|
||
color: #94a3b8;
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
.member-status {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 0.25rem;
|
||
|
||
.status-badge {
|
||
padding: 0.25rem 0.5rem;
|
||
border-radius: 4px;
|
||
font-size: 0.75rem;
|
||
font-weight: 500;
|
||
|
||
&.excellent {
|
||
background: #10b981;
|
||
color: white;
|
||
}
|
||
|
||
&.good {
|
||
background: #3b82f6;
|
||
color: white;
|
||
}
|
||
|
||
&.average {
|
||
background: #f59e0b;
|
||
color: white;
|
||
}
|
||
|
||
&.attention {
|
||
background: #f97316;
|
||
color: white;
|
||
}
|
||
|
||
&.poor {
|
||
background: #ef4444;
|
||
color: white;
|
||
}
|
||
}
|
||
|
||
.join-date {
|
||
font-size: 0.75rem;
|
||
color: #94a3b8;
|
||
}
|
||
}
|
||
}
|
||
|
||
.member-metrics {
|
||
.metric-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1rem;
|
||
margin-bottom: 0.75rem;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.metric-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.25rem;
|
||
|
||
.metric-label {
|
||
font-size: 0.75rem;
|
||
color: #64748b;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.metric-value {
|
||
font-size: 0.9rem;
|
||
color: #1e293b;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 客户详情区域
|
||
.customer-detail-section {
|
||
background: white;
|
||
border-radius: 12px;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
// 移动端适配
|
||
@media (max-width: 768px) {
|
||
.dashboard-header {
|
||
padding: 1rem;
|
||
|
||
.header-text {
|
||
h1 {
|
||
font-size: 1.3rem;
|
||
}
|
||
|
||
p {
|
||
font-size: 0.85rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.dashboard-main {
|
||
padding: 0.5rem;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.top-section {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.bottom-section {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.BB-section {
|
||
grid-template-columns: 1fr;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.right-section {
|
||
height: auto;
|
||
}
|
||
|
||
.action-items-compact {
|
||
height: 300px;
|
||
|
||
:deep(.action-items) {
|
||
.actions-summary {
|
||
grid-template-columns: repeat(4, 1fr);
|
||
|
||
.summary-item {
|
||
padding: 0.4rem;
|
||
|
||
.summary-count {
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 0.6rem;
|
||
}
|
||
}
|
||
}
|
||
|
||
.actions-list {
|
||
max-height: 150px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.team-detail-section {
|
||
padding: 1rem;
|
||
margin-top: 0.75rem;
|
||
|
||
.team-detail-header {
|
||
margin-bottom: 1.5rem;
|
||
|
||
h2 {
|
||
font-size: 1.2rem;
|
||
}
|
||
|
||
.team-summary {
|
||
gap: 1rem;
|
||
|
||
.summary-item {
|
||
|
||
.label,
|
||
.value {
|
||
font-size: 0.8rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.members-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 0.75rem;
|
||
|
||
.member-card {
|
||
padding: 0.75rem;
|
||
|
||
.member-header {
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
|
||
.member-status {
|
||
align-items: flex-start;
|
||
flex-direction: row;
|
||
gap: 0.5rem;
|
||
}
|
||
}
|
||
|
||
.member-metrics {
|
||
.metric-row {
|
||
grid-template-columns: 1fr;
|
||
gap: 0.5rem;
|
||
margin-bottom: 0.5rem;
|
||
|
||
.metric-item {
|
||
.metric-label {
|
||
font-size: 0.7rem;
|
||
}
|
||
|
||
.metric-value {
|
||
font-size: 0.8rem;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |