Browse Source

feature[litemall-admin, litemall-admin-api]:实现几个统计页面和效果。

Junling Bu 7 years ago
parent
commit
098fefc9f6

+ 31 - 0
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/StatVo.java

@@ -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));
+    }
+}

+ 72 - 0
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStatController.java

@@ -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);
+    }
+
+}

+ 4 - 3
litemall-admin/package.json

@@ -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 - 0
litemall-admin/src/api/stat.js

@@ -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
+  })
+}

+ 18 - 0
litemall-admin/src/router/index.js

@@ -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 - 0
litemall-admin/src/views/stat/goods.vue

@@ -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 - 0
litemall-admin/src/views/stat/order.vue

@@ -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 - 0
litemall-admin/src/views/stat/user.vue

@@ -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>

+ 13 - 0
litemall-db/src/main/java/org/linlinjava/litemall/db/dao/StatMapper.java

@@ -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();
+}

+ 32 - 0
litemall-db/src/main/java/org/linlinjava/litemall/db/service/StatService.java

@@ -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();
+    }
+}

+ 31 - 0
litemall-db/src/main/resources/org/linlinjava/litemall/db/dao/StatMapper.xml

@@ -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>

+ 46 - 0
litemall-db/src/test/java/org/linlinjava/litemall/db/StatMapperTest.java

@@ -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));
+        }
+    }
+
+}