From 35668474b65be39a277d7cb53693022b482e17ca Mon Sep 17 00:00:00 2001
From: 唐耀东 <18861537@qq.com>
Date: 星期四, 12 五月 2022 09:44:22 +0800
Subject: [PATCH] 提交代码

---
 src/views/components/organization/form.vue             |   81 ++
 src/views/components/nvr/list.vue                      |  130 +++
 src/views/construction/constructionBatch/index.vue     |   14 
 src/api/oa/nvr.js                                      |   44 +
 src/views/components/manufacturer/index.vue            |   71 +
 src/views/construction/reserveIp/index.vue             |   18 
 src/api/oa/organization.js                             |   44 +
 src/views/basics/building/index.vue                    |    8 
 src/views/basics/organization/index.vue                |  292 +++++++
 src/views/components/nvr/index.vue                     |   76 +
 src/views/construction/ipc/index.vue                   |  413 ++++++++++
 src/views/components/building/buildList.vue            |    6 
 src/views/components/building/index.vue                |   44 
 src/views/components/constructionBatch/index.vue       |   74 +
 src/views/basics/school/index.vue                      |   23 
 src/views/construction/constructionList/index.vue      |   29 
 src/views/components/organization/organizationList.vue |  127 +++
 src/views/components/building/form.vue                 |    1 
 src/views/components/manufacturer/list.vue             |  102 ++
 src/views/construction/nvr/index.vue                   |  527 +++++++++++++
 src/api/oa/ipc.js                                      |   44 +
 src/views/components/organization/index.vue            |   76 +
 src/views/components/constructionBatch/list.vue        |  116 ++
 23 files changed, 2,326 insertions(+), 34 deletions(-)

