You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
hy-trading-demo/PROJECT_HISTORY.md

14 KiB

项目开发历史记录

一、项目概述

本项目是一个牦牛产业数据可视化平台,采用 Vue.js 框架开发,包含多个功能模块:交易流向监测、市场环境监测、多维度市场分析、牦牛供应展示等。平台集成了 Element UI 组件库和 ECharts 数据可视化库,实现了响应式布局和交互式数据展示功能。

技术栈:

  • 前端框架:Vue.js 3.x(Composition API)
  • UI 组件库:Element Plus
  • 图表库:ECharts
  • 地图数据:GeoJSON(china.json)
  • 样式方案:CSS Scoped + CSS Flexbox/Grid
  • 构建工具:Vite

二、组件架构演变

2.1 初始阶段:单文件 App.vue

项目最初是一个单文件的 App.vue,包含了所有的业务逻辑和 UI 代码。随着功能增加,代码变得臃肿,难以维护。

2.2 组件拆分阶段

按照单一职责原则,将 monolithic App.vue 拆分为以下独立组件:

src/components/
├── AppHeader.vue          # 顶部导航栏
├── TransactionStats.vue   # 实时交易统计
├── SalesChart.vue         # 销售趋势图表
├── YakPopulationChart.vue # 牦牛存栏图表
├── FlowMonitorMap.vue     # 交易流向地图
├── SceneManagement.vue    # 场景管理(监控+环境)
└── MarketAnalysis.vue     # 多维度市场分析

三、主题风格演变

3.1 初始深绿色主题

最初尝试使用偏绿色的深色风格,模拟草原风格:

--primary-color: #22c55e;
--primary-dark: #15803d;
--background-dark: #0f172a;
--card-dark: #1e293b;

3.2 朴素灰色白色主题

用户反馈绿色不太合适,要求改回朴实一点的深色主题:

--background-color: #f8fafc;
--card-background: #ffffff;
--text-primary: #1e293b;
--text-secondary: #64748b;
--border-color: #e2e8f0;
--primary-color: #22c55e;  /* 保留绿色作为强调色 */

3.3 顶部导航栏样式

将顶部导航栏从白色改为深蓝色,增强视觉层次:

.app-header {
    background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%);
    color: white;
}

四、核心功能模块实现

4.1 场景管理组件(SceneManagement.vue)

场景管理组件是平台的核心模块之一,负责展示监控视频和环境监测数据。

布局演变:

  1. 初始布局:简单的垂直排列
  2. 卡片式布局:引入 Element UI 的 el-card 组件
  3. 双栏布局:左侧展示环境指标,右侧展示监控视频

最终布局结构:

<el-row :gutter="20">
    <!-- 左侧:环境监测指标 -->
    <el-col :span="12">
        <div class="indicators-left">
            <div class="indicator-row">
                <env-card v-for="item in firstRowIndicators" :key="item.id" :data="item" />
            </div>
            <div class="indicator-row">
                <env-card v-for="item in secondRowIndicators" :key="item.id" :data="item" />
            </div>
        </div>
    </el-col>
    
    <!-- 右侧:监控视频 -->
    <el-col :span="12">
        <div class="monitor-right">
            <div class="video-container" v-for="camera in activeCameras" :key="camera.id">
                <video :src="camera.src" controls />
                <div class="video-info">
                    <span class="camera-name">{{ camera.name }}</span>
                </div>
            </div>
            <div class="video-nav">
                <button @click="switchToPrevCamera" :disabled="currentCameraIndex === 0"></button>
                <button @click="switchToNextCamera" :disabled="currentCameraIndex === cameras.length - 1"></button>
            </div>
        </div>
    </el-col>
</el-row>

环境监测状态样式:

.env-card.normal {
    background: #ffffff;
    border: 1px solid #e2e8f0;
}

.env-card.warning {
    background: #fef2f2;
    border: 1px solid #fecaca;
}

.env-card.critical {
    background: #fef2f2;
    border: 1px solid #ef4444;
}

4.2 交易流向监测组件(FlowMonitorMap.vue)

使用 ECharts 实现地理数据可视化,展示牦牛销售网络、源地供应和红原出栏分布。

实现方案:

<script setup>
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';

const props = defineProps({
    mapData: {
        type: Object,
        default: null
    }
});

const chartRef = ref(null);
let chart = null;
let chinaMapData = null;

