shaogen1995 3 лет назад
Родитель
Сommit
32d3e5130f

+ 59 - 0
houtai/package-lock.json

@@ -11,6 +11,7 @@
         "axios": "^0.24.0",
         "Base64": "^1.1.0",
         "core-js": "^3.6.5",
+        "echarts": "^5.3.2",
         "element-ui": "^2.15.6",
         "js-base64": "^3.7.2",
         "moment": "^2.29.1",
@@ -6062,6 +6063,20 @@
         "safer-buffer": "^2.1.0"
       }
     },
+    "node_modules/echarts": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz",
+      "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==",
+      "dependencies": {
+        "tslib": "2.3.0",
+        "zrender": "5.3.1"
+      }
+    },
+    "node_modules/echarts/node_modules/tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+    },
     "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
@@ -16459,6 +16474,19 @@
       "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-2.1.2.tgz",
       "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
       "dev": true
+    },
+    "node_modules/zrender": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz",
+      "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==",
+      "dependencies": {
+        "tslib": "2.3.0"
+      }
+    },
+    "node_modules/zrender/node_modules/tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
     }
   },
   "dependencies": {
@@ -21301,6 +21329,22 @@
         "safer-buffer": "^2.1.0"
       }
     },
+    "echarts": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.3.2.tgz",
+      "integrity": "sha512-LWCt7ohOKdJqyiBJ0OGBmE9szLdfA9sGcsMEi+GGoc6+Xo75C+BkcT/6NNGRHAWtnQl2fNow05AQjznpap28TQ==",
+      "requires": {
+        "tslib": "2.3.0",
+        "zrender": "5.3.1"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
+          "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+        }
+      }
+    },
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz",
@@ -29911,6 +29955,21 @@
           "dev": true
         }
       }
+    },
+    "zrender": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.3.1.tgz",
+      "integrity": "sha512-7olqIjy0gWfznKr6vgfnGBk7y4UtdMvdwFmK92vVQsQeDPyzkHW1OlrLEKg6GHz1W5ePf0FeN1q2vkl/HFqhXw==",
+      "requires": {
+        "tslib": "2.3.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.3.0",
+          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
+          "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+        }
+      }
     }
   }
 }

+ 1 - 0
houtai/package.json

@@ -11,6 +11,7 @@
     "axios": "^0.24.0",
     "Base64": "^1.1.0",
     "core-js": "^3.6.5",
+    "echarts": "^5.3.2",
     "element-ui": "^2.15.6",
     "js-base64": "^3.7.2",
     "moment": "^2.29.1",

+ 57 - 0
houtai/src/apis/system.js

@@ -0,0 +1,57 @@
+import axios from '../utils/request'
+// 获取用户列表
+export const userList = (data) => {
+  return axios({
+    method: 'post',
+    url: '/sys/user/list',
+    data
+  })
+}
+// 新增/编辑用户
+export const userSave = (data) => {
+  return axios({
+    method: 'post',
+    url: '/sys/user/save',
+    data
+  })
+}
+
+// 删除用户
+export const userDel = (ids) => {
+  return axios({
+    method: 'get',
+    url: `/sys/user/removes/${ids}`
+  })
+}
+
+// 启用、停用账户
+export const editStatus = (id, isEnabled) => {
+  return axios({
+    method: 'get',
+    url: `/sys/user/editStatus/${id}/${isEnabled}`
+  })
+}
+// 重置密码
+export const userResetPass = (id) => {
+  return axios({
+    method: 'get',
+    url: `/sys/user/resetPass/${id}`
+  })
+}
+
+// 操作日志
+export const logList = (data) => {
+  return axios({
+    method: 'post',
+    url: '/sys/log/list',
+    data
+  })
+}
+
+// 授权项目
+export const userAuths = (userId, projectIds) => {
+  return axios({
+    method: 'get',
+    url: `/sys/user/auth/${userId}?projectIds=${projectIds}`
+  })
+}

+ 4 - 4
houtai/src/assets/css/base.css

