刘琳琳 1 week ago
parent
commit
021f7ced76

+ 83 - 0
src/api/HHOMCDevice.js

@@ -0,0 +1,83 @@
+import request from '@/utils/request'
+// 设备列表(分页)
+export function getList(data) {
+  return request({
+    url: '/api/v1/hh/omc/device/page',
+    method: 'post',
+    data
+  })
+}
+
+// 设备配置-添加-编辑
+export function add(data) {
+  return request({
+    url: '/api/v1/hh/omc/device/add',
+    method: 'post',
+    data
+  })
+}
+
+// 设备删除
+export function deleteById(deviceId) {
+  return request({
+    url: `/api/v1/hh/omc/device/del/${deviceId}`,
+    method: 'post'
+  })
+}
+
+// 设备授权
+export function autoById(deviceId) {
+  return request({
+    url: `/api/v1/hh/omc/device/enable`,
+    method: 'get',
+    params: { deviceId }
+  })
+}
+
+// 设备取消授权
+export function autoCancelById(deviceId) {
+  return request({
+    url: `/api/v1/hh/omc/device/disable`,
+    method: 'get',
+    params: { deviceId }
+  })
+}
+// 设备模版-新增-编辑
+export function templateEdit(data) {
+  return request({
+    url: '/api/v1/hh/omc/device/template/edit',
+    method: 'post',
+    data
+  })
+}
+// 设备模版列表
+export function templateList(data) {
+  return request({
+    url: '/api/v1/hh/omc/device/template/list',
+    method: 'get',
+    params: {}
+  })
+}
+// 设备模版列表(分页)
+export function templatePage(data) {
+  return request({
+    url: '/api/v1/hh/omc/device/template/page',
+    method: 'post',
+    data
+  })
+}
+// 设备模版-删除
+export function templateDel(deviceTemplateId) {
+  return request({
+    url: `/api/v1/hh/omc/device/template/${deviceTemplateId}`,
+    method: 'get'
+  })
+}
+// 模版-模版详情
+export function templateDetail(deviceTemplateId) {
+  return request({
+    url: '/api/v1/hh/omc/device/template/detail',
+    method: 'get',
+    params: { deviceTemplateId }
+  })
+}

+ 35 - 0
src/router/index.js

@@ -164,6 +164,41 @@ export const constantRoutes = [
       }
     ]
   },
