Browse Source

添加区域管理

hjs 1 year ago
parent
commit
a56a3a7588

+ 2 - 2
public/config.js

@@ -1,6 +1,6 @@
 window.g = {
   // ApiUrl: 'https://face.ldxk.edu.cn:8901/ywjl-fyzd', //计量
-  ApiUrl: 'https://noise.hz-hanghui.com:8088/yx-fyzd', //浙江
-  // ApiUrl: 'http://192.168.11.17:9100/yx-fyzd', //浙江本地
+  // ApiUrl: 'https://noise.hz-hanghui.com:8088/yx-fyzd', //浙江
+  ApiUrl: 'http://192.168.11.3:9100/yx-fyzd', //浙江本地
 
 }

+ 51 - 0
src/api/area.js

@@ -0,0 +1,51 @@
+import request from '@/utils/request'
+// 获取区域列表分页
+export function getAreaPageList(data) {
+  return request({
+    url: '/admin/zone/page',
+    method: 'post',
+    data
+  })
+}
+
+// 获取区域列表
+export function getAreaList(data) {
+  return request({
+    url: '/admin/zone/list',
+    method: 'post',
+    data
+  })
+}
+
+// 添加/编辑区域
+export function addOrUpdate(data) {
+  return request({
+    url: '/admin/zone/create',
+    method: 'post',
+    data
+  })
+}
+
+// 删除指定区域
+export function deleteArea(areaId) {
+  return request({
+    url: `admin/zone/delete/${areaId}`,
+    method: 'get'
+  })
+}
+
+// 删除指定区域的设备
+export function deleteDeviceOfArea(areaId, deviceId) {
+  return request({
+    url: `admin/zone/sn/delete/${areaId}/${deviceId}`,
+    method: 'get'
+  })
+}
+
+// 获取区域类型
+export function getAreaOfType() {
+  return request({
+    url: 'admin/zone/type/list',
+    method: 'get'
+  })
+}

BIN
src/icons/images/ic_plus.png


+ 61 - 0
src/mixins/tableMixins.js

@@ -0,0 +1,61 @@
+const tableMixins = {
+  data() {
+    return {
+      labelCol: { span: 4 }, // label宽
+      wrapperCol: { span: 20 }, // item宽
+      tableData: [], // table数据
+      tableLoading: false, // 是否加载中
+      sortOrder: 'descend', // 排序
+      pagination: { // 分页
+        current: 1, // 当前页码
+        pageSize: 10, // 每页条数
+        total: 0, // 总数
+        showTotal: total => `共有${total}条数据`, // 显示总数
+        pageSizeOptions: [10, 20, 50, 100], // 分页选项
+        layout: 'total, sizes, prev, pager, next, jumper'
+      }
+    }
+  },
+  mounted() {
+    this.initData()
+  },
+  methods: {
+    getFilterParams() {
+      const params = {
+        pageNum: this.pagination.current,
+        pageSize: this.pagination.pageSize,
+        data: { ...this.transformFilterForm() }
+      }
+      return params
+    },
+    transformFilterForm() {
+      return {}
+    },
+    setDataList(data) {
+      this.pagination.total = data.total || 0
+      this.tableData = data.list || []
+    },
+    handleSizeChange(current, size) {
+      this.getTableList()
+    },
+    async resetFilterFormParams() {
+      this.form = {}
+      this.clearPageParams()
+      await this.getTableList()
+    },
+    clearPageParams() {
+      this.sortOrder = 'descend'
+      this.pagination.current = 1
+      this.pagination.pageSize = 10
+    },
+    onTableChange(pagination, filters, sorter) {
+      this.sortOrder = sorter.order === 'descend' ? 'descend' : 'ascend'
+      this.pagination = pagination
+      this.tableChange(pagination, filters, sorter)
+      this.getTableList()
+    },
+    tableChange(pagination, filters, sorter) {}
+  }
+}
+
+export default tableMixins

+ 12 - 0
src/router/index.js

@@ -66,6 +66,18 @@ export const constantRoutes = [
       }
     ]
   },
