Browse Source

提交测试

hjs 1 year ago
parent
commit
44f82cd97d

+ 1 - 1
.env.development

@@ -3,5 +3,5 @@ ENV = 'development'
 
 # base api
 # VUE_APP_BASE_API = '/dev-api'
-VUE_APP_BASE_API = 'http://192.168.11.11:8081/hanghui-server-platform'
+VUE_APP_BASE_API = 'http://192.168.11.3:8081/hanghui-server-platform'
 # VUE_APP_BASE_API = 'https://tx.hz-hanghui.com:8088/hanghui-server-platform'

+ 10 - 0
src/api/ordinary_user.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 上传图片
+export function pictureLocal(data) {
+  return request({
+    url: 'https://tx.hz-hanghui.com:8088/yx-fyzd/upload/pictureLocal',
+    method: 'post',
+    data
+  })
+}

BIN
src/assets/default-img-home.jpg


+ 14 - 0
src/router/index.js

@@ -115,6 +115,20 @@ export const constantRoutes = [
         name: 'index',
         component: () => import('@/views/device/index'),
         meta: { title: '设备授权列表' }
+      },
+      {
+        path: 'add',
+        name: 'add',
+        hidden: true,
+        component: () => import('@/views/device/add'),
+        meta: { title: '添加设备' }
+      },
+      {
+        path: 'change',
+        name: 'change',
+        hidden: true,
+        component: () => import('@/views/device/change'),
+        meta: { title: '编辑设备' }
       }
     ]
   },

+ 1 - 1
src/utils/validate.js

