Ver código fonte

配置文件登录页

zcy 4 anos atrás
pai
commit
a3949863aa
14 arquivos alterados com 491 adições e 461 exclusões
  1. 1 1
      .env.development
  2. 1 1
      .env.production
  3. 1 1
      .env.staging
  4. 0 57
      mock/index.js
  5. 0 81
      mock/mock-server.js
  6. 0 29
      mock/table.js
  7. 0 84
      mock/user.js
  8. 0 25
      mock/utils.js
  9. 9 2
      src/api/user.js
  10. 261 0
      src/mixin/listMixin.js
  11. 3 2
      src/store/modules/user.js
  12. 26 23
      src/utils/request.js
  13. 188 153
      src/views/login/index.vue
  14. 1 2
      vue.config.js

+ 1 - 1
.env.development

@@ -2,4 +2,4 @@
 ENV = 'development'
 
 # base api
-VUE_APP_BASE_API = '/dev-api'
+VUE_APP_BASE_API = 'http://railway.iamsee.com'

+ 1 - 1
.env.production

@@ -2,5 +2,5 @@
 ENV = 'production'
 
 # base api
-VUE_APP_BASE_API = '/prod-api'
+VUE_APP_BASE_API = 'http://railway.iamsee.com'
 

+ 1 - 1
.env.staging

@@ -4,5 +4,5 @@ NODE_ENV = production
 ENV = 'staging'
 
 # base api
-VUE_APP_BASE_API = '/stage-api'
+VUE_APP_BASE_API = 'http://railway.iamsee.com'
 

+ 0 - 57
mock/index.js

@@ -1,57 +0,0 @@
-const Mock = require('mockjs')
-const { param2Obj } = require('./utils')
-
-const user = require('./user')
-const table = require('./table')
-
-const mocks = [
-  ...user,
-  ...table
-]
-
-// for front mock
-// please use it cautiously, it will redefine XMLHttpRequest,
-// which will cause many of your third-party libraries to be invalidated(like progress event).
-function mockXHR() {
-  // mock patch
-  // https://github.com/nuysoft/Mock/issues/300
-  Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
-  Mock.XHR.prototype.send = function() {
-    if (this.custom.xhr) {
-      this.custom.xhr.withCredentials = this.withCredentials || false
-
-      if (this.responseType) {
-        this.custom.xhr.responseType = this.responseType
-      }
-    }
-    this.proxy_send(...arguments)
-  }
-
-  function XHR2ExpressReqWrap(respond) {
-    return function(options) {
-      let result = null
-      if (respond instanceof Function) {
-        const { body, type, url } = options
-        // https://expressjs.com/en/4x/api.html#req
-        result = respond({
-          method: type,
-          body: JSON.parse(body),
-          query: param2Obj(url)
-        })
-      } else {
-        result = respond
-      }
-      return Mock.mock(result)
-    }
-  }
-
-  for (const i of mocks) {
-    Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
-  }
-}
-
-module.exports = {
-  mocks,
-  mockXHR
-}
-

+ 0 - 81
mock/mock-server.js

