an> 39
          v-if="form.monitorSceneId != null "
40
          ghost
41
          color="info"
42
          icon="delete-outline"
43
          @click="handleDelete"
44
        >删除场景</t-button
45
        >
44 46
          <div v-show="showConfirm" class="popover">
45 47
            <t-icon
46 48
              color="warning"
@ -54,14 +56,14 @@
54 56
                size="sm"
55 57
                color="primary"
56 58
                @click="handleConfirmDelete"
57
                >确定</t-button
59
              >确定</t-button
58 60
              >
59 61
              <t-button
60 62
                size="sm"
61 63
                color="secondary"
62 64
                style="margin-right: 8px"
63 65
                @click="handleCancelDelete"
64
                >取消</t-button
66
              >取消</t-button
65 67
              >
66 68
            </div>
67 69
          </div>
@ -72,108 +74,71 @@
72 74
</template>
73 75
74 76
<script>
77
import sysapi from '@/api/system'
75 78
export default {
76
  name: "ShiftSceneDialog",
79
  name: 'ShiftSceneDialog',
77 80
  props: {
78 81
    data: {
79 82
      type: Object,
80 83
      default() {
81
        return {};
82
      },
83
    },
84
        return {}
85
      }
86
    }
84 87
  },
85 88
  data() {
86 89
    return {
87 90
      visibled: false,
88 91
      form: {},
92
      SceneLayoutList: [],
89 93
      searchValue: null,
90 94
      loadingSubmit: false,
91 95
      showConfirm: false,
92
      loadingDelete: false,
93
    };
96
      loadingDelete: false
97
    }
94 98
  },
95 99
  computed: {
96 100
    title() {
97
      return this.data.id == null ? "新增场景" : "编辑场景";
98
    },
101
      return this.data.monitorSceneId == null ? '新增场景' : '编辑场景'
102
    }
99 103
  },
100 104
  watch: {
101 105
    data(val) {
102
      //侦听data属性
103
      this.form = this.data;
104
      this.visibled = true;
105
    },
106
      // 侦听data属性
107
      this.form = this.data
108
      this.visibled = true
109
    }
110
  },
111
  mounted() {
112
    this.getLayoutList()
106 113
  },
107 114
  methods: {
108
    getCameras() {
109
      sysapi.getCameras().then((resp) => {
110
        alert(11);
111
        this.cameraList = resp.data || [];
112
      });
113
    },
114
    groupClick(item) {
115
      //选中更换摄像头
116
      if (this.form.title == null) {
117
        this.form.title = item.title;
118
      }
119
      this.form.cameraId = item.cameraId;
120
      this.form.imgsrc = item.imgsrc;
115
    getLayoutList() {
116
      sysapi.getqueryMonitorSceneLayoutList().then((resp) => {
117
        this.SceneLayoutList = resp.data.data || []
118
      })
121 119
    },
122 120
    handleDelete() {
123
      this.showConfirm = true;
121
      this.showConfirm = true
124 122
    },
123
    // 保存
125 124
    handleSubmit() {
126
      this.loadingSubmit = true;
127
      sysapi
128
        .submitSchedule(this.form)
129
        .then(
130
          (resp) => {
131
            if (resp.data.areaMonitorId == null) {
132
              this.form.areaMonitorId = resp.data.areaMonitorId;
133
            }
134
            this.$emit("submit", this.form);
135
            this.visibled = false;
136
            this.$Message.success("提交成功");
137
          },
138
          (err) => {
139
            console.log(err);
140
            this.$Message.danger("提交失败");
141
          }
142
        )
143
        .finally(() => {
144
          this.loadingSubmit = false;
145
        });
146
    },
147
    onChange(page) {
148
      this.page = page;
149
      this.getAreaMonitors();
125
      this.$emit('submit', this.form)
150 126
    },
151 127
    handleCancelDelete() {
152
      this.showConfirm = false;
128
      this.showConfirm = false
153 129
    },
130
    // 删除场景
154 131
    handleConfirmDelete() {
155
      //this.loadingDelete = true;
156
157
      this.$emit("deleted", this.data);
158
      //   sysapi
159
      //     .deleteSchedule(this.data.scheduleId)
160
      //     .then(
161
      //       (resp) => {
162
      //         console.log(resp);
163
      //         this.$emit("deleted", this.data);
164
      //       },
165
      //       (err) => {
166
      //         console.log(err);
167
      //         this.$Message.danger("删除失败,请稍后再试!", 3);
168
      //       }
169
      //     )
170
      //     .finally(() => {
171
      //       this.loadingDelete = false;
172
      //       this.showConfirm = false;
173
      //     });
132
      this.showConfirm = false
133
      this.visibled = false
134
      this.$emit('deleted', this.form)
174 135
    },
175
  },
176
};
136
    handlecancel() {
137
    // 有问题
138
    // this.$forceUpdate()
139
    }
140
  }
141
}
177 142
</script>
178 143
179 144
<style lang="scss">

+ 378 - 195
security-protection-platform/src/modules/system/monitor/VideoMonitor/index.vue

@ -1,237 +1,420 @@
1 1
<template>
2
  <div class="p-24" ref="box">
2
  <div ref="box" class="p-24">
3 3
    <div>
4 4
      <t-row>
5 5
        <t-col>
6 6
          <div style="float: left">
7 7
            <span>风场: </span>
8
            <t-select v-model="currentWindPlaceValue" style="width: 200px; height: 32px">
9
              <t-option value="1">风场1</t-option>
10
              <t-option value="2">风场2</t-option>
8
            <t-select
9
              v-model="currentWindPlaceValue"
10
              style="width: 200px; height: 32px"
11
              @change="WindPlaceChenged"
12
            >
13
              <t-option
14
                v-for="item in departmentList"
15
                :key="item.code"
16
                :value="item.code"
17
              >{{ item.name }}</t-option
18
              >
11 19
            </t-select>
12 20
          </div>
13 21
        </t-col>
14
        <t-col>
15
          <div style="float: right">
16
            <t-button-group>
17
              <t-button @click="btnOnClick('areaMonitor')" :class="['base', btnIsClicked ? 'active' : '']">
18
                <span>大门</span>
19
                <div @click="handleSceneEdit('123')" v-if="dialogSceneData.id == '1'"
20
                  style="float: right; width: 14px; height: 14px">
21
                  <t-icon icon="edit" shape="circle" class="ico"></t-icon>
22
                </div>
23
              </t-button>
24
25
              <t-button @click="btnOnClick('areaMonitor')" :class="['base', btnIsClicked ? 'active' : '']">
26
                <span>值班室</span>
27
                <div @click="handleSceneEdit('456')" style="float: right; width: 14px; height: 14px"
28
                  v-if="dialogSceneData.id == '456'">
29
                  <t-icon icon="edit" shape="circle" class="ico"></t-icon>
22
        <t-col span="8">
23
          <div>
24
            <t-button-group style="float: right">
25
              <t-button
26
                v-for="item in monitorSceneList"
27
                :key="item.monitorSceneId"
28
                :class="[
29
                  'base',
30
                  item.monitorSceneId == currenScene.monitorSceneId
31
                    ? 'active'
32
                    : '',
33
                ]"
34
                style="
35
                  display: inline-block;
36
                  -moz-appearance: button;
37
                  -webkit-appearance: button;
38
                  appearance: button;
39
                "
40
                @click="handleSceneOnClick(item)"
41
              >
42
                <div>
43
                  {{ item.monitorSceneName }}
44
                  <div class="div_edit" @click.stop="handleSceneEdit(item)">
45
                    <t-icon
46
                      v-if="item.monitorSceneId == currenScene.monitorSceneId"
47
                      icon="edit"
48
                      shape="circle"
49
                      class="ico"
50
                    ></t-icon>
51
                  </div>
30 52
                </div>
31 53
              </t-button>
54
              <t-button
55
                style="48px"
56
                icon="plus-outline"
57
                @click="btnAddClick()"
58
              ></t-button>
32 59
            </t-button-group>
33
            <t-button @click="btnAddClick()" style="width: 48px">+</t-button>
34 60
          </div>
35 61
        </t-col>
36 62
      </t-row>
37 63
      <t-row>
38
        <t-col style="margin-top:10px;">
39
          <t-button color="info" icon="plus-circle" @click="handleCreate">新增监控</t-button>
64
        <t-col style="margin-top: 10px">
65
          <t-button color="info" icon="plus-circle" @click="handleCreate"
66
          >新增监控</t-button
67
          >
40 68
        </t-col>
41 69
      </t-row>
42 70
      <!--header-->
43 71
    </div>
44 72
    <div style="min-height: 280px; height: auto !important">
45
      <draggable v-model="areaMonitorList" @update="datadragEnd">
