xiongzhu há 7 anos atrás
pai
commit
0096abce66

+ 11 - 1
src/main/java/com/izouma/awesomeadmin/dao/UserInfoMapper.xml

@@ -20,6 +20,7 @@
         <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
         <result column="del_flag" property="delFlag" jdbcType="CHAR"/>
         <result column="work_number" property="workNumber" jdbcType="VARCHAR"/>
+        <result column="config" property="config" jdbcType="VARCHAR"/>
         <association property="departId" javaType="string" column="id"
                      select="com.izouma.awesomeadmin.dao.DepartInfoMapper.getUserDepartId"/>
         <association property="roleId" javaType="string" column="id"
@@ -27,7 +28,7 @@
     </resultMap>
     <sql id="Base_Column_List">
         id, username, nickname, icon, birthday, sex, open_id, union_id, phone, mail,
-        country, province, city, district, create_time, del_flag, work_number
+        country, province, city, district, create_time, del_flag, work_number, config
     </sql>
     <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer">
         select
@@ -101,6 +102,9 @@
             <if test="workNumber != null">
                 work_number,
             </if>
+            <if test="config != null">
+                config,
+            </if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">
@@ -160,6 +164,9 @@
             <if test="workNumber != null">
                 #{workNumber,jdbcType=VARCHAR},
             </if>
+            <if test="config != null">
+                #{config,jdbcType=VARCHAR},
+            </if>
         </trim>
     </insert>
     <update id="updateByPrimaryKeySelective" parameterType="com.izouma.awesomeadmin.model.UserInfo">
@@ -219,6 +226,9 @@
             <if test="workNumber != null">
                 work_number = #{workNumber,jdbcType=VARCHAR},
             </if>
+            <if test="config != null">
+                config = #{config,jdbcType=VARCHAR},
+            </if>
         </set>
         where id = #{id,jdbcType=INTEGER}
     </update>

+ 10 - 0
src/main/java/com/izouma/awesomeadmin/model/UserInfo.java

