还差批量图片上传

This commit is contained in:
2026-01-15 21:26:55 +08:00
parent 20c8248692
commit 56d4b104eb
11 changed files with 510 additions and 96 deletions
+1
View File
@@ -52,6 +52,7 @@ func ApiRoot(r *gin.RouterGroup) {
ApiStatic(r.Group("/static")) ApiStatic(r.Group("/static"))
ApiUser(r.Group("/users")) ApiUser(r.Group("/users"))
ApiFiles(r.Group("/files"))
r.GET("/", func(ctx *gin.Context) { r.GET("/", func(ctx *gin.Context) {
ReturnJson(ctx, "apiOK", nil) ReturnJson(ctx, "apiOK", nil)
+18
View File
@@ -0,0 +1,18 @@
package routers
import (
"fmt"
"github.com/gin-gonic/gin"
)
func ApiFiles(r *gin.RouterGroup) {
r.POST("/upload", func(ctx *gin.Context) {
fmt.Print(ctx.FormFile("file"))
ReturnJson(ctx, "apiOK", nil)
})
r.GET("/upload", func(ctx *gin.Context) {
ReturnJson(ctx, "apiOK", nil)
})
}
+115
View File
@@ -30,11 +30,21 @@
"axios": "^1.13.2", "axios": "^1.13.2",
"bootstrap": "^5.3.8", "bootstrap": "^5.3.8",
"cropperjs": "^2.1.0", "cropperjs": "^2.1.0",
"dropzone": "^6.0.0-beta.2",
"filepond": "^4.32.11",
"filepond-plugin-file-validate-type": "^1.2.9",
"filepond-plugin-image-crop": "^2.0.6",
"filepond-plugin-image-exif-orientation": "^1.0.11",
"filepond-plugin-image-preview": "^4.6.12",
"filepond-plugin-image-resize": "^2.0.10",
"flatpickr": "^4.6.13",
"litepicker": "^2.0.12", "litepicker": "^2.0.12",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"tom-select": "^2.4.3", "tom-select": "^2.4.3",
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-cropper": "^0.6.5", "vue-cropper": "^0.6.5",
"vue-filepond": "^7.0.4",
"vue-flatpickr-component": "^12.0.0",
"vue-i18n": "^11.1.12", "vue-i18n": "^11.1.12",
"vue-router": "^4.6.3" "vue-router": "^4.6.3"
}, },
@@ -1883,6 +1893,12 @@
"win32" "win32"
] ]
}, },
"node_modules/@swc/helpers": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.2.14.tgz",
"integrity": "sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA==",
"license": "MIT"
},
"node_modules/@tabler/core": { "node_modules/@tabler/core": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/@tabler/core/-/core-1.4.0.tgz", "resolved": "https://registry.npmjs.org/@tabler/core/-/core-1.4.0.tgz",
@@ -2520,6 +2536,16 @@
"node": ">=0.10" "node": ">=0.10"
} }
}, },
"node_modules/dropzone": {
"version": "6.0.0-beta.2",
"resolved": "https://registry.npmjs.org/dropzone/-/dropzone-6.0.0-beta.2.tgz",
"integrity": "sha512-k44yLuFFhRk53M8zP71FaaNzJYIzr99SKmpbO/oZKNslDjNXQsBTdfLs+iONd0U0L94zzlFzRnFdqbLcs7h9fQ==",
"license": "MIT",
"dependencies": {
"@swc/helpers": "^0.2.13",
"just-extend": "^5.0.0"
}
},
"node_modules/dunder-proto": { "node_modules/dunder-proto": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -2684,6 +2710,58 @@
} }
} }
}, },
"node_modules/filepond": {
"version": "4.32.11",
"resolved": "https://registry.npmjs.org/filepond/-/filepond-4.32.11.tgz",
"integrity": "sha512-+uHkc/XNksMMy2S+x5MGxTuA97NqzBBwmoixn3tqGELa4BgqJ+PBiWL3YeRamqAoYguT7t/au3s7ams2jjMshA==",
"license": "MIT",
"peer": true
},
"node_modules/filepond-plugin-file-validate-type": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/filepond-plugin-file-validate-type/-/filepond-plugin-file-validate-type-1.2.9.tgz",
"integrity": "sha512-Tzv07aNdZvjUXDRA3XL16QMEvh6llDrXlcZ6W0eTHQ+taHaVg/JKJTFs/AViO+6ZcpPCcQStbhYEL2HoS+vldw==",
"license": "MIT",
"peerDependencies": {
"filepond": ">=1.x <5.x"
}
},
"node_modules/filepond-plugin-image-crop": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/filepond-plugin-image-crop/-/filepond-plugin-image-crop-2.0.6.tgz",
"integrity": "sha512-bSy/KND4EP/QtW8MxIj23qgSEPUVRrT8XdktJ+OU9y8xRjFjTG+qcuw1LsycARQYRtzi8cZrD3P4POOITfkywQ==",
"license": "MIT",
"peerDependencies": {
"filepond": ">=3.x <5.x"
}
},
"node_modules/filepond-plugin-image-exif-orientation": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/filepond-plugin-image-exif-orientation/-/filepond-plugin-image-exif-orientation-1.0.11.tgz",
"integrity": "sha512-hLBc12Fk6Zkj3L8mSAn+elugHOqT5rLUbgVXQQIQjMe0FsGjtpoxqeVR6jt4IWHGat2L9sFAgU2TGmd1mqosCg==",
"license": "MIT",
"peerDependencies": {
"filepond": ">=3.x <5.x"
}
},
"node_modules/filepond-plugin-image-preview": {
"version": "4.6.12",
"resolved": "https://registry.npmjs.org/filepond-plugin-image-preview/-/filepond-plugin-image-preview-4.6.12.tgz",
"integrity": "sha512-Y8ETX5QVV0mbPB0586UH8AUmG9tZg8PuN5bdEAIlZVJFTct5ebViJ7+Am94/VhTPjLqZjBf1zmDq5JU6XRsZKw==",
"license": "MIT",
"peerDependencies": {
"filepond": ">=4.x <5.x"
}
},
"node_modules/filepond-plugin-image-resize": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/filepond-plugin-image-resize/-/filepond-plugin-image-resize-2.0.10.tgz",
"integrity": "sha512-irX+J275u8Ph1KcciCeSQmxeFjbu0+co5XVCkiwdSNnz6KiqrCKN7RXTvEbdgSdDzyi5omr2oP1rKWps5L1RsQ==",
"license": "MIT",
"peerDependencies": {
"filepond": ">=3.x <5.x"
}
},
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -2698,6 +2776,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/flatpickr": {
"version": "4.6.13",
"resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz",
"integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==",
"license": "MIT"
},
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.15.11", "version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
@@ -3011,6 +3095,12 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/just-extend": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-5.1.1.tgz",
"integrity": "sha512-b+z6yF1d4EOyDgylzQo5IminlUmzSeqR1hs/bzjBNjuGras4FXq/6TrzjxfN0j+TmI0ltJzTNlqXUMCniciwKQ==",
"license": "MIT"
},
"node_modules/kolorist": { "node_modules/kolorist": {
"version": "1.8.0", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz",
@@ -4201,6 +4291,31 @@
"integrity": "sha512-lSvY6IpeA/Tv/iPZ/FOkMHVRBPSlm7t57nuHEZFBMRNOH8ElvfqVlnHGDOAMlvPhh9gHiddiQoASS+fY0MFX0g==", "integrity": "sha512-lSvY6IpeA/Tv/iPZ/FOkMHVRBPSlm7t57nuHEZFBMRNOH8ElvfqVlnHGDOAMlvPhh9gHiddiQoASS+fY0MFX0g==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/vue-filepond": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/vue-filepond/-/vue-filepond-7.0.4.tgz",
"integrity": "sha512-HvWlCG8qjvyykrpPTDjJ+JqsHTXt5/0zWMX9vu7kU3JXCUODPUkGi9prZcauOnIZ4MqyeSZ9M0sDVwdMATyt1g==",
"license": "MIT",
"peerDependencies": {
"filepond": ">=4.7.4 < 5.x",
"vue": ">=3 < 4"
}
},
"node_modules/vue-flatpickr-component": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/vue-flatpickr-component/-/vue-flatpickr-component-12.0.0.tgz",
"integrity": "sha512-CJ5jrgTaeD66Z4mjEocSTAdB/n6IGSlUICwdBanpyCI8hswq5rwXvEYQ5IKA3K3uVjP5pBlY9Rg6o3xoszTPpA==",
"license": "MIT",
"dependencies": {
"flatpickr": "^4.6.13"
},
"engines": {
"node": ">=14.13.0"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/vue-i18n": { "node_modules/vue-i18n": {
"version": "11.1.12", "version": "11.1.12",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.1.12.tgz", "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.1.12.tgz",
+10
View File
@@ -34,11 +34,21 @@
"axios": "^1.13.2", "axios": "^1.13.2",
"bootstrap": "^5.3.8", "bootstrap": "^5.3.8",
"cropperjs": "^2.1.0", "cropperjs": "^2.1.0",
"dropzone": "^6.0.0-beta.2",
"filepond": "^4.32.11",
"filepond-plugin-file-validate-type": "^1.2.9",
"filepond-plugin-image-crop": "^2.0.6",
"filepond-plugin-image-exif-orientation": "^1.0.11",
"filepond-plugin-image-preview": "^4.6.12",
"filepond-plugin-image-resize": "^2.0.10",
"flatpickr": "^4.6.13",
"litepicker": "^2.0.12", "litepicker": "^2.0.12",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"tom-select": "^2.4.3", "tom-select": "^2.4.3",
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-cropper": "^0.6.5", "vue-cropper": "^0.6.5",
"vue-filepond": "^7.0.4",
"vue-flatpickr-component": "^12.0.0",
"vue-i18n": "^11.1.12", "vue-i18n": "^11.1.12",
"vue-router": "^4.6.3" "vue-router": "^4.6.3"
}, },
@@ -0,0 +1,83 @@
<script setup>
import { onMounted, ref, watch, defineProps,reactive } from "vue";
import flatpickr from "flatpickr";
import 'flatpickr/dist/flatpickr.css';
import 'flatpickr/dist/l10n/zh.js';
import { useI18n } from "vue-i18n";
const { t, locale } = useI18n();
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({
setdef: {
type: String,
default: "",
},
});
onMounted(() => {
// @formatter:off
//console.log(getCurrentDateTime())
//sele_data=getCurrentDateTime();
// console.log(prop.setdef)
if(prop.setdef=="")
{
datatimepack_config.defaultDate=getCurrentDateTime()
}else{
datatimepack_config.defaultDate=prop.setdef
}
datatimepack_config.locale=locale.value=="zh-CN"?"zh":"en";
flatpickr(datatimepack.value, datatimepack_config);
});
defineExpose({
});
</script>
<template>
<div ></div>
<input ref="datatimepack" type="datetime-local" class="form-control" v-model="sele_data">
</template>
@@ -0,0 +1,133 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import Dropzone from 'dropzone'
import 'dropzone/dist/dropzone.css'
const dropzoneElement = ref(null)
let dropzoneInstance = null
const files = ref([])
// 初始化 Dropzone
const initDropzone = () => {
if (!dropzoneElement.value) return
// 禁用自动发现
Dropzone.autoDiscover = false
// 移除任何现有的 Dropzone 实例
if (dropzoneInstance) {
dropzoneInstance.destroy()
}
// 初始化新的实例
dropzoneInstance = new Dropzone(dropzoneElement.value, {
url: '/api/files/upload', // 上传地址
method: 'post',
// 确保不启用分片上传
// chunking: false, // 明确禁用分片
// forceChunking: false, // 强制不分片
// chunkSize: false, // 不分片大小
// retryChunks: false, // 不重试分片
// parallelChunkUploads: false, // 不并行上传分片
parallelUploads: 1, // 同时上传的文件数
maxFilesize: 10, // MB
maxFiles: 5, // 最大文件数
acceptedFiles: 'image/*,.pdf,.doc,.docx', // 接受的文件类型
addRemoveLinks: true, // 显示移除链接
dictDefaultMessage: '拖放文件到这里或点击上传',
dictFallbackMessage: '您的浏览器不支持拖放文件上传',
dictFileTooBig: '文件太大 ({{filesize}}MB). 最大文件大小: {{maxFilesize}}MB.',
dictInvalidFileType: '不支持此文件类型',
dictResponseError: '服务器响应错误 {{statusCode}}',
dictCancelUpload: '取消上传',
dictUploadCanceled: '上传已取消',
dictCancelUploadConfirmation: '确定要取消上传吗?',
dictRemoveFile: '移除文件',
dictMaxFilesExceeded: '您最多只能上传 {{maxFiles}} 个文件',
// 事件处理
init: function() {
this.on('success', (file, response) => {
console.log('上传成功:', file.name, response)
}),
this.on('error', (file, errorMessage) => {
console.error('上传失败:', file.name, errorMessage)
}),
this.on('removedfile', (file) => {
console.log('remove:')
files.value = files.value.filter(f => f.name !== file.name)
})
}
})
}
// 自定义方法
const formatBytes = (bytes, decimals = 2) => {
if (bytes === 0) return '0 Bytes'
const k = 1024
const dm = decimals < 0 ? 0 : decimals
const sizes = ['Bytes', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
}
// 手动添加文件的方法
const addFiles = (fileList) => {
if (dropzoneInstance) {
Array.from(fileList).forEach(file => {
dropzoneInstance.addFile(file)
})
}
}
// 获取所有已添加的文件
const getAllFiles = () => {
return dropzoneInstance ? dropzoneInstance.files : []
}
// 清除所有文件
const removeAllFiles = () => {
if (dropzoneInstance) {
dropzoneInstance.removeAllFiles(true)
}
}
// 组件挂载时初始化
onMounted(() => {
initDropzone()
})
// 组件卸载时销毁
onUnmounted(() => {
if (dropzoneInstance) {
dropzoneInstance.destroy()
}
})
</script>
<template>
<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>
</template>
<style scoped>
.dropzone {
border: 2px dashed #cccccc;
border-radius: 5px;
background: white;
padding: 20px;
min-height: 150px;
}
</style>
+14
View File
@@ -154,5 +154,19 @@
"license": "License", "license": "License",
"source_code": "Source Code", "source_code": "Source Code",
"copy": "Copyright © 2025 Operations. All rights reserved." "copy": "Copyright © 2025 Operations. All rights reserved."
},
"cost_type":{
"unit_price":"Unit Price",
"freight":"Freight"
},
"order_status": {
"pending_order": "Pending Order",
"order_placed": "Order Placed",
"in_transit": "In Transit",
"completed": "Completed",
"refund_requested": "Refund Requested",
"returning": "Returning",
"refunded": "Refunded",
"lost_package": "Lost Package"
} }
} }
+14
View File
@@ -154,5 +154,19 @@
"license": "协议", "license": "协议",
"source_code": "源码", "source_code": "源码",
"copy": "版权 © 2025 Operations. 保留所有权利。" "copy": "版权 © 2025 Operations. 保留所有权利。"
},
"cost_type": {
"unit_price": "单价",
"freight": "运费"
},
"order_status": {
"pending_order": "待下单",
"order_placed": "已下单",
"in_transit": "运输中",
"completed": "已完成",
"refund_requested": "申请退款",
"returning": "退回中",
"refunded": "已退款",
"lost_package": "丢件"
} }
} }
@@ -3,7 +3,7 @@ import { onMounted, watch, ref ,reactive} from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import tagadder from "@/components/tagadder.vue"; import tagadder from "@/components/tagadder.vue";
import datePicker from "@/components/datePicker.vue"; import dateTimePicker from "@/components/dateTimePicker.vue";
import TomSelect from "tom-select"; import TomSelect from "tom-select";
import "tom-select/dist/css/tom-select.css"; import "tom-select/dist/css/tom-select.css";
@@ -14,47 +14,69 @@ function functionupdataTitle() {
document.title = "Operations." + t("purchase.add_part"); document.title = "Operations." + t("purchase.add_part");
} }
//货币类型
const currency_type = reactive({
1: "RMB",
2: "MOP",
3: "HKD",
4: "USD",
});
//成本类型
const cost_type = reactive({
1: t("cost_type.unit_price"),
2: t("cost_type.freight"),
});
function update_cost_type() {
cost_type["1"] = t("cost_type.unit_price");
cost_type["2"] = t("cost_type.freight");
}
//订单状态
const order_status = reactive({
1: t("order_status.pending_order"),
2: t("order_status.order_placed"),
3: t("order_status.in_transit"),
4: t("order_status.completed"),
5: t("order_status.refund_requested"),
6: t("order_status.returning"),
7: t("order_status.refunded"),
8: t("order_status.lost_package"),
});
function update_order_status() {
order_status["1"] = t("order_status.pending_order");
order_status["2"] = t("order_status.order_placed");
order_status["3"] = t("order_status.in_transit");
order_status["4"] = t("order_status.completed");
order_status["5"] = t("order_status.refund_requested");
order_status["6"] = t("order_status.returning");
order_status["7"] = t("order_status.refunded");
order_status["8"] = t("order_status.lost_package");
}
const cost_sheet_tab = reactive([]); const cost_sheet_tab = reactive([]);
// 表单对象 // 表单对象
const cost_sheet = reactive({ const cost_sheet = reactive({
type: '1', type: "1",
int: 1, int: 1,
cost: 0.0, cost: 0.0,
currency_type:'1' currency_type: "1",
}) });
function del_cost(key) {
cost_sheet_tab.splice(key, 1);
}
function add_cost() { function add_cost() {
var t={ cost_sheet_tab.push(JSON.parse(JSON.stringify(cost_sheet)));
type: cost_sheet.type, // var t = {
int: cost_sheet.int, // type: cost_type[cost_sheet.type],
cost: cost_sheet.cost, // int: cost_sheet.int,
currency_type:cost_sheet.currency_type // cost: cost_sheet.cost,
// currency_type: currency_type[cost_sheet.currency_type],
// };
// cost_sheet_tab.push(t);
//console.log(t);
} }
cost_sheet_tab.push(t)
console.log(cost_sheet_tab)
}
// const select_beast = ref()
// const select_type = ref()
// function sele_init(){
// new TomSelect(select_beast.value,{
// create: true,
// sortField: {
// //field: "text",
// //direction: "asc"
// }
// });
// new TomSelect(select_type.value,{
// create: true,
// sortField: {
// //field: "text",
// //direction: "asc"
// }
// });
// }
onMounted(() => { onMounted(() => {
functionupdataTitle(); functionupdataTitle();
@@ -63,6 +85,8 @@ onMounted(() => {
// 监听语言变化,更新标题 // 监听语言变化,更新标题
watch(locale, () => { watch(locale, () => {
functionupdataTitle(); functionupdataTitle();
update_cost_type();
update_order_status();
}); });
</script> </script>
@@ -96,7 +120,7 @@ watch(locale, () => {
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label" <label class="form-label"
>用途 <span class="form-label-description">0/100</span></label >备注 <span class="form-label-description">0/100</span></label
> >
<textarea <textarea
class="form-control" class="form-control"
@@ -129,7 +153,10 @@ watch(locale, () => {
<div class="mt-3"> <div class="mt-3">
<label class="form-label">成本</label> <label class="form-label">成本</label>
<table class="table table-vcenter card-table table-striped"> <table
v-show="cost_sheet_tab.length"
class="table table-vcenter card-table table-striped"
>
<thead> <thead>
<tr> <tr>
<th>类型</th> <th>类型</th>
@@ -141,14 +168,23 @@ watch(locale, () => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="value in cost_sheet_tab"> <tr v-for="(value, key) in cost_sheet_tab">
<td>{{value.type}}</td> <td>{{ cost_type[value.type] }}</td>
<td class="text-secondary">{{ value.int }}</td> <td class="text-secondary">{{ value.int }}</td>
<td class="text-secondary">{{ value.cost }}</td> <td class="text-secondary">{{ value.cost }}</td>
<td class="text-secondary">{{value.cost*value.int}}</td> <td class="text-secondary">
<td class="text-secondary">{{value.currency_type}}</td> {{ value.cost * value.int }}
</td>
<td class="text-secondary">
{{ currency_type[value.currency_type] }}
</td>
<td> <td>
<button class="btn btn-outline-danger">Del</button> <button
class="btn btn-outline-danger"
@click="del_cost(key)"
>
Del
</button>
</td> </td>
</tr> </tr>
<!-- <tr> <!-- <tr>
@@ -174,8 +210,9 @@ watch(locale, () => {
value="1" value="1"
v-model="cost_sheet.type" v-model="cost_sheet.type"
> >
<option value="1">单价</option> <option v-for="(value, key) in cost_type" :value="key">
<option value="2">运输</option> {{ value }}
</option>
</select> </select>
</div> </div>
<div class="col-xl-3"> <div class="col-xl-3">
@@ -209,15 +246,20 @@ watch(locale, () => {
value="1" value="1"
v-model="cost_sheet.currency_type" v-model="cost_sheet.currency_type"
> >
<option value="1">RMB</option> <option
<option value="2">MOP</option> v-for="(value, key) in currency_type"
<option value="3">HKD</option> :value="key"
<option value="4">USD</option> >
{{ value }}
</option>
</select> </select>
</div> </div>
<div class="col-xl-2"> <div class="col-xl-2">
操作 操作
<button class="form-control btn btn-outline-primary" @click="add_cost"> <button
class="form-control btn btn-outline-primary"
@click="add_cost"
>
添加 添加
</button> </button>
</div> </div>
@@ -234,7 +276,7 @@ watch(locale, () => {
<div class="row g-5"> <div class="row g-5">
<div class="col-xl-4"> <div class="col-xl-4">
<label class="form-label required">更新时间</label> <label class="form-label required">更新时间</label>
<datePicker></datePicker> <dateTimePicker></dateTimePicker>
</div> </div>
<div class="col-xl-4"> <div class="col-xl-4">
<label class="form-label">快递单号</label> <label class="form-label">快递单号</label>
@@ -254,13 +296,9 @@ watch(locale, () => {
autocomplete="off" autocomplete="off"
value="1" value="1"
> >
<option value="1">待下单</option> <option v-for="(value, key) in order_status" :value="key">
<option value="2">已下单</option> {{ value }}
<option value="3">运输中</option> </option>
<option value="4">已完成</option>
<option value="5">申请退款</option>
<option value="6">退回中</option>
<option value="7">已退款</option>
</select> </select>
</div> </div>
</div> </div>
+2 -16
View File
@@ -1,22 +1,8 @@
<script setup> <script setup>
import { useUserStore } from '@/stores/user' import useDropzone from '@/components/useDropzone.vue';
import imageCropper from '@/components/imageCropper.vue';
import croppertest from '@/components/croppertest.vue';
import imageCropperComponent from '@/components/imageCropperComponent.vue';
const user = useUserStore()
</script> </script>
<template> <template>
test
<imageCropper></imageCropper>
<useDropzone></useDropzone>
</template> </template>
+17 -15
View File
@@ -1,33 +1,35 @@
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from "node:url";
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import vue from '@vitejs/plugin-vue' import vue from "@vitejs/plugin-vue";
import vueDevTools from 'vite-plugin-vue-devtools' import vueDevTools from "vite-plugin-vue-devtools";
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [vue(), vueDevTools()],
vue(),
vueDevTools(),
],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) "@": fileURLToPath(new URL("./src", import.meta.url)),
}, },
}, },
build: { build: {
outDir: '../../backend/dist', // 默认是 'dist',可以修改为你想要的目录名 outDir: "../../backend/dist", // 默认是 'dist',可以修改为你想要的目录名
assetsDir: 'assets', // 静态资源目录(相对于 outDir) assetsDir: "assets", // 静态资源目录(相对于 outDir)
}, },
server: { server: {
proxy: { proxy: {
'/api': { "/api": {
target: 'http://127.0.0.1:8080', target: "http://127.0.0.1:8080",
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '/api'), // 如果需要重写路径 rewrite: (path) => path.replace(/^\/api/, "/api"), // 如果需要重写路径
// 如果后端接口没有 /api 前缀,可以这样写: // 如果后端接口没有 /api 前缀,可以这样写:
// rewrite: (path) => path.replace(/^\/api/, '') // rewrite: (path) => path.replace(/^\/api/, '')
// 设置代理超时配置
// proxyTimeout: 30000, // 代理服务器等待目标服务器响应的超时时间(毫秒)
// timeout: 30000, // 整个请求的超时时间(毫秒)
// connectTimeout: 30000, // 连接超时(毫秒,某些版本支持)
}, },
}, },
}, },
}) });