Loading src/api/algorithmList/algorithmFile.js 0 → 100644 +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' }) } src/components/FileAlgUpload/index.vue 0 → 100644 +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> src/views/algorithmControl/components/algorithmFile.vue 0 → 100644 +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 src/views/algorithmControl/components/form.vue +7 −62 Original line number Diff line number Diff line Loading @@ -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"> Loading Loading @@ -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(); Loading @@ -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([]); Loading Loading @@ -612,6 +554,9 @@ function handleUpdate(row) { open.value = true; isAdd.value = false; title.value = "修改算法"; setTimeout(()=>{ AlgorithmFileRef.value.getList() }) }); } Loading src/views/algorithmList/components/details.vue +47 −15 Original line number Diff line number Diff line Loading @@ -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']" Loading @@ -80,7 +79,7 @@ /> </div> </el-card> <el-card > <el-card style="position: relative;"> <div class="text-style" style="margin: 10px 0;"> 原始数据:支持自定义上传 </div> Loading @@ -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%"/> Loading @@ -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> --> Loading Loading @@ -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('') Loading @@ -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({ Loading Loading @@ -257,6 +266,7 @@ function handBuiltImg(item){ } function openIdentify(){ if(proxy.isNotEmpty(nowImg.value)){ incrementValue() handeUpload({fileName:nowImg.value}) }else{ proxy.$modal.msgWarning(`请上传图片!`); Loading @@ -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 Loading
src/api/algorithmList/algorithmFile.js 0 → 100644 +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' }) }
src/components/FileAlgUpload/index.vue 0 → 100644 +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>
src/views/algorithmControl/components/algorithmFile.vue 0 → 100644 +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
src/views/algorithmControl/components/form.vue +7 −62 Original line number Diff line number Diff line Loading @@ -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"> Loading Loading @@ -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(); Loading @@ -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([]); Loading Loading @@ -612,6 +554,9 @@ function handleUpdate(row) { open.value = true; isAdd.value = false; title.value = "修改算法"; setTimeout(()=>{ AlgorithmFileRef.value.getList() }) }); } Loading
src/views/algorithmList/components/details.vue +47 −15 Original line number Diff line number Diff line Loading @@ -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']" Loading @@ -80,7 +79,7 @@ /> </div> </el-card> <el-card > <el-card style="position: relative;"> <div class="text-style" style="margin: 10px 0;"> 原始数据:支持自定义上传 </div> Loading @@ -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%"/> Loading @@ -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> --> Loading Loading @@ -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('') Loading @@ -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({ Loading Loading @@ -257,6 +266,7 @@ function handBuiltImg(item){ } function openIdentify(){ if(proxy.isNotEmpty(nowImg.value)){ incrementValue() handeUpload({fileName:nowImg.value}) }else{ proxy.$modal.msgWarning(`请上传图片!`); Loading @@ -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