feature[litemall-admin, litemall-admin-api]:实现几个统计页面和效果。
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package org.linlinjava.litemall.admin.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StatVo {
|
||||
private String[] columns = new String[0];
|
||||
private List<Map> rows = new ArrayList<>();
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(String[] columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public List<Map> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setRows(List<Map> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
public void add(Map ... r) {
|
||||
rows.addAll(Arrays.asList(r));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.admin.util.StatVo;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.linlinjava.litemall.db.dao.StatMapper;
|
||||
import org.linlinjava.litemall.db.service.LitemallOrderService;
|
||||
import org.linlinjava.litemall.db.service.StatService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/stat")
|
||||
public class AdminStatController {
|
||||
private final Log logger = LogFactory.getLog(AdminStatController.class);
|
||||
|
||||
@Autowired
|
||||
private StatService statService;
|
||||
|
||||
@GetMapping("/user")
|
||||
public Object statUser(@LoginAdmin Integer adminId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<Map> rows = statService.statUser();
|
||||
String[] columns = new String[]{"day", "users"};
|
||||
StatVo statVo = new StatVo();
|
||||
statVo.setColumns(columns);
|
||||
statVo.setRows(rows);
|
||||
|
||||
return ResponseUtil.ok(statVo);
|
||||
}
|
||||
|
||||
@GetMapping("/order")
|
||||
public Object statOrder(@LoginAdmin Integer adminId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<Map> rows = statService.statOrder();
|
||||
String[] columns = new String[]{"day", "orders", "customers", "amount", "pcr"};
|
||||
StatVo statVo = new StatVo();
|
||||
statVo.setColumns(columns);
|
||||
statVo.setRows(rows);
|
||||
|
||||
return ResponseUtil.ok(statVo);
|
||||
}
|
||||
|
||||
@GetMapping("/goods")
|
||||
public Object statGoods(@LoginAdmin Integer adminId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<Map> rows = statService.statGoods();
|
||||
String[] columns = new String[]{"day", "orders", "products", "amount"};
|
||||
StatVo statVo = new StatVo();
|
||||
statVo.setColumns(columns);
|
||||
statVo.setRows(rows);
|
||||
|
||||
|
||||
return ResponseUtil.ok(statVo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,9 +13,10 @@
|
||||
"test": "npm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tinymce/tinymce-vue": "^1.0.8",
|
||||
"axios": "0.17.1",
|
||||
"clipboard": "1.7.1",
|
||||
"echarts": "3.8.5",
|
||||
"echarts": "^4.1.0",
|
||||
"element-ui": "2.0.8",
|
||||
"file-saver": "1.3.3",
|
||||
"font-awesome": "4.7.0",
|
||||
@@ -24,13 +25,13 @@
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"screenfull": "3.3.2",
|
||||
"v-charts": "^1.16.19",
|
||||
"vue": "2.5.10",
|
||||
"vue-count-to": "1.0.13",
|
||||
"vue-router": "3.0.1",
|
||||
"vue-splitpane": "1.0.2",
|
||||
"vuex": "3.0.1",
|
||||
"xlsx": "^0.11.16",
|
||||
"@tinymce/tinymce-vue": "1.0.8"
|
||||
"xlsx": "^0.11.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "7.2.3",
|
||||
|
||||
25
litemall-admin/src/api/stat.js
Normal file
25
litemall-admin/src/api/stat.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function statUser(query) {
|
||||
return request({
|
||||
url: '/stat/user',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function statOrder(query) {
|
||||
return request({
|
||||
url: '/stat/order',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function statGoods(query) {
|
||||
return request({
|
||||
url: '/stat/goods',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -106,6 +106,7 @@ export const asyncRouterMap = [
|
||||
{ path: 'comment', component: _import('goods/comment'), name: 'comment', meta: { title: '用户评论', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/promotion',
|
||||
component: Layout,
|
||||
@@ -120,6 +121,7 @@ export const asyncRouterMap = [
|
||||
{ path: 'topic', component: _import('promotion/topic'), name: 'topic', meta: { title: '专题管理', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/sys',
|
||||
component: Layout,
|
||||
@@ -135,5 +137,21 @@ export const asyncRouterMap = [
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/stat',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'statManage',
|
||||
meta: {
|
||||
title: '统计',
|
||||
icon: 'chart'
|
||||
},
|
||||
children: [
|
||||
{ path: 'user', component: _import('stat/user'), name: 'statUser', meta: { title: '用户统计', noCache: true }},
|
||||
{ path: 'order', component: _import('stat/order'), name: 'statOrder', meta: { title: '订单统计', noCache: true }},
|
||||
{ path: 'goods', component: _import('stat/goods'), name: 'statGoods', meta: { title: '商品统计', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
|
||||
37
litemall-admin/src/views/stat/goods.vue
Normal file
37
litemall-admin/src/views/stat/goods.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<ve-line :extend="chartExtend" :data="chartData" :settings="chartSettings"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { statGoods } from '@/api/stat'
|
||||
import VeLine from 'v-charts/lib/line'
|
||||
|
||||
export default {
|
||||
components: { VeLine },
|
||||
data() {
|
||||
return {
|
||||
chartData: {},
|
||||
chartSettings: {},
|
||||
chartExtend: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
statGoods().then(response => {
|
||||
this.chartData = response.data.data
|
||||
this.chartSettings = {
|
||||
labelMap: {
|
||||
'orders': '订单量',
|
||||
'products': '下单货品数量',
|
||||
'amount': '下单货品总额'
|
||||
}
|
||||
}
|
||||
this.chartExtend = {
|
||||
xAxis: { boundaryGap: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
37
litemall-admin/src/views/stat/order.vue
Normal file
37
litemall-admin/src/views/stat/order.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<ve-line :extend="chartExtend" :data="chartData" :settings="chartSettings"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { statOrder } from '@/api/stat'
|
||||
import VeLine from 'v-charts/lib/line'
|
||||
export default {
|
||||
components: { VeLine },
|
||||
data() {
|
||||
return {
|
||||
chartData: {},
|
||||
chartSettings: {},
|
||||
chartExtend: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
statOrder().then(response => {
|
||||
this.chartData = response.data.data
|
||||
this.chartSettings = {
|
||||
labelMap: {
|
||||
'orders': '订单量',
|
||||
'customers': '下单用户',
|
||||
'amount': '订单总额',
|
||||
'pcr': '客单价'
|
||||
}
|
||||
}
|
||||
this.chartExtend = {
|
||||
xAxis: { boundaryGap: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
38
litemall-admin/src/views/stat/user.vue
Normal file
38
litemall-admin/src/views/stat/user.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<ve-histogram :extend="chartExtend" :data="chartData" :settings="chartSettings"></ve-histogram>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { statUser } from '@/api/stat'
|
||||
import VeHistogram from 'v-charts/lib/histogram'
|
||||
|
||||
export default {
|
||||
components: { VeHistogram },
|
||||
data() {
|
||||
return {
|
||||
chartData: {},
|
||||
chartSettings: {},
|
||||
chartExtend: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
statUser().then(response => {
|
||||
this.chartData = response.data.data
|
||||
this.chartSettings = {
|
||||
labelMap: {
|
||||
'users': '用户增长数'
|
||||
}
|
||||
}
|
||||
this.chartExtend = {
|
||||
xAxis: { boundaryGap: true },
|
||||
series: {
|
||||
label: { show: true, position: 'top' }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.linlinjava.litemall.db.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface StatMapper {
|
||||
List<Map> statUser();
|
||||
List<Map> statOrder();
|
||||
List<Map> statGoods();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.linlinjava.litemall.db.service;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import org.linlinjava.litemall.db.dao.LitemallUserMapper;
|
||||
import org.linlinjava.litemall.db.dao.StatMapper;
|
||||
import org.linlinjava.litemall.db.domain.LitemallUser;
|
||||
import org.linlinjava.litemall.db.domain.LitemallUserExample;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class StatService {
|
||||
@Resource
|
||||
private StatMapper statMapper;
|
||||
|
||||
|
||||
public List<Map> statUser() {
|
||||
return statMapper.statUser();
|
||||
}
|
||||
|
||||
public List<Map> statOrder(){
|
||||
return statMapper.statOrder();
|
||||
}
|
||||
|
||||
public List<Map> statGoods(){
|
||||
return statMapper.statGoods();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.linlinjava.litemall.db.dao.StatMapper">
|
||||
<select id="statUser" resultType="map">
|
||||
select
|
||||
substr(add_time,1,10) as day,
|
||||
count(distinct id) as users
|
||||
from litemall_user
|
||||
group by substr(add_time,1,10)
|
||||
</select>
|
||||
<select id="statOrder" resultType="map">
|
||||
select
|
||||
substr(add_time,1,10) as day,
|
||||
count(id) as orders,
|
||||
count(distinct user_id) as customers,
|
||||
sum(actual_price) as amount,
|
||||
round(sum(actual_price)/count(distinct user_id),2) as pcr
|
||||
from litemall_order
|
||||
where order_status in(103)
|
||||
group by substr(add_time,1,10)
|
||||
</select>
|
||||
<select id="statGoods" resultType="map">
|
||||
select
|
||||
substr(add_time,1, 10) as day,
|
||||
count(distinct order_id) as orders,
|
||||
sum(number) as products,
|
||||
sum(number*retail_price) as amount
|
||||
from litemall_order_goods
|
||||
group by substr(add_time,1, 10)
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.linlinjava.litemall.db;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.linlinjava.litemall.db.dao.StatMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@WebAppConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest
|
||||
public class StatMapperTest {
|
||||
|
||||
@Autowired
|
||||
private StatMapper statMapper;
|
||||
|
||||
@Test
|
||||
public void testUser() {
|
||||
List<Map> result = statMapper.statUser();
|
||||
for(Map m : result) {
|
||||
m.forEach((k, v) -> System.out.println("key:value = " + k + ":" + v));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrder() {
|
||||
List<Map> result = statMapper.statOrder();
|
||||
for(Map m : result) {
|
||||
m.forEach((k, v) -> System.out.println("key:value = " + k + ":" + v));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoods() {
|
||||
List<Map> result = statMapper.statGoods();
|
||||
for(Map m : result) {
|
||||
m.forEach((k, v) -> System.out.println("key:value = " + k + ":" + v));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user