+  {
+    path: '/HHOMCDevice',
+    component: Layout,
+    redirect: '/HHOMCDevice/index',
+    name: 'HHOMCDevice',
+    meta: { title: 'HHOMC设备授权管理', icon: 'el-icon-s-opportunity', accountType: [0, 1] },
+    children: [
+      {
+        path: '/HHOMCDeviceTemplate/index',
+        name: 'HHOMCDeviceTemplate',
+        component: () => import('@/views/HHOMCDeviceTemplate/index.vue'),
+        meta: { title: '配置模板管理', icon: 'el-icon-crop', accountType: [0, 1] }
+      },
+      {
+        path: 'addTemplate',
+        name: 'AddHHOMCTemplate',
+        hidden: true,
+        component: () => import('@/views/HHOMCDeviceTemplate/add'),
+        meta: { title: '添加配置模板', accountType: [0, 1] }
+      },
+      {
+        path: 'index',
+        name: 'HHOMCDeviceIndex',
+        component: () => import('@/views/HHOMCDevice/index'),
+        meta: { title: '设备授权列表', icon: 'el-icon-suitcase-1', accountType: [0, 1] }
+      },
+      {
+        path: 'add',
+        name: 'HHOMCDeviceAdd',
+        hidden: true,
+        component: () => import('@/views/HHOMCDevice/add'),
+        meta: { title: '添加设备', accountType: [0, 1] }
+      }
+    ]
+  },
   {
     path: '/HHFaceDeviceList',
     component: Layout,

+ 138 - 0
src/views/HHOMCDevice/add.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="app-container">
+    <div class="head">
+      添加HHOMC设备
+      <el-button
+        type="primary"
+        size="mini"
+        style="margin-left: 20px"
+        @click="back"
+      >返回</el-button>
+      <el-button
+        type="primary"
+        size="mini"
+        style="margin-left: 20px"
+        @click="chooseTemplate"
+      >选用模板</el-button>
+    </div>
+    <edit-device-module
+      style="margin-left: 16px"
+      :template-data="templateData"
+      :is-dis="false"
+      @finish="back"
+      @back="back"
+    />
+    <el-dialog
+      title="选用模板"
+      :visible.sync="dialogVisible"
+      width="500px"
+      :close-on-click-modal="false"
+    >
+      <el-form
+        ref="form"
+        :model="form"
+        :rules="rules"
+        label-width="80px"
+        label-position="left"
+      >
+        <el-form-item label="模板名称" prop="id" required>
+          <el-select
+            v-model="form.id"
+            placeholder="请选择模板名称"
+            filterable
+            style="width: 100%"
+          >
+            <el-option
+              v-for="(item, index) in templateDataList"
+              :key="index"
+              :label="item.templateName"
+              :value="item.deviceTemplateId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false"> 取消 </el-button>
+        <el-button type="primary" @click="sure"> 确定 </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import EditDeviceModule from './components/EditDeviceModule'
+import { templateList, templateDetail } from '@/api/HHOMCDevice.js'
+
+export default {
+  components: { EditDeviceModule },
+  data() {
+    return {
+      templateData: {},
+      templateDataList: [],
+      dialogVisible: false,
+      form: {
+        id: null
+      },
+      rules: {
+        id: [
+          {
+            required: true,
+            message: '不能为空!',
+            trigger: ['change', 'blur']
+          }
+        ]
+      }
+    }
+  },
+  created() {
+    this.templateList()
+  },
+  mounted() {
+    // this.initData()
+  },
+  methods: {
+    back() {
+      this.$router.back()
+    },
+    chooseTemplate() {
+      this.form.id = null
+      this.dialogVisible = true
+      this.$nextTick(() => {
+        this.$refs['form'].clearValidate()
+      })
+    },
+    templateList() {
+      templateList().then((res) => {
+        this.templateDataList = res.data
+      })
+    },
+    sure() {
+      this.$refs['form'].validate((valid) => {
+        if (valid) {
+          templateDetail(this.form.id).then((res) => {
+            this.dialogVisible = false
+            this.templateData = JSON.parse(JSON.stringify(res.data))
+          })
+        }
+      })
+    }
+  }
+}
+</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>

+ 372 - 0
src/views/HHOMCDevice/components/EditDeviceModule.vue

@@ -0,0 +1,372 @@
+<template>
+  <div>
+    <el-form
+      ref="form"
+      :rules="rules"
+      :model="form"
+      label-position="left"
+      label-width="200px"
+      style="margin-top: 10px"
+    >
+      <TagCard title="设备基本信息">
+        <div class="wrap-content">
+          <div class="wrap-content__item">
+            <el-form-item label="设备sn" prop="sn" required>
+              <!-- :disabled="isDis" -->
+              <el-input
+                v-model="form.sn"
+                placeholder="请输入设备sn"
+                maxlength="100"
+                show-word-limit
+              />
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item label="购买方公司名称" prop="purchaserId">
+              <el-select
+                v-model="form.purchaserId"
+                placeholder="请选择购买方公司名称"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in buyList"
+                  :key="index"
+                  :label="item.companyName"
+                  :value="item.purchaserId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item label="应用类型" prop="applicationTypeId">
+              <el-select
+                v-model="form.applicationTypeId"
+                placeholder="请选择应用类型"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in applicationList"
+                  :key="index"
+                  :label="item.applicationType"
+                  :value="item.applicationTypeId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item
+              label="设备型号(硬件)"
+              prop="deviceModelHardwareId"
+            >
+              <el-select
+                v-model="form.deviceModelHardwareId"
+                placeholder="请选择设备型号(硬件)"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in deviceList"
+                  :key="index"
+                  :label="item.deviceModel"
+                  :value="item.deviceModelId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item
+              label="设备型号(环境)"
+              prop="deviceModelEnvironmentId"
+            >
+              <el-select
+                v-model="form.deviceModelEnvironmentId"
+                placeholder="请选择设备型号(环境)"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in deviceList"
+                  :key="index"
+                  :label="item.deviceModel"
+                  :value="item.deviceModelId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item label="系统类型" prop="systemTypeCode">
+              <el-select
+                v-model="form.systemTypeCode"
+                placeholder="请选择系统类型"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in systemType"
+                  :key="index"
+                  :label="item.name"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+        </div>
+      </TagCard>
+      <TagCard title="三方接口接入配置">
+        <div class="wrap-content">
+          <div class="wrap-content__item">
+            <el-form-item label="ws地址" prop="websocketSubscribeUrl">
+              <el-autocomplete
+                v-model="form.websocketSubscribeUrl"
+                popper-class="my-autocomplete"
+                :fetch-suggestions="(queryString, cb) => querySearch('websocketSubscribeUrlList', queryString, cb)"
+                placeholder="请输入地址"
+                clearable
+                style="width: 100%"
+              >
+                <template slot-scope="{ item }">
+                  <div class="name">{{ item.value }}</div>
+                  <span class="addr">{{ item.desc }}</span>
+                </template>
+              </el-autocomplete>
+            </el-form-item>
+          </div>
+        </div>
+      </TagCard>
+    </el-form>
+    <div class="card-footer">
+      <el-button style="width: 120px" @click="back"> 取消 </el-button>
+      <el-button type="primary" style="width: 120px" :loading="submitLoading" @click="submit">
+        确定
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import TagCard from '@/components/TagCard'
+import { add } from '@/api/HHOMCDevice.js'
+import { applicationTypeList, deviceModelList, purchaserList } from '@/api/configuration'
+
+export default {
+  components: { TagCard },
+  props: {
+    obj: {
+      type: Object,
+      default: () => {}
+    },
+    templateData: {
+      type: Object,
+      default: () => {}
+    },
+    isDis: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      form: {
+        sn: null, // 设备sn
+        purchaserId: null, // 购买方公司名称
+        applicationTypeId: null, // 应用类型
+        deviceModelHardwareId: null, // 设备型号(硬件)
+        deviceModelEnvironmentId: null, // 设备型号(环境)
+        systemTypeCode: null, // 系统类型
+        websocketSubscribeUrl: '' // ws地址
+      },
+      rules: {
+        sn: [
+          {
+            required: true,
+            whitespace: true,
+            message: '不能为空!',
+            trigger: ['change', 'blur']
+          }
+        ]
+      },
+      submitLoading: false,
+      websocketSubscribeUrlList: [
+        {
+          value: 'wss://hhomc.hz-hanghui.com:18096/',
+          desc: '塘栖域名地址'
+        }, {
+          value: 'ws://115.227.34.58:19086/',
+          desc: '塘栖IP地址'
+        }
+      ], // ws地址输入建议
+      applicationList: [], // 应用类型下拉
+      deviceList: [], // 设备型号下拉
+      buyList: [], // 购买方公司名称下拉
+      // 系统类型下拉
+      systemType: [
+        { id: 1, name: '蚂蚁OS' },
+        { id: 2, name: '非蚂蚁OS' }
+      ]
+    }
+  },
+  watch: {
+    templateData() {
+      console.log(this.templateData)
+      if (this.templateData != {}) {
+        this.form = {
+          ...this.templateData,
+          sn: this.form.sn,
+          purchaserId: this.form.purchaserId,
+          id: this.form.id
+        }
+        // this.form.sn = this.obj.sn;
+      }
+    }
+  },
+  mounted() {
+    this.initData()
+  },
+  methods: {
+    initData() {
+      this.getApplicationTypeList()
+      this.getDeviceModelList()
+      this.getPurchaserList()
+      this.$nextTick(() => {
+        if (this.obj) {
+          console.log(this.obj)
+          this.form = {
+            ...this.obj
+          }
+        }
+      })
+    },
+    // 获取应用类型列表
+    getApplicationTypeList() {
+      applicationTypeList().then((res) => {
+        this.applicationList = res.data
+      })
+    },
+    // 设备型号列表
+    getDeviceModelList() {
+      deviceModelList().then((res) => {
+        this.deviceList = res.data
+      })
+    },
+    // 购买方列表
+    getPurchaserList() {
+      purchaserList().then((res) => {
+        this.buyList = res.data
+      })
+    },
+    querySearch(field, queryString, cb) {
+      const restaurants = this[field]
+      const results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+      // 调用 callback 返回建议列表的数据
+      cb(results)
+    },
+    createFilter(queryString) {
+      return (restaurant) => {
+        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+      }
+    },
+    back() {
+      this.$emit('back')
+    },
+    submit(e) {
+      e.preventDefault()
+      this.$refs.form.validate(async(valid) => {
+        if (!valid) {
+          return false
+        }
+        if (this.submitLoading) {
+          return
+        }
+        this.submitLoading = true
+        try {
+          console.log(this.form)
+          await add(this.form)
+          this.$message({
+            message: `${this.form.id ? '修改' : '添加'}成功!`,
+            type: 'success'
+          })
+          this.$emit('back')
+        } catch (e) {
+          console.info('add', e)
+        } finally {
+          this.submitLoading = false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" >
+.my-autocomplete {
+  li {
+    padding: 5px 20px !important;
+
+    .name {
+      line-height: 20px !important;
+      white-space: pre-wrap; /* 保留空白符,如果内容超过容器宽度则换行 */
+      overflow-wrap: break-word; /* 在长单词或URL地址内部进行换行 */
+    }
+    .addr {
+      font-size: 12px;
+      color: #b4b4b4;
+    }
+
+    .highlighted .addr {
+      color: #ddd;
+    }
+  }
+}
+</style>
+<style lang="scss" scoped>
+.card-footer {
+  margin-top: 20px;
+  display: flex;
+  width: 100%;
+  justify-content: center;
+}
+.wrap-content {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  &__item {
+    width: calc(50% - 10px);
+    padding: 10px 10px;
+    .el-form-item {
+      margin-bottom: 0px !important;
+    }
+  }
+}
+.wrap-content-detail {
+  width: calc(100%);
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  position: relative;
+  border: 1px solid #ebeef5;
+  border-radius: 12px;
+  padding: 10px;
+  box-sizing: border-box;
+  overflow: hidden;
+  margin-bottom: 10px;
+  &__title {
+    position: absolute;
+    background: white;
+    height: 40px;
+    line-height: 40px;
+    top: -20px;
+    z-index: 999;
+    padding: 0 10px;
+  }
+  &__item {
+    width: calc(50% - 10px);
+    .el-form-item {
+      padding: 10px 0px;
+      margin-bottom: 0px !important;
+    }
+  }
+}
+
+</style>

+ 338 - 0
src/views/HHOMCDevice/components/UploadModal.vue

@@ -0,0 +1,338 @@
+// 上传设备
+<template>
+  <div>
+    <el-dialog
+      title="批量导入"
+      width="600px"
+      :visible.sync="dialogVisible"
+      :destroy-on-close="false"
+      :close-on-click-modal="false"
+      @close="dialogClose"
+    >
+      <el-form
+        ref="form"
+        :rules="rules"
+        :model="form"
+        label-position="left"
+        label-width="80px"
+      >
+        <el-form-item label="模板名称" prop="templateId" required>
+          <el-select
+            v-model="form.templateId"
+            placeholder="请选择模板名称"
+            filterable
+            style="width: 100%"
+            @change="changeTemplate"
+          >
+            <el-option
+              v-for="(item, index) in templateDataList"
+              :key="index"
+              :label="item.templateName"
+              :value="item.deviceTemplateId"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="上传文件" prop="correctList">
+          <batch-upload ref="batchUploadRef" @getFileList="batchUploadResult" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false"> 取消 </el-button>
+        <el-button type="primary" @click="submit"> 确定 </el-button>
+      </div>
+    </el-dialog>
+    <!-- 批量注册人员-抽屉 -->
+    <el-drawer
+      :title="hasCompleted ? '导入已完成' : '正在处理中..'"
+      :visible.sync="drawerVisible"
+      :wrapper-closable="false"
+      size="50%"
+      direction="rtl"
+    >
+      <div style="padding: 50px">
+        <div>
+          已处理条数;{{ hasDealNumber }}; 待处理条数:{{ waitDealNumber }};
+          总共条数:{{ allNumber }}
+        </div>
+        <el-progress
+          :percentage="makePercent"
+          :format="formatProgress"
+          style="margin-top: 10px"
+        />
+        <el-table
+          ref="batch_upload_result"
+          v-loading="false"
+          :data="batchUploadResultList"
+          class="table"
+          element-loading-text="Loading"
+          border
+          fit
+          highlight-current-row
+          height="500"
+        >
+          <el-table-column label="错误序号" align="center" width="100px">
+            <template slot-scope="scope">
+              {{ scope.$index + 1 }}
+            </template>
+          </el-table-column>
+          <el-table-column label="设备sn" align="center">
+            <template slot-scope="scope">
+              {{ scope.row.sn }}
+            </template>
+          </el-table-column>
+          <el-table-column label="购买方公司名称" align="center">
+            <template slot-scope="scope">
+              {{ scope.row.company }}
+            </template>
+          </el-table-column>
+          <el-table-column label="错误描述" align="center">
+            <template slot-scope="scope">
+              {{ scope.row.err }}
+            </template>
+          </el-table-column>
+        </el-table>
+        <div style="text-align: center; margin: 20px 0">
+          <el-button type="primary" @click="drawerVisible = false">
+            我已知晓
+          </el-button>
+          <el-button type="warning" @click="downloadBatchUploadErrorList">
+            下载错误列表文件
+          </el-button>
+        </div>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import BatchUpload from '@/components/BatchUpload'
+import { purchaserList } from '@/api/configuration'
+import { templateDetail, add } from '@/api/HHOMCDevice.js'
+
+export default {
+  components: { BatchUpload },
+  props: {
+    templateDataList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      buyList: [],
+      templateList: [],
+      form: {
+        templateId: null,
+        correctList: {
+          correct: [],
+          incorrect: []
+        }
+      },
+      rules: {
+        templateId: [
+          {
+            required: true,
+            type: 'number',
+            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))
+              ) {
+                return callback()
+              }
+              return callback('数据不能为空!')
+            }
+          }
+        ]
+      },
+      dialogVisible: false,
+      // 批量注册-处理提示值
+      hasDealNumber: 0,
+      waitDealNumber: 0,
+      allNumber: 0,
+      hasCompleted: false,
+      // 批量注册-抽屉控制值
+      drawerVisible: false,
+      batchUploadResultList: []
+    }
+  },
+  computed: {
+    // 批量注册-返回向下取整,减少渲染次数
+    makePercent() {
+      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.purchaserList()
+  },
+  methods: {
+    // 购买方列表
+    purchaserList() {
+      purchaserList().then((res) => {
+        this.buyList = res.data
+      })
+    },
+    changeTemplate(e) {
+      templateDetail(e).then((res) => {
+        this.form = Object.assign(this.form, res.data)
+      })
+    },
+    open() {
+      this.dialogVisible = true
+      this.$nextTick(() => {
+        this.$refs.form.resetFields()
+      })
+    },
+    dialogClose() {
+      this.$refs.batchUploadRef.clearFile()
+    },
+    batchUploadResult(correctList) {
+      this.form.correctList = correctList
+    },
+    // 批量注册人员-操作
+    getFileList(correctList) {
+      this.hasCompleted = false
+      this.drawerVisible = true
+      this.hasDealNumber = correctList.incorrect.length
+      this.waitDealNumber = correctList.correct.length
+      this.allNumber =
+        correctList.incorrect.length + correctList.correct.length
+      this.batchUploadResultList = correctList.incorrect.map((item) => {
+        return { name: item.file.name, err: item.reason }
+      })
+      this.makeScrollDown()
+      this.doSubmitUrl(correctList, 0)
+    },
+    // 批量注册人员-并提交至添加到接口
+    async doSubmitUrl(correctList, index) {
+      const that = this
+      if (index <= correctList.correct.length - 1) {
+        const item = correctList.correct[index]
+        if (item['设备sn']) {
+          // 组装数据上传
+          const data = JSON.parse(JSON.stringify(this.form))
+          data.sn = item['设备sn']
+          data.sn = data.sn.toString().trim()
+          if (item['购买方公司名称']) {
+            data.company = item['购买方公司名称']
+            data.company = data.company.trim()
+            const index = that.buyList.findIndex(
+              (i) => i.companyName === data.company
+            )
+            if (index > -1) {
+              try {
+                data.purchaserId = that.buyList[index].purchaserId
+                await add(data)
+              } catch (err) {
+                console.log(err)
+                this.batchUploadResultList.push({
+                  sn: data.sn,
+                  company: data.company,
+                  err: err
+                })
+              }
+            } else {
+              this.batchUploadResultList.push({
+                sn: item['设备sn'] || '',
+                company: item['购买方公司名称'] || '',
+                err: '购买方公司名称有误'
+              })
+            }
+          } else {
+            await add(data)
+          }
+        } else {
+          this.batchUploadResultList.push({
+            sn: item['设备sn'] || '',
+            err: '不包含 "设备sn" 字段'
+          })
+        }
+
+        this.hasDealNumber += 1
+        this.waitDealNumber -= 1
+        this.makeScrollDown()
+        // 继续调用
+        this.doSubmitUrl(correctList, ++index)
+      } else {
+        this.hasCompleted = true
+        this.$emit('finish')
+      }
+    },
+    // 批量注册人员-保持滚动条在最底部
+    makeScrollDown() {
+      this.$nextTick(() => {
+        this.$refs.batch_upload_result.$refs.bodyWrapper.scrollTop =
+          this.$refs.batch_upload_result.$refs.bodyWrapper.scrollHeight
+      })
+    },
+    // 批量注册人员-返回进度条尾部显示值
+    formatProgress(percent) {
+      return percent === 100 ? '已完成' : ''
+    },
+    // 批量注册人员-导出错误名单
+    downloadBatchUploadErrorList() {
+      const list = this.batchUploadResultList
+      let string = '序号\t设备sn\t错误原因\n'
+      for (let i = 0; i < this.batchUploadResultList.length; i++) {
+        string +=
+          (i + 1).toString() +
+          '\t' +
+          list[i].sn +
+          '\t' +
+          list[i].err +
+          '\t' +
+          '\n'
+      }
+      const blob = new Blob([string], { type: 'text/plain;charset=utf-8' })
+      const excel_url = window.URL.createObjectURL(blob)
+      const link = document.createElement('a')
+      link.href = excel_url
+      link.download = '批量注册结果错误名单.xls'
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+    },
+    submit(e) {
+      e.preventDefault()
+      this.$refs.form.validate((valid) => {
+        if (!valid) {
+          return false
+        }
+        this.dialogVisible = false
+        this.getFileList(this.form.correctList)
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+::v-deep .el-select {
+  width: 100%;
+}
+.table {
+  margin-top: 15px;
+}
+</style>

+ 585 - 0
src/views/HHOMCDevice/index.vue

@@ -0,0 +1,585 @@
+<template>
+  <div class="app-container">
+    <div v-if="isShowUpdate">
+      <div class="head">
+        编辑HHOMC设备
+        <el-button
+          type="primary"
+          size="mini"
+          style="margin-left: 10px"
+          @click="back"
+        >返回</el-button>
+        <el-button
+          type="primary"
+          size="mini"
+          style="margin-left: 10px"
+          @click="chooseTemplate"
+        >选用模板</el-button>
+      </div>
+      <edit-device-module
+        :key="`device_module_${updateData.id}`"
+        :is-dis="true"
+        :obj="updateData"
+        :template-data="templateData"
+        style="margin-left: 16px"
+        @finish="back"
+        @back="back"
+      />
+      <el-dialog
+        title="选用模板"
+        :visible.sync="dialogVisible"
+        width="500px"
+        :close-on-click-modal="false"
+      >
+        <el-form
+          ref="form"
+          :model="form"
+          :rules="rules"
+          label-width="80px"
+          label-position="left"
+        >
+          <el-form-item label="模板名称" prop="id" required>
+            <el-select
+              v-model="form.id"
+              placeholder="请选择模板名称"
+              filterable
+              style="width: 100%"
+            >
+              <el-option
+                v-for="(item, index) in templateDataList"
+                :key="index"
+                :label="item.templateName"
+                :value="item.deviceTemplateId"
+              />
+            </el-select>
+          </el-form-item>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+          <el-button @click="dialogVisible = false"> 取消 </el-button>
+          <el-button type="primary" @click="sure"> 确定 </el-button>
+        </div>
+      </el-dialog>
+    </div>
+    <div v-show="!isShowUpdate">
+      <uploadModal
+        ref="uploadModal"
+        :template-data-list="templateDataList"
+        @finish="modalSuccess(false)"
+      />
+      <div class="search-layout" style="margin-bottom: 0px; margin-top: -10px">
+        <el-input
+          v-model="form.sn"
+          placeholder="设备sn"
+          class="filter-item input"
+        />
+        <el-select
+          v-model="form.purchaserId"
+          class="filter-item"
+          placeholder="购买方公司"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in buyList"
+            :key="index"
+            :label="item.companyName"
+            :value="item.purchaserId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.applicationTypeId"
+          class="filter-item"
+          placeholder="应用类型"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in applicationList"
+            :key="index"
+            :label="item.applicationType"
+            :value="item.applicationTypeId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.deviceModelHardwareId"
+          class="filter-item"
+          placeholder="设备型号(硬件)"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in devicelList"
+            :key="index"
+            :label="item.deviceModel"
+            :value="item.deviceModelId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.deviceModelEnvironmentId"
+          class="filter-item"
+          placeholder="设备型号(环境)"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in devicelList"
+            :key="index"
+            :label="item.deviceModel"
+            :value="item.deviceModelId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.systemTypeCode"
+          class="filter-item"
+          placeholder="系统类型"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in systemType"
+            :key="index"
+            :label="item.name"
+            :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(1)"
+        >
+          搜索
+        </el-button>
+        <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"
+          @click="download"
+        >下载模板</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="addOrUpdate"
+        >批量导入</el-button>
+      </div>
+      <el-table
+        v-loading="tableLoading"
+        :data="tableData"
+        element-loading-text="加载中..."
+        border
+        fit
+        highlight-current-row
+      >
+        <el-table-column align="center" label="序号" width="95">
+          <template slot-scope="scope">
+            {{
+              (pagination.page - 1) * pagination.pageSize + (scope.$index + 1)
+            }}
+          </template>
+        </el-table-column>
+        <el-table-column label="设备sn">
+          <template slot-scope="scope">
+            {{ scope.row.sn }}
+          </template>
+        </el-table-column>
+        <el-table-column label="购买方公司">
+          <template slot-scope="scope">
+            {{ scope.row.companyName }}
+          </template>
+        </el-table-column>
+        <el-table-column label="应用类型">
+          <template slot-scope="scope">
+            {{ scope.row.applicationType }}
+          </template>
+        </el-table-column>
+        <el-table-column label="设备型号(硬件)">
+          <template slot-scope="scope">
+            {{ scope.row.deviceModelHardware }}
+          </template>
+        </el-table-column>
+        <el-table-column label="设备型号(环境)">
+          <template slot-scope="scope">
+            {{ scope.row.deviceModelEnvironment }}
+          </template>
+        </el-table-column>
+        <el-table-column label="系统类型">
+          <template slot-scope="scope">
+            {{ scope.row.systemType }}
+          </template>
+        </el-table-column>
+        <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 }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="操作"
+          align="center"
+          width="250"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="{ row, $index }">
+            <el-button type="primary" size="mini" @click="handleUpdate(row)">
+              编辑
+            </el-button>
+            <el-button
+              size="mini"
+              type="danger"
+              @click="handleDelete(row, $index)"
+            >
+              删除
+            </el-button>
+            <template>
+              <el-button
+                v-if="row.status"
+                size="mini"
+                type="danger"
+                @click="handleAuth(row, false)"
+              >取消授权</el-button>
+              <el-button
+                v-else
+                size="mini"
+                type="danger"
+                @click="handleAuth(row, true)"
+              >获取授权</el-button>
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        :total="pagination.total"
+        :page.sync="pagination.page"
+        :limit.sync="pagination.pageSize"
+        :page-sizes="pagination.pageSizeOptions"
+        :layout="pagination.layout"
+        @pagination="handleSizeChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import EditDeviceModule from './components/EditDeviceModule'
+import UploadModal from './components/UploadModal.vue'
+import tableMixins from '@/mixins/tableMixins'
+import {
+  getList,
+  deleteById,
+  autoById,
+  autoCancelById,
+  templateList,
+  templateDetail
+} from '@/api/HHOMCDevice.js'
+import Pagination from '@/components/Pagination'
+import {
+  applicationTypeList,
+  deviceModelList,
+  purchaserList
+} from '@/api/configuration'
+export default {
+  components: { Pagination, UploadModal, EditDeviceModule },
+  filters: {
+    statusFilter(status) {
+      return status ? 'success' : 'info'
+    },
+    statusFilterStr(status) {
+      return status ? '已授权' : '未授权'
+    }
+  },
+  mixins: [tableMixins],
+  data() {
+    return {
+      statusLists: [
+        {
+          key: false,
+          value: '未授权'
+        },
+        {
+          key: true,
+          value: '已授权'
+        }
+      ],
+      isShowUpdate: false,
+      updateData: {},
+      templateData: {},
+      pagination: {
+        page: 1,
+        current: 1
+      },
+      applicationList: [],
+      devicelList: [],
+      buyList: [],
+      systemType: [
+        { id: 1, name: '蚂蚁OS' },
+        { id: 2, name: '非蚂蚁OS' }
+      ],
+      templateDataList: [],
+      dialogVisible: false,
+      form: {
+        id: null
+      },
+      rules: {
+        id: [
+          {
+            required: true,
+            message: '不能为空!',
+            trigger: ['change', 'blur']
+          }
+        ]
+      }
+    }
+  },
+  methods: {
+    initData() {
+      this.getTableList()
+      this.applicationTypeList()
+      this.deviceModelList()
+      this.purchaserList()
+      this.templateList()
+    },
+    // 获取表格数据
+    async getTableList() {
+      this.pagination.current = this.pagination.page
+      this.tableLoading = true
+      try {
+        const result = await getList(this.getFilterParams())
+        this.setDataList(result.data)
+      } catch (e) {
+        console.log(e)
+      } finally {
+        this.tableLoading = false
+      }
+    },
+    // 获取筛选信息
+    query(type) {
+      if (type) {
+        this.pagination.page = 1
+        this.pagination.current = 1
+      }
+      this.clearPageParams()
+      this.getTableList()
+    },
+    // 增加筛选条件
+    transformFilterForm() {
+      return {
+        purchaserId: this.form.purchaserId || null,
+        applicationTypeId: this.form.applicationTypeId || null,
+        deviceModelHardwareId: this.form.deviceModelHardwareId || null,
+        deviceModelEnvironmentId: this.form.deviceModelEnvironmentId || null,
+        systemTypeCode: this.form.systemTypeCode || null,
+        sn: this.form.sn || null,
+        mode: this.form.mode || null,
+        status: this.form.status === '' ? null : this.form.status
+      }
+    },
+    // 下载模板
+    download() {
+      window.location.href =
+        process.env.VUE_APP_BASE_API + '/static/deviceListExcel.xlsx'
+    },
+    addOrUpdate() {
+      this.$refs.uploadModal.open()
+    },
+    modalSuccess(isEdit) {
+      if (!isEdit) {
+        this.clearPageParams()
+      }
+      this.getTableList()
+    },
+    handleCreate() {
+      this.$router.push({ path: '/HHOMCDevice/add' })
+    },
+    handleUpdate(row) {
+      this.isShowUpdate = true
+      this.updateData = JSON.parse(JSON.stringify(row))
+    },
+    back() {
+      this.isShowUpdate = false
+      this.query()
+    },
+    chooseTemplate() {
+      this.form.id = null
+      this.dialogVisible = true
+      this.$nextTick(() => {
+        this.$refs['form'].clearValidate()
+      })
+    },
+    templateList() {
+      templateList().then((res) => {
+        this.templateDataList = res.data
+      })
+    },
+    sure() {
+      this.$refs['form'].validate((valid) => {
+        if (valid) {
+          templateDetail(this.form.id).then((res) => {
+            this.dialogVisible = false
+            this.templateData = JSON.parse(JSON.stringify(res.data))
+          })
+        }
+      })
+    },
+    handleAuth(row, needAuth) {
+      const that = this
+      this.$confirm(
+        `确定 ${needAuth ? '获取授权' : '取消授权'} 操作吗?`,
+        '提示',
+        {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          showClose: false,
+          type: 'warning',
+          beforeClose: async(action, instance, done) => {
+            if (action === 'confirm') {
+              instance.confirmButtonLoading = true
+              instance.cancelButtonLoading = true
+              instance.confirmButtonText = '提交中...'
+              try {
+                if (needAuth) {
+                  await autoById(row.id)
+                } else {
+                  await autoCancelById(row.id)
+                }
+                this.$message({
+                  type: 'success',
+                  message: '操作成功!'
+                })
+                that.getTableList()
+              } catch (e) {
+                // this.$message({
+                //   type: 'error',
+                //   message: '删除失败!'
+                // })
+              } finally {
+                done()
+                setTimeout(() => {
+                  instance.confirmButtonLoading = false
+                  instance.cancelButtonLoading = false
+                }, 300)
+              }
+            } else {
+              done()
+            }
+          }
+        }
+      )
+        .then(() => {})
+        .catch(() => {})
+    },
+    handleDelete(row, index) {
+      const that = this
+      this.$confirm('确定删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        showClose: false,
+        type: 'warning',
+        beforeClose: async(action, instance, done) => {
+          if (action === 'confirm') {
+            instance.confirmButtonLoading = true
+            instance.cancelButtonLoading = true
+            instance.confirmButtonText = '提交中...'
+            try {
+              await deleteById(row.id)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              })
+              that.getTableList()
+            } catch (e) {
+              // this.$message({
+              //   type: 'error',
+              //   message: '删除失败!'
+              // })
+            } finally {
+              done()
+              setTimeout(() => {
+                instance.confirmButtonLoading = false
+                instance.cancelButtonLoading = false
+              }, 300)
+            }
+          } else {
+            done()
+          }
+        }
+      })
+        .then(() => {})
+        .catch(() => {})
+    },
+    // 获取应用类型列表
+    applicationTypeList() {
+      applicationTypeList().then((res) => {
+        this.applicationList = res.data
+      })
+    },
+    // 设备型号列表
+    deviceModelList() {
+      deviceModelList().then((res) => {
+        this.devicelList = res.data
+      })
+    },
+    // 购买方列表
+    purchaserList() {
+      purchaserList().then((res) => {
+        this.buyList = res.data
+      })
+    }
+  }
+}
+</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;
+}
+.head {
+  margin-left: 16px;
+  font-weight: 600;
+  font-size: 18px;
+  color: #333333;
+}
+.input {
+  width: 200px;
+  margin-right: 15px;
+}
+.m-r {
+  margin-right: 15px;
+}
+</style>

+ 58 - 0
src/views/HHOMCDeviceTemplate/add.vue

@@ -0,0 +1,58 @@
+<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-module
+      style="margin-left: 16px"
+      :obj="obj"
+      @finish="back"
+      @back="back"
+    />
+  </div>
+</template>
+
+<script>
+import EditDeviceModule from './components/EditDeviceModule'
+
+export default {
+  components: { EditDeviceModule },
+  data() {
+    return {
+      obj: null
+    }
+  },
+  created() {},
+  mounted() {
+    // this.initData()
+  },
+  methods: {
+    back() {
+      this.$router.back()
+    }
+  }
+}
+</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>

+ 326 - 0
src/views/HHOMCDeviceTemplate/components/EditDeviceModule.vue

@@ -0,0 +1,326 @@
+<template>
+  <div>
+    <el-form
+      ref="form"
+      :rules="rules"
+      :model="form"
+      label-position="left"
+      label-width="200px"
+      style="margin-top: 10px"
+    >
+      <TagCard title="设备基本信息">
+        <div class="wrap-content">
+          <div class="wrap-content__item">
+            <el-form-item label="模板名称" prop="templateName" required>
+              <el-input
+                v-model="form.templateName"
+                placeholder="请输入模板名称"
+              />
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item label="应用类型" prop="applicationTypeId">
+              <el-select
+                v-model="form.applicationTypeId"
+                placeholder="请选择应用类型"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in applicationList"
+                  :key="index"
+                  :label="item.applicationType"
+                  :value="item.applicationTypeId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item
+              label="设备型号(硬件)"
+              prop="deviceModelHardwareId"
+            >
+              <el-select
+                v-model="form.deviceModelHardwareId"
+                placeholder="请选择设备型号(硬件)"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in deviceList"
+                  :key="index"
+                  :label="item.deviceModel"
+                  :value="item.deviceModelId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item
+              label="设备型号(环境)"
+              prop="deviceModelEnvironmentId"
+            >
+              <el-select
+                v-model="form.deviceModelEnvironmentId"
+                placeholder="请选择设备型号(环境)"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in deviceList"
+                  :key="index"
+                  :label="item.deviceModel"
+                  :value="item.deviceModelId"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+          <div class="wrap-content__item">
+            <el-form-item label="系统类型" prop="systemTypeCode">
+              <el-select
+                v-model="form.systemTypeCode"
+                placeholder="请选择系统类型"
+                style="width: 100%"
+                filterable
+              >
+                <el-option
+                  v-for="(item, index) in systemType"
+                  :key="index"
+                  :label="item.name"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </div>
+        </div>
+      </TagCard>
+      <TagCard title="三方接口接入配置">
+        <div class="wrap-content">
+          <div class="wrap-content__item">
+            <el-form-item label="ws地址" prop="websocketSubscribeUrl">
+              <el-autocomplete
+                v-model="form.websocketSubscribeUrl"
+                popper-class="my-autocomplete"
+                :fetch-suggestions="(queryString, cb) => querySearch('websocketSubscribeUrlList', queryString, cb)"
+                placeholder="请输入地址"
+                clearable
+                style="width: 100%"
+              >
+                <template slot-scope="{ item }">
+                  <div class="name">{{ item.value }}</div>
+                  <span class="addr">{{ item.desc }}</span>
+                </template>
+              </el-autocomplete>
+            </el-form-item>
+          </div>
+        </div>
+      </TagCard>
+    </el-form>
+    <div class="card-footer">
+      <el-button style="width: 120px" @click="back"> 取消 </el-button>
+      <el-button type="primary" style="width: 120px" :loading="submitLoading" @click="submit">
+        确定
+      </el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import TagCard from '@/components/TagCard'
+import {
+  templateEdit
+} from '@/api/HHOMCDevice.js'
+import { applicationTypeList, deviceModelList } from '@/api/configuration'
+
+export default {
+  components: { TagCard },
+  props: {
+    obj: {
+      type: Object,
+      default: () => {}
+    },
+    isDis: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+      form: {
+        templateName: null, // 模板名称
+        applicationTypeId: null, // 应用类型
+        deviceModelHardwareId: null, // 设备型号(硬件)
+        deviceModelEnvironmentId: null, // 设备型号(环境)
+        systemTypeCode: null, // 系统类型
+        websocketSubscribeUrl: '' // ws地址
+      },
+      rules: {
+        templateName: [
+          {
+            required: true,
+            whitespace: true,
+            message: '不能为空!',
+            trigger: ['change', 'blur']
+          }
+        ]
+      },
+      submitLoading: false,
+      websocketSubscribeUrlList: [
+        {
+          value: 'wss://hhomc.hz-hanghui.com:18096/',
+          desc: '塘栖域名地址'
+        }, {
+          value: 'ws://115.227.34.58:19086/',
+          desc: '塘栖IP地址'
+        }
+      ], // ws地址输入建议
+      applicationList: [], // 应用类型下拉
+      deviceList: [], // 设备型号下拉
+      // 系统类型下拉
+      systemType: [
+        { id: 1, name: '蚂蚁OS' },
+        { id: 2, name: '非蚂蚁OS' }
+      ]
+    }
+  },
+  mounted() {
+    this.initData()
+  },
+  methods: {
+    initData() {
+      this.getApplicationTypeList()
+      this.getDeviceModelList()
+      this.$nextTick(() => {
+        if (this.obj) {
+          console.log(this.obj)
+          this.form = {
+            ...this.obj
+          }
+        }
+      })
+    },
+    // 获取应用类型列表
+    getApplicationTypeList() {
+      applicationTypeList().then((res) => {
+        this.applicationList = res.data
+      })
+    },
+    // 设备型号列表
+    getDeviceModelList() {
+      deviceModelList().then((res) => {
+        this.deviceList = res.data
+      })
+    },
+    querySearch(field, queryString, cb) {
+      const restaurants = this[field]
+      const results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
+      // 调用 callback 返回建议列表的数据
+      cb(results)
+    },
+    createFilter(queryString) {
+      return (restaurant) => {
+        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
+      }
+    },
+    back() {
+      this.$emit('back')
+    },
+    submit(e) {
+      e.preventDefault()
+      this.$refs.form.validate(async(valid) => {
+        if (!valid) {
+          return false
+        }
+        if (this.submitLoading) {
+          return
+        }
+        this.submitLoading = true
+        try {
+          console.log(this.form)
+          await templateEdit(this.form)
+          this.$message({
+            message: `${this.form.deviceTemplateId ? '修改' : '添加'}配置模板成功!`,
+            type: 'success'
+          })
+          this.$emit('back')
+        } catch (e) {
+          console.info('add', e)
+        } finally {
+          this.submitLoading = false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" >
+.my-autocomplete {
+  li {
+    padding: 5px 20px !important;
+
+    .name {
+      line-height: 20px !important;
+      white-space: pre-wrap; /* 保留空白符,如果内容超过容器宽度则换行 */
+      overflow-wrap: break-word; /* 在长单词或URL地址内部进行换行 */
+    }
+    .addr {
+      font-size: 12px;
+      color: #b4b4b4;
+    }
+
+    .highlighted .addr {
+      color: #ddd;
+    }
+  }
+}
+</style>
+<style lang="scss" scoped>
+.card-footer {
+  margin-top: 20px;
+  display: flex;
+  width: 100%;
+  justify-content: center;
+}
+.wrap-content {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  &__item {
+    width: calc(50% - 10px);
+    padding: 10px 10px;
+    .el-form-item {
+      margin-bottom: 0px !important;
+    }
+  }
+}
+.wrap-content-detail {
+  width: calc(100%);
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+  position: relative;
+  border: 1px solid #ebeef5;
+  border-radius: 12px;
+  padding: 10px;
+  box-sizing: border-box;
+  overflow: hidden;
+  margin-bottom: 10px;
+  &__title {
+    position: absolute;
+    background: white;
+    height: 40px;
+    line-height: 40px;
+    top: -20px;
+    z-index: 999;
+    padding: 0 10px;
+  }
+  &__item {
+    width: calc(50% - 10px);
+    .el-form-item {
+      padding: 10px 0px;
+      margin-bottom: 0px !important;
+    }
+  }
+}
+</style>

+ 383 - 0
src/views/HHOMCDeviceTemplate/index.vue

@@ -0,0 +1,383 @@
+<template>
+  <div class="app-container">
+    <div v-if="isShowUpdate">
+      <div class="head">
+        编辑配置模板
+        <el-button
+          type="primary"
+          size="mini"
+          style="margin-left: 10px"
+          @click="back"
+        >返回</el-button>
+      </div>
+      <edit-device-module
+        :key="`device_tem_${updateData.deviceTemplateId}`"
+        :is-dis="true"
+        :obj="updateData"
+        style="margin-left: 16px"
+        @finish="back"
+        @back="back"
+      />
+    </div>
+    <div v-show="!isShowUpdate">
+      <div class="search-layout" style="margin-bottom: 0px; margin-top: -10px">
+        <el-select
+          v-model="form.deviceTemplateId"
+          class="filter-item"
+          placeholder="模板"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in templateDataList"
+            :key="index"
+            :label="item.templateName"
+            :value="item.deviceTemplateId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.applicationTypeId"
+          class="filter-item"
+          placeholder="应用类型"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in applicationList"
+            :key="index"
+            :label="item.applicationType"
+            :value="item.applicationTypeId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.deviceModelHardwareId"
+          class="filter-item"
+          placeholder="设备型号(硬件)"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in devicelList"
+            :key="index"
+            :label="item.deviceModel"
+            :value="item.deviceModelId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.deviceModelEnvironmentId"
+          class="filter-item"
+          placeholder="设备型号(环境)"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in devicelList"
+            :key="index"
+            :label="item.deviceModel"
+            :value="item.deviceModelId"
+          />
+        </el-select>
+        <el-select
+          v-model="form.systemTypeCode"
+          class="filter-item"
+          placeholder="系统类型"
+          clearable
+          filterable
+        >
+          <el-option
+            v-for="(item, index) in systemType"
+            :key="index"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </div>
+      <div class="search-layout">
+        <el-button
+          class="filter-item"
+          style="margin-right: 0"
+          type="primary"
+          icon="el-icon-search"
+          @click="query(1)"
+        >
+          搜索
+        </el-button>
+        <el-button
+          class="filter-item"
+          style="margin-right: 0"
+          type="primary"
+          icon="el-icon-plus"
+          @click="handleCreate"
+        >
+          添加配置模板
+        </el-button>
+      </div>
+      <el-table
+        v-loading="tableLoading"
+        :data="tableData"
+        element-loading-text="加载中..."
+        border
+        fit
+        highlight-current-row
+      >
+        <el-table-column align="center" label="序号" width="95">
+          <template slot-scope="scope">
+            {{
+              (pagination.page - 1) * pagination.pageSize + (scope.$index + 1)
+            }}
+          </template>
+        </el-table-column>
+        <el-table-column label="模板名称">
+          <template slot-scope="scope">
+            {{ scope.row.templateName }}
+          </template>
+        </el-table-column>
+        <el-table-column label="应用类型">
+          <template slot-scope="scope">
+            {{ scope.row.applicationType }}
+          </template>
+        </el-table-column>
+        <el-table-column label="设备型号(硬件)">
+          <template slot-scope="scope">
+            {{ scope.row.deviceModelHardware }}
+          </template>
+        </el-table-column>
+        <el-table-column label="设备型号(环境)">
+          <template slot-scope="scope">
+            {{ scope.row.deviceModelEnvironment }}
+          </template>
+        </el-table-column>
+        <el-table-column label="系统类型">
+          <template slot-scope="scope">
+            {{ scope.row.systemType }}
+          </template>
+        </el-table-column>
+        <el-table-column
+          label="操作"
+          align="center"
+          width="250"
+          class-name="small-padding fixed-width"
+        >
+          <template slot-scope="{ row, $index }">
+            <el-button type="primary" size="mini" @click="handleUpdate(row)">
+              编辑
+            </el-button>
+            <el-button
+              size="mini"
+              type="danger"
+              @click="handleDelete(row, $index)"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        :total="pagination.total"
+        :page.sync="pagination.page"
+        :limit.sync="pagination.pageSize"
+        :page-sizes="pagination.pageSizeOptions"
+        :layout="pagination.layout"
+        @pagination="handleSizeChange"
+      />
+    </div>
+  </div>
+</template>
+
+<script>
+import tableMixins from '@/mixins/tableMixins'
+import Pagination from '@/components/Pagination'
+import EditDeviceModule from './components/EditDeviceModule'
+import {
+  applicationTypeList,
+  deviceModelList,
+  purchaserList
+} from '@/api/configuration'
+import {
+  templatePage,
+  templateDel,
+  templateList
+} from '@/api/HHOMCDevice.js'
+
+export default {
+  components: { Pagination, EditDeviceModule },
+  filters: {
+  },
+  mixins: [tableMixins],
+  data() {
+    return {
+      statusLists: [
+        {
+          key: false,
+          value: '未授权'
+        },
+        {
+          key: true,
+          value: '已授权'
+        }
+      ],
+      form: {},
+      isShowUpdate: false,
+      updateData: {},
+      pagination: {
+        page: 1,
+        current: 1
+      },
+      applicationList: [],
+      devicelList: [],
+      buyList: [],
+      systemType: [
+        { id: 1, name: '蚂蚁OS' },
+        { id: 2, name: '非蚂蚁OS' }
+      ],
+      templateDataList: []
+    }
+  },
+  methods: {
+    initData() {
+      this.getTableList()
+      this.applicationTypeList()
+      this.deviceModelList()
+      this.purchaserList()
+      this.templateList()
+    },
+    // 获取表格数据
+    async getTableList() {
+      this.pagination.current = this.pagination.page
+      this.tableLoading = true
+      try {
+        const result = await templatePage(this.getFilterParams())
+        this.setDataList(result.data)
+      } catch (e) {
+        console.log(e)
+      } finally {
+        this.tableLoading = false
+      }
+    },
+    // 获取筛选信息
+    query(type) {
+      if (type) {
+        this.pagination.page = 1
+        this.pagination.current = 1
+      }
+      this.clearPageParams()
+      this.getTableList()
+      this.templateList()
+    },
+    // 增加筛选条件
+    transformFilterForm() {
+      return {
+        purchaserId: this.form.purchaserId || null,
+        applicationTypeId: this.form.applicationTypeId || null,
+        deviceModelHardwareId: this.form.deviceModelHardwareId || null,
+        deviceModelEnvironmentId: this.form.deviceModelEnvironmentId || null,
+        systemTypeCode: this.form.systemTypeCode || null,
+        sn: this.form.sn || null,
+        company: this.form.company || null,
+        mode: this.form.mode || null,
+        deviceTemplateId: this.form.deviceTemplateId || null
+      }
+    },
+    handleCreate() {
+      this.$router.push({ path: '/HHOMCDevice/addTemplate' })
+    },
+    handleUpdate(row) {
+      this.isShowUpdate = true
+      this.updateData = JSON.parse(JSON.stringify(row))
+    },
+    back() {
+      this.isShowUpdate = false
+      this.query()
+    },
+    templateList() {
+      templateList().then((res) => {
+        this.templateDataList = res.data
+      })
+    },
+    handleDelete(row, index) {
+      const that = this
+      this.$confirm('确定删除吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        showClose: false,
+        type: 'warning',
+        beforeClose: async(action, instance, done) => {
+          if (action === 'confirm') {
+            instance.confirmButtonLoading = true
+            instance.cancelButtonLoading = true
+            instance.confirmButtonText = '提交中...'
+            try {
+              await templateDel(row.deviceTemplateId)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              })
+              that.getTableList()
+              that.templateList()
+            } catch (e) {
+              // this.$message({
+              //   type: 'error',
+              //   message: '删除失败!'
+              // })
+            } finally {
+              done()
+              setTimeout(() => {
+                instance.confirmButtonLoading = false
+                instance.cancelButtonLoading = false
+              }, 300)
+            }
+          } else {
+            done()
+          }
+        }
+      })
+        .then(() => {})
+        .catch(() => {})
+    },
+    // 获取应用类型列表
+    applicationTypeList() {
+      applicationTypeList().then((res) => {
+        this.applicationList = res.data
+      })
+    },
+    // 设备型号列表
+    deviceModelList() {
+      deviceModelList().then((res) => {
+        this.devicelList = res.data
+      })
+    },
+    // 购买方列表
+    purchaserList() {
+      purchaserList().then((res) => {
+        this.buyList = res.data
+      })
+    }
+  }
+}
+</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;
+}
+.head {
+  margin-left: 16px;
+  font-weight: 600;
+  font-size: 18px;
+  color: #333333;
+}
+.input {
+  width: 200px;
+  margin-right: 15px;
+}
+.m-r {
+  margin-right: 15px;
+}
+</style>