planet
shenhan000 2025-03-24 13:23:37 +08:00
parent c81a8f51fd
commit 8044855bbd
6 changed files with 136 additions and 44 deletions

View File

@ -30,7 +30,12 @@
processing processing
/> />
</div> </div>
<div v-if="requiredValid" class="item-valid"></div> <!-- <div v-if="requiredValid" class="item-valid"></div> -->
<!-- <div class="resume-upload">
<n-button type="primary" @click="resumeUpload">
继续上传
</n-button>
</div> -->
</div> </div>
</template> </template>
@ -77,7 +82,7 @@ const fileName = ref("");
const fileSize = ref(0); const fileSize = ref(0);
const progress = ref(0); const progress = ref(0);
const objectKey = ref(""); const objectKey = ref("");
const chunkSize = ref(3 * 1024 * 1024); const chunkSize = ref(5 * 1024 * 1024);
const totalChunks = ref(0); const totalChunks = ref(0);
const currentChunk = ref(1); const currentChunk = ref(1);
const uploadId = ref(""); const uploadId = ref("");
@ -89,6 +94,13 @@ const requiredValid = ref(false);
const hashCode = ref(""); const hashCode = ref("");
const message = useMessage(); const message = useMessage();
const currentFileSize = ref(0) const currentFileSize = ref(0)
//
const uploadStatus = ref<'idle' | 'uploading' | 'paused' | 'completed'>('idle');
const uploadedChunks = ref<Set<number>>(new Set());
const retryCount = ref<number>(0);
const maxRetries = 5; //
// //
const triggerFileSelect = () => { const triggerFileSelect = () => {
fileInputRef.value?.click(); fileInputRef.value?.click();
@ -162,6 +174,9 @@ const initParam = () => {
uploadId.value = ""; uploadId.value = "";
partArr.value = []; partArr.value = [];
requiredValid.value = false; requiredValid.value = false;
uploadStatus.value = 'idle';
uploadedChunks.value.clear();
retryCount.value = 0;
}; };
function getOssDefaultPath(name:any) { function getOssDefaultPath(name:any) {
@ -200,6 +215,18 @@ const selectFile = async (event: Event) => {
} }
try { try {
//
if (uploadStatus.value === 'paused' && file.value) {
const shouldResume = window.confirm('检测到未完成的上传,是否继续上传?');
if (shouldResume) {
await resumeUpload();
return;
} else {
//
initParam();
}
}
// //
progress.value = 0; progress.value = 0;
fileName.value = file.value.name; fileName.value = file.value.name;
@ -244,8 +271,15 @@ const selectFile = async (event: Event) => {
// //
// 0 1 // 0 1
try { try {
const res = await request.get( // const res = await request.get(
`/file/selectFile?type=${props.type}&name=${fileName.value}` // `/file/selectFile?type=${props.type}&name=${fileName.value}`
// );
const res = await request.post(
`/file/selectFile`,
{
type:props.type,
name:fileName.value
}
); );
if (res.data !== 1) { if (res.data !== 1) {
message.warning("文件名已存在"); message.warning("文件名已存在");
@ -314,6 +348,13 @@ const selectFile = async (event: Event) => {
const uploadFile = async () => { const uploadFile = async () => {
if (!file.value) return; if (!file.value) return;
while (currentChunk.value <= totalChunks.value) {
//
if (uploadedChunks.value.has(currentChunk.value)) {
currentChunk.value++;
continue;
}
const index = currentChunk.value - 1; const index = currentChunk.value - 1;
const start = index * chunkSize.value; const start = index * chunkSize.value;
const end = Math.min((index + 1) * chunkSize.value, file.value.size); const end = Math.min((index + 1) * chunkSize.value, file.value.size);
@ -325,24 +366,58 @@ const uploadFile = async () => {
formData.append("uploadId", uploadId.value); formData.append("uploadId", uploadId.value);
try { try {
uploadStatus.value = 'uploading';
const res = await request.post("/file/chunk", formData, { const res = await request.post("/file/chunk", formData, {
headers: { "Content-Type": "multipart/form-data" }, headers: { "Content-Type": "multipart/form-data" },
//
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
((currentChunk.value - 1) / totalChunks.value) * 100 +
(progressEvent.loaded / progressEvent.total!) * (100 / totalChunks.value)
);
progress.value = percentCompleted;
}
}); });
//
uploadedChunks.value.add(currentChunk.value);
partArr.value.push(res.data); partArr.value.push(res.data);
currentChunk.value++; currentChunk.value++;
progress.value = Math.floor((currentChunk.value / totalChunks.value) * 100); retryCount.value = 0; //
if (currentChunk.value <= totalChunks.value) { progress.value = Math.floor((currentChunk.value / totalChunks.value) * 100);
uploadFile();
} else {
progress.value = 99;
complete();
}
} catch (error) { } catch (error) {
initParam();
console.error("切片上传失败:", error); console.error("切片上传失败:", error);
message.warning("文件上传异常或上传已取消");
//
if (retryCount.value < maxRetries) {
retryCount.value++;
message.warning(`${currentChunk.value} 个分片上传失败,正在进行第 ${retryCount.value} 次重试...`);
await new Promise(resolve => setTimeout(resolve, 1000)); // 1
continue; //
}
//
uploadStatus.value = 'paused';
message.error(`上传失败,已暂停。您可以稍后继续上传。`);
return;
}
}
//
if (currentChunk.value > totalChunks.value) {
progress.value = 99;
uploadStatus.value = 'completed';
await complete();
}
};
//
const resumeUpload = async () => {
if (uploadStatus.value === 'paused' && file.value) {
retryCount.value = 0; //
message.info('正在继续上传...');
await uploadFile();
} }
}; };
@ -389,19 +464,21 @@ const emit = defineEmits<{
// //
const cancelUploadInfo = async () => { const cancelUploadInfo = async () => {
if (progress.value !== 100) { if (uploadStatus.value !== 'completed') {
try { try {
await request.post("/file/cancelUpload", { await request.post("/file/cancelUpload", {
objectKey: objectKey.value, objectKey: objectKey.value,
uploadId: uploadId.value, uploadId: uploadId.value,
}); });
uploadStatus.value = 'idle';
uploadedChunks.value.clear();
progress.value = 0;
showFileName.value = false;
initParam();
} catch (error) { } catch (error) {
message.error("取消上传失败"); message.error("取消上传失败");
} }
} }
progress.value = 0;
showFileName.value = false;
initParam();
}; };
// //

View File

@ -367,7 +367,7 @@ function handledeleteFile(item:any){
v-model:checked="item.isOnlineUse" v-model:checked="item.isOnlineUse"
:checked-value="1" :checked-value="1"
:unchecked-value="0" :unchecked-value="0"
disabled="true" :disabled="true"
label="允许在魔创未来在线使用" label="允许在魔创未来在线使用"
/> />
</div> </div>
@ -383,7 +383,7 @@ function handledeleteFile(item:any){
<n-checkbox <n-checkbox
v-model:checked="item.allowSoftwareUse" v-model:checked="item.allowSoftwareUse"
:checked-value="1" :checked-value="1"
disabled="true" :disabled="true"
:unchecked-value="0" :unchecked-value="0"
label="允许在魔创未来旗下其他产品在线使用" label="允许在魔创未来旗下其他产品在线使用"
/> />

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { Asterisk } from 'lucide-vue-next'; import { Asterisk, Trash } from 'lucide-vue-next';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
const props = defineProps({ const props = defineProps({
@ -32,6 +32,8 @@ function preStep() {
} }
const showSuccessModal = ref(false) const showSuccessModal = ref(false)
//
async function handlePublish() { async function handlePublish() {
for (let i = 0; i < localForm.value.modelVersionList.length; i++) { for (let i = 0; i < localForm.value.modelVersionList.length; i++) {
if (localForm.value.modelVersionList[i].delFlag === '0' && localForm.value.modelVersionList[i].sampleImagePaths.length === 0) { if (localForm.value.modelVersionList[i].delFlag === '0' && localForm.value.modelVersionList[i].sampleImagePaths.length === 0) {
@ -92,10 +94,14 @@ watch(
const fileInput = ref<HTMLInputElement | null>(null) const fileInput = ref<HTMLInputElement | null>(null)
const uploadFileIndex = ref(0) const uploadFileIndex = ref(0)
//
function triggerFileInput(index: number) { function triggerFileInput(index: number) {
(fileInput.value as HTMLInputElement)?.click() (fileInput.value as HTMLInputElement)?.click()
uploadFileIndex.value = index uploadFileIndex.value = index
} }
//
async function handleFileChange(event: Event) { async function handleFileChange(event: Event) {
const target = event.target as HTMLInputElement const target = event.target as HTMLInputElement
const files = target.files const files = target.files
@ -117,10 +123,16 @@ async function handleFileChange(event: Event) {
target.value = '' target.value = ''
} }
//
function onPositiveClick() { function onPositiveClick() {
showSuccessModal.value = false showSuccessModal.value = false
router.push('/personal-center') router.push('/personal-center')
} }
//
const deleteSampleImage = (index:number, data:any) =>{
data.splice(index, 1)
}
</script> </script>
<template> <template>
@ -166,8 +178,9 @@ function onPositiveClick() {
</n-spin> </n-spin>
<div class="grid grid-cols-3 gap-2.5 mt-4 w-full"> <div class="grid grid-cols-3 gap-2.5 mt-4 w-full">
<div v-for="(subItem, subIndex) in item.sampleImagePaths" :key="subIndex"> <div v-for="(subItem, subIndex) in item.sampleImagePaths" :key="subIndex" class="relative">
<img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt=""> <img class="w-full h-[200px] object-cover rounded-lg" :src="subItem" alt="">
<Trash @click="deleteSampleImage(subIndex, item.sampleImagePaths)" :size="20" class="mt-1 absolute top-2 right-2 text-gray-400 cursor-pointer hover:text-gray-100" />
</div> </div>
</div> </div>
</div> </div>

View File

@ -526,9 +526,8 @@ const toWallet = () => {
const zfbStatus = ref('0') const zfbStatus = ref('0')
async function getBindStatus(){ async function getBindStatus(){
const res = await request.get(`/ali/pay/queryBindStatus`) const res = await request.get(`/ali/pay/queryBindStatus`)
if (res.data === '1') { //'1 0 if (res.code === 200) { //'1 0
zfbStatus.value = res.data zfbStatus.value = res.data
message.success('绑定成功!')
} }
} }
getBindStatus() getBindStatus()
@ -550,6 +549,8 @@ const showBinding = async() =>{
if (res2.data === '1') { if (res2.data === '1') {
closeBindingModal() closeBindingModal()
message.success('绑定成功!') message.success('绑定成功!')
// window.location.reload()
getBindStatus()
} }
} }
catch (err) { catch (err) {

View File

@ -2,6 +2,7 @@
import CreateModels from "@/components/publishModel/CreateModels.vue"; import CreateModels from "@/components/publishModel/CreateModels.vue";
import EditVersion from "@/components/publishModel/EditVersion.vue"; import EditVersion from "@/components/publishModel/EditVersion.vue";
import UploadImg from "@/components/publishModel/UploadImg.vue"; import UploadImg from "@/components/publishModel/UploadImg.vue";
import { CirclePlus } from "lucide-vue-next";
import { NConfigProvider, NMessageProvider } from "naive-ui"; import { NConfigProvider, NMessageProvider } from "naive-ui";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const message = useMessage(); const message = useMessage();

View File

@ -83,8 +83,8 @@ export default defineNuxtConfig({
preset: 'node-server', preset: 'node-server',
devProxy: { devProxy: {
'/api': { '/api': {
// target: 'http://1.13.246.108:8080', // 线上 target: 'http://113.45.190.154:8080', // 线上
target: 'http://192.168.2.10:8080', // 代 // target: 'http://192.168.2.10:8080', // 代
// target: 'http://192.168.2.5:8080', // 嗨 // target: 'http://192.168.2.5:8080', // 嗨
// target: 'https://2d1a399f.r27.cpolar.top', // 嗨 // target: 'https://2d1a399f.r27.cpolar.top', // 嗨
changeOrigin: true, changeOrigin: true,