// 订单列表逻辑 (function() { // 存储 Token let authToken = ''; // 登录并获取订单数据 function loginAndFetchOrders() { // 如果已有 Token,直接获取订单 if (authToken) { fetchOrders(); return; } // 登录接口 $.ajax({ url: '/api/login', method: 'POST', contentType: 'application/json', data: JSON.stringify({ mobile: '18888888888', // 请替换为真实账号 password: '123456', // 请替换为真实密码 loginType: 0 }), success: function(res) { console.log('登录接口完整响应:', res); // 兼容多种 Token 返回结构 // 1. res.data.tokenValue (Sa-Token 常见) // 2. res.data.token (常见 JWT) // 3. res.token (根层级) // 4. res.data (直接返回字符串) let token = ''; if (res && res.code === 200) { if (res.data && res.data.tokenValue) { token = res.data.tokenValue; } else if (res.data && res.data.token) { token = res.data.token; } else if (res.token) { token = res.token; } else if (typeof res.data === 'string') { token = res.data; } } if (token) { authToken = token; console.log('登录成功,获取到Token:', authToken); fetchOrders(); fetchCattleOverview(); fetchSlaughterOverview(); } else { console.error('登录成功但未能提取Token,请检查响应结构:', res); } }, error: function(err) { console.error('登录请求错误:', err); } }); } // 获取订单列表 function fetchOrders() { if (!authToken) return; $.ajax({ url: '/api/delivery/pageQueryList', method: 'POST', // 假设是 POST 分页查询 contentType: 'application/json', headers: { 'Authorization': authToken, // 或者根据后端要求可能是其他 header key,如 satoken 'satoken': authToken }, data: JSON.stringify({ pageNo: 1, pageSize: 300, interfaceType: 2 }), success: function(res) { console.log('订单列表响应:', res); let list = []; if (res && res.data && Array.isArray(res.data.rows)) { // 适配 { code: 200, data: { rows: [...] } } 结构 list = res.data.rows; } else if (res && res.data && Array.isArray(res.data.records)) { // 适配 { code: 200, data: { records: [...] } } 结构 list = res.data.records; } else if (res && Array.isArray(res.data)) { // 适配 { code: 200, data: [...] } 结构 list = res.data; } renderOrderList(list); renderOrderStatusStats(list); updateMapWithFlyLines(list); }, error: function(err) { console.error('获取订单列表失败:', err); if (err.status === 401) { // Token 过期,重新登录 authToken = ''; loginAndFetchOrders(); } } }); } function renderOrderStatusStats(orders) { if (!orders || !Array.isArray(orders)) return; let pendingCount = 0; // status: 1 let shippingCount = 0; // status: 2 let doneCount = 0; // status: 3 orders.forEach(order => { const status = parseInt(order.status); if (status === 1) { pendingCount++; } else if (status === 2) { shippingCount++; } else if (status === 3) { doneCount++; } }); // 更新 DOM $('.stat-value[data-field="status_pending"]').text(pendingCount); $('.stat-value[data-field="status_shipping"]').text(shippingCount); $('.stat-value[data-field="status_done"]').text(doneCount); } function updateMapWithFlyLines(data) { if (!data || !Array.isArray(data)) return; const flyLineData = []; const pointMap = new Map(); // 用于去重地点 data.forEach(item => { // startLon, startLat, endLon, endLat if (item.startLon && item.startLat && item.endLon && item.endLat) { // 1. 飞线数据 flyLineData.push({ fromName: item.startLocation || item.startAddress || '', toName: item.endLocation || item.endAddress || '', coords: [ [parseFloat(item.startLon), parseFloat(item.startLat)], // 起点 [parseFloat(item.endLon), parseFloat(item.endLat)] // 终点 ] }); // 2. 起点数据 (用于显示名称) const startName = item.startLocation || item.startAddress || ''; if (startName) { const startKey = `${startName}_${item.startLon}_${item.startLat}`; if (!pointMap.has(startKey)) { pointMap.set(startKey, { name: startName, value: [parseFloat(item.startLon), parseFloat(item.startLat)] }); } } // 3. 终点数据 (用于显示名称) const endName = item.endLocation || item.endAddress || ''; if (endName) { const endKey = `${endName}_${item.endLon}_${item.endLat}`; if (!pointMap.has(endKey)) { pointMap.set(endKey, { name: endName, value: [parseFloat(item.endLon), parseFloat(item.endLat)] }); } } } }); // 更新 option8 (全局变量) if (typeof option8 !== 'undefined') { // series[1] 是线路 if (option8.series && option8.series[1]) { option8.series[1].data = flyLineData; } // series[3] 是运单地点 (我们在 chartMap.js 中新加的) if (option8.series && option8.series[3]) { option8.series[3].data = Array.from(pointMap.values()); } // 尝试获取 echarts 实例并更新 if (typeof myChart8 !== 'undefined') { myChart8.setOption(option8); } else if (window.myChart8) { window.myChart8.setOption(option8); } } } // 存储滚动定时器,防止重复创建 let orderScrollTimer = null; function renderOrderList(orders) { const container = $('.order_list_content'); if (container.length === 0) return; // 清除旧的定时器和事件监听 if (orderScrollTimer) { clearInterval(orderScrollTimer); orderScrollTimer = null; } container.off('mouseenter mouseleave'); let html = ''; if (orders.length === 0) { html = '
暂无运单
'; container.html(html); } else { orders.forEach((order, index) => { // 状态映射: 1-准备中,2-运送中,3-已结束 let statusText = '--'; let statusClass = ''; // 确保 status 是数字 const status = parseInt(order.status); switch(status) { case 1: statusText = '准备中'; statusClass = 'status-pending'; // 红色 break; case 2: statusText = '运送中'; statusClass = 'status-shipping'; // 黄色 break; case 3: statusText = '已结束'; statusClass = 'status-done'; // 绿色 break; default: statusText = '未知'; } html += `
${index + 1} ${order.deliveryNumber || '--'} ${order.startLocation || order.startAddress || '--'} ${order.endLocation || order.endAddress || '--'} ${statusText} ${order.estimatedDeliveryTime || '--'}
`; }); container.html(html); // 自动滚动逻辑 // 确保 DOM 渲染完成 setTimeout(() => { const scrollHeight = container[0].scrollHeight; const clientHeight = container.height(); // 只有当内容高度超过容器高度时才滚动 if (scrollHeight > clientHeight) { // 复制一份内容实现无缝滚动 container.append(html); let currentScroll = 0; function startScroll() { if (orderScrollTimer) clearInterval(orderScrollTimer); orderScrollTimer = setInterval(() => { currentScroll += 0.5; // 滚动速度,数值越小越慢 // 当滚动到第一份内容的末尾时,瞬间切换回顶部 if (currentScroll >= scrollHeight) { currentScroll = 0; } container.scrollTop(currentScroll); }, 20); // 刷新频率 } startScroll(); // 鼠标悬停暂停 container.on('mouseenter', function() { if (orderScrollTimer) clearInterval(orderScrollTimer); }); // 鼠标移开继续 container.on('mouseleave', function() { startScroll(); }); } }, 100); } } // 初始化 $(function() { loginAndFetchOrders(); // 定时刷新 (每30秒) setInterval(() => { if (authToken) { fetchOrders(); fetchCattleOverview(); fetchSlaughterOverview(); } else { loginAndFetchOrders(); } }, 30000); }); // 获取牛只概况(仓库列表) function fetchCattleOverview() { if (!authToken) return; $.ajax({ url: '/api/warehouse/list', method: 'POST', // 改为 POST contentType: 'application/json', headers: { 'Authorization': 'Bearer ' + authToken, 'satoken': authToken }, data: JSON.stringify({ pageNo: 1, pageSize: 100 // 假设需要分页参数,如果不传可能会报错 }), success: function(res) { console.log('牛只概况响应:', res); let list = []; // 适配双层嵌套结构: res.data.data.rows if (res && res.code === 200 && res.data) { if (res.data.data && Array.isArray(res.data.data.rows)) { // 结构: { code: 200, data: { data: { rows: [...] } } } list = res.data.data.rows; } else if (res.data.rows && Array.isArray(res.data.rows)) { // 结构: { code: 200, data: { rows: [...] } } list = res.data.rows; } else if (Array.isArray(res.data)) { list = res.data; } } renderCattleOverview(list); updateMapWithWarehouseData(list); }, error: function(err) { console.error('获取牛只概况失败:', err); } }); } function updateMapWithWarehouseData(data) { if (!data || !Array.isArray(data)) return; const mapData = data.map(item => { if (item.longitude && item.latitude) { return { name: item.warehouseName || '未知仓库', value: [parseFloat(item.longitude), parseFloat(item.latitude)] }; } return null; }).filter(item => item !== null); // 更新 option8 (全局变量) if (typeof option8 !== 'undefined') { // 假设 series[0] 是 scatter/effectScatter 用于显示地点 if (option8.series && option8.series[0]) { option8.series[0].data = mapData; } // 尝试获取 echarts 实例并更新 // myChart8 在 index.html 中定义为 var myChart8 (全局) if (typeof myChart8 !== 'undefined') { myChart8.setOption(option8); } else if (window.myChart8) { window.myChart8.setOption(option8); } } } function renderCattleOverview(data) { const container = $('#cattle_overview_container'); if (container.length === 0) return; let html = ''; if (!data || data.length === 0) { html = '
暂无数据
'; } else { data.forEach(item => { // 接口字段: warehouseName, account if (item.account === undefined) { console.warn('牛只概况接口返回数据缺少 account 字段,请检查接口文档或后端返回:', item); } const name = item.warehouseName || '--'; const value = item.account || 0; html += `
${name}
${value}
`; }); } container.html(html); } // 获取屠宰场概况 function fetchSlaughterOverview() { if (!authToken) return; $.ajax({ url: '/api/slaughter/house/list', method: 'POST', contentType: 'application/json', headers: { 'Authorization': 'Bearer ' + authToken, 'satoken': authToken }, data: JSON.stringify({ pageNo: 1, pageSize: 100 }), success: function(res) { console.log('屠宰场概况响应:', res); let list = []; // 适配双层嵌套结构: res.data.data.rows if (res && res.code === 200 && res.data) { if (res.data.data && Array.isArray(res.data.data.rows)) { list = res.data.data.rows; } else if (res.data.rows && Array.isArray(res.data.rows)) { list = res.data.rows; } else if (Array.isArray(res.data)) { list = res.data; } } renderSlaughterOverview(list); updateMapWithSlaughterData(list); }, error: function(err) { console.error('获取屠宰场概况失败:', err); } }); } function updateMapWithSlaughterData(data) { if (!data || !Array.isArray(data)) return; const mapData = data.map(item => { if (item.longitude && item.latitude) { return { name: item.houseName || '未知屠宰场', value: [parseFloat(item.longitude), parseFloat(item.latitude)] }; } return null; }).filter(item => item !== null); // 更新 option8 (全局变量) if (typeof option8 !== 'undefined') { // series[2] 是屠宰场 if (option8.series && option8.series[2]) { option8.series[2].data = mapData; } // 尝试获取 echarts 实例并更新 if (typeof myChart8 !== 'undefined') { myChart8.setOption(option8); } else if (window.myChart8) { window.myChart8.setOption(option8); } } } function renderSlaughterOverview(data) { const container = $('#slaughterhouse_overview_container'); if (container.length === 0) return; let html = ''; if (!data || data.length === 0) { html = '
暂无数据
'; } else { data.forEach(item => { // 接口字段: houseName, account const name = item.houseName || '--'; const value = item.account || 0; html += `
${name}
${value}
`; }); } container.html(html); } })(); // 移除旧的模拟数据逻辑 /* (function() { // ... 旧代码 ... })(); */ // 牛只行情列表逻辑 (function() { let scrollInterval; function fetchAndRenderMarketList() { $.ajax({ // 使用本地代理接口解决跨域问题 // 原接口: https://ad.yunmainiu.com/api/cattle-data // 代理配置在 server.js 中: /api/cattle-market-data -> https://ad.yunmainiu.com/api/cattle-data url: '/api/cattle-market-data', method: 'GET', success: function(response) { // 尝试解析字符串响应 if (typeof response === 'string') { try { response = JSON.parse(response); } catch (e) { console.error('JSON解析失败:', e); } } let data = []; // 兼容可能的返回格式:直接数组 或 { data: [] } if (Array.isArray(response)) { data = response; } else if (response && Array.isArray(response.data)) { data = response.data; } else if (response && Array.isArray(response.list)) { data = response.list; } console.log('获取到的牛只行情数据:', data); renderMarketList(data); }, error: function(err) { console.error('获取牛只行情数据失败:', err); // 失败时显示空或错误提示,或者保留旧数据 } }); } function renderMarketList(data) { const container = $('.market_list_content'); if (container.length === 0) return; let html = ''; if (data.length === 0) { html = '
暂无数据
'; } else { data.forEach((item, index) => { // 接口字段: province(省份), location(地区), type(品种), price(单价) html += `
${index + 1} ${item.province || '--'} ${item.location || '--'} ${item.type || '--'} ${item.price || '--'}
`; }); } container.html(html); // 清除旧的滚动定时器 if (scrollInterval) { clearInterval(scrollInterval); scrollInterval = null; } // 简单的自动滚动效果 // 需要等待DOM渲染完成后计算高度,这里简单使用setTimeout setTimeout(() => { let scrollPos = 0; // 重新获取DOM元素属性,确保准确 const scrollHeight = container[0].scrollHeight; const clientHeight = container[0].clientHeight; // 只有当内容高度超过容器高度时才滚动 if (scrollHeight > clientHeight) { scrollInterval = setInterval(() => { scrollPos += 1; // 当滚动到底部时,回到顶部 if (scrollPos >= scrollHeight - clientHeight) { scrollPos = 0; } container.scrollTop(scrollPos); }, 50); } }, 100); } $(function() { fetchAndRenderMarketList(); // 每60秒刷新一次数据 setInterval(fetchAndRenderMarketList, 60000); }); })(); // 出肉率图表逻辑 (function() { // 确保 DOM 加载完成 $(function() { const chartDom = document.getElementById('meat_yield_chart'); if (!chartDom) return; const myChart = echarts.init(chartDom); const option = { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, grid: { left: '3%', right: '10%', bottom: '3%', top: '10%', containLabel: true }, xAxis: { type: 'value', axisLabel: { color: '#fff', fontSize: 12 }, splitLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.1)' } }, axisLine: { show: true, lineStyle: { color: '#fff' } } }, yAxis: { type: 'category', data: ['鲁西黄牛', '西门塔尔', '夏洛莱', '利木赞', '安格斯'], axisLabel: { color: '#fff', fontSize: 12 }, axisLine: { show: true, lineStyle: { color: '#fff' } } }, series: [ { name: '出肉率', type: 'bar', data: [45, 52, 58, 55, 60], itemStyle: { normal: { color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ { offset: 0, color: '#2b86ff' }, { offset: 1, color: '#1effc0' } ]), barBorderRadius: [0, 5, 5, 0] } }, label: { show: true, position: 'right', formatter: '{c}%', color: '#fff' }, barWidth: '40%' } ] }; myChart.setOption(option); // 窗口大小改变时重置图表大小 window.addEventListener("resize", function () { myChart.resize(); }); // 模拟数据动态变化 setInterval(() => { const newData = option.series[0].data.map(val => { let change = Math.floor(Math.random() * 3) - 1; let newVal = val + change; if (newVal > 70) newVal = 70; if (newVal < 35) newVal = 35; return newVal; }); myChart.setOption({ series: [{ data: newData }] }); }, 5000); }); })();