فهرست منبع

ai中台代码迁移

lyq 3 هفته پیش
والد
کامیت
5af8c63052

+ 87 - 0
monitor_ui/src/api/business/ai/alarmanalysis.js

@@ -0,0 +1,87 @@
+import request from '@/utils/request'
+
+// 查询事件二次研判列表
+export function listAlarmanalysis(query) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询事件二次研判详细
+export function getAlarmanalysis(id) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/' + id,
+    method: 'get'
+  })
+}
+
+// 新增事件二次研判
+export function addAlarmanalysis(data) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改事件二次研判
+export function updateAlarmanalysis(data) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除事件二次研判
+export function delAlarmanalysis(id) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/' + id,
+    method: 'delete'
+  })
+}
+
+// 查询报警类型列表
+export function listAlarmType() {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/listAlarmType',
+    method: 'get',
+  })
+}
+
+// 生成提示词
+export function genPromptWord(desc) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/genPromptWord?desc=' + desc,
+    method: 'get',
+    timeout: 20000,
+  })
+}
+
+// 查询摄像头-通道树
+export function channelTree() {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/channelTree',
+    method: 'get',
+  })
+}
+
+// 同步事件二次研判
+export function syncAlarmanalysis(query) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/sync',
+    method: 'get',
+    params: query
+  })
+}
+
+// 同步事件二次研判
+export function syncAlarmanalysisDH(query) {
+  return request({
+    url: '/center-monitor/ai/alarmanalysis/syncDH',
+    method: 'get',
+    params: query
+  })
+}

+ 61 - 0
monitor_ui/src/api/business/ai/algorithm.js

@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 查询算法列表
+export function listAlgorithm(query) {
+  return request({
+    url: '/center-monitor/ai/algorithm/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询算法详细
+export function getAlgorithm(id) {
+  return request({
+    url: '/center-monitor/ai/algorithm/' + id,
+    method: 'get'
+  })
+}
+
+// 新增算法
+export function addAlgorithm(data) {
+  return request({
+    url: '/center-monitor/ai/algorithm',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改算法
+export function updateAlgorithm(data) {
+  return request({
+    url: '/center-monitor/ai/algorithm',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除算法
+export function delAlgorithm(id) {
+  return request({
+    url: '/center-monitor/ai/algorithm/' + id,
+    method: 'delete'
+  })
+}
+
+// 同步算法
+export function syncAlgorithm(query) {
+  return request({
+    url: '/center-monitor/ai/algorithm/sync',
+    method: 'get',
+    params: query
+  })
+}
+
+// 同步算法
+export function syncAlgorithmDH() {
+  return request({
+    url: '/center-monitor/ai/algorithm/syncDH',
+    method: 'get',
+  })
+}

+ 70 - 0
monitor_ui/src/api/business/ai/algorithmtask.js

@@ -0,0 +1,70 @@
+import request from '@/utils/request'
+
+// 查询任务列表
+export function listAlgorithmtask(query) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询任务详细
+export function getAlgorithmtask(id) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask/' + id,
+    method: 'get'
+  })
+}
+
+// 新增任务
+export function addAlgorithmtask(data) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改任务
+export function updateAlgorithmtask(data) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除任务
+export function delAlgorithmtask(id) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask/' + id,
+    method: 'delete'
+  })
+}
+
+// 查询算法列表
+export function listAlgorithm() {
+  return request({
+    url: '/center-monitor/ai/algorithmtask/listAlgorithm',
+    method: 'get',
+  })
+}
+
+// 同步任务
+export function syncAlgorithmtask(query) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask/sync',
+    method: 'get',
+    params: query
+  })
+}
+
+// 同步任务
+export function syncAlgorithmtaskDH(query) {
+  return request({
+    url: '/center-monitor/ai/algorithmtask/syncDH',
+    method: 'get',
+    params: query
+  })
+}

+ 10 - 0
monitor_ui/src/api/business/ai/historyalarm.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询报警类型列表
+export function listHistoryalarm(data) {
+  return request({
+    url: '/center-monitor/ai/historyalarm/list',
+    method: 'post',
+    data: data
+  })
+}

+ 68 - 0
monitor_ui/src/api/business/ai/singletype.js

