KA客户专员大屏仪表盘:基于streamlit构建的销售运营智能看板

重点客户的CDA,客户各业务的设定:

年度促销规划与渠道方案的执行与追踪;

import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
from datetime import datetime


# 启用缓存避免重复计算
@st.cache_data
def generate_data():
    """生成模拟数据集,包含客户、销售和应收账款数据"""
    np.random.seed(42)  # 固定随机种子保证数据一致性

    # 客户数据生成逻辑
    clients = pd.DataFrame({
        '客户名称': [f'客户A{i:02d}' for i in range(1, 31)],
        '本月销售额': np.random.lognormal(mean=10, sigma=0.3, size=30).astype(int) * 1000,
        '合作年限': np.random.randint(1, 6, 30),
        '库存金额': np.random.randint(10, 200, 30) * 1000,
        '货龄等级': np.random.choice(['新鲜库存<30天', '临期库存30-60天', '滞销库存>60天'], 30, p=[0.6, 0.3, 0.1]),
        '满意度': np.round(np.random.uniform(3.5, 5.0, 30), 1),
        '区域': np.random.choice(['华东', '华北', '华南', '西南'], 30)
    })

    # 销售时序数据(添加趋势项)
    date_rng = pd.date_range(start='2023-01-01', end='2023-12-31', freq='M')
    base_sales = np.linspace(1000000, 1500000, 12)  # 基础销售趋势
    sales = pd.DataFrame({
        '月份': date_rng,
        '销售额': (base_sales * np.random.normal(1, 0.1, 12)).astype(int),
        '促销金额': np.random.randint(20, 100, 12) * 10000,
        '产品线': np.random.choice(['健康食品', '家用器械', '个人护理'], 12)
    })

    # 应收账款数据生成
    receivables = pd.DataFrame({
        '客户名称': clients.sample(15, replace=False)['客户名称'].values,
        '应收金额': np.random.randint(5, 50, 15) * 10000,
        '账期状态': np.random.choice(['未到期', '逾期1-30天', '逾期31-60天', '逾期61天+'], 15),
        '超期天数': np.where(np.random.rand(15) > 0.7, np.random.randint(10, 90, 15), 0),
        '客户等级': np.random.choice(['VIP客户', '战略客户', '普通客户'], 15)
    })

    # 计算衍生指标
    receivables['已回收金额'] = receivables['应收金额'] * np.random.uniform(0.5, 1.0, 15)
    clients['库存周转天数'] = np.random.randint(15, 60, 30)

    return clients, sales, receivables


