Browse Source

[FE]增加了Ai报警和进出口记录界面

liuwenxun 4 years ago
parent
commit
729f257dae

+ 174 - 0
security-protection-platform/.aid/mock/access.js

@ -0,0 +1,174 @@
1
const Mock = require('mockjs')
2

3

4
const { data } = Mock.mock({
5
  'data|10-80': [{
6
    'type|1': ['进入', '离开'],
7
    employee_name: '@cname',
8
    employee_number: '@integer(1,99999)',
9
    company: '1#风场',
10
    department: '设备管理处',
11
    job: '运维人员',
12
    similarity: '85.66%',
13
    time: '@date("yyyy-MM-dd HH:mm:ss")',
14
    location: 'xxx风场集控室',
15
    terminal_name: '1#人脸终端',
16
    terminal_number: 'ZD00001',
17
    arrest_main_url: 'http://img95.699pic.com/photo/50028/0321.jpg_wh300.jpg',
18
    arrest_part_url: 'http://img95.699pic.com/photo/50028/0321.jpg_wh300.jpg',
19
    face_url: 'http://img95.699pic.com/photo/50028/0321.jpg_wh300.jpg'
20

21
  }]
22
})
23

24

25

26
module.exports = [
27
  {
28
    url: /\/access\/getaccesslist/,
29
    method: 'get',
30
    type: 'func',
31
    response: option => {
32
      option.url = decodeURIComponent(option.url)
33
      const TypeName = ['进入', '离开']
34
      //获取page
35
      var page = getQuery(option.url, 'page')
36
      //获取limit
37
      var limit = getQuery(option.url, 'limit')
38
      //获取开始时间
39
      var starttime = +new Date(getQuery(option.url, 'starttime'))
40
      //获取结束时间
41
      var endtime = +new Date(getQuery(option.url, 'endtime'))
42
      //获取进出类型
43
      var typeid = getQuery(option.url, 'typeid')
44

45
      //获取员工姓名
46
      var username = getQuery(option.url, 'username')
47

48

49
      var start = (page - 1) * limit
50
      var end = page * limit
51

52

53
      var result = data
54
      if (typeid) {
55
        result = result.filter((item) => { return item.type == TypeName[parseInt(typeid)] })
56
      }
57
      if (starttime) {
58
        result = result.filter((item) => { return +new Date(item.time) >= starttime })
59
      }
60

61
      if (endtime) {
62
        result = result.filter((item) => { return +new Date(item.time) <= endtime })
63
      }
64

65
      if (username) {
66
        result = result.filter((item) => { return item.employee_name.indexOf(username) != -1 })
67
      }
68

69

70

71

72

73
      return {
74
        data: result.slice(start, end),
75
        total: result.length,
76
        "success": true,
77
      }
78
    }
79

80
  },
81
  {
82
    url: '/access/getaccesstype',
83
    method: 'get',
84
    type: 'func',
85
    response: () => {
86
      return Mock.mock({
87
        'data|2': [{
88
          'id|+1': 0,
89
          'name|+1': ['进入', '离开']
90
        }]
91
      })
92
    }
93
  }
94
]
95
// Mock.mock(/\/access\/getaccesslist/, 'get', (option) => {
96

97
//   option.url = decodeURIComponent(option.url)
98
//   const TypeName = ['进入', '离开']
99
//   //获取page
100
//   var page = getQuery(option.url, 'page')
101
//   //获取limit
102
//   var limit = getQuery(option.url, 'limit')
103
//   //获取开始时间
104
//   var starttime = +new Date(getQuery(option.url, 'starttime'))
105
//   //获取结束时间
106
//   var endtime = +new Date(getQuery(option.url, 'endtime'))
107
//   //获取进出类型
108
//   var typeid = getQuery(option.url, 'typeid')
109

110
//   //获取员工姓名
111
//   var username = getQuery(option.url, 'username')
112

113

114
//   var start = (page - 1) * limit
115
//   var end = page * limit
116

117

118
//   var result = data
119
//   if (typeid) {
120
//     result = result.filter((item) => { return item.type == TypeName[parseInt(typeid)] })
121
//   }
122
//   if (starttime) {
123
//     result = result.filter((item) => { return +new Date(item.time) >= starttime })
124
//   }
125

126
//   if (endtime) {
127
//     result = result.filter((item) => { return +new Date(item.time) <= endtime })
128
//   }
129

130
//   if (username) {
131
//     result = result.filter((item) => { return item.employee_name.indexOf(username) != -1 })
132
//   }
133

134

135

136

137

138
//   return {
139
//     data: result.slice(start, end),
140
//     total: result.length,
141
//     msg: '测试成功'
142
//   }
143

144

145

146

147
// })
148

149

150

151
// Mock.mock('/access/getaccesstype', 'get', () => {
152
//   return Mock.mock({
153
//     'data|2': [{
154
//       'id|+1': 0,
155
//       'name|+1': ['进入', '离开']
156
//     }]
157
//   })
158

159

160
// })
161
//获取url的参数值
162
const getQuery = (url, name) => {
163
  const index = url.indexOf('?')
164
  if (index !== -1) {
165
    const queryStrArr = url.substr(index + 1).split('&')
166
    for (var i = 0; i < queryStrArr.length; i++) {
167
      const itemArr = queryStrArr[i].split('=')
168
      if (itemArr[0] === name) {
169
        return itemArr[1]
170
      }
171
    }
172
  }
173
  return null
174
}