46
        <transition-group>
47
          <div v-for="(viewArray,index) in viewDataList" :key="index">
48
            <div style="text-align: right;">
49
              <span style="width:300px">第{{index+1}}/{{viewDataList.length}}页</span>
50
            </div>
51
            <camera-card v-for="item in viewArray" :key="item.areaMonitorId" :data="item" :itemWidth="itemWidth"
52
              @edit="handleEdit" @deleted="handleDeleted" />
53
          </div>
54
        </transition-group>
55
      </draggable>
56
      <shift-scene-dialog :data="dialogSceneData" @submit="handleCameraSubmit" />
57
      <shift-camera-dialog :data="dialogData" @submit="handleCameraSubmit" />
73
      <draggable-grid
74
        v-model="areaMonitorList"
75
        :show-page="true"
76
        :grid="currenScene.monitorViewLayout!=null?currenScene.monitorViewLayout.split('X'):[4,1]"
77
        key-word="monitorSceneTerminalRelId"
78
        @update="datadragEnd"
79
      >
80
        <template v-slot="{ scope }">
81
          <view-card
82
            :data="scope.data"
83
            :width="scope.width + 'px'"
84
            :height="scope.height + 'px'"
85
            :monitor-scene-type-name="currenScene.monitorSceneTypeName"
86
            @nameChange="handleCameraSubmit"
87
            @edit="handleEdit"
88
            @deleted="handleDeleted"
89
          />
90
        </template>
91
      </draggable-grid>
92
      <shift-scene-dialog
93
        :data="dialogSceneData"
94
        @submit="handlesceneSubmit"
95
        @deleted="handlesceneDelete"
96
      />
97
      <shift-camera-dialog :data="dialogData" :monitor-scene-type-name="currenScene.monitorSceneTypeName"
98
                           :monitor-scene-type-id="currenScene.monitorSceneType"
99
                           @submit="handleCameraSubmit"/>
58 100
    </div>
59 101
  </div>
60 102
</template>
61 103
62
63 104
<script>
64
  import CameraCard from "../HomePageSettings/Card";
65
  import draggable from "vuedraggable";
66
  import ShiftSceneDialog from "./ShiftSceneDialog";
67
  import ShiftCameraDialog from "../HomePageSettings/ShiftCameraDialog";
