Commit 89befeef authored by 胡占生's avatar 胡占生 🇨🇳
Browse files

Merge branch 'developer' of http://git.censoft.com.cn/ai-yunshou/ai-yunshou-vue into developer

parents e48045d6 0dbe1947
Loading
Loading
Loading
Loading

src/assets/movie.mp4

0 → 100644
+311 KiB

File added.

No diff preview for this file type.

+331 −151
Original line number Original line Diff line number Diff line
<template>
<template>
    <el-dialog
  <el-dialog v-model="algorithmManage.visible.value" width="60%" append-to-body>
      v-model="open"
      width="1000px"
      append-to-body
    >
    <template v-slot:header>
    <template v-slot:header>
        <div class="cleartitle" style="display: flex;justify-content: flex-start;align-items: center;">
      <div
          <img src="@/assets/images/logo_video.png" width="25px" alt=""> <span>{{title}}</span>
        class="cleartitle"
        style="display: flex; justify-content: flex-start; align-items: center"
      >
        <img src="@/assets/images/logo_video.png" width="25px" alt="" />
        <span>{{ title }}</span>
      </div>
      </div>
    </template>
    </template>
    <el-row>
    <el-row>
      <el-col :span="12">
      <el-col :span="12">
          <el-row :gutter="10" class="mb8" style="justify-content: space-between;">
        <el-row :gutter="10" class="mb8" style="justify-content: space-between">
          <el-col :span="1.5">
          <el-col :span="1.5">
              <div class="form-title" style="display: flex;justify-content: flex-start;align-items: center;">
            <div
              class="form-title"
              style="
                display: flex;
                justify-content: flex-start;
                align-items: center;
              "
            >
              <span>基础信息</span>
              <span>基础信息</span>
            </div>
            </div>
          </el-col>
          </el-col>
          <el-col :span="6.8" style="display: flex;">
          <el-col :span="6.8" style="display: flex"> </el-col>
          </el-col>
        </el-row>
        </el-row>
         <el-card class="left-list">
        <div class="left-form">
          <el-table v-loading="loading" :data="algLevelList">
          <el-form
            <el-table-column label="告警等级名称" align="center" prop="alarmName" />
            ref="algLevelRef"
            <el-table-column label="告警等级颜色" align="center" prop="alarmColor"> 
            :model="unref(algorithmManage.form)"
            :rules="rules"
            label-position="left"
            label-width="100px"
            class="demo-form-inline"
          >
            <el-form-item
              label="摄像头名称"
              prop="deviceId"
              v-if="unref(device.list).length"
            >
              <el-select
                v-model="unref(algorithmManage.form).deviceId"
                placeholder="请选择摄像头"
                @change="handleDeviceChange"
              >
                <el-option
                  v-for="item in unref(device.list)"
                  :key="item.id"
                  :label="item.deviceName"
                  :value="item.id"
                ></el-option>
              </el-select>
            </el-form-item>
            <!-- RTSP地址 -->
            <el-form-item label="RTSP地址" prop="vedioUrl">
              <el-input
                v-model="unref(algorithmManage.form).videoUrl"
                readonly
              />
            </el-form-item>
            <el-form-item label="是否重新拉流" prop="restartFlow">
              <el-switch
                v-model="unref(algorithmManage.form).restartFlow"
                inline-prompt
                active-text="是"
                inactive-text="否"
                active-value="true"
              />
            </el-form-item>
            <el-form-item label="重新拉流时间" prop="reStreamingTime">
              <el-date-picker
                v-model="unref(algorithmManage.form).reStreamingTime"
                type="datetime"
              />
            </el-form-item>
          </el-form>
        </div>
        <div class="left-list">
          <el-table
            :data="
              unref(algorithmManage.form).aiRegionalLocationList ||
              aiAlgorithm.list.value
            "
          >
            <el-table-column
              label="算法名称"
              align="center"
              prop="algorithmName"
            />
            <el-table-column label="选择" align="center" prop="alarmColor">
              <template #default="scope">
              <template #default="scope">
                <span>
                <span>
                  <el-tag type="success" :style="{backgroundColor: scope.row.alarmColor,width:'50px'}">{{ }}</el-tag>
                  <el-switch
                    v-model="scope.row.status"
                    active-value="0"
                    inactive-value="1"
                  ></el-switch>
                </span>
                </span>
              </template>
              </template>
            </el-table-column>
            </el-table-column>
            <el-table-column label="告警等级展示方式" align="center" prop="alarmShowType" />
            <el-table-column
            <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
              label="识别区域"
              width="180"
              align="center"
              class-name="small-padding fixed-width"
            >
              <template #default="scope">
              <template #default="scope">
                  <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']">修改</el-button>
                <el-button
                  <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']">删除</el-button>
                  link
                  type="primary"
                  @click="beginDraw(scope.row)"
                  v-hasPermi="['system:post:edit']"
                  >绘制</el-button
                >
                <el-button
                  link
                  type="primary"
                  @click="aiConfig(scope.$index,scope.row)"
                  v-hasPermi="['system:post:remove']"
                  >配置</el-button
                >
              </template>
              </template>
            </el-table-column>
            </el-table-column>
          </el-table>
          </el-table>
         </el-card>
        </div>
      </el-col>
      <el-col :span="11" :offset="1" class="right-draw">
        <div>
          <el-button
            @click="getPhoto"
            v-if="!algorithmManage.form.value.liveMap"
            >拍照取图</el-button
          >
          <el-button @click="getNewPhoto" v-else>重新取图</el-button>
          <el-button @click="clearDraw">重绘标记</el-button>
          <el-button @click="++drawIndex">重绘下一个</el-button>
        </div>
        <div class="right-draw-content">
          <img
            v-if="algorithmManage.form.value.liveMap"
            :src="algorithmManage.form.value.liveMap"
            class="drawImg"
            alt=""
          />
          <template v-else>
            <video controls ref="videoEle" class="drawImg">
              <source src="@/assets/movie.mp4" type="video/mp4" />
            </video>
            <canvas id="canvas"></canvas>
          </template>
          <svg
            @click="pointDraw"
            v-if="drawId && algorithmManage.form.value.liveMap"
            class="drawSvg"
          >
            <title>多边形</title>
            <polygon
              :fill="item.fill"
              stroke="blue"
              stroke-width="1"
              v-for="item in graph[drawId]"
              :points="item.point"
              :key="item.key"
            />
          </svg>
        </div>
        <div class="right">
          <el-button type="primary" @click="submit">确认</el-button>
          <el-button type="primary" plain @click="algorithmManage.toClose"
            >取消</el-button
          >
        </div>
      </el-col>
      </el-col>
    </el-row>
    </el-row>
       
  </el-dialog>
  <el-dialog title="算法配置" v-model="aiAlgorithm.visible.value" width="30%">
    <el-form
      ref="algorithmManage.formRef"
      :model="aiAlgorithm.form"
      label-width="80px"
    >
      <el-form-item label="算法名称" prop="algorithmName">
        <el-input v-model="unref(aiAlgorithm.form).algorithmName" readonly />
      </el-form-item>
      <el-form-item label="告警间隔" prop="alarmInterval">
        <el-input
          placeholder="单位/秒"
          v-model="unref(aiAlgorithm.form).alarmInterval"
        />
      </el-form-item>
      <el-form-item label="行为持续多长时间报警" prop="continueWarnTime">
        <el-input
          placeholder="单位/秒"
          v-model="unref(aiAlgorithm.form).continueWarnTime"
        />
      </el-form-item>
      <el-form-item label="识别间隔(跳帧)" prop="identifyIntervals">
        <el-input v-model="unref(aiAlgorithm.form).identifyIntervals" />
      </el-form-item>
      <el-form-item label="标签阈值" prop="labelThreshold">
        <el-input v-model="unref(aiAlgorithm.form).labelThreshold" />
      </el-form-item>
      <div class="right">
        <el-button type="primary" @click="sureConfig">确认</el-button>
        <el-button type="primary" plain @click="aiAlgorithm.toClose"
          >取消</el-button
        >
      </div>
    </el-form>
  </el-dialog>
  </el-dialog>
