Pārlūkot izejas kodu

feat: DraggableGrid

chenlp5 4 gadi atpakaļ
vecāks
revīzija
91638384f1

+ 13 - 0
security-protection-platform/src/modules/dashboard/index.vue

@ -0,0 +1,13 @@
1
<template>
2
  <div>首页</div>
3
</template>
4
5
<script>
6
export default {
7
8
}
9
</script>
10
11
<style lang="scss">
12
13
</style>

+ 2 - 0
security-protection-platform/src/modules/system/monitor/HomePageSettings/Card.vue

@ -47,9 +47,11 @@ export default {
47 47
  },
48 48
  computed: {
49 49
    gridWidth: function () {
50
      if (this.itemWidth == null) return '100%'
50 51
      return this.itemWidth - 20 + 'px'
51 52
    },
52 53
    gridHeight: function () {
54
      if (this.itemWidth == null) return '100%'
53 55
      return this.itemWidth * 0.9 - 20 - 6 - 32 + 'px'
54 56
    }
55 57
  },

+ 125 - 149
security-protection-platform/src/modules/system/monitor/VideoMonitor/index.vue

@ -5,10 +5,7 @@
5 5
        <t-col>
6 6
          <div style="float: left">
7 7
            <span>风场: </span>
8
            <t-select
9
              v-model="currentWindPlaceValue"
10
              style="width: 200px; height: 32px"
11
            >
8
            <t-select v-model="currentWindPlaceValue" style="width: 200px; height: 32px">
12 9
              <t-option value="1">风场1</t-option>
13 10
              <t-option value="2">风场2</t-option>
14 11
            </t-select>
@ -17,30 +14,16 @@
17 14
        <t-col>
18 15
          <div style="float: right">
19 16
            <t-button-group>
20
              <t-button
21
                :class="['base', btnIsClicked ? 'active' : '']"
22
                @click="btnOnClick('areaMonitor')"
23
              >
17
              <t-button :class="['base', btnIsClicked ? 'active' : '']" @click="btnOnClick('areaMonitor')">
24 18
                <span>大门</span>
25
                <div
26
                  v-if="dialogSceneData.id == '1'"
27
                  style="float: right; width: 14px; height: 14px"
28
                  @click="handleSceneEdit('123')"
29
                >
19
                <div v-if="dialogSceneData.id == '1'" style="float: right; width: 14px; height: 14px" @click="handleSceneEdit('123')">
30 20
                  <t-icon icon="edit" shape="circle" class="ico"></t-icon>
31 21
                </div>
32 22
              </t-button>
33 23
34
              <t-button
35
                :class="['base', btnIsClicked ? 'active' : '']"
36
                @click="btnOnClick('areaMonitor')"
37
              >
24
              <t-button :class="['base', btnIsClicked ? 'active' : '']" @click="btnOnClick('areaMonitor')">
38 25
                <span>值班室</span>
39
                <div
40
                  v-if="dialogSceneData.id == '456'"
41
                  style="float: right; width: 14px; height: 14px"
42
                  @click="handleSceneEdit('456')"
43
                >
26
                <div v-if="dialogSceneData.id == '456'" style="float: right; width: 14px; height: 14px" @click="handleSceneEdit('456')">
44 27
                  <t-icon icon="edit" shape="circle" class="ico"></t-icon>
45 28
                </div>
46 29
              </t-button>
@ -50,41 +33,48 @@
50 33
        </t-col>
51 34
      </t-row>
52 35
      <t-row>
53
        <t-col style="margin-top: 10px">
54
          <t-button color="info" icon="plus-circle" @click="handleCreate" >新增监控</t-button
55
          >
36
        <t-col style="margin-top:10px;">
37
          <t-button color="info" icon="plus-circle" @click="handleCreate">新增监控</t-button>
56 38
        </t-col>
57 39
      </t-row>
58 40
      <!--header-->
59 41
    </div>
60
    <div style="min-height: 290px; height: auto !important">
61
      <!-- <draggable v-model="rows"> -->
62
      <div v-for="(row,index) in viewDataList" :key="index" @update="datadragEnd">
63
        <div style="text-align: right">
64
          <span style="width: 300px" >第{{ index + 1 }}/{{ viewDataList.length }}页</span
65
          >
66
        </div>
67
        <draggable
68
          :list="row"
69
          :group="{ name: 'row' }"
70
          @update="datadragEnd"
71
          @add="datadragEnd"
72
        >
73
          <camera-card
74
            v-for="item in row"
75
            :key="item.areaMonitorId"
76
            :data="item"
77
            :item-width="itemWidth"