diff --git a/src/api/oa/ipc.js b/src/api/oa/ipc.js
new file mode 100644
index 0000000..e870ff2
--- /dev/null
+++ b/src/api/oa/ipc.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨipc璁惧鍒楄〃
+export function listIpc(query) {
+  return request({
+    url: '/oa/ipc/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨipc璁惧璇︾粏
+export function getIpc(id) {
+  return request({
+    url: '/oa/ipc/' + id,
+    method: 'get'
+  })
+}
+
+// 鏂板ipc璁惧
+export function addIpc(data) {
+  return request({
+    url: '/oa/ipc',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼ipc璁惧
+export function updateIpc(data) {
+  return request({
+    url: '/oa/ipc',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎ipc璁惧
+export function delIpc(id) {
+  return request({
+    url: '/oa/ipc/' + id,
+    method: 'delete'
+  })
+}
diff --git a/src/api/oa/nvr.js b/src/api/oa/nvr.js
new file mode 100644
index 0000000..a91460f
--- /dev/null
+++ b/src/api/oa/nvr.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨNVR璁惧鍒楄〃
+export function listNvr(query) {
+  return request({
+    url: '/oa/nvr/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨNVR璁惧璇︾粏
+export function getNvr(id) {
+  return request({
+    url: '/oa/nvr/' + id,
+    method: 'get'
+  })
+}
+
+// 鏂板NVR璁惧
+export function addNvr(data) {
+  return request({
+    url: '/oa/nvr',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼NVR璁惧
+export function updateNvr(data) {
+  return request({
+    url: '/oa/nvr',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎NVR璁惧
+export function delNvr(id) {
+  return request({
+    url: '/oa/nvr/' + id,
+    method: 'delete'
+  })
+}
diff --git a/src/api/oa/organization.js b/src/api/oa/organization.js
new file mode 100644
index 0000000..0a0082d
--- /dev/null
+++ b/src/api/oa/organization.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ楂樻牎缁勭粐鏈烘瀯鍒楄〃
+export function listOrganization(query) {
+  return request({
+    url: '/oa/organization/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ楂樻牎缁勭粐鏈烘瀯璇︾粏
+export function getOrganization(id) {
+  return request({
+    url: '/oa/organization/' + id,
+    method: 'get'
+  })
+}
+
+// 鏂板楂樻牎缁勭粐鏈烘瀯
+export function addOrganization(data) {
+  return request({
+    url: '/oa/organization',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼楂樻牎缁勭粐鏈烘瀯
+export function updateOrganization(data) {
+  return request({
+    url: '/oa/organization',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎楂樻牎缁勭粐鏈烘瀯
+export function delOrganization(id) {
+  return request({
+    url: '/oa/organization/' + id,
+    method: 'delete'
+  })
+}
diff --git a/src/views/basics/building/index.vue b/src/views/basics/building/index.vue
index 294d29d..6ebe0a9 100644
--- a/src/views/basics/building/index.vue
+++ b/src/views/basics/building/index.vue
@@ -33,7 +33,6 @@
             icon="el-icon-plus"
             size="mini"
             @click="handleAdd"
-            v-hasPermi="['oa:building:add']"
         >鏂板
         </el-button>
       </el-col>
@@ -56,7 +55,6 @@
               type="text"
               icon="el-icon-edit"
               @click="handleUpdate(scope.row)"
-              v-hasPermi="['oa:building:edit']"
           >淇敼
           </el-button>
           <el-button
@@ -64,7 +62,6 @@
               type="text"
               icon="el-icon-plus"
               @click="handleAdd(scope.row)"
-              v-hasPermi="['oa:building:add']"
           >鏂板
           </el-button>
           <el-button
@@ -73,7 +70,6 @@
               class="del-btn"
               icon="el-icon-delete"
               @click="handleDelete(scope.row)"
-              v-hasPermi="['oa:building:remove']"
           >鍒犻櫎
           </el-button>
         </template>
@@ -81,7 +77,7 @@
     </el-table>
 
     <!-- 娣诲姞鎴栦慨鏀瑰缓绛戝崟鍏冨璇濇 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+    <el-dialog :title="title" :visible.sync="open" width="500px" :append-to-body="true" :close-on-click-modal="false">
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
         <el-form-item label="涓婄骇鍗曞厓" prop="parentId">
           <treeselect v-model="form.parentId" :options="buildingOptions" :normalizer="normalizer"
@@ -256,9 +252,9 @@
     /** 鎻愪氦鎸夐挳 */
     submitForm() {
       this.$refs["form"].validate(valid => {
-        this.form.schoolId = this.schoolId;
         if (valid) {
           this.buttonLoading = true;
+          this.form.schoolId = this.schoolId;
           if (this.form.id != null) {
             updateBuilding(this.form).then(response => {
               this.$modal.msgSuccess("淇敼鎴愬姛");
diff --git a/src/views/basics/organization/index.vue b/src/views/basics/organization/index.vue
new file mode 100644
index 0000000..946b4f6
--- /dev/null
+++ b/src/views/basics/organization/index.vue
@@ -0,0 +1,292 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鏈烘瀯鍚嶇О" prop="name">
+        <el-input
+            v-model="queryParams.name"
+            placeholder="璇疯緭鍏ユ満鏋勫悕绉�"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="mini"
+            @click="handleAdd"
+        >鏂板
+        </el-button>
+      </el-col>
+    </el-row>
+
+    <el-table
+        v-loading="loading"
+        :data="organizationList"
+        row-key="id"
+        default-expand-all
+        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column label="鏈烘瀯鍚嶇О" align="center" prop="name"/>
+      <el-table-column label="鏈烘瀯缂栧彿" prop="code"/>
+      <el-table-column label="鏄剧ず椤哄簭" align="center" prop="orderNum"/>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-edit"
+              @click="handleUpdate(scope.row)"
+          >淇敼
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-plus"
+              @click="handleAdd(scope.row)"
+          >鏂板
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-delete"
+              @click="handleDelete(scope.row)"
+          >鍒犻櫎
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀归珮鏍$粍缁囨満鏋勫璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" :append-to-body="true" :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="涓婄骇鏈烘瀯" prop="parentId">
+          <treeselect v-model="form.parentId" :options="organizationOptions" :normalizer="normalizer"
+                      placeholder="璇烽�夋嫨鐖剁骇id"/>
+        </el-form-item>
+        <el-form-item label="鏈烘瀯鍚嶇О" prop="name">
+          <el-input v-model="form.name" placeholder="璇疯緭鍏ユ満鏋勫悕绉�"/>
+        </el-form-item>
+        <el-form-item label="鏈烘瀯缂栧彿" prop="code">
+          <el-input v-model="form.code" placeholder="璇疯緭鍏ユ満鏋勭紪鍙�"/>
+        </el-form-item>
+        <el-form-item label="鏄剧ず椤哄簭" prop="orderNum">
+          <el-input-number v-model="form.orderNum" controls-position="right" :min="0"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import {
+  listOrganization,
+  getOrganization,
+  delOrganization,
+  addOrganization,
+  updateOrganization
+} from "@/api/oa/organization";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Organization",
+  components: {
+    Treeselect
+  },
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      // 鎸夐挳loading
+      buttonLoading: false,
+      // 閬僵灞�
+      loading: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 楂樻牎缁勭粐鏈烘瀯琛ㄦ牸鏁版嵁
+      organizationList: [],
+      // 楂樻牎缁勭粐鏈烘瀯鏍戦�夐」
+      organizationOptions: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        name: null,
+        schoolId: this.schoolId
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        id: [
+          {required: true, message: "涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        code: [
+          {required: true, message: "鏈烘瀯缂栧彿涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        name: [
+          {required: true, message: "鏈烘瀯鍚嶇О涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        schoolId: [
+          {required: true, message: "楂樻牎涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        parentId: [
+          {required: true, message: "鐖剁骇id涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ楂樻牎缁勭粐鏈烘瀯鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listOrganization(this.queryParams).then(response => {
+        this.organizationList = this.handleTree(response.data, "id", "parentId");
+        this.loading = false;
+      });
+    },
+    /** 杞崲楂樻牎缁勭粐鏈烘瀯鏁版嵁缁撴瀯 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.id,
+        label: node.name,
+        children: node.children
+      };
+    },
+    /** 鏌ヨ楂樻牎缁勭粐鏈烘瀯涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      listOrganization().then(response => {
+        this.organizationOptions = [];
+        const data = {id: 0, name: '椤剁骇鑺傜偣', children: []};
+        data.children = this.handleTree(response.data, "id", "parentId");
+        this.organizationOptions.push(data);
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        id: null,
+        code: null,
+        name: null,
+        detailedName: null,
+        schoolId: null,
+        parentId: null,
+        ancestors: null,
+        orderNum: null,
+        createBy: null,
+        createTime: null,
+        updateBy: null,
+        updateTime: null,
+        delFlag: null
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null && row.id) {
+        this.form.parentId = row.id;
+      } else {
+        this.form.parentId = 0;
+      }
+      this.open = true;
+      this.title = "娣诲姞楂樻牎缁勭粐鏈烘瀯";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.loading = true;
+      this.reset();
+      this.getTreeselect();
+      if (row != null) {
+        this.form.parentId = row.id;
+      }
+      getOrganization(row.id).then(response => {
+        this.loading = false;
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼楂樻牎缁勭粐鏈烘瀯";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.buttonLoading = true;
+          this.form.schoolId = this.schoolId;
+          if (this.form.id != null) {
+            updateOrganization(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          } else {
+            addOrganization(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$modal.confirm('鏄惁纭鍒犻櫎楂樻牎缁勭粐鏈烘瀯缂栧彿涓�"' + row.id + '"鐨勬暟鎹」锛�').then(() => {
+        this.loading = true;
+        return delOrganization(row.id);
+      }).then(() => {
+        this.loading = false;
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).finally(() => {
+        this.loading = false;
+      });
+    }
+  }
+};
+</script>
diff --git a/src/views/basics/school/index.vue b/src/views/basics/school/index.vue
index 11578c7..1f38640 100644
--- a/src/views/basics/school/index.vue
+++ b/src/views/basics/school/index.vue
@@ -143,6 +143,13 @@
           <el-button
               size="mini"
               type="text"
+              icon="el-icon-wind-power"
+              @click="handleOrganization(scope.row)"
+          >鏈烘瀯
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
               icon="el-icon-office-building"
               @click="handleBuild(scope.row)"
           >寤虹瓚
@@ -235,9 +242,15 @@
         <el-button @click="cancel">鍙� 娑�</el-button>
       </div>
     </Dialog>
+
     <!-- 寤虹瓚 -->
     <el-drawer title="寤虹瓚鍗曞厓" :visible.sync="buildOpen" size="50%" :append-to-body="true" :destroy-on-close="true">
       <building :schoolId="id"></building>
+    </el-drawer>
+
+    <!-- 缁勭粐鏈烘瀯 -->
+    <el-drawer title="缁勭粐鏈烘瀯" :visible.sync="organizationOpen" size="50%" :append-to-body="true" :destroy-on-close="true">
+      <organization :schoolId="id"></organization>
     </el-drawer>
   </div>
 </template>
@@ -246,12 +259,14 @@
 import {listSchool, getSchool, delSchool, addSchool, updateSchool} from "@/api/oa/school";
 import {listProvince, listCity} from "@/api/common/common";
 import building from '../building'
+import organization from '../organization'
 
 export default {
   name: "School",
   dicts: ['DICT105', 'DICT106'],
   components: {
-    building
+    building,
+    organization
   },
   data() {
     return {
@@ -324,6 +339,7 @@
       // 鍩庡競
       cityFormList: [],
       buildOpen: false,
+      organizationOpen: false,
       id: undefined
     };
   },
@@ -489,6 +505,11 @@
     handleBuild(r) {
       this.id = r.id;
       this.buildOpen = true;
+    },
+    // 缁勭粐鏈烘瀯
+    handleOrganization(r) {
+      this.id = r.id;
+      this.organizationOpen = true;
     }
   }
 };
diff --git a/src/views/components/building/buildList.vue b/src/views/components/building/buildList.vue
index dfaeccf..8a9174c 100644
--- a/src/views/components/building/buildList.vue
+++ b/src/views/components/building/buildList.vue
@@ -73,10 +73,8 @@
       currentRow: undefined
     };
   },
-  watch: {
-    'schoolId': function (v) {
-      this.getList()
-    }
+  mounted() {
+    this.getList()
   },
   methods: {
     /** 鏌ヨ寤虹瓚鍗曞厓鍒楄〃 */
diff --git a/src/views/components/building/form.vue b/src/views/components/building/form.vue
index c6314d2..3050dbb 100644
--- a/src/views/components/building/form.vue
+++ b/src/views/components/building/form.vue
@@ -19,6 +19,7 @@
 
 <script>
 /**
+ * !!!鏆傛椂寮冪敤
  * 閫夋嫨寤虹瓚鍗曞厓
  */
 import school from '../../components/school'
diff --git a/src/views/components/building/index.vue b/src/views/components/building/index.vue
index 964dcf6..69ad75c 100644
--- a/src/views/components/building/index.vue
+++ b/src/views/components/building/index.vue
@@ -1,21 +1,28 @@
 <template>
   <div>
-    <el-input placeholder="璇烽�夋嫨閫傜敤鍦扮偣" :value="buildingName" disabled>
+    <el-input placeholder="璇烽�夋嫨" :value="name" disabled>
       <el-button slot="append" icon="el-icon-thumb" @click="handleBuilding"></el-button>
     </el-input>
     <el-dialog title="寤虹瓚鍗曞厓" :visible.sync="open" width="800px" :append-to-body="true" :destroy-on-close="true">
-      <building-form @choice="choice"></building-form>
+      <buildList v-if="open" ref="buildRef" :schoolId="schoolId"></buildList>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="open = false">鍙� 娑�</el-button>
+      </div>
     </el-dialog>
   </div>
 </template>
 
 <script>
-import buildingForm from './form'
-
+import buildList from "./buildList";
+import { getBuilding } from "@/api/oa/building";
+/**
+ * 楂樻牎寤虹瓚鍗曞厓
+ */
 export default {
   name: "BuildInput",
   components: {
-    buildingForm
+    buildList
   },
   model: {
     prop: 'value',
@@ -26,12 +33,22 @@
       type: [Number],
       default: undefined
     },
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
   },
   data() {
     return {
-      message: undefined,
       open: false,
-      buildingName: ''
+      name: ''
+    }
+  },
+  created() {
+    if (this.value) {
+      getBuilding(this.value).then(response => {
+        this.name = response.data.name;
+      });
     }
   },
   methods: {
@@ -39,11 +56,16 @@
     handleBuilding() {
       this.open = true;
     },
-    // 閫変腑寤虹瓚鍗曞厓
-    choice(r) {
-      this.buildingName = r.name;
+    submitForm() {
+      if (!this.$refs.buildRef.currentRow) {
+        this.$message.warning("璇烽�夋嫨涓�鏉℃暟鎹�")
+        this.buttonLoading = false;
+        return;
+      }
+      const row = this.$refs.buildRef.currentRow;
+      this.name = row.name;
       this.open = false;
-      this.$emit("change", r.id);
+      this.$emit("change", row.id);
     }
   }
 }
diff --git a/src/views/components/constructionBatch/index.vue b/src/views/components/constructionBatch/index.vue
new file mode 100644
index 0000000..722b685
--- /dev/null
+++ b/src/views/components/constructionBatch/index.vue
@@ -0,0 +1,74 @@
+<template>
+  <div>
+    <el-input placeholder="璇烽�夋嫨" :value="name" disabled>
+      <el-button slot="append" icon="el-icon-thumb" @click="handleClick"></el-button>
+    </el-input>
+    <el-dialog title="鏂藉伐鎵规" :visible.sync="open" width="800px" :append-to-body="true" :destroy-on-close="true">
+      <construction-batch-form v-if="open" ref="batchRef" :schoolId="schoolId"></construction-batch-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="open = false">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import constructionBatchForm from './list'
+import { getConstructionBatch } from "@/api/oa/constructionBatch";
+
+export default {
+  name: "BuildInput",
+  components: {
+    constructionBatchForm
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
+  props: {
+    value: {
+      type: [Number],
+      default: undefined
+    },
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      open: false,
+      name: ''
+    }
+  },
+  created() {
+    if (this.value) {
+      getConstructionBatch(this.value).then(response => {
+        this.name = response.data.batch;
+      });
+    }
+  },
+  methods: {
+    // 閫夋嫨
+    handleClick() {
+      this.open = true;
+    },
+    // 纭畾
+    submitForm() {
+      const row = this.$refs.batchRef.currentRow;
+      if (!row) {
+        this.$message.warning("璇烽�夋嫨涓�鏉℃暟鎹�")
+        return;
+      }
+      this.name = row.batch;
+      this.open = false;
+      this.$emit("change", row.id);
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/components/constructionBatch/list.vue b/src/views/components/constructionBatch/list.vue
new file mode 100644
index 0000000..6740207
--- /dev/null
+++ b/src/views/components/constructionBatch/list.vue
@@ -0,0 +1,116 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鏂藉伐鎵规" prop="batch">
+        <el-input
+          v-model="queryParams.batch"
+          placeholder="璇疯緭鍏ユ柦宸ユ壒娆�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="constructionBatchList" highlight-current-row
+              @current-change="handleCurrentChange">
+      <el-table-column label="搴忓彿" type="index" align="center">
+        <template slot-scope="scope">
+          <span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鏂藉伐鎵规" align="center" prop="batch" />
+      <el-table-column label="鏂藉伐鍛ㄦ湡" align="center" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.startDate, '{y}-{m}-{d}') + ' - ' + parseTime(scope.row.endDate, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="璐熻矗浜�" align="center" prop="userId_dictText" />
+      <el-table-column label="鍥㈤槦鎴愬憳" align="center" prop="teamMembers" />
+      <el-table-column label="澶囨敞" align="center" prop="remarks" />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listConstructionBatch } from "@/api/oa/constructionBatch";
+/**
+ * 楂樻牎鏂藉伐鎵规
+ */
+export default {
+  name: "ConstructionBatchForm",
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      // 鎸夐挳loading
+      buttonLoading: false,
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鏂藉伐鎵规琛ㄦ牸鏁版嵁
+      constructionBatchList: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        batch: undefined
+      },
+      currentRow: undefined
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鏂藉伐鎵规鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listConstructionBatch(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
+        this.constructionBatchList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleCurrentChange(v) {
+      this.currentRow = v;
+    }
+  }
+};
+</script>
diff --git a/src/views/components/manufacturer/index.vue b/src/views/components/manufacturer/index.vue
new file mode 100644
index 0000000..ff9a575
--- /dev/null
+++ b/src/views/components/manufacturer/index.vue
@@ -0,0 +1,71 @@
+<template>
+  <div>
+    <el-input placeholder="璇烽�夋嫨" :value="name" disabled>
+      <el-button slot="append" icon="el-icon-thumb" @click="handleClick"></el-button>
+    </el-input>
+    <el-dialog title="鐢熶骇鍘傚晢" :visible.sync="open" width="800px" :append-to-body="true" :destroy-on-close="true">
+      <manufacturer-list v-if="open" ref="manufacturerRef"></manufacturer-list>
+      <div slot="footer" class="dialog-footer">
+        <el-button  type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="open = false">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import manufacturerList from "./list";
+import { getManufacturer } from "@/api/oa/manufacturer";
+/**
+ * 鐢熶骇鍘傚晢
+ */
+export default {
+  name: "manufacturerInput",
+  components: {
+    manufacturerList
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
+  props: {
+    value: {
+      type: [Number],
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      open: false,
+      name: ''
+    }
+  },
+  created() {
+    if (this.value) {
+      getManufacturer(this.value).then(response => {
+        this.name = response.data.name;
+      });
+    }
+  },
+  methods: {
+    handleClick() {
+      this.open = true;
+    },
+    submitForm() {
+      const row = this.$refs.manufacturerRef.currentRow;
+      if (!row) {
+        this.$message.warning("璇烽�夋嫨涓�鏉℃暟鎹�")
+        this.buttonLoading = false;
+        return;
+      }
+      this.name = row.name;
+      this.open = false;
+      this.$emit("change", row.id);
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/components/manufacturer/list.vue b/src/views/components/manufacturer/list.vue
new file mode 100644
index 0000000..c9afa4f
--- /dev/null
+++ b/src/views/components/manufacturer/list.vue
@@ -0,0 +1,102 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
+      <el-form-item label="鍘傚晢鍚嶇О" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="璇疯緭鍏ュ巶鍟嗗悕绉�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鍘傚晢浠g爜" prop="code">
+        <el-input
+          v-model="queryParams.code"
+          placeholder="璇疯緭鍏ュ巶鍟嗕唬鐮�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="manufacturerList"  highlight-current-row
+              @current-change="handleCurrentChange">
+      <el-table-column label="搴忓彿" align="center" width="50">
+        <template slot-scope="scope">
+          <span>{{ scope.$index + (queryParams.pageNum - 1) * queryParams.pageSize + 1 }} </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍘傚晢鍚嶇О" align="center" prop="name" />
+      <el-table-column label="鍘傚晢浠g爜" align="center" prop="code" />
+      <el-table-column label="鑱旂郴鏂瑰紡" align="center" prop="phone" />
+      <el-table-column label="閭" align="center" prop="mailbox" />
+      <el-table-column label="鑱旂郴鍦板潃" align="center" prop="contactAddress" show-overflow-tooltip />
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listManufacturer } from "@/api/oa/manufacturer";
+
+export default {
+  name: "Manufacturer",
+  data() {
+    return {
+      loading: false,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鍘傚晢琛ㄦ牸鏁版嵁
+      manufacturerList: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        name: undefined,
+        code: undefined
+      },
+      currentRow: undefined
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鍘傚晢鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listManufacturer(this.queryParams).then(response => {
+        this.manufacturerList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleCurrentChange(v) {
+      this.currentRow = v;
+    }
+  }
+};
+</script>
diff --git a/src/views/components/nvr/index.vue b/src/views/components/nvr/index.vue
new file mode 100644
index 0000000..783c5c7
--- /dev/null
+++ b/src/views/components/nvr/index.vue
@@ -0,0 +1,76 @@
+<template>
+  <div>
+    <el-input placeholder="璇烽�夋嫨" :value="name" disabled>
+      <el-button slot="append" icon="el-icon-thumb" @click="handleClick"></el-button>
+    </el-input>
+    <el-dialog title="NVR" :visible.sync="open" width="800px" :append-to-body="true" :destroy-on-close="true">
+      <nvr-list v-if="open" ref="nvrRef" :schoolId="schoolId"></nvr-list>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="open = false">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import nvrList from "./list";
+import {getNvr} from "@/api/oa/nvr";
+
+/**
+ * 楂樻牎NVR
+ */
+export default {
+  name: "manufacturerInput",
+  components: {
+    nvrList
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
+  props: {
+    value: {
+      type: [Number],
+      default: undefined
+    },
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      open: false,
+      name: ''
+    }
+  },
+  created() {
+    if (this.value) {
+      getNvr(this.value).then(response => {
+        this.name = response.data.deploymentName;
+      });
+    }
+  },
+  methods: {
+    handleClick() {
+      this.open = true;
+    },
+    submitForm() {
+      const row = this.$refs.nvrRef.currentRow;
+      if (!row) {
+        this.$message.warning("璇烽�夋嫨涓�鏉℃暟鎹�")
+        this.buttonLoading = false;
+        return;
+      }
+      this.name = row.deploymentName;
+      this.open = false;
+      this.$emit("change", row.id);
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/components/nvr/list.vue b/src/views/components/nvr/list.vue
new file mode 100644
index 0000000..475b604
--- /dev/null
+++ b/src/views/components/nvr/list.vue
@@ -0,0 +1,130 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="88px">
+      <el-form-item label="閫氶亾锛堣矾锛�" prop="passageway">
+        <el-select v-model="queryParams.passageway" placeholder="璇烽�夋嫨閫氶亾锛堣矾锛�">
+          <el-option
+              v-for="dict in dict.type.DICT109"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="nvrList" highlight-current-row
+              @current-change="handleCurrentChange">
+      <el-table-column label="搴忓彿" align="center" width="50">
+        <template slot-scope="scope">
+          <span>{{ scope.$index + (queryParams.pageNum - 1) * queryParams.pageSize + 1 }} </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="閮ㄧ讲鍚嶇О" align="center" prop="deploymentName"/>
+      <el-table-column label="閫氶亾锛堣矾锛�" align="center" prop="passageway"/>
+      <el-table-column label="LAN1" align="center" prop="lanOne"/>
+      <el-table-column label="IP" align="center" prop="ipOne"/>
+      <el-table-column label="LAN2" align="center" prop="lanTwo"/>
+      <el-table-column label="IP" align="center" prop="ipTwo"/>
+      <el-table-column label="鐧诲綍璐︽埛" align="center" prop="loginAccount"/>
+      <el-table-column label="纭洏" align="center" prop="hardDisk"/>
+      <el-table-column label="瀹夎浣嶇疆" align="center" prop="buildingId"/>
+      <el-table-column label="鎵�灞炲崟浣�" align="center" prop="organizationId"/>
+      <!--      <el-table-column label="鏂藉伐鎵规" align="center" prop="constructionBatchId" />-->
+      <!--      <el-table-column label="搴忓垪鍙�" align="center" prop="serialNumber" />-->
+      <!--      <el-table-column label="鍨嬪彿" align="center" prop="model" />-->
+      <!--      <el-table-column label="鐢熶骇鍘傚晢" align="center" prop="manufacturerId" />-->
+    </el-table>
+
+    <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import {listNvr, getNvr, delNvr, addNvr, updateNvr} from "@/api/oa/nvr";
+import building from '../../components/building'
+import organization from '../../components/organization'
+import constructionBatch from '../../components/constructionBatch'
+import manufacturer from '../../components/manufacturer'
+
+export default {
+  name: "Nvr",
+  dicts: ['DICT109'],
+  components: {
+    building,
+    organization,
+    constructionBatch,
+    manufacturer
+  },
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // NVR璁惧琛ㄦ牸鏁版嵁
+      nvrList: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        passageway: undefined,
+        buildingId: undefined,
+        organizationId: undefined,
+        constructionBatchId: undefined,
+        model: undefined
+      },
+      currentRow: undefined
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨNVR璁惧鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listNvr(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
+        this.nvrList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleCurrentChange(v) {
+      this.currentRow = v;
+    }
+  }
+};
+</script>
diff --git a/src/views/components/organization/form.vue b/src/views/components/organization/form.vue
new file mode 100644
index 0000000..74ab9b6
--- /dev/null
+++ b/src/views/components/organization/form.vue
@@ -0,0 +1,81 @@
+<template>
+  <div>
+    <div class="app-container">
+      <div class="tree-view">
+        <div class="tree-list">
+          <school ref="schoolRef" @schoolChange="schoolChange"></school>
+        </div>
+        <div class="right-view">
+          <organization-list ref="organizationRef" :schoolId="schoolId"></organization-list>
+        </div>
+      </div>
+    </div>
+    <div slot="footer" class="dialog-footer">
+      <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+<!--      <el-button @click="cancel">鍙� 娑�</el-button>-->
+    </div>
+  </div>
+</template>
+
+<script>
+/**
+ * 閫夋嫨缁勭粐鏈烘瀯
+ */
+import school from '../../components/school'
+import organizationList from "./organizationList";
+
+export default {
+  name: "organizationForm",
+  components: {
+    school,
+    organizationList
+  },
+  data() {
+    return {
+      buttonLoading: false,
+      activeName: 'second',
+      batchOpen: false,
+      ipOpen: false,
+      schoolId: undefined
+    }
+  },
+  methods: {
+    // 閫夋嫨楂樻牎
+    schoolChange(v) {
+      this.schoolId = v;
+    },
+    submitForm() {
+      this.buttonLoading = true;
+      if (!this.$refs.organizationRef.currentRow) {
+        this.$message.warning("璇烽�夋嫨涓�鏉℃暟鎹�")
+        this.buttonLoading = false;
+        return;
+      }
+      this.$emit('choice', this.$refs.organizationRef.currentRow);
+    }
+  }
+}
+</script>
+
+<style scoped>
+.tree-view {
+  display: flex;
+  flex-direction: row;
+  flex: 1;
+}
+.tree-list {
+  margin-right: 10px;
+}
+.right-view {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  flex: 1;
+}
+.right-view-title-icon {
+  display: flex;
+  flex-direction: row;
+  height: 40px;
+  align-items: center;
+}
+</style>
\ No newline at end of file
diff --git a/src/views/components/organization/index.vue b/src/views/components/organization/index.vue
new file mode 100644
index 0000000..0f60b08
--- /dev/null
+++ b/src/views/components/organization/index.vue
@@ -0,0 +1,76 @@
+<template>
+  <div>
+    <el-input placeholder="璇烽�夋嫨" :value="name" disabled>
+      <el-button slot="append" icon="el-icon-thumb" @click="handleBuilding"></el-button>
+    </el-input>
+    <el-dialog title="鎵�灞炲崟浣�" :visible.sync="open" width="800px" :append-to-body="true" :destroy-on-close="true">
+      <organization-list v-if="open" ref="organizationRef" :schoolId="schoolId"></organization-list>
+      <div slot="footer" class="dialog-footer">
+        <el-button  type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="open = false">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import organizationList from "./organizationList";
+import {getOrganization} from "@/api/oa/organization";
+/**
+ * 楂樻牎缁勭粐鏈烘瀯
+ */
+export default {
+  name: "OrganizationInput",
+  components: {
+    organizationList
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
+  props: {
+    value: {
+      type: [Number],
+      default: undefined
+    },
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      open: false,
+      name: ''
+    }
+  },
+  created() {
+    if (this.value) {
+      getOrganization(this.value).then(response => {
+        this.name = response.data.name;
+      });
+    }
+  },
+  methods: {
+    // 閫夋嫨寤虹瓚鍗曞厓
+    handleBuilding() {
+      this.open = true;
+    },
+    submitForm() {
+      const row = this.$refs.organizationRef.currentRow;
+      if (!row) {
+        this.$message.warning("璇烽�夋嫨涓�鏉℃暟鎹�")
+        this.buttonLoading = false;
+        return;
+      }
+      this.name = row.name;
+      this.open = false;
+      this.$emit("change", row.id);
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/src/views/components/organization/organizationList.vue b/src/views/components/organization/organizationList.vue
new file mode 100644
index 0000000..67ebf49
--- /dev/null
+++ b/src/views/components/organization/organizationList.vue
@@ -0,0 +1,127 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鏈烘瀯鍚嶇О" prop="name">
+        <el-input
+            v-model="queryParams.name"
+            placeholder="璇疯緭鍏ュ崟鍏冨悕绉�"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table
+        ref="singleTable"
+        v-loading="loading"
+        :data="organizationList"
+        row-key="id"
+        default-expand-all
+        :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+        highlight-current-row
+        @current-change="handleCurrentChange"
+    >
+      <el-table-column label="鏈烘瀯鍚嶇О" align="center" prop="name"/>
+      <el-table-column label="鏈烘瀯缂栧彿" prop="code"/>
+      <el-table-column label="鏄剧ず椤哄簭" align="center" prop="orderNum"/>
+    </el-table>
+  </div>
+</template>
+
+<script>
+import { listOrganization } from "@/api/oa/organization";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "OrganizationList",
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  components: {
+    Treeselect
+  },
+  data() {
+    return {
+      // 鎸夐挳loading
+      buttonLoading: false,
+      // 閬僵灞�
+      loading: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 楂樻牎缁勭粐鏈烘瀯琛ㄦ牸鏁版嵁
+      organizationList: [],
+      // 楂樻牎缁勭粐鏈烘瀯鏍戦�夐」
+      organizationOptions: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        name: undefined,
+        schoolId: this.schoolId
+      },
+      currentRow: undefined
+    };
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    /** 鏌ヨ寤虹瓚鍗曞厓鍒楄〃 */
+    getList() {
+      this.loading = true;
+      // 娓呯┖閫変腑鐘舵�佸拰鏁版嵁
+      if (this.currentRow) {
+        this.$refs.singleTable.setCurrentRow();
+        this.currentRow = undefined;
+      }
+      listOrganization(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
+        this.organizationList = this.handleTree(response.data, "id", "parentId");
+        this.loading = false;
+      });
+    },
+    /** 杞崲寤虹瓚鍗曞厓鏁版嵁缁撴瀯 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.id,
+        label: node.name,
+        children: node.children
+      };
+    },
+    /** 鏌ヨ寤虹瓚鍗曞厓涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      listOrganization({schoolId: this.schoolId}).then(response => {
+        this.organizationOptions = [];
+        const data = {id: 0, name: '椤剁骇鑺傜偣', children: []};
+        data.children = this.handleTree(response.data, "id", "parentId");
+        this.organizationOptions.push(data);
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handleCurrentChange(v) {
+      this.currentRow = v;
+    }
+  }
+};
+</script>
diff --git a/src/views/construction/constructionBatch/index.vue b/src/views/construction/constructionBatch/index.vue
index 946b5c3..639584a 100644
--- a/src/views/construction/constructionBatch/index.vue
+++ b/src/views/construction/constructionBatch/index.vue
@@ -142,6 +142,12 @@
 
 export default {
   name: "ConstructionBatch",
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
   data() {
     return {
       // 鎸夐挳loading
@@ -193,6 +199,11 @@
       userList: []
     };
   },
+  watch: {
+    'schoolId': function () {
+      this.getList()
+    }
+  },
   created() {
     this.getList();
   },
@@ -200,7 +211,7 @@
     /** 鏌ヨ鏂藉伐鎵规鍒楄〃 */
     getList() {
       this.loading = true;
-      listConstructionBatch(this.queryParams).then(response => {
+      listConstructionBatch(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
         this.constructionBatchList = response.rows;
         this.total = response.total;
         this.loading = false;
@@ -278,6 +289,7 @@
         this.form.endDate = this.form.date[1];
         if (valid) {
           this.buttonLoading = true;
+          this.form.schoolId = this.schoolId;
           if (this.form.id != null) {
             updateConstructionBatch(this.form).then(response => {
               this.$modal.msgSuccess("淇敼鎴愬姛");
diff --git a/src/views/construction/constructionList/index.vue b/src/views/construction/constructionList/index.vue
index 6020d32..346d4a5 100644
--- a/src/views/construction/constructionList/index.vue
+++ b/src/views/construction/constructionList/index.vue
@@ -7,8 +7,12 @@
       <div class="right-view">
         <el-tabs v-model="activeName" @tab-click="handleClick">
           <el-tab-pane label="鏂藉伐姒傚喌" name="first">鏂藉伐姒傚喌</el-tab-pane>
-          <el-tab-pane label="IPC璁惧" name="second">IPC璁惧</el-tab-pane>
-          <el-tab-pane label="NVR璁惧" name="third">NVR璁惧</el-tab-pane>
+          <el-tab-pane label="IPC璁惧" name="second">
+            <ipc v-if="activeName === 'second'" :schoolId="schoolId"></ipc>
+          </el-tab-pane>
+          <el-tab-pane label="NVR璁惧" name="third">
+            <nvr v-if="activeName === 'third'" :schoolId="schoolId"></nvr>
+          </el-tab-pane>
           <el-tab-pane label="IoT璁惧" name="fourth">IoT璁惧</el-tab-pane>
           <el-tab-pane label="AI璁惧" name="five">AI璁惧</el-tab-pane>
           <el-tab-pane label="浜ゆ崲璁惧" name="six">浜ゆ崲璁惧</el-tab-pane>
@@ -22,11 +26,11 @@
       </div>
     </div>
     <el-drawer title="鏂藉伐鎵规" :visible.sync="batchOpen" size="70%" :append-to-body="true" :destroy-on-close="true">
-      <construction-batch></construction-batch>
+      <construction-batch :schoolId="schoolId"></construction-batch>
     </el-drawer>
 
     <el-drawer title="棰勭暀IP" :visible.sync="ipOpen" size="70%" :append-to-body="true" :destroy-on-close="true">
-      <reserve-ip></reserve-ip>
+      <reserve-ip :schoolId="schoolId"></reserve-ip>
     </el-drawer>
   </div>
 </template>
@@ -35,25 +39,31 @@
 import school from '../../components/school'
 import constructionBatch from '../constructionBatch'
 import reserveIp from '../reserveIp'
+import nvr from '../nvr'
+import ipc from '../ipc'
 
 export default {
   name: "constructionList",
   components: {
     school,
     constructionBatch,
-    reserveIp
+    reserveIp,
+    nvr,
+    ipc
   },
   data() {
     return {
-      activeName: 'second',
+      activeName: 'first',
       batchOpen: false,
-      ipOpen: false
+      ipOpen: false,
+      schoolId: undefined
     }
   },
   methods: {
     // 閫夋嫨楂樻牎
     schoolChange(v) {
-
+      this.schoolId = v;
+      this.activeName = 'first';
     },
     handleClick(tab, event) {
       console.log(tab, event);
@@ -68,15 +78,18 @@
   flex-direction: row;
   flex: 1;
 }
+
 .tree-list {
   margin-right: 10px;
 }
+
 .right-view {
   display: flex;
   flex-direction: row;
   justify-content: space-between;
   flex: 1;
 }
+
 .right-view-title-icon {
   display: flex;
   flex-direction: row;
diff --git a/src/views/construction/ipc/index.vue b/src/views/construction/ipc/index.vue
new file mode 100644
index 0000000..35e4872
--- /dev/null
+++ b/src/views/construction/ipc/index.vue
@@ -0,0 +1,413 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="NVR" prop="nvrId">
+        <nvr v-model="queryParams.nvrId" :schoolId="schoolId"></nvr>
+      </el-form-item>
+      <el-form-item label="瀹夎浣嶇疆" prop="buildingId">
+        <building v-model="queryParams.buildingId" :schoolId="schoolId"></building>
+      </el-form-item>
+      <el-form-item label="鎵�灞炲崟浣�" prop="organizationId">
+        <organization v-model="queryParams.organizationId" :schoolId="schoolId"></organization>
+      </el-form-item>
+      <el-form-item label="鏂藉伐鎵规" prop="constructionBatchId">
+        <construction-batch v-model="queryParams.constructionBatchId" :schoolId="schoolId"></construction-batch>
+      </el-form-item>
+      <el-form-item label="鍨嬪彿" prop="model">
+        <el-input
+          v-model="queryParams.model"
+          placeholder="璇疯緭鍏ュ瀷鍙�"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['oa:ipc:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['oa:ipc:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['oa:ipc:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="ipcList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="搴忓彿" align="center" width="50">
+        <template slot-scope="scope">
+          <span>{{ scope.$index + (queryParams.pageNum - 1) * queryParams.pageSize + 1 }} </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="MAC" align="center" prop="mac" />
+      <el-table-column label="IP" align="center" prop="ip" />
+      <el-table-column label="绔彛" align="center" prop="port" />
+      <el-table-column label="鐧诲綍璐︽埛" align="center" prop="loginAccount" />
+      <el-table-column label="NVR" align="center" prop="nvrId_dictText" />
+      <el-table-column label="閫氶亾" align="center" prop="passageway_dictText" />
+      <el-table-column label="瀹夎浣嶇疆" align="center" prop="buildingId_dictText" />
+      <el-table-column label="鎵�灞炲崟浣�" align="center" prop="organizationId_dictText" />
+      <el-table-column label="鏂藉伐鎵规" align="center" prop="constructionBatchId_dictText" />
+<!--      <el-table-column label="搴忓垪鍙�" align="center" prop="serialNumber" />-->
+<!--      <el-table-column label="鍨嬪彿" align="center" prop="model" />-->
+<!--      <el-table-column label="鐢熶骇鍘傚晢" align="center" prop="manufacturerId_dictText" />-->
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['oa:ipc:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            class="del-btn"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['oa:ipc:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀筰pc璁惧瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" :append-to-body="true" :close-on-click-modal="false" :destroy-on-close="true">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="9">
+            <el-form-item label="MAC" prop="mac">
+              <el-input v-model="form.mac" placeholder="璇疯緭鍏AC" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="9">
+            <el-form-item label="IP" prop="ip">
+              <el-input v-model="form.ip" placeholder="璇疯緭鍏P" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="绔彛" prop="port">
+              <el-input-number v-model="form.port" controls-position="right" :min="0" :max="65535"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="鐧诲綍璐︽埛" prop="loginAccount">
+          <el-input v-model="form.loginAccount" maxlength="64" show-word-limit placeholder="璇疯緭鍏ョ櫥褰曡处鍙�"/>
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="nvr" prop="nvrId">
+              <nvr v-if="open" v-model="form.nvrId"  :schoolId="schoolId"></nvr>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閫氶亾" prop="passageway">
+              <el-select v-model="form.passageway" placeholder="璇烽�夋嫨閫氶亾锛堣矾锛�">
+                <el-option
+                    v-for="dict in dict.type.DICT109"
+                    :key="dict.value"
+                    :label="dict.label"
+                    :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="瀹夎浣嶇疆" prop="buildingId">
+          <building v-if="open" v-model="form.buildingId" :schoolId="schoolId"></building>
+        </el-form-item>
+        <el-form-item label="鎵�灞炲崟浣�" prop="organizationId">
+          <organization v-if="open" v-model="form.organizationId" :schoolId="schoolId"></organization>
+        </el-form-item>
+        <el-form-item label="鏂藉伐鎵规" prop="constructionBatchId">
+          <constructionBatch v-if="open" v-model="form.constructionBatchId" :schoolId="schoolId"></constructionBatch>
+        </el-form-item>
+        <el-form-item label="搴忓垪鍙�" prop="serialNumber">
+          <el-input v-model="form.serialNumber" maxlength="64" show-word-limit placeholder="璇疯緭鍏ュ簭鍒楀彿"/>
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鍨嬪彿" prop="model">
+              <el-input v-model="form.model" maxlength="64" show-word-limit placeholder="璇疯緭鍏ュ瀷鍙�"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢熶骇鍘傚晢" prop="manufacturerId">
+              <manufacturer v-if="open" v-model="form.manufacturerId"></manufacturer>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listIpc, getIpc, delIpc, addIpc, updateIpc } from "@/api/oa/ipc";
+import building from "../../components/building";
+import organization from "../../components/organization";
+import constructionBatch from "../../components/constructionBatch";
+import manufacturer from "../../components/manufacturer";
+import nvr from '../../components/nvr'
+
+export default {
+  name: "Ipc",
+  dicts: ['DICT109'],
+  components: {
+    building,
+    organization,
+    constructionBatch,
+    manufacturer,
+    nvr
+  },
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      // 鎸夐挳loading
+      buttonLoading: false,
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // ipc璁惧琛ㄦ牸鏁版嵁
+      ipcList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        nvrId: undefined,
+        buildingId: undefined,
+        organizationId: undefined,
+        constructionBatchId: undefined,
+        model: undefined,
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        id: [
+          { required: true, message: "涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        mac: [
+          { required: true, message: "mac涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            pattern: /^[A-F0-9]{2}(-[A-F0-9]{2}){5}$|^[A-F0-9]{2}(:[A-F0-9]{2}){5}$|^[A-F0-9]{12}$|^[A-F0-9]{4}(\.[A-F0-9]{4}){2}$/,
+            message: "璇疯緭鍏ユ纭殑MAC",
+            trigger: "blur"
+          }
+        ],
+        ip: [
+          { required: true, message: "IP涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            pattern: /^(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])$/,
+            message: "璇疯緭鍏ユ纭殑ip鍦板潃",
+            trigger: "blur"
+          }
+        ],
+        port: [
+          { required: true, message: "绔彛涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        loginAccount: [
+          { required: true, message: "鐧诲綍璐︽埛涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        buildingId: [
+          { required: true, message: "瀹夎浣嶇疆涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        organizationId: [
+          { required: true, message: "鎵�灞炲崟浣嶄笉鑳戒负绌�", trigger: "blur" }
+        ],
+        constructionBatchId: [
+          { required: true, message: "鏂藉伐鎵规涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  watch: {
+    'schoolId': function () {
+      this.getList()
+    }
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨipc璁惧鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listIpc(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
+        this.ipcList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        id: undefined,
+        mac: undefined,
+        ip: undefined,
+        port: undefined,
+        loginAccount: undefined,
+        nvrId: undefined,
+        passageway: undefined,
+        buildingId: undefined,
+        organizationId: undefined,
+        constructionBatchId: undefined,
+        serialNumber: undefined,
+        model: undefined,
+        manufacturerId: undefined,
+        createTime: undefined,
+        createBy: undefined,
+        updateBy: undefined,
+        updateTime: undefined,
+        delFlag: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞ipc璁惧";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.loading = true;
+      this.reset();
+      const id = row.id || this.ids
+      getIpc(id).then(response => {
+        this.loading = false;
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼ipc璁惧";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.buttonLoading = true;
+          this.form.schoolId = this.schoolId;
+          if (this.form.id != null) {
+            updateIpc(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          } else {
+            addIpc(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎ipc璁惧缂栧彿涓�"' + ids + '"鐨勬暟鎹」锛�').then(() => {
+        this.loading = true;
+        return delIpc(ids);
+      }).then(() => {
+        this.loading = false;
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).finally(() => {
+        this.loading = false;
+      });
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('oa/ipc/export', {
+        ...this.queryParams
+      }, `ipc_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/src/views/construction/nvr/index.vue b/src/views/construction/nvr/index.vue
new file mode 100644
index 0000000..a148e00
--- /dev/null
+++ b/src/views/construction/nvr/index.vue
@@ -0,0 +1,527 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="88px">
+      <el-form-item label="閫氶亾锛堣矾锛�" prop="passageway">
+        <el-select v-model="queryParams.passageway" placeholder="璇烽�夋嫨閫氶亾锛堣矾锛�">
+          <el-option
+              v-for="dict in dict.type.DICT109"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="瀹夎浣嶇疆" prop="buildingId">
+        <building v-model="queryParams.buildingId" :schoolId="schoolId"></building>
+      </el-form-item>
+      <el-form-item label="鎵�灞炲崟浣�" prop="organizationId">
+        <organization v-model="queryParams.organizationId" :schoolId="schoolId"></organization>
+      </el-form-item>
+      <el-form-item label="鏂藉伐鎵规" prop="constructionBatchId">
+        <construction-batch v-model="queryParams.constructionBatchId" :schoolId="schoolId"></construction-batch>
+      </el-form-item>
+      <el-form-item label="鍨嬪彿" prop="model">
+        <el-input
+            v-model="queryParams.model"
+            placeholder="璇疯緭鍏ュ瀷鍙�"
+            clearable
+            size="small"
+            @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+            type="primary"
+            plain
+            icon="el-icon-plus"
+            size="mini"
+            @click="handleAdd"
+            v-hasPermi="['oa:nvr:add']"
+        >鏂板
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            type="success"
+            plain
+            icon="el-icon-edit"
+            size="mini"
+            :disabled="single"
+            @click="handleUpdate"
+            v-hasPermi="['oa:nvr:edit']"
+        >淇敼
+        </el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+            type="danger"
+            plain
+            icon="el-icon-delete"
+            size="mini"
+            :disabled="multiple"
+            @click="handleDelete"
+            v-hasPermi="['oa:nvr:remove']"
+        >鍒犻櫎
+        </el-button>
+      </el-col>
+    </el-row>
+
+    <el-table v-loading="loading" :data="nvrList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center"/>
+      <el-table-column label="搴忓彿" align="center" width="50">
+        <template slot-scope="scope">
+          <span>{{ scope.$index + (queryParams.pageNum - 1) * queryParams.pageSize + 1 }} </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="閮ㄧ讲鍚嶇О" align="center" prop="deploymentName"/>
+      <el-table-column label="閫氶亾锛堣矾锛�" align="center" prop="passageway"/>
+      <el-table-column label="LAN1" align="center" prop="lanOne"/>
+      <el-table-column label="IP" align="center" prop="ipOne"/>
+      <el-table-column label="LAN2" align="center" prop="lanTwo"/>
+      <el-table-column label="IP" align="center" prop="ipTwo"/>
+      <el-table-column label="鐧诲綍璐︽埛" align="center" prop="loginAccount"/>
+      <el-table-column label="纭洏" align="center" prop="hardDisk"/>
+      <el-table-column label="瀹夎浣嶇疆" align="center" prop="buildingId"/>
+      <el-table-column label="鎵�灞炲崟浣�" align="center" prop="organizationId"/>
+      <!--      <el-table-column label="鏂藉伐鎵规" align="center" prop="constructionBatchId" />-->
+      <!--      <el-table-column label="搴忓垪鍙�" align="center" prop="serialNumber" />-->
+      <!--      <el-table-column label="鍨嬪彿" align="center" prop="model" />-->
+      <!--      <el-table-column label="鐢熶骇鍘傚晢" align="center" prop="manufacturerId" />-->
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-view"
+              @click="handleInfo(scope.row)"
+          >鏌ョ湅
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-edit"
+              @click="handleUpdate(scope.row)"
+              v-hasPermi="['oa:nvr:edit']"
+          >淇敼
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              icon="el-icon-folder"
+              @click="handleUpload(scope.row)"
+          >闄勪欢
+          </el-button>
+          <el-button
+              size="mini"
+              type="text"
+              class="del-btn"
+              icon="el-icon-delete"
+              @click="handleDelete(scope.row)"
+              v-hasPermi="['oa:nvr:remove']"
+          >鍒犻櫎
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀筃VR璁惧瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" :append-to-body="true" :close-on-click-modal="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px" :disabled="disabled">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="閮ㄧ讲鍚嶇О" prop="deploymentName">
+              <el-input v-model="form.deploymentName" maxlength="64" show-word-limit placeholder="璇疯緭鍏ラ儴缃插悕绉�"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閫氶亾" prop="passageway">
+              <el-select v-model="form.passageway" placeholder="璇烽�夋嫨閫氶亾锛堣矾锛�">
+                <el-option
+                    v-for="dict in dict.type.DICT109"
+                    :key="dict.value"
+                    :label="dict.label"
+                    :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="LAN1" prop="lanOne">
+              <el-input v-model="form.lanOne" placeholder="璇疯緭鍏AN1"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="IP" prop="ipOne">
+              <el-input v-model="form.ipOne" placeholder="璇疯緭鍏P"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="LAN2" prop="lanTwo">
+              <el-input v-model="form.lanTwo" placeholder="璇疯緭鍏AN2"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="IP" prop="ipTwo">
+              <el-input v-model="form.ipTwo" placeholder="璇疯緭鍏P"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鐧诲綍璐﹀彿" prop="loginAccount">
+              <el-input v-model="form.loginAccount" maxlength="64" show-word-limit placeholder="璇疯緭鍏ョ櫥褰曡处鍙�"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="纭洏" prop="hardDisk">
+              <el-input v-model="form.hardDisk" maxlength="64" show-word-limit placeholder="璇疯緭鍏ョ‖鐩�"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="瀹夎浣嶇疆" prop="buildingId">
+          <building v-if="open" v-model="form.buildingId" :schoolId="schoolId"></building>
+        </el-form-item>
+        <el-form-item label="鎵�灞炲崟浣�" prop="organizationId">
+          <organization v-if="open" v-model="form.organizationId" :schoolId="schoolId"></organization>
+        </el-form-item>
+        <el-form-item label="鏂藉伐鎵规" prop="constructionBatchId">
+          <constructionBatch v-if="open" v-model="form.constructionBatchId" :schoolId="schoolId"></constructionBatch>
+        </el-form-item>
+        <el-form-item label="搴忓垪鍙�" prop="serialNumber">
+          <el-input v-model="form.serialNumber" maxlength="64" show-word-limit placeholder="璇疯緭鍏ュ簭鍒楀彿"/>
+        </el-form-item>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鍨嬪彿" prop="model">
+              <el-input v-model="form.model" maxlength="64" show-word-limit placeholder="璇疯緭鍏ュ瀷鍙�"/>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢熶骇鍘傚晢" prop="manufacturerId">
+              <manufacturer v-if="open" v-model="form.manufacturerId"></manufacturer>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button :loading="buttonLoading" type="primary" @click="submitForm" :disabled="disabled">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 闄勪欢 -->
+    <Dialog title="闄勪欢" :visible.sync="fileOpen" width="500px" :append-to-body="true" :destroy-on-close="true">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="闄勪欢" prop="filePath">
+          <fileUpload v-model="form.filePath" :limit="1"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </Dialog>
+  </div>
+</template>
+
+<script>
+import {listNvr, getNvr, delNvr, addNvr, updateNvr} from "@/api/oa/nvr";
+import building from '../../components/building'
+import organization from '../../components/organization'
+import constructionBatch from '../../components/constructionBatch'
+import manufacturer from '../../components/manufacturer'
+
+export default {
+  name: "Nvr",
+  dicts: ['DICT109'],
+  components: {
+    building,
+    organization,
+    constructionBatch,
+    manufacturer
+  },
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
+  },
+  data() {
+    return {
+      // 鎸夐挳loading
+      buttonLoading: false,
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // NVR璁惧琛ㄦ牸鏁版嵁
+      nvrList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        passageway: undefined,
+        buildingId: undefined,
+        organizationId: undefined,
+        constructionBatchId: undefined,
+        model: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        id: [
+          {required: true, message: "涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        deploymentName: [
+          {required: true, message: "閮ㄧ讲鍚嶇О涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        passageway: [
+          {required: true, message: "閫氶亾涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        lanOne: [
+          {required: true, message: "LAN1涓嶈兘涓虹┖", trigger: "blur"},
+          {
+            pattern: /^[A-F0-9]{2}(-[A-F0-9]{2}){5}$|^[A-F0-9]{2}(:[A-F0-9]{2}){5}$|^[A-F0-9]{12}$|^[A-F0-9]{4}(\.[A-F0-9]{4}){2}$/,
+            message: "璇疯緭鍏ユ纭殑LAN",
+            trigger: "blur"
+          }
+        ],
+        ipOne: [
+          {required: true, message: "ip1涓嶈兘涓虹┖", trigger: "blur"},
+          {
+            pattern: /^(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])$/,
+            message: "璇疯緭鍏ユ纭殑ip鍦板潃",
+            trigger: "blur"
+          }
+        ],
+        lanTwo: [
+          {required: true, message: "LAN2涓嶈兘涓虹┖", trigger: "blur"},
+          {
+            pattern: /^[A-F0-9]{2}(-[A-F0-9]{2}){5}$|^[A-F0-9]{2}(:[A-F0-9]{2}){5}$|^[A-F0-9]{12}$|^[A-F0-9]{4}(\.[A-F0-9]{4}){2}$/,
+            message: "璇疯緭鍏ユ纭殑LAN",
+            trigger: "blur"
+          }
+        ],
+        ipTwo: [
+          {required: true, message: "ip2涓嶈兘涓虹┖", trigger: "blur"},
+          {
+            pattern: /^(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])\.(\d|[1-9]\d|1\d{2}|2[0-5][0-5])$/,
+            message: "璇疯緭鍏ユ纭殑ip鍦板潃",
+            trigger: "blur"
+          }
+        ],
+        loginAccount: [
+          {required: true, message: "鐧诲綍璐﹀彿涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        hardDisk: [
+          {required: true, message: "纭洏涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        buildingId: [
+          {required: true, message: "寤虹瓚鍗曞厓涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        organizationId: [
+          {required: true, message: "鎵�灞炴満鏋勪笉鑳戒负绌�", trigger: "blur"}
+        ],
+        constructionBatchId: [
+          {required: true, message: "鏂藉伐鎵规涓嶈兘涓虹┖", trigger: "blur"}
+        ],
+        filePath: [
+          {required: true, message: "闄勪欢涓嶈兘涓虹┖", trigger: "blur"}
+        ]
+      },
+      disabled: false,
+      fileOpen: false
+    };
+  },
+  watch: {
+    'schoolId': function () {
+      this.getList()
+    }
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨNVR璁惧鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listNvr(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
+        this.nvrList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.fileOpen = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        id: undefined,
+        deploymentName: undefined,
+        passageway: undefined,
+        lanOne: undefined,
+        ipOne: undefined,
+        lanTwo: undefined,
+        ipTwo: undefined,
+        loginAccount: undefined,
+        hardDisk: undefined,
+        buildingId: undefined,
+        organizationId: undefined,
+        constructionBatchId: undefined,
+        serialNumber: undefined,
+        model: undefined,
+        manufacturerId: undefined,
+        createTime: undefined,
+        createBy: undefined,
+        updateBy: undefined,
+        updateTime: undefined,
+        delFlag: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.disabled = false;
+      this.open = true;
+      this.title = "娣诲姞NVR璁惧";
+    },
+    handleInfo(row) {
+      this.loading = true;
+      this.disabled = true;
+      this.reset();
+      getNvr(row.id).then(response => {
+        this.loading = false;
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼NVR璁惧";
+      });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.loading = true;
+      this.disabled = false;
+      this.reset();
+      const id = row.id || this.ids
+      getNvr(id).then(response => {
+        this.loading = false;
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼NVR璁惧";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.buttonLoading = true;
+          this.form.schoolId = this.schoolId;
+          if (this.form.id != null) {
+            updateNvr(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.fileOpen = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          } else {
+            addNvr(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.fileOpen = false;
+              this.getList();
+            }).finally(() => {
+              this.buttonLoading = false;
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎NVR璁惧缂栧彿涓�"' + ids + '"鐨勬暟鎹」锛�').then(() => {
+        this.loading = true;
+        return delNvr(ids);
+      }).then(() => {
+        this.loading = false;
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).finally(() => {
+        this.loading = false;
+      });
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('oa/nvr/export', {
+        ...this.queryParams
+      }, `nvr_${new Date().getTime()}.xlsx`)
+    },
+    // 闄勪欢
+    handleUpload(row) {
+      this.loading = true;
+      this.disabled = false;
+      this.reset();
+      const id = row.id || this.ids
+      getNvr(id).then(response => {
+        this.loading = false;
+        this.form = response.data;
+        this.fileOpen = true;
+      });
+    }
+  }
+};
+</script>
diff --git a/src/views/construction/reserveIp/index.vue b/src/views/construction/reserveIp/index.vue
index 673999a..7e59d54 100644
--- a/src/views/construction/reserveIp/index.vue
+++ b/src/views/construction/reserveIp/index.vue
@@ -106,7 +106,7 @@
           <el-input v-model="form.mac" placeholder="璇疯緭鍏AC鍦板潃" />
         </el-form-item>
         <el-form-item label="閫傜敤鍦扮偣" prop="buildingId">
-          <building v-model="form.buildingId"></building>
+          <building v-if="open" v-model="form.buildingId" :schoolId="schoolId"></building>
         </el-form-item>
         <el-form-item label="鐢宠鏃ユ湡" prop="applicationDate">
           <el-date-picker clearable size="small"
@@ -116,7 +116,7 @@
           </el-date-picker>
         </el-form-item>
         <el-form-item label="澶囨敞" prop="remarks">
-          <el-input v-model="form.remarks" type="textarea" :rows="8" placeholder="璇疯緭鍏ュ唴瀹�" />
+          <el-input v-model="form.remarks" type="textarea" :rows="8" maxlength="512" show-word-limit placeholder="璇疯緭鍏ュ唴瀹�" />
         </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -137,6 +137,12 @@
   name: "ReserveIp",
   components: {
     building
+  },
+  props: {
+    schoolId: {
+      type: Number,
+      default: undefined
+    }
   },
   data() {
     return {
@@ -186,6 +192,11 @@
       buildOpen: false
     };
   },
+  watch: {
+    'schoolId': function () {
+      this.getList()
+    }
+  },
   created() {
     this.getList();
   },
@@ -193,7 +204,7 @@
     /** 鏌ヨ棰勭暀IP鍒楄〃 */
     getList() {
       this.loading = true;
-      listReserveIp(this.queryParams).then(response => {
+      listReserveIp(Object.assign({}, this.queryParams, {schoolId: this.schoolId})).then(response => {
         this.reserveIpList = response.rows;
         this.total = response.total;
         this.loading = false;
@@ -260,6 +271,7 @@
       this.$refs["form"].validate(valid => {
         if (valid) {
           this.buttonLoading = true;
+          this.form.schoolId = this.schoolId;
           if (this.form.id != null) {
             updateReserveIp(this.form).then(response => {
               this.$modal.msgSuccess("淇敼鎴愬姛");

--
Gitblit v1.9.1