diff --git a/config/routes.js b/config/routes.js index 4fec1eb..a5c011c 100644 --- a/config/routes.js +++ b/config/routes.js @@ -586,6 +586,60 @@ export default [ component: './order/exOrder', access: 'k31', }, + { + name: '营销报表', + path: '/order/order-market-report', + component: './order/order-market-report', + access: 'k31', + }, + { + name: '订单报表', + path: '/order/order-report', + component: './order/order-report', + access: 'k31', + }, + { + name: '订单报表详情', + path: '/order/order-report/order-report-detail', + component: './order/order-report-detail', + access: 'k31', + }, + { + name: '营收报表', + path: '/order/order-revenue-statement', + component: './order/order-revenue-statement', + access: 'k31', + }, + { + name: '产品报表', + path: '/order/order-product-report', + component: './order/order-product-report', + access: 'k31', + }, + { + name: '会员报表', + path: '/order/order-member-statement', + component: './order/order-member-statement', + access: 'k31', + }, + { + name: '销售成本分析', + path: '/order/cost-of-sales', + component: './order/cost-of-sales', + access: 'k31', + }, + { + name: '销售毛利分析', + path: '/order/sales-gross-profit', + component: './order/sales-gross-profit', + access: 'k31', + }, + { + name: '门店销售毛利分析', + path: '/order/gross-profit-store-sales', + component: './order/gross-profit-store-sales', + access: 'k31', + }, ], }, { diff --git a/src/pages/order/cost-of-sales/index.jsx b/src/pages/order/cost-of-sales/index.jsx new file mode 100644 index 0000000..f815970 --- /dev/null +++ b/src/pages/order/cost-of-sales/index.jsx @@ -0,0 +1,245 @@ +import React, { useState, useEffect } from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker, Table, Pagination, Spin, Select, message } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +import costSalesAPI from "./service"; +import moment from 'moment'; + +const columns = [ + { + title: '门店名称', + dataIndex: 'storeId', + key: 'storeId', + }, + { + title: '商品名称', + dataIndex: 'goodsId', + key: 'goodsId', + }, + { + title: '销售收入', + dataIndex: 'salesPrice', + key: 'salesPrice', + }, + { + title: '销售成本', + dataIndex: 'costPrice', + key: 'costPrice', + }, + { + title: '销售数量', + dataIndex: 'salesNum', + key: 'salesNum', + }, + { + title: '成本率', + dataIndex: 'costRate', + key: 'costRate', + } +]; + +const LoadingCard = () => { + return ( +
+ +
+ ) +} + +/** + * 销售成本分析 + * @returns + */ +export default function Index() { + + //订单报表列表 + const [costSalesData, setCostSalesData] = useState([]); + const [current, setCurrent] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + const [showLoading, setShowLoading] = useState(false); + const [timeRange, setTimeRange] = useState([ + moment(moment(new Date(Date.now() - 24 * 60 * 60 * 1000 * 7)).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), + ]); //日期选择器 + //门店 + const [storeIdArray, setStoreIdArray] = useState([]); + const [storeSelect, setStoreSelect] = useState([]); + //商品 + const [goodsIdArray, setGoodsIdArray] = useState([]); + const [goodsIdSelect, setGoodsIdSelect] = useState([]); + //商品类型 + const [goodsTypeArray, setGoodsTypeArray] = useState([]); + const [goodsTypeSelect, setGoodsTypeSelect] = useState([]); + + //页码变化 + const onPageChange = (current, pageSize) => { + setCurrent(current); + setPageSize(pageSize); + } + + //查询 + const onQueryReportSalescost = async () => { + const jsonData = { + "storeId": storeIdArray, + "goodsId": goodsIdArray, + "goodsTypeId": goodsTypeArray, + "begintime": timeRange[0], + "endtime": timeRange[1], + current, + pageSize + } + setShowLoading(true); + const response = await costSalesAPI.getReportSalescost({}); + setShowLoading(false); + if (response.statusCode === 200) { + setCostSalesData(response.data.data); + } else { + message.error(response.errors || '获取销售成本失败'); + } + } + + /** + * 查询店铺列表 + */ + const onQueryStoreList = async () => { + setShowLoading(true); + const response = await costSalesAPI.gettree({}); + setShowLoading(false); + if (response.statusCode === 200) { + const storeList = []; + response.data.forEach(item => { + if (item.type === 2 || item.type === 3) { + storeList.push(item) + } + }) + setStoreSelect(storeList); + } else { + message.error('查询店铺列表失败'); + } + } + + //查询商品列表 + const onQueryGoodsList = async () => { + setShowLoading(true); + const response = await costSalesAPI.goodsList({}); + setShowLoading(false); + if (response.statusCode === 200) { + setGoodsIdSelect(response.data); + } else { + message.error('查询商品列表失败'); + } + } + + //查询商品分类类型列表 + const onQueryGoodsType = async () => { + setShowLoading(true); + const response = await costSalesAPI.goodsTypeList({}); + setShowLoading(false); + if (response.statusCode === 200) { + setGoodsTypeSelect(response.data); + } else { + message.error('查询商品分类列表失败'); + } + } + + useEffect(() => { + onQueryReportSalescost(); + onQueryStoreList(); + onQueryGoodsList(); + onQueryGoodsType(); + }, []); + + return ( + + {showLoading ? : null} + +
+
+ + + + { + let tempDate = [ + moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD 23:59:59')), + ] + setTimeRange(tempDate); + }} /> +
+
+ + +
+
+
+ + +
+ +
+ + + ) +} diff --git a/src/pages/order/cost-of-sales/index.less b/src/pages/order/cost-of-sales/index.less new file mode 100644 index 0000000..c33fc6a --- /dev/null +++ b/src/pages/order/cost-of-sales/index.less @@ -0,0 +1,36 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-page { + display: flex; + justify-content: flex-end; + align-items: center; + height: 50px; +} + +// 加载中 +.loading-card { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.5); +} \ No newline at end of file diff --git a/src/pages/order/cost-of-sales/service.js b/src/pages/order/cost-of-sales/service.js new file mode 100644 index 0000000..bb2fdb4 --- /dev/null +++ b/src/pages/order/cost-of-sales/service.js @@ -0,0 +1,40 @@ +import { request } from 'umi'; + +export default { + getReportSalescost(data) { + return request(`/kitchen/api/report/salescost`, { + method: 'Post', + data: data, + }); + }, + /** + * 查询商品信息 + */ + goodsList(data) { + return request(`/kitchen/api/goodes/list`, { + method: 'Post', + data: data, + }); + }, + /** + * 查询商品类型 + */ + goodsTypeList(data) { + return request(`/kitchen/api/goodstype/list`, { + method: 'Post', + data: data, + }); + }, + + /** + * 查询门店列表 + */ + gettree(params) { + return request('​/kitchen/api​/sysOrg​/tree', { + data: { + ...params, + }, + }); + } + +}; diff --git a/src/pages/order/gross-profit-store-sales/index.jsx b/src/pages/order/gross-profit-store-sales/index.jsx new file mode 100644 index 0000000..5d5b1f7 --- /dev/null +++ b/src/pages/order/gross-profit-store-sales/index.jsx @@ -0,0 +1,149 @@ +import React, { useState, useEffect } from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker, Table, Pagination, Spin, Select, message } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +import costSalesAPI from "./service"; +import moment from 'moment'; + +const columns = [ + { + title: '门店名称', + dataIndex: 'storeId', + key: 'storeId', + }, + { + title: '毛利率', + dataIndex: 'marginRatio', + key: 'marginRatio', + } +]; + +const LoadingCard = () => { + return ( +
+ +
+ ) +} + +/** + * 门店销售毛利分析 + * @returns + */ +export default function Index() { + + //订单报表列表 + const [costSalesData, setCostSalesData] = useState([]); + const [current, setCurrent] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + const [showLoading, setShowLoading] = useState(false); + const [timeRange, setTimeRange] = useState([ + moment(moment(new Date(Date.now() - 24 * 60 * 60 * 1000 * 7)).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), + ]); //日期选择器 + //门店 + const [storeIdArray, setStoreIdArray] = useState([]); + const [storeSelect, setStoreSelect] = useState([]); + + //页码变化 + const onPageChange = (current, pageSize) => { + setCurrent(current); + setPageSize(pageSize); + } + + //查询 + const onQueryReportSalescost = async () => { + const jsonData = { + "storeId": storeIdArray, + "begintime": timeRange[0], + "endtime": timeRange[1], + current, + pageSize + } + setShowLoading(true); + const response = await costSalesAPI.getReportOrgsalesmargin({}); + setShowLoading(false); + if (response.statusCode === 200) { + setCostSalesData(response.data.data); + } else { + message.error(response.errors || '获取销售成本失败'); + } + } + + /** + * 查询店铺列表 + */ + const onQueryStoreList = async () => { + setShowLoading(true); + const response = await costSalesAPI.gettree({}); + setShowLoading(false); + if (response.statusCode === 200) { + const storeList = []; + response.data.forEach(item => { + if (item.type === 2 || item.type === 3) { + storeList.push(item) + } + }) + setStoreSelect(storeList); + } else { + message.error('查询店铺列表失败'); + } + } + + useEffect(() => { + onQueryReportSalescost(); + onQueryStoreList(); + }, []); + + return ( + + {showLoading ? : null} + +
+
+ + { + let tempDate = [ + moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD 23:59:59')), + ] + setTimeRange(tempDate); + }} /> +
+
+ + +
+
+
+ +
+
+ +
+ + + ) +} diff --git a/src/pages/order/gross-profit-store-sales/index.less b/src/pages/order/gross-profit-store-sales/index.less new file mode 100644 index 0000000..c33fc6a --- /dev/null +++ b/src/pages/order/gross-profit-store-sales/index.less @@ -0,0 +1,36 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-page { + display: flex; + justify-content: flex-end; + align-items: center; + height: 50px; +} + +// 加载中 +.loading-card { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.5); +} \ No newline at end of file diff --git a/src/pages/order/gross-profit-store-sales/service.js b/src/pages/order/gross-profit-store-sales/service.js new file mode 100644 index 0000000..d25abba --- /dev/null +++ b/src/pages/order/gross-profit-store-sales/service.js @@ -0,0 +1,21 @@ +import { request } from 'umi'; + +export default { + getReportOrgsalesmargin(data) { + return request(`/kitchen/api/report/orgsalesmargin`, { + method: 'Post', + data: data, + }); + }, + + /** + * 查询门店列表 + */ + gettree(params) { + return request('​/kitchen/api​/sysOrg​/tree', { + data: { + ...params, + }, + }); + } +}; diff --git a/src/pages/order/order-market-report/index.jsx b/src/pages/order/order-market-report/index.jsx new file mode 100644 index 0000000..b9403b5 --- /dev/null +++ b/src/pages/order/order-market-report/index.jsx @@ -0,0 +1,591 @@ +import React, { useEffect, useState } from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { DownloadOutlined } from '@ant-design/icons'; +import { Button, Table, Card, DatePicker, message, Pagination, Spin, TreeSelect } from 'antd'; +import styles from './index.less'; +import moment from 'moment'; +import marketAPI from "./service"; +import ExportJsonExcel from "js-export-excel" + +const { TreeNode } = TreeSelect; +const { RangePicker } = DatePicker; +const columns = [ + { + title: '时间', + dataIndex: 'date', + key: 'date', + width: 170, + align: 'center', + fixed: 'left' + }, + { + title: '店铺', + dataIndex: 'shopName', + key: 'shopName', + width: 170, + align: 'center', + fixed: 'left', + filters: [ + { + text: '四川黑菠萝科技', + value: '四川黑菠萝科技', + }, + { + text: '四川白菠萝科技', + value: '四川白菠萝科技', + } + ], + onFilter: (value, record) => record.shopName.indexOf(value) === 0, + }, + { + title: '营收', + dataIndex: 'revenue', + key: 'revenue', + children: [ + { + title: '营业额', + dataIndex: 'turnover', + key: 'turnover', + children: [ + { + title: '流水', + dataIndex: 'revenueFlow', + key: 'revenueFlow', + width: 100, + align: 'center', + }, + { + title: '实收', + dataIndex: 'paidAmount', + key: 'paidAmount', + width: 100, + align: 'center', + }, + ] + }, + { + title: '优惠明细', + dataIndex: 'discountDetails', + key: 'discountDetails', + children: [ + { + title: '会员价', + dataIndex: 'discountMember', + key: 'discountMember', + width: 100, + align: 'center', + }, + { + title: '优惠券', + dataIndex: 'discountCoupon', + key: 'discountCoupon', + width: 100, + align: 'center', + }, + { + title: '活动', + dataIndex: 'discountActivity', + key: 'discountActivity', + width: 100, + align: 'center', + } + ] + }, + ] + }, + { + title: '分类营收', + dataIndex: 'classifiedRevenue', + key: 'classifiedRevenue', + children: [ + { + title: '外卖营业额', + dataIndex: 'takeOutTurnover', + key: 'takeOutTurnover', + children: [ + { + title: '外卖营收', + dataIndex: 'takeOutRevenue', + key: 'takeOutRevenue', + width: 100, + align: 'center', + }, + { + title: '美团外卖', + dataIndex: 'meituanTakeout', + key: 'meituanTakeout', + width: 100, + align: 'center', + }, + { + title: '饿了么外卖', + dataIndex: 'hungryTakeOut', + key: 'hungryTakeOut', + width: 100, + align: 'center', + }, + ] + }, + { + title: '食堂营收', + dataIndex: 'canteenRevenue', + key: 'canteenRevenue', + children: [ + { + title: '堂食流水', + dataIndex: 'freshWaterInTheHall', + key: 'freshWaterInTheHall', + width: 100, + align: 'center', + }, + { + title: '堂食实收', + dataIndex: 'paidInFood', + key: 'paidInFood', + width: 100, + align: 'center', + } + ] + }, + { + title: '第三方平台营收', + dataIndex: 'thirdPartyPlatformRevenue', + key: 'thirdPartyPlatformRevenue', + children: [ + { + title: '大众点评', + dataIndex: 'publicComments', + key: 'publicComments', + width: 100, + align: 'center', + }, + { + title: '口碑', + dataIndex: 'wordOfMouth', + key: 'wordOfMouth', + width: 100, + align: 'center', + }, + { + title: '抖音', + dataIndex: 'tiktok', + key: 'tiktok', + width: 100, + align: 'center', + } + ] + }, + ] + }, + { + title: '堂食单价', + dataIndex: 'unitPriceCanteenFood', + key: 'unitPriceCanteenFood', + children: [ + { + title: '客单价', + dataIndex: 'customerUnitPrice', + key: 'customerUnitPrice', + children: [ + { + title: '流水单价', + dataIndex: 'customerRevenueFlow', + key: 'customerRevenueFlow', + width: 100, + align: 'center', + }, + { + title: '实收单价', + dataIndex: 'customerPaidAmount', + key: 'customerPaidAmount', + width: 100, + align: 'center', + } + ] + }, + { + title: '单单价', + dataIndex: 'singleUnitPrice', + key: 'singleUnitPrice', + children: [ + { + title: '流水单价', + dataIndex: 'orderRevenueFlow', + key: 'orderRevenueFlow', + width: 100, + align: 'center', + }, + { + title: '实收单价', + dataIndex: 'orderPaidAmount', + key: 'orderPaidAmount', + width: 100, + align: 'center', + } + ] + }, + ] + }, + { + title: '交易笔数', + dataIndex: 'numberOfTransactions', + key: 'numberOfTransactions', + children: [ + { + title: '现金', + dataIndex: 'sourceCashCount', + key: 'sourceCashCount', + width: 100, + align: 'center', + }, + { + title: '微信支付', + dataIndex: 'sourceWeChatCount', + key: 'sourceWeChatCount', + width: 100, + align: 'center', + }, + { + title: '大众点评', + dataIndex: 'numPublicComments', + key: 'numPublicComments', + width: 100, + align: 'center', + }, + { + title: '口碑', + dataIndex: 'numWordOfMouth', + key: 'numWordOfMouth', + width: 100, + align: 'center', + }, + { + title: '抖音', + dataIndex: 'numTiktok', + key: 'numTiktok', + width: 100, + align: 'center', + }, + { + title: '美团外卖', + dataIndex: 'numMeituanTakeout', + key: 'numMeituanTakeout', + width: 100, + align: 'center', + }, + { + title: '饿了么外卖', + dataIndex: 'numHungryTakeOut', + key: 'numHungryTakeOut', + width: 100, + align: 'center', + }, + ] + }, + { + title: '收入构成', + dataIndex: 'revenueComposition', + key: 'revenueComposition', + children: [ + { + title: '收入来源', + dataIndex: 'sourceOfIncome', + key: 'sourceOfIncome', + children: [ + { + title: '会员', + dataIndex: 'memberIncomeMoney', + key: 'memberIncomeMoney', + width: 100, + align: 'center', + }, + { + title: '非会员', + dataIndex: 'nonMemberIncomeMoney', + key: 'nonMemberIncomeMoney', + width: 100, + align: 'center', + }, + { + title: '外卖', + dataIndex: 'incomeTakeOut', + key: 'incomeTakeOut', + width: 100, + align: 'center', + }, + { + title: '团购', + dataIndex: 'incomeGroupPurchase', + key: 'incomeGroupPurchase', + width: 100, + align: 'center', + }, + ] + }, + { + title: '收入结构', + dataIndex: 'revenueStructure', + key: 'revenueStructure', + children: [ + { + title: '微信支付', + dataIndex: 'sourceWeChatMoney', + key: 'sourceWeChatMoney', + width: 100, + align: 'center', + }, + { + title: '现金支付', + dataIndex: 'sourceCashMoney', + key: 'sourceCashMoney', + width: 100, + align: 'center', + }, + { + title: '大众点评', + dataIndex: 'incomePublicComments', + key: 'incomePublicComments', + width: 100, + align: 'center', + }, + { + title: '口碑', + dataIndex: 'incomeWordOfMouth', + key: 'incomeWordOfMouth', + width: 100, + align: 'center', + }, + { + title: '抖音', + dataIndex: 'incomeTiktok', + key: 'incomeTiktok', + width: 100, + align: 'center', + }, + { + title: '美团外卖', + dataIndex: 'incomeMeituan', + key: 'incomeMeituan', + width: 100, + align: 'center', + }, + { + title: '饿了么外卖', + dataIndex: 'incomeHungry', + key: 'incomeHungry', + width: 100, + align: 'center', + }, + ] + }, + ] + } +] + +const LoadingCard = () => { + return ( +
+ +
+ ) +} + +/** + * 营销报表 + * @returns + */ +export default function Index() { + + const [data, setData] = useState([]); + const [current, setCurrent] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + const [orgTree, setOrgTree] = useState([]); + const [showLoading, setShowLoading] = useState(false); + const [timeRange, setTimeRange] = useState([ + moment(moment(new Date(Date.now() - 24 * 60 * 60 * 1000 * 7)).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), + ]); //日期选择器 + const [currentOrg, setCurrentOrg] = useState(''); + + useEffect(() => { + queryMarketReport(); + }, [current, pageSize, timeRange]); + + useEffect(() => { + onGetOrgTree(); + }, []); + + //计算总计 + const calcTotal = () => { + const originData = JSON.parse(JSON.stringify(data)); + const totalData = {} + data.forEach(dataObj => { + Object.keys(dataObj).forEach(key => { + if (key === 'date') { + totalData.date = '合计'; + } else if (key == 'shopName') { + totalData.shopName = ''; + } else if (typeof dataObj[key] === 'number') { + if (totalData[key] && typeof totalData[key] === 'number') { + totalData[key] += dataObj[key]; + } else { + totalData[key] = 0; + totalData[key] += dataObj[key]; + } + } else { + totalData[key] = '暂无统计' + } + }); + }); + originData.push(totalData); + setData(originData); + } + + const queryMarketReport = async () => { + const jsonData = { + startTime: timeRange[0], + endTime: timeRange[1], + current: current, + pageSize: pageSize + } + currentOrg.key && (jsonData.shopId = currentOrg.key); + setShowLoading(true); + const response = await marketAPI.getMarketReportList(jsonData); + setShowLoading(false); + if (response.statusCode === 200) { + setData(response.data.data); + setTotal(response.data.total); + } else { + message.error(response.errors || '获取营销报表失败'); + } + } + + //页码变化 + const onPageChange = (current, pageSize) => { + setCurrent(current); + setPageSize(pageSize); + } + + //下载Excel + const onDownloadExcel = async () => { + const jsonData = { + startTime: timeRange[0], + endTime: timeRange[1], + } + currentOrg.key && (jsonData.shopId = currentOrg.key); + setShowLoading(true); + const response = await marketAPI.marketingReportExport(jsonData); + setShowLoading(false); + if (response.statusCode === 200) { + let option = {}; //option代表的就是excel文件 + const date = new Date(); + const excelName = "营销报表-" + date.toLocaleString().replaceAll('\/', '-'); + option.fileName = excelName; //excel文件名称 + const sheetHeader = []; + Object.keys(response.data[0]).forEach(item => { + sheetHeader.push(item); + }); + console.log('sheetHeader', sheetHeader); + option.datas = [ + { + sheetData: response.data, //excel文件中的数据源 + sheetName: excelName, //excel文件中sheet页名称 + sheetFilter: sheetHeader, //excel文件中需显示的列数据 + sheetHeader: ['ID', '时间', '店铺名称', '店铺ID', '营收流水', + '实际营收', '会员折扣', '优惠券折扣', '活动折扣','客单价-流水单价', '客单价-实收单价', + '单单价-总流水', '单单价-总实收', + '现金-交易笔数', '现金收入', '微信-交易笔数', '微信收入', '会员收入', '非会员收入' + ] //excel文件中每列的表头名称 + } + ] + let toExcel = new ExportJsonExcel(option); //生成excel文件 + toExcel.saveExcel(); + } else { + message.error(response.errors || '导出失败'); + } + } + + //获取组织树 + const onGetOrgTree = async () => { + setShowLoading(true); + const response = await marketAPI.getOrgTree(); + setShowLoading(false); + if (response.statusCode === 200) { + const originTree = response.data; + onSetOrgTreeStatus(originTree); + setOrgTree(originTree); + } else { + message.error(response.errors || '获取组织树出错'); + } + } + + //设置组织树不可选择状态 + const onSetOrgTreeStatus = (originTree) => { + originTree.forEach(treeItem => { + if (treeItem.children && treeItem.children.length > 0) { + onSetOrgTreeStatus(treeItem.children); + } else { + if (treeItem.type === 2 || treeItem.type === 3) { + treeItem.disabled = false; + } else { + treeItem.disabled = true; + } + } + }); + } + + return ( + + {showLoading ? : null} + +
+
+ { + let tempDate = [ + moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD 23:59:59')), + ] + setTimeRange(tempDate); + }} /> + { + if (node.type === 2 || node === 3) { + setCurrentOrg(node); + } else { + setCurrentOrg(""); + } + }} + placeholder="请选择组织架构" + treeDefaultExpandAll + /> +
+ +
+ + + +
+
+
+ +
+
+
+ +
+
+
+ ) +} diff --git a/src/pages/order/order-market-report/index.less b/src/pages/order/order-market-report/index.less new file mode 100644 index 0000000..ed50ea4 --- /dev/null +++ b/src/pages/order/order-market-report/index.less @@ -0,0 +1,41 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-page { + display: flex; + justify-content: flex-end; + align-items: center; + height: 50px; +} + +.data-search-left { + display: flex; + align-items: center; +} + +// 加载中 +.loading-card { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.5); +} \ No newline at end of file diff --git a/src/pages/order/order-market-report/service.js b/src/pages/order/order-market-report/service.js new file mode 100644 index 0000000..7820383 --- /dev/null +++ b/src/pages/order/order-market-report/service.js @@ -0,0 +1,26 @@ +import { request } from 'umi'; + +export default { + //获取分页数据 + getMarketReportList(data) { + return request(`/kitchen/api/report-statistics/marketing-report`, { + method: 'Post', + data: data, + }); + }, + + //获取组织架构 + getOrgTree() { + return request(`/kitchen/api/report-statistics/org-tree`, { + method: 'GET', + }); + }, + + //下载报表 + marketingReportExport(data) { + return request(`/kitchen/api/report-statistics/marketing-report-export`, { + method: 'Post', + data: data, + }); + } +}; diff --git a/src/pages/order/order-member-statement/index.jsx b/src/pages/order/order-member-statement/index.jsx new file mode 100644 index 0000000..8c62138 --- /dev/null +++ b/src/pages/order/order-member-statement/index.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +/** + * 会员报表 + * @returns + */ +export default function Index() { + + return ( + + +
+ +
+ + +
+
+
+ + 会员报表 + +
+ ) +} diff --git a/src/pages/order/order-member-statement/index.less b/src/pages/order/order-member-statement/index.less new file mode 100644 index 0000000..74d0c92 --- /dev/null +++ b/src/pages/order/order-member-statement/index.less @@ -0,0 +1,16 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-card { +} \ No newline at end of file diff --git a/src/pages/order/order-product-report/index.jsx b/src/pages/order/order-product-report/index.jsx new file mode 100644 index 0000000..253aa3b --- /dev/null +++ b/src/pages/order/order-product-report/index.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +/** + * 产品报表 + * @returns + */ +export default function Index() { + + return ( + + +
+ +
+ + +
+
+
+ + 产品报表 + +
+ ) +} diff --git a/src/pages/order/order-product-report/index.less b/src/pages/order/order-product-report/index.less new file mode 100644 index 0000000..74d0c92 --- /dev/null +++ b/src/pages/order/order-product-report/index.less @@ -0,0 +1,16 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-card { +} \ No newline at end of file diff --git a/src/pages/order/order-report-detail/index.jsx b/src/pages/order/order-report-detail/index.jsx new file mode 100644 index 0000000..e3df461 --- /dev/null +++ b/src/pages/order/order-report-detail/index.jsx @@ -0,0 +1,245 @@ +import React, { useState, useEffect } from 'react'; +import { Button, Card, Image, Timeline, message, Tag } from 'antd'; +import styles from './index.less'; +import { ExclamationCircleOutlined, UserOutlined, RedEnvelopeOutlined, WhatsAppOutlined } from '@ant-design/icons'; +import { history } from 'umi'; +import orderReportAPI from "./service"; +import { PageContainer } from '@ant-design/pro-layout'; + +const orderNumber = history.location.query.orderNumber; + +/** + * 订单详情 + * @returns + */ +export default function Index() { + + const [orderInfo, setOrderInfo] = useState({ + memberInfo: {}, //用户信息 + goodsInfo: [], //商品信息 + informationRefundInfo: [], //售后信息 + discountInfo: [] //优惠信息 + }); + + const [orderStatus, setOrderStatus] = useState({ + isTrue: true + }); + + const onQueryOrderDetail = async () => { + if (orderNumber) { + const response = await orderReportAPI.getOrderReporByNumber(orderNumber); + if (response.statusCode === 200) { + setOrderInfo(response.data); + orderIsNormal(response.data); + } else { + message.error(response.errors || '订单详情获取失败'); + } + } + } + + const orderIsNormal = (order) => { + let isNormal = { + isTrue: true, + msg: '正常订单' + }; + if (!(order.payMoneyEx === '正常')) { + isNormal.isTrue = false; + isNormal.msg = '订单支付金额异常'; + } + else if (!(order.payOrderTimeEx === '正常')) { + isNormal.isTrue = false; + isNormal.msg = '订单支付时间异常'; + } + else if (!(order.payOrderEx === '正常')) { + isNormal.isTrue = false; + isNormal.msg = '订单支付异常'; + } + else if (!(order.refundMoneyEx === '正常' || order.refundMoneyEx === '' || order.refundMoneyEx === null)) { + isNormal.isTrue = false; + isNormal.msg = '订单退款金额异常'; + } + else if (!(order.refundOrderTimeEx === '正常' || order.refundOrderTimeEx === '' || order.refundOrderTimeEx === null)) { + isNormal.isTrue = false; + isNormal.msg = '订单退款时间异常'; + } + else if (!(order.refundOrderEx === '正常' || order.refundOrderEx === '' || order.refundOrderEx === null)) { + isNormal.isTrue = false; + isNormal.msg = '订单退款异常'; + } + console.log('isNormal', isNormal); + setOrderStatus(isNormal); + } + + useEffect(() => { + onQueryOrderDetail(); + }, []); + + return ( + +
+ {/* 用户基本信息 */} +
+
+
+ #{orderInfo.sortId} +
+
+ { + orderStatus.isTrue ?
正常订单
:
{orderStatus.msg}
+ } +
+
+ {orderInfo.createdAt} +
+
+
+
+ +
+
+
+ {orderInfo.memberInfo.memberName || '系统用户'} +
+
+ #门店新客 + #门店会员 +
+
+
+
+ + 为保证服务体验,您在拨打或接听隐私号电话时,可能被录音 +
+
+ + 顾客电话 + + + {orderInfo.memberInfo.phone || '暂无电话'} + +
+
+
+ 优惠信息 +
+
+ { + orderInfo.discountInfo?.map(discountItem => { + return ( +
+ {discountItem.type === 1 ? } color="#f50">{discountItem.name}:{discountItem.value} : null} + {discountItem.type === 2 ? } color="#87d068">{discountItem.name}:{discountItem.value} : null} + {discountItem.type === 3 ? } color="#108ee9">{discountItem.name}:{discountItem.value} : null} +
+ ) + }) + } + +
+
+
+ {/* 订单数据 */} +
+
+ 订单信息 +
+
+
订单编号
+
{orderInfo.orderNumber}
+
+
+
支付方式
+
微信支付
+
+
+
下单时间
+
{orderInfo.createdAt}
+
+
+
就餐人数
+
商家按餐量提供
+
+
+
桌台号码
+
0
+
+
+ {/* 商品信息 */} +
+
+ 商品信息 +
+
+ { + orderInfo.goodsInfo.map(item => { + return ( +
+
+ +
+
+ {item.goodsName || '暂无名称'} +
+
+ ¥{item.memberPrice} +
+
+ x{item.count}份 +
+
+ ) + }) + } +
+ {/* 小计 */} +
+
小计
+
+
优惠金额
+
¥{orderInfo.discountMoney}
+
+
+
支付金额
+
¥{orderInfo.orderRealMoney}
+
+
+
+ {/* 售后信息 */} +
+
+ 售后信息 +
+ + { + orderInfo.informationRefundInfo.length > 0 ? + orderInfo.informationRefundInfo.map(item => { + return ( + +
+ {item.createdAt} {item.refundDesc} +
+
+ ) + }) + : + + 暂无售后信息 + + } +
+
+
+
+ + ) +} diff --git a/src/pages/order/order-report-detail/index.less b/src/pages/order/order-report-detail/index.less new file mode 100644 index 0000000..6768071 --- /dev/null +++ b/src/pages/order/order-report-detail/index.less @@ -0,0 +1,201 @@ +.order-detail-container { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.order-head { + display: flex; + align-items: center; + position: relative; + height: 50px; + margin-bottom: 10px; +} + +.order-head::before { + position: absolute; + content: ''; + width: 0; + height: 0; + top: 50%; + transform: translateY(-50%); + left: 50px; + border-top: 20px solid transparent; + border-bottom: 20px solid transparent; + border-left: 20px solid rgb(88, 91, 110); +} + +.order-number { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + width: 70px; + height: 40px; + left: -20px; + top: 50%; + transform: translateY(-50%); + background-color: rgb(88, 91, 110); + color: #FFF; + font-size: 26px; +} + +.order-status-true { + font-size: 14px; + padding: 5px 20px; + background-color: #2db7f5; + color: #FFF; +} + +.order-status-false { + font-size: 14px; + padding: 5px 20px; + background-color: #F84352; + color: #FFF; +} + +.order-cook-state { + font-size: 22px; + margin-left: 100px; + margin-right: 20px; +} + +.order-cook-date { + font-size: 16px; + color: rgb(246, 152, 38); +} + +// 用户信息 +.member-info { + display: flex; +} + +.member-info-img { + margin-right: 20px; +} + +.member-info-row { + display: flex; + flex-direction: column; + justify-content: center; +} + +.member-info-head { + font-size: 22px; + margin-right: 10px; +} + +.member-info-label { + font-size: 16px; + color: #999; +} + +.member-info-label span { + margin-right: 10px; +} + +.member-info-privacy { + margin: 10px 0; + font-size: 16px; + color: rgb(88, 91, 110); +} + +.member-info-privacy span { + margin-left: 10px; +} + +.member-info-prefix { + font-size: 16px; + color: rgb(88, 91, 110); + margin-right: 10px; +} + +.member-info-suffix { + font-size: 16px; + color: #222; +} + +// 备餐状态 +.prepare-meals { + margin-top: 20px; + font-size: 16px; + color: #222; +} + +.prepare-meals-title { + font-weight: 700; +} + + + +// 商品信息 +.goods-card { + // margin-top: 20px; +} + +.goods-title { + font-size: 22px; + font-weight: 700; + margin-bottom: 10px; +} + +.goods-item { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; + font-size: 16px; + color: #222; +} + +// 小计 +.goods-calc { + padding-top: 10px; + border-top: 1px dashed #dedede; + font-size: 16px; +} + +.goods-calc-title { + font-size: 16px; + font-weight: 700; +} + +.goods-calc-item { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 16px; +} + +.goods-calc-pay .goods-calc-sufix { + color: #F84352; +} + +// 订单信息 +.sale-after-line { + font-size: 16px; +} + +@media screen and (min-width: 1200px) { + .order-head-card, + .goods-card, + .order-base-card, + .sale-after-card { + padding: 20px; + background-color: #FFF; + width: 49.5%; + box-sizing: border-box; + } +} + +@media screen and (max-width: 1200px) { + .order-head-card, + .goods-card, + .order-base-card, + .sale-after-card { + padding: 20px; + background-color: #FFF; + width: 100%; + box-sizing: border-box; + } +} \ No newline at end of file diff --git a/src/pages/order/order-report-detail/service.js b/src/pages/order/order-report-detail/service.js new file mode 100644 index 0000000..bc9b448 --- /dev/null +++ b/src/pages/order/order-report-detail/service.js @@ -0,0 +1,9 @@ +import { request } from 'umi'; + +export default { + getOrderReporByNumber(orderNumber) { + return request(`/kitchen/api/report-statistics/order-info-report/${orderNumber}`, { + method: 'GET', + }); + } +}; diff --git a/src/pages/order/order-report/index.jsx b/src/pages/order/order-report/index.jsx new file mode 100644 index 0000000..d58951b --- /dev/null +++ b/src/pages/order/order-report/index.jsx @@ -0,0 +1,299 @@ +import React, { useState, useEffect } from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker, Table, message, Pagination, Space, Tag, Spin, TreeSelect } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +import orderReportAPI from "./service"; +import moment from 'moment'; +import { history } from "umi"; +import { CheckCircleOutlined, CloseCircleOutlined, DownloadOutlined } from '@ant-design/icons'; +import ExportJsonExcel from "js-export-excel" + +const columns = [ + { + title: '交易单号', + dataIndex: 'transactionId', + key: 'transactionId', + }, + { + title: '店铺名称', + dataIndex: 'shopName', + key: 'shopName', + }, + { + title: '原价(¥)', + dataIndex: 'orderOriginalMoney', + key: 'orderOriginalMoney', + }, + { + title: '优惠(¥)', + dataIndex: 'discountMoney', + key: 'discountMoney', + }, + { + title: '实际支付(¥)', + dataIndex: 'orderRealMoney', + key: 'orderRealMoney', + }, + { + title: '创建时间', + dataIndex: 'createdAt', + key: 'createdAt', + }, + { + title: '订单状态', + key: 'orderStatus', + render: (record) => { + let isNormal = true; + if (!(record.payMoneyEx === '正常' && + record.payOrderTimeEx === '正常' && + record.payOrderEx === '正常') + ) { + isNormal = false; + } + if (!(record.refundMoneyEx === '正常' || record.refundMoneyEx === '' || record.refundMoneyEx === null)) { + isNormal = false; + } + if (!(record.refundOrderTimeEx === '正常' || record.refundOrderTimeEx === '' || record.refundOrderTimeEx === null)) { + isNormal = false; + } + if (!(record.refundOrderEx === '正常' || record.refundOrderEx === '' || record.refundOrderEx === null)) { + isNormal = false; + } + return ( + <> + { + isNormal ? } color="success"> + 正常 + + : + } color="error"> + 异常 + + } + + ) + }, + }, + { + title: '售后信息', + key: 'orderStatus', + render: (record) => { + return ( + <> + { + record.isRefund ? + 有 + + : + + 无 + + } + + ) + }, + }, + { + title: '操作', + key: 'action', + render: (_, record) => ( + + { + history.push({ + pathname: '/order/order-report/order-report-detail', + query: { + orderNumber: record.orderNumber + } + }); + }}>详情 + + ), + }, +]; + +const LoadingCard = () => { + return ( +
+ +
+ ) +} + +/** + * 订单报表 + * @returns + */ +export default function Index() { + + //订单报表列表 + const [orderReportList, setOrderReportList] = useState([]); + const [current, setCurrent] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + const [showLoading, setShowLoading] = useState(false); + const [currentOrg, setCurrentOrg] = useState(''); + const [orgTree, setOrgTree] = useState([]); + + + const [timeRange, setTimeRange] = useState([ + moment(moment(new Date(Date.now() - 24 * 60 * 60 * 1000 * 7)).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), + ]); //日期选择器 + + useEffect(() => { + onQueryOrderReportList(); + }, [current, pageSize]); + + + useEffect(() => { + onGetOrgTree(); + }, []); + + + //获取订单列表 + const onQueryOrderReportList = async () => { + const jsonData = { + startTime: timeRange[0], + endTime: timeRange[1], + current, + pageSize + } + currentOrg.key && (jsonData.shopId = currentOrg.key); + setShowLoading(true); + const response = await orderReportAPI.getOrderReportList(jsonData); + setShowLoading(false); + if (response.statusCode === 200) { + setOrderReportList(response.data.data); + setTotal(response.data.total) + } else { + message.error(response.errors || '获取订单报表列表失败'); + } + } + + //页码变化 + const onPageChange = (current, pageSize) => { + setCurrent(current); + setPageSize(pageSize); + } + + //获取组织树 + const onGetOrgTree = async () => { + setShowLoading(true); + const response = await orderReportAPI.getOrgTree(); + setShowLoading(false); + if (response.statusCode === 200) { + const originTree = response.data; + onSetOrgTreeStatus(originTree); + setOrgTree(originTree); + } else { + message.error(response.errors || '获取组织树出错'); + } + } + + //设置组织树不可选择状态 + const onSetOrgTreeStatus = (originTree) => { + originTree.forEach(treeItem => { + if (treeItem.children && treeItem.children.length > 0) { + onSetOrgTreeStatus(treeItem.children); + } else { + if (treeItem.type === 2 || treeItem.type === 3) { + treeItem.disabled = false; + } else { + treeItem.disabled = true; + } + } + }); + } + + //下载Excel + const onDownloadExcel = async () => { + const jsonData = { + startTime: timeRange[0], + endTime: timeRange[1], + } + currentOrg.key && (jsonData.shopId = currentOrg.key); + setShowLoading(true); + const response = await orderReportAPI.orderReportExport(jsonData); + setShowLoading(false); + if (response.statusCode === 200) { + let option = {}; //option代表的就是excel文件 + const date = new Date(); + const excelName = "订单报表-" + date.toLocaleString().replaceAll('\/', '-'); + option.fileName = excelName; //excel文件名称 + const sheetHeader = []; + Object.keys(response.data[0]).forEach(item => { + sheetHeader.push(item); + }); + option.datas = [ + { + sheetData: response.data, //excel文件中的数据源 + sheetName: excelName, //excel文件中sheet页名称 + sheetFilter: sheetHeader, //excel文件中需显示的列数据 + sheetHeader: ['ID', '取餐号', '用户Id', '优惠合集', '订单号(本系统)', + '交易号', '店铺ID', '店铺名字', '商品总价', '优惠金额', '实付金额', + '创建时间', '支付金额异常', + '订单支付时间异常', '订单异常', '售后金额异常', '售后时间异常', '售后订单异常' + ] //excel文件中每列的表头名称 + } + ] + let toExcel = new ExportJsonExcel(option); //生成excel文件 + toExcel.saveExcel(); + } else { + message.error(response.errors || '导出失败'); + } + } + + return ( + + {showLoading ? : null} + +
+
+ { + let tempDate = [ + moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD 23:59:59')), + ] + setTimeRange(tempDate); + }} /> + { + console.log('node>>>', node); + if (node.type === 2 || node === 3) { + setCurrentOrg(node); + } else { + setCurrentOrg(""); + } + }} + placeholder="请选择组织架构" + treeDefaultExpandAll + /> +
+
+ + + +
+
+
+ + +
+ +
+ + + ) +} diff --git a/src/pages/order/order-report/index.less b/src/pages/order/order-report/index.less new file mode 100644 index 0000000..c33fc6a --- /dev/null +++ b/src/pages/order/order-report/index.less @@ -0,0 +1,36 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-page { + display: flex; + justify-content: flex-end; + align-items: center; + height: 50px; +} + +// 加载中 +.loading-card { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.5); +} \ No newline at end of file diff --git a/src/pages/order/order-report/service.js b/src/pages/order/order-report/service.js new file mode 100644 index 0000000..777cde2 --- /dev/null +++ b/src/pages/order/order-report/service.js @@ -0,0 +1,25 @@ +import { request } from 'umi'; + +export default { + getOrderReportList(data) { + return request(`/kitchen/api/report-statistics/order-report`, { + method: 'Post', + data: data, + }); + }, + + //获取组织架构 + getOrgTree() { + return request(`/kitchen/api/report-statistics/org-tree`, { + method: 'GET', + }); + }, + + //下载报表 + orderReportExport(data) { + return request(`/kitchen/api/report-statistics/order-report-export`, { + method: 'Post', + data: data, + }); + } +}; diff --git a/src/pages/order/order-revenue-statement/index.jsx b/src/pages/order/order-revenue-statement/index.jsx new file mode 100644 index 0000000..c2e0ebd --- /dev/null +++ b/src/pages/order/order-revenue-statement/index.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +/** + * 营收报表 + * @returns + */ +export default function Index() { + + return ( + + +
+ +
+ + +
+
+
+ + 营收报表 + +
+ ) +} diff --git a/src/pages/order/order-revenue-statement/index.less b/src/pages/order/order-revenue-statement/index.less new file mode 100644 index 0000000..74d0c92 --- /dev/null +++ b/src/pages/order/order-revenue-statement/index.less @@ -0,0 +1,16 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-card { +} \ No newline at end of file diff --git a/src/pages/order/sales-gross-profit/index.jsx b/src/pages/order/sales-gross-profit/index.jsx new file mode 100644 index 0000000..6ef8a2a --- /dev/null +++ b/src/pages/order/sales-gross-profit/index.jsx @@ -0,0 +1,229 @@ +import React, { useState, useEffect } from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, DatePicker, Table, Pagination, Spin, Select, message } from 'antd'; +import styles from './index.less'; +const { RangePicker } = DatePicker; +import costSalesAPI from "./service"; +import moment from 'moment'; + +const columns = [ + { + title: '门店名称', + dataIndex: 'storeId', + key: 'storeId', + }, + { + title: '商品名称', + dataIndex: 'goodsId', + key: 'goodsId', + }, + { + title: '毛利率', + dataIndex: 'marginRatio', + key: 'marginRatio', + } +]; + +const LoadingCard = () => { + return ( +
+ +
+ ) +} + +/** + * 销售毛利分析 + * @returns + */ +export default function Index() { + + //订单报表列表 + const [costSalesData, setCostSalesData] = useState([]); + const [current, setCurrent] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + const [showLoading, setShowLoading] = useState(false); + const [timeRange, setTimeRange] = useState([ + moment(moment(new Date(Date.now() - 24 * 60 * 60 * 1000 * 7)).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), + ]); //日期选择器 + //门店 + const [storeIdArray, setStoreIdArray] = useState([]); + const [storeSelect, setStoreSelect] = useState([]); + //商品 + const [goodsIdArray, setGoodsIdArray] = useState([]); + const [goodsIdSelect, setGoodsIdSelect] = useState([]); + //商品类型 + const [goodsTypeArray, setGoodsTypeArray] = useState([]); + const [goodsTypeSelect, setGoodsTypeSelect] = useState([]); + + //页码变化 + const onPageChange = (current, pageSize) => { + setCurrent(current); + setPageSize(pageSize); + } + + //查询 + const onQueryReportSalescost = async () => { + const jsonData = { + "storeId": storeIdArray, + "goodsId": goodsIdArray, + "goodsTypeId": goodsTypeArray, + "begintime": timeRange[0], + "endtime": timeRange[1], + current, + pageSize + } + setShowLoading(true); + const response = await costSalesAPI.getReportSalesmargin({}); + setShowLoading(false); + if (response.statusCode === 200) { + setCostSalesData(response.data.data); + } else { + message.error(response.errors || '获取销售成本失败'); + } + } + + /** + * 查询店铺列表 + */ + const onQueryStoreList = async () => { + setShowLoading(true); + const response = await costSalesAPI.gettree({}); + setShowLoading(false); + if (response.statusCode === 200) { + const storeList = []; + response.data.forEach(item => { + if (item.type === 2 || item.type === 3) { + storeList.push(item) + } + }) + setStoreSelect(storeList); + } else { + message.error('查询店铺列表失败'); + } + } + + //查询商品列表 + const onQueryGoodsList = async () => { + setShowLoading(true); + const response = await costSalesAPI.goodsList({}); + setShowLoading(false); + if (response.statusCode === 200) { + setGoodsIdSelect(response.data); + } else { + message.error('查询商品列表失败'); + } + } + + //查询商品分类类型列表 + const onQueryGoodsType = async () => { + setShowLoading(true); + const response = await costSalesAPI.goodsTypeList({}); + setShowLoading(false); + if (response.statusCode === 200) { + setGoodsTypeSelect(response.data); + } else { + message.error('查询商品分类列表失败'); + } + } + + useEffect(() => { + onQueryReportSalescost(); + onQueryStoreList(); + onQueryGoodsList(); + onQueryGoodsType(); + }, []); + return ( + + {showLoading ? : null} + +
+
+ + + + { + let tempDate = [ + moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD 00:00:00')), + moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD 23:59:59')), + ] + setTimeRange(tempDate); + }} /> +
+
+ + +
+
+
+ +
+
+ +
+ + + ) +} diff --git a/src/pages/order/sales-gross-profit/index.less b/src/pages/order/sales-gross-profit/index.less new file mode 100644 index 0000000..c33fc6a --- /dev/null +++ b/src/pages/order/sales-gross-profit/index.less @@ -0,0 +1,36 @@ +.data-search-card { + margin-bottom: 20px; +} + +.data-search-box { + display: flex; + align-items: center; + justify-content: space-between; +} + +.search-btn-item { + margin-left: 20px; +} + +.table-page { + display: flex; + justify-content: flex-end; + align-items: center; + height: 50px; +} + +// 加载中 +.loading-card { + position: fixed; + display: flex; + align-items: center; + justify-content: center; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999; + background-color: rgba(0, 0, 0, 0.5); +} \ No newline at end of file diff --git a/src/pages/order/sales-gross-profit/service.js b/src/pages/order/sales-gross-profit/service.js new file mode 100644 index 0000000..7537b2e --- /dev/null +++ b/src/pages/order/sales-gross-profit/service.js @@ -0,0 +1,39 @@ +import { request } from 'umi'; + +export default { + getReportSalesmargin(data) { + return request(`/kitchen/api/report/salesmargin`, { + method: 'Post', + data: data, + }); + }, + /** + * 查询商品信息 + */ + goodsList(data) { + return request(`/kitchen/api/goodes/list`, { + method: 'Post', + data: data, + }); + }, + /** + * 查询商品类型 + */ + goodsTypeList(data) { + return request(`/kitchen/api/goodstype/list`, { + method: 'Post', + data: data, + }); + }, + + /** + * 查询门店列表 + */ + gettree(params) { + return request('​/kitchen/api​/sysOrg​/tree', { + data: { + ...params, + }, + }); + } +};