销售信息大屏初版

This commit is contained in:
jhd
2026-06-01 15:43:46 +08:00
parent a4409e5afe
commit 20d376e93e
5 changed files with 1458 additions and 2 deletions

117
src/api/sales.js Normal file
View File

@@ -0,0 +1,117 @@
import request from '@/utils/request'
// ===== Mock 数据(后端无认证时兜底) =====
const mockSummary = {
totalOrderCount: 450,
totalSalesAmount: 9860,
completedOrderCount: 320,
completedSalesAmount: 7230,
totalUnpaidAmount: 2630,
avgOrderAmount: 21.9
}
const mockSalesmanStats = [
{ salesmanName: '张伟', totalAmount: 12560000 },
{ salesmanName: '李强', totalAmount: 9820000 },
{ salesmanName: '王芳', totalAmount: 8750000 },
{ salesmanName: '赵磊', totalAmount: 6540000 },
{ salesmanName: '刘洋', totalAmount: 5210000 },
{ salesmanName: '陈静', totalAmount: 3980000 },
{ salesmanName: '杨光', totalAmount: 2850000 }
]
const mockLevelStats = [
{ customerLevel: '高', count: 400 },
{ customerLevel: '中', count: 44 },
{ customerLevel: '低', count: 1 },
{ customerLevel: 'VIP', count: 1 }
]
const mockIndustryStats = [
{ industry: '制造业', count: 168 },
{ industry: '贸易', count: 165 },
{ industry: '加工业', count: 115 },
{ industry: '互联网', count: 1 }
]
const mockOrders = [
{ orderNo: 'ORD20260515001', customer: '周口钢铁', product: '冷轧卷', amount: 125000, status: '生产中', time: '10:30' },
{ orderNo: 'ORD20260515002', customer: '南阳重工', product: '镀锌板', amount: 89000, status: '已完成', time: '09:45' },
{ orderNo: 'ORD20260515003', customer: '洛阳机械', product: '酸洗板', amount: 156000, status: '待生产', time: '11:20' },
{ orderNo: 'ORD20260515004', customer: '开封汽配', product: '冷轧卷', amount: 67000, status: '生产中', time: '08:15' },
{ orderNo: 'ORD20260515005', customer: '商丘金属', product: '镀铬板', amount: 45000, status: '已完成', time: '07:30' },
{ orderNo: 'ORD20260515006', customer: '山东福安德', product: '镀锌板', amount: 234000, status: '生产中', time: '14:20' },
{ orderNo: 'ORD20260515007', customer: '临沂屹钢', product: '冷轧卷', amount: 187000, status: '待生产', time: '13:45' },
{ orderNo: 'ORD20260515008', customer: '江苏永腾', product: '酸洗板', amount: 92000, status: '已完成', time: '15:10' },
{ orderNo: 'ORD20260515009', customer: '武汉欣航晟', product: '镀锌板', amount: 76000, status: '生产中', time: '16:30' },
{ orderNo: 'ORD20260515010', customer: '天津盛盈', product: '冷轧卷', amount: 198000, status: '待生产', time: '17:00' },
{ orderNo: 'ORD20260515011', customer: '河南宏之澳', product: '镀铬板', amount: 54000, status: '生产中', time: '09:20' },
{ orderNo: 'ORD20260515012', customer: '上海圳洋', product: '镀锌板', amount: 312000, status: '已完成', time: '11:50' },
{ orderNo: 'ORD20260515013', customer: '许昌涵博', product: '酸洗板', amount: 43000, status: '待生产', time: '08:40' },
{ orderNo: 'ORD20260515014', customer: '济宁钰昌', product: '冷轧卷', amount: 88000, status: '生产中', time: '14:10' },
{ orderNo: 'ORD20260515015', customer: '无锡昌德', product: '镀锌板', amount: 165000, status: '已完成', time: '10:00' }
]
const withMock = (apiFn, mockData) => {
return async (params) => {
try {
const res = await apiFn(params)
// request.js 在 401 时返回 [],此时降级为 mock
if (Array.isArray(res) && res.length === 0) return { data: mockData }
return { data: (res && res.data !== undefined) ? res.data : res }
} catch {
return { data: mockData }
}
}
}
/**
* 销售汇总指标
*/
export const getSalesSummary = withMock(
(params) => request({ url: '/crm/salesReport/summary', method: 'get', params }),
mockSummary
)
/**
* 销售员统计排行
*/
export const getSalesmanStats = withMock(
(params) => request({ url: '/crm/salesReport/salesmanStats', method: 'get', params }),
mockSalesmanStats
)
/**
* 客户等级分布
*/
export const getCustomerLevelStats = withMock(
(params) => request({ url: '/crm/salesReport/customerLevelStats', method: 'get', params }),
mockLevelStats
)
/**
* 行业分布统计
*/
export const getIndustryStats = withMock(
(params) => request({ url: '/crm/salesReport/industryStats', method: 'get', params }),
mockIndustryStats
)
/**
* 订单明细列表
*/
export const getOrderDetails = withMock(
(params) => request({ url: '/crm/salesReport/orderDetails', method: 'get', params }),
{ rows: mockOrders, total: mockOrders.length }
)
/**
* 完整销售报表(一次性返回所有数据)
*/
export function getFullSalesReport(params) {
return request({
url: '/crm/salesReport/fullReport',
method: 'get',
params
})
}

View File

@@ -29,7 +29,7 @@
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { Monitor, PieChart, Document, Bell } from '@element-plus/icons-vue'
import { Monitor, PieChart, Document, Bell, Coin } from '@element-plus/icons-vue'
const route = useRoute()
const store = useStore()
@@ -44,7 +44,8 @@ const iconMap = {
'energy': Monitor,
'oee': PieChart,
'output': PieChart,
'stop': Bell
'stop': Bell,
'sales': Coin
}
const getIcon = (iconName) => {
@@ -52,6 +53,7 @@ const getIcon = (iconName) => {
}
const menuItems = [
{ path: '/sales', meta: { title: '销售信息大屏', icon: 'sales' } },
{ path: '/dashboard/order', meta: { title: '订单大屏', icon: 'order' } },
{ path: '/dashboard/cost', meta: { title: '成本大屏', icon: 'cost' } },
{ path: '/dashboard/energy', meta: { title: '能源大屏', icon: 'energy' } },

View File

@@ -62,6 +62,12 @@ export const constantRoutes = [
component: () => import('@/views/screens/warehouse-overview/index.vue'),
meta: { title: '库区总览大屏' }
},
{
path: '/sales',
name: 'SalesOverview',
component: () => import('@/views/screens/sales/index.vue'),
meta: { title: '销售信息大屏' }
},
{
path: '/wip',
name: 'WipOverview',

File diff suppressed because it is too large Load Diff

View File

@@ -34,6 +34,10 @@ export default defineConfig({
'/oee': {
target: 'http://localhost:8080',
changeOrigin: true
},
'/crm': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}