+ 236 - 0
security-protection-platform/.aid/mock/aialarm.js

@ -0,0 +1,236 @@
1
const Mock = require('mockjs')
2

3
const { data } = Mock.mock({
4
  'data|10-80': [
5
    {
6
      id: '@id',
7
      'state|1': ['处理中', '未确认', '已处理'],
8
      'type|1': ['身份异常', '穿戴异常', '潜在危险', '违规违章', '仪表异常'],
9
      'describe|1': ['报警描述', '未授权车辆', '电梯门未关闭',],
10
      equipment_name: '1#人脸终端',
11
      equipment_number: 's00001',
12
      equipment_location: '1#风场SVG室',
13
      alarm_time: '@date("yyyy-MM-dd HH:mm:ss")',
14
      Handler: '@cname',
15
      processing_time: '@date("yyyy-MM-dd HH:mm:ss")',
16
      picture_url: 'http://img95.699pic.com/photo/50028/0321.jpg_wh300.jpg',
17
      video_url: 'https://video.pearvideo.com/mp4/adshort/20201113/cont-1706887-15482034_adpkg-ad_hd.mp4'
18
    },
19

20
  ]
21
})
22

23
module.exports = [
24
  {
25
    url: /\/aialarm\/getaialarmlist/,
26
    method: 'get',
27
    type: 'func',
28
    response: (option) => {
29
      const TypeName = ['身份异常', '穿戴异常', '潜在危险', '违规违章', '仪表异常']
30
      //获取page
31
      var page = getQuery(option.url, 'page')
32
      //获取limit
33
      var limit = getQuery(option.url, 'limit')
34

35
      //获取开始时间
36
      var starttime = +new Date(getQuery(option.url, 'starttime'))
37
      //获取结束时间
38
      var endtime = +new Date(getQuery(option.url, 'endtime'))
39
      //获取报警类型
40
      var typeid = getQuery(option.url, 'typeid')
41

42
      var start = (page - 1) * limit
43
      var end = page * limit
44
      // console.log(option)
45

46
      var result = data
47

48
      if (typeid) {
49
        result = result.filter((item) => { return item.type == TypeName[parseInt(typeid)] })
50
      }
51

52
      if (starttime) {
53
        result = result.filter((item) => { return +new Date(item.time) >= starttime })
54
      }
55

56
      if (endtime) {
57
        result = result.filter((item) => { return +new Date(item.time) <= endtime })
58
      }
59

60

61
      return {
62
        data: result.slice(start, end),
63
        total: result.length,
64
        msg: '测试成功'
65
      }
66
    }
67
  },
68
  {
69
    url: '/aialarm/getaialarmtype',
70
    method: 'get',
71
    type: 'func',
72
    response: () => {
73
      return Mock.mock({
74
        'data|5': [{
75
          'id|+1': 0,
76
          'name|+1': ['身份异常', '穿戴异常', '潜在危险', '违规违章', '仪表异常']
77
        }]
78
      })
79
    }
80
  },
81
  {
82
    url: /\/aialarm\/dispose/,
83
    method: 'put',
84
    type: 'func',
85
    response: (req) => {
86
      var res = JSON.parse(req.body)
87
      // console.log(res)
88
      var id = res.id
89
      var msg = res.msg
90
      for (var i = 0; i < data.length; i++) {
91
        if (data[i].id == id) {
92
          judgeradio(data[i], msg)
93
          return {
94
            success: true,
95
            msg: '处理成功',
96
            data: data[i]
97
          }
98
        }
99
      }
100

101

102
    }
103
  }
104
]
105

106

107
// Mock.mock(/\/aialarm\/getaialarmlist/, 'get', (option) => {
108
//   const TypeName = ['身份异常', '穿戴异常', '潜在危险', '违规违章', '仪表异常']
109
//   //获取page
110
//   var page = getQuery(option.url, 'page')
111
//   //获取limit
112
//   var limit = getQuery(option.url, 'limit')
113

114
//   //获取开始时间
115
//   var starttime = +new Date(getQuery(option.url, 'starttime'))
116
//   //获取结束时间
117
//   var endtime = +new Date(getQuery(option.url, 'endtime'))
118
//   //获取报警类型
119
//   var typeid = getQuery(option.url, 'typeid')
120

121
//   var start = (page - 1) * limit
122
//   var end = page * limit
123
//   // console.log(option)
124

125
//   var result = data
126

127
//   if (typeid) {
128
//     result = result.filter((item) => { return item.type == TypeName[parseInt(typeid)] })
129
//   }
130

131
//   if (starttime) {
132
//     result = result.filter((item) => { return +new Date(item.time) >= starttime })
133
//   }
134

135
//   if (endtime) {
136
//     result = result.filter((item) => { return +new Date(item.time) <= endtime })
137
//   }
138

139

140
//   return {
141
//     data: result.slice(start, end),
142
//     total: result.length,
143
//     msg: '测试成功'
144
//   }
145
// })
146

147
// Mock.mock('/aialarm/getaialarmtype', 'get', () => {
148
//   return Mock.mock({
149
//     'data|5': [{
150
//       'id|+1': 0,
151
//       'name|+1': ['身份异常', '穿戴异常', '潜在危险', '违规违章', '仪表异常']
152
//     }]
153
//   })
154