@@ -0,0 +1,68 @@
+import request from '@/utils/request'
+
+// 查询报警类型列表
+export function listSingletype(query) {
+  return request({
+    url: '/center-monitor/ai/singletype/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询报警类型详细
+export function getSingletype(id) {
+  return request({
+    url: '/center-monitor/ai/singletype/' + id,
+    method: 'get'
+  })
+}
+
+// 新增报警类型
+export function addSingletype(data) {
+  return request({
+    url: '/center-monitor/ai/singletype',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改报警类型
+export function updateSingletype(data) {
+  return request({
+    url: '/center-monitor/ai/singletype',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除报警类型
+export function delSingletype(id) {
+  return request({
+    url: '/center-monitor/ai/singletype/' + id,
+    method: 'delete'
+  })
+}
+
+// 查询归属列表
+export function listAffiliation() {
+  return request({
+    url: '/center-monitor/ai/singletype/listAffiliation',
+    method: 'get',
+  })
+}
+
+// 同步报警类型
+export function syncSingletype() {
+  return request({
+    url: '/center-monitor/ai/singletype/sync',
+    method: 'get',
+  })
+}
+
+// 同步报警类型
+export function syncSingletypeDH() {
+  return request({
+    url: '/center-monitor/ai/singletype/syncDH',
+    method: 'get',
+  })
+}

+ 10 - 0
monitor_ui/src/api/business/ai/zeroshot.js

@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 查询报警类型列表
+export function listZeroshot(data) {
+  return request({
+    url: '/center-monitor/api/ai/zeroshot/list',
+    method: 'post',
+    data: data
+  })
+}

+ 496 - 0
monitor_ui/src/views/business/ai/alarmanalysis/index.vue

@@ -0,0 +1,496 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="配置名称" prop="configName">
+        <el-input
+          v-model="queryParams.configName"
+          placeholder="请输入配置名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['ai:alarmanalysis:add']"
+        >新增配置</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['ai:alarmanalysis:edit']"
+        >修改配置</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleAsyncDH"
+          v-hasPermi="['ai:alarmanalysis:list']"
+        >拉取</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="alarmanalysisList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="配置名称" align="center" prop="configName" />
+      <el-table-column label="报警类型" align="center" prop="alarmTypeName" />
+      <el-table-column label="prompt" align="center" prop="scenarioDescription" :show-overflow-tooltip="true" />
+      <el-table-column label="分析周期" align="center" prop="analysisCycle" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          {{ scope.row.analysisCycle.split(",").map(item => dict.type.bus_ai_week.find(week => week.value === item).label).join(",") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="分析时段" align="center" prop="alarmAnalysisConfigJobs" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          {{ scope.row.alarmAnalysisConfigJobs.map(item => item.startTimeHour + ":" + item.startTimeMinute + ":" + item.startTimeSecond
+            + "-" + item.endTimeHour + ":" + item.endTimeMinute + ":" + item.endTimeSecond).join(",") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="生效通道" align="center" prop="channels" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          {{ scope.row.channels.map(item => item.channelName).join(",") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="启用状态" align="center" prop="enabled">
+        <template slot-scope="scope">
+          {{ scope.row.enabled == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="同步状态" align="center" prop="syncStatus">
+        <template slot-scope="scope">
+          {{ scope.row.syncStatus == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['ai:alarmanalysis:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['ai:alarmanalysis:remove']"
+          >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-refresh"
+            @click="handleAsync(scope.row)"
+            v-hasPermi="['ai:alarmanalysis:query']"
+          >推送</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改事件二次研判对话框 -->
+    <el-dialog v-loading="loading" :title="title" :visible.sync="open" width="1200px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="140px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="配置名称" prop="configName">
+              <el-input v-model="form.configName" placeholder="请输入配置名称" maxlength="32" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="报警类型" prop="alarmType">
+              <el-select v-model="form.alarmType" placeholder="请选择报警类型" style="width: 440px">
+                <el-option
+                  v-for="alarmType in alarmTypeList"
+                  :key="alarmType.alarmType"
+                  :label="alarmType.alarmTypeName"
+                  :value="alarmType.alarmType"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="Prompt填写方式" prop="scenarioDescription">
+          <el-col :span="12">
+            <el-input v-model="form.promptSuggestion.oneSentenceDescription" placeholder="请用一句话描述算法用途" />
+          </el-col>
+          <el-col :span="4">
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="genPromptWord">生成提示词</el-button>
+          </el-col>
+          <el-col :span="16">
+            <div style="margin: 15px 0;"></div>
+            <el-input v-model="form.scenarioDescription" type="textarea" placeholder="请输入内容" :autosize="{ minRows: 10 }" disabled />
+          </el-col>
+        </el-form-item>
+        <el-form-item label="分析周期" prop="analysisCycle">
+          <el-col :span="2">
+            <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
+          </el-col>
+          <el-col :span="14">
+            <el-checkbox-group v-model="form.analysisCycles" @change="handleCheckedCitiesChange">
+              <el-checkbox v-for="week in dict.type.bus_ai_week" :label="week.value" :key="week.value">{{week.label}}</el-checkbox>
+            </el-checkbox-group>
+          </el-col>
+        </el-form-item>
+        <el-form-item label="分析时段" prop="alarmAnalysisConfigJobs">
+          <el-row v-for="(item, index) in form.timeRangeList">
+            <el-time-picker :key="index" is-range v-model="form.timeRangeList[index]" range-separator="至"></el-time-picker>
+            <el-button :key="index" type="danger" plain icon="el-icon-delete" size="mini" @click="handleDeleteTimeRange"></el-button>
+            <div style="margin: 15px 0;"></div>
+          </el-row>
+          <el-row>
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddTimeRange" v-if="form.timeRangeList.length != 5">添加时段</el-button>
+          </el-row>
+        </el-form-item>
+        <el-form-item label="绑定通道" prop="channels">
+          <el-col :span="10">
+            <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
+            <div style="margin: 15px 0;"></div>
+            <el-tree :data="data" show-checkbox node-key="id" :props="defaultProps" @check="handleNodeCheck"
+                     :filter-node-method="filterNode" ref="tree" style="height:200px;overflow:auto"></el-tree>
+          </el-col>
+          <el-col :span="2">
+            <el-button style="margin-top: 90px;margin-left: 15px"> > </el-button>
+          </el-col>
+          <el-col :span="12">
+            <el-table :data="form.channels" style="width: 100%">
+              <el-table-column prop="channelName" label="通道名称"></el-table-column>
+              <el-table-column prop="channelCode" label="通道编码"></el-table-column>
+              <el-table-column prop="deviceName" label="所属设备"></el-table-column>
+            </el-table>
+          </el-col>
+        </el-form-item>
+        <el-form-item label="识别框">
+          <el-switch v-model="form.detection" active-value="1" inactive-value="0"></el-switch>
+          <span>开启识别框后,报警抓图中会框选出报警源</span>
+        </el-form-item>
+        <el-form-item label="启用状态">
+          <el-switch v-model="form.enabled" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listAlarmanalysis, getAlarmanalysis, delAlarmanalysis, addAlarmanalysis, updateAlarmanalysis, listAlarmType, genPromptWord, channelTree, syncAlarmanalysis, syncAlarmanalysisDH } from "@/api/business/ai/alarmanalysis";
+
+export default {
+  name: "Alarmanalysis",
+  dicts: ['bus_ai_week'],
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 事件二次研判表格数据
+      alarmanalysisList: [],
+      alarmTypeList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        configName: null,
+      },
+      // 表单参数
+      form: {
+        timeRangeList: [],
+        promptSuggestion: {
+          oneSentenceDescription: null,
+        }
+      },
+      // 表单校验
+      rules: {
+        configName: [
+          { required: true, message: "配置名称不能为空", trigger: "blur" }
+        ],
+        alarmType: [
+          { required: true, message: "报警类型不能为空", trigger: "change" }
+        ],
+        scenarioDescription: [
+          { required: true, message: "Prompt填写方式不能为空", trigger: "blur" }
+        ],
+        analysisCycle: [
+          { required: true, message: "分析周期不能为空", trigger: "blur" }
+        ],
+        alarmAnalysisConfigJobs: [
+          { required: true, message: "分析时段不能为空", trigger: "blur" }
+        ],
+        channels: [
+          { required: true, message: "绑定通道不能为空", trigger: "blur" }
+        ],
+      },
+      checkAll: false,
+      isIndeterminate: false,
+      filterText: '',
+      data: [],
+      defaultProps: {
+        children: 'children',
+        label: 'label'
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getAlarmTypeList();
+  },
+  watch: {
+    filterText(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  methods: {
+    /** 查询事件二次研判列表 */
+    getList() {
+      this.loading = true;
+      listAlarmanalysis(this.queryParams).then(response => {
+        this.alarmanalysisList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getAlarmTypeList() {
+      listAlarmType().then(response => {
+        this.alarmTypeList = response.data;
+      });
+    },
+    genPromptWord() {
+      this.loading = true;
+      genPromptWord(this.form.promptSuggestion.oneSentenceDescription).then(response => {
+        this.form.scenarioDescription = response.data;
+        this.$refs.form.validateField("scenarioDescription");
+        this.$modal.msgSuccess("操作成功");
+        this.loading = false;
+      }).catch(error => {
+        this.loading = false;
+      });
+    },
+    handleCheckAllChange(val) {
+      this.form.analysisCycles = val ? dict.type.bus_ai_week.map(item => item.value) : [];
+      this.isIndeterminate = false;
+    },
+    handleCheckedCitiesChange(value) {
+      let checkedCount = value.length;
+      this.checkAll = checkedCount === dict.type.bus_ai_week.length;
+      this.isIndeterminate = checkedCount > 0 && checkedCount < dict.type.bus_ai_week.length;
+    },
+    handleDeleteTimeRange(index) {
+      this.form.timeRangeList.splice(index, 1);
+    },
+    handleAddTimeRange() {
+      this.form.timeRangeList.push([new Date(2016, 9, 10, 0, 0, 0), new Date(2016, 9, 10, 23, 59, 59)]);
+    },
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    handleNodeCheck(node, obj) {
+      this.form.channels = obj.checkedNodes.filter(item => "0" != item.parentId).map(item => {
+        let pnode = this.$refs.tree.getNode(item.parentId);
+        return {channelCode: item.id, channelName: item.label, orgName: pnode.label, orgCode: pnode.id, deviceName: pnode.label}
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        configName: null,
+        alarmType: null,
+        scenarioDescription: null,
+        analysisCycle: null,
+        analysisCycles: [],
+        alarmAnalysisConfigJobs: [],
+        timeRangeList: [
+          [new Date(2016, 9, 10, 0, 0, 0), new Date(2016, 9, 10, 23, 59, 59)]
+        ],
+        channels: [],
+        detection: "1",
+        enabled: "1",
+        calculatePoints: 0,
+        promptSuggestion: {
+          generationType: 1,
+          oneSentenceDescription: null,
+          scenes: null,
+          sceneList: [],
+          types: null,
+          typeList: [],
+        }
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      channelTree().then(response => {
+        this.data = this.handleTreeView(response.data)
+        this.open = true;
+        this.title = "添加事件二次研判";
+      });
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAlarmanalysis(id).then(response => {
+        this.form = response.data;
+        this.$set(this.form, "analysisCycles", this.form.analysisCycle.split(","));
+        this.$set(this.form, "timeRangeList", this.form.alarmAnalysisConfigJobs.map(item => [new Date(2016, 9, 10, item.startTimeHour, item.startTimeMinute, item.startTimeSecond), new Date(2016, 9, 10, item.endTimeHour, item.endTimeMinute, item.endTimeSecond)]));
+        channelTree().then(response => {
+          this.data = this.handleTreeView(response.data)
+          this.$refs.tree.setCheckedKeys(this.form.channels.map(item => item.channelCode));
+        });
+        if (this.form.promptSuggestion.scenes) {
+          this.form.promptSuggestion.sceneList = this.form.promptSuggestion.scenes.split(",");
+        }
+        if (this.form.promptSuggestion.types) {
+          this.form.promptSuggestion.typeList = this.form.promptSuggestion.types.split(",");
+        }
+        this.open = true;
+        this.title = "修改事件二次研判";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.form.analysisCycle = this.form.analysisCycles.join(",");
+      this.form.alarmAnalysisConfigJobs = this.form.timeRangeList.map(item => {
+        return {
+          startTimeHour: item[0].getHours(),
+          startTimeMinute: item[0].getMinutes(),
+          startTimeSecond: item[0].getSeconds(),
+          endTimeHour: item[1].getHours(),
+          endTimeMinute: item[1].getMinutes(),
+          endTimeSecond: item[1].getSeconds()
+        }
+      });
+      if (null != this.form.promptSuggestion.sceneList) {
+        this.form.promptSuggestion.scenes = this.form.promptSuggestion.sceneList.join(",");
+      }
+      if (null != this.form.promptSuggestion.typeList) {
+        this.form.promptSuggestion.types = this.form.promptSuggestion.typeList.join(",");
+      }
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.alarmTypeName = this.alarmTypeList.filter(item => this.form.alarmType == item.alarmType)[0].alarmTypeName
+          if (this.form.id != null) {
+            updateAlarmanalysis(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAlarmanalysis(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除配置名称为"' + row.configName + '"的数据项?').then(function() {
+        return delAlarmanalysis(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ai/alarmanalysis/export', {
+        ...this.queryParams
+      }, `alarmanalysis_${new Date().getTime()}.xlsx`)
+    },
+    handleAsync(row) {
+      this.loading = true;
+      syncAlarmanalysis(row).then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    },
+    handleAsyncDH() {
+      this.loading = true;
+      syncAlarmanalysisDH().then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    }
+  }
+};
+</script>

+ 349 - 0
monitor_ui/src/views/business/ai/algorithm/index.vue

@@ -0,0 +1,349 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="算法名称" prop="algorithmName">
+        <el-input
+          v-model="queryParams.algorithmName"
+          placeholder="请输入算法名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['ai:algorithm:add']"
+        >新增算法</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['ai:algorithm:edit']"
+        >修改算法</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleAsyncDH"
+          v-hasPermi="['ai:algorithm:list']"
+        >拉取</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="algorithmList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="算法名称" align="center" prop="algorithmName" />
+      <el-table-column label="报警类型" align="center" prop="alarmTypeName" />
+      <el-table-column label="启用状态" align="center" prop="enabled">
+        <template slot-scope="scope">
+          {{ scope.row.enabled == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="同步状态" align="center" prop="syncStatus">
+        <template slot-scope="scope">
+          {{ scope.row.syncStatus == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['ai:algorithm:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['ai:algorithm:remove']"
+          >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-refresh"
+            @click="handleAsync(scope.row)"
+            v-hasPermi="['ai:algorithm:query']"
+          >推送</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改算法对话框 -->
+    <el-dialog v-loading="loading" :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="140px">
+        <el-row>
+          <el-col :span="16">
+            <el-form-item label="算法名称" prop="algorithmName">
+              <el-input v-model="form.algorithmName" placeholder="请输入算法名称" maxlength="32" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="16">
+            <el-form-item label="报警类型" prop="alarmType">
+              <el-select v-model="form.alarmType" placeholder="请选择报警类型" style="width: 370px">
+                <el-option
+                  v-for="alarmType in alarmTypeList"
+                  :key="alarmType.alarmType"
+                  :label="alarmType.alarmTypeName"
+                  :value="alarmType.alarmType"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="Prompt填写方式" prop="algorithmRule">
+          <el-col :span="14">
+            <el-input v-model="form.scenarioDescription" placeholder="请用一句话描述算法用途" />
+          </el-col>
+          <el-col :span="4">
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="genPromptWord">生成提示词</el-button>
+          </el-col>
+          <el-col :span="24">
+            <div style="margin: 15px 0;"></div>
+            <el-input v-model="form.algorithmRule" type="textarea" placeholder="请输入内容" :autosize="{ minRows: 16 }" disabled />
+          </el-col>
+        </el-form-item>
+        <el-form-item label="启用状态">
+          <el-switch v-model="form.enabled" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listAlgorithm, getAlgorithm, delAlgorithm, addAlgorithm, updateAlgorithm, syncAlgorithm, syncAlgorithmDH } from "@/api/business/ai/algorithm";
+import { listAlarmType, genPromptWord } from "@/api/business/ai/alarmanalysis";
+
+export default {
+  name: "Algorithm",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 算法表格数据
+      algorithmList: [],
+      alarmTypeList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        algorithmName: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        algorithmName: [
+          { required: true, message: "算法名称不能为空", trigger: "blur" }
+        ],
+        alarmType: [
+          { required: true, message: "报警类型不能为空", trigger: "change" }
+        ],
+        algorithmRule: [
+          { required: true, message: "Prompt填写方式不能为空", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getAlarmTypeList();
+  },
+  methods: {
+    /** 查询算法列表 */
+    getList() {
+      this.loading = true;
+      listAlgorithm(this.queryParams).then(response => {
+        this.algorithmList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getAlarmTypeList() {
+      listAlarmType().then(response => {
+        this.alarmTypeList = response.data;
+      });
+    },
+    genPromptWord() {
+      this.loading = true;
+      genPromptWord(this.form.scenarioDescription).then(response => {
+        this.form.algorithmRule = response.data;
+        this.$refs.form.validateField("algorithmRule");
+        this.$modal.msgSuccess("操作成功");
+        this.loading = false;
+      }).catch(error => {
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        algorithmName: null,
+        alarmType: null,
+        algorithmRule: null,
+        enabled: "1",
+        promptSuggestion: {
+          generationType: 1,
+          scenes: null,
+          sceneList: [],
+          types: null,
+          typeList: [],
+        }
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加算法";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAlgorithm(id).then(response => {
+        this.form = response.data;
+        if (this.form.promptSuggestion.scenes) {
+          this.form.promptSuggestion.sceneList = this.form.promptSuggestion.scenes.split(",");
+        }
+        if (this.form.promptSuggestion.types) {
+          this.form.promptSuggestion.typeList = this.form.promptSuggestion.types.split(",");
+        }
+        this.open = true;
+        this.title = "修改算法";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.alarmTypeName = this.alarmTypeList.filter(item => this.form.alarmType == item.alarmType)[0].alarmTypeName
+          if (this.form.id != null) {
+            updateAlgorithm(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAlgorithm(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除算法名称为"' + row.algorithmName + '"的数据项?').then(function() {
+        return delAlgorithm(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ai/algorithm/export', {
+        ...this.queryParams
+      }, `algorithm_${new Date().getTime()}.xlsx`)
+    },
+    handleAsync(row) {
+      this.loading = true;
+      syncAlgorithm(row).then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    },
+    handleAsyncDH() {
+      this.loading = true;
+      syncAlgorithmDH().then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    }
+  }
+};
+</script>

+ 562 - 0
monitor_ui/src/views/business/ai/algorithmtask/index.vue

@@ -0,0 +1,562 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="任务名称" prop="taskName">
+        <el-input
+          v-model="queryParams.taskName"
+          placeholder="请输入任务名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['ai:algorithmtask:add']"
+        >新增任务</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['ai:algorithmtask:edit']"
+        >修改任务</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleAsyncDH"
+          v-hasPermi="['ai:algorithmtask:list']"
+        >拉取</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="algorithmtaskList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="任务名称" align="center" prop="taskName" />
+      <el-table-column label="算法名称" align="center" prop="infos">
+        <template slot-scope="scope">
+          {{ scope.row.infos.map(item => item.aigorithmName).join(",") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="分析类型" align="center" prop="analysisType">
+        <template slot-scope="scope">
+          {{ scope.row.analysisType == "1" ? "单图分析" : "组合分析" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="任务类型" align="center" prop="auto">
+        <template slot-scope="scope">
+          {{ scope.row.auto == "1" ? "自动抓图" : "定时抓图" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="分析频率" align="center">
+        <template slot-scope="scope">
+          {{ scope.row.analysisFrequency + scope.row.analysisFrequencyUnit }}
+        </template>
+      </el-table-column>
+      <el-table-column label="分析周期" align="center" prop="analysisCycle" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          {{ scope.row.analysisCycle.split(",").map(item => dict.type.bus_ai_week.find(week => week.value === item).label).join(",") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="分析时段" align="center" prop="taskJobs" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          {{ scope.row.taskJobs.map(item => item.startTimeHour + ":" + item.startTimeMinute + ":" + item.startTimeSecond
+          + "-" + item.endTimeHour + ":" + item.endTimeMinute + ":" + item.endTimeSecond).join(",") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="是否启用" align="center" prop="enabled">
+        <template slot-scope="scope">
+          {{ scope.row.enabled == "0" ? "关闭" : "开启" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="同步状态" align="center" prop="syncStatus">
+        <template slot-scope="scope">
+          {{ scope.row.syncStatus == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['ai:algorithmtask:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['ai:algorithmtask:remove']"
+          >删除</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-refresh"
+            @click="handleAsync(scope.row)"
+            v-hasPermi="['ai:algorithmtask:query']"
+          >推送</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改任务对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="1200px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="任务名称" prop="taskName">
+              <el-input v-model="form.taskName" placeholder="请输入任务名称" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="算法名称" prop="algorithmIds">
+              <el-select v-model="form.algorithmIds" multiple placeholder="请选择算法" style="width: 440px">
+                <el-option
+                  v-for="algorithm in algorithmList"
+                  :key="algorithm.algorithmId"
+                  :label="algorithm.algorithmName"
+                  :value="algorithm.algorithmId"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="分析类型" prop="analysisType">
+          <el-radio-group v-model="form.analysisType" @input="handleRadioChange">
+            <el-radio :key="1" :label="1">单图分析(分析及场景识别)</el-radio>
+            <!--<el-radio :key="2" :label="2">组合分析(行为动作判断)</el-radio>-->
+          </el-radio-group>
+        </el-form-item>
+        <div style="margin-left: 80px">
+          <el-form-item label="抓图规则" prop="auto" v-if="form.analysisType == 1">
+            <el-radio-group v-model="form.auto">
+              <el-radio :key="0" :label="0">定时</el-radio>
+              <el-radio :key="1" :label="1">自动</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-row>
+            <el-col :span="8">
+              <el-form-item label="分析频率" prop="analysisFrequency" v-if="form.analysisType == 1 && form.auto == 0">
+                <el-input v-model="form.analysisFrequency" placeholder="请输入抓图间隔" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="4">
+              <el-form-item prop="analysisFrequencyUnit" v-if="form.analysisType == 1 && form.auto == 0" style="margin-left: -60px">
+                <el-select v-model="form.analysisFrequencyUnit" style="width: 80px">
+                  <el-option label="秒" value="秒"></el-option>
+                  <el-option label="分" value="分"></el-option>
+                  <el-option label="时" value="时"></el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="任务分析间隔" prop="combTaskInterval" v-if="form.analysisType == 2">
+                <div style="display: flex;align-items: center">
+                  <el-input v-model="form.combTaskInterval" placeholder="请输入任务分析间隔" />
+                  <span style="margin-left: 10px">秒</span>
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="抓图间隔" prop="captureInterval" v-if="form.analysisType == 2">
+                <div style="display: flex;align-items: center">
+                  <el-input v-model="form.captureInterval" placeholder="请输入抓图间隔" />
+                  <span style="margin-left: 10px">秒</span>
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row>
+            <el-col :span="12">
+              <el-form-item label="抓图数量" prop="captureImageNum" v-if="form.analysisType == 2">
+                <div style="display: flex;align-items: center">
+                  <el-input v-model="form.captureImageNum" placeholder="请输入抓图数量" />
+                  <span style="margin-left: 10px">张</span>
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </div>
+        <el-form-item label="分析周期" prop="analysisCycle">
+          <el-col :span="2">
+            <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
+          </el-col>
+          <el-col :span="14">
+            <el-checkbox-group v-model="form.analysisCycles" @change="handleCheckedCitiesChange">
+              <el-checkbox v-for="week in dict.type.bus_ai_week" :label="week.value" :key="week.value">{{week.label}}</el-checkbox>
+            </el-checkbox-group>
+          </el-col>
+        </el-form-item>
+        <el-form-item label="分析时段" prop="taskJobs">
+          <el-row v-for="(item, index) in form.timeRangeList">
+            <el-time-picker :key="index" is-range v-model="form.timeRangeList[index]" range-separator="至"></el-time-picker>
+            <el-button :key="index" type="danger" plain icon="el-icon-delete" size="mini" @click="handleDeleteTimeRange"></el-button>
+            <div style="margin: 15px 0;"></div>
+          </el-row>
+          <el-row>
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAddTimeRange" v-if="form.timeRangeList.length != 5">添加时段</el-button>
+          </el-row>
+        </el-form-item>
+        <el-form-item label="识别框">
+          <el-switch v-model="form.detection" active-value="1" inactive-value="0"></el-switch>
+          <span>开启识别框后,报警抓图中会框选出报警源</span>
+          <div v-if="this.form.analysisType == 2">组合分析不支持配置识别框</div>
+        </el-form-item>
+        <el-form-item label="图片压缩">
+          <el-switch v-model="form.detection" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+        <div style="margin-left: 100px">
+          <el-form-item label="等比缩放" v-if="this.form.detection == 1">
+            <el-select v-model="form.shortSideResolution" style="width: 300px">
+              <el-option label="1080 px" value="1080"></el-option>
+              <el-option label="720 px" value="720"></el-option>
+              <el-option label="480 px" value="480"></el-option>
+            </el-select>
+          </el-form-item>
+        </div>
+        <el-form-item label="选择通道" prop="channelInfos">
+          <el-col :span="10">
+            <el-input placeholder="输入关键字进行过滤" v-model="filterText"></el-input>
+            <div style="margin: 15px 0;"></div>
+            <el-tree :data="data" show-checkbox node-key="id" :props="defaultProps" @check="handleNodeCheck"
+                     :filter-node-method="filterNode" ref="tree" style="height:200px;overflow:auto"></el-tree>
+          </el-col>
+          <el-col :span="2">
+            <el-button style="margin-top: 90px;margin-left: 15px"> > </el-button>
+          </el-col>
+          <el-col :span="12">
+            <el-table :data="form.channelInfos" style="width: 100%;height:300px;overflow:auto">
+              <el-table-column prop="channelName" label="通道名称"></el-table-column>
+              <el-table-column prop="channelCode" label="通道编码"></el-table-column>
+              <el-table-column prop="deviceName" label="所属设备"></el-table-column>
+            </el-table>
+          </el-col>
+        </el-form-item>
+        <el-form-item label="目标点定位">
+          <el-switch v-model="form.calculatePoints" active-value="1" inactive-value="0"></el-switch>
+          <span>仅针对前端可以上报PTZ的设备生效,且需要设备完成标定动作</span>
+        </el-form-item>
+        <el-form-item label="启用状态">
+          <el-switch v-model="form.enabled" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listAlgorithmtask, getAlgorithmtask, delAlgorithmtask, addAlgorithmtask, updateAlgorithmtask, listAlgorithm, syncAlgorithmtask, syncAlgorithmtaskDH } from "@/api/business/ai/algorithmtask";
+import { channelTree } from "@/api/business/ai/alarmanalysis";
+import { checkPositiveInteger } from "@/api/system/rules"
+
+export default {
+  name: "Algorithmtask",
+  dicts: ['bus_ai_week'],
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 任务表格数据
+      algorithmtaskList: [],
+      algorithmList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        taskName: null
+      },
+      // 表单参数
+      form: {
+        timeRangeList: [],
+      },
+      // 表单校验
+      rules: {
+        taskName: [
+          { required: true, message: "任务名称不能为空", trigger: "blur" }
+        ],
+        algorithmIds: [
+          { required: true, message: "算法不能为空", trigger: "change" }
+        ],
+        analysisFrequency: [
+          { required: true, message: "分析频率不能为空", trigger: "blur" },
+          { validator: checkPositiveInteger, trigger: "blur" }
+        ],
+        analysisCycle: [
+          { required: true, message: "分析周期不能为空", trigger: "blur" }
+        ],
+        taskJobs: [
+          { required: true, message: "分析时段不能为空", trigger: "blur" }
+        ],
+        channelInfos: [
+          { required: true, message: "选择通道不能为空", trigger: "blur" }
+        ],
+      },
+      checkAll: false,
+      isIndeterminate: false,
+      filterText: '',
+      data: [],
+      defaultProps: {
+        children: 'children',
+        label: 'label'
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getAlgorithmList();
+  },
+  watch: {
+    filterText(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  methods: {
+    /** 查询任务列表 */
+    getList() {
+      this.loading = true;
+      listAlgorithmtask(this.queryParams).then(response => {
+        this.algorithmtaskList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getAlgorithmList() {
+      listAlgorithm().then(response => {
+        this.algorithmList = response.data;
+      });
+    },
+    handleRadioChange(val) {
+      if (1 == val) {
+        this.form.detection = "1";
+      } else {
+        this.form.detection = "0";
+      }
+    },
+    handleCheckAllChange(val) {
+      this.form.analysisCycles = val ? dict.type.bus_ai_week.map(item => item.value) : [];
+      this.isIndeterminate = false;
+    },
+    handleCheckedCitiesChange(value) {
+      let checkedCount = value.length;
+      this.checkAll = checkedCount === dict.type.bus_ai_week.length;
+      this.isIndeterminate = checkedCount > 0 && checkedCount < dict.type.bus_ai_week.length;
+    },
+    handleDeleteTimeRange(index) {
+      this.form.timeRangeList.splice(index, 1);
+    },
+    handleAddTimeRange() {
+      this.form.timeRangeList.push([new Date(2016, 9, 10, 0, 0, 0), new Date(2016, 9, 10, 23, 59, 59)]);
+    },
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    handleNodeCheck(node, obj) {
+      this.form.channelInfos = obj.checkedNodes.filter(item => "0" != item.parentId).map(item => {
+        let pnode = this.$refs.tree.getNode(item.parentId);
+        return {channelCode: item.id, channelName: item.label, orgName: pnode.label, orgCode: pnode.id, deviceName: pnode.label}
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        taskName: null,
+        infos: [],
+        algorithmIds: [],
+        analysisType: 1,
+        auto: 0,
+        analysisFrequency: null,
+        analysisFrequencyUnit: "分",
+        combTaskInterval: null,
+        captureInterval: null,
+        captureImageNum: null,
+        analysisCycle: null,
+        analysisCycles: [],
+        taskJobs: [],
+        timeRangeList: [
+          [new Date(2016, 9, 10, 0, 0, 0), new Date(2016, 9, 10, 23, 59, 59)]
+        ],
+        detection: "1",
+        shortSideResolution: 720,
+        channelInfos: [],
+        calculatePoints: "0",
+        enabled: "1",
+        templateId: null,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      channelTree().then(response => {
+        this.data = this.handleTreeView(response.data)
+        this.open = true;
+        this.title = "添加任务";
+      });
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getAlgorithmtask(id).then(response => {
+        this.form = response.data;
+        this.$set(this.form, "algorithmIds", this.form.infos.map(item => item.aigorithmId));
+        this.$set(this.form, "analysisCycles", this.form.analysisCycle.split(","));
+        this.$set(this.form, "timeRangeList", this.form.taskJobs.map(item => [new Date(2016, 9, 10, item.startTimeHour, item.startTimeMinute, item.startTimeSecond), new Date(2016, 9, 10, item.endTimeHour, item.endTimeMinute, item.endTimeSecond)]));
+        channelTree().then(response => {
+          this.data = this.handleTreeView(response.data)
+          this.$refs.tree.setCheckedKeys(this.form.channelInfos.map(item => item.channelCode));
+        });
+        this.open = true;
+        this.title = "修改任务";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.form.infos = this.form.algorithmIds.map(item => {
+        return {aigorithmId: item, aigorithmName: this.algorithmList.filter(algorithm => item == algorithm.algorithmId)[0].algorithmName}
+      });
+      this.form.analysisCycle = this.form.analysisCycles.join(",");
+      this.form.taskJobs = this.form.timeRangeList.map(item => {
+        return {
+          startTimeHour: item[0].getHours(),
+          startTimeMinute: item[0].getMinutes(),
+          startTimeSecond: item[0].getSeconds(),
+          endTimeHour: item[1].getHours(),
+          endTimeMinute: item[1].getMinutes(),
+          endTimeSecond: item[1].getSeconds()
+        }
+      });
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateAlgorithmtask(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addAlgorithmtask(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除任务名称为"' + row.taskName + '"的数据项?').then(function() {
+        return delAlgorithmtask(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ai/algorithmtask/export', {
+        ...this.queryParams
+      }, `algorithmtask_${new Date().getTime()}.xlsx`)
+    },
+    handleAsync(row) {
+      this.loading = true;
+      syncAlgorithmtask(row).then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    },
+    handleAsyncDH() {
+      this.loading = true;
+      syncAlgorithmtaskDH().then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    }
+  }
+};
+</script>

+ 132 - 0
monitor_ui/src/views/business/ai/historyalarm/index.vue

@@ -0,0 +1,132 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="来源设备" prop="alarmTypeName">
+        <el-input
+          v-model="queryParams.alarmTypeName"
+          placeholder="请输入报警类型"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="报警编号" prop="alarmType">
+        <el-input
+          v-model="queryParams.alarmType"
+          placeholder="请输入报警编号"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="historyalarmList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="报警类型名称" align="center" prop="alarmTypeName" />
+      <el-table-column label="报警编号" align="center" prop="alarmType" />
+      <el-table-column label="归属" align="center" prop="affiliationName" />
+      <el-table-column label="是否保存" align="center" prop="isSave">
+        <template slot-scope="scope">
+          {{ scope.row.isSave == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="禁用" align="center" prop="status">
+        <template slot-scope="scope">
+          {{ scope.row.status == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="是否故障" align="center" prop="failure">
+        <template slot-scope="scope">
+          {{ scope.row.failure == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="报警等级" align="center" prop="alarmGrade">
+        <template slot-scope="scope">
+          {{ scope.row.alarmGrade == "1" ? "严重" : (scope.row.alarmGrade == "2" ? "一般" : "轻微") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="报警风暴(秒)" align="center" prop="alarmStorm" />
+      <el-table-column label="处理页面" align="center" prop="urlNameKey">
+        <template slot-scope="scope">默认</template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listHistoryalarm } from "@/api/business/ai/historyalarm";
+
+export default {
+  name: "Historyalarm",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 报警类型表格数据
+      historyalarmList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        alarmTypeName: null,
+        alarmType: null,
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询报警类型列表 */
+    getList() {
+      this.loading = true;
+      listHistoryalarm(this.queryParams).then(response => {
+        this.historyalarmList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    }
+  }
+};
+</script>

+ 381 - 0
monitor_ui/src/views/business/ai/singletype/index.vue

@@ -0,0 +1,381 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="报警类型" prop="alarmTypeName">
+        <el-input
+          v-model="queryParams.alarmTypeName"
+          placeholder="请输入报警类型"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="报警编号" prop="alarmType">
+        <el-input
+          v-model="queryParams.alarmType"
+          placeholder="请输入报警编号"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['ai:singletype:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['ai:singletype:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['ai:singletype:export']"
+        >导出</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleAsync"
+          v-hasPermi="['ai:singletype:list']"
+        >推送</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleAsyncDH"
+          v-hasPermi="['ai:singletype:list']"
+        >拉取</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="singletypeList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="报警类型名称" align="center" prop="alarmTypeName" />
+      <el-table-column label="报警编号" align="center" prop="alarmType" />
+      <el-table-column label="归属" align="center" prop="affiliationName" />
+      <el-table-column label="是否保存" align="center" prop="isSave">
+        <template slot-scope="scope">
+          {{ scope.row.isSave == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="禁用" align="center" prop="status">
+        <template slot-scope="scope">
+          {{ scope.row.status == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="是否故障" align="center" prop="failure">
+        <template slot-scope="scope">
+          {{ scope.row.failure == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="报警等级" align="center" prop="alarmGrade">
+        <template slot-scope="scope">
+          {{ scope.row.alarmGrade == "1" ? "严重" : (scope.row.alarmGrade == "2" ? "一般" : "轻微") }}
+        </template>
+      </el-table-column>
+      <el-table-column label="报警风暴(秒)" align="center" prop="alarmStorm" />
+      <el-table-column label="处理页面" align="center" prop="urlNameKey">
+        <template slot-scope="scope">默认</template>
+      </el-table-column>
+      <el-table-column label="同步状态" align="center" prop="syncStatus">
+        <template slot-scope="scope">
+          {{ scope.row.syncStatus == "0" ? "否" : "是" }}
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['ai:singletype:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['ai:singletype:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改报警类型对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+        <el-form-item label="报警类型名称" prop="alarmTypeName">
+          <el-input v-model="form.alarmTypeName" placeholder="请输入报警类型名称" maxlength="64" />
+        </el-form-item>
+        <el-form-item label="报警编号" prop="alarmType">
+          <el-input-number v-model="form.alarmType" placeholder="请输入报警编号" controls-position="right" :min="0" :max="2147483647" :disabled="title == '修改报警类型'" style="width: 330px" />
+        </el-form-item>
+        <el-form-item label="归属" prop="affiliation">
+          <el-select v-model="form.affiliation" placeholder="请选择归属" style="width: 350px">
+            <el-option
+              v-for="affiliation in affiliationList"
+              :key="affiliation.affiliation"
+              :label="affiliation.affiliationName"
+              :value="affiliation.affiliation"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="处理页面" prop="urlNameKey">
+          <el-select v-model="form.urlNameKey" disabled style="width: 350px">
+            <el-option value="default subsystem" label="默认"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="报警等级" prop="language">
+          <el-select v-model="form.alarmGrade" style="width: 350px">
+            <el-option value="1" label="严重"></el-option>
+            <el-option value="2" label="一般"></el-option>
+            <el-option value="3" label="轻微"></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="报警风暴" prop="alarmStorm">
+          <el-input-number v-model="form.alarmStorm" placeholder="请输入报警风暴" controls-position="right" :min="0" :max="999" style="width: 330px" />
+          <font size="3">秒</font>
+        </el-form-item>
+        <el-form-item label="是否保存">
+          <el-switch v-model="form.isSave" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+        <el-form-item label="禁用">
+          <el-switch v-model="form.status" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+        <el-form-item label="是否故障">
+          <el-switch v-model="form.failure" active-value="1" inactive-value="0"></el-switch>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listSingletype, getSingletype, delSingletype, addSingletype, updateSingletype, listAffiliation, syncSingletype, syncSingletypeDH } from "@/api/business/ai/singletype";
+import { checkNonnegativeInt } from "@/api/system/rules"
+
+export default {
+  name: "Singletype",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 报警类型表格数据
+      singletypeList: [],
+      affiliationList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        alarmTypeName: null,
+        alarmType: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        alarmTypeName: [
+          { required: true, message: "报警类型名称不能为空", trigger: "blur" }
+        ],
+        alarmType: [
+          { required: true, message: "报警编号不能为空", trigger: "blur" },
+          { validator: checkNonnegativeInt, trigger: "blur" }
+        ],
+        affiliation: [
+          { required: true, message: "归属不能为空", trigger: "change" }
+        ],
+        alarmStorm: [
+          { required: true, message: "报警风暴不能为空", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getAffiliationList();
+  },
+  methods: {
+    /** 查询报警类型列表 */
+    getList() {
+      this.loading = true;
+      listSingletype(this.queryParams).then(response => {
+        this.singletypeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getAffiliationList() {
+      listAffiliation().then(response => {
+        this.affiliationList = response.data;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        alarmTypeName: null,
+        alarmType: null,
+        affiliation: null,
+        urlNameKey: "default subsystem",
+        alarmGrade: "2",
+        alarmStorm: 10,
+        isSave: "1",
+        status: "0",
+        failure: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加报警类型";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getSingletype(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改报警类型";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          this.form.affiliationName = this.affiliationList.filter(item => this.form.affiliation == item.affiliation)[0].affiliationName
+          if (this.form.id != null) {
+            updateSingletype(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addSingletype(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除报警类型名称为"' + row.alarmTypeName + '"的数据项?').then(function() {
+        return delSingletype(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('ai/singletype/export', {
+        ...this.queryParams
+      }, `singletype_${new Date().getTime()}.xlsx`)
+    },
+    handleAsync() {
+      this.loading = true;
+      syncSingletype().then(response => {
+        this.$modal.msgSuccess("推送成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    },
+    handleAsyncDH() {
+      this.loading = true;
+      syncSingletypeDH().then(response => {
+        this.$modal.msgSuccess("同步成功");
+        this.loading = false;
+        this.getList();
+      }).catch(error => {
+        this.loading = false;
+      });
+    }
+  }
+};
+</script>

+ 248 - 0
monitor_ui/src/views/business/ai/zeroshot/index.vue

@@ -0,0 +1,248 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="96px">
+      <el-form-item label="来源设备" prop="channelCodeList">
+        <treeselect ref="tree" v-model="queryParams.channelCodeList" :options="options" multiple value-consists-of="LEAF_PRIORITY" placeholder="请选择来源设备" style="width: 280px" />
+      </el-form-item>
+      <el-form-item label="日期范围" prop="dateRange">
+        <el-date-picker
+          v-model="queryParams.dateRange"
+          type="datetimerange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          style="width: 330px">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="报警类型" prop="alarmType">
+        <el-select v-model="queryParams.alarmType" placeholder="请选择报警类型" clearable>
+          <el-option
+            v-for="alarmType in alarmTypeList"
+            :key="alarmType.alarmType"
+            :label="alarmType.alarmTypeName"
+            :value="alarmType.alarmType"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="AI研判状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择AI研判状态" clearable>
+          <el-option value="1" label="AI研判异常"></el-option>
+          <el-option value="10" label="AI研判:非报警事件"></el-option>
+          <el-option value="11" label="AI研判:报警事件"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="人工研判状态" prop="customStatus">
+        <el-select v-model="queryParams.customStatus" placeholder="请选择人工研判状态" clearable>
+          <el-option value="0" label="人工研判:非报警事件"></el-option>
+          <el-option value="1" label="人工研判:报警事件"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row v-loading="loading">
+      <el-col :span="6" v-for="(item, index) in zeroshotList" :key="item.id">
+        <el-card :body-style="{ padding: '0px' }">
+          <img :src="item.picture" class="image">
+          <div style="padding: 14px;">
+            <div>{{ item.channelName }}</div>
+            <div>
+              {{ item.alarmTypeName }}
+              <time class="time">{{ item.createTime }}</time>
+            </div>
+            <div>{{ item.status == "1" ? "AI研判异常" : (item.status == "10" ? "AI研判:非报警事件" : "人工研判:报警事件") }}</div>
+            <div class="bottom clearfix">
+              <el-button type="text" class="button" @click="handlePrompt(item.prompt)">Prompt</el-button>
+              <el-button type="text" class="button" @click="handleDetail(item.aiResult)">AI研判详情</el-button>
+            </div>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.page"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <el-dialog :title="title" :visible.sync="open" width="30%" append-to-body>
+      <span>{{ this.info }}</span>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="cancel">取 消</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listZeroshot } from "@/api/business/ai/zeroshot";
+import { channelTree, listAlarmType } from "@/api/business/ai/alarmanalysis";
+import Treeselect from "@riophae/vue-treeselect"
+import "@riophae/vue-treeselect/dist/vue-treeselect.css"
+
+export default {
+  name: "Zeroshot",
+  components: { Treeselect },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 报警类型表格数据
+      zeroshotList: [],
+      alarmTypeList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      info: "",
+      // 查询参数
+      queryParams: {
+        page: 1,
+        pageSize: 12,
+        channelCodeList: [],
+        startTime: null,
+        endTime: null,
+        dateRange: null,
+        alarmType: null,
+        statuss: [],
+        status: null,
+        customStatuss: [],
+        customStatus: null
+      },
+      options: [],
+      defaultProps: {
+        children: "children",
+        label: "label"
+      },
+    };
+  },
+  created() {
+    this.getChannelList();
+    let now = new Date(), before = new Date(now.getTime() - 6 * 60 * 60 * 1000);
+    this.queryParams.dateRange = [`${before.getFullYear()}-${('0' + (before.getMonth() + 1)).slice(-2)}-${('0' + before.getDate()).slice(-2)} ${('0' + before.getHours()).slice(-2)}:${('0' + before.getMinutes()).slice(-2)}:${('0' + before.getSeconds()).slice(-2)}`,
+      `${now.getFullYear()}-${('0' + (now.getMonth() + 1)).slice(-2)}-${('0' + now.getDate()).slice(-2)} ${('0' + now.getHours()).slice(-2)}:${('0' + now.getMinutes()).slice(-2)}:${('0' + now.getSeconds()).slice(-2)}`]
+    this.getAlarmTypeList();
+    this.getList();
+  },
+  methods: {
+    /** 查询报警类型列表 */
+    getList() {
+      if (this.queryParams.dateRange && this.queryParams.dateRange.length) {
+        if (24 * 60 * 60 * 1000 < (new Date(this.queryParams.dateRange[1]).getTime() - new Date(this.queryParams.dateRange[0]).getTime())) {
+          this.$modal.msgSuccess("查询开始时间和结束时间只能在24小时之内");
+          return
+        }
+      } else {
+        this.$modal.msgSuccess("请先选择日期范围");
+        return
+      }
+      this.queryParams.startTime = this.queryParams.dateRange[0];
+      this.queryParams.endTime = this.queryParams.dateRange[1]
+      if (this.queryParams.status) {
+        this.queryParams.statuss = this.queryParams.status.split(",");
+      }
+      if (this.queryParams.customStatus) {
+        this.queryParams.customStatuss = this.queryParams.customStatus.split(",");
+      }
+      this.loading = true;
+      listZeroshot(this.queryParams).then(response => {
+        this.zeroshotList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    getChannelList() {
+      channelTree().then(response => {
+        this.options = this.handleTreeView(response.data).map(channel => {
+          if (channel.children && channel.children.length) {
+            channel.children = channel.children.map(item => {
+              delete item.children
+              return item
+            })
+          }
+          return channel
+        })
+      });
+    },
+    getAlarmTypeList() {
+      listAlarmType().then(response => {
+        this.alarmTypeList = response.data;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.page = 1;
+      this.queryParams.statuss = [];
+      this.queryParams.customStatuss = [];
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    handlePrompt(data) {
+      this.info = data;
+      this.open = true;
+      this.title = "Prompt";
+    },
+    handleDetail(data) {
+      this.info = data;
+      this.open = true;
+      this.title = "AI研判详情";
+    },
+  }
+};
+</script>
+
+<style>
+  .time {
+    font-size: 13px;
+    color: #999;
+    float: right;
+  }
+
+  .bottom {
+    margin-top: 13px;
+    line-height: 12px;
+    float: right;
+  }
+
+  .button {
+    padding: 0;
+    float: right;
+  }
+
+  .image {
+    width: 100%;
+    display: block;
+    max-height: 232px;
+  }
+
+  .clearfix:before,
+  .clearfix:after {
+    display: table;
+    content: "";
+  }
+
+  .clearfix:after {
+    clear: both
+  }
+</style>