shaogen1995 2 anos atrás
pai
commit
1df2e5ef24

+ 5 - 0
houtai/.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 23 - 0
houtai/.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+/dist
+edit-backstage
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?

+ 24 - 0
houtai/README.md

@@ -0,0 +1,24 @@
+# houtai
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+### Customize configuration
+See [Configuration Reference](https://cli.vuejs.org/config/).

+ 5 - 0
houtai/babel.config.js

@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/cli-plugin-babel/preset'
+  ]
+}

Diferenças do arquivo suprimidas por serem muito extensas
+ 30013 - 0
houtai/package-lock.json


+ 71 - 0
houtai/package.json

@@ -0,0 +1,71 @@
+{
+  "name": "houtai",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "serve": "vue-cli-service serve",
+    "build": "vue-cli-service build",
+    "lint": "vue-cli-service lint"
+  },
+  "dependencies": {
+    "axios": "^0.24.0",
+    "Base64": "^1.1.0",
+    "core-js": "^3.6.5",
+    "dayjs": "^1.11.5",
+    "echarts": "^5.4.0",
+    "element-ui": "^2.15.6",
+    "js-base64": "^3.7.2",
+    "moment": "^2.29.1",
+    "vant": "^2.12.45",
+    "vue": "^2.6.11",
+    "vue-json-excel": "^0.3.0",
+    "vue-router": "^3.2.0",
+    "wangeditor": "^4.7.11"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "~4.5.0",
+    "@vue/cli-plugin-eslint": "~4.5.0",
+    "@vue/cli-plugin-router": "~4.5.0",
+    "@vue/cli-service": "~4.5.0",
+    "@vue/eslint-config-standard": "^5.1.2",
+    "babel-eslint": "^10.1.0",
+    "eslint": "^6.7.2",
+    "eslint-plugin-import": "^2.20.2",
+    "eslint-plugin-node": "^11.1.0",
+    "eslint-plugin-promise": "^4.2.1",
+    "eslint-plugin-standard": "^4.0.0",
+    "eslint-plugin-vue": "^6.2.2",
+    "less": "^3.0.4",
+    "less-loader": "^5.0.0",
+    "lint-staged": "^9.5.0",
+    "vue-template-compiler": "^2.6.11"
+  },
+  "eslintConfig": {
+    "root": true,
+    "env": {
+      "node": true
+    },
+    "extends": [
+      "plugin:vue/essential",
+      "@vue/standard"
+    ],
+    "parserOptions": {
+      "parser": "babel-eslint"
+    },
+    "rules": {}
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions",
+    "not dead"
+  ],
+  "gitHooks": {
+    "pre-commit": "lint-staged"
+  },
+  "lint-staged": {
+    "*.{js,jsx,vue}": [
+      "vue-cli-service lint",
+      "git add"
+    ]
+  }
+}

BIN
houtai/public/favicon.ico


+ 17 - 0
houtai/public/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title>河南博物院-文物展示平台后台</title>
+  </head>
+  <body>
+    <noscript>
+      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+    </noscript>
+    <div id="app"></div>
+    <!-- built files will be auto injected -->
+  </body>
+</html>

+ 9 - 0
houtai/src/App.vue

@@ -0,0 +1,9 @@
+<template>
+  <div id="app">
+    <Router-view/>
+  </div>
+</template>
+
+<style lang="less">
+
+</style>

+ 26 - 0
houtai/src/apis/login.js

@@ -0,0 +1,26 @@
+import axios from '../utils/request'
+// 用户登录接口
+export const userLogin = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/admin/login',
+    data
+  })
+}
+// 修改密码
+export const updatePwd = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/sys/user/updatePwd',
+    data
+  })
+}
+
+// 获取场景管理列表
+export const sceneList = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/cms/scene/list',
+    data
+  })
+}

+ 62 - 0
houtai/src/apis/tab2.js

@@ -0,0 +1,62 @@
+import axios from '../utils/request'
+// 获取列表
+export const goodsList = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/cms/goods/list',
+    data
+  })
+}
+// 点击删除
+export const goodsRemove = (id) => {
+  return axios({
+    url: `/api/cms/goods/remove/${id}`
+  })
+}
+// 新增、编辑
+export const goodsSave = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/cms/goods/save',
+    data
+  })
+}
+// 是否显示
+export const goodsDisplay = (id, display) => {
+  return axios({
+    url: `/api/cms/goods/display/${id}/${display}`
+  })
+}
+
+// 通过id获取详情
+export const goodsDetail = (id) => {
+  return axios({
+    url: `/api/cms/goods/detail/${id}`
+  })
+}
+
+// ------------------------------操作日志列表
+export const logList = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/sys/log/list',
+    data
+  })
+}
+
+// ------------------------------操作日志列表
+export const dictGetTree = (data) => {
+  return axios({
+    method: 'post',
+    url: '/api/cms/dict/getTree',
+    data
+  })
+}
+
+// ------------------------------统计
+export const goodsReport = (data) => {
+  return axios({
+    url: '/api/cms/goods/report',
+    data
+  })
+}

+ 164 - 0
houtai/src/assets/css/base.css