@@ -16,5 +16,5 @@ export function isExternal(path) {
  */
 export function validUsername(str) {
   const valid_map = ['admin', 'editor']
-  return valid_map.indexOf(str.trim()) >= 0
+  return str && valid_map.indexOf(str.trim()) >= 0
 }

+ 50 - 0
src/views/device/add.vue

@@ -0,0 +1,50 @@
+<template>
+  <div class="app-container">
+    <div class="head">
+      添加设备
+      <el-button type="primary" size="mini" style="margin-left: 20px;" @click="back">返回</el-button>
+    </div>
+    <edit-device style="margin-left: 40px;" @finish="back" />
+    <div class="foot-layout">
+      <el-button style="margin-left: 20px;width: 120px;" @click="back">取 消</el-button>
+      <div style="width: 80px;" />
+      <el-button type="primary" style="width: 120px;" @click="submit">提 交</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import EditDevice from './components/edit'
+
+export default {
+  components: { EditDevice },
+  data() {
+    return {}
+  },
+  mounted() {
+    // this.initData()
+  },
+  methods: {
+    back() {
+      this.$router.go(-1)
+    }
+  }
+}
+</script>
+
+<style scoped>
+.head {
+  margin-left: 16px;
+  font-weight: 600;
+  font-size: 18px;
+  color: #333333;
+}
+.foot-layout {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 34px;
+  padding-right: 180px;
+  margin-bottom: 20px;
+}
+</style>

+ 61 - 0
src/views/device/change.vue

@@ -0,0 +1,61 @@
+<template>
+  <div class="app-container">
+    <div class="head">
+      编辑设备
+      <el-button type="primary" size="mini" style="margin-left: 20px;" @click="back">返回</el-button>
+    </div>
+    <edit-device :obj="obj" style="margin-left: 40px;" @finish="back" />
+    <div class="foot-layout">
+      <el-button style="margin-left: 20px;width: 120px;" @click="back">取 消</el-button>
+      <div style="width: 80px;" />
+      <el-button type="primary" style="width: 120px;" @click="submit">提 交</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import EditDevice from './components/edit'
+
+export default {
+  components: { EditDevice },
+  data() {
+    return {
+      obj: null
+    }
+  },
+  mounted() {
+    this.initData()
+  },
+  methods: {
+    back() {
+      this.$router.go(-1)
+    },
+    initData() {
+      if (this.$route.query && this.$route.query.obj) {
+        try {
+          this.obj = JSON.parse(decodeURIComponent(this.$route.query.obj))
+        } catch (e) {
+          this.obj = null
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.head {
+  margin-left: 16px;
+  font-weight: 600;
+  font-size: 18px;
+  color: #333333;
+}
+.foot-layout {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 34px;
+  padding-right: 180px;
+  margin-bottom: 20px;
+}
+</style>

+ 564 - 0
src/views/device/components/edit.vue

@@ -0,0 +1,564 @@
+<template>
+  <div class="wrap-layout">
+    <el-form
+      ref="form"
+      :model="form"
+      :rules="rules"
+      label-width="150px"
+      label-position="left"
+    >
+      <div class="item-layout">
+        <span class="prompt">设备基本信息</span>
+        <div class="display-config-layout">
+          <el-form-item label="设备sn" prop="sn" required>
+            <el-input v-model="form.sn" placeholder="请输入设备sn" maxlength="50" />
+          </el-form-item>
+          <el-form-item label="服务商平台名称" prop="tenantId" required>
+            <el-select v-model="form.tenantId" placeholder="服务商平台名称" filterable>
+              <el-option v-for="(item, index) in merchantLists" :key="index" :label="item.name" :value="item.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="公司名称" prop="company" required>
+            <el-input v-model="form.company" placeholder="请输入公司名称" maxlength="50" />
+          </el-form-item>
+          <el-form-item label="场景" prop="sceneId" :required="false">
+            <el-select v-model="form.sceneId" placeholder="请选择场景" clearable>
+              <el-option v-for="(item, index) in sceneLists" :key="index" :label="item.sceneName" :value="item.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="模式" prop="mode" required>
+            <el-select v-model="form.mode" placeholder="请选择模式">
+              <el-option v-for="(item, index) in modeLists" :key="index" :label="item.value" :value="item.key" />
+            </el-select>
+          </el-form-item>
+          <el-form-item v-if="!(!form.mode || form.mode === 'public')" label="⽤户库" prop="userLibId" :required="false">
+            <el-select v-model="form.userLibId" placeholder="请选择⽤户库" clearable>
+              <el-option v-for="(item, index) in userlibLists" :key="index" :label="item.userLibName" :value="item.id" />
+            </el-select>
+          </el-form-item>
+        </div>
+      </div>
+      <div class="item-layout">
+        <span class="prompt">采集配置</span>
+        <div class="display-config-layout">
+          <el-form-item label="启用支付宝人脸能力" prop="useAlipayFace" required>
+            <el-radio-group v-model="form.useAlipayFace">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="启用身份证功能" prop="useIdcard">
+            <el-radio-group v-model="form.useIdcard">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="启用人证比对" prop="usePersonCard">
+            <el-radio-group v-model="form.usePersonCard">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="启用二维码功能" prop="useQrcode">
+            <el-radio-group v-model="form.useQrcode">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </div>
+      </div>
+      <div v-if="form.useAlipayFace" class="item-layout">
+        <span class="prompt">支付宝刷脸配置</span>
+        <div class="display-config-layout">
+          <el-form-item label="刷脸模式" prop="faceMode">
+            <el-radio-group v-model="form.faceMode">
+              <el-radio label="auto">自动</el-radio>
+              <el-radio label="click">点击</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="form.faceMode === 'click'" label="点击刷脸按钮的文本" prop="clickButtonText">
+            <el-input v-model="form.clickButtonText" placeholder="请输入点击刷脸按钮的文本" maxlength="50" />
+          </el-form-item>
+          <el-form-item v-if="form.faceMode === 'click'" label="是否抓拍人脸" prop="isCaptureFace">
+            <el-radio-group v-model="form.isCaptureFace">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item class="overlength" label="need1V1是否使用支付宝刷证提示页" prop="isNeed1V1">
+            <el-radio-group v-model="form.isNeed1V1">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </div>
+      </div>
+      <div class="item-layout">
+        <span class="prompt">联动平台配置</span>
+        <div class="display-config-layout">
+          <el-form-item label="启用联动平台" prop="useLinkage">
+            <el-radio-group v-model="form.useLinkage">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="form.useLinkage" label="联动平台地址" prop="linkageAds">
+            <el-input v-model="form.linkageAds" placeholder="请输入联动平台地址" maxlength="100" />
+          </el-form-item>
+        </div>
+      </div>
+      <div class="item-layout">
+        <span class="prompt">结果页配置</span>
+        <div class="display-config-layout">
+          <el-form-item class="overlength" label="刷脸成功结果页时长(1~10)" prop="successPageTime">
+            <el-input-number v-model="form.successPageTime" size="mini" :min="1" :max="10" />
+          </el-form-item>
+          <el-form-item class="overlength" label="刷脸失败结果页时长(1~10)" prop="failPageTime">
+            <el-input-number v-model="form.failPageTime" size="mini" :min="1" :max="10" />
+          </el-form-item>
+          <el-form-item label="开门信号" prop="useSerialPort">
+            <el-radio-group v-model="form.useSerialPort">
+              <el-radio label="default" style="margin-right: 40px;">继电器</el-radio>
+              <el-radio label="RS232">RS232</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="form.useSerialPort === 'RS232'" label="RS232默认信号" prop="signalNo">
+            <el-input v-model="form.signalNo" placeholder="请输入RS232默认信号" maxlength="100" />
+          </el-form-item>
+          <el-form-item label="成功语音" prop="sucVoice">
+            <el-input v-model="form.sucVoice" placeholder="请输入成功语音" maxlength="50" />
+          </el-form-item>
+          <el-form-item label="成功文字" prop="sucText">
+            <el-input v-model="form.sucText" placeholder="请输入成功文字" maxlength="50" />
+          </el-form-item>
+          <el-form-item label="失败语音" prop="failVoice">
+            <el-input v-model="form.failVoice" placeholder="请输入成功语音" maxlength="50" />
+          </el-form-item>
+          <el-form-item label="失败文字" prop="failText">
+            <el-input v-model="form.failText" placeholder="请输入失败文字" maxlength="50" />
+          </el-form-item>
+        </div>
+      </div>
+      <div class="item-layout">
+        <span class="prompt">页面背景配置</span>
+        <div class="display-config-layout">
+          <el-form-item label="首页图片配置" prop="homePageUrl">
+            <el-upload
+              name="file"
+              class="avatar-uploader"
+              action="#"
+              :show-file-list="false"
+              :http-request="(event) => { doUploadAvatar(event, 'homeImgUrl'); }"
+              :before-upload="beforeAvatarUpload"
+              :auto-upload="true"
+              accept="image/png,image/gif,image/jpg,image/jpeg"
+            >
+              <img v-if="!form.homeImgUrl" class="upload-img" src="../../../assets/default-img-home.jpg" alt="">
+              <div v-else class="upload-img">
+                <img :src="form.homeImgUrl">
+                <span class="del-img" @click.stop="handleRemove('homeImgUrl')">x</span>
+              </div>
+            </el-upload>
+          </el-form-item>
+          <el-form-item label="过渡图片配置" prop="transitionPageUrl">
+            <el-upload
+              name="file"
+              class="avatar-uploader"
+              action="#"
+              :show-file-list="false"
+              :http-request="(event) => { doUploadAvatar(event, 'transitionPageUrl'); }"
+              :before-upload="beforeAvatarUpload"
+              :auto-upload="true"
+              accept="image/png,image/gif,image/jpg,image/jpeg"
+            >
+              <!-- <view v-if="!form.transitionPageUrl">
+                <i class="el-icon-upload" />
+                <div class="el-upload__text">上传图片</div>
+              </view> -->
+              <i v-if="!form.transitionPageUrl" class="el-icon-plus avatar-uploader-icon" />
+              <div v-else class="upload-img">
+                <img :src="form.transitionPageUrl">
+                <span class="del-img" @click.stop="handleRemove('transitionPageUrl')">x</span>
+              </div>
+            </el-upload>
+          </el-form-item>
+        </div>
+      </div>
+      <div class="item-layout">
+        <span class="prompt">系统配置</span>
+        <div class="display-config-layout">
+          <el-form-item label="补光灯" prop="lightMode">
+            <el-select v-model="form.lightMode" placeholder="请选择补光灯模式">
+              <el-option v-for="(item, index) in lightModeLists" :key="index" :label="item.value" :value="item.key" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="语音音量(1~100)" prop="volume">
+            <el-input-number v-model="form.volume" size="mini" :min="1" :max="100" />
+          </el-form-item>
+          <el-form-item label="隐藏底部导航栏" prop="hideNavigationBar">
+            <el-radio-group v-model="form.hideNavigationBar">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="禁止下拉通知栏" prop="forbidPullDown">
+            <el-radio-group v-model="form.forbidPullDown">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </div>
+      </div>
+      <div class="item-layout">
+        <span class="prompt">zoloConfig摄像头配置</span>
+        <div class="display-config-layout">
+          <el-form-item class="overlength" label="摄像头显示角度(0~270)" prop="supAlgorithmAngle">
+            <el-input-number v-model="form.zoloConfig.supAlgorithmAngle" size="mini" :min="0" :max="270" />
+          </el-form-item>
+          <el-form-item class="overlength" label="RGB摄像头旋转角度(0~270)" prop="algorithmAngle">
+            <el-input-number v-model="form.zoloConfig.algorithmAngle" size="mini" :min="0" :max="270" />
+          </el-form-item>
+          <el-form-item class="overlength" label="IR摄像头旋转角度(0~270)" prop="displayAngle">
+            <el-input-number v-model="form.zoloConfig.displayAngle" size="mini" :min="1" :max="270" />
+          </el-form-item>
+          <el-form-item label="RGB摄像头镜像" prop="isMirror">
+            <el-radio-group v-model="form.zoloConfig.isMirror">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="IR摄像头镜像" prop="isDisplayMirror">
+            <el-radio-group v-model="form.zoloConfig.isDisplayMirror">
+              <el-radio :label="true">是</el-radio>
+              <el-radio :label="false">否</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </div>
+      </div>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { add } from '@/api/device'
+import { pictureLocal } from '@/api/ordinary_user'
+import { getAllList } from '@/api/merchant'
+import { getList as getSceneList } from '@/api/scene'
+import { getList as getUserlibList } from '@/api/userlib'
+
+export default {
+  name: 'EditDevice',
+  props: {
+    obj: {
+      type: Object,
+      default: () => {}
+    }
+  },
+  data() {
+    return {
+      submitLoading: false,
+      merchantLists: [],
+      sceneLists: [],
+      userlibLists: [],
+      modeLists: [
+        {
+          key: 'public',
+          value: '开放'
+        },
+        {
+          key: 'close',
+          value: '封闭'
+        },
+        {
+          key: 'elasticity',
+          value: '弹性'
+        }
+      ],
+      lightModeLists: [
+        {
+          key: 'auto',
+          value: '自动'
+        }
+      ],
+      form: {
+        // 点击刷脸按钮文本 默认 点击开始刷脸核验
+        clickButtonText: '点击开始刷脸核验',
+        // 公司名称
+        company: null,
+        // 刷脸模式: 点击/自动 click/auto 默认 auto
+        faceMode: 'auto',
+        // 刷脸失败结果页时长 1-10 默认值5
+        failPageTime: 5,
+        // 失败文字 默认: 比对失败,请联系现场工作人员
+        failText: '比对失败,请联系现场工作人员',
+        // 失败语音 默认: 比对失败,请联系现场工作人员
+        failVoice: '比对失败,请联系现场工作人员',
+        // 	禁止下拉通知栏 默认: false
+        forbidPullDown: false,
+        // 隐藏底部导航栏 默认: false
+        hideNavigationBar: false,
+        // 首页图片
+        homePageUrl: null,
+        id: null,
+        // 是否抓拍人脸 默认:false
+        isCaptureFace: false,
+        // need1V1是否使用支付宝刷证提示页 默认:true
+        isNeed1V1: true,
+        // 补光灯: 自动 auto 默认:auto
+        lightMode: 'auto',
+        // 	联动平台地址
+        linkageAds: null,
+        // 模式 mode: public/close/elasticity 三个参数分别代表 开放/封闭/弹性
+        mode: null,
+        // 场景id
+        sceneId: null,
+        // RS232默认信号
+        signalNo: null,
+        // 设备sn
+        sn: null,
+        // 授权状态 false:未授权 true:已授权
+        status: null,
+        // 成功文字 默认: 请通行
+        sucText: '请通行',
+        // 成功语音 默认: 请通行
+        sucVoice: '请通行',
+        // 刷脸成功结果页时长 1-10 默认值2
+        successPageTime: 2,
+        // 商户id tenantId
+        tenantId: null,
+        // 过渡图片
+        transitionPageUrl: null,
+        // 是否启用支付宝人脸能力 默认:true
+        useAlipayFace: true,
+        // 是否启用身份证功能 默认:true
+        useIdcard: true,
+        // 	是否启用联动平台 默认:true
+        useLinkage: true,
+        // 	是否人证比对 默认:false
+        usePersonCard: false,
+        // 是否启用二维码功能 默认:true
+        useQrcode: true,
+        // 	开门信号: 继电器/RS232 default/RS232 默认:default
+        useSerialPort: 'default',
+        // 用户库id
+        userLibId: null,
+        // 语音音量 0-100 默认值80
+        volume: 80,
+        // zoloConfig摄像头配置
+        zoloConfig: {
+          // RGB摄像头旋转角度 0-270 默认值270
+          algorithmAngle: 270,
+          // IR摄像头旋转角度 0-270 默认值270
+          displayAngle: 270,
+          // IR摄像头镜像 默认值false
+          isDisplayMirror: false,
+          // RGB摄像头镜像 默认值true
+          isMirror: true,
+          // 摄像头显示角度 0-270 默认值90
+          supAlgorithmAngle: 90
+        }
+      },
+      rules: {
+        sn: [
+          {
+            required: true,
+            message: '请输入设备sn',
+            trigger: 'blur'
+          }
+        ]
+      }
+    }
+  },
+  mounted() {
+    this.initData()
+  },
+  methods: {
+    initData() {
+      this.getMerchantList()
+      this.getSceneList()
+      this.getUserlibList()
+      if (this.obj) {
+        this.form = this.obj
+      }
+    },
+    getMerchantList() {
+      getAllList().then(res => {
+        this.merchantLists = res.data
+      })
+    },
+    getSceneList() {
+      getSceneList({ pageNumber: 1, pageSize: 1000 }).then(res => {
+        this.sceneLists = res.data.records
+      })
+    },
+    getUserlibList() {
+      getUserlibList({ pageNumber: 1, pageSize: 1000 }).then(res => {
+        this.userlibLists = res.data.records
+      })
+    },
+    handleRemove(type) {
+      if (type) {
+        this.form[type] = null
+      }
+    },
+    // 图片上传前
+    beforeAvatarUpload(file) {
+      if (!(file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/jpg' || file.type === 'image/jpeg')) {
+        this.$notify.warning({
+          title: '警告',
+          message: '请上传格式为image/png, image/gif, image/jpg, image/jpeg的图片'
+        })
+        return
+      }
+      const isLt2M = file.size / 1024 / 1024 < 2
+      if (!isLt2M) {
+        this.$notify.warning({
+          title: '警告',
+          message: '图片大小必须小于2M'
+        })
+        return
+      }
+    },
+    doUploadAvatar(obj, type) {
+      this.listLoading = true
+      var avatar = new FormData()
+      avatar.append('file', obj.file)
+      pictureLocal(avatar).then((res) => {
+        this.value = res.data
+        this.listLoading = false
+        this.$set(this.form, type, res.data)
+      })
+    },
+    submit(e) {
+      e.preventDefault()
+      this.$refs.form.validate(async(valid) => {
+        if (!valid) {
+          return false
+        }
+        if (this.submitLoading) {
+          return
+        }
+        this.submitLoading = true
+        try {
+          // 启用支付宝人脸能力
+          // if (!this.form.useAlipayFace) {
+          //   this.form.faceMode = 'auto'
+          //   this.form.isNeed1V1 = true
+          // }
+
+          // 是否启用联动平台
+          if (!this.form.useLinkage) {
+            this.form.linkageAds = null
+          }
+
+          // 刷脸模式 非点击
+          if (this.form.faceMode !== 'click') {
+            this.form.clickButtonText = null
+            this.form.isCaptureFace = false
+          }
+
+          // 开门信号
+          // if (this.form.useSerialPort !== 'RS232') {
+          //   this.form.
+          // }
+          await add(this.form)
+          this.$emit('finish')
+        } catch (e) {
+          console.info('add', e)
+        } finally {
+          this.submitLoading = false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.wrap-layout {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  width: 1120px;
+  form {
+    width: 100%;
+  }
+
+  .item-layout {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    position: relative;
+    width: 100%;
+    margin-top: 24px;
+    &:before {
+      position: absolute;
+      top: 1px;
+      left: -10px;
+      width: 3px;
+      height: 16px;
+      content: "";
+      background-color: #409EFF;
+      border-radius: 3px;
+    }
+    .prompt {
+      font-size: 16px;
+      font-weight: 600;
+      color: #333333;
+    }
+    .display-config-layout {
+      display: flex;
+      flex-wrap: wrap;
+      padding-top: 12px;
+      width: 100%;
+      & > div {
+        width: calc(50% - 60px);
+        flex: none;
+        margin-left: 0;
+        margin-right: 0;
+      }
+      & > div:nth-child(odd) {
+        margin-right: 120px;
+      }
+      .overlength ::v-deep .el-form-item__label {
+        line-height: 1.4;
+      }
+      .upload-img {
+        width: 63px;
+        height: 91px;
+        position: relative;
+        img {
+          width: 100%;
+          height: 100%;
+          object-fit: contain;
+          // border-radius: 12px;
+        }
+        .del-img {
+          display: inline-block;
+          width: 20px;
+          height: 20px;
+          background: #83878f;
+          color: #fff;
+          position: absolute;
+          top: -12px;
+          right: -10px;
+          border-radius: 48%;
+          line-height: 18px;
+        }
+      }
+
+      ::v-deep .el-radio__input {
+        vertical-align: top;
+      }
+      ::v-deep .el-select {
+        width: 100%;
+      }
+      ::v-deep .el-radio-group {
+        & > label.el-radio {
+          margin-right: 60px;
+        }
+      }
+    }
+  }
+}
+</style>

+ 116 - 15
src/views/device/index.vue

@@ -1,18 +1,35 @@
 <template>
   <div class="app-container">
-    <addModal ref="addModel" @success="modalSuccess" />
-    <uploadModal ref="uploadModal" @finish="modalSuccess(false)" />
-    <div style="margin-bottom: 20px;">
+    <!-- <addModal ref="addModel" @success="modalSuccess" />
+    <uploadModal ref="uploadModal" @finish="modalSuccess(false)" /> -->
+    <div class="search-layout" style="margin-bottom: 0px;margin-top: -10px;">
       <el-input v-model="form.sn" placeholder="设备sn" style="width: 256px;" class="filter-item" />
-      <el-input v-model="form.company" placeholder="公司名" style="width: 256px;margin-left: 20px;" class="filter-item" />
-      <el-button class="filter-item" type="primary" style="margin-left: 20px;" icon="el-icon-search" @click="query">
+      <el-input v-model="form.company" placeholder="公司名" style="width: 256px;" class="filter-item" />
+      <el-select v-model="form.tenantId" class="filter-item" placeholder="请选择服务商平台名称" clearable filterable>
+        <el-option v-for="(item, index) in merchantLists" :key="index" :label="item.name" :value="item.id" />
+      </el-select>
+      <el-select v-model="form.sceneId" class="filter-item" placeholder="请选择场景" clearable>
+        <el-option v-for="(item, index) in sceneLists" :key="index" :label="item.sceneName" :value="item.id" />
+      </el-select>
+      <el-select v-model="form.mode" class="filter-item" placeholder="请选择模式" clearable>
+        <el-option v-for="(item, index) in modeLists" :key="index" :label="item.value" :value="item.key" />
+      </el-select>
+      <el-select v-model="form.userLibId" class="filter-item" placeholder="请选择⽤户库" clearable>
+        <el-option v-for="(item, index) in userlibLists" :key="index" :label="item.userLibName" :value="item.id" />
+      </el-select>
+      <el-select v-model="form.status" class="filter-item" placeholder="请选择状态" clearable>
+        <el-option v-for="(item, index) in statusLists" :key="index" :label="item.value" :value="item.key" />
+      </el-select>
+    </div>
+    <div class="search-layout">
+      <el-button class="filter-item" style="margin-right: 0;" type="primary" icon="el-icon-search" @click="query">
         搜索
       </el-button>
-      <el-button class="filter-item" style="margin-left: 20px;" type="primary" icon="el-icon-plus" @click="handleCreate">
+      <el-button class="filter-item" style="margin-right: 0;" type="primary" icon="el-icon-plus" @click="handleCreate">
         添加
       </el-button>
-      <el-button type="primary" icon="el-icon-download" style="margin-left: 20px;" @click="download">下载模板</el-button>
-      <el-button type="primary" style="margin-left: 20px;" plain @click="addOrUpdate">批量导入</el-button>
+      <el-button type="primary" icon="el-icon-download" @click="download">下载模板</el-button>
+      <el-button type="primary" plain @click="addOrUpdate">批量导入</el-button>
     </div>
     <el-table
       v-loading="tableLoading"
@@ -62,12 +79,17 @@
           {{ scope.row.sceneName }}
         </template>
       </el-table-column>
+      <el-table-column label="模式">
+        <template slot-scope="scope">
+          {{ scope.row.mode | modeFilter }}
+        </template>
+      </el-table-column>
       <el-table-column label="⽤⼾库名称">
         <template slot-scope="scope">
           {{ scope.row.userLibName }}
         </template>
       </el-table-column>
-      <el-table-column label="状态" align="center" class-name="status-col" width="100">
+      <el-table-column label="状态" align="center" class-name="status-col" width="120">
         <template slot-scope="{row}">
           <el-tag :type="row.status | statusFilter">
             {{ row.status | statusFilterStr }}
@@ -101,31 +123,90 @@
 </template>
 
 <script>
-import AddModal from './modal/AddModal.vue'
-import UploadModal from './modal/UploadModal.vue'
+// import AddModal from './modal/AddModal.vue'
+// import UploadModal from './modal/UploadModal.vue'
 import tableMixins from '@/mixins/tableMixins'
 import { getList, deleteById, autoById, autoCancelById } from '@/api/device'
+import { getAllList as getMerchantList } from '@/api/merchant'
+import { getList as getSceneList } from '@/api/scene'
+import { getList as getUserlibList } from '@/api/userlib'
 import Pagination from '@/components/Pagination'
 
 export default {
-  components: { Pagination, AddModal, UploadModal },
+  components: { Pagination },
   filters: {
     statusFilter(status) {
       return status ? 'success' : 'info'
     },
     statusFilterStr(status) {
       return status ? '已授权' : '未授权'
+    },
+    modeFilter(value) {
+      if (value === 'public') {
+        return '开放'
+      } else if (value === 'close') {
+        return '封闭'
+      } else if (value === 'elasticity') {
+        return '弹性'
+      } else {
+        return ''
+      }
     }
   },
   mixins: [tableMixins],
   data() {
     return {
+      merchantLists: [],
+      sceneLists: [],
+      userlibLists: [],
+      modeLists: [
+        {
+          key: 'public',
+          value: '开放'
+        },
+        {
+          key: 'close',
+          value: '封闭'
+        },
+        {
+          key: 'elasticity',
+          value: '弹性'
+        }
+      ],
+      statusLists: [
+        {
+          key: false,
+          value: '未授权'
+        },
+        {
+          key: true,
+          value: '已授权'
+        }
+      ],
       form: {}
     }
   },
   methods: {
     initData() {
       this.getTableList()
+      this.getMerchantList()
+      this.getSceneList()
+      this.getUserlibList()
+    },
+    getMerchantList() {
+      getMerchantList().then(res => {
+        this.merchantLists = res.data
+      })
+    },
+    getSceneList() {
+      getSceneList({ pageNumber: 1, pageSize: 1000 }).then(res => {
+        this.sceneLists = res.data.records
+      })
+    },
+    getUserlibList() {
+      getUserlibList({ pageNumber: 1, pageSize: 1000 }).then(res => {
+        this.userlibLists = res.data.records
+      })
     },
     // 获取表格数据
     async getTableList() {
@@ -148,7 +229,12 @@ export default {
     transformFilterForm() {
       return {
         sn: this.form.sn || null,
-        company: this.form.company || null
+        company: this.form.company || null,
+        tenantId: this.form.tenantId || null,
+        sceneId: this.form.sceneId || null,
+        mode: this.form.mode || null,
+        userLibId: this.form.userLibId || null,
+        status: this.form.status === '' ? null : this.form.status
       }
     },
     // 下载模板
@@ -165,10 +251,12 @@ export default {
       this.getTableList()
     },
     handleCreate() {
-      this.$refs.addModel.open()
+      // this.$refs.addModel.open()
+      this.$router.push({ path: '/device/add' })
     },
     handleUpdate(row) {
-      this.$refs.addModel.open(Object.assign({}, row))
+      // this.$refs.addModel.open(Object.assign({}, row))
+      this.$router.push({ path: '/device/change', query: { obj: encodeURIComponent(JSON.stringify(row)) }})
     },
     handleAuth(row, needAuth) {
       const that = this
@@ -251,3 +339,16 @@ export default {
   }
 }
 </script>
+
+<style scoped>
+  .search-layout {
+    margin-bottom: 20px;
+  }
+  .search-layout .filter-item {
+    margin-right: 20px;
+    margin-top: 10px;
+  }
+  .search-layout .filter-item:last-of-type {
+    margin-right: 0;
+  }
+</style>

+ 37 - 3
src/views/device/modal/AddModal.vue

@@ -14,7 +14,7 @@
         <el-input v-model="form.sn" />
       </el-form-item>
       <el-form-item label="服务商平台名称" prop="tenantId" required>
-        <el-select v-model="form.tenantId" class="filter-item" placeholder="服务商平台名称">
+        <el-select v-model="form.tenantId" class="filter-item" placeholder="服务商平台名称" filterable>
           <el-option v-for="(item, index) in merchantLists" :key="index" :label="item.name" :value="item.id" />
         </el-select>
       </el-form-item>
@@ -26,7 +26,12 @@
           <el-option v-for="(item, index) in sceneLists" :key="index" :label="item.sceneName" :value="item.id" />
         </el-select>
       </el-form-item>
-      <el-form-item label="⽤户库" prop="userLibId" :required="false">
+      <el-form-item label="模式" prop="mode" required>
+        <el-select v-model="form.mode" class="filter-item" placeholder="请选择模式">
+          <el-option v-for="(item, index) in modeLists" :key="index" :label="item.value" :value="item.key" />
+        </el-select>
+      </el-form-item>
+      <el-form-item v-if="!(!form.mode || form.mode === 'public')" label="⽤户库" prop="userLibId" :required="false">
         <el-select v-model="form.userLibId" class="filter-item" placeholder="请选择⽤户库" clearable>
           <el-option v-for="(item, index) in userlibLists" :key="index" :label="item.userLibName" :value="item.id" />
         </el-select>
@@ -55,12 +60,27 @@ export default {
       merchantLists: [],
       sceneLists: [],
       userlibLists: [],
+      modeLists: [
+        {
+          key: 'public',
+          value: '开放'
+        },
+        {
+          key: 'close',
+          value: '封闭'
+        },
+        {
+          key: 'elasticity',
+          value: '弹性'
+        }
+      ],
       form: {
         id: null,
         sn: null,
         tenantId: null,
         company: null,
         sceneId: null,
+        mode: null,
         userLibId: null
       },
       rules: {
@@ -72,6 +92,9 @@ export default {
         ],
         company: [
           { required: true, whitespace: true, message: '不能为空!', trigger: ['change', 'blur'] }
+        ],
+        mode: [
+          { required: true, whitespace: true, message: '不能为空!', trigger: ['change', 'blur'] }
         ]
       },
       visible: false,
@@ -79,6 +102,16 @@ export default {
       isEdit: false
     }
   },
+  watch: {
+    'form.mode': {
+      handler(value) {
+        if (!value || value === 'public') {
+          this.form.userLibId = null
+        }
+      },
+      immediate: true
+    }
+  },
   created() {
     this.getMerchantList()
     this.getSceneList()
@@ -130,7 +163,8 @@ export default {
             tenantId: this.form.tenantId,
             company: this.form.company,
             sceneId: this.form.sceneId,
-            userLibId: this.form.userLibId
+            userLibId: this.form.userLibId,
+            mode: this.form.mode
           }
           await add(params)
           this.visible = false

+ 35 - 2
src/views/device/modal/UploadModal.vue

@@ -11,7 +11,7 @@
     >
       <el-form ref="form" :rules="rules" :model="form" label-position="left" label-width="120px">
         <el-form-item label="服务商平台名称" prop="tenantId" required>
-          <el-select v-model="form.tenantId" class="filter-item" placeholder="服务商平台名称">
+          <el-select v-model="form.tenantId" class="filter-item" placeholder="服务商平台名称" filterable>
             <el-option v-for="(item, index) in merchantLists" :key="index" :label="item.name" :value="item.id" />
           </el-select>
         </el-form-item>
@@ -20,7 +20,12 @@
             <el-option v-for="(item, index) in sceneLists" :key="index" :label="item.sceneName" :value="item.id" />
           </el-select>
         </el-form-item>
-        <el-form-item label="⽤户库" prop="userLibId" :required="false">
+        <el-form-item label="模式" prop="mode" required>
+          <el-select v-model="form.mode" class="filter-item" placeholder="请选择模式">
+            <el-option v-for="(item, index) in modeLists" :key="index" :label="item.value" :value="item.key" />
+          </el-select>
+        </el-form-item>
+        <el-form-item v-if="!(!form.mode || form.mode === 'public')" label="⽤户库" prop="userLibId" :required="false">
           <el-select v-model="form.userLibId" class="filter-item" placeholder="请选择⽤户库" clearable>
             <el-option v-for="(item, index) in userlibLists" :key="index" :label="item.userLibName" :value="item.id" />
           </el-select>
@@ -115,10 +120,25 @@ export default {
       merchantLists: [],
       sceneLists: [],
       userlibLists: [],
+      modeLists: [
+        {
+          key: 'public',
+          value: '开放'
+        },
+        {
+          key: 'close',
+          value: '封闭'
+        },
+        {
+          key: 'elasticity',
+          value: '弹性'
+        }
+      ],
       form: {
         tenantId: null,
         sceneId: null,
         userLibId: null,
+        mode: null,
         correctList: {
           correct: [],
           incorrect: []
@@ -128,6 +148,9 @@ export default {
         tenantId: [
           { required: true, type: 'number', whitespace: true, message: '不能为空!', trigger: ['change', 'blur'] }
         ],
+        mode: [
+          { required: true, whitespace: true, message: '不能为空!', trigger: ['change', 'blur'] }
+        ],
         correctList: [
           { required: true, type: 'object', message: '模板文件不能为空!', trigger: ['change', 'blur'], validator: (rule, value, callback) => {
             if (Object.keys(value).length > 0 && ((value.correct && value.correct.length > 0) || (value.incorrect && value.incorrect.length > 0))) {
@@ -154,6 +177,16 @@ export default {
       return Math.floor((this.hasDealNumber / this.allNumber) * 100)
     }
   },
+  watch: {
+    'form.mode': {
+      handler(value) {
+        if (!value || value === 'public') {
+          this.form.userLibId = null
+        }
+      },
+      immediate: true
+    }
+  },
   created() {
     this.getMerchantList()
     this.getSceneList()

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

@@ -60,7 +60,7 @@ export default {
       }
     }
     const validatePassword = (rule, value, callback) => {
-      if (value.length < 6) {
+      if (!value || value.length < 6) {
         callback(new Error('密码不能少于6位'))
       } else {
         callback()

+ 2 - 1
src/views/scene/modal/AddModal.vue

@@ -58,7 +58,8 @@ export default {
         { key: 'MEDICAL_T', value: '医疗 / MEDICAL_T' },
         { key: 'COMMUNITY', value: '社区 / COMMUNITY' },
         { key: 'GOVERNMENT', value: '政务 / GOVERNMENT' },
-        { key: 'TRAFFIC', value: '出行 / TRAFFIC' }
+        { key: 'TRAFFIC', value: '出行 / TRAFFIC' },
+        { key: 'SCENIC', value: '景区 / SCENIC' }
       ]
     }
   },