const mapTypes = [
    { value: 'sales', label: '销售网络分布' },
    { value: 'supply', label: '源地供应分布' },
    { value: 'slaughter', label: '红原出栏分布' }
];

const activeMapType = ref('sales');

const initChart = async () => {
    chart = echarts.init(chartRef.value);
    
    const response = await fetch('/data/china.json');
    chinaMapData = await response.json();
    echarts.registerMap('china', chinaMapData);
    
    updateChart();
    window.addEventListener('resize', handleResize);
};

const updateChart = () => {
    const data = mockData[activeMapType.value];
    
    const option = {
        backgroundColor: '#f5f7fa',
        title: {
            text: data.title,
            subtext: data.subtitle,
            left: 'center',
            top: 20
        },
        geo: {
            map: 'china',
            roam: true,
            center: data.center,
            zoom: data.zoom,
            itemStyle: {
                areaColor: '#e2e8f0',
                borderColor: '#94a3b8'
            }
        },
        series: [
            {
                type: 'lines',
                coordinateSystem: 'geo',
                lineStyle: {
                    color: '#22c55e',
                    width: 2,
                    curveness: 0.15
                },
                effect: {
                    show: true,
                    period: 4,
                    trailLength: 0.3,
                    symbol: 'arrow',
                    symbolSize: 8
                }
            },
            {
                name: '核心',
                type: 'effectScatter',
                coordinateSystem: 'geo',
                symbolSize: (val) => val[2] / 2,
                itemStyle: {
                    color: '#ef4444'
                },
                rippleEffect: {
                    brushType: 'stroke',
                    scale: 3
                }
            }
        ]
    };
    
    chart.setOption(option, true);
};
</script>

4.3 多维度市场分析组件(MarketAnalysis.vue)

包含三个分析维度:销售结构分析、价格趋势分析、客户来源分析。

布局结构:

<el-row :gutter="20">
    <el-col :span="12">
        <el-card>
            <template #header>
                <div class="card-header">
                    <span>销售结构分析</span>
                    <el-radio-group v-model="salesViewType" size="small">
                        <el-radio-button value="pie">饼图</el-radio-button>
                        <el-radio-button value="bar">柱状图</el-radio-button>
                    </el-radio-group>
                </div>
            </template>
            <div ref="salesChartRef" class="chart-container" />
        </el-card>
    </el-col>
    
    <el-col :span="12">
        <el-card>
            <template #header>
                <div class="card-header">
                    <span>价格趋势分析</span>
                    <el-radio-group v-model="pricePeriod" size="small">
                        <el-radio-button value="week"></el-radio-button>
                        <el-radio-button value="month"></el-radio-button>
                        <el-radio-button value="year"></el-radio-button>
                    </el-radio-group>
                </div>
            </template>
            <div ref="priceChartRef" class="chart-container" />
        </el-card>
    </el-col>
</el-row>

<el-row :gutter="20" style="margin-top: 20px;">
    <el-col :span="24">
        <el-card>
            <template #header>
                <div class="card-header">
                    <span>客户来源分析</span>
                </div>
            </template>
            <div ref="customerChartRef" class="chart-container" />
        </el-card>
    </el-col>
</el-row>

五、数据架构演变

5.1 初始阶段:组件内嵌 mock 数据

各组件内部定义模拟数据,导致数据冗余和重复请求。

const mockData = {
    salesByPriceRange: [...],
    priceTrend: [...],
    // ...
};

5.2 JSON 文件阶段

将 mock 数据移到静态 JSON 文件:

{
    "marketAnalysis": {
        "salesByPriceRange": [...],
        "salesByRegion": [...],
        "priceTrend": [...],
        "customerSource": [...]
    }
}

5.3 共享数据架构阶段(最终方案)

在 App.vue 中集中获取数据,通过 props 传递给子组件:

// App.vue
<script setup>
import { ref, onMounted } from 'vue';
import SceneManagement from './components/SceneManagement.vue';
import MarketAnalysis from './components/MarketAnalysis.vue';
import FlowMonitorMap from './components/FlowMonitorMap.vue';

const sharedData = ref(null);

const fetchSharedData = async () => {
    try {
        const response = await fetch('/data/mockData.json');
        sharedData.value = await response.json();
    } catch (error) {
        console.error('获取共享数据失败:', error);
    }
};

