diff --git a/src/api/sales.js b/src/api/sales.js new file mode 100644 index 0000000..1c325b7 --- /dev/null +++ b/src/api/sales.js @@ -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 + }) +} diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue index c3e41a8..6535f18 100644 --- a/src/layout/components/Sidebar/index.vue +++ b/src/layout/components/Sidebar/index.vue @@ -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' } }, diff --git a/src/router/index.js b/src/router/index.js index 88666f0..df48683 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -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', diff --git a/src/views/screens/sales/index.vue b/src/views/screens/sales/index.vue new file mode 100644 index 0000000..f966ec2 --- /dev/null +++ b/src/views/screens/sales/index.vue @@ -0,0 +1,1327 @@ + + + + + diff --git a/vite.config.js b/vite.config.js index 85b4a76..7b114c3 100644 --- a/vite.config.js +++ b/vite.config.js @@ -34,6 +34,10 @@ export default defineConfig({ '/oee': { target: 'http://localhost:8080', changeOrigin: true + }, + '/crm': { + target: 'http://localhost:8080', + changeOrigin: true } } }