155

156
// })
157

158
// Mock.mock(/\/aialarm\/dispose/, 'put', (req) => {
159
//   // console.log(typeof req.body)
160
//   var res = JSON.parse(req.body)
161
//   // console.log(res)
162
//   var id = res.id
163
//   var msg = res.msg
164

165

166

167
//   for (var i = 0; i < data.length; i++) {
168
//     if (data[i].id == id) {
169
//       judgeradio(data[i], msg)
170
//       return {
171
//         success: true,
172
//         msg: '处理成功',
173
//         data: data[i]
174
//       }
175
//     }
176
//   }
177

178

179

180

181

182

183
// })
184

185
/**
186
{
187
  state: '处理中',
188
  type: '身份异常',
189
  describe: '未授权车辆',
190
  equipment_name: '1#人脸终端',
191
  equipment_number: 's00001',
192
  equipment_location: '1#风场SVG室',
193
  alarm_time: '2020-09-21 16:07:09',
194
  Handler: '张三',
195
  processing_time: '2020-09-21 16:07:09',
196

197

198

199
},
200
*/
201

202
const judgeradio = (item, msg) => {
203
  //未确认的模态框选择了确认
204
  if (msg == '确认') {
205
    console.log(item)
206
    // this.data[this.currentdata.index].state = '处理中'
207
    item.state = '处理中'
208
    console.log(item)
209

210
  }
211
  //未确认的模态框选择了误判
212
  if (msg == '误判') {
213
    // this.$Message.info('未确认的模态框选择了误判')
214
    item.state = '处理中'
215
  }
216
  //处理中的模态框选择了关闭按钮
217
  if (msg == '关闭') {
218
    // this.data[this.currentdata.index].state = '已处理'
219
    item.state = '已处理'
220
  }
221
}
222

223
//获取url的参数值
224
const getQuery = (url, name) => {
225
  const index = url.indexOf('?')
226
  if (index !== -1) {
227
    const queryStrArr = url.substr(index + 1).split('&')
228
    for (var i = 0; i < queryStrArr.length; i++) {
229
      const itemArr = queryStrArr[i].split('=')
230
      if (itemArr[0] === name) {
231
        return itemArr[1]
232
      }
233
    }
234
  }
235
  return null
236
}

+ 16 - 0
security-protection-platform/src/api/access/index.js

@ -0,0 +1,16 @@
1
import http from '@/http'
2
const { $http } = http
3

4

5
const api = {
6
  getaccesslist (params) {
7
    return $http.get('/access/getaccesslist', params)
8
  },
9

10
  getaccesstype () {
11
    return $http.get('/access/getaccesstype')
12
  }
13

14
}
15

16
export default api

+ 21 - 0
security-protection-platform/src/api/aialarm/index.js

@ -0,0 +1,21 @@
1
import http from '@/http'
2
const { $http } = http
3

4

5
const api = {
6
  getaialarmlist (params) {
7
    return $http.get('/aialarm/getaialarmlist/', params)
8
  },
9
  getaialarmtype () {
10
    return $http.get('/aialarm/getaialarmtype')
11
  },
12
  dispose (params) {
13
    return $http.put('/aialarm/dispose/', params)
14
  }
15

16

17

18

19
}
20

21
export default api

+ 371 - 0
security-protection-platform/src/modules/access/index.vue

@ -0,0 +1,371 @@
1
<template>
2
  <div class="access">
3

4
    <div class="access_header">
5
      <div>
6
        <span class="title">开始时间 : </span>
7
        <t-date-picker :confirm="false" v-model="searchdata.starttime" placeholder="请选择开始时间" style="width:200px;height:32px"></t-date-picker>
8
      </div>
9

10
      <div>
11
        <span class="title">结束时间 : </span>
12
        <t-date-picker :confirm="false" v-model="searchdata.endtime" placeholder="请选择结束时间" style="width:200px;height:32px"></t-date-picker>
13
      </div>
14

15
      <div>
16
        <span class="title">进出类型 : </span>
17
        <t-select v-model="searchdata.typeid" style="width:200px;height:32px">
18
          <t-option v-for="item in accesstype" :value="item.id" :key="item.id">{{ item.name }}</t-option>
19

20
        </t-select>
21
      </div>
22

23
    </div>
24

25
    <div class="access_header">
26
      <div class="alarm_people">
27
        <span class="title">员工 : </span>
28
        <t-input v-model="searchdata.username" placeholder="员工姓名、编号关键字" style="width: 200px"></t-input>
29
      </div>
30

31
      <div>
32
        <t-button color="primary" @click="btnsearch">查询</t-button>
33
        <t-button @click="reset">重置</t-button>
34
      </div>
35
    </div>
36
    <!-- 导出excel -->
37
    <div>
38
      <t-button color="primary" icon="upload" style="width:128px;height:32px" class="upload">导出至Excel</t-button>
39
    </div>
40

41
    <t-table :data="data" line @selection-change="handleSelectionChange">
42
      <t-table-column type="selection" width="34px"></t-table-column>
43
      <t-table-column label="进出类型" width="80px">
44
        <template slot-scope="scope">
45
          <t-tag v-if="scope.row.type=== '离开'" state="info">{{ scope.row.type }}</t-tag>
46
          <t-tag v-if="scope.row.type=== '进入'" state="success">{{ scope.row.type }}</t-tag>