</template>
</template>


<script setup>
<script setup>
import { listAlgLevel, detailAlgLevel , addAlgLevel, updateAlgLevel, deleteAlgLevel} from "@/api/algorithmList/algorithmDown.js";
import { reactify } from "@vueuse/core";
const { proxy } = getCurrentInstance();
import { onMounted, ref, unref } from "vue";
const emit = defineEmits();
const { algorithmManage } = defineProps({ algorithmManage: Object });
const open = ref(false);
import { useIndex } from "../hooks";
const openAdd = ref(false);
import { colors, drawImage } from "../utils";
const butLoading = ref(false);
const device = useIndex({
const title = ref("");
  list: "/yunshou/aiDevice/list",
const titleLevel = ref("");
const loading = ref(true);
const algLevelList = ref([]);
const data = reactive({
  form: {},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    postCode: undefined,
  },
  rules: {
    alarmName: [{ required: true, message: "告警等级名称不能为空", trigger: "blur" }],
    postCode: [{ required: true, message: "岗位编码不能为空", trigger: "blur" }],
    postSort: [{ required: true, message: "岗位顺序不能为空", trigger: "blur" }],
  }
});
});

const aiAlgorithm = useIndex({
const { queryParams, form, rules } = toRefs(data);
  list: "/yunshou/aiAlgorithmConfig/list",

  detail: "/yunshou/aiAlgorithmConfig/",
/** 表单重置 */
});
function reset() {
function handleDeviceChange(e, index) {
  butLoading.value = false;
  const d = device.list.value.find((x) => x.id == e);
  form.value = {
  algorithmManage.form.value.videoUrl = d.videoUrl;
    id: undefined,
    alarmName: undefined,
    alarmColor: '#409EFF',
    alarmShowType: []
  };
  proxy.resetForm("algLevelRef");
}
}


/** 查询算法列表 */
function submit() {
function getLevelList() {
  let algorithms = [];
  loading.value = true;
  if (algorithmManage.form.value.id) {
  listAlgLevel(queryParams.value).then(response => {
    algorithms = unref(algorithmManage.form).aiRegionalLocationList;
    algLevelList.value = response.rows
  } else {
    loading.value = false;
    algorithmManage.form.value.runningState = 0;
    unref(aiAlgorithm.list).forEach((val) => {
      algorithms.push({
        algorithmId: val.id,
        drawingArea: graph[val.id]
          ? JSON.stringify(graph[val.id])
          : val.drawingArea
          ? val.drawingArea
          : "",
        status: val.status,
        ...val.params,
      });
    });
    });
  }
  }

  algorithmManage.form.value.algorithms = algorithms;
/** 新增按钮操作 */
  algorithmManage.toSubmit();
function handleAdd() {
  open.value = true;
  title.value = "告警等级列表";
  getLevelList()
}
/** 等级新增按钮操作 */
function handleLevelAdd() {
  reset();
  openAdd.value = true;
  titleLevel.value = "新增告警等级";
}
}

const configIndex = ref(0);
/** 修改按钮操作 */
function aiConfig(index,e) {
function handleUpdate(row) {
  configIndex.value = index;
  reset();
  const current = unref(aiAlgorithm.list)[index];
  const id = row.id || ids.value;
  aiAlgorithm.form.value = algorithmManage.form.value.id
  detailAlgLevel(id).then(response => {
    ? e
    form.value = response.data;
    : {
    form.value.alarmShowType=form.value.alarmShowType.split(',')
        algorithmName: current.algorithmName,
    openAdd.value = true;
      };
    titleLevel.value = "修改告警等级";
  aiAlgorithm.visible.value = true;
  });
}
}

// 确认配置
/** 提交按钮 */
function sureConfig() {
function submitForm() {
  if (algorithmManage.form.value.id) {
  proxy.$refs["algLevelRef"].validate(valid => {
    const current = unref(algorithmManage.form).aiRegionalLocationList[
    if (valid) {
      configIndex.value
      form.value.alarmShowType=form.value.alarmShowType.join()
    ];
      butLoading.value = true;
    unref(algorithmManage.form).aiRegionalLocationList[configIndex.value] = {
      if (form.value.id != undefined) {
      ...current,
        updateAlgLevel(form.value).then(response => {
      ...unref(aiAlgorithm.form),
          proxy.$modal.msgSuccess("修改成功");
    };
          openAdd.value = false;
          butLoading.value = false;
          getLevelList();
        });
  } else {
  } else {
        addAlgLevel(form.value).then(response => {
    unref(aiAlgorithm.list)[configIndex.value].params = unref(aiAlgorithm.form);
          proxy.$modal.msgSuccess("新增成功");
          openAdd.value = false;
          butLoading.value = false;
          getLevelList();
        });
  }
  }
  aiAlgorithm.toClose();
}
}
  });
let drawId = ref();
let drawIndex = ref(0);
const graph = reactive({});

const videoEle = ref(null);
function getPhoto() {
  algorithmManage.form.value.liveMap = drawImage(videoEle.value);
}
/* 重新取图 */
function getNewPhoto() {
  unref(algorithmManage.form).liveMap = "";
  for (let key in graph) {
    graph[key] = [];
  }
}
function beginDraw(e) {
  drawId.value = e.id;
  if (typeof e.drawingArea == "string" && e.drawingArea) {
    graph[e.id] = JSON.parse(e.drawingArea);
  }
  drawIndex.value = graph[drawId.value] ? graph[drawId.value].length : 0;
}
function clearDraw() {
  graph[drawId.value] = [];
  drawIndex.value = 0;
}
function pointDraw(e) {
  if (!graph[drawId.value]) {
    graph[drawId.value] = [];
  }
  if (!graph[drawId.value][drawIndex.value]) {
    graph[drawId.value][drawIndex.value] = {
      fill: colors(),
      point: "",
    };
  }
  graph[drawId.value][drawIndex.value].point += `${e.offsetX},${e.offsetY} `;
}
}
/** 取消按钮 */
function cancel() {
  openAdd.value = false;
  reset();
}
/** 删除按钮操作 */
function handleDelete(row) {
    const id = row.id || ids.value;
    proxy.$modal.confirm('删除后,已配置的告警等级将被清空').then(function() {
      return deleteAlgLevel(id);
    }).then(() => {
      getLevelList();
      proxy.$modal.msgSuccess("删除成功");
    }).catch(() => {});
  }
defineExpose({ handleAdd , handleUpdate })
</script>
</script>


<style scoped lang="scss">
<style scoped lang="scss">
@@ -174,8 +332,30 @@ defineExpose({ handleAdd , handleUpdate })
  display: inline-block;
  display: inline-block;
  width: 10px; /* 矩形的宽度 */
  width: 10px; /* 矩形的宽度 */
  height: 30px; /* 矩形的高度 */
  height: 30px; /* 矩形的高度 */
      background-color: #1890FF; /* 矩形的背景颜色 */
  background-color: #1890ff; /* 矩形的背景颜色 */
  margin-right: 10px;
  margin-right: 10px;
  border-radius: 8px;
  border-radius: 8px;
}
}
.drawImg {
  width: 100%;
  height: 100%;
}
.right {
  text-align: right;
}
.right-draw {
  display: grid;
  grid-template-rows: 30px 1fr 30px;
  gap: 20px;
  .right-draw-content {
    position: relative;
    svg {
      position: absolute;
      left: 0;
      top: 0;
      height: 100%;
      width: 100%;
    }
  }
}
</style>
</style>
 No newline at end of file
+131 −0
Original line number Original line Diff line number Diff line
import { onMounted, ref, watch } from "vue";
import request from "@/utils/request";
import { ElMessageBox } from "element-plus";
function useIndex(apis, callback) {
  const visible = ref(false);
  const search = ref({});
  const form = ref({
    regionName: "",
  });
  const list = ref([]);
  const page = ref({
    pageNum: 1,
    pageSize: 10,
    total: 0,
  });

  watch(
    () => visible.value,
    (newVal) => {
      if (newVal == false) {
        form.value = {};
      }
    }
  );

  watch([() => page.value.pageNum, () => page.value.pageSize], (val) => {
    getList();
  });
  function toEdit(data) {
    getDetail(data.id);
    visible.value = true;
  }
  function toAdd() {
    visible.value = true;
  }
  function toDel(data, immclose = true) {
    //弹框确认
    return new Promise((resolve) => {
      ElMessageBox.confirm("是否删除?").then(() => {
        request({
          url: apis.delete + data.id,
          method: "delete",
        }).then((res) => {
          if (immclose) {
            visible.value = false;
            getList();
          }
          resolve();
        });
      });
    });
  }
  function getList(params) {
    request({
      url: apis.list,
      method: "get",
      params: { ...params, ...page.value, ...search.value },
    }).then((res) => {
      list.value = res.data || res.rows;
      page.value.total = res.total;
    });
  }
  function getDetail(id) {
    return request({
      url: apis.detail + id,
      method: "get",
    }).then((res) => {
      callback && callback(res);
      form.value = res.data;
      return res;
    });
  }
  function toSubmit(immclose = true) {
    return new Promise((resolve, reject) => {
      if (form.value.id) {
        request({
          url: apis.edit,
          method: "put",
          data: form.value,
        }).then((res) => {
          if (immclose) {
            visible.value = false;
            getList();
          }
          resolve();
        });
      } else {
        request({
          url: apis.add,
          method: "post",
          data: form.value,
        }).then((res) => {
          if (immclose) {
            visible.value = false;
            getList();
          }
          resolve();
        });
      }
    });
  }

  function toClose() {
    visible.value = false;
  }
  function toOpen() {
    visible.value = false;
  }
  onMounted(() => {
    if (apis.list) {
      getList();
    }
  });

  return {
    visible,
    form,
    list,
    page,
    toEdit,
    toAdd,
    toDel,
    getDetail,
    toClose,
    toSubmit,
    getList,
    toOpen,
  };
}

export { useIndex };
+20 −0
Original line number Original line Diff line number Diff line
.areaNodes {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.pagination-right {
  display: flex;
  justify-content: flex-end;
  width: 100%;
  margin-top: 20px;
}
.el-tree {
  :deep(.is-current) {
    & > .el-tree-node__content {
         background-color: var(--el-color-primary-light-9);
    }
  }
}
+327 −149

File changed.

Preview size limit exceeded, changes collapsed.

Loading