@@ -0,0 +1,164 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+body {
+  background-color: transparent;
+}
+ul li {
+  list-style: none;
+}
+a {
+  text-decoration:none ;
+  color: #b9412e;
+}
+.insideTop {
+  position: relative;
+  padding-left: 30px;
+  font-weight: 700;
+  height: 40px;
+  margin-bottom: 12px;
+}
+.insideTop .add{
+  position: absolute;
+  top: -10px;
+  right: 30px;
+}
+.obstruct{
+  position: absolute;
+  left: 0px;
+  top: 60px;
+  width: 100%;
+  background-color: #f2ecde;
+  height: 12px;
+}
+.biaoshi{
+  position: relative;
+  font-style:normal
+}
+.biaoshi::before{
+  position: absolute;
+  top: 0px;
+  left: -92px;
+  content: '*';
+  color: #F56C6C;
+}
+
+
+.cell{
+  text-align: center !important;
+}
+.table .el-input__inner{
+  text-align: center;
+}
+.el-input__inner{
+  padding-right: 45px;
+}
+input::-webkit-outer-spin-button,
+input::-webkit-inner-spin-button {
+-webkit-appearance: none;
+}
+input[type="number"] {
+-moz-appearance: textfield;
+}
+.el-dialog{
+  min-width: 652px;
+}
+.el-upload__tip{
+  font-size: 14px;
+}
+
+.el-table--fit{
+  border-top: 1px solid #EBEEF5;
+}
+.table_img{
+  width: 100px;
+  height: 80px;
+  object-fit: cover;
+  border: 1px solid #ccc;
+}
+.table_name{
+  cursor: pointer;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;    
+}
+
+.upHint{
+  font-size: 12px;
+  color: #ccc;
+  height: 20px;
+  margin-top: -5px;
+}
+.el-radio__input.is-checked+.el-radio__label{
+  color: #964134;
+}
+.el-radio__input.is-checked .el-radio__inner{
+  border-color: #964134;
+  background: #964134;
+}
+.el-image__preview{
+  border: 5px solid #cccccc;
+  object-fit: cover;
+}
+.el-upload--picture-card:hover, .el-upload:focus{
+  color: #b9412e;
+}
+.w-e-menu {
+	z-index: 2 !important;
+}
+.w-e-text-container {
+	z-index: 1 !important;
+}
+.w-e-toolbar {
+	z-index: 10 !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(18) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(19) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(13) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(14) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(16) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(20) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(21) {
+	display: none !important;
+}
+.w-e-toolbar .w-e-menu:nth-of-type(26) {
+	display: none !important;
+}
+.avatar-uploader .el-upload-list__item-name{
+  display: none;
+}
+.avatar-uploader .el-upload-list__item.is-success .el-upload-list__item-status-label{
+  display: none;
+}
+.el-upload-list__item .el-progress{
+  width: 500px;
+  position: static;
+  margin-bottom: 15px;
+}
+.el-upload-list__item{
+  width: 500px;
+}
+.el-month-table td.end-date .cell, .el-month-table td.start-date .cell{
+  background-color: #b9412e;
+}
+
+.el-month-table td.today .cell{
+  color: #b9412e;
+}
+.el-message-box__title{
+  color: #b9412e;
+}

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


BIN
houtai/src/assets/img/bg.jpg


BIN
houtai/src/assets/imgAdd/comment.png


BIN
houtai/src/assets/imgAdd/like.png


BIN
houtai/src/assets/imgAdd/likeAc.png


BIN
houtai/src/assets/imgAdd/mesBac.png


BIN
houtai/src/assets/imgAdd/touxiang.png


+ 24 - 0
houtai/src/main.js

@@ -0,0 +1,24 @@
+import Vue from 'vue'
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+import App from './App.vue'
+import router from './router'
+// 表格导出
+import JsonExcel from 'vue-json-excel'
+import './assets/css/base.css'
+Vue.component('downloadExcel', JsonExcel)
+
+Vue.config.productionTip = false
+const imgErr = {
+  data () {
+    return {
+      defaultImg: 'this.src="' + require('./assets/img/IMGerror.png') + '"'
+    }
+  }
+}
+Vue.mixin(imgErr)
+Vue.use(ElementUI)
+new Vue({
+  router,
+  render: h => h(App)
+}).$mount('#app')

+ 66 - 0
houtai/src/router/index.js

@@ -0,0 +1,66 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+import { Message } from 'element-ui'
+Vue.use(VueRouter)
+
+const routes = [
+  {
+    path: '/',
+    name: 'login',
+    component: () => import('../views/login.vue')
+  },
+  {
+    path: '/layout',
+    name: 'layout',
+    component: () => import('../views/layout/index.vue'),
+    children: [
+      {
+        path: 'tab2',
+        name: 'tab2',
+        meta: { myInd: 2 },
+        component: () => import('../views/tab2/index.vue')
+      },
+      {
+        path: 'tab2Add',
+        name: 'tab2Add',
+        meta: { myInd: 2 },
+        component: () => import('../views/tab2/add.vue')
+      },
+      {
+        path: 'tab3',
+        name: 'tab3',
+        meta: { myInd: 3 },
+        component: () => import('../views/tab3/index.vue')
+      },
+      {
+        path: 'tab1',
+        name: 'tab1',
+        meta: { myInd: 1 },
+        component: () => import('../views/tab1/index.vue')
+      }
+
+    ]
+  }
+]
+
+const router = new VueRouter({
+  // mode: 'history',
+  base: process.env.BASE_URL,
+  routes
+})
+
+router.beforeEach((to, from, next) => {
+  // 如果是去登录页,不需要验证,直接下一步
+  if (to.name === 'login') next()
+  // 否则要有token值才能下一步,不然就返回登录页
+  else {
+    const token = localStorage.getItem('HNBWY_token')
+    if (token) next()
+    else {
+      Message.warning('登录失效,请重新登录')
+      next({ name: 'login' })
+    }
+  }
+})
+
+export default router

+ 106 - 0
houtai/src/utils/pass.js

@@ -0,0 +1,106 @@
+/* eslint-disable */
+function NoToChinese (num) {
+  num = String(num)
+  var chnNumChar = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
+  if (num == 0) {
+    return chnNumChar[0]
+  }
+  let tmp = ''
+  for (let i = 0; i < num.length; i++) {
+    const ele = num.charAt(i)
+    tmp += chnNumChar[ele]
+  }
+
+  return tmp
+}
+
+function randomWord (randomFlag, min, max) {
+  let str = ''
+  let range = min
+  const arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
+  // 随机产生
+  if (randomFlag) {
+    range = Math.round(Math.random() * (max - min)) + min
+  }
+  for (var i = 0; i < range; i++) {
+    const pos = Math.round(Math.random() * (arr.length - 1))
+    str += arr[pos]
+  }
+  return str
+}
+
+module.exports = {
+  formatDate: function (time) {
+    var weekArr = ['日', '一', '二', '三', '四', '五', '六']
+    var date = new Date(time)
+    var year = date.getFullYear()
+    var month = date.getMonth() + 1
+    var day = date.getDate()
+    var week = '星期' + weekArr[date.getDay()]
+    if (window.innerWidth < 1700) {
+      return (
+        year +
+        '年' +
+        (String(month).length > 1 ? month : '0' + month) +
+        '月' +
+        (String(day).length > 1 ? day : '0' + day) +
+        '日' +
+        '<br/>' +
+        week
+      )
+    }
+    return (
+      year +
+      '年' +
+      (String(month).length > 1 ? month : '0' + month) +
+      '月' +
+      (String(day).length > 1 ? day : '0' + day) +
+      '日' +
+      ' ' +
+      week
+    )
+  },
+  smoothscrollpos: function (domName) {
+    if (domName == '/') {
+      return window.scrollTo(0, 0)
+    }
+    const smoothscroll = () => {
+      const dom = document.getElementById(domName)
+      // window.scrollTo({
+      //   top:dom.offsetTop - 100,
+      //   left:0,
+      //   behavior: "smooth"
+      // })
+      dom && window.scrollTo(0, dom.offsetTop - 120)
+    }
+    smoothscroll()
+  },
+
+  formatTime: function (time, fan = false) {
+    let t1 = time.split(' ')[0].split('-')
+    if (fan) {
+      t1 = t1.map((item) => {
+        const t = NoToChinese(item)
+        return t
+      })
+    }
+    return t1
+  },
+  encodeStr: function (str, strv = '') {
+    const NUM = 2
+    const front = randomWord(false, 8)
+    const middle = randomWord(false, 8)
+    const end = randomWord(false, 8)
+
+    const str1 = str.substring(0, NUM)
+    const str2 = str.substring(NUM)
+
+    if (strv) {
+      const strv1 = strv.substring(0, NUM)
+      const strv2 = strv.substring(NUM)
+      return [front + str2 + middle + str1 + end, front + strv2 + middle + strv1 + end]
+    }
+
+    return front + str2 + middle + str1 + end
+  }
+}

+ 37 - 0
houtai/src/utils/request.js

@@ -0,0 +1,37 @@
+import axios from 'axios'
+const service = axios.create({
+  // baseURL: 'http://192.168.20.55:8032', // 本地调试
+  baseURL: process.env.NODE_ENV === 'development' ? 'https://hnbwg.4dage.com' : '',
+  timeout: 5000
+})
+// 请求拦截器
+service.interceptors.request.use(function (config) {
+  // console.log('触发拦截器')
+  // 在发送请求之前做些什么:看看有没有token,如果有通过请求头的方式传递token
+  const token = localStorage.getItem('HNBWY_token')
+  if (token) { // 判断是否有token,有,则
+    // config.headers['Authorization'] = token
+    config.headers.token = token
+  }
+
+  return config
+}, function (error) {
+  // 对请求错误做些什么
+  return Promise.reject(error)
+})
+
+// 添加响应拦截器
+service.interceptors.response.use(function (response) {
+  // console.log('触发相应拦截器', response)
+  // 对响应数据做点什么--response就是发送每个请求的返回值
+  if (response.data.code === 5001 || response.data.code === 5002) {
+    // Toast.fail('未登录,请先登录')
+    localStorage.removeItem('HNBWY_token')
+  }
+  return response.data
+}, function (error) {
+  // 对响应错误做点什么
+  return Promise.reject(error)
+})
+
+export default service

+ 363 - 0
houtai/src/views/layout/index.vue

@@ -0,0 +1,363 @@
+<template>
+  <div class="layout">
+    <div class="top">
+      <p>河南博物院文物展示平台后台</p>
+      <div class="top_right" @mouseenter="cut = true" @mouseleave="cut = false">
+        <div class="user">
+          <span>{{ userName }}</span>
+          <!-- 下箭头 -->
+          <div class="pull_down" v-if="cut"></div>
+          <div class="pull_up" v-else></div>
+        </div>
+        <!-- 点击箭头出来的ul -->
+        <ul class="user_handle" v-show="cut">
+          <li @click="isShow = true">修改密码</li>
+          <li @click="outLogin">退出登录</li>
+        </ul>
+      </div>
+    </div>
+    <div class="con">
+      <div class="left">
+        <div
+          class="biaoji el-icon-message"
+          :class="{ biaojiAc: $route.meta.myInd === 2 }"
+        >
+          内容管理
+        </div>
+        <ul>
+          <li
+            v-for="item in tab1"
+            :key="item.id"
+            :class="{ active: $route.meta.myInd === item.id }"
+            @click="push(item.url)"
+          >
+            {{ item.name }}
+          </li>
+        </ul>
+
+        <div
+          class="biaoji el-icon-s-data"
+          :class="{ biaojiAc: $route.meta.myInd === 1 }"
+        >
+          统计管理
+        </div>
+        <ul>
+          <li
+            v-for="item in tab3"
+            :key="item.id"
+            :class="{ active: $route.meta.myInd === item.id }"
+            @click="push(item.url)"
+          >
+            {{ item.name }}
+          </li>
+        </ul>
+
+        <div
+          class="biaoji el-icon-setting"
+          :class="{ biaojiAc: $route.meta.myInd === 3 }"
+        >
+          系统管理
+        </div>
+        <ul>
+          <li
+            v-for="item in tab2"
+            :key="item.id"
+            :class="{ active: $route.meta.myInd === item.id }"
+            @click="push(item.url)"
+          >
+            {{ item.name }}
+          </li>
+        </ul>
+      </div>
+      <!-- 右侧内容 -->
+      <div class="right" @click="cut = false">
+        <Router-view />
+      </div>
+    </div>
+    <!-- 点击修改密码出现弹窗 -->
+    <el-dialog title="修改密码" :visible.sync="isShow" @close="btnX()">
+      <el-form :model="form" label-width="100px" :rules="rules" ref="ruleForm">
+        <el-form-item label="旧密码:" prop="oldPassword">
+          <el-input
+            v-model="form.oldPassword"
+            placeholder="请输入"
+            show-password
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="新密码:" prop="newPassword">
+          <el-input
+            v-model="form.newPassword"
+            placeholder="请输入"
+            show-password
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="确定新密码:" prop="checkPass">
+          <el-input
+            v-model="form.checkPass"
+            placeholder="请输入"
+            show-password
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="btnX">取 消</el-button>
+        <el-button type="primary" @click="btnOk">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { encodeStr } from '../../utils/pass'
+import { Base64 } from 'js-base64'
+import { updatePwd } from '@/apis/login'
+export default {
+  name: 'layout',
+  components: {},
+  data () {
+    // 这里存放数据
+    const validatePass2 = (rule, value, callback) => {
+      if (value !== this.form.newPassword) {
+        callback(new Error('两次输入密码不一致!'))
+      } else {
+        callback()
+      }
+    }
+    return {
+      // 修改密码
+      form: {
+        oldPassword: '',
+        newPassword: '',
+        checkPass: ''
+      },
+      rules: {
+        checkPass: [{ validator: validatePass2, trigger: 'blur' }],
+        oldPassword: [{ required: true, message: '不能为空', trigger: 'blur' }],
+        newPassword: [
+          { required: true, message: '不能为空', trigger: 'blur' },
+          { max: 15, message: '不能超过15个字', trigger: 'blur' }
+        ]
+      },
+      userName: '',
+      cut: false,
+      isShow: false,
+      tab1: [{ name: '典藏管理', id: 2, url: '/layout/tab2' }],
+      tab2: [{ name: '操作日志', id: 3, url: '/layout/tab3' }],
+      tab3: [{ name: '文物统计', id: 1, url: '/layout/tab1' }]
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    // 修改密码点击取消
+    btnX () {
+      this.$refs.ruleForm.resetFields()
+      this.cut = false
+      this.isShow = false
+      this.form = {
+        oldPassword: '',
+        newPassword: '',
+        checkPass: ''
+      }
+    },
+    // 修改密码点击确定
+    async btnOk () {
+      await this.$refs.ruleForm.validate()
+      try {
+        const data = {
+          oldPassword: encodeStr(Base64.encode(this.form.oldPassword)),
+          newPassword: encodeStr(Base64.encode(this.form.newPassword))
+        }
+        const res = await updatePwd(data)
+        if (res.code === 0) {
+          this.$message.success('修改成功')
+          localStorage.clear('HNBWY_token')
+          localStorage.clear('HNBWY_userInfo')
+          this.$router.push('/')
+        } else this.$message.error(res.msg)
+      } catch (error) {
+        console.log(error)
+      }
+    },
+    push (url) {
+      this.$router.push(url).catch(() => {})
+    },
+    // 点击退出登录
+    outLogin () {
+      this.cut = false
+      this.$confirm('确定退出吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(() => {
+          localStorage.clear('HNBWY_token')
+          localStorage.clear('HNBWY_userName')
+          this.$router.push('/')
+          this.$message.success('退出成功!')
+        })
+        .catch(() => {
+          this.$message.info('已取消')
+        })
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {
+    // 获取用户名
+    const res = localStorage.getItem('HNBWY_userName')
+    this.userName = res
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {},
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.layout {
+  .top {
+    padding-left: 50px;
+    position: relative;
+    width: 100%;
+    min-width: 1860px;
+    box-shadow: 1px 3px 3px 3px rgb(196, 177, 177);
+    height: 70px;
+    background-color: #3a80d2;
+    display: flex;
+    align-items: center;
+    & > P {
+      color: #fff;
+      font-size: 24px;
+      font-weight: 700;
+    }
+    .top_right {
+      width: 150px;
+      position: absolute;
+      right: 30px;
+      top: 0;
+      height: 100%;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      .user {
+        color: #fff;
+        cursor: pointer;
+        position: relative;
+        display: flex;
+        align-items: center;
+        font-weight: 700;
+        img {
+          margin-right: 15px;
+          width: 34px;
+          height: 34px;
+          border-radius: 50%;
+          overflow: hidden;
+        }
+        .pull_down {
+          position: absolute;
+          right: -25px;
+          bottom: 4px;
+          display: inline-block;
+          width: 0;
+          height: 0;
+          border-left: 8px solid transparent;
+          border-right: 8px solid transparent;
+          border-bottom: 8px solid #fff;
+        }
+        .pull_up {
+          cursor: pointer;
+          position: absolute;
+          right: -25px;
+          bottom: 4px;
+          display: inline-block;
+          width: 0;
+          height: 0;
+          border-left: 8px solid transparent;
+          border-right: 8px solid transparent;
+          border-top: 8px solid #fff;
+        }
+      }
+      .user_handle {
+        z-index: 999;
+        padding: 10px 40px;
+        position: absolute;
+        right: 0;
+        bottom: -90px;
+        background-color: #3a80d2;
+        li {
+          color: #fff;
+          cursor: pointer;
+          margin: 10px 0;
+        }
+        li:hover {
+          color: orange;
+        }
+      }
+    }
+  }
+  .con {
+    min-width: 1860px;
+    min-height: 807px;
+    background-color: #f2ecde;
+    display: flex;
+    width: 100%;
+    padding: 30px;
+    height: calc(100vh - 70px);
+  }
+  .left {
+    min-width: 180px;
+    width: 180px;
+    height: 100%;
+    min-height: 770px;
+    background-color: #fff;
+    padding-top: 30px;
+    .biaoji {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      height: 40px;
+      width: 90%;
+      border-radius: 0 40px 40px 0;
+      font-weight: 700;
+      font-size: 20px;
+      padding-left: 20px;
+      padding-right: 30px;
+    }
+    .biaojiAc {
+      background-color: #3a80d2;
+      color: #fff;
+    }
+    ul {
+      li {
+        cursor: pointer;
+        padding-left: 55px;
+        margin: 30px 0;
+        &:hover {
+          color: #3a80d2;
+        }
+      }
+      .active {
+        color: #3a80d2;
+      }
+    }
+  }
+  .right {
+    position: relative;
+    padding: 20px 0 0 0;
+    min-width: 1500px;
+    flex: 1;
+    margin-left: 30px;
+    background-color: #fff;
+    height: 100%;
+    min-height: 770px;
+  }
+}
+</style>

+ 154 - 0
houtai/src/views/login.vue

@@ -0,0 +1,154 @@
+<!--  -->
+<template>
+  <div class="login">
+    <div class="con">
+      <div class="left">
+        <p>河南博物院</p>
+        <p>文物展示平台后台</p>
+      </div>
+      <div class="right" @keyup.enter="login">
+        <p>欢迎登录</p>
+        <div class="input">
+          <el-form
+            :model="ruleForm"
+            :rules="rules"
+            ref="ruleForm"
+            class="demo-ruleForm"
+          >
+            <el-form-item prop="userName">
+              <el-input
+                v-model="ruleForm.userName"
+                placeholder="账号"
+              ></el-input>
+            </el-form-item>
+            <el-form-item prop="passWord">
+              <el-input
+                show-password
+                v-model="ruleForm.passWord"
+                placeholder="密码"
+              ></el-input>
+            </el-form-item>
+          </el-form>
+        </div>
+        <div class="btn" @click="login">登 录</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { encodeStr } from '../utils/pass'
+import { Base64 } from 'js-base64'
+import { userLogin } from '@/apis/login'
+export default {
+  name: 'login',
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      ruleForm: {
+        userName: '',
+        passWord: ''
+      },
+      rules: {
+        userName: [{ required: true, message: '不能为空', trigger: 'blur' }],
+        passWord: [{ required: true, message: '不能为空', trigger: 'blur' }]
+      }
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    async login () {
+      try {
+        await this.$refs.ruleForm.validate()
+        const data = {
+          userName: this.ruleForm.userName,
+          passWord: encodeStr(Base64.encode(this.ruleForm.passWord))
+        }
+        const res = await userLogin(data)
+        if (res.code === 0) {
+          localStorage.setItem('HNBWY_token', res.data.token)
+          localStorage.setItem('HNBWY_userName', res.data.user.userName)
+          this.$router.push('/layout/tab2')
+          this.$message.success('登录成功')
+        } else this.$message.warning(res.msg)
+      } catch (error) {
+        console.log(error)
+      }
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {},
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.login {
+  width: 100vw;
+  height: 100vh;
+  background: url("../assets/img/bg.jpg");
+  background-size: 100% 100%;
+  .con {
+    display: flex;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    width: 700px;
+    height: 400px;
+    .left {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      width: 350px;
+      height: 100%;
+      background-color: rgba(58, 128, 210, 0.8);
+      & > p {
+        width: 80%;
+        margin: 0 auto;
+        margin-bottom: 30px;
+        color: #fff;
+        font-weight: 700;
+        text-align: center;
+        font-size: 30px;
+      }
+    }
+    .right {
+      width: 350px;
+      background-color: rgba(255, 255, 255, 0.8);
+      & > p {
+        font-size: 24px;
+        text-align: center;
+        margin-top: 50px;
+      }
+      .input {
+        width: 90%;
+        margin: 50px auto;
+      }
+      .btn {
+        cursor: pointer;
+        width: 90%;
+        height: 40px;
+        line-height: 40px;
+        text-align: center;
+        margin: 50px auto 0;
+        background-color: #3a80d2;
+        border-radius: 8px;
+        color: #fff;
+      }
+    }
+  }
+}
+</style>

+ 178 - 0
houtai/src/views/tab1/index.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="tab1">
+    <div class="insideTop">文物统计</div>
+    <div class="obstruct"></div>
+    <!-- 主要内容 -->
+    <div class="conten">
+      <div class="row1">
+        <div class="tit">文物类别</div>
+        <div id="echarts1"></div>
+        <div class="sumNum1">合计:{{num1}}</div>
+      </div>
+      <div class="row2">
+        <div class="tit">文物级别</div>
+        <div id="echarts2"></div>
+        <div class="sumNum2">合计:{{num2}}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts/core'
+import {
+  TitleComponent,
+  TooltipComponent,
+  LegendComponent
+} from 'echarts/components'
+import { PieChart } from 'echarts/charts'
+import { LabelLayout } from 'echarts/features'
+import { CanvasRenderer } from 'echarts/renderers'
+import { goodsReport } from '../../apis/tab2'
+
+echarts.use([
+  TitleComponent,
+  TooltipComponent,
+  LegendComponent,
+  PieChart,
+  CanvasRenderer,
+  LabelLayout
+])
+
+export default {
+  name: 'tab1',
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      num1: 0,
+      num2: 0
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    echartsFu (bs, data, name, centen, radius) {
+      const chartDom = document.getElementById(`echarts${bs}`)
+      const myChart = echarts.init(chartDom)
+
+      const option = {
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b} : {c} ({d}%)'
+        },
+        legend: {
+          type: 'scroll',
+          orient: 'vertical',
+          right: 20,
+          top: 20,
+          bottom: 20,
+          data,
+          formatter: (name) => {
+            const value = data.filter((v) => v.name === name)
+            return `${name}(${value[0].value})`
+          }
+        },
+        series: [
+          {
+            name,
+            type: 'pie',
+            radius: radius,
+            center: [centen, '50%'],
+            itemStyle: {
+              borderRadius: 10,
+              borderColor: '#fff',
+              borderWidth: 2
+            },
+            data,
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.5)'
+              }
+            }
+          }
+        ]
+      }
+
+      option && myChart.setOption(option)
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  async created () {},
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  async mounted () {
+    const res = await goodsReport()
+    const data1 = []
+    const data2 = []
+    let num1 = 0
+    let num2 = 0
+    res.data.textureDetail.forEach((v) => {
+      if (v.psc) data1.push({ value: v.psc, name: v.name })
+      num1 += v.psc
+    })
+
+    res.data.levelDetail.forEach(v => {
+      data2.push({ value: v.psc, name: v.name })
+      num2 += v.psc
+    })
+    this.num1 = num1
+    this.num2 = num2
+    this.echartsFu(1, data1, '文物类别', '35%', ['40%', '70%'])
+    this.echartsFu(2, data2, '文物级别', '40%', ['30%', '60%'])
+  },
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.tab1 {
+  height: 100%;
+  .insideTop .add {
+    right: 55px;
+  }
+  .conten {
+    padding: 15px 30px 0;
+    height: calc(100% - 32px);
+    display: flex;
+    justify-content: space-between;
+    .row1 {
+      width: 55%;
+    }
+    .row2 {
+      width: 40%;
+    }
+    .tit {
+      margin: 15px 0;
+    }
+    #echarts1 {
+      width: 100%;
+      height: 520px;
+      border-right: 2px solid #ccc;
+    }
+    #echarts2 {
+      width: 100%;
+      height: 520px;
+    }
+    .sumNum1 {
+      margin-top: 15px;
+      text-align: center;
+      padding-right: 250px;
+    }
+    .sumNum2 {
+      margin-top: 15px;
+      text-align: center;
+      padding-right: 105px;
+    }
+  }
+}
+</style>

+ 646 - 0
houtai/src/views/tab2/add.vue

@@ -0,0 +1,646 @@
+<!--  -->
+<template>
+  <div class="tab2Add">
+    <div class="top">
+      典藏信息 > {{ ruleForm.type === "img" ? "精品图片" : "三维模型" }} >
+      {{ ruleForm.id ? "编辑" : "新增" }}
+    </div>
+    <div class="conten">
+      <el-form
+        :model="ruleForm"
+        ref="ruleForm"
+        label-width="120px"
+        class="demo-ruleForm"
+      >
+        <!-- 名称 -->
+        <div class="checkBox2">
+          <el-form-item label="名称:">
+            <i class="biaoshi biaoshi2"></i>
+            <el-input
+              v-model="ruleForm.name"
+              maxlength="10"
+              show-word-limit
+            ></el-input>
+          </el-form-item>
+          <!-- 总登记号 -->
+          <el-form-item label="总登记号:">
+            <el-input
+              v-model="ruleForm.registerNum"
+              maxlength="25"
+              show-word-limit
+            ></el-input>
+          </el-form-item>
+        </div>
+        <div class="checkBox">
+          <!-- 日期 -->
+          <el-form-item label="日期:">
+            <i class="biaoshi biaoshi2"></i>
+            <el-date-picker
+              format="yyyy-MM-dd"
+              value-format="yyyy-MM-dd"
+              v-model="day"
+              type="date"
+              placeholder="选择日期"
+            >
+            </el-date-picker>
+          </el-form-item>
+
+          <!-- 类型 -->
+          <el-form-item label="类别:">
+            <el-select
+              v-model="ruleForm.dictTextureId"
+              clearable
+              placeholder="请选择类别"
+            >
+              <el-option
+                v-for="i in dictTextureArr"
+                :key="i.value"
+                :label="i.label"
+                :value="i.value"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+          <!-- 年代 -->
+          <el-form-item label="年代:">
+            <el-cascader
+              ref="elCascader"
+              clearable
+              v-model="dictAgeId"
+              :options="options"
+            >
+            </el-cascader>
+          </el-form-item>
+          <!-- 级别 -->
+          <el-form-item label="级别:">
+            <el-select
+              v-model="ruleForm.dictLevelId"
+              clearable
+              placeholder="请选择级别"
+            >
+              <el-option
+                v-for="i in dictLevelArr"
+                :key="i.value"
+                :label="i.label"
+                :value="i.value"
+              >
+              </el-option>
+            </el-select>
+          </el-form-item>
+        </div>
+        <!-- 尺寸 -->
+        <el-form-item label="尺寸:" class="sizeInput">
+          <el-input v-model="chang" maxlength="100" show-word-limit></el-input>
+        </el-form-item>
+
+        <!-- 图片 -->
+        <el-form-item label="图片:">
+          <i class="biaoshi biaoshi1"></i>
+          <el-upload
+            accept=".png,.jpg,.jpeg,.gif"
+            :data="{ type: 'img' }"
+            class="avatar-uploader"
+            :action="baseURL + '/api/cms/goods/upload'"
+            :headers="{ token }"
+            :show-file-list="true"
+            :before-upload="beforethumbUpload"
+            :on-success="upload_thumb_success"
+          >
+            <div v-if="ruleForm.thumb" class="imgdiv">
+              <img
+                style="
+                  width: 150px;
+                  height: 150px;
+                  display: block;
+                  object-fit: cover;
+                "
+                :src="baseURL + ruleForm.thumb"
+              />
+              <i
+                class="el-icon-circle-close"
+                @click.stop="ruleForm.thumb = ''"
+              ></i>
+            </div>
+            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
+          </el-upload>
+          <p class="upHint">
+            格式要求:支持png、jpg、gif和jpeg的图片格式;最大支持20MB。
+          </p>
+        </el-form-item>
+        <!-- 说明 -->
+        <el-form-item label="说明:">
+          <div class="txtBtn">
+            <el-button
+              :disabled="ruleForm.description.length >= 128"
+              size="small"
+              round
+              @click="ruleForm.description += '&emsp;&emsp;'"
+              >首行缩进</el-button
+            >
+            <el-button
+              :disabled="ruleForm.description.length >= 135"
+              size="small"
+              round
+              @click="ruleForm.description += '<br/>'"
+              >换行</el-button
+            >
+          </div>
+          <el-input
+            type="textarea"
+            v-model="ruleForm.description"
+            maxlength="140"
+            show-word-limit
+          ></el-input>
+        </el-form-item>
+        <!-- 附件 -->
+        <div class="rowFrom">
+          <el-form-item label="模型文件:" v-if="ruleForm.type === 'model'">
+            <i class="biaoshi"></i>
+            <el-upload
+              accept=".4dage"
+              multiple
+              drag
+              class="upload-demo"
+              :data="{ type: 'model' }"
+              :file-list="fileList"
+              :action="baseURL + '/api/cms/goods/upload'"
+              :headers="{ token }"
+              :before-upload="beforeFujian"
+              :on-success="successFujian"
+              :before-remove="beforeRemove"
+              :on-remove="handleRemove"
+              :limit="1"
+              :on-exceed="handleExceed"
+              :show-file-list="true"
+            >
+              <i class="el-icon-upload"></i>
+              <div class="el-upload__text">
+                将文件拖到此处,或<em>点击上传</em>
+              </div>
+              <div class="el-upload__text smEl">
+                仅支持.4dage格式的模型文件,大小不得超过500MB
+              </div>
+            </el-upload>
+          </el-form-item>
+          &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
+          <el-form-item label="音频文件:" v-if="ruleForm.type === 'model'">
+            <el-upload
+              accept=".mp3"
+              multiple
+              drag
+              class="upload-demo"
+              :data="{ type: 'audio' }"
+              :file-list="fileList2"
+              :action="baseURL + '/api/cms/goods/upload'"
+              :headers="{ token }"
+              :before-upload="beforeFujian2"
+              :on-success="successFujian2"
+              :before-remove="beforeRemove2"
+              :on-remove="handleRemove2"
+              :limit="1"
+              :on-exceed="handleExceed2"
+              :show-file-list="true"
+            >
+              <i class="el-icon-upload"></i>
+              <div class="el-upload__text">
+                将文件拖到此处,或<em>点击上传</em>
+              </div>
+              <div class="el-upload__text smEl">
+                仅支持MP3格式的音频文件,大小不得超过10MB
+              </div>
+            </el-upload>
+          </el-form-item>
+        </div>
+      </el-form>
+    </div>
+    <!-- 底部按钮 -->
+    <div class="con_btn">
+      <el-button @click="goBack">取 消</el-button>&emsp;
+      <el-button type="primary" @click="saveGood">保 存</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { goodsSave, goodsDetail, dictGetTree } from '../../apis/tab2'
+import axios from '@/utils/request'
+export default {
+  name: 'tab2Add',
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      // 日期
+      day: '',
+
+      // 服务器前缀地址
+      baseURL: '',
+      // 尺寸
+      chang: '',
+      // 年代
+      dictAgeId: [],
+      options: [],
+      // 类型数组
+      dictTextureArr: [],
+      // 级别数组
+      dictLevelArr: [],
+      ruleForm: {
+        // 总登记号
+        registerNum: '',
+        // 类别
+        dictTextureId: '',
+        // 级别
+        dictLevelId: '',
+        name: '',
+        type: null,
+        description: '',
+        thumb: '',
+        // 上传模型
+        filePath: '',
+        fileName: ''
+      },
+      fileList: [],
+      // ---------音频
+      fileList2: []
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {},
+  // 方法集合
+  methods: {
+    // 点击取消
+    goBack () {
+      let k = this.$route.query.k
+      if (!k) k = '1'
+      this.$router.push({
+        path: '/layout/tab2',
+        query: { typeU: this.ruleForm.type, k }
+      })
+    },
+    // 点击保存
+    async saveGood () {
+      if (this.ruleForm.name.trim() === '') {
+        return this.$message.warning('名称不能为空')
+      }
+      if (this.ruleForm.thumb === '') {
+        return this.$message.warning('图片不能为空')
+      }
+      if (this.ruleForm.filePath === '' && this.ruleForm.type === 'model') {
+        return this.$message.warning('文件不能为空')
+      }
+      if (!this.day) return this.$message.warning('日期不能为空')
+      const obj = { ...this.ruleForm }
+      obj.day = this.day
+      // 年代数据判断
+      if (this.dictAgeId && this.dictAgeId[1]) {
+        obj.dictAgeId = this.dictAgeId[1]
+        // eslint-disable-next-line no-constant-condition
+        const tempArr = this.$refs.elCascader.getCheckedNodes()[0].pathLabels
+        obj.dictAgeFront = tempArr.join('/')
+      }
+      // 长宽高判断
+      if (this.chang) obj.sizeLength = this.chang
+      const res = await goodsSave(obj)
+      if (res.code === 0) {
+        this.$message.success('操作成功')
+        this.goBack()
+      } else this.$message.warning(res.msg)
+    },
+    // 上传图片
+    beforethumbUpload (file) {
+      // console.log(998, file)
+      // 限制图片大小和格式
+      const sizeOk = file.size / 1024 / 1024 < 20
+      const typeOk =
+        file.type === 'image/png' ||
+        (file.type === 'image/jpeg' && !file.name.includes('.jfif')) ||
+        file.type === 'image/gif'
+
+      return new Promise((resolve, reject) => {
+        if (!typeOk) {
+          this.$message.error('图片格式有误!')
+          reject(file)
+        } else if (!sizeOk) {
+          this.$message.error('图片大小超过20M!')
+          reject(file)
+        } else {
+          resolve(file)
+        }
+      })
+    },
+    upload_thumb_success (data) {
+      this.$message.success('上传成功')
+      this.ruleForm.thumb = data.data.filePath
+    },
+    // 上传附件
+    beforeFujian (file) {
+      console.log('附件上传前', file)
+      const sizeOk = file.size / 1024 / 1024 < 500
+      const typeOk = file.type === '' && file.name.includes('.4dage')
+      return new Promise((resolve, reject) => {
+        if (!sizeOk) {
+          this.$message.error('模型大小超过500M!')
+          reject(file)
+        } else if (!typeOk) {
+          this.$message.error('模型格式有误!')
+          reject(file)
+        } else {
+          resolve(file)
+        }
+      })
+    },
+    successFujian (file) {
+      console.log('上传附件成功', file)
+      if (file.code === 0) {
+        this.ruleForm.filePath = file.data.filePath
+        this.ruleForm.fileName = file.data.fileName
+        this.$message.success('上传成功')
+      } else if (file.code === -1) {
+        this.$message.warning('上传失败,不支持的文件格式')
+      }
+    },
+    beforeRemove (file, fileList) {
+      if (file && file.status === 'success') {
+        return this.$confirm(`确定移除 ${file.name}?`)
+      }
+    },
+    handleRemove (file, fileList) {
+      this.ruleForm.filePath = ''
+      this.ruleForm.fileName = ''
+    },
+    handleExceed (files, fileList) {
+      this.$message.warning('只能上传一个文件,请删除原文件后操作')
+    },
+
+    // 上传音频-------------
+    beforeFujian2 (file) {
+      console.log('附件上传前222', file)
+      const sizeOk = file.size / 1024 / 1024 < 10
+      const typeOk = file.type === 'audio/mpeg'
+      return new Promise((resolve, reject) => {
+        if (!sizeOk) {
+          this.$message.error('音频大小超过10M!')
+          reject(file)
+        } else if (!typeOk) {
+          this.$message.error('音频格式有误!')
+          reject(file)
+        } else {
+          resolve(file)
+        }
+      })
+    },
+    successFujian2 (file) {
+      console.log('上传附件成功222', file)
+      if (file.code === 0) {
+        this.ruleForm.audioPath = file.data.filePath
+        this.ruleForm.audioName = file.data.fileName
+        this.$message.success('上传成功')
+      } else if (file.code === -1) {
+        this.$message.warning('上传失败,不支持的文件格式')
+      }
+    },
+    beforeRemove2 (file, fileList) {
+      if (file && file.status === 'success') {
+        return this.$confirm(`确定移除 ${file.name}?`)
+      }
+    },
+    handleRemove2 (file, fileList) {
+      this.ruleForm.audioPath = ''
+      this.ruleForm.audioName = ''
+    },
+    handleExceed2 (files, fileList) {
+      this.$message.warning('只能上传一个文件,请删除原文件后操作')
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  async created () {
+    // 获取服务器前缀地址
+    this.baseURL = axios.defaults.baseURL
+    // 获取用户token
+    this.token = localStorage.getItem('HNBWY_token')
+    // 拿到路由跳转传过来的数据
+    this.ruleForm.type = this.$route.query.typeU
+
+    // 几个下拉框的数据
+    // --------年代
+    const res = await dictGetTree({ type: 'age' })
+    const temp = []
+    res.data.forEach((v, i) => {
+      temp.push({ value: v.id, label: v.name, children: [] })
+      v.children.forEach((p) => {
+        temp[i].children.push({ value: p.id, label: p.name })
+      })
+    })
+    this.options = [...temp]
+
+    // -------类别
+    const res2 = await dictGetTree({ type: 'texture' })
+    this.dictTextureArr = res2.data.map((v) => {
+      return { value: v.id, label: v.name }
+    })
+    // -------级别
+    const res3 = await dictGetTree({ type: 'level' })
+    this.dictLevelArr = res3.data.map((v) => {
+      return { value: v.id, label: v.name }
+    })
+
+    // 如果是编辑
+    let id = this.$route.query.id
+    if (id) {
+      id = Number(id)
+      const resSon = await goodsDetail(id)
+      this.ruleForm = resSon.data
+      // 附件回显
+      this.fileList = [{ name: resSon.data.fileName }]
+      // 音频回显
+      if (resSon.data.audioName) {
+        this.fileList2 = [{ name: resSon.data.audioName }]
+      }
+
+      // 年代回显
+      if (resSon.data.dictAgeId) {
+        res.data.forEach((v) => {
+          v.children.forEach((p) => {
+            if (p.id === resSon.data.dictAgeId) this.dictAgeId = [v.id, p.id]
+          })
+        })
+      }
+      // 尺寸回显
+      this.chang = resSon.data.sizeLength
+      // 日期回显
+      this.day = resSon.data.day
+    }
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {},
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.tab2Add {
+  width: 100%;
+  height: 100%;
+
+  .rowFrom {
+    display: flex;
+
+    /deep/.el-upload-list {
+      width: 360px;
+    }
+
+    /deep/.el-upload-list li {
+      width: 360px !important;
+    }
+  }
+
+  .top {
+    margin-top: -20px;
+    height: 50px;
+    line-height: 50px;
+    padding-left: 50px;
+    background-color: #f8f8f8;
+    font-weight: 700;
+  }
+
+  .conten {
+    padding-right: 300px;
+    padding-top: 20px;
+
+    .upHint {
+      position: absolute;
+      bottom: 40px;
+      left: 160px;
+    }
+
+    .avatar-uploader .el-upload {
+      border-radius: 6px;
+      cursor: pointer;
+      position: relative;
+      overflow: hidden;
+    }
+
+    .avatar-uploader .el-upload:hover {
+      border-color: #3e5eb3;
+    }
+
+    .avatar-uploader-icon {
+      border: 1px dashed #ccc;
+      font-size: 28px;
+      color: #8c939d;
+      width: 150px;
+      height: 150px;
+      line-height: 150px;
+      text-align: center;
+    }
+
+    .biaoshi1::before {
+      left: -64px;
+    }
+
+    .biaoshi2::before {
+      top: -11px;
+      left: -64px;
+    }
+
+    /deep/.el-form-item {
+      margin-bottom: 12px;
+    }
+
+    /deep/.el-textarea textarea {
+      margin-top: 10px;
+      height: 55px;
+      resize: none;
+    }
+
+    /deep/.el-textarea .el-input__count {
+      position: absolute;
+      bottom: -24px;
+      right: 4px;
+      background-color: transparent;
+      height: 30px;
+      line-height: 30px;
+    }
+
+    .smEl {
+      color: #ccc;
+      font-size: 12px;
+      margin-top: -15px;
+    }
+  }
+
+  .con_btn {
+    position: absolute;
+    bottom: 20px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+
+  .txtBtn {
+    position: absolute;
+    top: -32px;
+    right: 4px;
+  }
+
+  /deep/.imgdiv .el-icon-circle-close {
+    font-size: 20px;
+  }
+
+  .checkBox {
+    display: flex;
+  }
+
+  .checkBox2 {
+    width: 100%;
+    display: flex;
+
+    & > div {
+      width: 50%;
+    }
+  }
+
+  .fromSize {
+    /deep/.el-form-item__content {
+      display: flex;
+    }
+
+    /deep/.el-input {
+      width: 100px;
+    }
+
+    /deep/.el-input--suffix {
+      width: 90px;
+    }
+
+    /deep/.el-input__inner {
+      padding: 0 5px !important;
+    }
+
+    .sizeRow {
+      margin-right: 90px;
+    }
+
+    .sizeRow2 {
+      /deep/.el-input {
+        width: 110px;
+      }
+    }
+  }
+  .sizeInput{
+    /deep/input{
+      padding-right: 70px !important;
+    }
+  }
+
+  /deep/.el-upload-list {
+    margin-top: -12px;
+  }
+}
+</style>

+ 650 - 0
houtai/src/views/tab2/index.vue

@@ -0,0 +1,650 @@
+<template>
+  <div class="tab2">
+    <div class="insideTop">
+      文物管理
+      <div class="add">
+        <el-button type="primary" @click="addGood">新增</el-button>
+      </div>
+    </div>
+    <div class="obstruct"></div>
+    <div class="conten">
+      <div class="con_left" v-show="0">
+        <div class="cutJT">
+          <i class="el-icon-menu"></i>
+          典藏管理
+        </div>
+        <ul>
+          <li
+            v-for="item in conLeftArr"
+            :key="item.id"
+            :class="{ active: formData.type === item.type }"
+            @click="cutLeft(item.type)"
+          >
+            {{ item.name }}
+          </li>
+        </ul>
+      </div>
+      <!-- 右侧主要内容 -->
+      <div class="con_right" v-loading="loading">
+        <div class="search" @keyup.enter="searchBtn">
+          <span>&emsp;&emsp;名称:</span>
+          <el-input
+            maxlength="25"
+            show-word-limit
+            v-model="formData.searchKey"
+            placeholder="请输入关键字"
+            style="width: 240px"
+          ></el-input>
+          <span class="search_k">&emsp;&emsp;类别:</span>
+          <el-select v-model="formData.dictTextureId" placeholder="请选择类别">
+            <el-option
+              v-for="i in dictTextureArr"
+              :key="i.value"
+              :label="i.label"
+              :value="i.value"
+            >
+            </el-option>
+          </el-select>
+          <span class="search_k">年代:</span>
+          <el-select v-model="formData.dictAgeId" placeholder="请选择类别">
+            <el-option
+              v-for="i in dictAgeArr"
+              :key="i.value"
+              :label="i.label"
+              :value="i.value"
+            >
+            </el-option>
+          </el-select>
+          <span class="search_k">级别:</span>
+          <el-select v-model="formData.dictLevelId" placeholder="请选择类别">
+            <el-option
+              v-for="i in dictLevelArr"
+              :key="i.value"
+              :label="i.label"
+              :value="i.value"
+            >
+            </el-option>
+          </el-select>
+        </div>
+        <div class="search" @keyup.enter="searchBtn">
+          <span>总登记号:</span>
+          <el-input
+            maxlength="25"
+            show-word-limit
+            v-model="formData.registerNum"
+            placeholder="请输入关键字"
+            style="width: 240px"
+          ></el-input>
+
+          <span class="search_k">创建时间:</span>
+          <el-date-picker
+            style="width: 257px; padding-right: 0px"
+            v-model="time"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+          >
+          </el-date-picker>
+
+          <!-- 右侧按钮 -->
+          <div class="search_btn">
+            <el-button type="primary" @click="searchBtn">查 询</el-button>
+            <el-button @click="resetBtn">重 置</el-button>
+            <download-excel
+              :before-generate="derive"
+              class="export-excel-wrapper"
+              :data="json_data"
+              :fields="json_fields"
+              :name="`文物信息清单${nowTime}.xls`"
+            >
+              <!-- 上面可以自定义自己的样式,还可以引用其他组件button -->
+              <el-button>批量导出</el-button>
+            </download-excel>
+          </div>
+        </div>
+        <!-- 表格 -->
+        <div class="table">
+          <el-table :data="tableData" style="width: 100%">
+            <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 label="名称" prop="name"> </el-table-column>
+            <el-table-column label="总登记号">
+              <template #default="{ row }">
+                <span
+                  style="cursor: pointer"
+                  :title="row.registerNum"
+                  v-if="row.registerNum"
+                  >{{
+                    row.registerNum.length > 10
+                      ? row.registerNum.substring(0, 10) + "..."
+                      : row.registerNum
+                  }}</span
+                >
+                <span v-else>(空)</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="类别">
+              <template #default="{ row }">
+                <span v-if="row.dictTextureName">{{
+                  row.dictTextureName
+                }}</span>
+                <span v-else>(空)</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="年代">
+              <template #default="{ row }">
+                <span v-if="row.dictAgeFront">{{ row.dictAgeFront }}</span>
+                <span v-else>(空)</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="级别">
+              <template #default="{ row }">
+                <span v-if="row.dictLevelName">{{ row.dictLevelName }}</span>
+                <span v-else>(空)</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="说明">
+              <template #default="{ row }">
+                <span
+                  style="cursor: pointer"
+                  :title="handTxt(row.description)"
+                  v-if="handTxt(row.description)"
+                  >{{
+                    handTxt(row.description).length > 10
+                      ? handTxt(row.description).substring(0, 10) + "..."
+                      : handTxt(row.description)
+                  }}</span
+                >
+                <span v-else>(空)</span>
+              </template>
+            </el-table-column>
+            <el-table-column label="图片" width="120">
+              <template #default="{ row }">
+                <img
+                  class="table_img"
+                  :src="baseURL + row.thumb"
+                  alt=""
+                  :onerror="defaultImg"
+                />
+              </template>
+            </el-table-column>
+            <el-table-column prop="day" label="日期"> </el-table-column>
+            <el-table-column label="操作">
+              <template #default="{ row }">
+                <el-button
+                  type="text"
+                  @click="lookQrCode(row.qrPath, row.fileName)"
+                  >二维码</el-button
+                >
+
+                <el-button type="text" @click="editGood(row.id)"
+                  >编辑</el-button
+                >
+                <el-button
+                  type="text"
+                  style="color: #d9001b"
+                  :disabled="!!row.display"
+                  @click="delGoods(row.id)"
+                  :class="{ disNo: row.display }"
+                  >删除</el-button
+                >
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </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 class="qrCodeBox" v-show="qrCodeSrc">
+      <!-- 关闭 -->
+      <div
+        class="closeQrCode el-icon-circle-close"
+        @click="qrCodeSrc = ''"
+      ></div>
+      <img v-if="qrCodeSrc" :src="baseURL + qrCodeSrc" alt="" />
+      <!-- 下载二维码 -->
+      <a
+        target="blank"
+        :href="baseURL + qrCodeSrc"
+        :download="qrName"
+        class="qrCodeDown"
+        >保存二维码</a
+      >
+    </div>
+  </div>
+</template>
+
+<script>
+import axios from '@/utils/request'
+import { goodsList, goodsRemove, goodsDisplay, dictGetTree } from '@/apis/tab2'
+import dayjs from 'dayjs'
+import relativeTime from 'dayjs/plugin/relativeTime'
+import 'dayjs/locale/zh-cn'
+dayjs.extend(relativeTime)
+
+export default {
+  name: 'tab2',
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      loading: false,
+      nowTime: '',
+      // 导出表格的数据
+      json_fields: {
+        名称: 'name', // 常规字段
+        总登记号: 'registerNum', // 支持嵌套属性
+        类别: 'dictTextureName',
+        年代: 'dictAgeName',
+        级别: 'dictLevelName',
+        长: 'sizeLength',
+        宽: 'sizeWidth',
+        高: 'sizeHeight',
+        说明: 'description'
+      },
+      json_data: [],
+      json_meta: [
+        [
+          {
+            ' key ': ' charset ',
+            ' value ': ' utf- 8 '
+          }
+        ]
+      ],
+
+      baseURL: '',
+      total: 0,
+      time: '',
+      conLeftArr: [
+        { name: '精品图片', type: 'img' },
+        { name: '三维模型', type: 'model' }
+      ],
+      formData: {
+        startTime: '',
+        endTime: '',
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: '',
+        registerNum: '',
+        dictTextureId: '',
+        dictLevelId: '',
+        dictAgeId: '',
+        type: 'model'
+      },
+      tableData: [],
+      dictLevelArr: [],
+      dictTextureArr: [],
+      dictAgeArr: [],
+      // 二维码查看
+      qrCodeSrc: '',
+      qrName: ''
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  watch: {
+    time (val) {
+      this.handleSelect(val)
+    }
+  },
+  // 方法集合
+  methods: {
+    // 点击二维码
+    lookQrCode (url, name) {
+      this.qrCodeSrc = url
+      this.qrName = name.split('.')[0]
+    },
+
+    // 处理说明的文本
+    handTxt (val) {
+      let temp = val.replaceAll('&emsp;', ' ')
+      temp = temp.replaceAll('<br/>', '/')
+      return temp
+    },
+    // 点击导出
+    async derive () {
+      this.searchBtn()
+      this.json_data = []
+      this.loading = true
+      this.nowTime = dayjs().format('YYYYMMDD')
+      // 封装获取列表的函数
+      const res = await goodsList({
+        ...this.formData,
+        pageNum: 1,
+        pageSize: 9999
+      })
+      if (res.code === 0) {
+        if (res.data.records.length === 0) {
+          this.$message.warning('没有符合条件的数据')
+          this.loading = false
+          return
+        }
+        this.json_data = res.data.records.map((v) => {
+          return {
+            name: v.name,
+            registerNum: v.registerNum,
+            dictTextureName: v.dictTextureName,
+            dictAgeName: v.dictAgeName,
+            dictLevelName: v.dictLevelName,
+            sizeLength: v.sizeLength.replace(',', ''),
+            sizeWidth: v.sizeWidth.replace(',', ''),
+            sizeHeight: v.sizeHeight.replace(',', ''),
+            description: v.description
+          }
+        })
+        this.loading = false
+      } else this.$message.warning(res.msg)
+    },
+    // 点击重置
+    resetBtn () {
+      this.formData.searchKey = ''
+      this.time = ''
+      this.formData.pageNum = 1
+      this.formData.startTime = this.formData.endTime = ''
+      this.formData.registerNum =
+        this.formData.dictTextureId =
+        this.formData.dictLevelId =
+        this.formData.dictAgeId =
+          ''
+      this.goodsList(this.formData)
+    },
+    // 点击查询
+    searchBtn () {
+      this.formData.pageNum = 1
+      this.goodsList(this.formData)
+    },
+    // 点击开关
+    async changeSwit (val, id) {
+      const res = await goodsDisplay(id, val)
+      if (res.code === 0) {
+        this.$message.success('操作成功')
+        this.goodsList(this.formData)
+      } else this.$message.warning(res.msg)
+      console.log(998, val, id)
+    },
+    // 分页器方法
+    currentChange (val) {
+      // console.log('当前页改变了', val)
+      this.formData.pageNum = val
+      this.goodsList(this.formData)
+    },
+    sizeChange (val) {
+      // console.log('条数改变了', val)
+      this.formData.pageNum = 1
+      this.formData.pageSize = val
+      this.goodsList(this.formData)
+    },
+    // 点击删除
+    delGoods (id) {
+      this.$confirm('删除后,信息无法恢复,是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      })
+        .then(async () => {
+          const res = await goodsRemove(id)
+          if (res.code === 0) {
+            this.$message.success('删除成功')
+            if (this.tableData.length === 1 && this.formData.pageNum > 1) {
+              this.formData.pageNum -= 1
+            }
+            this.goodsList(this.formData)
+          } else this.$message.warning(res.msg)
+        })
+        .catch(() => {
+          this.$message.info('已取消')
+        })
+    },
+    // 点击编辑文物
+    editGood (id) {
+      this.$router.push({
+        path: '/layout/tab2Add',
+        query: { typeU: this.formData.type, id, k: this.formData.pageNum }
+      })
+    },
+    // 点击新增文物
+    addGood () {
+      this.$router.push({
+        path: '/layout/tab2Add',
+        query: { typeU: this.formData.type, k: this.formData.pageNum }
+      })
+    },
+    // 点击左侧的tab栏
+    cutLeft (type) {
+      if (type === this.formData.type) return
+      this.formData.pageNum = 1
+      this.formData.type = type
+      this.goodsList(this.formData)
+    },
+    // 时间处理----------------
+    handleSelect (e) {
+      const date = []
+      for (const i in e) {
+        date.push(this.gettime(e[i]))
+      }
+      this.formData.startTime = date[0]
+      if (date[1]) {
+        this.formData.endTime = date[1].replace('00:00:00', '23:59:59')
+      }
+      if (e === null) this.formData.endTime = ''
+    },
+    gettime (data) {
+      const value =
+        data.getFullYear() +
+        '-' +
+        this.checkTime(data.getMonth() + 1) +
+        '-' +
+        this.checkTime(data.getDate()) +
+        ' ' +
+        this.checkTime(data.getHours()) +
+        ':' +
+        this.checkTime(data.getMinutes()) +
+        ':' +
+        this.checkTime(data.getSeconds())
+      return value
+    },
+    checkTime (i) {
+      if (i < 10) {
+        i = '0' + i
+      }
+      return i
+    },
+    // 封装获取列表的函数
+    async goodsList (data) {
+      const res = await goodsList(data)
+      this.total = res.data.total
+      this.tableData = res.data.records
+      // console.log(998, res)
+    }
+  },
+  // 生命周期 - 创建完成(可以访问当前this实例)
+  async created () {
+    // 获取服务器前缀地址
+    this.baseURL = axios.defaults.baseURL
+    // 判断是第一次进来还是修改或者新增或者查看后返回
+    // 拿到路由跳转传过来的数据
+    if (this.$route.query.typeU) {
+      this.formData.type = this.$route.query.typeU
+    }
+    const k = this.$route.query.k
+    if (k) this.formData.pageNum = Number(k)
+    this.goodsList(this.formData)
+    // 几个下拉框的数据
+    // --------年代
+    const res = await dictGetTree({ type: 'age' })
+    const temp = []
+    res.data.forEach((v) => {
+      v.children.forEach((p) => {
+        temp.push({ value: p.id, label: p.name })
+      })
+    })
+    temp.unshift({ value: '', label: '全部' })
+    this.dictAgeArr = [...temp]
+    // -------类别
+    const res2 = await dictGetTree({ type: 'texture' })
+    this.dictTextureArr = res2.data.map((v) => {
+      return { value: v.id, label: v.name }
+    })
+    this.dictTextureArr.unshift({ value: '', label: '全部' })
+    // -------级别
+    const res3 = await dictGetTree({ type: 'level' })
+    this.dictLevelArr = res3.data.map((v) => {
+      return { value: v.id, label: v.name }
+    })
+    this.dictLevelArr.unshift({ value: '', label: '全部' })
+  },
+  // 生命周期 - 挂载完成(可以访问DOM元素)
+  mounted () {},
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.tab2 {
+  height: 100%;
+  .qrCodeBox {
+    z-index: 10;
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100vw;
+    height: 100vh;
+    background-color: rgba(0, 0, 0, 0.8);
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    .qrCodeDown {
+      position: absolute;
+      width: 120px;
+      height: 40px;
+      line-height: 36px;
+      text-align: center;
+      top: 24px;
+      right: 90px;
+      color: #fff;
+      border-radius: 20px;
+      border: 1px solid #fff;
+    }
+    .closeQrCode {
+      cursor: pointer;
+      color: #fff;
+      position: absolute;
+      right: 30px;
+      top: 30px;
+      font-size: 30px;
+    }
+    & > img {
+      max-width: 500px;
+      max-height: 500px;
+      object-fit: cover;
+    }
+  }
+  .conten {
+    display: flex;
+    height: calc(100% - 52px);
+    .con_left {
+      padding: 20px 0 0 15px;
+      width: 150px;
+      height: 100%;
+      border-right: 1px solid black;
+      .cutJT {
+        margin-bottom: 10px;
+      }
+      ul {
+        li {
+          cursor: pointer;
+          width: 100px;
+          text-align: center;
+          line-height: 40px;
+          height: 40px;
+          &:hover {
+            color: #3a80d2;
+          }
+        }
+        .active {
+          color: #3a80d2;
+        }
+      }
+    }
+    .con_right {
+      padding: 15px 30px 0;
+      width: 100%;
+      .classify {
+        text-align: center;
+        width: 40px;
+        padding-bottom: 10px;
+        color: #b9412e;
+        border-bottom: 2px solid #b9412e;
+      }
+      .search {
+        display: flex;
+        align-items: center;
+        margin-bottom: 20px;
+        position: relative;
+        margin-top: 12px;
+        height: 40px;
+        /deep/.el-input__inner {
+          padding-right: 50px;
+        }
+        /deep/.el-select {
+          width: 150px;
+        }
+        .search_k {
+          margin-left: 30px;
+        }
+        .search_btn {
+          margin-left: 50px;
+          display: flex;
+          justify-content: space-between;
+          width: 300px;
+        }
+      }
+    }
+  }
+  // .table {
+  //   max-width: 1370px;
+  // }
+  /deep/.el-table__body-wrapper {
+    max-height: 440px;
+    overflow-y: auto;
+  }
+  .paging {
+    display: flex;
+    align-items: center;
+    position: absolute;
+    bottom: 15px;
+    right: 50px;
+    & > span {
+      margin-right: 15px;
+      font-size: 13px;
+    }
+  }
+  .disNo {
+    color: #ccc !important;
+  }
+}
+</style>

+ 160 - 0
houtai/src/views/tab3/index.vue

@@ -0,0 +1,160 @@
+<template>
+  <div class="tab6">
+    <div class="insideTop">
+      操作日志
+    </div>
+    <div class="obstruct"></div>
+    <!-- 主要内容 -->
+    <div class="conten">
+      <!-- <div class="search"  @keyup.enter="searchBtn">
+        <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%">
+          <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">
+      <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/tab2'
+export default {
+  name: 'tab6',
+  components: {},
+  data () {
+    // 这里存放数据
+    return {
+      total: 0,
+      formData: {
+        pageNum: 1,
+        pageSize: 10,
+        searchKey: ''
+      },
+      tableData: []
+    }
+  },
+  // 监听属性 类似于data概念
+  computed: {},
+  // 监控data中的数据变化
+  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 () {},
+  beforeCreate () {}, // 生命周期 - 创建之前
+  beforeMount () {}, // 生命周期 - 挂载之前
+  beforeUpdate () {}, // 生命周期 - 更新之前
+  updated () {}, // 生命周期 - 更新之后
+  beforeDestroy () {}, // 生命周期 - 销毁之前
+  destroyed () {}, // 生命周期 - 销毁完成
+  activated () {} // 如果页面有keep-alive缓存功能,这个函数会触发
+}
+</script>
+<style lang='less' scoped>
+.tab6 {
+  height: 100%;
+  .insideTop .add{
+    right: 55px;
+  }
+  .conten {
+    padding: 15px 30px 0;
+    height: calc(100% - 32px);
+    .classify {
+      text-align: center;
+      width: 40px;
+      padding-bottom: 10px;
+      color: #b9412e;
+      border-bottom: 2px solid #b9412e;
+    }
+    .search {
+      display: flex;
+      margin-bottom: 20px;
+      position: relative;
+      margin-top: 12px;
+      height: 40px;
+      .search_k {
+        margin-left: 30px;
+      }
+      .search_btn {
+        margin-left: 30px;
+        display: flex;
+        justify-content: space-between;
+        width: 100px;
+      }
+    }
+    .table {
+      max-width: 1533px;
+    }
+    /deep/.el-table__body-wrapper {
+      max-height: 528px;
+      overflow-y: auto;
+    }
+  }
+  .paging {
+    position: absolute;
+    bottom: 15px;
+    right: 50px;
+  }
+}
+</style>

+ 3 - 0
houtai/vue.config.js

@@ -0,0 +1,3 @@
+module.exports = {
+  publicPath: './'
+}