47
        </template>
48
      </t-table-column>
49
      <t-table-column label="姓名" prop="employee_name" width="66px">
50
      </t-table-column>
51
      <t-table-column label="员工编号" prop="employee_number" width="80px">
52
      </t-table-column>
53
      <t-table-column label="公司" prop="company" width="69px">
54
      </t-table-column>
55
      <t-table-column label="部门" prop="department" width="94px">
56
      </t-table-column>
57
      <t-table-column label="职务" prop="job" width="80px">
58
      </t-table-column>
59
      <t-table-column label="相似度" prop="similarity" width="75px">
60
      </t-table-column>
61
      <t-table-column label="进出时间" prop="time" width="169px">
62
      </t-table-column>
63
      <t-table-column label="位置" prop="location" width="122px">
64
      </t-table-column>
65
      <t-table-column label="终端名称" prop="terminal_name" width="97px">
66
      </t-table-column>
67
      <t-table-column label="终端编号" prop="terminal_number" width="72px">
68
      </t-table-column>
69
      <t-table-column label="操作" width="80px">
70
        <template slot-scope="scope">
71
          <a href="javascript:void(0)" size="sm" style="color:#0089D4" @click="handleClick(scope)">识别详情</a>
72
        </template>
73
      </t-table-column>
74

75
    </t-table>
76

77
    <!-- 分页 -->
78
    <t-pager :total="total" :current="page" show-elevator class="pager" @on-change="onChange"></t-pager>
79

80
    <!-- 模态框 -->
81
    <t-modal :visibled.sync="detail_modal" title="识别详情" width="840px" height="538px">
82

83
      <div style="text-align:center">
84
        <div class="detail_content">
85
          <div class="detail_item1">
86
            <div>抓拍图片</div>
87
            <div>
88
              <img :src="rowdata.arrest_main_url" alt="" srcset="" style="width:100%;height:100%">
89
            </div>
90
          </div>
91
          <div class="detail_item2">
92
            <div>识别结果</div>
93
            <div>
94
              <div>
95
                <img :src="rowdata.arrest_part_url" alt="" srcset="" style="width:120px;height:160px;border-radius: 5px; ">
96
                <div class="bottomimg">抓拍图片</div>
97
              </div>
98
              <div>
99
                <img src="http://img95.699pic.com/photo/50028/0321.jpg_wh300.jpg" alt="" srcset="">
100
              </div>
101
              <div>
102
                <img :src="rowdata.face_url" alt="" srcset="" style="width:100%;height:160px; border-radius: 5px;">
103
                <div class="bottomimg">人脸底库</div>
104
              </div>
105
            </div>
106
            <div class="describe">
107
              <div>
108
                <t-icon icon="user-outline"></t-icon> {{ rowdata.employee_name }}({{ rowdata.employee_number }})
109
              </div>
110
              <div>
111
                <t-icon icon="map-marker"></t-icon> {{ rowdata.location }}
112
              </div>
113
              <div>
114
                <t-icon icon="clock-outline"></t-icon> {{ rowdata.time }}
115
              </div>
116
              <div>
117
                <t-icon icon="team-outline"></t-icon> 相似度:{{ rowdata.similarity }}
118
              </div>
119
            </div>
120
          </div>
121
        </div>
122
      </div>
123
      <div slot="footer">
124
        <t-button type="danger" long @click="detail_modal = false">关闭</t-button>
125
      </div>
126
    </t-modal>
127

128
  </div>
129
</template>
130

131
<script>
132
import accessapi from '@/api/access'
133

134
export default {
135
  data () {
136
    return {
137
      // 进出类型
138
      accesstype: [],
139
      // 页码
140
      total: 0,
141
      // 选择的数据
142
      selectdata: [],
143
      // 模态框显示
144
      detail_modal: false,
145
      // 当前行数据
146
      rowdata: {},
147

148
      // 查询的参数
149
      searchdata: {
150
        typeid: '',
151
        username: '',
152
        starttime: '',
153
        endtime: ''
154
      },
155
      // 一页的数据
156
      data: [
157

158
      ],
159
      // 当前页
160
      page: 1,
161
      limit: 10
162

163
    }
164
  },
165

166
  mounted () {
167
    this.gettype()
168
    this.search()
169
  },
170
  methods: {
171
    // 表格中的选择数据
172
    handleSelectionChange (val) {
173
      this.selectdata = val
174
    },
175
    // 点击详情
176
    handleClick (scope) {
177
      this.detail_modal = true
178
      this.rowdata = scope.row
179
      console.log(this.rowdata)
180
    },
181
    // 分页
182
    onChange (val) {
183
      this.page = val
184
      this.search()
185
    },
186

187
    // 点击查询按钮
188
    btnsearch () {
189
      if (this.page === 1) {
190
        this.search()
191
      } else {
192
        this.page = 1
193
      }
194
    },
195
    // 获取进出类型
196
    gettype () {
197
      accessapi.getaccesstype().then((res) => {
198
        this.accesstype = res.data.data
199
        console.log(this.accesstype)
200
      })
201
    },
202
    // 查询数据
203
    async search () {
204
      // 检验数据
205
      var flag = this.startreend(this.searchdata.starttime, this.searchdata.endtime)
206
      if (flag) {
207
        // console.log(this.page)
208
        // console.log(this.searchdata)
209

210
        var params = this.searchdata
211
        params.page = this.page
212
        params.limit = this.limit
213
        console.log(params)
214
        var res = await accessapi.getaccesslist({ params: params })
215
        // console.log(res)
216
        if (res.status === 200) {
217
          console.log(res)
218
          this.data = res.data.data
219
          // console.log(this.data)
220
          this.total = Math.ceil(res.data.total / this.limit) * 5
221
        }
222
      } else {
223
        this.$Message.danger('开始时间不能在结束时间的后面')
224
      }
225
    },
226

227
    // 重置数据
228
    reset () {
229
      for (var index in this.searchdata) {
230
        this.searchdata[index] = ''
231
      }
232
      this.page = 1
233
      this.$Message.success('数据重置成功')
234
    },
235

236
    // 字符串更改为时间类型
237
    stringtodate (date) {
238
      date = date.substring(0, 19)
239
      date = date.replace(/-/g, '/')
240
      var timestamp = new Date(date).getTime()
241
      return timestamp
242
    },
243
    // 验证开始时间·和结束时间
244
    startreend (startdate, enddate) {
245
      startdate = this.stringtodate(startdate)
246
      enddate = this.stringtodate(enddate)
247
      if (startdate > enddate) {
248
        return false
249
      } else {
250
        return true
251
      }
252
    }
253
  }
254
}
255
</script>
256