def main_dashboard():
    # 页面设置
    st.set_page_config(layout="wide", page_icon="📊", page_title="销售运营智能看板")
    st.title("📈 销售运营智能看板")

    # 加载数据
    df_clients, df_sales, df_receivables = generate_data()

    # ---- 侧边栏控件 ----
    with st.sidebar:
        st.header("数据筛选")
        selected_region = st.multiselect(
            "选择区域",
            options=df_clients['区域'].unique(),
            default=df_clients['区域'].unique()
        )

        selected_product = st.selectbox(
            "选择产品线",
            options=df_sales['产品线'].unique(),
            index=0
        )

        st.divider()
        st.download_button("下载客户数据",
                           df_clients.to_csv(index=False).encode('utf-8'),
                           "client_data.csv")
        st.download_button("下载销售数据",
                           df_sales.to_csv(index=False).encode('utf-8'),
                           "sales_data.csv")
        st.download_button("下载账款数据",
                           df_receivables.to_csv(index=False).encode('utf-8'),
                           "receivables_data.csv")
        st.caption(f"更新时间:{datetime.now().strftime('%Y-%m-%d %H:%M')}")

    # 数据筛选处理
    filtered_clients = df_clients[df_clients['区域'].isin(selected_region)]
    filtered_sales = df_sales[df_sales['产品线'] == selected_product]

    # ---- 顶部指标卡 ----
    col1, col2, col3, col4 = st.columns(4)
    with col1:
        current_sales = filtered_sales.iloc[-1]['销售额'] if not filtered_sales.empty else 0
        prev_sales = filtered_sales.iloc[-2]['销售额'] if len(filtered_sales) > 1 else current_sales
        change_pct = ((current_sales - prev_sales) / prev_sales) * 100 if prev_sales != 0 else 0
        st.metric("当月销售额", f"¥{current_sales / 10000:.1f}万",
                  f"环比{change_pct:+.1f}%")

    with col2:
        recovery_amount = df_receivables['已回收金额'].sum()
        total_receivable = df_receivables['应收金额'].sum()
        recovery_rate = (recovery_amount / total_receivable) * 100 if total_receivable != 0 else 0
        st.metric("账款回收率", f"{recovery_rate:.1f}%",
                  f"已回收¥{recovery_amount / 10000:.1f}万")

    with col3:
        avg_satisfaction = filtered_clients['满意度'].mean() if not filtered_clients.empty else 0
        st.metric("客户满意度", f"{avg_satisfaction:.1f}/5.0",
                  f"样本量:{len(filtered_clients)}")

    with col4:
        avg_turnover = filtered_clients['库存周转天数'].mean() if not filtered_clients.empty else 0
        st.metric("库存周转天数", f"{avg_turnover:.0f}天",
                  "行业基准:45天", delta_color="inverse")

    # ---- 主分析区 ----
    tab1, tab2, tab3 = st.tabs(["📊 销售分析", "👥 客户分析", "⏳ 账款监控"])

    with tab1:
        # 销售趋势分析
        fig = px.area(filtered_sales, x='月份', y='销售额',
                      title=f"{selected_product}销售趋势分析",
                      template="plotly_white",
                      color_discrete_sequence=['#1f77b4'],
                      line_group='产品线')
        fig.update_layout(hovermode="x unified")
        st.plotly_chart(fig, use_container_width=True)

        # 促销效果分析
        col1, col2 = st.columns(2)
        with col1:
            fig = px.bar(filtered_sales, x='月份', y='促销金额',
                         title="促销投入分布",
                         color_discrete_sequence=['#ff7f0e'],
                         text_auto='.2s')
            st.plotly_chart(fig, use_container_width=True)

        with col2:
            fig = px.pie(filtered_clients, values='本月销售额',
                         names='区域', hole=0.4,
                         title="区域销售占比",
                         color_discrete_sequence=px.colors.qualitative.Pastel)
            st.plotly_chart(fig, use_container_width=True)

    with tab2:
        # 客户价值分布
        col1, col2 = st.columns(2)
        with col1:
            fig = px.treemap(filtered_clients, path=['区域', '客户名称'],
                             values='本月销售额',
                             color='合作年限',
                             title="客户价值分布(面积=销售额)",
                             color_continuous_scale='Blues')
            st.plotly_chart(fig, use_container_width=True)

        with col2:
            # 库存健康度分析
            fig = px.sunburst(filtered_clients, path=['货龄等级', '客户名称'],
                              values='库存金额',
                              color='库存周转天数',
                              title="库存结构分析",
                              color_continuous_scale='RdYlGn_r')
            st.plotly_chart(fig, use_container_width=True)

            # 满意度分布
            fig = px.histogram(filtered_clients, x='满意度',
                               nbins=8,
                               title="客户满意度分布",
                               color_discrete_sequence=['#2ca02c'])
            st.plotly_chart(fig, use_container_width=True)

    with tab3:
        # 账款状态分析
        col1, col2 = st.columns([3, 1])
        with col1:
            fig = px.funnel(df_receivables, x='应收金额', y='账期状态',
                            color='客户等级',
                            title="应收账款账期分布",
                            color_discrete_map={
                                'VIP客户': '#9467bd',
                                '战略客户': '#8c564b',
                                '普通客户': '#17becf'
                            })
            st.plotly_chart(fig, use_container_width=True)

        with col2:
            st.subheader("超期账款预警")
            overdue = df_receivables[df_receivables['超期天数'] > 0]
            if not overdue.empty:
                overdue = overdue.sort_values('超期天数', ascending=False)
                for idx, row in overdue.iterrows():
                    progress_value = min(row['超期天数'] / 90, 1.0)
                    st.progress(progress_value,
                                f"{row['客户名称']} 超期{row['超期天数']}天")
            else:
                st.success("✅ 当前无超期账款")

            # 添加账款回收预测
            st.markdown("---")
            st.markdown("#### 回收预测")
            days_overdue = overdue['超期天数'].sum()
            predicted_recovery = 0.85 ** days_overdue * 100
            st.metric("预计回收率", f"{predicted_recovery:.1f}%")


if __name__ == "__main__":
    main_dashboard()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值