@@ -134,10 +134,10 @@ input[type="number"] {
   border-radius: 5px;
   margin: 0 5px;
   min-width: 28px;
-  background-color: #f4f4f5;
+  background-color: transparent;
 }
 .el-pagination .btn-next, .el-pagination .btn-prev{
-  background-color: #f4f4f5;
+  background-color: transparent;
   padding: 0;
   min-width: 28px;
 }
@@ -148,8 +148,8 @@ input[type="number"] {
   color: #b9412e;
 }
 .el-pager li.active{
-  color: #fff;
-  background-color: #b9412e;
+  color: #b9412e;
+  background-color: transparent;
 }
 .el-pagination button:hover{
   color: #b9412e;

BIN
houtai/src/assets/img/1.png


BIN
houtai/src/assets/img/2.png


BIN
houtai/src/assets/img/3.png


BIN
houtai/src/assets/img/4.png


+ 25 - 13
houtai/src/views/layout/index.vue

@@ -2,9 +2,9 @@
   <div class="layout">
     <div class="top">
       <p>江门市中国传统村落一张图管理后台</p>
-      <div class="top_right" @mouseenter='cut=true' @mouseleave='cut=false'>
+      <div class="top_right" @mouseenter="cut = true" @mouseleave="cut = false">
         <div class="user">
-          <span>{{userName}}</span>
+          <span>{{ userInfo.userName }}</span>
           <!-- 下箭头 -->
           <div class="pull_down" v-if="cut"></div>
           <div class="pull_up" v-else></div>
@@ -18,7 +18,12 @@
     </div>
     <div class="con">
       <div class="left">
-        <div class="biaoji el-icon-message" :class="{biaojiAc: $route.meta.myInd===1}">内容管理</div>
+        <div
+          class="biaoji el-icon-message"
+          :class="{ biaojiAc: $route.meta.myInd === 1 }"
+        >
+          内容管理
+        </div>
         <ul>
           <li
             v-for="item in tab1"
@@ -29,8 +34,14 @@
             {{ item.name }}
           </li>
         </ul>
-        <div class="biaoji el-icon-setting" :class="{biaojiAc: $route.meta.myInd>1}">系统管理</div>
-        <ul>
+        <div
+          v-if="userAdmin"
+          class="biaoji el-icon-setting"
+          :class="{ biaojiAc: $route.meta.myInd > 1 }"
+        >
+          系统管理
+        </div>
+        <ul v-if="userAdmin">
           <li
             v-for="item in tab2"
             :key="item.id"
@@ -96,6 +107,8 @@ export default {
       }
     }
     return {
+      userAdmin: false,
+
       // 修改密码
       form: {
         oldPassword: '',
@@ -110,12 +123,10 @@ export default {
           { max: 15, message: '不能超过15个字', trigger: 'blur' }
         ]
       },
-      userName: '',
+      userInfo: {},
       cut: false,
       isShow: false,
-      tab1: [
-        { name: '资料管理', id: 1, url: '/layout/tab1' }
-      ],
+      tab1: [{ name: '资料管理', id: 1, url: '/layout/tab1' }],
       tab2: [
         { name: '用户管理', id: 2, url: '/layout/tab2' },
         { name: '数据统计', id: 3, url: '/layout/tab3' },
@@ -172,7 +183,7 @@ export default {
       })
         .then(() => {
           localStorage.clear('JMYZU_token')
-          localStorage.clear('JMYZU_userName')
+          localStorage.clear('JMYZU_userInfo')
           this.$router.push('/')
           this.$message.success('退出成功!')
         })
@@ -184,8 +195,9 @@ export default {
   // 生命周期 - 创建完成(可以访问当前this实例)
   created () {
     // 获取用户名
-    const res = localStorage.getItem('JMYZU_userName')
-    this.userName = res
+    const res = JSON.parse(localStorage.getItem('JMYZU_userInfo'))
+    this.userInfo = res
+    if (res.isAdmin === 1) this.userAdmin = true
   },
   // 生命周期 - 挂载完成(可以访问DOM元素)
   mounted () {},
@@ -308,7 +320,7 @@ export default {
       padding-left: 20px;
       padding-right: 30px;
     }
-    .biaojiAc{
+    .biaojiAc {
       background-color: #a30014;
       color: #fff;
     }

+ 1 - 1
houtai/src/views/login.vue

@@ -73,7 +73,7 @@ export default {
         const res = await userLogin(data)
         if (res.code === 0) {
           localStorage.setItem('JMYZU_token', res.data.token)
-          localStorage.setItem('JMYZU_userName', res.data.user.userName)
+          localStorage.setItem('JMYZU_userInfo', JSON.stringify(res.data.user))
           this.$router.push('/layout/tab1')
           this.$message.success('登录成功')
         } else this.$message.warning(res.msg)

+ 10 - 2
houtai/src/views/tab1/index.vue

@@ -17,9 +17,17 @@
       </div>
       <div class="table">
         <el-table :data="tableData" style="width: 100%">
-          <el-table-column prop="id" label="编号" width="200"></el-table-column>
+          <el-table-column label="编号" width="150">
+            <template slot-scope="scope">
+              {{ scope.$index + 1 }}
+            </template>
+          </el-table-column>
+          <!-- <el-table-column prop="id" label="编号" width="200"></el-table-column> -->
           <el-table-column prop="name" label="村落名称"></el-table-column>
-          <el-table-column prop="updateTime" label="最近更新时间"></el-table-column>
+          <el-table-column
+            prop="updateTime"
+            label="最近更新时间"
+          ></el-table-column>
           <el-table-column label="操作">
             <template #default="{ row }">
               <el-button

+ 218 - 0
houtai/src/views/tab2/Dialog.vue

@@ -0,0 +1,218 @@
+<template>
+  <el-dialog
+    :title="ruleForm.id ? '编辑用户' : '新增用户'"
+    :visible="dialogVisible"
+    @close="btnX"
+  >
+    <el-form
+      :model="ruleForm"
+      :rules="rules"
+      ref="ruleForm"
+      label-width="100px"
+      class="demo-ruleForm"
+    >
+      <el-form-item label="账号" prop="userName">
+        <el-input
+          :disabled="!!ruleForm.id"
+          v-model="ruleForm.userName"
+          maxlength="15"
+          show-word-limit
+        ></el-input>
+      </el-form-item>
+      <el-form-item label="电话" prop="phone">
+        <el-input
+          v-model="ruleForm.phone"
+          maxlength="11"
+          show-word-limit
+        ></el-input>
+      </el-form-item>
+      <!-- 授权 -->
+      <div class="limits" v-if="ruleForm.id&&ruleForm.isAdmin !== 1">
+        <span>权限</span>&emsp;
+        <el-checkbox
+          :indeterminate="isIndeterminate"
+          v-model="checkAll"
+          @change="handleCheckAllChange"
+          >全选</el-checkbox
+        >
+        <el-checkbox-group
+          v-model="checkedCities"
+          @change="handleCheckedCitiesChange"
+        >
+          <el-checkbox
+            v-for="item in villageList"
+            :label="item.id"
+            :key="item.id"
+            >{{ item.name }}</el-checkbox
+          >
+        </el-checkbox-group>
+      </div>
+      <el-form-item label="是否启用:">
+        <el-radio
+          v-model="ruleForm.isEnabled"
+          :label="1"
+          :disabled="ruleForm.isAdmin === 1"
+          >是</el-radio
+        >
+        <el-radio
+          v-model="ruleForm.isEnabled"
+          :label="0"
+          :disabled="ruleForm.isAdmin === 1"
+          >否</el-radio
+        >
+      </el-form-item>
+      <div class="hint">* 默认密码:123456</div>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="btnX">取 消</el-button>
+      <el-button type="primary" @click="btnOk">确 定</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { userSave, userAuths } from '@/apis/system'
+import { villageList } from '@/apis/tab1'
+
+export default {
+  name: 'tab2Dialog',
+  props: {
+    dialogVisible: {
+      type: Boolean,
+      default: false
+    }
+  },
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      // 村落数据
+      villageList: [],
+      ruleForm: {
+        id: null,
+        isEnabled: 1,
+        phone: '',
+        sex: 0,
+        userName: ''
+      },
+      rules: {
+        userName: [{ required: true, message: '不能为空', trigger: 'blur' }],
+        phone: [
+          { required: true, message: '不能为空', trigger: 'blur' },
+          {
+            pattern: /^1[3-9]\d{9}$/,
+            message: '请输入合法手机号',
+            trigger: 'blur'
+          }
+        ]
+      },
+      // 关于授权的数据
+      checkAll: false,
+      checkedCities: [],
+      isIndeterminate: false
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    // 关于授权的数据
+    handleCheckAllChange (val) {
+      this.checkedCities = val ? this.villageList.map((v) => v.id) : []
+      this.isIndeterminate = false
+    },
+    handleCheckedCitiesChange (value) {
+      const checkedCount = value.length
+      this.checkAll = checkedCount === this.villageList.length
+      this.isIndeterminate =
+        checkedCount > 0 && checkedCount < this.villageList.length
+    },
+    // 父组件点击编辑的时候调用
+    async setRuleForm (item) {
+      this.ruleForm = { ...item }
+      if (item.projectIds !== '') {
+        this.checkedCities = item.projectIds.split(',')
+        if (this.checkedCities.length >= 12) {
+          this.checkAll = true
+          this.isIndeterminate = false
+        } else this.isIndeterminate = true
+        this.checkedCities = this.checkedCities.map(v => Number(v))
+      } else {
+        this.checkedCities = []
+        this.checkAll = this.isIndeterminate = false
+      }
+    },
+    // 点击取消
+    btnX () {
+      this.$refs.ruleForm.resetFields()
+      this.ruleForm = {
+        id: null,
+        isEnabled: 1,
+        phone: '',
+        sex: 0,
+        userName: ''
+      }
+      this.$emit('update:dialogVisible', false)
+    },
+    async btnOk () {
+      try {
+        await this.$refs.ruleForm.validate()
+        const res = await userSave(this.ruleForm)
+        if (res.code === 0) {
+          if (this.ruleForm.id) {
+            const res2 = await userAuths(
+              this.ruleForm.id,
+              this.checkedCities.join(',')
+            )
+            if (res2.code === 0) {
+              this.$emit('clickSon')
+              this.btnX()
+              this.$message.success('操作成功')
+            } else this.$message.warning(res2.msg)
+          } else {
+            this.$emit('clickSon')
+            this.btnX()
+            this.$message.success('操作成功')
+          }
+        } else this.$message.warning(res.msg)
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  async created () {
+    const res = await villageList()
+    this.villageList = res.data
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {},
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.limits {
+  padding-left: 60px;
+  margin-bottom: 15px;
+  /deep/.el-checkbox-group .el-checkbox {
+    width: 80px;
+    margin-top: 10px;
+  }
+  /deep/.el-checkbox-group {
+    padding-left: 46px;
+  }
+}
+.hint {
+  color: red;
+  margin-left: 100px;
+  margin-top: -15px;
+}
+</style>

+ 187 - 10
houtai/src/views/tab2/index.vue

@@ -2,23 +2,110 @@
   <div class="tab2">
     <div class="insideTop">
       用户管理
+      <div class="addBtn">
+        <el-button type="primary" @click="dialogVisible = true">新增</el-button>
+      </div>
     </div>
     <div class="obstruct"></div>
     <div class="conten">
+      <div class="top">
+        <el-input
+          style="width: 300px"
+          v-model="pageData.searchKey"
+          placeholder="请输入用户名"
+        ></el-input>
+        &emsp;&emsp;
+        <el-button type="primary" @click="userList(pageData)">查 询</el-button>
+        <el-button @click="reset">重 置</el-button>
+      </div>
+      <div class="table">
+        <el-table :data="tableData" style="width: 100%" height="550px">
+          <el-table-column label="编号" width="80">
+            <template slot-scope="scope">
+              {{
+                scope.$index + (pageData.pageNum - 1) * pageData.pageSize + 1
+              }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="userName" label="账号"> </el-table-column>
+          <el-table-column prop="phone" label="联系电话"> </el-table-column>
+          <el-table-column prop="createTime" label="新建时间">
+          </el-table-column>
 
+          <el-table-column label="启用状态">
+            <template #default="{ row }">
+              <el-switch
+                :disabled="row.isAdmin === 1"
+                @change="changeSta($event, row.id)"
+                v-model="row.isEnabled"
+                active-color="#a30014"
+                inactive-color="#ccc"
+                :active-value="1"
+                :inactive-value="0"
+              >
+              </el-switch>
+              <!-- {{ row.isEnabled ? "启用" : "禁用" }} -->
+            </template>
+          </el-table-column>
+          <el-table-column label="操作">
+            <template #default="{ row }">
+              <el-button type="text" @click="editUser(row)">修改</el-button>
+              <el-button
+                v-if="row.isAdmin !== 1"
+                type="text"
+                @click="resetPass(row.id)"
+                >重置密码</el-button
+              >
+              <el-button
+                v-if="row.isAdmin !== 1"
+                type="text"
+                style="color: #f56c6c"
+                @click="userDel(row.id)"
+                >删除</el-button
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <!-- 分页器 -->
+      <div class="paging">
+        <span>共 {{ total }} 条</span>
+        <el-pagination
+          :current-page="pageData.pageNum"
+          @current-change="currentChange"
+          @size-change="sizeChange"
+          layout="sizes,prev,pager,next,jumper"
+          :total="total"
+        >
+        </el-pagination>
+      </div>
     </div>
-
+    <!-- 点击新增和编辑出现的弹窗 -->
+    <Dialog
+      ref="projectRef"
+      :dialogVisible.sync="dialogVisible"
+      @clickSon="userList(pageData)"
+    />
   </div>
 </template>
 
 <script>
+import Dialog from './Dialog'
+import { userList, userDel, editStatus, userResetPass } from '@/apis/system'
 export default {
   name: 'tab2',
-  components: {},
+  components: { Dialog },
   data () {
     // 这里存放数据
     return {
-
+      dialogVisible: false,
+      total: 0,
+      pageData: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: ''
+      },
+      tableData: []
     }
   },
   // 监听属性 类似于data概念
@@ -27,16 +114,80 @@ export default {
   watch: {},
   // 方法集合
   methods: {
-
+    // 点击编辑,调用子组件弹窗的方法
+    editUser (item) {
+      this.$refs.projectRef.setRuleForm(item)
+      this.dialogVisible = true
+    },
+    // 点击重置密码
+    async resetPass (id) {
+      this.$confirm('确定重置吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(async () => {
+          const res = await userResetPass(id)
+          if (res.code === 0) {
+            this.$message.success('重置成功!')
+          } else this.$message.warning(res.msg)
+        })
+        .catch(() => {
+          this.$message.info('已取消重置')
+        })
+    },
+    // 启用和停用状态
+    async changeSta (val, id) {
+      await editStatus(id, val)
+      this.$message.success('操作成功!')
+    },
+    // 点击删除
+    userDel (id) {
+      this.$confirm('确定删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(async () => {
+          const res = await userDel(id)
+          if (res.code === 0) {
+            this.$message.success('删除成功!')
+            this.userList(this.pageData)
+          } else this.$message.warning(res.msg)
+        })
+        .catch(() => {
+          this.$message.info('已取消删除')
+        })
+    },
+    // 点击重置
+    reset () {
+      this.pageData.pageNum = 1
+      this.pageData.searchKey = ''
+      this.userList(this.pageData)
+    },
+    // 封装一个获取表列表的方法
+    async userList (data) {
+      const res = await userList(data)
+      this.total = res.data.total
+      this.tableData = res.data.records
+    },
+    // 分页器
+    currentChange (val) {
+      this.pageData.pageNum = val
+      this.userList(this.pageData)
+    },
+    sizeChange (val) {
+      this.pageData.pageNum = 1
+      this.pageData.pageSize = val
+      this.userList(this.pageData)
+    }
   },
   // 生命周期 - 创建完成(可以访问当前this实例)
   created () {
-
+    this.userList(this.pageData)
   },
   // 生命周期 - 挂载完成(可以访问DOM元素)
-  mounted () {
-
-  },
+  mounted () {},
   beforeCreate () {}, // 生命周期 - 创建之前
   beforeMount () {}, // 生命周期 - 挂载之前
   beforeUpdate () {}, // 生命周期 - 更新之前
@@ -47,6 +198,32 @@ export default {
 }
 </script>
 <style lang='less' scoped>
-//@import url(); 引入公共css类
-
+.tab2 {
+  width: 100%;
+  height: 100%;
+  .insideTop {
+    position: relative;
+    .addBtn {
+      position: absolute;
+      top: -10px;
+      right: 20px;
+    }
+  }
+  .conten {
+    width: 100%;
+    height: calc(100% - 52px);
+    position: relative;
+    padding: 20px;
+    .table {
+      margin-top: 20px;
+    }
+    .paging {
+      display: flex;
+      align-items: center;
+      position: absolute;
+      bottom: 30px;
+      right: 20px;
+    }
+  }
+}
 </style>

+ 265 - 12
houtai/src/views/tab3/index.vue

@@ -1,24 +1,81 @@
 <template>
   <div class="tab3">
     <div class="insideTop">
-      数据统计
+      数据统计(等待开发)
+      <div class="addBtn">
+        <el-button type="primary">导出</el-button>
+      </div>
     </div>
     <div class="obstruct"></div>
     <div class="conten">
-
+      <!-- 上面盒子 -->
+      <div class="top">
+        <div class="topLft">
+          <div class="row" v-for="(item, index) in data1" :key="index">
+            <div class="inco">
+              <span class="tit">{{ item.name }}</span>
+              <p>{{ item.num }}</p>
+            </div>
+            <div class="img">
+              <img :src="require(`@/assets/img/${item.img}`)" alt="" />
+            </div>
+          </div>
+        </div>
+        <div class="topRight">
+          <span class="tit">各村落访问量</span>
+          <div id="echaBox"></div>
+        </div>
+      </div>
+      <!-- 下面盒子 -->
+      <div class="bottom">
+        <span class="tit">VR景点打卡排行</span>
+        <div class="botRowBox">
+          <div class="botRow" v-for="i in 10" :key="i">
+            <div class="botLeft">
+              <h3>NO.1</h3>
+              <p>打卡数:321</p>
+              <p>宇宙卢工祠堂</p>
+            </div>
+            <div class="botRight">
+              <img src="../../assets/img/bg.jpg" alt="" />
+            </div>
+          </div>
+        </div>
+      </div>
     </div>
-
   </div>
 </template>
 
 <script>
+import * as echarts from 'echarts/core'
+import {
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  LegendComponent
+} from 'echarts/components'
+import { BarChart } from 'echarts/charts'
+import { CanvasRenderer } from 'echarts/renderers'
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  GridComponent,
+  LegendComponent,
+  BarChart,
+  CanvasRenderer
+])
 export default {
   name: 'tab3',
   components: {},
   data () {
     // 这里存放数据
     return {
-
+      data1: [
+        { name: '累计访问量', num: '103,354', img: '1.png' },
+        { name: '今日访问量', num: '3,354', img: '2.png' },
+        { name: '累计点赞数', num: '3,354', img: '3.png' },
+        { name: '页面分享数', num: '3,354', img: '4.png' }
+      ]
     }
   },
   // 监听属性 类似于data概念
@@ -26,16 +83,71 @@ export default {
   // 监控data中的数据变化
   watch: {},
   // 方法集合
-  methods: {
-
-  },
+  methods: {},
   // 生命周期 - 创建完成(可以访问当前this实例)
-  created () {
-
-  },
+  created () {},
   // 生命周期 - 挂载完成(可以访问DOM元素)
   mounted () {
+    var chartDom = document.getElementById('echaBox')
+    var myChart = echarts.init(chartDom)
+    var option
+    option = {
+      color: ['#02a7f0'],
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        }
+      },
+      grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '3%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'value',
+        boundaryGap: [0, 0.01],
+        show: false
+      },
+      yAxis: {
+        type: 'category',
+        data: [
+          '东宁村',
+          '良溪村',
+          '卢边村',
+          '田心村',
+          '仓前村',
+          '霄南村',
+          '歇马村',
+          '自力村',
+          '马降龙村',
+          '浮石村',
+          '浮月村',
+          '横江村'
+        ],
+        axisTick: {
+          // y轴刻度线
+          show: false
+        },
+        axisLine: {
+          // y轴
+          show: false
+        }
+      },
+      series: [
+        {
+          name: '',
+          type: 'bar',
+          data: [
+            3353, 3353, 3353, 3353, 3353, 3353, 3000, 2899, 3330, 2228, 4455,
+            5555
+          ]
+        }
+      ]
+    }
 
+    option && myChart.setOption(option)
   },
   beforeCreate () {}, // 生命周期 - 创建之前
   beforeMount () {}, // 生命周期 - 挂载之前
@@ -47,6 +159,147 @@ export default {
 }
 </script>
 <style lang='less' scoped>
-//@import url(); 引入公共css类
-
+.botRowBox::-webkit-scrollbar {
+  /*滚动条整体样式*/
+  width: 10px; /*高宽分别对应横竖滚动条的尺寸*/
+  height: 1px;
+}
+.botRowBox::-webkit-scrollbar-thumb {
+  /*滚动条里面小方块*/
+  border-radius: 10px;
+  -webkit-box-shadow: inset 0 0 5px transparent;
+  background: #aaaaaa;
+}
+.botRowBox::-webkit-scrollbar-track {
+  /*滚动条里面轨道*/
+  -webkit-box-shadow: inset 0 0 5px transparent;
+  border-radius: 10px;
+  background: transparent;
+}
+.tab3 {
+  width: 100%;
+  height: 100%;
+  .insideTop {
+    position: relative;
+    .addBtn {
+      position: absolute;
+      top: -10px;
+      right: 20px;
+    }
+  }
+  .conten {
+    width: 100%;
+    height: calc(100% - 52px);
+    background-color: #f2ecde;
+    .tit {
+      font-weight: 700;
+      font-size: 18px;
+      color: #7f7f7f;
+    }
+    .top {
+      display: flex;
+      width: 100%;
+      height: 428px;
+      .topLft {
+        width: 50%;
+        height: 100%;
+        padding-right: 20px;
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        align-content: space-between;
+        .row {
+          width: 49%;
+          height: 48%;
+          background-color: #fff;
+          display: flex;
+          .inco {
+            padding: 0px 10px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            width: calc(100% - 120px);
+            height: 100%;
+            & > p {
+              margin-top: 15px;
+              font-size: 22px;
+              font-weight: 700;
+            }
+          }
+          .img {
+            width: 120px;
+            height: 100%;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            & > img {
+              width: 70px;
+              height: 70px;
+            }
+          }
+        }
+      }
+      .topRight {
+        width: 50%;
+        height: 100%;
+        background-color: #fff;
+        position: relative;
+        padding: 12px 0 0 20px;
+        #echaBox {
+          position: absolute;
+          top: 0;
+          left: 0;
+          width: 100%;
+          height: 100%;
+        }
+      }
+    }
+    .bottom {
+      background-color: #fff;
+      padding: 20px 0 0 20px;
+      margin-top: 12px;
+      width: 100%;
+      height: calc(100% - 440px);
+      .botRowBox {
+        width: 100%;
+        height: calc(100% - 60px);
+        overflow-y: auto;
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        padding-right: 20px;
+        margin-top: 20px;
+        .botRow {
+          margin-bottom: 20px;
+          width: 30%;
+          height: 200px;
+          display: flex;
+          .botLeft {
+            flex: 1;
+            padding: 15px 10px 0 0;
+            & > h3 {
+              font-size: 24px;
+              text-align: center;
+            }
+            & > p {
+              text-align: center;
+              margin-top: 30px;
+              cursor: pointer;
+            }
+          }
+          .botRight {
+            width: 300px;
+            height: 200px;
+            & > img {
+              width: 100%;
+              height: 100%;
+              object-fit: cover;
+            }
+          }
+        }
+      }
+    }
+  }
+}
 </style>

+ 116 - 11
houtai/src/views/tab4/index.vue

@@ -4,39 +4,106 @@
       操作日志
     </div>
     <div class="obstruct"></div>
+    <!-- 主要内容 -->
     <div class="conten">
-
+      <div class="search">
+        <el-input
+          v-model="formData.searchKey"
+          placeholder="请输入关键字"
+          style="width: 240px"
+        ></el-input>
+        <!-- 右侧按钮 -->
+        <div class="search_btn">
+          <el-button type="primary" @click="searchBtn">查 询</el-button>
+        </div>
+      </div>
+      <!-- 表格 -->
+      <div class="table">
+        <el-table :data="tableData" style="width: 100%" height="529px">
+          <el-table-column label="序号" width="80">
+            <template slot-scope="scope">
+              {{
+                scope.$index + (formData.pageNum - 1) * formData.pageSize + 1
+              }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="userName" label="账号"> </el-table-column>
+          <el-table-column prop="type" label="操作模块"> </el-table-column>
+          <el-table-column prop="description" label="操作事件"></el-table-column>
+          <el-table-column prop="createTime" label="操作时间"></el-table-column>
+        </el-table>
+      </div>
+    </div>
+    <!-- 分页 -->
+    <div class="paging">
+      <span>共 {{ total }} 条</span>
+      <el-pagination
+        layout="sizes,prev, pager, next,jumper"
+        :total="total"
+        :current-page="formData.pageNum"
+        @current-change="currentChange"
+        @size-change="sizeChange"
+      >
+      </el-pagination>
     </div>
-
   </div>
 </template>
 
 <script>
+import { logList } from '@/apis/system'
 export default {
   name: 'tab4',
   components: {},
   data () {
     // 这里存放数据
     return {
-
+      total: 0,
+      formData: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: ''
+      },
+      tableData: []
     }
   },
   // 监听属性 类似于data概念
   computed: {},
   // 监控data中的数据变化
-  watch: {},
+  watch: {
+  },
   // 方法集合
   methods: {
-
+    // 点击查询
+    searchBtn () {
+      this.formData.pageNum = 1
+      this.logList(this.formData)
+    },
+    // 封装获取列表的函数
+    async logList (data) {
+      const res = await logList(data)
+      this.total = res.data.total
+      this.tableData = res.data.records
+      // console.log(998, res)
+    },
+    // 分页器方法
+    currentChange (val) {
+      // console.log('当前页改变了', val)
+      this.formData.pageNum = val
+      this.logList(this.formData)
+    },
+    sizeChange (val) {
+      // console.log('条数改变了', val)
+      this.formData.pageNum = 1
+      this.formData.pageSize = val
+      this.logList(this.formData)
+    }
   },
   // 生命周期 - 创建完成(可以访问当前this实例)
   created () {
-
+    this.logList(this.formData)
   },
   // 生命周期 - 挂载完成(可以访问DOM元素)
-  mounted () {
-
-  },
+  mounted () {},
   beforeCreate () {}, // 生命周期 - 创建之前
   beforeMount () {}, // 生命周期 - 挂载之前
   beforeUpdate () {}, // 生命周期 - 更新之前
@@ -47,6 +114,44 @@ export default {
 }
 </script>
 <style lang='less' scoped>
-//@import url(); 引入公共css类
-
+.tab4 {
+  height: 100%;
+  .insideTop .add{
+    right: 55px;
+  }
+  .conten {
+    position: relative;
+    padding: 15px 30px 0;
+    height: calc(100% - 52px);
+    .classify {
+      text-align: center;
+      width: 40px;
+      padding-bottom: 10px;
+      color: #b9412e;
+      border-bottom: 2px solid #b9412e;
+    }
+    .search {
+      display: flex;
+      margin-bottom: 20px;
+      position: relative;
+      height: 40px;
+      .search_k {
+        margin-left: 30px;
+      }
+      .search_btn {
+        margin-left: 30px;
+        display: flex;
+        justify-content: space-between;
+        width: 100px;
+      }
+    }
+  }
+    .paging {
+      display: flex;
+      align-items: center;
+      position: absolute;
+      bottom: 30px;
+      right: 20px;
+    }
+}
 </style>