@@ -1,81 +0,0 @@
-const chokidar = require('chokidar')
-const bodyParser = require('body-parser')
-const chalk = require('chalk')
-const path = require('path')
-const Mock = require('mockjs')
-
-const mockDir = path.join(process.cwd(), 'mock')
-
-function registerRoutes(app) {
-  let mockLastIndex
-  const { mocks } = require('./index.js')
-  const mocksForServer = mocks.map(route => {
-    return responseFake(route.url, route.type, route.response)
-  })
-  for (const mock of mocksForServer) {
-    app[mock.type](mock.url, mock.response)
-    mockLastIndex = app._router.stack.length
-  }
-  const mockRoutesLength = Object.keys(mocksForServer).length
-  return {
-    mockRoutesLength: mockRoutesLength,
-    mockStartIndex: mockLastIndex - mockRoutesLength
-  }
-}
-
-function unregisterRoutes() {
-  Object.keys(require.cache).forEach(i => {
-    if (i.includes(mockDir)) {
-      delete require.cache[require.resolve(i)]
-    }
-  })
-}
-
-// for mock server
-const responseFake = (url, type, respond) => {
-  return {
-    url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
-    type: type || 'get',
-    response(req, res) {
-      console.log('request invoke:' + req.path)
-      res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
-    }
-  }
-}
-
-module.exports = app => {
-  // parse app.body
-  // https://expressjs.com/en/4x/api.html#req.body
-  app.use(bodyParser.json())
-  app.use(bodyParser.urlencoded({
-    extended: true
-  }))
-
-  const mockRoutes = registerRoutes(app)
-  var mockRoutesLength = mockRoutes.mockRoutesLength
-  var mockStartIndex = mockRoutes.mockStartIndex
-
-  // watch files, hot reload mock server
-  chokidar.watch(mockDir, {
-    ignored: /mock-server/,
-    ignoreInitial: true
-  }).on('all', (event, path) => {
-    if (event === 'change' || event === 'add') {
-      try {
-        // remove mock routes stack
-        app._router.stack.splice(mockStartIndex, mockRoutesLength)
-
-        // clear routes cache
-        unregisterRoutes()
-
-        const mockRoutes = registerRoutes(app)
-        mockRoutesLength = mockRoutes.mockRoutesLength
-        mockStartIndex = mockRoutes.mockStartIndex
-
-        console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed  ${path}`))
-      } catch (error) {
-        console.log(chalk.redBright(error))
-      }
-    }
-  })
-}

+ 0 - 29
mock/table.js

@@ -1,29 +0,0 @@
-const Mock = require('mockjs')
-
-const data = Mock.mock({
-  'items|30': [{
-    id: '@id',
-    title: '@sentence(10, 20)',
-    'status|1': ['published', 'draft', 'deleted'],
-    author: 'name',
-    display_time: '@datetime',
-    pageviews: '@integer(300, 5000)'
-  }]
-})
-
-module.exports = [
-  {
-    url: '/vue-admin-template/table/list',
-    type: 'get',
-    response: config => {
-      const items = data.items
-      return {
-        code: 20000,
-        data: {
-          total: items.length,
-          items: items
-        }
-      }
-    }
-  }
-]

+ 0 - 84
mock/user.js

@@ -1,84 +0,0 @@
-
-const tokens = {
-  admin: {
-    token: 'admin-token'
-  },
-  editor: {
-    token: 'editor-token'
-  }
-}
-
-const users = {
-  'admin-token': {
-    roles: ['admin'],
-    introduction: 'I am a super administrator',
-    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
-    name: 'Super Admin'
-  },
-  'editor-token': {
-    roles: ['editor'],
-    introduction: 'I am an editor',
-    avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
-    name: 'Normal Editor'
-  }
-}
-
-module.exports = [
-  // user login
-  {
-    url: '/vue-admin-template/user/login',
-    type: 'post',
-    response: config => {
-      const { username } = config.body
-      const token = tokens[username]
-
-      // mock error
-      if (!token) {
-        return {
-          code: 60204,
-          message: 'Account and password are incorrect.'
-        }
-      }
-
-      return {
-        code: 20000,
-        data: token
-      }
-    }
-  },
-
-  // get user info
-  {
-    url: '/vue-admin-template/user/info\.*',
-    type: 'get',
-    response: config => {
-      const { token } = config.query
-      const info = users[token]
-
-      // mock error
-      if (!info) {
-        return {
-          code: 50008,
-          message: 'Login failed, unable to get user details.'
-        }
-      }
-
-      return {
-        code: 20000,
-        data: info
-      }
-    }
-  },
-
-  // user logout
-  {
-    url: '/vue-admin-template/user/logout',
-    type: 'post',
-    response: _ => {
-      return {
-        code: 20000,
-        data: 'success'
-      }
-    }
-  }
-]

+ 0 - 25
mock/utils.js

@@ -1,25 +0,0 @@
-/**
- * @param {string} url
- * @returns {Object}
- */
-function param2Obj(url) {
-  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
-  if (!search) {
-    return {}
-  }
-  const obj = {}
-  const searchArr = search.split('&')
-  searchArr.forEach(v => {
-    const index = v.indexOf('=')
-    if (index !== -1) {
-      const name = v.substring(0, index)
-      const val = v.substring(index + 1, v.length)
-      obj[name] = val
-    }
-  })
-  return obj
-}
-
-module.exports = {
-  param2Obj
-}

+ 9 - 2
src/api/user.js

@@ -1,8 +1,15 @@
 import request from '@/utils/request'
-
+export function captchaImage(params) {
+  return request({
+    url: '/captchaImage',
+    responseType: 'blob',
+    method: 'get',
+    params
+  })
+}
 export function login(data) {
   return request({
-    url: '/vue-admin-template/user/login',
+    url: '/login',
     method: 'post',
     data
   })

+ 261 - 0
src/mixin/listMixin.js

@@ -0,0 +1,261 @@
+/**
+ * 新增修改完成调用 modalFormOk方法 编辑弹框组件ref定义为modalForm
+ * 高级查询按钮调用 superQuery方法  高级查询组件ref定义为superQueryModal
+ * data中url定义 list为查询列表  delete为删除单条记录  deleteBatch为批量删除
+ */
+import { filterObj } from '@/utils/util'
+import { deleteAction, getAction, downFile, getFileAccessHttpUrl } from '@/api/manage'
+import Vue from 'vue'
+import { ACCESS_TOKEN, TENANT_ID } from '@/store/mutation-types'
+import store from '@/store'
+
+export const JeecgListMixin = {
+  data() {
+    return {
+      /* 查询条件-请不要在queryParam中声明非字符串值的属性 */
+      queryParam: {},
+      /* 数据源 */
+      dataSource: [],
+      /* 分页参数 */
+      ipagination: {
+        current: 1,
+        pageSize: 10,
+        pageSizeOptions: ['10', '20', '30'],
+        showTotal: (total, range) => {
+          return range[0] + '-' + range[1] + ' 共' + total + '条'
+        },
+        showQuickJumper: true,
+        showSizeChanger: true,
+        total: 0
+      },
+      /* 排序参数 */
+      isorter: {
+        column: 'createTime',
+        order: 'desc'
+      },
+      /* 筛选参数 */
+      filters: {},
+      /* table加载状态 */
+      loading: false,
+      /* table选中keys*/
+      selectedRowKeys: [],
+      /* table选中records*/
+      selectionRows: [],
+      /* 查询折叠 */
+      toggleSearchStatus: false,
+      /* 高级查询条件生效状态 */
+      superQueryFlag: false,
+      /* 高级查询条件 */
+      superQueryParams: '',
+      /** 高级查询拼接方式 */
+      superQueryMatchType: 'and'
+    }
+  },
+  created() {
+    if (!this.disableMixinCreated) {
+      console.log(' -- mixin created -- ')
+      this.loadData()
+      // 初始化字典配置 在自己页面定义
+      this.initDictConfig()
+    }
+  },
+  computed: {
+    // token header
+    tokenHeader() {
+      const head = { 'X-Access-Token': Vue.ls.get(ACCESS_TOKEN) }
+      const tenantid = Vue.ls.get(TENANT_ID)
+      if (tenantid) {
+        head['tenant-id'] = tenantid
+      }
+      return head
+    }
+  },
+  methods: {
+    loadData(arg) {
+      if (!this.url.list) {
+        this.$message.error('请设置url.list属性!')
+        return
+      }
+      // 加载数据 若传入参数1则加载第一页的内容
+      if (arg === 1) {
+        this.ipagination.current = 1
+      }
+      var params = this.getQueryParams()// 查询条件
+      this.loading = true
+      getAction(this.url.list, params).then((res) => {
+        if (res.success) {
+          // update-begin---author:zhangyafei    Date:20201118  for:适配不分页的数据列表------------
+          this.dataSource = res.result.records || res.result
+          if (res.result.total) {
+            this.ipagination.total = res.result.total
+          } else {
+            this.ipagination.total = 0
+          }
+          // update-end---author:zhangyafei    Date:20201118  for:适配不分页的数据列表------------
+        } else {
+          this.$message.warning(res.message)
+        }
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    initDictConfig() {
+      console.log('--这是一个假的方法!')
+    },
+    handleSuperQuery(params, matchType) {
+      // 高级查询方法
+      if (!params) {
+        this.superQueryParams = ''
+        this.superQueryFlag = false
+      } else {
+        this.superQueryFlag = true
+        this.superQueryParams = JSON.stringify(params)
+        this.superQueryMatchType = matchType
+      }
+      this.loadData(1)
+    },
+    getQueryParams() {
+      // 获取查询条件
+      const sqp = {}
+      if (this.superQueryParams) {
+        sqp['superQueryParams'] = encodeURI(this.superQueryParams)
+        sqp['superQueryMatchType'] = this.superQueryMatchType
+      }
+      var param = Object.assign(sqp, this.queryParam, this.isorter, this.filters)
+      param.field = this.getQueryField()
+      param.pageNo = this.ipagination.current
+      param.pageSize = this.ipagination.pageSize
+      return filterObj(param)
+    },
+    getQueryField() {
+      // TODO 字段权限控制
+      var str = 'id,'
+      this.columns.forEach(function(value) {
+        str += ',' + value.dataIndex
+      })
+      return str
+    },
+
+    onSelectChange(selectedRowKeys, selectionRows) {
+      this.selectedRowKeys = selectedRowKeys
+      this.selectionRows = selectionRows
+    },
+    onClearSelected() {
+      this.selectedRowKeys = []
+      this.selectionRows = []
+    },
+    searchQuery() {
+      this.loadData(1)
+    },
+    superQuery() {
+      this.$refs.superQueryModal.show()
+    },
+    searchReset() {
+      this.queryParam = {}
+      this.loadData(1)
+    },
+    batchDel: function() {
+      if (!this.url.deleteBatch) {
+        this.$message.error('请设置url.deleteBatch属性!')
+        return
+      }
+      if (this.selectedRowKeys.length <= 0) {
+        this.$message.warning('请选择一条记录!')
+        return
+      } else {
+        var ids = ''
+        for (var a = 0; a < this.selectedRowKeys.length; a++) {
+          ids += this.selectedRowKeys[a] + ','
+        }
+        var that = this
+        this.$confirm({
+          title: '确认删除',
+          content: '是否删除选中数据?',
+          onOk: function() {
+            that.loading = true
+            deleteAction(that.url.deleteBatch, { ids: ids }).then((res) => {
+              if (res.success) {
+                // 重新计算分页问题
+                that.reCalculatePage(that.selectedRowKeys.length)
+                that.$message.success(res.message)
+                that.loadData()
+                that.onClearSelected()
+              } else {
+                that.$message.warning(res.message)
+              }
+            }).finally(() => {
+              that.loading = false
+            })
+          }
+        })
+      }
+    },
+    handleDelete: function(id) {
+      if (!this.url.delete) {
+        this.$message.error('请设置url.delete属性!')
+        return
+      }
+      var that = this
+      deleteAction(that.url.delete, { id: id }).then((res) => {
+        if (res.success) {
+          // 重新计算分页问题
+          that.reCalculatePage(1)
+          that.$message.success(res.message)
+          that.loadData()
+        } else {
+          that.$message.warning(res.message)
+        }
+      })
+    },
+    reCalculatePage(count) {
+      // 总数量-count
+      const total = this.ipagination.total - count
+      // 获取删除后的分页数
+      const currentIndex = Math.ceil(total / this.ipagination.pageSize)
+      // 删除后的分页数<所在当前页
+      if (currentIndex < this.ipagination.current) {
+        this.ipagination.current = currentIndex
+      }
+      console.log('currentIndex', currentIndex)
+    },
+    handleEdit: function(record) {
+      this.$refs.modalForm.edit(record)
+      this.$refs.modalForm.title = '编辑'
+      this.$refs.modalForm.disableSubmit = false
+    },
+    handleAdd: function() {
+      this.$refs.modalForm.add()
+      this.$refs.modalForm.title = '新增'
+      this.$refs.modalForm.disableSubmit = false
+    },
+    handleTableChange(pagination, filters, sorter) {
+      // 分页、排序、筛选变化时触发
+      // TODO 筛选
+      console.log(pagination)
+      if (Object.keys(sorter).length > 0) {
+        this.isorter.column = sorter.field
+        this.isorter.order = sorter.order == 'ascend' ? 'asc' : 'desc'
+      }
+      this.ipagination = pagination
+      this.loadData()
+    },
+    handleToggleSearch() {
+      this.toggleSearchStatus = !this.toggleSearchStatus
+    },
+    // 给popup查询使用(查询区域不支持回填多个字段,限制只返回一个字段)
+    getPopupField(fields) {
+      return fields.split(',')[0]
+    },
+    modalFormOk() {
+      // 新增/修改 成功时,重载列表
+      this.loadData()
+      // 清空列表选中
+      this.onClearSelected()
+    },
+    handleDetail: function(record) {
+      this.$refs.modalForm.edit(record)
+      this.$refs.modalForm.title = '详情'
+      this.$refs.modalForm.disableSubmit = true
+    }
+  }
+}

+ 3 - 2
src/store/modules/user.js

@@ -31,9 +31,10 @@ const mutations = {
 const actions = {
   // user login
   login({ commit }, userInfo) {
-    const { username, password } = userInfo
+    const { username, password, uuid, code } = userInfo
     return new Promise((resolve, reject) => {
-      login({ username: username.trim(), password: password }).then(response => {
+      login({ username: username.trim(), password: password, code: code, uuid: uuid }).then(response => {
+        debugger
         const { data } = response
         commit('SET_TOKEN', data.token)
         setToken(data.token)

+ 26 - 23
src/utils/request.js

@@ -43,32 +43,35 @@ service.interceptors.response.use(
    * You can also judge the status by HTTP Status Code
    */
   response => {
-    const res = response.data
-
-    // if the custom code is not 20000, it is judged as an error.
-    if (res.code !== 20000) {
-      Message({
-        message: res.message || 'Error',
-        type: 'error',
-        duration: 5 * 1000
-      })
+    if (response.headers['content-type'] === 'image/jpeg') {
+      return response.data
+    } else {
+      const res = response.data
+      // if the custom code is not 20000, it is judged as an error.
+      if (res.code !== 200) {
+        Message({
+          message: res.msg || 'Error',
+          type: 'error',
+          duration: 5 * 1000
+        })
 
-      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
-      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
-        // to re-login
-        MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
-          confirmButtonText: 'Re-Login',
-          cancelButtonText: 'Cancel',
-          type: 'warning'
-        }).then(() => {
-          store.dispatch('user/resetToken').then(() => {
-            location.reload()
+        // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
+        if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
+          // to re-login
+          MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
+            confirmButtonText: 'Re-Login',
+            cancelButtonText: 'Cancel',
+            type: 'warning'
+          }).then(() => {
+            store.dispatch('user/resetToken').then(() => {
+              location.reload()
+            })
           })
-        })
+        }
+        return Promise.reject(new Error(res.msg || 'Error'))
+      } else {
+        return res
       }
-      return Promise.reject(new Error(res.message || 'Error'))
-    } else {
-      return res
     }
   },
   error => {

+ 188 - 153
src/views/login/index.vue

@@ -1,89 +1,128 @@
 <template>
   <div class="login-container">
-    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
-
-      <div class="title-container">
-        <h3 class="title">Login Form</h3>
-      </div>
-
-      <el-form-item prop="username">
-        <span class="svg-container">
-          <svg-icon icon-class="user" />
-        </span>
-        <el-input
-          ref="username"
-          v-model="loginForm.username"
-          placeholder="Username"
-          name="username"
-          type="text"
-          tabindex="1"
+    <el-row class="window-login">
+      <el-col :span="9">
+        <div id="u35">
+          <div id="u37">
+            <div id="u39">
+              <div id="u39_text" class="text ">
+                <span></span>
+              </div>
+            </div>
+            <div id="u38">
+              <div id="u38_text" class="text">
+                <p style="font-size:20px;line-height:normal;">
+                  <span style="font-family:'FZXBSJW--GB1-0', 'FZXiaoBiaoSong-B05S', sans-serif;font-weight:400;">
+                    牵引供电维护管理信息化系统
+                  </span>
+                </p>
+                <p style="font-size:14px;line-height:24px;margin-top: 5px">
+                  <span style="font-family:'Helvetica', sans-serif;font-weight:400;">
+                    Information System Platform
+                  </span>
+                </p>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-col>
+      <el-col :span="15">
+        <el-form
+          ref="loginForm"
+          :model="loginForm"
+          :rules="loginRules"
+          class="login-form"
           auto-complete="on"
-        />
-      </el-form-item>
-
-      <el-form-item prop="password">
-        <span class="svg-container">
-          <svg-icon icon-class="password" />
-        </span>
-        <el-input
-          :key="passwordType"
-          ref="password"
-          v-model="loginForm.password"
-          :type="passwordType"
-          placeholder="Password"
-          name="password"
-          tabindex="2"
-          auto-complete="on"
-          @keyup.enter.native="handleLogin"
-        />
-        <span class="show-pwd" @click="showPwd">
-          <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
-        </span>
-      </el-form-item>
+          label-position="left"
+        >
+          <div class="title-container" style="margin-top:45px;margin-bottom: 80px">
+            <h2 class="title">用户登录 <span style="font-size: 15px">USER LOGIN</span></h2>
+          </div>
+
+          <el-form-item prop="username">
+            <el-input
+              ref="username"
+              v-model="loginForm.username"
+              placeholder="请输入用户名"
+              name="username"
+              prefix-icon="el-icon-s-check"
+              type="text"
+              tabindex="1"
+              auto-complete="on"
+              size="medium"
+            />
+          </el-form-item>
 
-      <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
+          <el-form-item prop="password" style="position: relative">
+            <el-input
+              :key="passwordType"
+              ref="password"
+              v-model="loginForm.password"
+              :type="passwordType"
+              placeholder="请输入密码"
+              name="password"
+              prefix-icon="el-icon-lock"
+              tabindex="2"
+              auto-complete="on"
+            />
+            <span class="show-pwd" style="position: absolute;right: 12px;top: 8px;" @click="showPwd">
+              <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
+            </span>
+          </el-form-item>
 
-      <div class="tips">
-        <span style="margin-right:20px;">username: admin</span>
-        <span> password: any</span>
-      </div>
+          <el-form-item prop="code">
+            <el-input
+              ref="code"
+              v-model="loginForm.code"
+              style="width: 70%;vertical-align:middle"
+              placeholder="请输入验证码"
+              prefix-icon="el-icon-lock"
+              tabindex="2"
+              auto-complete="on"
+              @keyup.enter.native="handleLogin"
+            />
+            <img :src="imgSrc" alt="" style="margin-left:5%;width: 25%;height: 45px;vertical-align:middle;" @click="captchaImage">
+          </el-form-item>
 
-    </el-form>
+          <el-form-item>
+            <el-tooltip class="item" effect="dark" content="请联系管理员重置密码" placement="top">
+              <el-button type="text" style="float: right;padding:0">忘记密码?</el-button>
+            </el-tooltip>
+          </el-form-item>
+          <el-button
+            :loading="loading"
+            type="primary"
+            style="width:100%;margin-bottom:30px;"
+            @click.native.prevent="handleLogin"
+          ><h2 style="margin: 5px">登  录</h2>
+          </el-button>
+        </el-form>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
 <script>
-import { validUsername } from '@/utils/validate'
-
+import { captchaImage } from '@/api/user'
 export default {
   name: 'Login',
   data() {
-    const validateUsername = (rule, value, callback) => {
-      if (!validUsername(value)) {
-        callback(new Error('Please enter the correct user name'))
-      } else {
-        callback()
-      }
-    }
-    const validatePassword = (rule, value, callback) => {
-      if (value.length < 6) {
-        callback(new Error('The password can not be less than 6 digits'))
-      } else {
-        callback()
-      }
-    }
     return {
       loginForm: {
-        username: 'admin',
-        password: '111111'
+        username: '',
+        password: '',
+        code: '',
+        uuid: ''
       },
       loginRules: {
-        username: [{ required: true, trigger: 'blur', validator: validateUsername }],
-        password: [{ required: true, trigger: 'blur', validator: validatePassword }]
+        username: [{ required: true, trigger: 'blur', message: '请输入用户名' }],
+        password: [{ required: true, trigger: 'blur', message: '请输入密码' }],
+        code: [{ required: true, trigger: 'blur', message: '请输入验证码' }]
       },
       loading: false,
       passwordType: 'password',
-      redirect: undefined
+      redirect: undefined,
+      imgSrc: ''
     }
   },
   watch: {
@@ -94,7 +133,16 @@ export default {
       immediate: true
     }
   },
+  created() {
+    this.captchaImage()
+  },
   methods: {
+    captchaImage() {
+      captchaImage({ type: 'math' }).then(res => {
+        const url = window.URL.createObjectURL(res)
+        this.imgSrc = url
+      })
+    },
     showPwd() {
       if (this.passwordType === 'password') {
         this.passwordType = ''
@@ -126,112 +174,99 @@ export default {
 </script>
 
 <style lang="scss">
-/* 修复input 背景不协调 和光标变色 */
-/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
+  .login-container {
+    .el-form {
+      width: 90%;
+      margin: 0 auto;
+      .el-input__inner{
+        height: 50px;
+      }
+    }
+  }
+</style>
 
-$bg:#283443;
-$light_gray:#fff;
-$cursor: #fff;
+<style lang="css" scoped>
 
-@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
-  .login-container .el-input input {
-    color: $cursor;
+  .login-container {
+    min-height: 100%;
+    width: 100%;
+    overflow: hidden;
   }
-}
 
-/* reset element-ui css */
-.login-container {
-  .el-input {
-    display: inline-block;
-    height: 47px;
-    width: 85%;
-
-    input {
-      background: transparent;
-      border: 0px;
-      -webkit-appearance: none;
-      border-radius: 0px;
-      padding: 12px 5px 12px 15px;
-      color: $light_gray;
-      height: 47px;
-      caret-color: $cursor;
-
-      &:-webkit-autofill {
-        box-shadow: 0 0 0px 1000px $bg inset !important;
-        -webkit-text-fill-color: $cursor !important;
-      }
-    }
+  .window-login {
+    overflow: hidden;
+    border-radius: 15px;
+    margin: 0 auto;
+    margin-top: 9%;
+    width: 800px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)
   }
 
-  .el-form-item {
-    border: 1px solid rgba(255, 255, 255, 0.1);
-    background: rgba(0, 0, 0, 0.1);
-    border-radius: 5px;
-    color: #454545;
+  #u35 {
+    width: 100%;
+    height: 540px;
+    font-family: '微软雅黑', sans-serif;
+    font-weight: 400;
+    font-style: normal;
+    background-image: url(https://axure-file.lanhuapp.com/83ee941a-8080-4603-ab36-dc56ce561371__b332944a16cd91abd30b3a70f019b96f.svg);
   }
-}
-</style>
 
-<style lang="scss" scoped>
-$bg:#2d3a4b;
-$dark_gray:#889aa4;
-$light_gray:#eee;
-
-.login-container {
-  min-height: 100%;
-  width: 100%;
-  background-color: $bg;
-  overflow: hidden;
+  #u37 {
+    width: 100%;
+    height: 100%;
+    background-image: url(https://axure-file.lanhuapp.com/83ee941a-8080-4603-ab36-dc56ce561371__3da133640c87c7921faf320a11a3196b.svg);
+    background-position: left top;
+    background-repeat: no-repeat;
+    background-attachment: scroll;
+    background-size: 1440px 712px;
+    background-origin: border-box;
+    border: none;
+  }
 
-  .login-form {
-    position: relative;
-    width: 520px;
-    max-width: 100%;
-    padding: 160px 35px 0;
-    margin: 0 auto;
-    overflow: hidden;
+  #u38 {
+    height: 60px;
+    color: #FFFFFF;
   }
 
-  .tips {
-    font-size: 14px;
-    color: #fff;
-    margin-bottom: 10px;
+  #u38 p {
+    margin: 0;
+  }
 
-    span {
-      &:first-of-type {
-        margin-right: 16px;
-      }
-    }
+  #u38 .text {
+    text-align: center;
+    padding: 2px 2px 2px 2px;
+    box-sizing: border-box;
+    width: 100%;
   }
 
-  .svg-container {
-    padding: 6px 5px 6px 15px;
-    color: $dark_gray;
-    vertical-align: middle;
-    width: 30px;
-    display: inline-block;
+  #u38_text {
+    word-wrap: break-word;
+    text-transform: none;
   }
 
-  .title-container {
+  #u39 {
     position: relative;
-
-    .title {
-      font-size: 26px;
-      color: $light_gray;
-      margin: 0px auto 40px auto;
-      text-align: center;
-      font-weight: bold;
-    }
+    margin: 0 auto;
+    width: 50px;
+    height: 100px;
+    display: flex;
+    font-family: 'Font Awesome 5 Pro Solid', 'Font Awesome 5 Pro Regular', 'Font Awesome 5 Pro', sans-serif;
+    font-weight: 900;
+    font-style: normal;
+    font-size: 72px;
+    color: #FFFFFF;
   }
 
-  .show-pwd {
+  #u39 .text {
     position: absolute;
-    right: 10px;
-    top: 7px;
-    font-size: 16px;
-    color: $dark_gray;
-    cursor: pointer;
-    user-select: none;
+    align-self: center;
+    padding: 0;
+    box-sizing: border-box;
+    width: 100%;
+  }
+
+  #u39_text {
+    word-wrap: break-word;
+    text-transform: none;
   }
-}
 </style>

+ 1 - 2
vue.config.js

@@ -35,8 +35,7 @@ module.exports = {
     overlay: {
       warnings: false,
       errors: true
-    },
-    before: require('./mock/mock-server.js')
+    }
   },
   configureWebpack: {
     // provide the app's title in webpack's name field, so that