42
    <div style="min-height: 280px; height: auto !important">
43
      <draggable-grid v-model="areaMonitorList" :show-page="true" key-word="areaMonitorId" @update="datadragEnd">
44
        <template v-slot:prepend="{scope}">
45
          <create-card key="create-card" :style="{ width: scope.width + 'px', height: scope.height + 'px' }"/>
46
        </template>
47
48
        <template v-slot="{scope}">
49
          <view-card
50
            :data="scope.data"
51
            :width="scope.width + 'px'"
52
            :height="scope.height + 'px'"
78 53
            @edit="handleEdit"
79 54
            @deleted="handleDeleted"
80 55
          />
81
        </draggable>
82
      </div>
56
        </template>
57
      </draggable-grid>
58
      <!-- <draggable v-model="areaMonitorList" @update="datadragEnd"> -->
59
      <!-- <transition-group>
60
          <div v-for="(viewArray,index) in viewDataList" :key="index">
61
            <div style="text-align: right;">
62
              <span style="width:300px">第{{ index+1 }}/{{ viewDataList.length }}页</span>
63
            </div>
64
            <draggable v-model="viewDataList[index]" v-bind="dragOptions" @update="datadragEnd">
65
              <camera-card
66
                v-for="item in viewArray"
67
                :key="item.areaMonitorId"
68
                :data="item"
69
                :item-width="itemWidth"
70
                @edit="handleEdit"
71
                @deleted="handleDeleted"
72
              />
73
            </draggable>
74
          </div>
75
        </transition-group> -->
83 76
      <!-- </draggable> -->
84
      <shift-scene-dialog
85
        :data="dialogSceneData"
86
        @submit="handleCameraSubmit"
87
      />
77
      <shift-scene-dialog :data="dialogSceneData" @submit="handleCameraSubmit" />
88 78
      <shift-camera-dialog :data="dialogData" @submit="handleCameraSubmit" />
89 79
    </div>
90 80
  </div>
