AIManage/src/views/manage/datas/edit.vue

578 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!-- 用户管理 -->
<template>
<div class="app-container model-detail">
<!-- 用户新增/编辑表单 -->
<el-card v-loading="loading">
<template #header><svg-icon icon-class="pause" style="width: 20px; height: 20px" />数据集基本信息
</template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :lg="12" :xs="24">
<el-form-item label="数据集名称" prop="dataset_name">
<el-input v-model="form.dataset_name" placeholder="请输入数据集名称" />
</el-form-item>
</el-col>
<el-col :lg="12" :xs="24">
<el-form-item label="数据集版本" prop="dataset_version">
<el-input v-model="form.dataset_version" type="number" placeholder="请输入数据集版本" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :lg="12" :xs="24">
<el-form-item label="适用任务类型" prop="modl_sub_type">
<el-select v-model="form.modl_sub_type" disabled placeholder="请选择适用任务类型">
<el-option v-for="item in listOpt.modlSubTypeList" :key="item.modl_sub_type"
:label="item.modl_sub_type_name" :value="item.modl_sub_type" />
</el-select>
</el-form-item>
</el-col>
<el-col :lg="12" :xs="24">
<el-form-item label="数据集格式" prop="dats_dataset_format">
<el-select v-model="form.dats_dataset_format" disabled placeholder="请选择数据集格式">
<el-option v-for="item in listOpt.datasetFormatList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :lg="12" :xs="24">
<el-form-item label="标注类型" prop="dats_label_type">
<el-select v-model="form.dats_label_type" disabled placeholder="请选择标注类型">
<el-option v-for="item in listOpt.labelTypeList" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</el-col>
<el-col :lg="12" :xs="24">
<el-form-item label="图像分辨率" prop="image_height">
<el-row style="width: 100%">
<el-col :lg="11">
<el-input v-model="form.image_width" disabled placeholder="请输入分辨率宽度">
<template #prepend> 宽 </template>
</el-input>
</el-col>
<el-col :lg="2" class="font-center"><el-icon>
<Rank />
</el-icon></el-col>
<el-col :lg="11">
<el-input v-model="form.image_height" disabled placeholder="请输入分辨率高度">
<template #prepend> 高 </template>
</el-input>
</el-col>
</el-row>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :lg="12" :xs="24">
<el-form-item label="数据集描述" prop="dataset_desc">
<el-input v-model="form.dataset_desc" placeholder="请输入数据集描述" :rows="2" type="textarea" />
</el-form-item>
</el-col>
<el-col :lg="12" :xs="24"> </el-col>
</el-row>
<el-row>
<el-col :lg="12" :xs="24">
<el-form-item label="数据集参数文件" prop="dataset_parameters">
<el-upload ref="uploadRef" class="upload-demo upload-demo-1" :on-change="handleFileChange"
:on-remove="handleFileRemove" :on-exceed="handleFileExceed" :auto-upload="false" :limit="1"
accept="application/json">
<el-button type="primary"><el-icon class="el-icon--upload"> <i-ep-upload-filled />
</el-icon>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
请上传大小不超过 <strong style="color: red">10M</strong>,格式为
<strong style="color: red">json</strong> 的文件
</div>
</template>
</el-upload>
</el-form-item>
</el-col>
<el-col :lg="12" :xs="24">
<div style="padding-left: 35px" v-if="fileStatus">
<el-divider content-position="left"><strong style="color: #409eff">数据集参数文件预览</strong></el-divider>
<json-viewer :value="jsonData.data" copyable boxed sort theme="my-json-view jv-light" />
</div>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card style="margin-top: 12px">
<template #header><svg-icon icon-class="pause" style="width: 20px; height: 20px" />图片信息<strong
style="color: #409eff">{{ imgCount }}</strong>
<el-button type="primary" style="position: absolute; right: 30px" @click="handleRemoveAll"
:disabled="imageList.length == 0"><i-ep-delete />清空全部</el-button>
</template>
<el-upload v-model:file-list="imageList" class="upload-demo upload-demo-2" :before-remove="beforeRemove" />
<el-empty v-if="imageList.length == 0" description="暂 无 数 据" />
</el-card>
<el-card class="card-footer">
<el-button type="primary" @click="handleImageDialog"><i-ep-upload-filled />上传图片</el-button>
<el-button type="primary" @click="handleSubmit"><i-ep-check />确 定</el-button>
<el-button @click="closeBack"><i-ep-close />取 消</el-button>
</el-card>
<el-dialog v-model="dialogVisible" title="上传标注图片" width="880" append-to-body>
<el-card v-loading.fullscreen.lock="uploadLoading">
<el-upload v-model:file-list="uploadImgFileList" class="upload-demo upload-demo-3"
:before-remove="handleRemoveFiles" :auto-upload="autoUpload" :on-change="handleChangeFiles"
list-type="picture" multiple accept="application/json,image/jpeg">
<!--accept="application/json,image/png,image/jpg,image/jpeg"-->
<el-button type="primary"><el-icon class="el-icon--upload"> <i-ep-upload-filled /> </el-icon>选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
请上传大小不超过 <strong style="color: red">10M</strong>,格式为
<strong style="color: red">json/jpg</strong> 的文件
</div>
</template>
</el-upload>
<el-empty v-if="uploadImgFileList.length == 0" description="暂 无 数 据" />
</el-card>
<!-- 弹窗底部操作按钮 -->
<template #footer>
<div class="dialog-footer">
<el-button type="primary" :disabled="uploadImgFileList.length == 0" @click="startUploadFiles">开始上传</el-button>
<el-button @click="dialogVisible = false">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import ConstApi from "@/api/const";
import DataSetApi from "@/api/dataSet";
import { json } from 'stream/consumers';
const route = useRoute();
const router = useRouter();
const ID = ref(""); // 编号
const form = ref({}); // 基础表单
const formRef = ref(ElForm); // 表单
const loading = ref(false); // 加载状态
const dialogOpen = ref(false); // 加载状态
const fileStatus = ref(false); // 文件状态
const codeHtml = ref(""); // 文件信息
const jsonData = reactive({
data: {}
})
const imgCount = ref(0); // 图片信息
const imageList = ref([]); // 图片列表
const remImageList = ref([]); // 删除图片列表
// 上传组件
const uploadRef = ref<UploadInstance>();
const autoTime = ref(""); // 自动上传
const autoUpload = ref(false); // 自动上传
const dialogVisible = ref(false); // 加载状态
const uploadLoading = ref(false); // 加载状态
const uploadAllList = ref([]); // 待上传文件列表
const uploadJsonList = ref([]); // 待上传JSON列表
const uploadImgFileList = ref([]); // 待上传图片列表
// 基础数据列表
let listOpt = reactive({
labelTypeList: [],
modlSubTypeList: [],
datasetFormatList: [],
});
// 校验规则
const rules = reactive({
dataset_name: [{ required: true, message: "数据集名称不能为空", trigger: "blur" }],
dataset_version: [{ required: true, message: "数据集版本不能为空", trigger: "blur" }],
modl_sub_type: [{ required: true, message: "适用任务类型不能为空", trigger: "change" }],
dats_dataset_format: [
{ required: true, message: "数据集格式不能为空", trigger: "change" },
],
dats_label_type: [{ required: true, message: "标注类型不能为空", trigger: "change" }],
image_width: [{ required: true, message: "分辨率宽度不能为空", trigger: "blur" }],
image_height: [{ required: true, message: "分辨率高度不能为空", trigger: "blur" }],
dataset_desc: [{ required: false, message: "数据集描述不能为空", trigger: "blur" }],
dataset_parameters: [
{ required: true, message: "数据集参数文件不能为空", trigger: "blur" },
],
});
/** 表单提交 */
const handleSubmit = useThrottleFn(() => {
formRef.value.validate((valid: any) => {
if (valid) {
if (!form.value.image_width) {
ElMessage.error("请输入图片分辨率宽度!");
return false;
}
loading.value = true;
DataSetApi.updateDataSet(form.value.dataset_id, form.value)
.then((res) => {
if (res.data.code == 0) {
ElMessage.success("保存成功");
closeBack();
}
})
.finally(() => {
loading.value = false;
});
}
});
}, 3000);
/** 上传文件 */
function handleChangeFiles(uploadFile, uploadFiles) {
//uploadFile.status = 'success';
clearTimeout(autoTime.value);
if (uploadFile.raw.type == "application/json") {
uploadJsonList.value.push(uploadFile);
}
autoTime.value = setTimeout(doEquipmentFiles, 280);
}
/** 上传文件>回调 */
const doEquipmentFiles = () => {
uploadImgFileList.value = uploadImgFileList.value.filter(
(it) => it.raw.type != "application/json"
);
if (form.value.dats_label_type != "no_label") {
var element = document.getElementsByClassName("upload-demo-3")[0];
var children = element.querySelectorAll(".el-upload-list__item");
children.forEach((item) => {
var mylabel = item.querySelectorAll(".mylabel");
//console.log("mylabel.length==>" + mylabel.length);
if (mylabel.length > 0) {
mylabel.forEach((lab) => {
lab.remove();
});
}
let name = item.querySelector(".el-upload-list__item-file-name").textContent;
let disp = uploadJsonList.value.filter((it) => disName(name, it.name));
//console.log("disp==>" + disp.length);
if (disp.length > 0) {
item.insertAdjacentHTML(
"beforeend",
"<span class='el-tag el-tag--success el-tag--dark mylabel mylabel--success'><span class='el-tag__content'>已标注</span></span>"
);
} else {
item.insertAdjacentHTML(
"beforeend",
"<span class='el-tag el-tag--danger el-tag--dark mylabel mylabel--error'><span class='el-tag__content'>未标注</span></span>"
);
}
});
}
};
/** 标注文件名称比对 */
function disName(img, json) {
if (
img.substring(0, img.lastIndexOf(".")) == json.substring(0, json.lastIndexOf("."))
) {
return true;
} else {
return false;
}
}
/** 删除图片的json标注 */
function handleRemoveFiles(uploadFile, uploadFiles) {
uploadJsonList.value = uploadJsonList.value.filter(
(it) => !disName(uploadFile.name, it.name)
);
return true;
}
/** 开始上传文件 */
function startUploadFiles() {
var element = document.getElementsByClassName("upload-demo-3")[0];
var errors = element.querySelectorAll(".mylabel--error");
if (errors.length > 0) {
ElMessage.error(errors.length + " 个图片未上传标注文件!请上传或删除图片。");
return false;
}
uploadImgFileList.value.forEach((item) => {
let json = uploadJsonList.value.filter((it) => disName(item.name, it.name));
const formData = new FormData();
formData.append("image_file_name", item.name);
formData.append("image_file", item.raw);
formData.append("label_file", json.length > 0 ? json[0].raw : null);
uploadLoading.value = true;
DataSetApi.rawUpload(form.value.dataset_id, formData)
.then((res) => {
if (res.data.code == 0) {
uploadImgFileList.value = uploadImgFileList.value.filter(
(it) => item.name != it.name
);
uploadJsonList.value = uploadJsonList.value.filter(
(it) => !disName(item.name, it.name)
);
if (uploadImgFileList.value.length == 0) {
handleQuery();
dialogVisible.value = false;
}
}
})
.finally(() => {
uploadLoading.value = false;
});
});
}
/** 删除文件 */
function beforeRemove(file) {
remImageList.value.push(file.name);
let remList = [];
remList.push(file.name);
return ElMessageBox.confirm("确认删除数据集图片?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(
async () => {
let res = await DataSetApi.deleteFile(ID.value, { file_name_list: remList });
if (res.data.code == 0) {
imgCount.value = imageList.value.length - 1;
ElMessage.success("删除成功");
}
return true;
},
() => false
);
}
/** 删除文件-清空所有 */
function handleRemoveAll() {
ElMessageBox.confirm("确认删除全部数据集图片?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(function () {
let list = [];
imageList.value.forEach(item => {
list.push(item.name);
});
DataSetApi.deleteFile(ID.value, { file_name_list: list }).then((res) => {
if (res.data.code == 0) {
imageList.value = [];
imgCount.value = imageList.value.length;
ElMessage.success("删除成功");
}
});
});
}
/** 打开文件上传弹窗 */
function handleImageDialog() {
dialogVisible.value = true;
}
// 文件上传
function handleFileChange(file) {
//先创建一个读文件的对象 FileReader
let reader = new FileReader();
//判断浏览器是否支持 FileReader
if (typeof FileReader === "undefined") {
this.$message({
type: "info",
message: "您的浏览器不支持文件读取。",
});
return;
}
uploadFile(file).then((res) => {
if (isJSON(res)) {
form.value.dataset_parameters = JSON.parse(res);
formRef.value.validateField("dataset_parameters");
codeHtml.value = res;
jsonData.data = res;
fileStatus.value = true;
}
});
}
/** 解析json */
function isJSON(str) {
try {
// 尝试解析输入的字符串
JSON.parse(str);
ElMessage.success("JSON文件解析成功");
return true;
// 成功解析
} catch (error) {
// 解析失败
ElMessage.error("JSON文件解析失败");
uploadRef.value.clearFiles();
fileStatus.value = false;
form.value.dataset_parameters = "";
return false;
}
}
// 文件读取
function uploadFile(file) {
return new Promise(function (resolve, reject) {
let reader = new FileReader();
reader.readAsArrayBuffer(file.raw);
reader.onload = function (e) {
var ints = new Uint8Array(e.target.result); //要使用读取的内容所以将读取内容转化成Uint8Array
let snippets = new TextDecoder("UTF-8").decode(ints); //二进制缓存区内容转化成中文(即也就是读取到的内容)
resolve(snippets);
};
});
}
// 文件删除
function handleFileRemove() {
form.value.dataset_parameters = "";
codeHtml.value = "";
jsonData.data = {};
fileStatus.value = false;
}
// 超出限制,清空文件列表
function handleFileExceed() {
uploadRef.value.clearFiles();
ElMessage.warning("已清空文件列表,请重新上传!");
handleFileRemove();
}
/** 返回默认页面 */
function closeBack() {
router.push({ path: "/dataMgr/datas" });
}
// 初始化选项列表
const initData = () => {
let id = route.query.id;
ID.value = id;
DataSetApi.dataSetInfo(id).then((res) => {
if (res.data.code == 0) {
let resolution = res.data.data.image_resolution.split("x");
res.data.data.image_width = resolution[0];
res.data.data.image_height = resolution[1];
form.value = res.data.data;
codeHtml.value = JSON.stringify(res.data.data.dataset_parameters);
jsonData.data = res.data.data.dataset_parameters;
if (codeHtml.value == "{}") {
fileStatus.value = false;
} else {
fileStatus.value = true;
}
}
});
handleQuery();
ConstApi.modlSubType().then((res) => {
if (res.data.code == 0) {
listOpt.modlSubTypeList = res.data.data.modl_sub_type_list || [];
}
});
ConstApi.datasetFormatType().then((res) => {
if (res.data.code == 0) {
listOpt.datasetFormatList = res.data.data.dats_dataset_format_list || [];
}
});
ConstApi.datsLabelType().then((res) => {
if (res.data.code == 0) {
listOpt.labelTypeList = res.data.data.dats_label_type_list || [];
}
});
};
// 初始化选项列表
const handleQuery = () => {
DataSetApi.rawFiles(ID.value).then((res) => {
if (res.data.code == 0) {
if (res.data.data.file_name_list) {
let list = [];
res.data.data.file_name_list.forEach((item) => {
list.push({ name: item, url: item });
});
imageList.value = list;
imgCount.value = imageList.value.length;
}
}
});
};
onMounted(() => {
initData();
});
</script>
<style scoped lang="scss">
.model-detail {
:deep(.el-card__header) {
padding: 8px 4px;
display: flex;
align-items: center;
}
}
.sp-file {
color: #29d;
}
.tb-base-info {
line-height: 30px;
}
:deep(.svg-icon) {
margin-right: 8px;
}
.card-footer {
position: fixed;
width: calc(100% - 215px);
bottom: 0px;
:deep(.el-card__body) {
padding: 10px;
.el-pagination {
justify-content: end;
}
}
}
.font-center {
text-align: center;
color: #cccccc;
}
</style>
<style scope>
.el-dialog__body {
overflow: auto;
}
.el-card__body {
overflow: auto;
}
.upload-demo-2>.el-upload {
display: none !important;
}
.upload-demo-2>.el-upload-list {
margin: 0 !important;
}
.upload-demo-2>*>.el-upload-list__item {
float: left !important;
width: 25% !important;
}
.upload-demo-3>*>.el-upload-list__item {
float: left !important;
width: 49% !important;
}
.upload-demo-3>*>.el-upload-list__item:nth-child(even) {
margin-left: 10px;
}
.dialog-footer {
text-align: center;
}
.mylabel {
position: absolute;
right: 10px;
bottom: 10px;
}
</style>