257
<style lang='scss' scoped>
258
.access {
259
  font-size: 14px;
260
  padding: 6px 24px;
261
  height: 702px;
262
  .upload {
263
    font-size: 14px;
264
    line-height: 22px;
265
    margin: 29px 0 25px 0;
266
  }
267
  .table th,
268
  .table td {
269
    font-size: 14px;
270
    padding: 0 0 0 18px;
271
  }
272
  .access_header {
273
    display: flex;
274
    justify-content: space-between;
275
    margin-top: 24px;
276
    .title {
277
      display: inline-block;
278
      width: 70px;
279
      height: 20px;
280
      font-size: 14px;
281
      text-align: right;
282
      color: rgba($color: #000000, $alpha: 0.65);
283
    }
284
  }
285

286
  .pager {
287
    float: right;
288
    margin-top: 26px;
289
  }
290
}
291
.detail_content {
292
  width: 100%;
293
  height: 376px;
294
  display: flex;
295
  justify-content: space-between;
296

297
  .detail_item1 {
298
    width: 45%;
299
    text-align: left;
300
    > div:nth-child(1) {
301
      margin: 0 0 20px 0;
302
      color: rgba(0, 0, 0, 0.65);
303
      font-size: 14px;
304
    }
305
    > div:nth-child(2) {
306
      width: 100%;
307
      height: 240px;
308

309
      border-radius: 5px;
310
      overflow: hidden;
311
    }
312
  }
313

314
  .detail_item2 {
315
    width: 50%;
316
    text-align: left;
317
    > div:nth-child(1) {
318
      margin: 0 0 20px 0;
319
      color: rgba(0, 0, 0, 0.65);
320
      font-size: 14px;
321
    }
322
    > div:nth-child(2) {
323
      width: 100%;
324
      height: 190px;
325

326
      display: flex;
327
      justify-content: space-between;
328
      .bottomimg {
329
        margin-top: 12px;
330
        width: 100%;
331
        text-align: center;
332
        font-size: 12px;
333
        color: rgba(0, 0, 0, 0.65);
334
      }
335

336
      > div:nth-child(1) {
337
        width: 120px;
338
        height: 100%;
339
      }
340
      > div:nth-child(2) {
341
        width: 117.76px;
342
        height: 160px;
343

344
        line-height: 160px;
345
        img {
346
          width: 100%;
347
          height: 84.32px;
348
        }
349
      }
350
      > div:nth-child(3) {
351
        height: 100%;
352
        width: 120px;
353
      }
354
    }
355
    .describe {
356
      margin-top: 20px;
357
      width: 100%;
358
      height: 148px;
359
      display: flex;
360
      flex-wrap: wrap;
361
      align-items: center;
362

363
      > div {
364
        width: 100%;
365
        height: 22px;
366
        font-size: 14px;
367
      }
368
    }
369
  }
370
}
371
</style>

+ 481 - 0
security-protection-platform/src/modules/aialarm/index.vue

@ -0,0 +1,481 @@
1
<template>
2
  <div class="ai_alarm">
3
    <!-- 顶部的查询组件 -->
4

5
    <div class="alarm_header">
6
      <div>
7
        <span class="title">报警类型 : </span>
8
        <t-select v-model="searchdata.typeid" style="width:200px;height:32px">
9
          <t-option v-for="(item,index) in alarmtypelist" :key="index" :value="item.id">{{ item.name }}</t-option>
10
        </t-select>
11
      </div>
12

13
      <div>
14
        <span class="title">开始时间 : </span>
15
        <t-date-picker :confirm="false" v-model="searchdata.starttime" placeholder="请选择开始时间" style="width:200px;height:32px"></t-date-picker>
16
      </div>
17

18
      <div>
19
        <span class="title">结束时间 : </span>
20
        <t-date-picker :confirm="false" v-model="searchdata.endtime" placeholder="请选择结束时间" style="width:200px;height:32px"></t-date-picker>
21
      </div>
22

23
    </div>
24

25
    <div class="alarm_header">
26
      <div class="alarm_people">
27
        <span class="title">报警人 : </span>
28
        <t-select v-model="searchdata.Police" style="width:200px;height:32px">
29
          <t-option value="你好">选项1</t-option>
30
          <t-option value="世界">选项2</t-option>
31
        </t-select>
32
      </div>
33

34
      <div>
35
        <t-button color="primary" @click="btnsearch">查询</t-button>
36
        <t-button @click="reset">重置</t-button>
37
      </div>
38
    </div>
39

40
    <!-- 导出excel组件 -->
41
    <div>
42
      <t-button color="primary" icon="upload" style="width:128px;height:32px" class="upload">导出至Excel</t-button>
43
    </div>
44

45
    <!-- 表格 -->
46
    <t-table :data="data" line @selection-change="handleSelectionChange">
47
      <t-table-column type="selection" width="50"></t-table-column>
48
      <t-table-column label="状态" width="110">
49
        <template slot-scope="scope">
50

51
          <t-tag v-if="scope.row.state=== '处理中'" state="info">{{ scope.row.state }}</t-tag>
52
          <t-tag v-if="scope.row.state=== '未确认'" state="warning">{{ scope.row.state }}</t-tag>
53
          <t-tag v-if="scope.row.state=== '已处理'" state="success">{{ scope.row.state }}</t-tag>
54
        </template>
55
      </t-table-column>
56
      <t-table-column label="报警类型" prop="type">
57
      </t-table-column>
58
      <t-table-column label="报警描述" prop="describe" width="110">
59
      </t-table-column>
60
      <t-table-column label="设备名称" prop="equipment_name" width="110">
61
      </t-table-column>
62
      <t-table-column label="设备编号" prop="equipment_number" width="90">
63
      </t-table-column>
64
      <t-table-column label="设备位置" prop="equipment_location" width="120">
65
      </t-table-column>
66
      <t-table-column label="报警时间" prop="alarm_time" width="148px">
67
      </t-table-column>
68
      <t-table-column label="处理人" prop="Handler" width="70">
69
      </t-table-column>
70
      <t-table-column label="处理时间" prop="processing_time" width="148px">
71
      </t-table-column>
72
      <t-table-column label="操作">
73
        <template slot-scope="scope">
74

75
          <a href="javascript:void(0)" size="sm" style="color:#0089D4" @click="handleClick(scope,0)">详情</a>
76
          <a v-if="scope.row.state=='处理中'" style="color:#0089D4" @click="handleClick(scope,1)">关闭</a>
77
          <a v-if="scope.row.state=='未确认'" style="color:#0089D4" @click="handleClick(scope,1)">处理</a>
78
        </template>
79
      </t-table-column>
80
    </t-table>
81

82
    <!-- 分页 -->
83
    <t-pager :total="total" :current="page" show-elevator class="pager" @on-change="onChange"></t-pager>
84

85
    <!-- 模态框-->
86
    <t-modal :visibled.sync="details_modal" :title="clickdetail==0?'报警详情':'报警处理'" width="732px">
87

88
      <div style="text-align:center">
89
        <div class="details_item1">
90
          <div class="detail">
91
            <label class="detail_title">状态:</label>
92
            <div class="detail_content">
93
              <t-tag v-if="currentdata.data.state==='未确认'" state="warning">{{ currentdata.data.state }}</t-tag>
94
              <t-tag v-if="currentdata.data.state==='已处理'" state="success">{{ currentdata.data.state }}</t-tag>
95
              <t-tag v-if="currentdata.data.state==='处理中'" state="info">{{ currentdata.data.state }}</t-tag>
96
            </div>
97

98
          </div>
99
          <div class="detail">
100
            <label class="detail_title">报警类型:</label>
101
            <div class="detail_content">{{ currentdata.data.type }}</div>
102
          </div>
103
          <div class="detail">
104
            <label class="detail_title">报警描述:</label>
105
            <div class="detail_content">{{ currentdata.data.describe }}</div>
106
          </div>
107
          <div class="detail">
108
            <label class="detail_title">报警时间:</label>
109
            <div class="detail_content">{{ currentdata.data.alarm_time }}</div>
110
          </div>
111

112
          <div class="detail">
113
            <label class="detail_title">设备编号:</label>
114
            <div class="detail_content">{{ currentdata.data.equipment_name }}</div>
115
          </div>
116
          <div class="detail">
117
            <label class="detail_title">设备位置:</label>
118
            <div class="detail_content">{{ currentdata.data.equipment_location }}</div>
119
          </div>
120

121
          <div class="detail">
122
            <label class="detail_title">处理人:</label>
123
            <div class="detail_content">{{ currentdata.data.Handler }}</div>
124
          </div>
125

126
          <div class="detail">
127
            <label class="detail_title">处理时间:</label>
128
            <div>{{ currentdata.data.processing_time }}</div>
129
          </div>
130
        </div>
131

132
        <div class="details_item2">
133
          <div>
134
            <div>识别图片</div>
135
            <div><img :src="currentdata.data.picture_url" alt="" srcset="" style="width:100%;height:100%"></div>
136
          </div>
137
          <div>
138
            <div>识别视频</div>
139
            <div>
140
              <video :src="currentdata.data.video_url" class="video" controls></video>
141
            </div>
142
          </div>
143
        </div>
144
        <div v-if="clickdetail==1">
145
          <div v-if="currentdata.data.state!='已处理'" class="radio">
146
            <div>报警处理 : </div>
147
            <div v-if="currentdata.data.state=='未确认'">
148
              <t-radio-group v-model="msg">
149
                <t-radio label="确认">
150

151
                  <span>确认</span>
152
                </t-radio>
153
                <t-radio label="误判">
154

155
                  <span>误判</span>
156
                </t-radio>
157

158
              </t-radio-group>
159
            </div>
160

161
            <div v-if="currentdata.data.state=='处理中'">
162
              <t-radio-group v-model="msg">
163
                <t-radio label="关闭">关闭</t-radio>
164
              </t-radio-group>
165

166
            </div>
167
          </div>
168
        </div>
169
      </div>
170
      <div slot="footer">
171
        <div v-if="clickdetail==1">
172

173
          <div>
174
            <t-button @click="details_modal=false">取消</t-button>
175
            <t-button color="primary" @click="confimclick">确认</t-button>
176

177
          </div>
178
        </div>
179
        <div v-else>
180
          <t-button type="danger" long @click="details_modal=false">关闭</t-button>
181
        </div>
182
      </div>
183
    </t-modal>
184

185
  </div>
186
</template>
187

188
<script>
189

190
import aialarmapi from '@/api/aialarm'
191
export default {
192

193
  data () {
194
    return {
195
      searchdata: {
196
        typeid: '', // 报警类型
197
        Police: '', // 报警人
198
        starttime: '', // 开始时间
199
        endtime: '' // 结束时间
200
      },
201
      // 报警类型
202
      alarmtypelist: [],
203
      // 报警人
204
      // 模态框中的单选按钮
205
      msg: '',
206
      // 模态框
207
      details_modal: false,
208
      // 当前行的数据
209
      currentdata: {
210
        index: '',
211
        data: {}
212
      },
213
      // 选择的数据
214
      selectdata: [],
215
      // 判断是详情还是处理
216
      clickdetail: 0,
217
      // 一页的数据
218
      data: [
219
        // {
220
        //   state: '处理中',
221
        //   type: '身份异常',
222
        //   describe: '未授权车辆',
223
        //   equipment_name: '1#人脸终端',
224
        //   equipment_number: 's00001',
225
        //   equipment_location: '1#风场SVG室',
226
        //   alarm_time: '2020-09-21 16:07:09',
227
        //   Handler: '张三',
228
        //   processing_time: '2020-09-21 16:07:09',
229

230
        // },
231

232
      ],
233
      // 页数
234
      page: 1,
235
      limit: 10,
236

237
      total: 0
238

239
    }
240
  },
241
  mounted () {
242
    this.gettype()
243
    this.search()
244
  },
245
  methods: {
246
    // 选择行
247
    handleSelectionChange (val) {
248
      // console.log(val)
249
      this.selectdata = val
250
    },
251

252
    // 点击详情
253
    handleClick (scope, val) {
254
      this.clickdetail = val
255
      // 去除模态框中的单选项
256

257
      this.msg = ''
258

259
      this.details_modal = true // 打开模态框
260
      this.currentdata.data = scope.row // 获取当前行的数据
261
      this.currentdata.index = scope.$index // 获取当前行的索引
262
      console.log(this.currentdata.data)
263
    },
264

265
    // 未确认状态的模态框的确认按钮 || 处理中状态的模态框的确认按钮
266
    confimclick () {
267
      // 获取单选框中的值
268
      // console.log(this.msg)
269
      // 判断是否选择了单选框
270
      if (this.msg) {
271
        // 向后端发送数据
272
        this.alarmdispose(this.currentdata.data.id, this.msg)
273
        // 关闭模态框
274
        this.details_modal = false
275
      } else {
276
        this.$Message.warning('请选择按钮')
277
      }
278
    },
279

280
    async alarmdispose (id, msg) {
281
      var res = await aialarmapi.dispose({ 'id': id, 'msg': msg })
282
      console.log(res)
283
      if (res.status === 200) {
284
        // console.log(res.data.data)
285
        this.judgeradio(msg)
286
      } else {
287
        this.$Message.danger('处理失败')
288
      }
289
    },
290

291
    // 判断选择了哪个单选按钮
292
    judgeradio (msg) {
293
      // 未确认的模态框选择了确认
294
      if (msg === '确认') {
295
        this.data[this.currentdata.index].state = '处理中'
296
      }
297
      // 未确认的模态框选择了误判
298
      if (msg === '误判') {
299
        this.$Message.info('未确认的模态框选择了误判')
300
      }
301
      // 处理中的模态框选择了关闭按钮
302
      if (msg === '关闭') {
303
        this.data[this.currentdata.index].state = '已处理'
304
      }
305
    },
306
    onChange (val) {
307
      // console.log(val)
308
      this.page = val
309
      this.search()
310
    },
311

312
    // 点击查询按钮
313
    btnsearch () {
314
      if (this.page === 1) {
315
        this.search()
316
      } else {
317
        this.page = 1
318
      }
319
    },
320

321
    // 获取报警类型 以及报警人
322
    async gettype () {
323
      var res = await aialarmapi.getaialarmtype()
324
      // console.log(res)
325
      if (res.status === 200) {
326
        this.alarmtypelist = res.data.data
327
        console.log(this.alarmtypelist)
328
      }
329
    },
330

331
    // 查询数据时
332
    async search () {
333
      var flag = this.startreend(this.searchdata.starttime, this.searchdata.endtime)
334
      console.log(flag)
335
      if (flag) {
336
        // 查询
337
        var params = this.searchdata
338
        params.page = this.page
339
        params.limit = this.limit
340

341
        var res = await aialarmapi.getaialarmlist({
342
          params: params
343
        })
344

345
        // console.log(res)
346
        if (res.status === 200) {
347
          this.data = res.data.data
348
          this.total = Math.ceil(res.data.total / this.limit) * 5
349
        } else {
350
          this.$Message.danger('数据获取失败')
351
        }
352
      } else {
353
        this.$Message.danger('开始时间不能在结束时间的后面')
354
      }
355
    },
356

357
    // 重置
358
    reset () {
359
      for (var index in this.searchdata) {
360
        this.searchdata[index] = ''
361
      }
362
      // console.log(this.searchdata)
363
      this.page = 1
364
      this.$Message.success('数据重置成功')
365
    },
366
    // 字符串更改为时间类型
367
    stringtodate (date) {
368
      date = date.substring(0, 19)
369
      date = date.replace(/-/g, '/')
370
      var timestamp = new Date(date).getTime()
371
      return timestamp
372
    },
373
    // 验证开始时间·和结束时间
374
    startreend (startdate, enddate) {
375
      startdate = this.stringtodate(startdate)
376
      enddate = this.stringtodate(enddate)
377
      if (startdate > enddate) {
378
        return false
379
      } else {
380
        return true
381
      }
382
    }
383

384
  }
385
}
386

387
</script>
388

389
<style lang='scss' >
390
.ai_alarm {
391
  font-size: 14px;
392
  padding: 6px 24px;
393
  .upload {
394
    font-size: 14px;
395
    line-height: 22px;
396
    margin: 29px 0 25px 0;
397
  }
398
  .table th,
399
  .table td {
400
    padding: 0 0 0 21px;
401
  }
402
  .alarm_header {
403
    display: flex;
404
    justify-content: space-between;
405
    margin-top: 24px;
406
    .title {
407
      display: inline-block;
408
      width: 70px;
409
      height: 20px;
410
      font-size: 14px;
411
      text-align: right;
412
      color: rgba($color: #000000, $alpha: 0.65);
413
    }
414
  }
415
}
416
.pager {
417
  float: right;
418
  margin-top: 26px;
419
}
420
.details_item1 {
421
  display: flex;
422
  justify-content: space-between;
423
  flex-wrap: wrap;
424
  height: 192px;
425
  align-items: center;
426
  border-radius: 4px;
427
  background-color: rgba(245, 245, 245, 1);
428
  padding: 0 16px;
429
  color: rgba(0, 0, 0, 0.45);
430
  font-size: 14px;
431
  .detail {
432
    width: 49%;
433
    display: flex;
434
    .detail_title {
435
      display: block;
436
      width: 70px;
437
      height: 22px;
438
      text-align: right;
439
    }
440
    .detail_content {
441
      flex: 1;
442
      text-align: left;
443
    }
444
  }
445
}
446

447
.details_item2 {
448
  display: flex;
449
  justify-content: space-between;
450
  margin-top: 24px;
451
  > div {
452
    width: 49%;
453
    > div:nth-child(1) {
454
      text-align: left;
455
      font-size: 14px;
456
      color: rgba(0, 0, 0, 0.65);
457
      margin-bottom: 8px;
458
    }
459
    > div:nth-child(2) {
460
      height: 250px;
461
      // border: 1px solid black;
462
      border-radius: 5px;
463
      overflow: hidden;
464
    }
465
  }
466
}
467
.radio {
468
  margin-top: 19px;
469
  float: left;
470
  display: flex;
471
  align-items: center;
472
  > div:nth-child(1) {
473
    margin-right: 5px;
474
  }
475
}
476
.video {
477
  width: 100%;
478
  height: 100%;
479
  object-fit: fill;
480
}
481
</style>

+ 26 - 0
security-protection-platform/src/routes.js

@ -66,6 +66,19 @@ export const constantRoutes = [
66 66
        meta: { title: '假勤管理', icon: 'home' }
67 67
      }
68 68
    ]
69
  },
70
  {
71
    path: '/alarm',
72
    component: Layout,
73
    meta: { icon: 'bell' },
74
    children: [
75
      {
76
        name: 'ai_alarm',
77
        path: '',
78
        component: () => import(/* webpackChunkName: "sys_attendance" */ './modules/aialarm/index.vue'),
79
        meta: { title: 'AI报警', icon: 'bell' }
80
      }
81
    ]
69 82
  }, {
70 83
    path: '/system',
71 84
    component: Layout,
@ -92,6 +105,19 @@ export const constantRoutes = [
92 105
        meta: { title: '监控布局' }
93 106
      }
94 107
    ]
108
  },
109
  {
110
    path: '/access',
111
    component: Layout,
112
    meta: { icon: 'home' },
113
    children: [
114
      {
115
        name: 'access',
116
        path: '',
117
        component: () => import(/* webpackChunkName: "sys_attendance" */ './modules/access/index.vue'),
118
        meta: { title: '进出记录', icon: 'home' }
119
      }
120
    ]
95 121
  }, {
96 122
    path: '*',
97 123
    hidden: true,