@ -95,12 +85,19 @@ import CameraCard from '../HomePageSettings/Card'
95 85
import draggable from 'vuedraggable'
96 86
import ShiftSceneDialog from './ShiftSceneDialog'
97 87
import ShiftCameraDialog from '../HomePageSettings/ShiftCameraDialog'
88
import DraggableGrid from '../components/DraggableGrid'
89
import ViewCard from '../components/ViewCard'
90
import CreateCard from '../components/CreateCard'
91
98 92
export default {
99 93
  components: {
100 94
    CameraCard,
101 95
    draggable,
102 96
    ShiftSceneDialog,
103
    ShiftCameraDialog
97
    ShiftCameraDialog,
98
    DraggableGrid,
99
    ViewCard,
100
    CreateCard
104 101
  },
105 102
  data() {
106 103
    return {
@ -111,80 +108,70 @@ export default {
111 108
      dialogData: {},
112 109
      currentType: 3,
113 110
      itemWidth: null,
114
      sceneList: [
115
        {
116
          sceneName: '大门',
117
          id: '1',
118
          parentId: '1',
119
          displayType: '4'
120
        },
121
        {
122
          sceneName: '值班室',
123
          id: '2',
124
          parentId: '1',
125
          displayType: '3'
126
        }
127
      ],
128
      areaMonitorList: [
129
        {
130
          title: '摄像头001',
131
          cameraId: '001',
132
          areaMonitorId: '001',
133
          sceneId: '1',
134
          sortOrder: 0,
135
          imgsrc:
136
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
137
        },
138
        {
139
          title: '摄像头002',
140
          cameraId: '002',
141
          areaMonitorId: '002',
142
          sortOrder: 1,
143
          imgsrc:
144
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
145
        },
146
        {
147
          title: '摄像头003',
148
          cameraId: '003',
149
          areaMonitorId: '003',
150
          sortOrder: 2,
151
          imgsrc:
152
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
153
        },
154
        {
155
          title: '摄像头004',
156
          cameraId: '004',
157
          areaMonitorId: '004',
158
          sortOrder: 3,
159
          imgsrc:
160
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
161
        },
162
        {
163
          title: '摄像头005',
164
          cameraId: '005',
165
          areaMonitorId: '005',
166
          sortOrder: 4,
167
          imgsrc:
168
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
169
        },
170
        {
171
          title: '摄像头006',
172
          cameraId: '006',
173
          areaMonitorId: '006',
174
          sortOrder: 5,
175
          imgsrc:
176
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
177
        },
178
        {
179
          title: '摄像头007',
180
          cameraId: '007',
181
          areaMonitorId: '007',
182
          sortOrder: 6,
183
          imgsrc:
184
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
185
        }
111
      sceneList: [{
112
        sceneName: '大门',
113
        id: '1',
114
        parentId: '1',
115
        displayType: '4'
116
      },
117
      {
118
        sceneName: '值班室',
119
        id: '2',
120
        parentId: '1',
121
        displayType: '3'
122
      }
186 123
      ],
187
      rows: []
124
      areaMonitorList: [{
125
        title: '摄像头001',
126
        cameraId: '001',
127
        areaMonitorId: '001',
128
        sceneId: '1',
129
        sortOrder: 0,
130
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
131
      },
132
      {
133
        title: '摄像头002',
134
        cameraId: '002',
135
        areaMonitorId: '002',
136
        sortOrder: 1,
137
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
138
      },
139
      {
140
        title: '摄像头003',
141
        cameraId: '003',
142
        areaMonitorId: '003',
143
        sortOrder: 2,
144
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
145
      },
146
      {
147
        title: '摄像头004',
148
        cameraId: '004',
149
        areaMonitorId: '004',
150
        sortOrder: 3,
151
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
152
      },
153
      {
154
        title: '摄像头005',
155
        cameraId: '005',
156
        areaMonitorId: '005',
157
        sortOrder: 4,
158
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
159
      },
160
      {
161
        title: '摄像头006',
162
        cameraId: '006',
163
        areaMonitorId: '006',
164
        sortOrder: 5,
165
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
166
      },
167
      {
168
        title: '摄像头007',
169
        cameraId: '007',
170
        areaMonitorId: '007',
171
        sortOrder: 6,
172
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
173
      }
174
      ]
188 175
    }
189 176
  },
190 177
  computed: {
@ -197,11 +184,8 @@ export default {
197 184
    viewDataList: function () {
198 185
      let tempDataList = []
199 186
      for (
200
        let i = 0;
201
        i < Math.ceil(this.areaMonitorList.length / this.currentType);
202
        i++
203
      ) {
204
        // this.currentType需要*this.currentType,测试减少一个组的数据
187
        let i = 0; i < Math.ceil(this.areaMonitorList.length / this.currentType); i++
188
      ) { // this.currentType需要*this.currentType,测试减少一个组的数据
205 189
        tempDataList[i] = this.areaMonitorList.slice(
206 190
          i * this.currentType,
207 191
          (i + 1) * this.currentType
@ -213,10 +197,6 @@ export default {
213 197
  mounted() {
214 198
    let dom = this.$refs.box
215 199
    this.itemWidth = dom.clientWidth / this.currentType - 25
216
    document.body.ondrop = function (event) {
217
      event.preventDefault()
218
      event.stopPropagation()
219
    }
220 200
  },
221 201
  methods: {
222 202
    handleSceneEdit(item) {
@ -251,8 +231,9 @@ export default {
251 231
      this.areaMonitorList.splice(index, 1)
252 232
    },
253 233
    datadragEnd(evt) {
254
      this.updateData()
255
      this.$forceUpdate()
234
      console.log(evt)
235
      console.log('拖动前的索引 :' + this.areaMonitorList[evt.oldIndex].title)
236
      console.log('拖动后的索引 :' + this.areaMonitorList[evt.newIndex].title)
256 237
    },
257 238
    handleCameraSubmit(data) {
258 239
      if (this.dialogData.areaMonitorId != null) {
@ -263,26 +244,21 @@ export default {
263 244
      } else {
264 245
        this.areaMonitorList.unshift(data)
265 246
      }
266
    },
267
    updateData() {
268
      this.areaMonitorList = this.viewDataList.reduce((prev, next) => {
269
        return prev.concat(next)
270
      })
271 247
    }
272 248
  }
273 249
}
274 250
</script>
275 251
276 252
<style lang="scss">
277
.ico {
278
  width: 14px;
279
  height: 14px;
280
  line-height: 14px !important;
281
  margin: 2px;
282
}
253
  .ico {
254
    width: 14px;
255
    height: 14px;
256
    line-height: 14px !important;
257
    margin: 2px;
258
  }
283 259
284
.table-pager {
285
  justify-content: flex-end;
286
  float: right;
287
}
260
  .table-pager {
261
    justify-content: flex-end;
262
    float: right;
263
  }
288 264
</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>

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

@ -0,0 +1,70 @@
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="name"
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
    }
35
  },
36
  watch: {},
37
  mounted() {},
38
  methods: {
39
    // 移入
40
    mouseOver() {
41
      this.text_tatus = 1
42
    },
43
    // 移出
44
    mouseLeave() {
45
      this.text_tatus = 0
46
    },
47
    // 修改
48
    iconChange() {
49
      this.text_tatus = 2
50
    },
51
    // 提交
52
    iconSubmit() {
53
      this.text_tatus = 1
54
      this.$emit('nameSubmit', this.name)
55
    }
56
  }
57
}
58
</script>
59
60
<style lang="scss">
61
.update-name {
62
  font-size: 14px;
63
  padding: 0 5px;
64
65
  .iconChange {
66
    height: 20px;
67
    float: right;
68
  }
69
}
70
</style>

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

@ -0,0 +1,199 @@
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.imgsrc})`" class="card-bg" />
5
      <div class="opt">
6
        <t-button shape="round" icon="arrow-expand-all-outline" style="margin: 0px 0px 0px 0px">移动</t-button>
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
          你确定删除该监控吗?
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="data.title" @nameSubmit="nameChange" />
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
  mounted() {
52
53
  },
54
  methods: {
55
    nameChange: function (name) {
56
      // 修改名称
57
      alert(name)
58
    },
59
    handleDelete() {
60
      this.showConfirm = true
61
    },
62
    handleConfirm() {},
63
    handleCancelDelete() {
64
      this.showConfirm = false
65
    },
66
    handleConfirmDelete() {
67
      // this.loadingDelete = true;
68
      // 把事件抛出去,保持控件的干净
69
      this.$emit('deleted', this.data)
70
      //   sysapi
71
      //     .deleteSchedule(this.data.scheduleId)
72
      //     .then(
73
      //       (resp) => {
74
      //         console.log(resp);
75
      //         this.$emit("deleted", this.data);
76
      //       },
77
      //       (err) => {
78
      //         console.log(err);
79
      //         this.$Message.danger("删除失败,请稍后再试!", 3);
80
      //       }
81
      //     )
82
      //     .finally(() => {
83
      //       this.loadingDelete = false;
84
      //       this.showConfirm = false;
85
      //     });
86
    },
87
    handleEdit() {
88
      this.$emit('edit', this.data)
89
    }
90
  }
91
}
92
</script>
93
94
<style lang="scss">
95
  @import "@/assets/styles/aid-theme/_variable.scss";
96
97
  .div-block {
98
    display: inline-block;
99
    .card-bg {
100
      background-size: cover;
101
      height: 100%;
102
      width: 100%;
103
    }
104
105
    .card-main {
106
      height: calc(100% - 37px);
107
      margin-bottom: 5px;
108
    }
109
110
    .card-title {
111
      padding: 5px;
112
      height: 32px;
113
      line-height: 22px;
114
    }
115
116
    .opt {
117
      position: absolute;
118
      left: 0;
119
      top: 0;
120
      width: 100%;
121
      height: 100%;
122
      opacity: 0;
123
      display: flex;
124
      justify-content: center;
125
      align-items: center;
126
127
      &::before {
128
        content: "";
129
        display: block;
130
        position: absolute;
131
        left: 0;
132
        top: 0;
133
        width: 100%;
134
        height: 100%;
135
        background-color: black;
136
        border-radius: 4px;
137
        opacity: 0.8;
138
      }
139
140
      &::after {
141
        content: "";
142
        display: none;
143
        position: absolute;
144
        left: 0;
145
        top: 0;
146
        width: 100%;
147
        height: 100%;
148
        background-color: black;
149
        border-radius: 4px;
150
        opacity: 0;
151
      }
152
153
      &>.btn {
154
        color: rgba(255, 255, 255, 0.65);
155
        border-color: rgba(0, 0, 0, 0);
156
        background-color: rgba(0, 0, 0, 0);
157
158
        &:hover {
159
          color: white;
160
          background-color: $brand-primary;
161
        }
162
      }
163
164
      &:hover {
165
        opacity: 1;
166
      }
167
    }
168
169
    &.active &__opt {
170
      opacity: 1;
171
    }
172
173
    &.lock &__opt::after {
174
      display: block;
175
    }
176
177
    .popover {
178
      width: 213px;
179
      background-color: white;
180
      color: rgba(0, 0, 0, 0.65);
181
      position: absolute;
182
      bottom: 12px;
183
      left: 12px;
184
      padding: 16px 20px;
185
      border-radius: 4px;
186
    }
187
188
    .btn-block {
189
      display: flex;
190
      flex-direction: row-reverse;
191
      margin-top: 14px;
192
    }
193
  }
194
195
  .div-footer {
196
    height: 32px;
197
    margin-top: 6px;
198
  }
199
</style>

+ 13 - 0
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' },