68
  export default {
69
    components: {
70
      CameraCard,
71
      draggable,
72
      ShiftSceneDialog,
73
      ShiftCameraDialog
105
import CameraCard from '../HomePageSettings/Card'
106
import draggable from 'vuedraggable'
107
import ShiftSceneDialog from './ShiftSceneDialog'
108
import ShiftCameraDialog from '../HomePageSettings/ShiftCameraDialog'
109
import DraggableGrid from '../components/DraggableGrid'
110
import ViewCard from '../components/ViewCard'
111
import CreateCard from '../components/CreateCard'
112
import sysapi from '@/api/system'
113
114
export default {
115
  components: {
116
    CameraCard,
117
    draggable,
118
    ShiftSceneDialog,
119
    ShiftCameraDialog,
120
    DraggableGrid,
121
    ViewCard,
122
    CreateCard
123
  },
124
  create() {
125
    document.body.ondrop = function (event) {
126
      event.preventDefault()
127
      event.stopPropagation()
128
    }
129
  },
130
  data() {
131
    return {
132
      // 选中的组织机构ID
133
      currentWindPlaceValue: '2',
134
      currenScene: {},
135
      btnIsClicked: true,
136
      //
137
      dialogSceneData: {},
138
      dialogData: {},
139
      currentType: 4,
140
      itemWidth: null,
141
      departmentList: [],
142
      monitorSceneList: [
143
        {
144
          sceneName: '大门',
145
          id: '1',
146
          parentId: '1',
147
          displayType: '4'
148
        },
149
        {
150
          sceneName: '值班室',
151
          id: '2',
152
          parentId: '1',
153
          displayType: '3'
154
        }
155
      ],
156
      areaMonitorList: [
157
        {
158
          title: '摄像头001',
159
          cameraId: '001',
160
          areaMonitorId: '001',
161
          sceneId: '1',
162
          sortOrder: 0,
163
          imgsrc:
164
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
165
        }
166
      ]
167
    }
168
  },
169
  computed: {
170
    gridWidth: function () {
171
      return this.itemWidth - 20 + 'px'
74 172
    },
75
    data() {
76
      return {
77
        currentWindPlaceValue: "2",
78
        currentitem: {},
79
        btnIsClicked: true,
80
        dialogSceneData: {},
81
        dialogData: {},
82
        currentType: 3,
83
        itemWidth: null,
84
        sceneList: [{
85
            sceneName: "大门",
86
            id: "1",
87
            parentId: "1",
88
            displayType: "4",
89
          },
90
          {
91
            sceneName: "值班室",
92
            id: "2",
93
            parentId: "1",
94
            displayType: "3",
95
          },
96
        ],
97
        areaMonitorList: [{
98
            title: "摄像头001",
99
            cameraId: "001",
100
            areaMonitorId: "001",
101
            sceneId: "1",
102
            sortOrder: 0,
103
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
104
          },
105
          {
106
            title: "摄像头002",
107
            cameraId: "002",
108
            areaMonitorId: "002",
109
            sortOrder: 1,
110
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
111
          },
112
          {
113
            title: "摄像头003",
114
            cameraId: "003",
115
            areaMonitorId: "003",
116
            sortOrder: 2,
117
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
118
          },
119
          {
120
            title: "摄像头004",
121
            cameraId: "004",
122
            areaMonitorId: "004",
123
            sortOrder: 3,
124
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
125
          },
126
          {
127
            title: "摄像头005",
128
            cameraId: "005",
129
            areaMonitorId: "005",
130
            sortOrder: 4,
131
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
132
          },
133
          {
134
            title: "摄像头006",
135
            cameraId: "006",
136
            areaMonitorId: "006",
137
            sortOrder: 5,
138
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
139
          },
140
          {
141
            title: "摄像头007",
142
            cameraId: "007",
143
            areaMonitorId: "007",
144
            sortOrder: 6,
145
            imgsrc: "https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26",
146
          },
147
        ],
148
      };
173
    gridHeight: function () {
174
      return this.itemWidth * 0.9 - 20 - 6 - 32 + 'px'
149 175
    },
150
    computed: {
151
      gridWidth: function () {
152
        return this.itemWidth - 20 + "px";
153
      },
154
      gridHeight: function () {
155
        return this.itemWidth * 0.9 - 20 - 6 - 32 + "px";
156
      },
157
      viewDataList: function () {
158
        let tempDataList = [];
159
        for (
160
          let i = 0; i < Math.ceil(this.areaMonitorList.length / this.currentType); i++
161
        ) {//this.currentType需要*this.currentType,测试减少一个组的数据
162
          
163
          tempDataList[i] = this.areaMonitorList.slice(
164
            i * this.currentType,
165
            (i + 1) * this.currentType
166
          );
176
    viewDataList: function () {
177
      let tempDataList = []
178
      for (
179
        let i = 0;
180
        i < Math.ceil(this.areaMonitorList.length / this.currentType);
181
        i++
182
      ) {
183
        // this.currentType需要*this.currentType,测试减少一个组的数据
184
        tempDataList[i] = this.areaMonitorList.slice(
185
          i * this.currentType,
186
          (i + 1) * this.currentType
187
        )
188
      }
189
      return tempDataList
190
    }
191
  },
192
  mounted() {
193
    let dom = this.$refs.box
194
    this.itemWidth = dom.clientWidth / this.currentType - 25
195
    this.getDepartments()
196
  },
197
  methods: {
198
    //  获取组织
199
    getDepartments() {
200
      sysapi.getDepartments().then((resp) => {
201
        this.departmentList = resp.data.data || []
202
        if (this.departmentList.length > 0) {
203
          this.currentWindPlaceValue = this.departmentList[0].code
204
          this.getMonitorScene(this.currentWindPlaceValue)
167 205
        }
168
        return tempDataList;
169
      },
206
      })
207
    },
208
    // 获取监控场景
209
    getMonitorScene(orgId) {
210
      sysapi.getMonitorScene(orgId).then((resp) => {
211
        this.monitorSceneList = resp.data.data || []
212
        if (this.monitorSceneList.length > 0) {
213
          this.currenScene = this.monitorSceneList[0]
214
          this.geTerminalRel(this.currenScene)
215
        }
216
      })
217
    },
218
    // 场景ID查询该场景下所有监控终端列表
219
    geTerminalRel(monitorScene) {
220
      sysapi.getTerminalRel(monitorScene.monitorSceneId).then((resp) => {
221
        this.areaMonitorList = resp.data.data || []
222
      })
170 223
    },
171
    mounted() {
172
      let dom = this.$refs.box;
173
      this.itemWidth = dom.clientWidth / this.currentType - 25;
224
    WindPlaceChenged(cloneValue) {
225
      this.getMonitorScene(cloneValue)
174 226
    },
175
    methods: {
176
      handleSceneEdit(item) {
177
        alert(item);
178
        event.stopPropagation();
179
      },
180
      btnOnClick(item) {
181
        this.dialogSceneData = item;
182
      },
183
      btnAddClick() {
184
        this.dialogSceneData = {
185
          sceneName: null,
186
          id: null,
187
          parentId: this.currentWindPlaceValue,
188
          displayType: null,
189
        };
190
      },
191
      handleEdit(item) {
192
        this.dialogData = Object.assign({}, item);
193
        console.log(item.title);
194
      },
195
      handleCreate() {
196
        this.dialogData = {
197
          title: null,
198
          cameraId: null,
199
          areaMonitorId: null,
200
          sortOrder: 5,
201
          imgsrc: null,
202
        };
203
      },
204
      handleDeleted(index) {
205
        this.areaMonitorList.splice(index, 1);
206
      },
207
      datadragEnd(evt) {
208
        console.log("拖动前的索引 :" + this.areaMonitorList[evt.oldIndex].title);
209
        console.log("拖动后的索引 :" + this.areaMonitorList[evt.newIndex].title);
210
      },
211
      handleCameraSubmit(data) {
212
        if (this.dialogData.areaMonitorId != null) {
213
          const target = this.areaMonitorList.find(
214
            (item) => item.areaMonitorId === this.dialogData.areaMonitorId
215
          modifyMonitorScene(target);
216
          Object.assign(target, data);
217
        } else {
218
          this.areaMonitorList.unshift(data);
227
    handleSceneOnClick(item) {
228
      if (this.currenScene !== item) {
229
        this.currenScene = item
230
        this.geTerminalRel(this.currenScene)
231
      }
232
    },
233
    // 场景
234
    handleSceneEdit(item) {
235
      this.dialogSceneData = this.currenScene
236
      // event.stopPropagation()
237
    },
238
    btnAddClick() {
239
      this.dialogSceneData = {
240
        monitorSceneId: null, // 场景ID(新增时为空,修改时必填)
241
        monitorSceneName: null, // 场景名称(必填)
242
        organizationId: this.currentWindPlaceValue, // 组织标识(必填)
243
        monitorViewLayout: '1X1', // 布局CODE(必填)
244
        monitorSceneCode: '' // 场景CODE(暂时为空)
245
      }
246
    },
247
    handlesceneDelete(item) {
248
      sysapi.deleteMonitorScene(item)
249
        .then((resp) => {
250
          this.$Message.danger('删除成功')
251
        }).catch((error) => {
252
          console.log(error)
253
          this.$Message.danger('删除失败')
254
        }).finally(() => {
255
          this.getMonitorScene(this.currentWindPlaceValue)
256
        })
257
    },
258
    handlesceneSubmit(data) {
259
      if (data.monitorSceneId != null) {
260
        const target = this.monitorSceneList.find(
261
          (item) =>
262
            item.monitorSceneId ===
263
          data.monitorSceneId
264
        )
265
        Object.assign(target, data)
266
        sysapi
267
          .modifyMonitorScene(targetmodifyMonitorScene(target)
268
          .then((resp) => {
269
            if (resp.data.success === false) {
270
              this.$Message.danger(resp.data.fail.message)
271
            } else {
272
              this.$Message.success('修改成功')
273
            }
274
          }).catch((error) => {
275
            console.log(error)
276
            this.$Message.danger('修改失败')
277
          }).finally(() => {
278
            this.getMonitorScene(this.currentWindPlaceValue)
279
          })
280
      } else {
281
        sysapi.createMonitorScene(data)
282
          .then((resp) => {
283
            if (resp.data.success === false) {
284
              this.$Message.danger(resp.data.fail.message)
285
            } else {
286
              this.$Message.success('增添成功')
287
            }
288
          })
289
          .catch((error) => {
290
            console.log(error)
291
            this.$Message.danger('增添失败')
292
          }).finally(() => {
293
            this.getMonitorScene(this.currentWindPlaceValue)
294
          })
295
      }
296
    },
297
    // 监控
298
    handleEdit(item) {
299
      this.dialogData = Object.assign({}, item)
300
      console.log(item.title)
301
    },
302
    handleCreate() {
303
      this.dialogData = {
304
        customProperties: {},
305
        validDate: null,
306
        expireDate: null,
307
        dataStatus: '1',
308
        createDate: '2020-12-01 23:48:51',
309
        createOpId: null,
310
        createOrgId: null,
311
        doneCode: null,
312
        doneDate: '2020-12-01 23:48:51',
313
        opId: null,
314
        orgId: null,
315
        mgmtDistrict: null,
316
        mgmtCounty: null,
317
        regionId: null,
318
        tenantCode: null,
319
        monitorSceneTerminalRelId: null, // 场景与监控终端关联ID
320
        monitorSceneId: this.currenScene.monitorSceneId, // 场景ID
321
        resourceToolId: null, // 监控终端ID
322
        resourceToolName: null, // 监控终端名称
323
        pictureUrl: null, // 监控终端图片URL
324
        videoUrl: null, // 监控终端视频URL
325
        place: null, // 监控终端位置
326
        resourceToolIndex: null, // 监控终端在场景中的序号
327
        effectType: 'OUT'
328
      }
329
    },
330
    handleDeleted(data) {
331
      sysapi.deleteTerminalRel(data)
332
        .then((resp) => {
333
        }).catch((error) => {
334
          console.log(error)
335
          this.$Message.danger('删除失败')
336
        }).finally(() => {
337
          this.geTerminalRel(this.currenScene)
338
        })
339
    },
340
    datadragEnd(evt) {
341
      if (evt.oldIndex !== evt.newIndex) {
342
        let params = {
343
          monitorSceneTerminalRelId: this.areaMonitorList[evt.oldIndex].monitorSceneTerminalRelId, // 场景与终端关联ID
344
          monitorSceneId: this.currenScene.monitorSceneId, // 场景ID
345
          resourceToolId: this.areaMonitorList[evt.oldIndex].resourceToolId, // 终端ID
346
          resourceToolIndex: this.areaMonitorList[evt.newIndex].resourceToolIndex // 移动位置序号
219 347
        }
220
      },
348
        sysapi.moveTerminalRelIndex(params).then((resp) => {})
349
          .catch((error) => {
350
            console.log(error)
351
            this.$Message.danger('修改位置失败')
352
          }).finally(() => {
353
            this.geTerminalRel(this.currenScene)
354
          })
355
      }
221 356
    },
222
  };
357
    handleCameraSubmit(data) {
358
      if (data.monitorSceneTerminalRelId != null) {
359
        const target = this.areaMonitorList.find(
360
          (item) =>
361
            item.monitorSceneTerminalRelId ===
362
          data.monitorSceneTerminalRelId
363
        )
364
        Object.assign(target, data)
365
        sysapi
366
          .modifyTerminalRel(target)
367
          .then((resp) => {
368
            if (resp.data.success === false) {
369
              this.$Message.danger(resp.data.fail.message)
370
            } else {
371
              this.$Message.success('修改成功')
372
            }
373
          }).catch((error) => {
374
            console.log(error)
375
            this.$Message.danger('修改失败')
376
          }).finally(() => {
377
            this.geTerminalRel(this.currenScene)
378
          })
379
      } else {
380
        sysapi.createTerminalRel(data)
381
          .then((resp) => {
382
            if (resp.data.success === false) {
383
              this.$Message.danger(resp.data.fail.message)
384
            } else {
385
              this.$Message.success('增添成功')
386
            }
387
          })
388
          .catch((error) => {
389
            console.log(error)
390
            this.$Message.danger('增添失败')
391
          }).finally(() => {
392
            this.geTerminalRel(this.currenScene)
393
          })
394
      }
395
    }
396
  }
397
}
223 398
</script>
224 399
225 400
<style lang="scss">
401
.div_edit {
402
  float: right;
403
  width: 14px;
404
  height: 14px;
405
  position: absolute;
406
  top: 0.4833px;
407
  right: 1.8px;
408
  z-index: 100;
226 409
  .ico {
227 410
    width: 14px;
228 411
    height: 14px;
229 412
    line-height: 14px !important;
230 413
    margin: 2px;
231 414
  }
232
233
  .table-pager {
234
    justify-content: flex-end;
235
    float: right;
236
  }
237
</style>
415
}
416
.table-pager {
417
  justify-content: flex-end;
418
  float: right;
419
}
420
</style>

+ 37 - 0
security-protection-platform/src/modules/system/monitor/components/CreateCard/index.vue

@ -0,0 +1,37 @@
1
<template>
2
  <div class="create-card">
3
    <div class="create-card-block" @click="$emit('click')">
4
      <t-icon icon="plus-outline"></t-icon>
5
      <span>新增监控</span>
6
    </div>
7
  </div>
8
</template>
9
10
<script>
11
export default {
12
13
}
14
</script>
15
16
<style lang="scss">
17
.create-card {
18
  display: inline-block;
19
  overflow: hidden;
20
  cursor: pointer;
21
  height: 100%;
22
  padding: 10px;
23
  margin-bottom: 10px;
24
  &-block {
25
    display: flex;
26
    height: calc(100% - 0px);
27
    justify-content: center;
28
    align-items: center;
29
    border: 1px dotted #D9D9D9;
30
31
    &:hover {
32
      border-color: transparent;
33
      box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.15), -1px -1px 5px rgba(0, 0, 0, 0.15);
34
    }
35
  }
36
}
37
</style>

+ 117 - 0
security-protection-platform/src/modules/system/monitor/components/DraggableGrid/index.vue

@ -0,0 +1,117 @@
1
<template>
2
  <div ref="box" class="draggable-container">
3
    <draggable :list="list" v-bind="dragOptions" v-on="$listeners">
4
      <transition-group>
5
        <slot :scope="{width: gridWidth, height: gridHeight}" name="prepend"></slot>
6
7
        <template v-for="item in list">
8
          <div v-if="item && keyWord in item" :key="item[keyWord]" :style="{width: gridWidth + 'px', height: gridHeight + 'px'}" class="draggable-item">
9
            <slot :scope="{data: item, width: gridWidth, height: gridHeight}"></slot>
10
          </div>
11
        </template>
12
      </transition-group>
13
    </draggable>
14
15
    <template v-if="showPage">
16
      <div v-for="descr in pageDescrs" :key="descr.text" :style="descr.style" class="page-descr">
17
        <span>{{ descr.text }}</span>
18
      </div>
19
    </template>
20
  </div>
21
</template>
22
23
<script>
24
import ViewCard from '../ViewCard'
25
import Draggable from 'vuedraggable'
26
27
export default {
28
  components: { ViewCard, Draggable },
29
  model: {
30
    prop: 'list',
31
    event: 'input'
32
  },
33
  props: {
34
    list: {
35
      type: Array,
36
      default: () => []
37
    },
38
    keyWord: {
39
      type: String,
40
      required: true
41
    },
42
    grid: {
43
      type: Array,
44
      default: () => [4, 1]
45
    },
46
    gridPer: { // 长宽比
47
      type: Number,
48
      default: 1.3
49
    },
50
    showPage: {
51
      type: Boolean,
52
      default: false
53
    }
54
  },
55
  data() {
56
    return {
57
      boxWidth: 0,
58
      dragOptions: {
59
        animation: 300,
60
        group: 'viewData',
61
        draggable: '.draggable-item',
62
        filter: '.page-descr',
63
        // disabled: this.disabled,
64
        ghostClass: 'ghost'
65
      }
66
    }
67
  },
68
  computed: {
69
    gridHeight() {
70
      return this.boxWidth / this.grid[0] / this.gridPer
71
    },
72
    gridWidth() {
73
      return this.boxWidth / this.grid[0]
74
    },
75
    pageSize() {
76
      return this.grid[0] * this.grid[1]
77
    },
78
    pageDescrs() {
79
      let pageSum = Math.ceil(this.list.length / this.pageSize)
80
      const descrs = []
81
      for (let i = 0; i < pageSum; i++) {
82
        descrs.push({
83
          text: `第 ${i + 1} / ${pageSum} 页`,
84
          style: {
85
            // 分页高 + 分页间隔和 + 基础偏移
86
            top: (this.gridHeight * this.grid[1] * (i + 1)) + (10 * i) + 5 + 'px'
87
          }
88
        })
89
      }
90
      return descrs
91
    }
92
  },
93
  mounted() {
94
    this.boxWidth = this.$refs.box.clientWidth
95
  },
96
  methods: {
97
  }
98
99
}
100
</script>
101
102
<style lang="scss">
103
.draggable-container {
104
  position: relative;
105
  line-height: 0;
106
  .page-descr {
107
    text-align: right;
108
    position: absolute;
109
    right: 0;
110
  }
111
}
112
.draggable-item {
113
  display: inline-block;
114
  overflow: hidden;
115
  margin-bottom: 10px;
116
}
117
</style>

+ 76 - 0
security-protection-platform/src/modules/system/monitor/components/ViewCard/UpdateName.vue

@ -0,0 +1,76 @@
1
<template>
2
  <div class="update-name">
3
    <div v-if="text_tatus == 0" @mouseover="mouseOver">
4
      {{ name }}
5
    </div>
6
    <div v-else-if="text_tatus == 1" @mouseleave="mouseLeave">
7
      {{ name }}
8
      <div class="iconChange" @click="iconChange">
9
        <t-icon icon="edit-outline" size="24"> </t-icon>
10
      </div>
11
    </div>
12
    <div v-else @mouseleave="mouseLeave">
13
      <t-input
14
        v-model="cname"
15
        size="sm"
16
        icon="check-outline"
17
        icon-placement="right"
18
        @icon-click="iconSubmit"
19
      >
20
      </t-input>
21
    </div>
22
  </div>
23
</template>
24
25
<script>
26
export default {
27
  name: 'UpdateName',
28
  props: {
29
    name: String
30
  },
31
  data() {
32
    return {
33
      text_tatus: 0,
34
      cname: null
35
    }
36
  },
37
  watch: {},
38
  mounted() {
39
    this.cname = this.name
40
  },
41
  methods: {
42
    // 移入
43
    mouseOver() {
44
      this.text_tatus = 1
45
    },
46
    // 移出
47
    mouseLeave() {
48
      if (this.text_tatus === 2) {
49
        this.$emit('nameSubmit', this.cname)
50
      }
51
      this.text_tatus = 0
52
    },
53
    // 修改
54
    iconChange() {
55
      this.text_tatus = 2
56
    },
57
    // 提交
58
    iconSubmit() {
59
      this.text_tatus = 1
60
      this.$emit('nameSubmit', this.cname)
61
    }
62
  }
63
}
64
</script>
65
66
<style lang="scss">
67
.update-name {
68
  font-size: 14px;
69
  padding: 0 5px;
70
71
  .iconChange {
72
    height: 20px;
73
    float: right;
74
  }
75
}
76
</style>

+ 194 - 0
security-protection-platform/src/modules/system/monitor/components/ViewCard/index.vue

@ -0,0 +1,194 @@
1
<template>
2
  <div :class="{ active: showConfirm, lock: loadingDelete }" :style="{ width, height }" class="masonry__item div-block">
3
    <div class="card card-has-shadowed card-main">
4
      <div :style="`backgroundImage:url(${data.pictureUrl})`" class="card-bg" />
5
      <div class="opt">
6
        <div class="move">拖拽移动</div>
7
        <t-button shape="round" icon="swap-outline" style="margin: 0px 2px 0px 2px" @click="handleEdit">替换</t-button>
8
        <t-button shape="round" icon="delete" @click="handleDelete">删除</t-button>
9
        <div v-show="showConfirm" class="popover">
10
          <t-icon color="warning" icon="alert-circle" style="vertical-align: middle" />
11
          你确定删除该{{ monitorSceneTypeName }}吗?
12
          <div class="btn-block">
13
            <t-button :loading="loadingDelete" size="sm" color="primary" @click="handleConfirmDelete">确定</t-button>
14
            <t-button size="sm" color="secondary" style="margin-right: 8px" @click="handleCancelDelete">取消</t-button>
15
          </div>
16
        </div>
17
      </div>
18
    </div>
19
    <div class="card card-has-shadowed card-title">
20
      <update-name :name="name" @nameSubmit="handleChangeName" />
21
    </div>
22
  </div>
23
</template>
24
25
<script>
26
import UpdateName from './UpdateName'
27
export default {
28
  components: {
29
    UpdateName
30
  },
31
  props: {
32
    data: {
33
      type: Object,
34
      require: true
35
    },
36
    width: {
37
      type: String,
38
      default: '100%'
39
    },
40
    height: {
41
      type: String,
42
      default: '100%'
43
    }
44
  },
45
  data() {
46
    return {
47
      showConfirm: false,
48
      loadingDelete: false
49
    }
50
  },
51
  computed: {
52
    name: function () {
53
      return this.data.resourceToolName
54
    }
55
  },
56
  mounted() {
57
58
  },
59
  methods: {
60
    handleChangeName: function (name) {
61
      // 修改名称
62
      if (this.data.resourceToolName !== name) {
63
        this.data.resourceToolName = name
64
        this.$emit('nameChange', this.data)
65
      }
66
    },
67
    handleDelete() {
68
      this.showConfirm = true
69
    },
70
    handleConfirm() {},
71
    handleCancelDelete() {
72
      this.showConfirm = false
73
    },
74
    handleConfirmDelete() {
75
      // 把事件抛出去,保持控件的干净
76
      this.$emit('deleted', this.data)
77
    },
78
    handleEdit() {
79
      this.$emit('edit', this.data)
80
    }
81
  }
82
}
83
</script>
84
85
<style lang="scss">
86
  @import "@/assets/styles/aid-theme/_variable.scss";
87
88
  .div-block {
89
    display: inline-block;
90
    .card-bg {
91
      background-size: cover;
92
      height: 100%;
93
      width: 100%;
94
    }
95
96
    .card-main {
97
      height: calc(100% - 37px);
98
      margin-bottom: 5px;
99
    }
100
101
    .card-title {
102
      padding: 5px;
103
      height: 32px;
104
      line-height: 22px;
105
    }
106
107
    .opt {
108
      position: absolute;
109
      left: 0;
110
      top: 0;
111
      width: 100%;
112
      height: 100%;
113
      opacity: 0;
114
      display: flex;
115
      justify-content: center;
116
      align-items: center;
117
      .move{
118
        color: rgb(255, 255, 255);
119
        position: absolute;
120
        top: 12px;
121
        text-align: center;
122
      }
123
      &::before {
124
        content: "";
125
        display: block;
126
        position: absolute;
127
        left: 0;
128
        top: 0;
129
        width: 100%;
130
        height: 100%;
131
        background-color: #00000038;
132
        border-radius: 4px;
133
        opacity: 0.8;
134
      }
135
      &::after {
136
        content: "";
137
        display: none;
138
        position: absolute;
139
        left: 0;
140
        top: 0;
141
        width: 100%;
142
        height: 100%;
143
        background-color: black;
144
        border-radius: 4px;
145
        opacity: 0;
146
      }
147
148
      &>.btn {
149
        color: rgba(255, 255, 255, 0.65);
150
        border-color: rgba(0, 0, 0, 0);
151
        background-color: rgba(0, 0, 0, 0);
152
153
        &:hover {
154
          color: white;
155
          background-color: $brand-primary;
156
        }
157
      }
158
159
      &:hover {
160
        opacity: 1;
161
      }
162
    }
163
164
    &.active &__opt {
165
      opacity: 1;
166
    }
167
168
    &.lock &__opt::after {
169
      display: block;
170
    }
171
172
    .popover {
173
      width: 213px;
174
      background-color: white;
175
      color: rgba(0, 0, 0, 0.65);
176
      position: absolute;
177
      bottom: 12px;
178
      left: 12px;
179
      padding: 16px 20px;
180
      border-radius: 4px;
181
    }
182
183
    .btn-block {
184
      display: flex;
185
      flex-direction: row-reverse;
186
      margin-top: 14px;
187
    }
188
  }
189
190
  .div-footer {
191
    height: 32px;
192
    margin-top: 6px;
193
  }
194
</style>

+ 3 - 3
security-protection-platform/src/modules/system/monitor/index.vue

@ -1,9 +1,9 @@
1 1
<template>
2
<div class="app-monitor">
2
  <div class="app-monitor">
3 3
    <t-tabs :animated="false" class="sys-monitor__tabs">
4 4
      <t-tab-panel label="首页" panel-id="tab-1">
5 5
        <home-page-settings class="sys-attendance__page" />
6
        
6
7 7
      </t-tab-panel>
8 8
      <t-tab-panel label="视频监控" panel-id="tab-2">
9 9
        <video-monitor class="sys-attendance__page" />
@ -55,4 +55,4 @@ export default {
55 55
.sys-attendance__page {
56 56
  padding: 24px 0;
57 57
}
58
</style>
58
</style>

+ 173 - 0
security-protection-platform/src/modules/videoSurveillance/components/ReplayDialog/index.vue

@ -0,0 +1,173 @@
1
<template>
2
  <t-modal :visibled.sync="visible" :header-visibled="false" :footer-visibled="false" :no-padding="true" width="100%">
3
    <div class="replayer">
4
      <div class="replayer-list">
5
        <t-tabs v-model="currentTab" mode="scrollY" orientation="vertical" width="150px" @change="handleTabChange">
6
          <t-tab-panel v-for="item in list" :key="item.fileId" :label="item.fileName" :panel-id="item.fileId" />
7
        </t-tabs>
8
      </div>
9
10
      <div class="replayer-video">
11
        <t-loading v-model="loadVideo">
12
          <span class="text-md text-info">获取视频资源...</span>
13
        </t-loading>
14
        <video-player
15
          :sources="videoList"
16
          :autoadvance="0"
17
          :style="{opacity: loadVideo ? 0: 1}"
18
          @player-inited="handlePlayerInited"
19
          @playlistitem="handlePlayerCurrentChange"
20
        />
21
      </div>
22
    </div>
23
  </t-modal>
24
</template>
25
26
<script>
27
import VideoPlayer from '@/components/VideoPlayer'
28
29
export default {
30
  components: { VideoPlayer },
31
  props: {
32
    list: {
33
      type: Array,
34
      default: () => []
35
    },
36
    visibled: {
37
      type: Boolean,
38
      default: false
39
    }
40
  },
41
  data() {
42
    return {
43
      currentTab: null,
44
      loadVideo: false,
45
      videoList: [],
46
      $player: null
47
    }
48
  },
49
  computed: {
50
    visible: {
51
      get() { return this.visibled },
52
      set(val) {
53
        if (!val) this.$player.pause()
54
        this.$emit('update:visibled', val)
55
      }
56
    }
57
  },
58
  watch: {
59
    list: {
60
      handler(val) {
61
        console.warn(`list Change`)
62
        this.resetVideoList()
63
        if (val.length > 0) {
64
          this.currentTab = val[0].fileId
65
          // 手动触发第一个tab点击事件
66
          this.handleTabChange(null, 0)
67
        }
68
      },
69
      immediate: true
70
    }
71
  },
72
  methods: {
73
    handlePlayerInited(player) {
74
      this.$player = player
75
      window.player = this
76
    },
77
    async handleTabChange(name, index) {
78
      this.$player.pause()
79
      await this.preloadOriVideoUrl(index)
80
      this.play(index)
81
    },
82
    handlePlayerCurrentChange(e, item) {
83
      const { index, fileId } = item
84
      this.currentTab = fileId
85
      this.preloadOriVideoUrl(index)
86
    },
87
    resetVideoList() {
88
      const videoList = this.list.map((item, index) => {
89
        const { fileId, fileType } = item
90
        return {
91
          index,
92
          fileId,
93
          fileType,
94
          loaded: false
95
        }
96
      })
97
98
      this.videoList = videoList
99
    },
100
    play(index) {
101
      console.log(`播放:index=${index}`)
102
      // 调用额外的currentItem方法以避免currentItem在首次不生效
103
      // https://github.com/brightcove/videojs-playlist/blob/master/docs/api.md
104
      this.$player.playlist.currentItem()
105
      this.$player.playlist.currentItem(index)
106
      this.$player.play()
107
    },
108
    /**
109
     *  从index开始预载videoList的视频地址
110
     *  此方法将在获取index对应的地址后就立即返回
111
     */
112
    preloadOriVideoUrl(index = 0, maxLength = 5) {
113
      return new Promise((resolve, reject) => {
114
        for (let i = index; i in this.videoList && i - index < maxLength; i++) {
115
          console.log(`预载地址:index=${i}`)
116
          const item = this.videoList[i]
117
          const task = item.loaded
118
            ? Promise.resolve()
119
            : this.getOriVideoUrl(item.fileId).then(resp => {
120
              console.log(`预载完成,更新播放源:index=${i}`)
121
              item.loaded = true
122
              item.sources = [{
123
                src: resp.url,
124
                type: item.fileType
125
              }]
126
            })
127
          if (i === index) {
128
            this.loadVideo = !item.loaded
129
            task.then(() => {
130
              resolve()
131
            }).finally(() => {
132
              this.loadVideo = false
133
            })
134
          }
135
        }
136
      })
137
    },
138
    /*
139
     * 获取真实视频地址
140
     */
141
    getOriVideoUrl(fileId) {
142
      console.log(`请求地址:${fileId}`)
143
      // fake
144
      return new Promise((resolve, reject) => {
145
        setTimeout(() => {
146
          const x = Math.random()
147
          const url = x > 0.5
148
            ? 'http://10.19.90.34:19000/tool-image/tool-image_7d359725fac4464fb248284caf321993.mp4'
149
            : 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4'
150
          resolve({
151
            url
152
          })
153
        }, 1000)
154
      })
155
    }
156
  }
157
}
158
</script>
159
160
<style lang="scss">
161
.replayer {
162
  display: flex;
163
  &-list {
164
    margin-right: 20px;
165
    // width: 200px;
166
  }
167
168
  &-video {
169
    position: relative;
170
    flex: auto;
171
  }
172
}
173
</style>

+ 176 - 154
security-protection-platform/src/modules/videoSurveillance/index.vue

@ -1,55 +1,49 @@
1 1
<template>
2 2
  <div class="page-main">
3 3
    <t-button-group class="top-btn">
4
      <t-button :color="tabType === 'gate' ? 'primary' : 'secondary'" @click="tabClick('gate')">风场大门</t-button>
5
      <t-button :color="tabType === 'room' ? 'primary' : 'secondary'" @click="tabClick('room')">集控室</t-button>
4
      <t-button :color="tabId === 1 ? 'primary' : 'secondary'" @click="tabClick(1)">风场大门</t-button>
5
      <t-button :color="tabId === 2 ? 'primary' : 'secondary'" @click="tabClick(2)">集控室</t-button>
6 6
    </t-button-group>
7 7
    <div class="page-top">
8 8
      <span>风场:</span>
9
      <t-select v-model="gateFieldData" @change="getWindFieldData">
9
      <t-select v-model="gateFieldData" clearable @change="getVideoSurveillanceData(true)">
10 10
        <t-option v-for="(item,index) in organizationList" :key="index" :value="item.id">{{ item.org }}</t-option>
11 11
      </t-select>
12 12
    </div>
13
    <div v-if="tabType==='gate'" >
14
      <div class="page-bottom">
15
        <t-card v-for="(item,index) in gateList" :key="index" :class="index%3===0?'card-video-first':'card-video'">
13
    <div class="page-bottom">
14
      <div v-for="(item,index) in videoList" :key="index">
15
        <t-card class="card-video">
16 16
          <img :src="item.url" class="card-image">
17 17
          <div slot="foot" class="bottom">
18 18
            <span v-tooltip="item.videoDetail">{{ item.videoDetail.content | handleText }}</span>
19 19
            <div style="margin-left:auto">
20
              <t-button v-tooltip="item.options1" class="bottom-btn" @click="goDistinguishRecord(item.videoId)"><t-icon size="16" icon="image-outline"></t-icon></t-button>
21
              <t-button v-tooltip="item.options2" class="bottom-btn"><t-icon size="16" icon="piechart-outline"></t-icon></t-button>
22
              <t-button v-tooltip="item.options3" class="bottom-btn"><t-icon size="16" icon="arrow-expand-all-outline"></t-icon></t-button>
20
              <t-button v-tooltip="item.options1" class="bottom-btn" @click="goDistinguishRecord(item.videoId)">
21
                <t-icon size="16" icon="image-outline"></t-icon>
22
              </t-button>
23
              <t-button v-tooltip="item.options2" class="bottom-btn" @click="handleReview(item.videoId)">
24
                <t-icon size="16" icon="piechart-outline"></t-icon>
25
              </t-button>
26
              <t-button v-tooltip="item.options3" class="bottom-btn">
27
                <t-icon size="16" icon="arrow-expand-all-outline"></t-icon>
28
              </t-button>
23 29
            </div>
24 30
          </div>
25 31
        </t-card>
26 32
      </div>
27
      <t-pager :page-size="gatePageSize" :current="gateCurrent" :total="gateTotal" :sizer-range="[ 5, 10, 20, 30 ]" class="pager" show-elevator @on-change="onChangeGate"></t-pager>
28
    </div>
29
    <div v-if="tabType==='room'" >
30
      <div class="page-bottom">
31
        <t-card v-for="(item,index) in roomList" :key="index" :class="index%3===0?'card-video-first':'card-video'">
32
          <img :src="item.url" class="card-image">
33
          <div slot="foot" class="bottom">
34
            <span v-tooltip="item.videoDetail">{{ item.videoDetail.content | handleText }}</span>
35
            <div style="margin-left:auto">
36
              <t-button v-tooltip="item.options1" class="bottom-btn" @click="goDistinguishRecord(item.videoId)"><t-icon size="16" icon="image-outline"></t-icon></t-button>
37
              <t-button v-tooltip="item.options2" class="bottom-btn"><t-icon size="16" icon="piechart-outline"></t-icon></t-button>
38
              <t-button v-tooltip="item.options3" class="bottom-btn"><t-icon size="16" icon="arrow-expand-all-outline"></t-icon></t-button>
39
            </div>
40
          </div>
41
        </t-card>
42
      </div>
43
      <t-pager :page-size="roomPageSize" :current="roomCurrent" :total="roomTotal" :sizer-range="[ 5, 10, 20, 30 ]" class="pager" show-elevator @on-change="onChangeRoom"></t-pager>
44 33
    </div>
34
    <t-pager :page-size="videoPageSize" :current="videoCurrent" :total="videoTotal" :sizer-range="[ 5, 10, 20, 30 ]" class="pager" show-elevator @on-change="onChangeGate"></t-pager>
35
    <replay-dialog :list="replayList" :visibled.sync="showReplayDialog" />
45 36
  </div>
46 37
</template>
47 38
<script>
48 39
import sysapi from '@/api/videoSurveillance'
49 40
import commonapi from '@/api/common'
41
import ReplayDialog from './components/ReplayDialog'
42
50 43
export default {
44
  components: { ReplayDialog },
51 45
  filters: {
52
    handleText(value) {
46
    handleText (value) {
53 47
      if (!value) return ''
54 48
      if (value.length > 13) {
55 49
        return value.slice(0, 13) + '...'
@ -57,38 +51,81 @@ export default {
57 51
      return value
58 52
    }
59 53
  },
60
  data() {
54
  data () {
61 55
    return {
62
      gateCurrent: 1, // 大门分页数据
63
      gatePageSize: 10, // 大门分页数据
64
      gateTotal: 100, // 大门分页总数
65
      roomCurrent: 1, // 集控室分页数据
66
      roomPageSize: 10, // 集控室分页数据
67
      roomTotal: 100, // 集控室分页总数
68
      tabType: 'gate',
56
      videoCurrent: 1, // 大门分页数据
57
      videoPageSize: 10, // 大门分页数据
58
      videoTotal: 100, // 大门分页总数
59
      tabId: 1,
60
      paramsObj: { // 接口请求数据
61
        page: 0,
62
        limit: 10
63
      },
64
      departments: '',
69 65
      organizationList: [], // 风场数据
70 66
      gateFieldData: 101101,
71
      gateList: [],
72
      roomList: []
67
      videoList: [],
68
      totalList: [],
69
      roomList: [],
70
71
      showReplayDialog: false,
72
      replayList: []
73 73
    }
74 74
  },
75
  mounted() {
75
  mounted () {
76 76
    this.getWindFiledList() // 获取风场列表
77
    this.getWindFieldData()
78
    this.getCenterRoomData()
77
    this.getVideoSurveillanceData() // 获取视频监控界面数据
79 78
  },
80 79
  methods: {
81
    tabClick(name) {
82
      this.gateFieldData = ''
83
      this.gateCurrent = 1
84
      this.roomCurrent = 1
85
      if (name === 'gate') {
86
        this.tabType = 'gate'
87
      } else {
88
        this.tabType = 'room'
89
      }
80
    async handleReview (id) {
81
      // const res = await sysapi.getVideoPlayBack(id)
82
      // console.log(res)
83
      this.replayList = [{
84
        fileName: '12月14 16:55',
85
        fileId: 'ai-video_5A02296PAKA885B-video20201214165526.mp4',
86
        fileType: 'video/mp4'
87
      }, {
88
        fileName: '12月14 16:56',
89
        fileId: 'ai-video_5A02296PAKA885B-video20201214165527.mp4',
90
        fileType: 'video/mp4'
91
      }, {
92
        fileName: '12月14 16:57',
93
        fileId: 'ai-video_5A02296PAKA885B-video20201214165528.mp4',
94
        fileType: 'video/mp4'
95
      }, {
96
        fileName: '12月14 16:58',
97
        fileId: 'ai-video_5A02296PAKA885B-video20201214165529.mp4',
98
        fileType: 'video/mp4'
99
      }, {
100
        fileName: '12月14 16:59',
101
        fileId: 'ai-video_5A02296PAKA885B-video20201214165530.mp4',
102
        fileType: 'video/mp4'
103
      }, {
104
        fileName: '12月14 17:00',
105
        fileId: 'ai-video_5A02296PAKA885B-video20201214165531.mp4',
106
        fileType: 'video/mp4'
107
      }]
108
      this.replayList = [{
109
        sources: [{
110
          src: 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4',
111
          type: 'video/mp4'
112
        }]
113
      }, {
114
        sources: [{
115
          src: 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4',
116
          type: 'video/mp4'
117
        }]
118
      }]
119
      this.showReplayDialog = true
90 120
    },
91
    getWindFiledList() {
121
    async tabClick (id) {
122
      this.paramsObj.page = 0
123
      this.videoList = []
124
      this.tabId = id
125
      this.videoCurrent = 1
126
      this.getVideoSurveillanceData()
127
    },
128
    getWindFiledList () {
92 129
      commonapi.getDepartments().then(resp => {
93 130
        this.organizationList = []
94 131
        console.log(resp)
@ -104,132 +141,117 @@ export default {
104 141
      })
105 142
    },
106 143
    // 获得风场大门数据
107
    getWindFieldData() {
108
      let obj = {
109
        page: this.gateCurrent,
110
        limit: this.gatePageSize
144
    getVideoSurveillanceData (isWind) {
145
      if (isWind) {
146
        this.videoList = []
111 147
      }
112
      sysapi.getGateFieldData({params: obj}).then(res => {
113
        this.gateList = res.data.data
114
        this.gateTotal = res.data.total
115
        this.gateList.forEach(element => {
116
          const txt = element.videoDetail
117
          element.videoDetail = {}
118
          element.videoDetail.content = txt
119
          element.videoDetail.placement = 'top'
148
      if (this.videoList.length <= 10) {
149
        this.paramsObj.page = this.videoCurrent
150
        sysapi.getVideoSurveillanceData({ params: this.paramsObj }).then(res => {
151
          this.departments = res.data.departments
152
          this.videoTotal = this.departments[this.tabId - 1].total
153
          res.data.data.forEach((element, index) => {
154
            if (element.departmentId === this.tabId) {
155
              this.videoList.push(element)
156
            }
157
          })
158
          this.videoList.forEach(element => {
159
            if (typeof (element.videoDetail) === 'object') {
160
              var txt = element.videoDetail.content
161
            } else { txt = element.videoDetail }
162
            element.videoDetail = {}
163
            element.videoDetail.content = txt
164
            element.videoDetail.placement = 'top'
165
          })
166
          this.getVideoSurveillanceData()
120 167
        })
121
      })
122
    },
123
    // 获得集控室数据
124
    getCenterRoomData() {
125
      let obj = {
126
        page: this.roomCurrent,
127
        limit: this.roomPageSize
128 168
      }
129
      sysapi.getCenterRoomData({params: obj}).then(res => {
130
        this.roomList = res.data.data
131
        this.roomTotal = res.data.total
132
        this.roomList.forEach(element => {
133
          const txt = element.videoDetail
134
          element.videoDetail = {}
135
          element.videoDetail.content = txt
136
          element.videoDetail.placement = 'top'
137
        })
138
      })
139
    },
140
    // 集控室分页
141
    onChangeRoom (val) {
142
      this.roomCurrent = val
143
      this.getCenterRoomData()
144 169
    },
145 170
    // 进入识别记录界面
146
    goDistinguishRecord(id) {
147
      this.$router.push({path: '/videoSurveillance/distinguishRecord', query: {videoId: id}})
171
    goDistinguishRecord (id) {
172
      this.$router.push({ path: '/videoSurveillance/distinguishRecord', query: { videoId: id } })
148 173
    },
149 174
    // 风场大门分页
150
    onChangeGate(val) {
151
      this.gateCurrent = val
152
      this.getWindFieldData()
175
    onChangeGate (val) {
176
      this.videoList = []
177
      this.videoCurrent = val
178
      this.getVideoSurveillanceData()
153 179
    }
154 180
  }
155 181
}
156 182
</script>
157 183
<style lang="scss" scoped>
158
.page-main{
159
    padding:30px 24px 24px 24px;
160
    .top-btn{
161
        float: right;
162
    }
163
    .page-bottom{
164
        display: flex;
184
.page-main {
185
  padding: 30px 24px 24px 24px;
186
  .top-btn {
187
    float: right;
188
  }
189
  .page-bottom {
190
    display: flex;
191
    width: 100%;
192
    flex-wrap: wrap;
193
    margin-left: -24px;
194
    .card-video-first,
195
    .card-video {
196
      width: 354px;
197
      height: 240px;
198
      margin-top: 20px;
199
      .card-image {
165 200
        width: 100%;
166
        flex-wrap: wrap;
167
        .card-video-first, .card-video{
168
          width:397px;
169
          margin-top: 20px;
170
          height:245px;
171
            .card-image{
172
                width: 100%;
173
                height: 100%;
174
            }
175
            .bottom{
176
                padding: 0 12px;
177
                display: flex;
178
                align-items: center;
179
                background-color: rgba(0, 0, 0, 0.5);
180
                height: 40px;
181
                color: #fff;
182
                font-size: 14px;
183
                .bottom-btn{
184
                    color: #fff;
185
                    border: none;
186
                    padding:0 !important;
187
                    &:hover{
188
                        color: #0089d4;
189
                    }
190
                }
191
            }
192
        }
193
        .card-video-first{
194
          .card-footer{
195
             padding: 0px !important;
196
             background: none;
197
             width: 100%;
198
             position: absolute;
199
             border-top: none;
200
             bottom: 0px;
201
             }
202
            .card-block{
203
              padding:0 !important;
204
            }
205
        }
206
        .card-video{
207
          .card-footer{
208
             padding: 0px 0 0 24px !important;
209
             background: none;
210
             width: 100%;
211
             position: absolute;
212
             border-top: none;
213
             bottom: 0px;
214
             }
215
            .card-block, .card-video-block{
216
              margin-left: 24px;
217
              padding:0 !important;
218
            }
201
        height: 100%;
202
      }
203
      .bottom {
204
        padding: 0 12px;
205
        display: flex;
206
        align-items: center;
207
        background-color: rgba(0, 0, 0, 0.5);
208
        height: 40px;
209
        color: #fff;
210
        font-size: 14px;
211
        .bottom-btn {
212
          color: #fff;
213
          border: none;
214
          padding: 0 !important;
215
          &:hover {
216
            color: #0089d4;
217
          }
219 218
        }
219
      }
220
    }
221
    .card-video {
222
      .card-footer {
223
        padding: 0px 0 0 24px !important;
224
        background: none;
225
        width: 100%;
226
        position: absolute;
227
        border-top: none;
228
        bottom: 0px;
229
      }
230
      .card-block,
231
      .card-video-block {
232
        margin-left: 24px;
233
        padding: 0 !important;
234
      }
220 235
    }
221
    .pager{
236
  }
237
  .pager {
222 238
    margin-right: auto;
223 239
    margin: 21px 0px 24px 0;
224 240
    float: right;
225 241
  }
226
.btn-primary, .radio-group-button .form-radio:checked, .radio-group-button .form-radio[checked]{
242
  .btn-primary,
243
  .radio-group-button .form-radio:checked,
244
  .radio-group-button .form-radio[checked] {
227 245
    color: #0089d4;
228 246
    background-color: #fff;
229 247
    border: 1px solid #0089d4;
230
}
231
.btn-secondary, .radio-group-button .form-radio, .checkbox-group--button .form-checkbox .form-checkbox__inner, .btn-dashed-secondary, .btn-outline-secondary{
248
  }
249
  .btn-secondary,
250
  .radio-group-button .form-radio,
251
  .checkbox-group--button .form-checkbox .form-checkbox__inner,
252
  .btn-dashed-secondary,
253
  .btn-outline-secondary {
232 254
    background: none;
233
}
255
  }
234 256
}
235 257
</style>

+ 3 - 3
security-protection-platform/src/modules/workorder/components/modal/approvalmodal.vue

@ -20,8 +20,8 @@
20 20
    <t-form ref="approvalModalForm" :model="approvalModalForm" :rules="approvalModalFormRules" :label-span="2" label-position="right">
21 21
      <t-form-item label="审批结果:" prop="result">
22 22
        <t-radio-group v-model="approvalModalForm.result">
23
          <t-radio label="0">同意</t-radio>
24
          <t-radio label="1">拒绝</t-radio>
23
          <t-radio label="1">同意</t-radio>
24
          <t-radio label="0">拒绝</t-radio>
25 25
        </t-radio-group>
26 26
      </t-form-item>
27 27
      <t-form-item label="审批意见:" prop="comments">
@ -98,7 +98,6 @@ export default {
98 98
      this.$refs['approvalModalForm'].validate((valid) => {
99 99
        if (valid) {
100 100
          this.addApprovalData()
101
          this.$emit('refresh-all-data')
102 101
        } else {
103 102
          this.loadingSubmit = false
104 103
          console.log('error--------->请输入完整的表单信息!')
@ -111,6 +110,7 @@ export default {
111 110
      const res = await workOrderApi.addApprovalData(this.approvalModalForm)
112 111
      if (res.status === 200) {
113 112
        this.resetModalData()
113
        this.$emit('refresh-all-data')
114 114
        this.$Message.success('操作成功!')
115 115
      } else {
116 116
        this.$Message.danger('操作失败!')

+ 1 - 1
security-protection-platform/src/modules/workorder/components/modal/cardreplacementmodal.vue

@ -92,7 +92,6 @@ export default {
92 92
      this.$refs['cardReplacementModalForm'].validate((valid) => {
93 93
        if (valid) {
94 94
          this.addCardReplacementData()
95
          this.$emit('refresh-data')
96 95
        } else {
97 96
          console.log('error--------->请输入完整的表单信息!')
98 97
          this.loadingSubmit = false
@ -112,6 +111,7 @@ export default {
112 111
        if (res.data.fail) {
113 112
          this.$Message.warning(res.data.fail)
114 113
        } else {
114
          this.$emit('refresh-data')
115 115
          this.$Message.success('提交成功!')
116 116
        }
117 117
      } else {

+ 3 - 2
security-protection-platform/src/modules/workorder/components/modal/fieldservicemodal.vue

@ -115,7 +115,6 @@ export default {
115 115
      this.$refs['fieldServiceModalForm'].validate((valid) => {
116 116
        if (valid) {
117 117
          this.addFieldServiceData()
118
          this.$emit('refresh-data')
119 118
        } else {
120 119
          console.log('error--------->请输入完整的表单信息!')
121 120
          this.loadingSubmit = false
@ -143,6 +142,7 @@ export default {
143 142
        if (res.data.fail) {
144 143
          this.$Message.warning(res.data.fail)
145 144
        } else {
145
          this.$emit('refresh-data')
146 146
          this.$Message.success('提交成功!')
147 147
        }
148 148
      } else {
@ -155,7 +155,7 @@ export default {
155 155
      if (startDate && endDate) {
156 156
        const start = +new Date(startDate)
157 157
        const end = +new Date(endDate)
158
        return (end - start) / (24 * 60 * 60 * 1000)
158
        return (end - start) / (24 * 60 * 60 * 1000) + 1
159 159
      } else {
160 160
        return 0
161 161
      }
@ -163,6 +163,7 @@ export default {
163 163
    // 计算结束时间
164 164
    calEndTime (startDate, duration) {
165 165
      if (startDate && duration) {
166
        duration = duration - 1
166 167
        const endDate = formatDateTime(new Date(+new Date(startDate) + (duration * 24 * 60 * 60 * 1000)))
167 168
        return endDate
168 169
      } else {

+ 3 - 2
security-protection-platform/src/modules/workorder/components/modal/leavemodal.vue

@ -113,7 +113,6 @@ export default {
113 113
      this.$refs['leaveModalForm'].validate((valid) => {
114 114
        if (valid) {
115 115
          this.addLeaveData()
116
          this.$emit('refresh-data')
117 116
        } else {
118 117
          console.log('error--------->请输入完整的表单信息!')
119 118
          this.loadingSubmit = false
@ -141,6 +140,7 @@ export default {
141 140
        if (res.data.fail) {
142 141
          this.$Message.warning(res.data.fail)
143 142
        } else {
143
          this.$emit('refresh-data')
144 144
          this.$Message.success('提交成功!')
145 145
        }
146 146
      } else {
@ -153,7 +153,7 @@ export default {
153 153
      if (startDate && endDate) {
154 154
        const start = +new Date(startDate)
155 155
        const end = +new Date(endDate)
156
        return (end - start) / (24 * 60 * 60 * 1000)
156
        return (end - start) / (24 * 60 * 60 * 1000) + 1
157 157
      } else {
158 158
        return 0
159 159
      }
@ -161,6 +161,7 @@ export default {
161 161
    // 计算结束时间
162 162
    calEndTime (startDate, duration) {
163 163
      if (startDate && duration) {
164
        duration = duration - 1
164 165
        const endDate = formatDateTime(new Date(+new Date(startDate) + (duration * 24 * 60 * 60 * 1000)))
165 166
        return endDate
166 167
      } else {

+ 3 - 2
security-protection-platform/src/modules/workorder/components/modal/overtimemodal.vue

@ -102,7 +102,6 @@ export default {
102 102
      this.$refs['overtimeModalForm'].validate((valid) => {
103 103
        if (valid) {
104 104
          this.addWorkOverTimeData()
105
          this.$emit('refresh-data')
106 105
        } else {
107 106
          console.log('error--------->请输入完整的表单信息!')
108 107
          this.loadingSubmit = false
@ -130,6 +129,7 @@ export default {
130 129
        if (res.data.fail) {
131 130
          this.$Message.warning(res.data.fail)
132 131
        } else {
132
          this.$emit('refresh-data')
133 133
          this.$Message.success('提交成功!')
134 134
        }
135 135
      } else {
@ -142,7 +142,7 @@ export default {
142 142
      if (startDate && endDate) {
143 143
        const start = +new Date(startDate)
144 144
        const end = +new Date(endDate)
145
        return (end - start) / (24 * 60 * 60 * 1000)
145
        return (end - start) / (24 * 60 * 60 * 1000) + 1
146 146
      } else {
147 147
        return 0
148 148
      }
@ -150,6 +150,7 @@ export default {
150 150
    // 计算结束时间
151 151
    calEndTime (startDate, duration) {
152 152
      if (startDate && duration) {
153
        duration = duration - 1
153 154
        const endDate = formatDateTime(new Date(+new Date(startDate) + (duration * 24 * 60 * 60 * 1000)))
154 155
        return endDate
155 156
      } else {

+ 1 - 1
security-protection-platform/src/modules/workorder/components/modal/workorderinfomodal.vue

@ -15,7 +15,7 @@
15 15
    </div>
16 16
    <div v-if="status" class="approval-info row">
17 17
      <div class="col-6">审批人:<span>{{ data.approver }}</span></div>
18
      <div class="col-6">审批结果:<span>{{ data.result===0?'同意':'驳回' }}</span></div>
18
      <div class="col-6">审批结果:<span>{{ data.result==='0'?'失败':'成功' }}</span></div>
19 19
      <div class="col-12">审批时间:<span>{{ data.approveTime }}</span></div>
20 20
      <div class="col-12">审批意见:<span>{{ data.comments }}</span></div>
21 21
    </div>

+ 23 - 4
security-protection-platform/src/routes.js

@ -18,6 +18,19 @@ export const constantRoutes = [
18 18
    hidden: true
19 19
  },
20 20
  {
21
    path: '/dashboard',
22
    component: Layout,
23
    meta: { icon: 'home' },
24
    children: [
25
      {
26
        name: 'dashboard',
27
        path: '',
28
        component: () => import(/* webpackChunkName: "dashboard" */ './modules/dashboard'),
29
        meta: { title: '首页', icon: 'home' }
30
      }
31
    ]
32
  },
33
  {
21 34
    path: '/videoSurveillance',
22 35
    component: Layout,
23 36
    meta: { icon: 'home' },
@ -93,16 +106,22 @@ export const constantRoutes = [
93 106
        meta: { title: '设备管理' }
94 107
      },
95 108
      {
96
        name: 'sys_attendance',
97
        path: 'attendance',
98
        component: () => import(/* webpackChunkName: "sys_attendance" */ './modules/system/attendance'),
99
        meta: { title: '考勤配置' }
109
        name: 'sys_task',
110
        path: 'assignment',
111
        component: () => import(/* webpackChunkName: "sys_attendance" */ './modules/system/assignment'),
112
        meta: { title: 'AI任务' }
100 113
      },
101 114
      {
102 115
        name: 'sys_monitor',
103 116
        path: 'monitor',
104 117
        component: () => import(/* webpackChunkName: "sys_monitor" */ './modules/system/monitor'),
105 118
        meta: { title: '监控布局' }
119
      },
120
      {
121
        name: 'sys_attendance',
122
        path: 'attendance',
123
        component: () => import(/* webpackChunkName: "sys_attendance" */ './modules/system/attendance'),
124
        meta: { title: '考勤配置' }
106 125
      }
107 126
    ]
108 127
  },

+ 1 - 0
security-protection-platform/src/styles/index.scss

@ -25,6 +25,7 @@ html {
25 25
*,
26 26
*:before,
27 27
*:after {
28
  font-family: inherit;
28 29
  box-sizing: inherit;
29 30
}
30 31

登录 - Nuosi Git Service

登录