onMounted(() => {
    fetchSharedData();
});
</script>

<template>
    <SceneManagement v-if="sharedData" :scene-data="sharedData.sceneData" />
    <MarketAnalysis v-if="sharedData" :market-analysis-data="sharedData.marketAnalysis" />
    <FlowMonitorMap v-if="sharedData" :map-data="sharedData.flowData" />
</template>

优势:

  • 减少网络请求次数(只请求一次)
  • 保证数据一致性
  • 便于数据管理和维护

六、关键文件结构

zhhxjy/
├── public/
│   └── data/
│       ├── mockData.json      # 共享模拟数据
│       └── china.json         # 中国地图地理数据
├── src/
│   ├── components/
│   │   ├── AppHeader.vue      # 顶部导航
│   │   ├── TransactionStats.vue
│   │   ├── SalesChart.vue
│   │   ├── YakPopulationChart.vue
│   │   ├── FlowMonitorMap.vue # 交易流向地图
│   │   ├── SceneManagement.vue # 场景管理
│   │   └── MarketAnalysis.vue  # 市场分析
│   ├── App.vue                # 主应用组件
│   ├── main.js                # 应用入口
│   └── style.css              # 全局样式
├── index.html
├── package.json
└── vite.config.js

七、遇到的问题及解决方案

7.1 地图数据加载失败

问题:从外部 URL 下载地图数据失败(404 错误)

解决方案

  • 使用本地 china.json 文件
  • 放置在 public/data/ 目录下
  • 通过 /data/china.json 路径访问

7.2 视频容器高度不匹配

问题:增加视频宽度后,容器高度计算错误,导致内容溢出或留白

解决方案

.video-wrapper {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.video-content {
    flex: 1;
    height: 100%;
}

.video-info-main {
    flex: 1;
    display: flex;
    flex-direction: column;
}

7.3 右侧导航按钮消失

问题:视频宽度增加后,右侧切换按钮被隐藏

解决方案

.monitor-right {
    width: 800px;  /* 增加容器宽度 */
}

.video-content {
    width: 320px;  /* 固定视频宽度 */
}

7.4 预警颜色不一致

问题:环境监测的预警状态使用了黄色主题,与整体风格不符

解决方案

.env-card.warning {
    background: #fef2f2;
    border: 1px solid #fecaca;
}

.env-card.critical {
    background: #fef2f2;
    border: 1px solid #ef4444;
}

.warning-badge {
    background: #ef4444;
    color: white;
}

7.5 Mock 数据位置错误

问题:mockData.json 放在 src/data 目录,无法通过 HTTP 请求访问

解决方案

  • 创建 public/data/ 目录
  • 将 mockData.json 移动到新目录
  • 通过 /data/mockData.json 路径访问

八、开发里程碑

里程碑 1:组件拆分

  • 完成 App.vue 到独立组件的拆分
  • 建立规范的目录结构

里程碑 2:主题定制

  • 实现灰色白色主题
  • 保留绿色作为强调色
  • 优化顶部导航栏样式

里程碑 3:布局优化

  • 实现卡片式布局
  • 优化监控视频布局
  • 修复各种溢出和高度问题

里程碑 4:数据架构

  • 实现共享数据获取
  • 减少冗余请求
  • 统一数据管理

里程碑 5:地图集成

  • 实现本地地图数据加载
  • 完成交易流向可视化
  • 添加交互控制功能

九、后续优化建议

  1. 性能优化:对 ECharts 图表实现懒加载
  2. 响应式设计:增加移动端适配
  3. 数据可视化:添加更多交互功能(缩放、筛选、导出)
  4. 错误处理:增加请求失败的重试机制和错误提示
  5. 代码规范:添加 TypeScript 类型支持
  6. 测试覆盖:增加单元测试和 E2E 测试

十、技术要点总结

功能 技术方案 关键代码
组件通信 Props + Events defineProps(), defineEmits()
状态管理 Ref + Watch ref(), watch()
图表渲染 ECharts echarts.init(), chart.setOption()
地图渲染 ECharts Geo registerMap(), geo 配置
卡片布局 Element UI el-card, el-row, el-col
数据获取 Fetch API fetch('/data/xxx.json')
样式隔离 Scoped CSS <style scoped>
响应式 Flexbox display: flex, flex: 1

文档生成时间:2025-12-27