@@ -55,6 +55,8 @@ public class UserInfo {
 
     private String workNumber;
 
+    private String config;
+
     public String getToken() {
         return token;
     }
@@ -222,5 +224,13 @@ public class UserInfo {
     public void setWorkNumber(String workNumber) {
         this.workNumber = workNumber;
     }
+
+    public String getConfig() {
+        return config;
+    }
+
+    public void setConfig(String config) {
+        this.config = config;
+    }
 }
 

+ 8 - 5
src/main/java/com/izouma/awesomeadmin/web/UserInfoController.java

@@ -46,15 +46,15 @@ import javax.servlet.http.HttpSession;
 public class UserInfoController {
 
     @Autowired
-    private UserInfoService userInfoService;
+    private UserInfoService   userInfoService;
     @Autowired
-    private PowerInfoService powerInfoService;
+    private PowerInfoService  powerInfoService;
     @Autowired
-    private SysMenuService sysMenuService;
+    private SysMenuService    sysMenuService;
     @Autowired
     private DepartInfoService departInfoService;
     @Autowired
-    private IdentityService identityService;
+    private IdentityService   identityService;
 
     /**
      * <p>获取全部记录。</p>
@@ -80,7 +80,10 @@ public class UserInfoController {
                 Subject subject = SecurityUtils.getSubject();
                 UserInfo userInfo = (UserInfo) subject.getPrincipal();
                 if (userInfo != null) {
-                    return new Result(true, userInfo);
+                    userInfo = userInfoService.getUserInfoById(userInfo.getId().toString());
+                    if (userInfo != null) {
+                        return new Result(true, userInfo);
+                    }
                 }
             } catch (Exception ignored) {
 

Diff do ficheiro suprimidas por serem muito extensas
+ 245 - 233
src/main/vue/package-lock.json


BIN
src/main/vue/src/assets/logo.png


+ 3 - 0
src/main/vue/src/components/MenuItem.vue

@@ -122,6 +122,9 @@ export default {
     padding: 0 45px;
     transition: background-color 0.2s, color 0.2s;
     box-sizing: border-box;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
     * {
         vertical-align: middle;
     }

+ 26 - 10
src/main/vue/src/components/SubMenu.vue

@@ -26,6 +26,7 @@
 </template>
 <script>
     import MenuItem from './MenuItem'
+    import {mapState} from 'vuex'
 
     export default {
         name: 'SubMenu',
@@ -61,6 +62,7 @@
                 w: 0,
                 h: 0,
                 c: 0,
+                top: 0,
                 isOpen: false,
                 active: false,
                 collapsing: false,
@@ -71,6 +73,7 @@
             this.reCale()
         },
         computed: {
+            ...mapState(['windowSize']),
             isLeaf() {
                 return !(this.menu.children instanceof Array)
             },
@@ -92,17 +95,12 @@
             menuStyle() {
                 if ((this.collapse || (this.depth > 0)) && !this.collapsing) {
                     let style = {
-                        position: 'absolute',
+                        position: 'fixed',
                         left: this.x + this.w + 'px',
                         height: 56 * this.c + 10 + 'px',
                         paddingLeft: '5px',
-                        zIndex: 3
-                    }
-                    if (this.$refs.title && (this.$refs.title.getBoundingClientRect().y + 56 * this.c + 15) > window.innerHeight) {
-                        let offset = this.$refs.title.getBoundingClientRect().y + 56 * this.c + 15 - window.innerHeight
-                        style.top = this.y - offset + 'px'
-                    } else {
-                        style.top = this.y + 'px'
+                        zIndex: 3,
+                        top: this.top + 'px'
                     }
                     // if (this.y + 56 * this.c + 10 > window.innerHeight) {
                     //     style.top = window.innerHeight - 56 * this.c - 15 + 'px'
@@ -157,16 +155,30 @@
             },
             reCale() {
                 this.x = this.$refs.title.offsetLeft
-                this.y = this.$refs.title.offsetTop
                 this.w = this.$refs.title.offsetWidth
                 this.h = this.$refs.title.offsetHeight
+                if (this.$refs.title && this.$refs.title.getBoundingClientRect) {
+                    this.y = this.$refs.title.getBoundingClientRect().y
+                    this.x = this.$refs.title.getBoundingClientRect().x
+                } else {
+                    this.y = this.$refs.title.offsetTop
+                }
                 if (!this.isLeaf) {
                     this.c = this.$refs.child.childElementCount
                 }
+                if (this.y + 56 * this.c + 15 > window.innerHeight) {
+                    let offset = this.y + 56 * this.c + 15 - window.innerHeight
+                    this.top = this.y - offset
+                } else {
+                    this.top = this.y
+                }
             },
             enterBody(e) {
                 if (this.collapse || (this.depth > 0)) {
-                    this.isOpen = true
+                    this.reCale();
+                    this.$nextTick(() => {
+                        this.isOpen = true
+                    })
                 }
             },
             leaveBody(e) {
@@ -210,6 +222,9 @@
                 } else {
                     this.isOpen = this.active && this.depth === 0 ? true : false
                 }
+            },
+            "windowSize.height"() {
+                // this.reCale();
             }
         },
         components: {
@@ -226,6 +241,7 @@
         box-sizing: border-box;
         transition: background-color 0.2s, color 0.2s;
         position: relative;
+        user-select: none;
         .icon {
             margin-right: 6px;
         }

+ 20 - 2
src/main/vue/src/entries/admin.js

@@ -156,7 +156,7 @@ Vue.mixin({
             return format(new Date(cellValue), 'HH:mm', {locale: zh})
         },
         datetimeFormatter(row, column, cellValue, index) {
-            if (!cellValue) return ''
+            if (!cellValue) return '';
             return format(new Date(cellValue), 'YYYY/MM/DD HH:mm', {locale: zh})
         }
     }
@@ -173,8 +173,26 @@ const updateTableHeight = () => {
     }
 };
 
+const debounce = function (idle, action) {
+    let last;
+    return function () {
+        let ctx = this, args = arguments;
+        clearTimeout(last);
+        last = setTimeout(function () {
+            action.apply(ctx, args)
+        }, idle)
+    }
+};
+
 window.onload = updateTableHeight;
-window.onresize = updateTableHeight;
+window.onresize = debounce(100, () => {
+
+    updateTableHeight();
+    store.commit('updateWindowSize', {
+        width: window.innerWidth,
+        height: window.innerHeight
+    })
+});
 setInterval(updateTableHeight, 500);
 
 new Vue({

+ 1 - 0
src/main/vue/src/main.less

@@ -10,6 +10,7 @@ html, body {
     -moz-osx-font-smoothing: grayscale;
     margin: 0;
     padding: 0;
+    background: #ffffff;
 }
 
 html {

+ 265 - 268
src/main/vue/src/pages/Admin.vue

@@ -4,40 +4,41 @@
             <div class="logo-wrapper">
                 <img src="../assets/logo.png" alt="">
             </div>
-                <div style="flex-grow: 1; margin-left: 20px;">
-                    <router-link :to="{name:'dashboard'}">牧业2.0系统</router-link>
-                </div>
+            <div style="flex-grow: 1; margin-left: 20px; font-size: 18px;">
+                <router-link :to="{name:'dashboard'}">牧业2.0系统</router-link>
+            </div>
 
-                <div class="header-btn" @click="collapse=!collapse">
-                    <div :style="{transform: collapse ? 'rotate(90deg)' : ''}">
-                        <i class="fas fa-bars" style="font-size: 20px;"></i>
-                    </div>
+            <div class="header-btn" @click="collapse=!collapse">
+                <div :style="{transform: collapse ? 'rotate(90deg)' : ''}">
+                    <i class="fas fa-bars" style="font-size: 20px;"></i>
                 </div>
+            </div>
 
-                <el-tooltip effect="dark" :content="isFullscreen ? '退出全屏' : '全屏'" placement="bottom" :open-delay="1000">
-                    <div class="header-btn" @click="toggleFullScreen" ref="fullscreen">
-                        <i class="fas fa-expand" style="font-size: 20px;"></i>
-                    </div>
-                </el-tooltip>
+            <el-tooltip effect="dark" :content="isFullscreen ? '退出全屏' : '全屏'" placement="bottom" :open-delay="1000">
+                <div class="header-btn" @click="toggleFullScreen" ref="fullscreen">
+                    <i class="fas fa-expand" style="font-size: 20px;"></i>
+                </div>
+            </el-tooltip>
 
-                <el-dropdown @command="onCommand" style="margin-left: 20px;">
-                    <!-- <img :src="userInfo ? userInfo.icon || '' : ''" class="avatar"/> -->
-                    <div class="header-btn">
-                        <div>
-                            <i class="fas fa-cog fa-fw" style="font-size: 20px;color:#fff"></i>
-                        </div>
+            <el-dropdown @command="onCommand" style="margin-left: 20px;">
+                <!-- <img :src="userInfo ? userInfo.icon || '' : ''" class="avatar"/> -->
+                <div class="header-btn">
+                    <div>
+                        <i class="fas fa-cog fa-fw" style="font-size: 20px;color:#fff"></i>
                     </div>
+                </div>
 
-                    <el-dropdown-menu slot="dropdown">
-                        <el-dropdown-item command="logout">退出登录</el-dropdown-item>
-                    </el-dropdown-menu>
-                </el-dropdown>
+                <el-dropdown-menu slot="dropdown">
+                    <el-dropdown-item command="logout">退出登录</el-dropdown-item>
+                </el-dropdown-menu>
+            </el-dropdown>
         </el-header>
         <el-container>
             <el-aside class="aside">
 
                 <div class="userInfo" :style="{height:collapse?'100px':'220px'}">
-                    <img :style="{height:collapse?'30px':'70px',width:collapse?'30px':'70px'}" :src="userInfo ? userInfo.icon || '' : ''" class="avatar"/>
+                    <img :style="{height:collapse?'30px':'70px',width:collapse?'30px':'70px'}"
+                         :src="userInfo ? userInfo.icon || '' : ''" class="avatar"/>
                     <div v-if="!collapse" class="name">{{userInfo.username}}</div>
                     <div v-if="!collapse" class="workNumber">{{userInfo.workNumber}}</div>
                 </div>
@@ -48,16 +49,16 @@
                 <nav-menu :menus="menus" :activeId="activeMenu" :collapse="collapse" :width="220" theme="#232E3B">
                 </nav-menu>
             </el-aside>
-            <el-container style="background-color:#F2F4F5;">
+            <el-container>
                 <el-header height='40px' style='padding:0'>
-                    <el-tabs class="head-tabs" height='40px' v-model="editableTabsValue2" type="card" closable @tab-remove="removeTab" @tab-click="chooseOne">
-                        <el-tab-pane v-for="(item, index) in loginHistory" :key="item.name" :label="item.title" :name="item.name">
-
+                    <el-tabs class="head-tabs" height='40px' v-model="editableTabsValue2" type="card" closable
+                             @tab-remove="removeTab" @tab-click="chooseOne">
+                        <el-tab-pane v-for="(item, index) in loginHistory" :key="item.name" :label="item.title"
+                                     :name="item.name">
                         </el-tab-pane>
                     </el-tabs>
                 </el-header>
-                <el-main >
-
+                <el-main>
                     <router-view></router-view>
                 </el-main>
             </el-container>
@@ -67,290 +68,286 @@
 </template>
 
 <script>
-import SysMenu from '../components/SysMenu'
-import NavMenu from '../components/NavMenu'
-import { mapState } from 'vuex'
+    import SysMenu from '../components/SysMenu'
+    import NavMenu from '../components/NavMenu'
+    import {mapState} from 'vuex'
 
-export default {
-    name: 'App',
-    mounted() {
-        this.getMenus();
-        let fn = () => {
-            this.isFullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+    export default {
+        name: 'App',
+        mounted() {
+            this.getMenus();
+            let fn = () => {
+                this.isFullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
 
-        };
-        document.addEventListener('fullscreenchange', fn);
-        document.addEventListener('webkitfullscreenchange', fn);
-        document.addEventListener('mozfullscreenchange', fn);
-        document.addEventListener('MSFullscreenChange', fn);
-    },
-    data() {
-        return {
-            rawMenus: [],
-            menus: [],
-            activeMenu: '',
-            menuPath: [],
-            collapse: false,
-            isFullscreen: false,
-            editableTabsValue2: '/dashboard',
-            flag: true
-        }
-    },
-    computed: {
-        ...mapState(['userInfo', 'loginHistory', 'chooseLogin'])
-    },
-    methods: {
-        findActiveMenu() {
-            var list = [...this.loginHistory]
-            this.activeMenu = '';
-            this.menuPath = [];
-            let path = this.$route.path;
-            const findActiveMenu = (parents, childMenus) => {
-                childMenus.forEach(i => {
-                    let parents_copy = [...parents];
-                    if (i.href === path) {
-                        parents_copy.push(i);
-                        this.menuPath = parents_copy.map(i => i.name);
-                        this.activeMenu = i.id;
-                        if (this.flag) {
-                            var flag = false
-                            list.forEach(item => {
-                                if (item.name == i.href) {
-                                    flag = true
-                                }
-                            })
-                            if (!flag) {
-                                list.push({
-                                    name: i.href,
-                                    title: i.name
+            };
+            document.addEventListener('fullscreenchange', fn);
+            document.addEventListener('webkitfullscreenchange', fn);
+            document.addEventListener('mozfullscreenchange', fn);
+            document.addEventListener('MSFullscreenChange', fn);
+        },
+        data() {
+            return {
+                rawMenus: [],
+                menus: [],
+                activeMenu: '',
+                menuPath: [],
+                collapse: false,
+                isFullscreen: false,
+                editableTabsValue2: '/dashboard',
+                flag: true
+            }
+        },
+        computed: {
+            ...mapState(['userInfo', 'loginHistory', 'chooseLogin'])
+        },
+        methods: {
+            findActiveMenu() {
+                var list = [...this.loginHistory]
+                this.activeMenu = '';
+                this.menuPath = [];
+                let path = this.$route.path;
+                const findActiveMenu = (parents, childMenus) => {
+                    childMenus.forEach(i => {
+                        let parents_copy = [...parents];
+                        if (i.href === path) {
+                            parents_copy.push(i);
+                            this.menuPath = parents_copy.map(i => i.name);
+                            this.activeMenu = i.id;
+                            if (this.flag) {
+                                var flag = false
+                                list.forEach(item => {
+                                    if (item.name == i.href) {
+                                        flag = true
+                                    }
                                 })
-                                this.$store.commit('updateLoginHistory', list)
-                                this.editableTabsValue2 = i.href
-                            }
+                                if (!flag) {
+                                    list.push({
+                                        name: i.href,
+                                        title: i.name
+                                    })
+                                    this.$store.commit('updateLoginHistory', list)
+                                    this.editableTabsValue2 = i.href
+                                }
 
-                        }
+                            }
 
 
-                    } else {
-                        if (i.children) {
-                            parents_copy.push(i);
-                            findActiveMenu(parents_copy, i.children);
+                        } else {
+                            if (i.children) {
+                                parents_copy.push(i);
+                                findActiveMenu(parents_copy, i.children);
+                            }
                         }
+                    })
+                };
+                findActiveMenu([], this.rawMenus);
+            },
+            getMenus() {
+                this.$http.get({
+                    url: '/sysMenu/userMenuTree',
+                    data: {
+                        userId: this.userInfo.id
                     }
-                })
-            };
-            findActiveMenu([], this.rawMenus);
-        },
-        getMenus() {
-            this.$http.get({
-                url: '/sysMenu/userMenuTree',
-                data: {
-                    userId: this.userInfo.id
-                }
-            }).then(res => {
-                if (res.success) {
-                    this.rawMenus = res.data;
-                    this.menus = res.data;
-                    this.findActiveMenu();
-                }
-            })
-        },
-        toggleFullScreen() {
-            this.isFullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
-            let element = document.body;
-            let requestMethod;
-            if (this.isFullscreen) {
-                requestMethod = document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen;
-            } else {
-                requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
-            }
-            if (requestMethod) {
-                requestMethod.call(this.isFullscreen ? document : element);
-            }
-        },
-        onCommand(command) {
-            if (command === 'logout') {
-                this.$http.post({
-                    url: '/auth/logout'
                 }).then(res => {
                     if (res.success) {
-                        this.$store.commit('updateUserInfo', null);
-                        this.$router.replace('/login');
+                        this.rawMenus = res.data;
+                        this.menus = res.data;
+                        this.findActiveMenu();
                     }
                 })
-            }
-        },
-        removeTab(temp) {
-            console.log(temp)
-            var list = [...this.loginHistory]
-
-            list.forEach((item, index) => {
-                if (item.name == temp) {
-                    list.splice(index, 1)
+            },
+            toggleFullScreen() {
+                this.isFullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+                let element = document.body;
+                let requestMethod;
+                if (this.isFullscreen) {
+                    requestMethod = document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen;
+                } else {
+                    requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
                 }
-            })
+                if (requestMethod) {
+                    requestMethod.call(this.isFullscreen ? document : element);
+                }
+            },
+            onCommand(command) {
+                if (command === 'logout') {
+                    this.$http.post({
+                        url: '/auth/logout'
+                    }).then(res => {
+                        if (res.success) {
+                            this.$store.commit('updateUserInfo', null);
+                            this.$router.replace('/login');
+                        }
+                    })
+                }
+            },
+            removeTab(temp) {
+                console.log(temp)
+                var list = [...this.loginHistory]
 
-            if (list.length == 0) {
-                list.push({
-                    name: '/dashboard',
-                    title: '首页'
+                list.forEach((item, index) => {
+                    if (item.name == temp) {
+                        list.splice(index, 1)
+                    }
                 })
-            }
 
+                if (list.length == 0) {
+                    list.push({
+                        name: '/dashboard',
+                        title: '首页'
+                    })
+                }
 
-            this.$store.commit('updateLoginHistory', list)
-            setTimeout(() => {
-                if (temp == this.editableTabsValue2) {
 
-                    this.$router.push({
-                        path: list[0].name
-                    })
-                    this.$store.commit('updateChooseLogin', list[0].name)
+                this.$store.commit('updateLoginHistory', list)
+                setTimeout(() => {
+                    if (temp == this.editableTabsValue2) {
 
-                }
+                        this.$router.push({
+                            path: list[0].name
+                        })
+                        this.$store.commit('updateChooseLogin', list[0].name)
 
-            }, 100);
-        },
-        chooseOne(item) {
-            this.$router.push({
-                path: item.name
-            })
-            this.editableTabsValue2 = item.name
-        }
-    },
-    watch: {
-        $route(val) {
-            this.findActiveMenu(this.rawMenus);
-            this.flag = false
-        },
-        isFullscreen(val) {
-            this.$refs.fullscreen.innerHTML = '';
-            let i = document.createElement('i');
-            i.style.fontSize = '20px';
-            i.className = val ? 'fas fa-compress' : 'fas fa-expand';
-            this.$refs.fullscreen.append(i);
-            FontAwesome.dom.i2svg();
+                    }
+
+                }, 100);
+            },
+            chooseOne(item) {
+                this.$router.push({
+                    path: item.name
+                })
+                this.editableTabsValue2 = item.name
+            }
         },
-        chooseLogin() {
-            if (this.chooseLogin) {
-                this.editableTabsValue2 = this.chooseLogin
+        watch: {
+            $route(val) {
+                this.findActiveMenu(this.rawMenus);
+                this.flag = false
+            },
+            isFullscreen(val) {
+                this.$refs.fullscreen.innerHTML = '';
+                let i = document.createElement('i');
+                i.style.fontSize = '20px';
+                i.className = val ? 'fas fa-compress' : 'fas fa-expand';
+                this.$refs.fullscreen.append(i);
+                FontAwesome.dom.i2svg();
+            },
+            chooseLogin() {
+                if (this.chooseLogin) {
+                    this.editableTabsValue2 = this.chooseLogin
+                }
             }
+        },
+        components: {
+            SysMenu,
+            NavMenu
         }
-    },
-    components: {
-        SysMenu,
-        NavMenu
     }
-}
 </script>
 <style lang="less">
-.aside {
-    width: auto !important;
-    .el-menu {
-        border: none !important;
-        &:not(.el-menu--collapse) {
-            width: 200px;
+    .aside {
+        width: auto !important;
+        .el-menu {
+            border: none !important;
+            &:not(.el-menu--collapse) {
+                width: 200px;
+            }
         }
     }
-}
 </style>
 <style lang="less" scoped>
-#app {
-    height: 100%;
-}
-
-.header {
-    color: #fff;
-    background-color: #0096e0;
-    display: flex;
-    align-items: center;
-    padding-left: 0;
-    // border-bottom: 1px solid #dcdfe6;
-    height: 68px;
+    #app {
+        height: 100%;
+    }
 
-    .logo-wrapper {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        min-width: 220px;
-        color: white;
-        font-size: 20px;
-        font-weight: 700;
-        // background: fade(black, 20%);
-        background-color: #0096e0;
+    .header {
+        color: #fff;
+        background-color: #409EFF;
         display: flex;
         align-items: center;
-        img {
-            width: 162px;
-            height: 48px;
+        padding-left: 0;
+        // border-bottom: 1px solid #dcdfe6;
+        height: 68px;
+
+        .logo-wrapper {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: white;
+            font-size: 20px;
+            font-weight: 700;
+            // background: fade(black, 20%);
+            padding-left: 20px;
+            img {
+                height: 64px;
+            }
         }
-    }
 
-    .header-btn {
-        width: 60px;
-        height: 68px;
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        cursor: pointer;
-        transition: all 0.3s;
-        & > div {
+        .header-btn {
+            width: 60px;
+            height: 68px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
             transition: all 0.3s;
+            & > div {
+                transition: all 0.3s;
+            }
+            &:hover {
+                background: fade(black, 10%);
+            }
         }
-        &:hover {
-            background: fade(black, 10%);
+        .avatar {
+            width: 40px;
+            height: 40px;
+            border: 1px solid #ebebeb;
+            border-radius: 50%;
         }
-    }
-    .avatar {
-        width: 40px;
-        height: 40px;
-        border: 1px solid #ebebeb;
-        border-radius: 50%;
-    }
-    a {
-        &:visited {
-            color: #fff;
-            font-weight: bold;
+        a {
+            &:visited {
+                color: #fff;
+                font-weight: bold;
+            }
         }
     }
-}
 
-.aside {
-    background: #232e3b;
-    transition: all 0.4s ease;
-    -ms-overflow-style: none;
+    .aside {
+        background: #232e3b;
+        transition: all 0.4s ease;
+        -ms-overflow-style: none;
 
-    .userInfo {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        flex-direction: column;
-        height: 220px;
-        img {
-            width: 70px;
-            height: 70px;
-            border-radius: 100%;
-            margin-top: 20px;
-        }
+        .userInfo {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            flex-direction: column;
+            height: 220px;
+            img {
+                width: 70px;
+                height: 70px;
+                border-radius: 100%;
+                margin-top: 20px;
+            }
 
-        .name {
-            font-size: 20px;
-            font-weight: 500;
-            color: rgba(255, 255, 255, 1);
-            line-height: 28px;
-            margin-top: 12px;
-        }
+            .name {
+                font-size: 20px;
+                font-weight: 500;
+                color: rgba(255, 255, 255, 1);
+                line-height: 28px;
+                margin-top: 12px;
+            }
 
-        .workNumber {
-            font-size: 14px;
-            font-weight: 400;
-            color: rgba(255, 255, 255, 1);
-            line-height: 20px;
+            .workNumber {
+                font-size: 14px;
+                font-weight: 400;
+                color: rgba(255, 255, 255, 1);
+                line-height: 20px;
+            }
         }
     }
-}
 
-.aside::-webkit-scrollbar {
-    display: none;
-}
+    .aside::-webkit-scrollbar {
+        display: none;
+    }
 </style>

+ 77 - 58
src/main/vue/src/pages/Dashboard.vue

@@ -1,7 +1,13 @@
 <template>
-    <div>
-        <el-button v-if="editable" size="small" @click="save">保存</el-button>
-        <el-button v-else size="small" @click="editable=true">编辑</el-button>
+    <div style="padding-bottom: 80px">
+        <div class="edit-icon-wrapper">
+            <template v-if="editable">
+                <i class="edit-icon el-icon-plus"></i>
+                <i class="edit-icon el-icon-close" @click="editable = false"></i>
+                <i class="edit-icon el-icon-check" @click="save"></i>
+            </template>
+            <i v-else class="edit-icon el-icon-edit" @click="editable=true"></i>
+        </div>
         <grid-layout
             style="margin:0 -10px;"
             :layout="layout"
@@ -29,82 +35,95 @@
 
 <script>
     import {GridLayout, GridItem} from 'vue-grid-layout'
+    import defaultLayout from './DashboardDefaultLayout.json'
+    import {mapState} from 'vuex'
 
     export default {
         created() {
-
+            let layout;
+            try {
+                let config = JSON.parse(this.userInfo.config);
+                layout = config.dashboard;
+            } catch (e) {
+            }
+            if (!layout) {
+                layout = defaultLayout
+            }
+            this.layout = layout;
         },
         data() {
             return {
-                layout: [
-                    {
-                        "x": 0,
-                        "y": 2,
-                        "w": 6,
-                        "h": 10,
-                        "i": "4",
-                        "name": "CowStructure",
-                        "moved": false
-                    },
-                    {
-                        "x": 0,
-                        "y": 0,
-                        "w": 2,
-                        "h": 2,
-                        "i": "5",
-                        "name": "FarmNum",
-                        "moved": false
-                    },
-                    {
-                        "x": 0,
-                        "y": 12,
-                        "w": 12,
-                        "h": 7,
-                        "i": "6",
-                        "name": "AverageLactation",
-                        "moved": false
-                    },
-                    {
-                        "x": 6,
-                        "y": 2,
-                        "w": 6,
-                        "h": 10,
-                        "i": "7",
-                        "name": "AreaLivestock",
-                        "moved": false
-                    },
-                    {
-                        "x": 2,
-                        "y": 0,
-                        "w": 10,
-                        "h": 2,
-                        "i": "8",
-                        "name": "CowNum",
-                        "moved": false
-                    }
-                ],
+                layout: [],
                 editable: false
             }
         },
+        computed: {
+            ...mapState(['userInfo'])
+        },
         methods: {
             save() {
                 console.log(JSON.stringify(this.layout, null, 4));
-                this.editable = false
+                this.editable = false;
+                let config = JSON.parse(this.userInfo.config || "{}");
+                config.dashboard = this.layout;
+                config = JSON.stringify(config);
+                this.$http.post({
+                    url: '/userInfo/update',
+                    data: {
+                        id: this.userInfo.id,
+                        config: config
+                    }
+                }).then(res => {
+                    if (res.success) {
+                        this.$message.success('保存成功')
+                    }
+                })
             }
-        },
+        }
+        ,
         components: {
             GridLayout,
             GridItem,
-            CowStructure: () => import('../widgets/CowStructure'),
-            FarmNum: () => import('../widgets/FarmNum'),
-            AverageLactation: () => import('../widgets/AverageLactation'),
-            AreaLivestock: () => import('../widgets/AreaLivestock'),
-            CowNum: () => import('../widgets/CowNum')
+            CowStructure:
+                () => import('../widgets/CowStructure'),
+            FarmNum:
+                () => import('../widgets/FarmNum'),
+            AverageLactation:
+                () => import('../widgets/AverageLactation'),
+            AreaLivestock:
+                () => import('../widgets/AreaLivestock'),
+            CowNum:
+                () => import('../widgets/CowNum'),
+            CowStockChange:
+                () => import('../widgets/CowStockChange')
         }
     }
 </script>
 
 <style lang="less">
+    .edit-icon-wrapper {
+        position: fixed;
+        bottom: 40px;
+        right: 40px;
+        display: flex;
+        flex-direction: column;
+        z-index: 999;
+        .edit-icon {
+            margin-top: 20px;
+            border-radius: 50%;
+            width: 40px;
+            height: 40px;
+            background: #ffffff;
+            text-align: center;
+            line-height: 40px;
+            box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.3);
+            cursor: pointer;
+            &:hover {
+                background: fade(#ffffff, 20%);
+            }
+        }
+    }
+
     .widget-wrapper {
         display: flex;
         flex-direction: column;

+ 56 - 0
src/main/vue/src/pages/DashboardDefaultLayout.json

@@ -0,0 +1,56 @@
+[
+    {
+        "x": 0,
+        "y": 2,
+        "w": 4,
+        "h": 11,
+        "i": "4",
+        "name": "CowStructure",
+        "moved": false
+    },
+    {
+        "x": 0,
+        "y": 0,
+        "w": 2,
+        "h": 2,
+        "i": "5",
+        "name": "FarmNum",
+        "moved": false
+    },
+    {
+        "x": 0,
+        "y": 13,
+        "w": 6,
+        "h": 10,
+        "i": "6",
+        "name": "AverageLactation",
+        "moved": false
+    },
+    {
+        "x": 6,
+        "y": 13,
+        "w": 6,
+        "h": 10,
+        "i": "7",
+        "name": "AreaLivestock",
+        "moved": false
+    },
+    {
+        "x": 2,
+        "y": 0,
+        "w": 10,
+        "h": 2,
+        "i": "8",
+        "name": "CowNum",
+        "moved": false
+    },
+    {
+        "x": 4,
+        "y": 2,
+        "w": 8,
+        "h": 11,
+        "i": "9",
+        "name": "CowStockChange",
+        "moved": false
+    }
+]

+ 9 - 3
src/main/vue/src/vuex/index.js

@@ -13,7 +13,11 @@ export default new Vuex.Store({
             name: '/dashboard',
             title: '首页'
         }],
-        chooseLogin: 'dashboard'
+        chooseLogin: 'dashboard',
+        windowSize: {
+            width: 0,
+            height: 0
+        }
     },
     mutations: {
         updateTableHeight(state, height) {
@@ -30,8 +34,10 @@ export default new Vuex.Store({
         },
         updateChooseLogin(state, name) {
             state.chooseLogin = name
+        },
+        updateWindowSize(state, windowSize) {
+            state.windowSize = windowSize
         }
     },
     actions: {}
-})
-;
+});

+ 31 - 43
src/main/vue/src/widgets/AreaLivestock.vue

@@ -1,7 +1,7 @@
 <template>
     <widget-card :bodyStyle="bodyStyle" ref="container" class="chart-container">
         <div slot="header">区域存栏数</div>
-        <div id="chart-area-livestock"></div>
+        <div ref="chart" class="chart"></div>
     </widget-card>
 </template>
 <script>
@@ -11,15 +11,33 @@
 
     export default {
         mounted() {
-            require.ensure(['@antv/g2', '@antv/data-set'], require => {
+            require.ensure(['@antv/g2'], require => {
                 const G2 = require('@antv/g2');
-                const DataSet = require('@antv/data-set');
-                axios.get(this.$widgetBaseUrl + 'api/Values/GetCowsAvgMrDays', {
+                axios.get(this.$widgetBaseUrl + 'api/Values/GetCowsQYCLS', {
                     withCredentials: false
                 }).then(res => {
                     if (res.data.rtnCode > 0) {
-                        this.chartData = res.data.rtnList;
-                        this.drawChart(G2, DataSet);
+                        let data = [];
+                        res.data.rtnList.forEach(i => {
+                            if (!i['当前牧场']) return;
+                            data.push({
+                                "牧场": i['当前牧场'],
+                                "牛数": i["后备牛"],
+                                type: '后备牛'
+                            });
+                            data.push({
+                                "牧场": i['当前牧场'],
+                                "牛数": i["泌乳牛"],
+                                type: '泌乳牛'
+                            });
+                            data.push({
+                                "牧场": i['当前牧场'],
+                                "牛数": i["干奶牛"],
+                                type: '干奶牛'
+                            });
+                        });
+                        this.chartData = data;
+                        this.drawChart(G2);
                     }
                 })
             });
@@ -38,50 +56,20 @@
             ...mapState(['farmName'])
         },
         methods: {
-            drawChart(G2, DataSet) {
-                var data = [{
-                    name: 'London',
-                    'Jan.': 18.9,
-                    'Feb.': 28.8,
-                    'Mar.': 39.3,
-                    'Apr.': 81.4,
-                    'May': 47,
-                    'Jun.': 20.3,
-                    'Jul.': 24,
-                    'Aug.': 35.6
-                }, {
-                    name: 'Berlin',
-                    'Jan.': 12.4,
-                    'Feb.': 23.2,
-                    'Mar.': 34.5,
-                    'Apr.': 99.7,
-                    'May': 52.6,
-                    'Jun.': 35.5,
-                    'Jul.': 37.4,
-                    'Aug.': 42.4
-                }];
-                var ds = new DataSet();
-                var dv = ds.createView().source(data);
-                dv.transform({
-                    type: 'fold',
-                    fields: ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'Jun.', 'Jul.', 'Aug.'], // 展开字段集
-                    key: '月份', // key字段
-                    value: '月均降雨量' // value字段
-                });
-
-                var chart = new G2.Chart({
-                    container: 'chart-area-livestock',
+            drawChart(G2) {
+                let chart = new G2.Chart({
+                    container: this.$refs.chart,
                     forceFit: true,
                     height: this.$refs.container.$el.offsetHeight - 75,
                     padding: 'auto',
                     options: {
                         legends: {
-                            position: 'right',
+                            position: 'bottom',
                         }
                     }
                 });
-                chart.source(dv);
-                chart.intervalStack().position('月份*月均降雨量').color('name');
+                chart.source(this.chartData);
+                chart.intervalStack().position('牧场*牛数').color('type');
                 chart.render();
             }
         },
@@ -91,7 +79,7 @@
     }
 </script>
 <style lang="less" scoped>
-    #chart-area-livestock {
+    .chart {
         width: 100%;
     }
 </style>

+ 1 - 1
src/main/vue/src/widgets/AverageLactation.vue

@@ -19,7 +19,7 @@
                     if (res.data.rtnCode > 0) {
                         this.chartData = res.data.rtnList.map(i => {
                             return {
-                                name: i['当前牧场'],
+                                name: String(i['当前牧场']),
                                 value: i['泌乳天数']
                             }
                         });

+ 118 - 0
src/main/vue/src/widgets/CowStockChange.vue

@@ -0,0 +1,118 @@
+<template>
+    <widget-card :bodyStyle="bodyStyle" ref="container" class="chart-container">
+        <div slot="header">牛只存量变化</div>
+        <div ref="chart" class="chart"></div>
+    </widget-card>
+</template>
+<script>
+    import WidgetCard from './WidgetCard'
+    import {mapState} from 'vuex'
+    import axios from 'axios'
+    import {format} from 'date-fns'
+
+    export default {
+        mounted() {
+            require.ensure(['@antv/g2'], require => {
+                const G2 = require('@antv/g2');
+                axios.get(this.$widgetBaseUrl + 'api/Values/GetCowsStock', {
+                    params: {
+                        FrameName: this.farmName
+                    },
+                    withCredentials: false
+                }).then(res => {
+                    if (res.data.rtnCode > 0) {
+                        let data = [];
+                        res.data.rtnList.forEach(i => {
+                            data.push({
+                                "牛群": '泌乳牛',
+                                date: i['日期'],
+                                "数量": i['泌乳牛头数']
+                            });
+                            data.push({
+                                "牛群": '干奶牛',
+                                date: i['日期'],
+                                "数量": i['干奶牛头数']
+                            });
+                            data.push({
+                                "牛群": '成母牛',
+                                date: i['日期'],
+                                "数量": i['成母牛头数']
+                            });
+                        });
+                        this.chartData = data;
+                        this.drawChart(G2);
+                    }
+                })
+            });
+        },
+        data() {
+            return {
+                myChart: null,
+                bodyStyle: {
+                    display: 'flex',
+                    alignItems: 'center'
+                },
+                chartData: []
+            }
+        },
+        computed: {
+            ...mapState(['farmName'])
+        },
+        methods: {
+            drawChart(G2) {
+                let data = [
+                    {
+                        "牛群": "泌乳牛",
+                        "date": format(new Date("2018.09.27"), 'YYYY年MM月DD日'),
+                        "数量": 3623
+                    },
+                    {
+                        "牛群": "干奶牛",
+                        "date": format(new Date("2018.09.27"), 'YYYY年MM月DD日'),
+                        "数量": 714
+                    },
+                    {
+                        "牛群": "成母牛",
+                        "date": format(new Date("2018.09.27"), 'YYYY年MM月DD日'),
+                        "数量": 4337
+                    },
+                    {
+                        "牛群": "泌乳牛",
+                        "date": format(new Date("2018.09.28"), 'YYYY年MM月DD日'),
+                        "数量": 3623
+                    },
+                    {
+                        "牛群": "干奶牛",
+                        "date": format(new Date("2018.09.28"), 'YYYY年MM月DD日'),
+                        "数量": 714
+                    },
+                    {
+                        "牛群": "成母牛",
+                        "date": format(new Date("2018.09.28"), 'YYYY年MM月DD日'),
+                        "数量": 4337
+                    }
+                ];
+                console.log(JSON.stringify(data, 0, 4))
+                let chart = new G2.Chart({
+                    container: this.$refs.chart,
+                    forceFit: true,
+                    height: this.$refs.container.$el.offsetHeight - 75,
+                });
+                chart.source(data);
+                chart.interval().position('牛群*数量').color('date').adjust([{
+                    type: 'dodge',
+                    marginRatio: 1 / 32
+                }]);
+                chart.render();
+            }
+        },
+        components: {
+            WidgetCard
+        }
+    }
+</script>
+<style lang="less" scoped>
+    .chart {
+        width: 100%;
+    }
+</style>

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff