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

fix: 算法详情 改为进度条显示,算法文件上传对接联调,页面调整

parent 74db2f5f
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
/** 
 * 新增算法文件
 * @param {object} params 算法文件
 * @param {string} params.createBy 
 * @param {object} params.createTime 
 * @param {object} params.params 
 * @param {string} params.remark 
 * @param {string} params.searchValue 
 * @param {string} params.updateBy 
 * @param {object} params.updateTime 
 * @param {string} params.id 主键
 * @param {string} params.algorithmId 算法id
 * @param {string} params.algorithmName 算法名称
 * @param {string} params.algorithmStatus 算法状态 0上传中 1已发布
 * @param {string} params.md5Result MD5核对结果
 * @param {string} params.algorithmFile 算法文件
 * @param {string} params.fileSize 文件大小
 * @returns
 */
import request from '@/utils/request'

// 查询算法文件
export function listFile(query) {
    return request({
      url: '/yunshou/aiAlgorithmFile/list',
      method: 'get',
      params: query
    })
  }
  
// 查询算法文件x详情
export function detailFile(id) {
    return request({
      url: `/yunshou/aiAlgorithmFile/${id}`,
      method: 'get',
    })
  }
  

// 新增算法文件
export function addFile(data) {
  return request({
    url: '/yunshou/aiAlgorithmFile',
    method: 'post',
    data: data
  })
}

// 修改算法文件
export function updateFile(data) {
    return request({
      url: '/yunshou/aiAlgorithmFile',
      method: 'put',
      data: data
    })
  }
  

// 删除算法文件
export function deleteFile(ids) {
  return request({
    url: `/yunshou/aiAlgorithmFile/${ids}`,
    method: 'delete'
  })
}
+210 −0
Original line number Diff line number Diff line
<!-- 算法文件上传 -->
<template>
  <div class="upload-file">
    <el-upload
      multiple
      :action="uploadFileUrl"
      :before-upload="handleBeforeUpload"
      :file-list="fileList"
      :limit="limit"
      :on-error="handleUploadError"
      :on-exceed="handleExceed"
      :on-success="handleUploadSuccess"
      :show-file-list="false"
      :headers="headers"
      class="upload-file-uploader"
      ref="fileUpload"
    >
      <!-- 上传按钮 -->
      <el-button type="primary">选取文件</el-button>
    </el-upload>
    <!-- 上传提示 -->
    <div class="el-upload__tip" v-if="showTip">
      请上传
      <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
      <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
      的文件
    </div>
    <!-- 文件列表 -->
    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
      <li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
        <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
        </el-link>
        <div class="ele-upload-list__item-content-action">
          <el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
        </div>
      </li>
    </transition-group>
  </div>
</template>

<script setup>
import { getToken } from "@/utils/auth";

const props = defineProps({
  modelValue: [String, Object, Array],
  // 数量限制
  limit: {
    type: Number,
    default: 1,
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 1024,
  },
  // 文件类型, 例如['png', 'jpg', 'jpeg']
  fileType: {
    type: Array,
    default: () => [],
  },
  // 是否显示提示
  isShowTip: {
    type: Boolean,
    default: true
  }
});

const { proxy } = getCurrentInstance();
const emit = defineEmits();
const number = ref(0);
const uploadList = ref([]);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传文件服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const nowFileSize = ref('');
const showTip = computed(
  () => props.isShowTip && (props.fileType || props.fileSize)
);

watch(() => props.modelValue, val => {
  if (val) {
    let temp = 1;
    // 首先将值转为数组
    const list = Array.isArray(val) ? val : props.modelValue.split(',');
    // 然后将数组转为对象数组
    fileList.value = list.map(item => {
      if (typeof item === "string") {
        item = { name: item, url: item };
      }
      item.uid = item.uid || new Date().getTime() + temp++;
      return item;
    });
  } else {
    fileList.value = [];
    return [];
  }
},{ deep: true, immediate: true });

// 上传前校检格式和大小
function handleBeforeUpload(file) {
  nowFileSize.value = (file.size / 1024 / 1024).toFixed(2);
  // 校检文件类型
  if (props.fileType.length) {
    const fileName = file.name.split('.');
    const fileExt = fileName[fileName.length - 1];
    const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
    if (!isTypeOk) {
      proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
      return false;
    }
  }
  // 校检文件大小
  if (props.fileSize) {
    const isLt = file.size / 1024 / 1024 < props.fileSize;
    if (!isLt) {
      proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
      return false;
    }
  }
  proxy.$modal.loading("正在上传文件,请稍候...");
  number.value++;
  return true;
}

// 文件个数超出
function handleExceed() {
  proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}

// 上传失败
function handleUploadError(err) {
  proxy.$modal.msgError("上传文件失败");
}

// 上传成功回调
function handleUploadSuccess(res, file) {
  if (res.code === 200) {
    uploadList.value.push({ name: res.fileName, url: res.fileName });
    uploadedSuccessfully();
  } else {
    number.value--;
    proxy.$modal.closeLoading();
    proxy.$modal.msgError(res.msg);
    proxy.$refs.fileUpload.handleRemove(file);
    uploadedSuccessfully();
  }
}

// 删除文件
function handleDelete(index) {
  fileList.value.splice(index, 1);
  emit("update:modelValue", listToString(fileList.value),nowFileSize.value);
}

// 上传结束处理
function uploadedSuccessfully() {
  if (number.value > 0 && uploadList.value.length === number.value) {
    fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
    uploadList.value = [];
    number.value = 0;
    emit("update:modelValue", listToString(fileList.value),nowFileSize.value);
    proxy.$modal.closeLoading();
  }
}

// 获取文件名称
function getFileName(name) {
  // 如果是url那么取最后的名字 如果不是直接返回
  if (name.lastIndexOf("/") > -1) {
    return name.slice(name.lastIndexOf("/") + 1);
  } else {
    return name;
  }
}

// 对象转成指定字符串分隔
function listToString(list, separator) {
  let strs = "";
  separator = separator || ",";
  for (let i in list) {
    if (list[i].url) {
      strs += list[i].url + separator;
    }
  }
  return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
</script>

<style scoped lang="scss">
.upload-file-uploader {
  margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
  border: 1px solid #e4e7ed;
  line-height: 2;
  margin-bottom: 10px;
  position: relative;
}
.upload-file-list .ele-upload-list__item-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: inherit;
}
.ele-upload-list__item-content-action .el-link {
  margin-right: 10px;
}
</style>
+215 −0
Original line number Diff line number Diff line
<template>
  <div>
    <el-row :gutter="10" class="mb8" style="justify-content: space-between;">
      <el-col :span="1.5">
        <div class="form-title" style="display: flex;justify-content: flex-start;align-items: center;">
          <span>算法维护</span>
        </div>
      </el-col>
      <el-col :span="6.8" style="display: flex;">
        <el-button type="success" plain icon="UploadFilled" @click="handleAdd">算法上传</el-button>
      </el-col>
    </el-row>
    <el-card class="left-list">
      <el-table :data="wrapList">
        <el-table-column type="expand">
          <template #default="scope">
            <div m="4">
              <el-tag v-for="item in scope.row.labelList" :key="item.id" :type="'primary'">{{ item.labelCode + ':' +
                item.labelThreshold }}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="文件名称" align="center" prop="algorithmName" />
        <el-table-column label="状态" align="center" prop="algorithmStatus" >
        <template #default="scope">
          <el-tag  :type="scope.row.algorithmStatus=='2'?'success':'primary'">{{ scope.row.algorithmStatus=='2'?'使用中':'已上传' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="MD5核对结果" align="center" prop="md5Result" />
        <el-table-column label="文件大小" align="center" prop="fileSize" />
        <el-table-column label="进度" align="center" prop="postSort" />
        <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
          <template #default="scope">
            <!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
                            >版本内容</el-button> -->
            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <el-dialog v-model="open" width="500px" append-to-body>
      <template v-slot:header>
        <div 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>
      </template>
      <el-row :gutter="10" class="mb8">
        <div class="form-title" style="display: flex;justify-content: flex-start;align-items: center;">
          <span>基础信息</span>
        </div>
      </el-row>
      <el-form ref="algRef" :model="form" :rules="rules" label-width="80px">
        <el-row>
          <el-col :span="24">
            <el-form-item label="算法标签" prop="labels">
              <el-input type="textarea" :rows="4" v-model="form.labels" placeholder="请输入算法标签" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="算法文件" prop="algorithmFile">
              <FileAlgUpload @update:modelValue="getFile" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { addFile, deleteFile, updateFile, listFile } from "@/api/algorithmList/algorithmFile.js";
import FileAlgUpload from '@/components/FileAlgUpload'
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const open = ref(false);
const title = ref("");
const total = ref("");
const wrapList = ref([]);
const props = defineProps({
  algId: {
    type: String,
    default: ''
  }
})
const data = reactive({
  form: {},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    postCode: undefined,
    postName: undefined,
    status: undefined
  },
  rules: {
    // postName: [{ required: true, message: "岗位名称不能为空", trigger: "blur" }],
  }
});

const { queryParams, form, rules } = toRefs(data);

/** 表单重置 */
function reset() {
  form.value = {

  };
  proxy.resetForm("algRef");
}


/** 获取文件列表*/
function getList() {
  listFile({ algorithmId: props.algId }).then(response => {
    console.log("🚀 ~ listFile ~ response:", response)
    wrapList.value = response.rows;
    total.value = response.total;
  });
}
/** 新增按钮操作 */
function handleAdd() {
  reset();
  open.value = true;
  title.value = "新增算法文件";
}

/** 修改按钮操作 */
function handleUpdate(row) {
  reset();
  const postId = row.id || ids.value;
  getPost(postId).then(response => {
    form.value = response.data;
    open.value = true;
    title.value = "修改算法";
  });
}

/** 删除按钮操作 */
function handleDelete(row) {
  const id = row.id || ids.value;
  proxy.$modal.confirm('是否确认删除算法文件名称为"' + row.algorithmName + '"的数据项?').then(function () {
    return deleteFile(id);
  }).then(() => {
    getList();
    proxy.$modal.msgSuccess("删除成功");
  }).catch(() => { });
}

/** 提交按钮 */
function submitForm() {
  proxy.$refs["algRef"].validate(valid => {
    if (valid) {
      form.value.algorithmId = props.algId;
      if (form.value.postId != undefined) {
        updateFile(form.value).then(response => {
          proxy.$modal.msgSuccess("修改成功");
          open.value = false;
          getList();
        });
      } else {
        addFile(form.value).then(response => {
          proxy.$modal.msgSuccess("新增成功");
          open.value = false;
          getList();
        });
      }
    }
  });
}
/** 取消按钮 */
function cancel() {
  open.value = false;
  reset();
}

function getFile(url,size) {
  console.log("🚀 ~ getFile ~ url:", url)
  console.log("🚀 ~ getFile ~ size:", size)
  form.value.algorithmFile = url
  form.value.fileSize = size + 'm'
}

defineExpose({ handleAdd, handleUpdate, getList })
</script>

<style scoped lang="scss">
.form-title {
  display: flex;
  align-items: center;
  /*for vertical align*/
  font-size: 16px;
  font-weight: 600;
  border-radius: 5px;
  padding: 0;
}

.form-title::before {
  content: "";
  display: inline-block;
  width: 10px;
  /* 矩形的宽度 */
  height: 30px;
  /* 矩形的高度 */
  background-color: #1890FF;
  /* 矩形的背景颜色 */
  margin-right: 10px;
  border-radius: 8px;
}
</style>
 No newline at end of file
+7 −62
Original line number Diff line number Diff line
@@ -201,59 +201,7 @@
                    </el-form-item>
                  </el-col>
                </el-row>
              <el-row :gutter="10" class="mb8" style="justify-content: space-between;">
                <el-col :span="1.5">
                  <div class="form-title" style="display: flex;justify-content: flex-start;align-items: center;">
                    <span>算法维护</span>
                  </div>
              </el-col>
              <el-col :span="6.8" style="display: flex;">
                  <!-- <el-button
                    type="primary"
                    plain
                    icon="Search"
                    @click="handleAdd"
                  >搜索</el-button>
                  <el-button
                    type="success"
                    plain
                    icon="Refresh"
                    @click="handleUpdate"
                  >版本更新</el-button> -->
                  <el-button
                    type="success"
                    plain
                    icon="UploadFilled"
                    @click="handleUpdate"
                  >算法上传</el-button>
              </el-col>
              </el-row>
              <el-card class="left-list">
                <el-table  :data="wrapList" >
                  <el-table-column type="expand">
                    <template #default="props">
                      <div m="4">
                        <p m="t-0 b-2">State: {{props + 'props.row.state' }}</p>
                        <p m="t-0 b-2">City: {{ 'props.row.city' }}</p>
                        <p m="t-0 b-2">Address: {{ 'props.row.address' }}</p>
                        <p m="t-0 b-2">Zip: {{ 'props.row.zip' }}</p>
                        <h3>Family</h3>
                      </div>
                    </template>
                  </el-table-column>
                  <el-table-column label="文件名称" align="center" prop="algorithmName" />
                  <el-table-column label="状态" align="center" prop="algorithmStatus" />
                  <el-table-column label="MD5核对结果" align="center" prop="md5Result" />
                  <el-table-column label="文件大小" align="center" prop="fileSize" />
                  <el-table-column label="进度" align="center" prop="postSort" />
                  <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
                      <template #default="scope">
                        <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:post:edit']">修改</el-button>
                        <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:post:remove']">删除</el-button>
                      </template>
                  </el-table-column>
                </el-table>
              </el-card>
                <AlgorithmFile :algId="form.id" ref="AlgorithmFileRef" />
            </el-tab-pane>
            <el-tab-pane label="算法详情" name="算法详情">
              <el-row :gutter="10" class="mb8">
@@ -505,6 +453,7 @@ import { addAlg, updateAlg , detailAlg , listAlgFile, addListAlgorithmCase , lis
import { listScene, detailScene , addScene, updateScene, deleteScene} from "@/api/algorithmList/scene.js";
import { listBoundary, detailBoundary , addBoundary, updateBoundary, deleteBoundary} from "@/api/algorithmList/boundary.js";
import { listAlgLevel} from "@/api/algorithmList/algorithmDown.js";
import AlgorithmFile from './algorithmFile.vue'
const { proxy } = getCurrentInstance();
const { algorithm_scen, algorithm_case } = proxy.useDict("algorithm_scen", "algorithm_case");
const emit = defineEmits();
@@ -514,18 +463,11 @@ const openBoundary = ref(false);
const isAdd = ref(true);
const title = ref("");
const imgVideoData = ref("");
const AlgorithmFileRef = ref(null);
const titleScene = ref("");
const titleBoundary = ref("");
const activeName = ref("基础信息");
const wrapList = ref([
  {
    algorithmId:'1',
    algorithmStatus:'1',
    fileSize:'500M',
    md5Result:'一致',
    algorithmName:'火焰算法',
  }
]);

const sceneList = ref([]);
const boundaryList = ref([]);
const levelList = ref([]);
@@ -612,6 +554,9 @@ function handleUpdate(row) {
    open.value = true;
    isAdd.value = false;
    title.value = "修改算法";
    setTimeout(()=>{
      AlgorithmFileRef.value.getList()
    })
  });
}

+47 −15
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@
                       </video>
                    </div>
                    <ImgVideoUpload 
                      v-if="form.algorithmStatus=='0'"
                      style="position: absolute;bottom: 5px;left: 26%;" 
                      :modelValue="uploadUrl" 
                      :fileType="['png', 'jpg', 'mp4']"
@@ -80,7 +79,7 @@
                     />
                  </div>
                </el-card>
                <el-card >
                <el-card style="position: relative;">
                  <div class="text-style" style="margin: 10px 0;">
                    原始数据:支持自定义上传
                  </div>
@@ -93,12 +92,13 @@
                        <source :src="'http://192.168.3.82'+nowImg" type="video/mp4" />
                    </video>
                  </div>
                  <el-button v-if="form.algorithmStatus=='0'" type="primary" plain @click="openIdentify" style="margin: 10px 0;">开始识别</el-button>
                  <el-button type="primary" plain @click="openIdentify" style="position: absolute;bottom: 5px;" :loading="identify">开始识别</el-button>
                </el-card>
                <el-card >
                <el-card style="position: relative;"  element-loading-text="正在识别中请稍后...">
                  <div class="text-style" style="margin: 10px 0;">
                    算法识别结果:
                  </div>
                  <div v-if="!identify">
                    <div class="img-box" v-if="outFilePath.length==0">
                      <div>{{ resultStr }}</div>
                      <img src="@/assets/images/default/Image-1.png" width="100%"/>
@@ -109,7 +109,13 @@
                          <source :src="'http://192.168.3.82'+outFilePath" type="video/mp4" />
                      </video>
                    </div>
                  <div style="display: flex;justify-content: space-between;margin: 10px 0;">
                  </div>
          
                  <!-- 进度条模块 -->
                  <div v-else>
                    <el-progress :percentage="progressValue" />
                  </div>
                  <div style="display: flex;justify-content: space-between;margin: 10px 0;position: absolute;bottom: 5px;">
                    <!-- <el-button type="primary" plain>重置区域</el-button> -->
                     <div></div>
                    <!-- <el-button type="primary" plain @click="downVideo">下载识别视频</el-button> -->
@@ -173,7 +179,7 @@ import { detailAlg ,listCase} from "@/api/algorithmList/index.js";
import { listScene,detailScene } from "@/api/algorithmList/scene.js";
import { listBoundary, detailBoundary } from "@/api/algorithmList/boundary.js";
import { useWebSockets} from './websockt.js'; // 注意文件路径可能需要调整  
const { handeUpload , outFilePath,resultStr} = useWebSockets();
const { handeUpload , outFilePath,resultStr,identify} = useWebSockets();
const router = useRouter();
const route = useRoute()
const nowImg=ref('')
@@ -190,6 +196,9 @@ const invalidList = ref([])
const invalidImgList = ref([])
const effectiveImgList = ref([])
const imgVideoData = ref([])

const progressValue = ref(0)

const nowText=ref('算法详情')
const baseUrl = 'http://192.168.3.82'
const data = reactive({
@@ -257,6 +266,7 @@ function handBuiltImg(item){
}
function openIdentify(){
  if(proxy.isNotEmpty(nowImg.value)){
    incrementValue()
    handeUpload({fileName:nowImg.value})
  }else{
    proxy.$modal.msgWarning(`请上传图片!`);
@@ -278,9 +288,31 @@ function getFileType(fileName) {

function downVideo(){
  window.open(baseUrl+'/algorithm/images/ResDir/2024/9/2/1830503463524630529/Safety helmet wearing detection/1725261009531_1.mp4')

}

// 进度条
function incrementValue() {
  progressValue.value = 0; // 初始化进度值为0
  const interval = 300; // 变化间隔时间,单位毫秒
  const totalTime = 30000; // 总时间,单位毫秒
  const intervalId = setInterval(() => {
    progressValue.value++; // 增加值
    if (progressValue.value >= 100) {
      clearInterval(intervalId); // 当值达到或超过100时,停止变化
    }
    if(!identify.value){
      progressValue.value=100;
      clearInterval(intervalId);
    }
  }, interval);

  // 如果需要在30秒后停止,即使还没达到100
  // setTimeout(() => {
  //   progressValue.value=100;
  //   console.log('123', 123)
  //   clearInterval(intervalId);
  // }, totalTime);
}
getDetials()

</script>
Loading