licailing 4 лет назад
Родитель
Сommit
fc7dce70f8

+ 18 - 12
src/main/java/com/izouma/wenlvju/domain/regulation/Complain.java

@@ -10,8 +10,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import javax.persistence.Column;
-import javax.persistence.Convert;
+import javax.persistence.*;
 import java.time.LocalDateTime;
 import java.util.List;
 
@@ -20,6 +19,7 @@ import java.util.List;
 @AllArgsConstructor
 @NoArgsConstructor
 @Builder
+@Entity
 @ApiModel(value = "咨询投诉")
 public class Complain extends BaseEntity {
     @ApiModelProperty(value = "记录人")
@@ -31,6 +31,9 @@ public class Complain extends BaseEntity {
     @ApiModelProperty(value = "来电时间")
     private LocalDateTime complainAt;
 
+    @ApiModelProperty(value = "服务对象")
+    private String name;
+
     @ApiModelProperty(value = "性别")
     private String sex;
 
@@ -50,35 +53,38 @@ public class Complain extends BaseEntity {
     /**
      * 考级机构
      * 承办单位
+     * 考点
      */
+    @Enumerated(EnumType.STRING)
     @ApiModelProperty(value = "单位类型")
     private UnitType unitType;
 
     @ApiModelProperty(value = "单位名称")
     private String unitName;
 
-//    @Convert(converter = StringArrayConverter.class)
-//    @Column(columnDefinition = "TEXT")
-//    @ApiModelProperty(value = "图片")
-//    private List<String> img;
+    @Convert(converter = StringArrayConverter.class)
+    @Column(columnDefinition = "TEXT")
+    @ApiModelProperty(value = "图片")
+    private List<String> file;
 
-    @ApiModelProperty(value = "经办人")
-    private Long reviewUserId;
+//    @ApiModelProperty(value = "经办人")
+//    private Long reviewUserId;
 
     @Column(columnDefinition = "TEXT")
     @ApiModelProperty(value = "办理情况")
     private String processing;
 
     @ApiModelProperty(value = "情况属实")
-    private Boolean real;
+    private Boolean situationIsReal;
 
+    @Convert(converter = StringArrayConverter.class)
     @Column(columnDefinition = "TEXT")
-    @ApiModelProperty(value = "审查图片")
-    private List<String> reviewImg;
+    @ApiModelProperty(value = "审查附件")
+    private List<String> reviewFile;
 
     @ApiModelProperty(value = "审查时间")
     private LocalDateTime reviewAt;
 
     @ApiModelProperty(value = "办结")
-    private boolean completion;
+    private boolean finish;
 }

+ 22 - 3
src/main/java/com/izouma/wenlvju/domain/regulation/EquipmentLog.java

@@ -1,16 +1,35 @@
 package com.izouma.wenlvju.domain.regulation;
 
+import com.alibaba.excel.annotation.ExcelIgnore;
 import com.izouma.wenlvju.domain.BaseEntity;
 import io.swagger.annotations.ApiModel;
 import lombok.Data;
+import org.hibernate.annotations.Where;
+import org.springframework.data.annotation.CreatedDate;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import java.time.LocalDateTime;
 
 @Data
 @ApiModel(value = "监控日志")
-public class EquipmentLog extends BaseEntity {
-    private String roomId;
+@Where(clause = "del = 0")
+public class EquipmentLog {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @ExcelIgnore
+    private Long id;
+
+    @CreatedDate
+    private LocalDateTime createdAt;
+
+    private String examRoomId;
 
-    private String status;
+    private String deviceSerial;
 
     private String organizationId;
 
+    private boolean del;
 }

+ 1 - 1
src/main/java/com/izouma/wenlvju/domain/regulation/RecordCheck.java

@@ -29,7 +29,7 @@ public class RecordCheck extends BaseEntity {
 
     @Convert(converter = StringArrayConverter.class)
     @Column(columnDefinition = "TEXT")
-    private List<String> files;
+    private List<String> file;
 
     private Long userId;
 }

+ 5 - 1
src/main/java/com/izouma/wenlvju/enums/UnitType.java

@@ -8,5 +8,9 @@ public enum UnitType {
     /*
     考级机构
      */
-    GRADING_ORGANIZATION
+    GRADING_ORGANIZATION,
+    /*
+    考点
+     */
+    EXAMINATION
 }

+ 16 - 0
src/main/java/com/izouma/wenlvju/repo/regulation/ComplainRepo.java

@@ -0,0 +1,16 @@
+package com.izouma.wenlvju.repo.regulation;
+
+import com.izouma.wenlvju.domain.regulation.Complain;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+
+public interface ComplainRepo extends JpaRepository<Complain, Long>, JpaSpecificationExecutor<Complain> {
+    @Query("update Complain t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+}

+ 20 - 0
src/main/java/com/izouma/wenlvju/service/regulation/ComplainService.java

@@ -0,0 +1,20 @@
+package com.izouma.wenlvju.service.regulation;
+
+import com.izouma.wenlvju.domain.regulation.Complain;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.repo.regulation.ComplainRepo;
+import com.izouma.wenlvju.utils.JpaUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class ComplainService {
+
+    private ComplainRepo complainRepo;
+
+    public Page<Complain> all(PageQuery pageQuery) {
+        return complainRepo.findAll(JpaUtils.toSpecification(pageQuery, Complain.class), JpaUtils.toPageRequest(pageQuery));
+    }
+}

+ 5 - 1
src/main/java/com/izouma/wenlvju/web/ExamRoomController.java

@@ -1,6 +1,7 @@
 package com.izouma.wenlvju.web;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.StrUtil;
 import com.izouma.wenlvju.domain.ExamRoom;
 import com.izouma.wenlvju.dto.ExamRoomDTO;
@@ -86,7 +87,10 @@ public class ExamRoomController extends BaseController {
 
     @PostMapping("/byToday")
     @ApiOperation("今日所有备案的考场信息")
-    public List<ExamRoomDTO> byToday(@RequestBody PageQuery pageQuery, Integer status) {
+    public List<ExamRoomDTO> byToday(@RequestBody PageQuery pageQuery) {
+        Map<String, Object> query = pageQuery.getQuery();
+        Integer status = Convert.convert(Integer.class, query.get("status"));
+        query.remove("status");
         return examRoomService.byToday(pageQuery, status);
     }
 }

+ 0 - 2
src/main/java/com/izouma/wenlvju/web/RecordController.java

@@ -6,7 +6,6 @@ import com.izouma.wenlvju.dto.PageQuery;
 import com.izouma.wenlvju.dto.RecordDTO;
 import com.izouma.wenlvju.exception.BusinessException;
 import com.izouma.wenlvju.repo.RecordRepo;
-import com.izouma.wenlvju.repo.UserRepo;
 import com.izouma.wenlvju.service.RecordService;
 import com.izouma.wenlvju.utils.ObjUtils;
 import com.izouma.wenlvju.utils.excel.ExcelUtils;
@@ -30,7 +29,6 @@ import java.util.List;
 public class RecordController extends BaseController {
     private RecordService recordService;
     private RecordRepo    recordRepo;
-    private UserRepo      userRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")

+ 63 - 0
src/main/java/com/izouma/wenlvju/web/regulation/ComplainController.java

@@ -0,0 +1,63 @@
+package com.izouma.wenlvju.web.regulation;
+
+import com.izouma.wenlvju.web.BaseController;
+import com.izouma.wenlvju.domain.regulation.Complain;
+import com.izouma.wenlvju.service.regulation.ComplainService;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.exception.BusinessException;
+import com.izouma.wenlvju.repo.regulation.ComplainRepo;
+import com.izouma.wenlvju.utils.ObjUtils;
+import com.izouma.wenlvju.utils.excel.ExcelUtils;
+
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/complain")
+@AllArgsConstructor
+public class ComplainController extends BaseController {
+    private ComplainService complainService;
+    private ComplainRepo complainRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public Complain save(@RequestBody Complain record) {
+        if (record.getId() != null) {
+            Complain orig = complainRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return complainRepo.save(orig);
+        }
+        return complainRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<Complain> all(@RequestBody PageQuery pageQuery) {
+        return complainService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public Complain get(@PathVariable Long id) {
+        return complainRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        complainRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<Complain> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/main/resources/genjson/Complain.json


+ 126 - 0
src/main/vue/src/components/VideoGridOrganization.vue

@@ -0,0 +1,126 @@
+<template>
+    <el-card>
+        <div slot="header">
+            <span class="span-size">考场名称:{{ roomname }}<br /></span>
+        </div>
+        <div class="video" :id="name" style="width:100%;height:320px">
+            <!-- <div class="bottom"></div> -->
+
+            <video
+                v-if="videoUrl"
+                :src="videoUrl"
+                controlsList="nodownload noremote footbar"
+                controls="controls"
+                style="width:100%;height:320px"
+                oncontextmenu="return false;"
+                ref="video"
+                autoplay
+                loop
+                muted
+            >
+                您的浏览器不支持 video 标签。
+            </video>
+        </div>
+    </el-card>
+</template>
+
+<script>
+import EZUIKit from 'ezuikit-js';
+
+export default {
+    name: 'VideoGrid',
+    props: ['token', 'device', 'name', 'roomname'],
+    data() {
+        return {
+            player: null,
+            list: [
+                'https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/video/2021-03-19-14-47-24CxnKwMnv.mp4',
+                'https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/video/2021-03-19-15-30-43nvcwuumz.mp4',
+                'https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/video/2021-03-19-14-33-40dhjGRCso.mp4',
+                'https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/video/2021-03-19-14-47-40sDbsFufH.mp4'
+            ],
+            videoUrl: ''
+        };
+    },
+    methods: {
+        init(form = {}) {
+            let token = form.accessToken || this.token;
+            let device = form.deviceSerial || this.device;
+
+            this.player = new EZUIKit.EZUIKitPlayer({
+                autoplay: true,
+                id: this.name || 'video-container',
+                accessToken: token,
+                url: 'ezopen://open.ys7.com/' + device + '/1.live',
+                template: 'security', // simple - 极简版;standard-标准版;security - 安防版(预览回放);voice-语音版;
+                // 视频上方头部控件
+                // header: ['capturePicture', 'save', 'zoom'], // 如果templete参数不为simple,该字段将被覆盖
+                plugin: ['talk'] // 加载插件,talk-对讲
+                // 视频下方底部控件
+                // footer: ['talk', 'broadcast', 'hd', 'fullScreen'] // 如果template参数不为simple,该字段将被覆盖
+                // audio: 0, // 是否默认开启声音 0 - 关闭 1 - 开启
+                // openSoundCallBack: data => console.log('开启声音回调', data),
+                // closeSoundCallBack: data => console.log('关闭声音回调', data),
+                // startSaveCallBack: data => console.log('开始录像回调', data),
+                // stopSaveCallBack: data => console.log('录像回调', data),
+                // capturePictureCallBack: data => console.log('截图成功回调', data),
+                // fullScreenCallBack: data => console.log('全屏回调', data),
+                // getOSDTimeCallBack: data => console.log('获取OSDTime回调', data),
+            });
+            console.group('mounted 组件挂载完毕状态===============》');
+        },
+        showFullScreen() {
+            if (!this.player) {
+                this.init();
+                return;
+            }
+            this.player.fullScreen();
+        },
+        initVideo(index = 0) {
+            this.videoUrl = this.list[index % this.list.length];
+            // this.$nextTick(() => {
+            //     setTimeout(() => {
+            //         this.$refs.video.play();
+            //     }, 500);
+            // });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.el-card {
+    width: 30%;
+    margin-right: 3%;
+    margin-bottom: 20px;
+}
+
+.video {
+    position: relative;
+    cursor: pointer;
+    /deep/ iframe {
+        width: 100%;
+        height: 100%;
+    }
+    video {
+        background-color: #000;
+        height: 100%;
+    }
+}
+
+.bottom {
+    background-color: #fff;
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    height: 30px;
+    z-index: 3;
+}
+
+.span-size {
+    font-size: 14px;
+    color: #565b66;
+    line-height: 15px;
+}
+</style>

+ 29 - 2
src/main/vue/src/router.js

@@ -214,8 +214,19 @@ const router = new Router({
                 },
                 {
                     path: '/videoList',
-                    name: 'videoList',
-                    component: () => import(/* webpackChunkName: "recordList" */ '@/views/record/VideoList.vue'),
+                    name: 'VideoList',
+                    component: () => import(/* webpackChunkName: "videoList" */ '@/views/record/VideoList.vue'),
+                    meta: {
+                        title: '视频监控'
+                    }
+                },
+                {
+                    path: '/videoOrganizationList',
+                    name: 'VideoOrganizationList',
+                    component: () =>
+                        import(
+                            /* webpackChunkName: "videoOrganizationList" */ '@/views/record/VideoOrganizationList.vue'
+                        ),
                     meta: {
                         title: '视频监控'
                     }
@@ -537,6 +548,22 @@ const router = new Router({
                     meta: {
                         title: '备案管理'
                     }
+                },
+                {
+                    path: '/complainEdit',
+                    name: 'ComplainEdit',
+                    component: () => import(/* webpackChunkName: "complainEdit" */ '@/views/ComplainEdit.vue'),
+                    meta: {
+                        title: '咨询投诉编辑'
+                    }
+                },
+                {
+                    path: '/complainList',
+                    name: 'ComplainList',
+                    component: () => import(/* webpackChunkName: "complainList" */ '@/views/ComplainList.vue'),
+                    meta: {
+                        title: '咨询投诉'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]

+ 181 - 0
src/main/vue/src/views/ComplainEdit.vue

@@ -0,0 +1,181 @@
+<template>
+    <div class="edit-view">
+        <el-form
+            :model="formData"
+            :rules="rules"
+            ref="form"
+            label-width="100px"
+            label-position="right"
+            size="small"
+            style="max-width: 700px;"
+        >
+            <el-divider direction="horizontal" content-position="left">诉求人基本信息</el-divider>
+            <el-form-item prop="source" label="来源渠道">
+                <el-input v-model="formData.source"></el-input>
+            </el-form-item>
+            <el-form-item prop="complainAt" label="来电时间">
+                <el-date-picker
+                    v-model="formData.complainAt"
+                    type="datetime"
+                    value-format="yyyy-MM-dd HH:mm:ss"
+                    placeholder="选择日期时间"
+                >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item prop="name" label="服务对象">
+                <el-input v-model="formData.name"></el-input>
+            </el-form-item>
+            <el-form-item prop="sex" label="性别">
+                <el-select v-model="formData.sex">
+                    <el-option label="男" value="男"></el-option>
+                    <el-option label="女" value="女"></el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item prop="phone" label="联系方式">
+                <el-input v-model="formData.phone"></el-input>
+            </el-form-item>
+            <el-divider direction="horizontal" content-position="left">诉求信息</el-divider>
+            <el-form-item prop="content" label="投诉内容">
+                <el-input type="textarea" :rows="5" v-model="formData.content"></el-input>
+            </el-form-item>
+            <el-form-item prop="title" label="投诉目的">
+                <el-input type="textarea" :rows="3" v-model="formData.title"></el-input>
+            </el-form-item>
+            <el-form-item prop="nature" label="问题性质">
+                <el-input v-model="formData.nature"></el-input>
+            </el-form-item>
+            <el-form-item prop="unitType" label="涉及的单位">
+                <el-select v-model="formData.unitType" clearable filterable placeholder="请选择">
+                    <el-option
+                        v-for="item in unitTypeOptions"
+                        :key="item.value"
+                        :label="item.label"
+                        :value="item.value"
+                    >
+                    </el-option>
+                </el-select>
+                <el-input v-model="formData.unitName" style="width: 68%"></el-input>
+            </el-form-item>
+
+            <el-form-item prop="file" label="图片">
+                <file-upload v-model="formData.file"></file-upload>
+            </el-form-item>
+            <el-divider direction="horizontal" content-position="left">审查情况</el-divider>
+            <el-form-item prop="processing" label="办理情况">
+                <el-input type="textarea" :rows="5" v-model="formData.processing"></el-input>
+            </el-form-item>
+            <el-form-item prop="situationIsReal" label="情况属实">
+                <el-radio-group v-model="formData.situationIsReal">
+                    <el-radio :label="true">是</el-radio>
+                    <el-radio :label="false">否</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item prop="reviewFile" label="审查附件">
+                <file-upload v-model="formData.reviewFile"></file-upload>
+            </el-form-item>
+            <el-form-item prop="reviewAt" label="审查时间">
+                <el-date-picker
+                    v-model="formData.reviewAt"
+                    type="datetime"
+                    value-format="yyyy-MM-dd HH:mm:ss"
+                    placeholder="选择日期时间"
+                >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item prop="finish" label="办结">
+                <el-radio-group v-model="formData.finish">
+                    <el-radio :label="true">是</el-radio>
+                    <el-radio :label="false">否</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item>
+                <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>
+                <el-button @click="onDelete" :loading="saving" type="danger" v-if="formData.id">删除 </el-button>
+                <el-button @click="$router.go(-1)">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+<script>
+export default {
+    name: 'ComplainEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('complain/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {
+                phone: [
+                    {
+                        pattern: /^1[3-9]\d{9}$/,
+                        message: '请输入正确的手机号',
+                        trigger: 'blur'
+                    }
+                ]
+            },
+            unitTypeOptions: [
+                { label: '承办单位', value: 'ORGANIZATION' },
+                { label: '考级机构', value: 'GRADING_ORGANIZATION' },
+                { label: '考点', value: 'EXAMINATION' }
+            ]
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/complain/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/complain/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 190 - 0
src/main/vue/src/views/ComplainList.vue

@@ -0,0 +1,190 @@
+<template>
+    <div class="list-view">
+        <div class="filters-container">
+            <el-input placeholder="输入关键字" v-model="search" clearable class="filter-item"></el-input>
+            <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">搜索 </el-button>
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" class="filter-item">添加 </el-button>
+            <el-button
+                @click="download"
+                type="primary"
+                icon="el-icon-download"
+                :loading="downloading"
+                class="filter-item"
+                >导出EXCEL
+            </el-button>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="100"> </el-table-column>
+            <el-table-column prop="source" label="来源渠道"> </el-table-column>
+            <el-table-column prop="complainAt" label="来电时间"> </el-table-column>
+            <el-table-column prop="sex" label="性别"> </el-table-column>
+            <el-table-column prop="phone" label="联系方式"> </el-table-column>
+            <el-table-column prop="title" label="投诉目的"> </el-table-column>
+            <el-table-column prop="content" label="投诉内容"> </el-table-column>
+            <el-table-column prop="nature" label="问题性质"> </el-table-column>
+            <el-table-column prop="unitType" label="单位类型" :formatter="unitTypeFormatter"> </el-table-column>
+            <el-table-column prop="unitName" label="单位名称"> </el-table-column>
+            <el-table-column prop="file" label="图片"> </el-table-column>
+            <el-table-column prop="processing" label="办理情况"> </el-table-column>
+            <el-table-column prop="situationIsReal" label="情况属实">
+                <template slot-scope="{ row }">
+                    <el-tag :type="row.situationIsReal ? '' : 'info'">{{ row.situationIsReal }}</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column prop="reviewFile" label="审查附件"> </el-table-column>
+            <el-table-column prop="reviewAt" label="审查时间"> </el-table-column>
+            <el-table-column prop="finish" label="办结">
+                <template slot-scope="{ row }">
+                    <el-tag :type="row.finish ? '' : 'info'">{{ row.finish }}</el-tag>
+                </template>
+            </el-table-column>
+            <el-table-column label="操作" align="center" fixed="right" min-width="150">
+                <template slot-scope="{ row }">
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
+                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'ComplainList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/complain/all',
+            downloading: false,
+            unitTypeOptions: [
+                { label: '承办单位', value: 'ORGANIZATION' },
+                { label: '考级机构', value: 'GRADING_ORGANIZATION' },
+                { label: '考点', value: 'EXAMINATION' }
+            ]
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        unitTypeFormatter(row, column, cellValue, index) {
+            let selectedOption = this.unitTypeOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        beforeGetData() {
+            return { search: this.search };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/complainEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/complainEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/complain/excel', {
+                    responseType: 'blob',
+                    params: { size: 10000 }
+                })
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/complain/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 24 - 7
src/main/vue/src/views/ExamRoomList.vue

@@ -1,9 +1,14 @@
 <template>
     <div class="list-view">
         <div class="filters-container">
-            <el-input placeholder="输入考场名称" v-model="search" clearable class="filter-item"></el-input>
-            <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">搜索 </el-button>
-            <el-button @click="addRow" type="primary" icon="el-icon-plus" class="filter-item">添加 </el-button>
+            <!-- <el-input placeholder="输入考场名称" v-model="search" clearable class="filter-item"></el-input>
+            <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">搜索 </el-button> -->
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" class="filter-item" v-if="organization"
+                >添加
+            </el-button>
+            <el-button @click="showVideo" type="primary" icon="el-icon-video-camera" class="filter-item"
+                >监控平台
+            </el-button>
             <!-- <el-button
                 @click="download"
                 type="primary"
@@ -37,8 +42,12 @@
             <el-table-column label="操作" align="center" fixed="right" min-width="150">
                 <template slot-scope="{ row }">
                     <el-button @click="monitor(row)" type="success" size="mini" plain>监控</el-button>
-                    <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑</el-button>
-                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                    <el-button @click="editRow(row)" type="primary" size="mini" plain v-if="organization"
+                        >编辑</el-button
+                    >
+                    <el-button @click="deleteRow(row)" type="danger" size="mini" plain v-if="organization"
+                        >删除</el-button
+                    >
                 </template>
             </el-table-column>
         </el-table>
@@ -92,8 +101,8 @@ export default {
     computed: {
         selection() {
             return this.$refs.table.selection.map(i => i.id);
-        }
-        // ...mapState(['organization'])
+        },
+        ...mapState(['organization'])
     },
     methods: {
         beforeGetData() {
@@ -190,6 +199,14 @@ export default {
                     console.log(e);
                     this.$message.error(e.error);
                 });
+        },
+        showVideo() {
+            this.$router.push({
+                path: '/videoOrganizationList',
+                query: {
+                    ...this.$route.query
+                }
+            });
         }
     },
     components: {

+ 3 - 2
src/main/vue/src/views/record/RecordCheck.vue

@@ -17,8 +17,9 @@
                     <el-form-item prop="content" label="检查情况">
                         <el-input :rows="5" type="textarea" v-model="item.content"></el-input>
                     </el-form-item>
-                    <el-form-item prop="files" label="作证材料">
-                        <file-upload v-model="item.files"></file-upload>
+                    <el-form-item prop="file" label="作证材料">
+                        <!-- <file-upload v-model="item.file"></file-upload> -->
+                        <multi-upload v-model="item.file"></multi-upload>
                     </el-form-item>
                     <el-form-item>
                         <el-button

+ 24 - 6
src/main/vue/src/views/record/VideoList.vue

@@ -41,6 +41,7 @@
                     </el-select>
                 </el-form-item>
             </el-col>
+            <el-button @click="getVideo" type="primary" icon="el-icon-search" class="filter-item">查询 </el-button>
             <!-- <el-col :span="14">
                 <el-form-item label="考级活动时间">
                     <el-date-picker
@@ -153,15 +154,32 @@ export default {
                 });
         },
         getVideo() {
+            let data = {
+                size: 100,
+                query: {
+                    examinationTime: format(new Date(), 'yyyy-MM-dd')
+                }
+            };
+            if (this.search) {
+                data.search = this.search;
+            }
+            if (this.district) {
+                data.query.district = this.district;
+            }
+            if (this.agency) {
+                data.query.examinationAgency = this.agency;
+            }
+            if (this.organizer) {
+                data.query.organizer = this.organizer;
+            }
+            if (this.status) {
+                data.query.status = this.status;
+            }
             this.$http
                 .get('ezvizToken/getToken')
                 .then(res => {
                     this.token = res;
-                    return this.$http.post(
-                        '/examRoom/byToday',
-                        { size: 100, query: { examinationTime: format(new Date(), 'yyyy-MM-dd') } },
-                        { body: 'json' }
-                    );
+                    return this.$http.post('/examRoom/byToday', data, { body: 'json' });
                 })
                 .then(res => {
                     this.list = res;
@@ -195,7 +213,7 @@ export default {
 
 <style lang="less" scoped>
 .edit-view {
-    height: 798px;
+    height: 900px;
 }
 
 .video-list {

+ 127 - 0
src/main/vue/src/views/record/VideoOrganizationList.vue

@@ -0,0 +1,127 @@
+<template>
+    <div class="edit-view">
+        <div class="video-list">
+            <video-grid
+                v-for="item in list"
+                ref="video"
+                :token="token"
+                :device="item.deviceSerial"
+                :key="item.id"
+                :roomname="item.name"
+                :name="`video_${item.id}`"
+            ></video-grid>
+        </div>
+    </div>
+</template>
+
+<script>
+import VideoGrid from '../../components/VideoGridOrganization.vue';
+import format from 'date-fns/format';
+export default {
+    components: { VideoGrid },
+    data() {
+        return {
+            token: '',
+            form: {},
+            list: [],
+            time: '',
+            records: [],
+            districts: [],
+            district: '',
+            search: '',
+            agency: '',
+            dateRange: '',
+            status: ''
+        };
+    },
+    created() {
+        this.$http
+            .get('/district/NJ')
+            .then(res => {
+                this.districts = res;
+            })
+            .catch(e => {
+                console.log(e);
+                this.$message.error(e.error);
+            });
+    },
+    mounted() {
+        // this.getTime();
+        this.getVideo();
+    },
+    methods: {
+        getTime() {
+            this.time = format(new Date(), 'yyyy/MM/dd hh:mm:ss');
+            setTimeout(() => {
+                this.getTime();
+            }, 1000);
+        },
+        randomNum(minNum, maxNum) {
+            switch (arguments.length) {
+                case 1:
+                    return parseInt(Math.random() * minNum + 1, 10);
+                    break;
+                case 2:
+                    return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
+                    break;
+                default:
+                    return 0;
+                    break;
+            }
+        },
+        getVideo() {
+            let data = {
+                size: 100,
+                query: {}
+            };
+            if (this.$route.query.rid) {
+                data.query.recordId = this.$route.query.rid;
+            }
+            this.$http
+                .get('ezvizToken/getToken')
+                .then(res => {
+                    this.token = res;
+                    return this.$http.post('/examRoom/all', data, { body: 'json' });
+                })
+                .then(res => {
+                    this.list = res.content;
+                    this.$nextTick(() => {
+                        if (res.content.length > 0) {
+                            res.content.forEach((item, index) => {
+                                if (index == 0) {
+                                    this.$refs.video[index].init();
+                                } else {
+                                    let _index = this.randomNum(0, 4);
+                                    console.log(_index);
+                                    this.$refs.video[index].initVideo(index);
+                                }
+                            });
+                        }
+                    });
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.edit-view {
+    height: 900px;
+}
+
+.video-list {
+    display: flex;
+    flex-wrap: wrap;
+}
+
+.span-size {
+    font-size: 14px;
+    color: #565b66;
+    line-height: 15px;
+    padding: 0 10px 0 10px;
+}
+</style>

Некоторые файлы не были показаны из-за большого количества измененных файлов