上传相同文件有bug

This commit is contained in:
2026-01-23 21:13:43 +08:00
parent d52ba97147
commit 2ab794a0e3
3 changed files with 180 additions and 125 deletions
@@ -2,55 +2,58 @@
import { onMounted, ref, watch, defineProps, reactive } from "vue"; import { onMounted, ref, watch, defineProps, reactive } from "vue";
import flatpickr from "flatpickr"; import flatpickr from "flatpickr";
import 'flatpickr/dist/flatpickr.css'; import "flatpickr/dist/flatpickr.css";
import 'flatpickr/dist/l10n/zh.js'; import "flatpickr/dist/l10n/zh.js";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
const { t, locale } = useI18n(); const { t, locale } = useI18n();
const datatimepack = ref();
const datatimepack=ref()
const datatimepack_config=reactive({
enableTime: true,
dateFormat: "Y-m-d H:i",
minuteIncrement:1,
time_24hr: true
//locale:"zh"
})
const sele_data=reactive()
function getCurrentDateTime() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
watch(locale, () => {
if(locale.value=="zh-CN"){
datatimepack_config.locale='zh'
}else{
datatimepack_config.locale='en'
}
//console.log(locale.value=="zh-CN"?"zh":"en")
});
const prop = defineProps({ const prop = defineProps({
setdef: { setdef: {
type: String, type: String,
default: "", default: "",
}, },
max_date: {
type: [String, Date, Function],
default: () => new Date(), // 默认值为当前时间
},
}); });
const datatimepack_config = reactive({
enableTime: true,
dateFormat: "Y-m-d H:i",
minuteIncrement: 1,
time_24hr: true,
maxDate: prop.max_date, // 只能选择当前时间之前的时间
//locale:"zh"
});
const sele_data = reactive();
function getCurrentDateTime() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0"); // 月份从0开始
const day = String(now.getDate()).padStart(2, "0");
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
watch(locale, () => {
if (locale.value == "zh-CN") {
datatimepack_config.locale = "zh";
} else {
datatimepack_config.locale = "en";
}
//console.log(locale.value=="zh-CN"?"zh":"en")
});
onMounted(() => { onMounted(() => {
// @formatter:off // @formatter:off
//console.log(getCurrentDateTime()) //console.log(getCurrentDateTime())
@@ -58,26 +61,25 @@ onMounted(() => {
// console.log(prop.setdef) // console.log(prop.setdef)
if(prop.setdef=="") if (prop.setdef == "") {
{ datatimepack_config.defaultDate = getCurrentDateTime();
datatimepack_config.defaultDate=getCurrentDateTime()
} else { } else {
datatimepack_config.defaultDate=prop.setdef datatimepack_config.defaultDate = prop.setdef;
} }
datatimepack_config.locale = locale.value == "zh-CN" ? "zh" : "en"; datatimepack_config.locale = locale.value == "zh-CN" ? "zh" : "en";
flatpickr(datatimepack.value, datatimepack_config); flatpickr(datatimepack.value, datatimepack_config);
}); });
defineExpose({ defineExpose({});
});
</script> </script>
<template> <template>
<div></div> <div></div>
<input ref="datatimepack" type="datetime-local" class="form-control" v-model="sele_data"> <input
ref="datatimepack"
type="datetime-local"
class="form-control"
v-model="sele_data"
/>
</template> </template>
@@ -13,27 +13,27 @@ const lightbox = new FsLightbox();
const userStore = useUserStore(); const userStore = useUserStore();
const dropzoneElement = ref(null); const dropzoneElement = ref(null);
let dropzoneInstance = null; var dropzoneInstance = null;
const files = reactive([]); const files = reactive([]);
function get_file_from_uuid(uuid) { function get_file_from_uuid(uuid) {
if (files.length != 0) { if (files.length != 0) {
for(let i=0;i<files.length;i++){ for (var i = 0; i < files.length; i++) {
if (files[i].uuid == uuid) { if (files[i].uuid == uuid) {
return i; return i;
} }
} }
}
return -1; return -1;
}
return -2;
} }
function remove_file_from_uuie(uuid) { function remove_file_from_uuie(uuid) {
//delete files[uuid] //devare files[uuid]
var id=get_file_from_uuid(uuid) var id = get_file_from_uuid(uuid);
if (id >= 0) { if (id >= 0) {
files.splice(id, 1) files.splice(id, 1);
} }
} }
@@ -87,12 +87,12 @@ const initDropzone = () => {
//addRemoveLinks: true, // 显示移除链接 //addRemoveLinks: true, // 显示移除链接
dictDefaultMessage: t("dropzone.upload_drop_or_click"), dictDefaultMessage: t("dropzone.upload_drop_or_click"),
dictFallbackMessage: t("dropzone.upload_browser_not_supported"), dictFallbackMessage: t("dropzone.upload_browser_not_supported"),
dictFileTooBig: dictFivarooBig:
t("dropzone.upload_file_too_big") + t("dropzone.upload_file_too_big") +
"({{filesize}}MB). " + "({{filesize}}MB). " +
t("dropzone.upload_max_file_size") + t("dropzone.upload_max_file_size") +
"{{maxFilesize}}MB.", "{{maxFilesize}}MB.",
dictInvalidFileType: t("dropzone.upload_invalid_file_type"), dictInvalidFivarype: t("dropzone.upload_invalid_file_type"),
dictResponseError: t("dropzone.upload_server_error") + "{{statusCode}}", dictResponseError: t("dropzone.upload_server_error") + "{{statusCode}}",
//dictCancelUpload: t('dropzone.upload_cancel'), //dictCancelUpload: t('dropzone.upload_cancel'),
//dictUploadCanceled: t('dropzone.upload_canceled'), //dictUploadCanceled: t('dropzone.upload_canceled'),
@@ -106,23 +106,23 @@ const initDropzone = () => {
// 事件处理 // 事件处理
init: function () { init: function () {
this.on("success", (file, response) => { this.on("success", (file, response) => {
console.log("上传成功:", file, response); //console.log("上传成功:", file, response);
file.previewElement.addEventListener("click", function (e) { file.previewElement.addEventListener("click", function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
// 处理点击事件 // 处理点击事件
console.log("缩略图被点击", file); //console.log("缩略图被点击", file);
//动态把文件载入灯箱 //动态把文件载入灯箱
//先移除原有数据 //先移除原有数据
lightbox.props.sources.splice(0,lightbox.props.sources.length) lightbox.props.sources.splice(0, lightbox.props.sources.length);
var dis_id = 0; var dis_id = 0;
var dis_id_t = 0; var dis_id_t = 0;
for (let i=0;i<files.length;i++){ for (var i = 0; i < files.length; i++) {
if (files[i]["is_upload"] == true) { if (files[i]["is_upload"] == true) {
lightbox.props.sources.push(files[i]["get_url"]) lightbox.props.sources.push(files[i]["get_url"]);
if (files[i]["uuid"] == file.upload.uuid) { if (files[i]["uuid"] == file.upload.uuid) {
dis_id = dis_id_t; dis_id = dis_id_t;
} }
@@ -148,9 +148,8 @@ const initDropzone = () => {
// size: file.size, // size: file.size,
// }; // };
var file_id=get_file_from_uuid(file.upload.uuid) var file_id = get_file_from_uuid(file.upload.uuid);
if(file_id>=0) if (file_id >= 0) {
{
files[file_id]["hash"] = response.return.hash; files[file_id]["hash"] = response.return.hash;
files[file_id]["get_url"] = response.return.get; files[file_id]["get_url"] = response.return.get;
files[file_id]["download_url"] = response.return.download; files[file_id]["download_url"] = response.return.download;
@@ -159,7 +158,7 @@ const initDropzone = () => {
files[file_id]["is_upload"] = true; files[file_id]["is_upload"] = true;
console.log(files) //console.log(files)
} }
//files.push(t) //files.push(t)
@@ -173,21 +172,30 @@ const initDropzone = () => {
console.error("上传失败:", file.name, errorMessage); console.error("上传失败:", file.name, errorMessage);
}); });
this.on("removedfile", (file) => { this.on("removedfile", (file) => {
console.log("remove:", file); //console.log("remove:", file);
//files.value = files.value.filter(f => f.name !== file.name) //files.value = files.value.filter(f => f.name !== file.name)
remove_file_from_uuie(file.upload.uuid) remove_file_from_uuie(file.upload.uuid);
console.log(files) //console.log(files)
}); });
this.on("addedfile", (file) => { this.on("addedfile", (file) => {
//添加文件 //添加文件
console.log("addfile", file); console.log(get_file_from_uuid(file.upload.uuid));
//控制排序 需要从添加文件开始操作
//判断文件是否重复
if (get_file_from_uuid(file.upload.uuid) <0) {
// //控制排序 需要从添加文件开始操作
var t = { var t = {
uuid: file.upload.uuid, uuid: file.upload.uuid,
is_upload: false, is_upload: false,
}; };
files.push(t); files.push(t);
console.log(files); console.log(files);
return;
}
//this.removeFile(file)
}); });
this.on("sending", function (file, xhr, formData) { this.on("sending", function (file, xhr, formData) {
// 获取表单值并添加到 FormData // 获取表单值并添加到 FormData
@@ -229,6 +237,10 @@ const initDropzone = () => {
// } // }
// } // }
function return_files() {
return files;
}
// 组件挂载时初始化 // 组件挂载时初始化
onMounted(() => { onMounted(() => {
initDropzone(); initDropzone();
@@ -242,6 +254,10 @@ onUnmounted(() => {
dropzoneInstance.destroy(); dropzoneInstance.destroy();
} }
}); });
defineExpose({
return_files,
});
</script> </script>
<template> <template>
@@ -310,15 +326,8 @@ onUnmounted(() => {
<!-- 移除按钮 --> <!-- 移除按钮 -->
</div> </div>
</div> </div>
<div class="text-end">{{ files.length }}/{{ maxFiles }}</div>
<div ref="dropzoneElement" class="dropzone"></div> <div ref="dropzoneElement" class="dropzone"></div>
<!-- <div v-if="files.length > 0" class="mt-4">
<h3>已选择的文件</h3>
<ul>
<li v-for="file in files" :key="file.name">
{{ file.name }} ({{ formatBytes(file.size) }})
</li>
</ul>
</div> -->
</div> </div>
</template> </template>
@@ -2,6 +2,8 @@
import { onMounted, watch, ref, reactive } from "vue"; import { onMounted, watch, ref, reactive } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import MyOffcanvas from "@/components/MyOffcanvas.vue";
import tagadder from "@/components/tagadder.vue"; import tagadder from "@/components/tagadder.vue";
import dateTimePicker from "@/components/dateTimePicker.vue"; import dateTimePicker from "@/components/dateTimePicker.vue";
@@ -18,7 +20,12 @@ import "tom-select/dist/css/tom-select.css";
const textarea_maxlen = 256; const textarea_maxlen = 256;
const textarea_len = ref(0); const textarea_len = ref(0);
const textarea_val = ref();
const title_input_dom = ref();
const photos_hash = ref();
const mos = ref();
const { t, locale } = useI18n(); const { t, locale } = useI18n();
@@ -44,7 +51,7 @@ const order_status = reactive({
1: t("order_status.pending_order"), 1: t("order_status.pending_order"),
2: t("order_status.order_placed"), 2: t("order_status.order_placed"),
3: t("order_status.in_transit"), 3: t("order_status.in_transit"),
4: t("order_status.completed"), 4: t("order_status.compvared"),
5: t("order_status.refund_requested"), 5: t("order_status.refund_requested"),
6: t("order_status.returning"), 6: t("order_status.returning"),
7: t("order_status.refunded"), 7: t("order_status.refunded"),
@@ -55,7 +62,7 @@ function update_order_status() {
order_status["1"] = t("order_status.pending_order"); order_status["1"] = t("order_status.pending_order");
order_status["2"] = t("order_status.order_placed"); order_status["2"] = t("order_status.order_placed");
order_status["3"] = t("order_status.in_transit"); order_status["3"] = t("order_status.in_transit");
order_status["4"] = t("order_status.completed"); order_status["4"] = t("order_status.compvared");
order_status["5"] = t("order_status.refund_requested"); order_status["5"] = t("order_status.refund_requested");
order_status["6"] = t("order_status.returning"); order_status["6"] = t("order_status.returning");
order_status["7"] = t("order_status.refunded"); order_status["7"] = t("order_status.refunded");
@@ -86,19 +93,50 @@ function add_cost() {
//console.log(t); //console.log(t);
} }
const submit_sheet = reactive({
title: "",
remark: "",
photos: [],
link: "",
part_name: "",
styles: [],
costs: [],
update_time: "",
tracking_number: "",
order_status: "1",
});
function submit_order() { function submit_order() {
console.log("up"); if (submit_sheet.title == "") {
title_input_dom.value.classList.add("is-invalid");
title_input_dom.value.addEventListener("input", function () {
if (this.value.trim() !== "") {
this.classList.remove("is-invalid");
//this.removeEventListener('input');
}
});
mos.value?.showAlert("danger", t("purchase_addorder.title"), 1000);
return;
}
//载入图片哈希列表
var photos = photos_hash.value.return_files();
for (var i = 0; i < photos.length; i++) {
submit_sheet.photos.push(photos[i].hash);
}
console.log(submit_sheet);
} }
function textarea_change(a) { function textarea_change(a) {
//console.log(textarea_val.value.length) //console.log(textarea_val.value.length)
textarea_len.value = textarea_val.value.length; textarea_len.value = submit_sheet.remark.length;
// if(a.inputType=="insertText"){ // if(a.inputType=="insertText"){
// textarea_len.value+=1; // textarea_len.value+=1;
// } // }
// if(a.inputType=="deleteContentBackward"){ // if(a.inputType=="devareContentBackward"){
// textarea_len.value-=1; // textarea_len.value-=1;
// } // }
} }
@@ -132,7 +170,7 @@ watch(
cost_sheet.cost = parseFloat(fixed); cost_sheet.cost = parseFloat(fixed);
} }
} }
} },
); );
</script> </script>
@@ -166,6 +204,8 @@ watch(
class="form-control" class="form-control"
name="example-text-input" name="example-text-input"
:placeholder="t('purchase_addorder.title')" :placeholder="t('purchase_addorder.title')"
v-model="submit_sheet.title"
ref="title_input_dom"
/> />
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -182,12 +222,13 @@ watch(
:placeholder="t('purchase_addorder.remarks_text')" :placeholder="t('purchase_addorder.remarks_text')"
:maxlength="textarea_maxlen" :maxlength="textarea_maxlen"
@input="textarea_change" @input="textarea_change"
v-model="textarea_val" v-model="submit_sheet.remark"
></textarea> ></textarea>
<useDropzone <useDropzone
acceptedFiles="image/*" acceptedFiles="image/*"
uploadURL="/api/files/upload/image" uploadURL="/api/files/upload/image"
maxFiles="10" maxFiles="10"
ref="photos_hash"
></useDropzone> ></useDropzone>
</div> </div>
</div> </div>
@@ -202,13 +243,13 @@ watch(
<label class="form-label">{{ <label class="form-label">{{
t("purchase_addorder.link") t("purchase_addorder.link")
}}</label> }}</label>
<input <textarea
name="url" name="url"
type="url" type="url"
class="form-control" class="form-control"
placeholder="http" placeholder="http"
value="" v-model="submit_sheet.link"
/> ></textarea>
<div class="mb-3 mt-3"> <div class="mb-3 mt-3">
<label class="form-label">{{ <label class="form-label">{{
t("purchase_addorder.part_name") t("purchase_addorder.part_name")
@@ -218,6 +259,7 @@ watch(
class="form-control" class="form-control"
name="example-text-input" name="example-text-input"
:placeholder="t('purchase_addorder.part_name')" :placeholder="t('purchase_addorder.part_name')"
v-model="submit_sheet.part_name"
/> />
</div> </div>
<div class="mt-3"> <div class="mt-3">
@@ -289,7 +331,7 @@ watch(
<select <select
ref="select_type" ref="select_type"
class="form-control" class="form-control"
autocomplete="off" autocompvare="off"
value="1" value="1"
v-model="cost_sheet.type" v-model="cost_sheet.type"
> >
@@ -324,7 +366,7 @@ watch(
<select <select
ref="select_beast" ref="select_beast"
class="form-control" class="form-control"
autocomplete="off" autocompvare="off"
value="1" value="1"
v-model="cost_sheet.currency_type" v-model="cost_sheet.currency_type"
> >
@@ -374,7 +416,7 @@ watch(
:placeholder=" :placeholder="
t('purchase_addorder.input_tracking_number') t('purchase_addorder.input_tracking_number')
" "
value="" v-model="submit_sheet.tracking_number"
/> />
</div> </div>
<div class="col-xl-4"> <div class="col-xl-4">
@@ -382,8 +424,8 @@ watch(
<select <select
ref="select_beast" ref="select_beast"
class="form-control" class="form-control"
autocomplete="off" autocompvare="off"
value="1" v-model="submit_sheet.order_status"
> >
<option v-for="(value, key) in order_status" :value="key"> <option v-for="(value, key) in order_status" :value="key">
{{ value }} {{ value }}
@@ -409,6 +451,8 @@ watch(
</div> </div>
</div> </div>
</div> </div>
<MyOffcanvas ref="mos" />
</template> </template>
<style></style> <style></style>