+  {
+    path: '/area',
+    component: Layout,
+    children: [
+      {
+        path: 'index',
+        name: 'area_manage',
+        component: () => import('@/views/area/index'),
+        meta: { title: '区域名称列表', role: [5], icon: 'el-icon-map-location' }
+      }
+    ]
+  },
   {
     path: '/enterprise',
     component: Layout,

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

@@ -0,0 +1,383 @@
+<template>
+  <div class="app-container">
+    <addModal ref="addModel" :machine-list="machineList" :area-type-list="areaTypeList" @success="modalSuccess" />
+    <!--搜索区-->
+    <el-select v-model="form.zoneId" filterable clearable placeholder="请选择区域" class="input" no-data-text="“选择区域”为空">
+      <el-option
+        v-for="(item, index) in areaPreviewList"
+        :key="index"
+        :label="item.name"
+        :value="item.id"
+      />
+    </el-select>
+    <el-select
+      v-model="form.sn"
+      filterable
+      clearable
+      placeholder="请选择设备编号"
+      class="margin-left input"
+    >
+      <el-option
+        v-for="(item, index) in machineList"
+        :key="index"
+        :label="item.sn"
+        :value="item.sn"
+      />
+    </el-select>
+    <el-select
+      v-model="form.sn"
+      filterable
+      clearable
+      placeholder="请选择设备地点"
+      class="margin-left input"
+    >
+      <el-option
+        v-for="(item, index) in machineList"
+        :key="index"
+        :label="item.name"
+        :value="item.sn"
+      />
+    </el-select>
+    <el-select
+      v-model="form.zoneType"
+      filterable
+      clearable
+      placeholder="请选择区域类型"
+      class="margin-left input"
+    >
+      <el-option
+        v-for="(item, index) in areaTypeList"
+        :key="index"
+        :label="item.desc"
+        :value="item.type"
+      />
+    </el-select>
+    <el-button type="primary" icon="el-icon-search" class="margin-left" @click="query">搜索</el-button>
+    <!--主表格-->
+    <div class="table-wrap">
+      <div class="table-add" @click="handleCreate">
+        <img src="@/icons/images/ic_plus.png">
+      </div>
+      <div v-for="(item, index) in tableData" :key="index" class="table-item">
+        <div class="table-item-head">
+          <div class="head-title">{{ item.name }}</div>
+          <div style="flex:auto;text-align: center;"><el-tag v-if="item.zoneType" type="success">{{ getAreaDescByType(item.zoneType) }}</el-tag></div>
+          <el-button type="primary" size="small" round @click="handleUpdate(item)">编辑</el-button>
+          <el-button type="danger" icon="el-icon-delete" size="small" circle plain @click="handleAreaDelete(item)" />
+        </div>
+        <div class="table-item-content">
+          <div v-for="(itemS, indexS) in item.devices" :key="indexS" class="content-item">
+            <div class="content-item-id">{{ itemS.sn }}</div>
+            <div class="content-item-name">{{ itemS.name }}</div>
+            <div class="content-item-status">
+              <el-tag v-if="itemS.online === 1" type="success">在线</el-tag>
+              <el-tag v-else type="info">离线</el-tag>
+              <el-button type="danger" icon="el-icon-close" size="mini" class="content-item-status-delete" circle @click="handleDeviceDelete(item.id, itemS)" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!--分页栏-->
+    <pagination
+      :total="pagination.total"
+      :page.sync="pagination.current"
+      :limit.sync="pagination.pageSize"
+      :page-sizes="pagination.pageSizeOptions"
+      :layout="pagination.layout"
+      @pagination="handleSizeChange"
+    />
+  </div>
+</template>
+
+<script>
+import { getAreaPageList, getAreaList, deleteArea, deleteDeviceOfArea, getAreaOfType } from '@/api/area'
+import { getFaceDeviceList } from '@/api/old_api_pengwenbing'
+import tableMixins from '@/mixins/tableMixins'
+import Pagination from '@/components/Pagination'
+import AddModal from './modal/AddModal.vue'
+
+export default {
+  components: { Pagination, AddModal },
+  mixins: [tableMixins],
+  data() {
+    return {
+      form: {
+        zoneId: null,
+        adminId: null,
+        zoneType: null,
+        sn: null
+      },
+      areaPreviewList: [],
+      // 设备列表_搜索
+      machineList: [],
+      // 区域类型列表
+      areaTypeList: []
+    }
+  },
+  methods: {
+    initData() {
+      this.form.adminId = this.$store.getters.adminId
+      this.getAreaList()
+      this.getFaceDeviceList()
+      this.getAreaTypeList()
+      this.getTableList()
+    },
+    getAreaDescByType(type) {
+      if (!type) {
+        return ''
+      }
+      const areaType = this.areaTypeList.find(item => item.type === type)
+      if (!areaType) {
+        return ''
+      }
+      return areaType.desc || ''
+    },
+    // 返回所有的区域列表概览
+    async getAreaList() {
+      try {
+        const result = await getAreaList(this.form)
+        this.areaPreviewList = result.data
+      } catch (e) {
+        console.log(e)
+        this.areaPreviewList = []
+      }
+    },
+    // 获取设备列表-搜索
+    getFaceDeviceList() {
+      getFaceDeviceList().then((res) => {
+        this.machineList = res.data
+      })
+    },
+    // 获取区域类型列表
+    getAreaTypeList() {
+      getAreaOfType().then((res) => {
+        this.areaTypeList = res.data
+      })
+    },
+    // 获取表格数据
+    async getTableList() {
+      this.tableLoading = true
+      try {
+        const result = await getAreaPageList(this.getFilterParams())
+        this.setDataList(result.data)
+      } catch (e) {
+        console.log(e)
+      } finally {
+        this.tableLoading = false
+      }
+    },
+    // 获取筛选信息
+    query() {
+      this.clearPageParams()
+      this.getTableList()
+    },
+    // 增加筛选条件
+    transformFilterForm() {
+      return this.form
+    },
+    modalSuccess(isEdit) {
+      if (!isEdit) {
+        this.clearPageParams()
+      }
+      this.getTableList()
+    },
+    handleCreate() {
+      this.$refs.addModel.open()
+    },
+    handleUpdate(row) {
+      this.$refs.addModel.open(Object.assign({}, row))
+    },
+    handleAreaDelete(row) {
+      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 deleteArea(row.id)
+              this.$message({
+                type: 'success',
+                message: '删除成功!'
+              })
+              that.getAreaList()
+              that.getTableList()
+            } catch (e) {
+              // this.$message({
+              //   type: 'error',
+              //   message: '删除失败!'
+              // })
+            } finally {
+              done()
+              setTimeout(() => {
+                instance.confirmButtonLoading = false
+                instance.cancelButtonLoading = false
+              }, 300)
+            }
+          } else {
+            done()
+          }
+        }
+      }).then(() => {}).catch(() => {})
+    },
+    handleDeviceDelete(areaId, row) {
+      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 deleteDeviceOfArea(areaId, row.sn)
+              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(() => {})
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+  .table{
+    margin-top: 15px;
+  }
+  .flex {
+    display: flex;
+    justify-content: flex-start;
+    align-items: center;
+  }
+  .margin-left {
+    margin: 10px 0 0 10px;
+  }
+  .input {
+    width: 200px;
+  }
+  ::-webkit-scrollbar{
+    width: 6px;
+    height: 6px;
+    background-color: #F1F2F5;
+  }
+
+::-webkit-scrollbar-thumb{
+  background-color:#BFC6D4;
+  border-radius: 10px;
+}
+::-webkit-scrollbar-track{
+  background-color: transparent;
+}
+  .table-wrap {
+    display: flex;
+    flex-wrap: wrap;
+    & > div {
+      margin-top: 28px;
+      margin-left: 1%;
+      min-width: 375px;
+      width: 32%;
+      height: 256px;
+      flex: none;
+      overflow: hidden;
+      border: 1px solid #E3E9F8;
+      border-radius: 8px;
+    }
+    & > div:nth-of-type(3n+1) {
+      margin-left: 0;
+    }
+    .table-add {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      background-color: #F8FAFF;
+      cursor: pointer;
+      & img {
+        width: 80px;
+        height: 80px;
+      }
+    }
+    .table-item {
+      display: flex;
+      flex-direction: column;
+      .table-item-head {
+        width: 100%;
+        height: 62px;
+        display: flex;
+        align-items: center;
+        padding: 0 14px 0 20px;
+        background-color: #E3EBFF57;
+        .head-title {
+          font-size: 20px;
+          color: #1B55AB;
+        }
+      }
+      .table-item-content {
+        width: 100%;
+        padding: 0 12px;
+        height: calc(256px - 62px);
+        overflow: auto;
+        .content-item {
+          margin-top: 12px;
+          padding: 4px 6px;
+          display: flex;
+          align-items: center;
+          font-size: 14xp;
+          color: #606266;
+          &:last-of-type {
+            margin-bottom: 12px;
+          }
+          &:hover {
+            background-color: #F5F8FF;
+            border-radius: 5px;
+            .content-item-status .content-item-status-delete {
+              visibility: visible;
+            }
+          }
+          .content-item-id {
+            width: 160px;
+            flex: none;
+          }
+          .content-item-name {
+            flex: auto;
+          }
+          .content-item-status {
+            flex: none;
+            display: flex;
+            align-items: center;
+            .content-item-status-delete {
+              margin-left: 15px;
+              visibility: hidden;
+              padding: 3px !important;
+            }
+          }
+        }
+      }
+    }
+  }
+</style>

+ 134 - 0
src/views/area/modal/AddModal.vue

@@ -0,0 +1,134 @@
+// 添加/修改商户
+<template>
+  <el-dialog
+    :title="isEdit ? '编辑区域' : '添加区域'"
+    width="766px"
+    :visible.sync="visible"
+    :destroy-on-close="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="form" :rules="rules" :model="form" label-position="left" label-width="100px">
+      <el-form-item prop="id" style="margin-bottom: 0;">&nbsp;</el-form-item>
+      <el-form-item label="区域名称" prop="name" required>
+        <el-input v-model="form.name" placeholder="请输入区域名称" />
+      </el-form-item>
+      <el-form-item label="绑定设备" prop="snJson" required>
+        <el-select v-model="form.snJson" class="filter-item" placeholder="请选择设备进行绑定" clearable multiple filterable>
+          <el-option v-for="(item, index) in machineList" :key="index" :label="item.sn" :value="item.sn" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="区域类型" prop="zoneType">
+        <el-select v-model="form.zoneType" class="filter-item" placeholder="请选择区域类型" clearable>
+          <el-option v-for="(item, index) in areaTypeList" :key="index" :label="item.desc" :value="item.type" />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="visible = false">
+        取消
+      </el-button>
+      <el-button type="primary" :loading="submitLoading" @click="submit">
+        确定
+      </el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { addOrUpdate } from '@/api/area'
+
+export default {
+  props: {
+    machineList: {
+      type: Array,
+      default: () => []
+    },
+    areaTypeList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      form: {
+        id: null,
+        name: null,
+        zoneType: null,
+        snJson: null
+      },
+      rules: {
+        name: [
+          { required: true, whitespace: true, message: '不能为空!', trigger: ['change', 'blur'] }
+        ],
+        // zoneType: [
+        //   { required: false, type: 'number', message: '不能为空!', trigger: ['change', 'blur'] }
+        // ],
+        snJson: [
+          { required: true, type: 'array', message: '不能为空!', trigger: ['change', 'blur'] }
+        ]
+      },
+      visible: false,
+      submitLoading: false,
+      isEdit: false
+    }
+  },
+  methods: {
+    open(obj) {
+      this.visible = true
+      this.submitLoading = false
+      this.$nextTick(() => {
+        this.$refs.form.resetFields()
+        if (obj && Object.keys(obj).length > 0) {
+          this.form.id = obj.id
+          this.form.name = obj.name
+          this.form.zoneType = obj.zoneType
+          if (obj.snJson) {
+            this.form.snJson = obj.snJson.split(',')
+          } else {
+            this.form.snJson = null
+          }
+          this.isEdit = true
+        } else {
+          this.isEdit = false
+        }
+      })
+    },
+    submit(e) {
+      e.preventDefault()
+      this.$refs.form.validate(async(valid) => {
+        if (!valid) {
+          return false
+        }
+        if (this.submitLoading) {
+          return
+        }
+        if (this.form.snJson && this.form.snJson.length > 0) {
+          this.form.snJson = this.form.snJson.join(',')
+        } else {
+          this.form.snJson = null
+        }
+        this.submitLoading = true
+        try {
+          await addOrUpdate({ ...this.form, adminId: this.$store.getters.adminId })
+          this.visible = false
+          this.$emit('success', this.isEdit)
+        } catch (e) {
+          this.$refs.form.resetFields()
+          console.info('add', e)
+        } finally {
+          this.submitLoading = false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+::v-deep .el-select {
+  width: 100%;
+}
+::v-deep .el-dialog__body {
+  padding-bottom: 0;
+}
+</style>

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

@@ -239,8 +239,8 @@ $cursor: #fff;
       caret-color: black;
 
       &:-webkit-autofill {
-        box-shadow: 0 0 0px 1000px $bg inset !important;
-        -webkit-text-fill-color: $cursor !important;
+        box-shadow: 0 0 0px 1000px rgb(224,232,251) inset !important;
+        -webkit-text-fill-color: #000 !important;
       }
     }
   }