u
This commit is contained in:
1 parent
b7f2efc7c3
commit
cc88205cba
23 files changed
+1239
-799
No files matched your search
+2
-3
@@ -41,7 +41,6 @@ public class FileController {
|
||||
// 3. 物理路径
|
||||
String basePath = fileConfig.getTempPath(); // D:/data/file/temp/
|
||||
|
||||
System.out.println(basePath);
|
||||
// 4. 保存
|
||||
FileUtils.saveFile(file, basePath, uuidName);
|
||||
|
||||
@@ -99,7 +98,7 @@ public class FileController {
|
||||
|
||||
// 8. 返回
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("fileName", uuidName);
|
||||
result.put("fileName", fileName);
|
||||
result.put("url", url);
|
||||
result.put("path", relativePath);
|
||||
|
||||
@@ -237,7 +236,7 @@ public class FileController {
|
||||
result.put("url", url);
|
||||
result.put("path", relativePath);
|
||||
result.put("uid", nextId);
|
||||
result.put("fileName", newFileName);
|
||||
result.put("fileName", fileName);
|
||||
result.put("bucket", bucket);
|
||||
|
||||
return Result.ok(result);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
url=jdbc:sqlserver://118.89.70.199:1433;databaseName=G3BoxOCR
|
||||
username=sa
|
||||
password=zhang520..
|
||||
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
|
||||
#url=jdbc:sqlserver://127.0.0.1:1433;databaseName=G3ContainerOCR
|
||||
#url=jdbc:sqlserver://118.89.70.199:1433;databaseName=G3BoxOCR
|
||||
#username=sa
|
||||
#password=123456@aaa
|
||||
#password=zhang520..
|
||||
#driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
|
||||
url=jdbc:sqlserver://127.0.0.1:1433;databaseName=G3ContainerOCR
|
||||
username=sa
|
||||
password=123456@aaa
|
||||
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
|
||||
|
||||
@@ -14,7 +14,8 @@ const form = ref<any>({
|
||||
b_container_img: '',
|
||||
})
|
||||
|
||||
const subFileList = ref([])
|
||||
const subFileList = ref([]) // 装货照片
|
||||
const subFileList2 = ref([]) // 发货单、签收单、过磅单
|
||||
|
||||
onLoad((options) => {
|
||||
const id = options.id
|
||||
@@ -34,7 +35,7 @@ async function loadMainData() {
|
||||
try {
|
||||
const orgUrl = await getOrgBaseUrl(userStore.userInfo.orgid)
|
||||
|
||||
// 并发请求(提升性能)
|
||||
// ================= 并发请求 =================
|
||||
const [res, fileRes] = await Promise.all([
|
||||
loadDataApi({
|
||||
viewName: 'v_container',
|
||||
@@ -42,7 +43,7 @@ async function loadMainData() {
|
||||
}),
|
||||
loadDataApi({
|
||||
viewName: 'bf_file',
|
||||
searchCondition: `father = '${form.value.b_id}' AND mx_cate_id = '1'`,
|
||||
searchCondition: `father = '${form.value.b_id}'`,
|
||||
}),
|
||||
])
|
||||
|
||||
@@ -60,19 +61,46 @@ async function loadMainData() {
|
||||
form.value = mainData
|
||||
}
|
||||
else {
|
||||
console.warn('未获取到主数据')
|
||||
uni.showToast({
|
||||
title: '当前数据无效',
|
||||
icon: 'none',
|
||||
duration: 1500,
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
const pages = getCurrentPages()
|
||||
|
||||
if (pages.length > 1) {
|
||||
uni.navigateBack()
|
||||
}
|
||||
else {
|
||||
uni.reLaunch({
|
||||
url: '/',
|
||||
})
|
||||
}
|
||||
}, 1500)
|
||||
return
|
||||
}
|
||||
|
||||
// ================= 子表 =================
|
||||
// ================= 子表统一处理 =================
|
||||
if (fileRes.success) {
|
||||
const files = (fileRes.data || []).map(file => ({
|
||||
const allFiles = fileRes.data || []
|
||||
|
||||
const formatFile = file => ({
|
||||
...file,
|
||||
mx_mapfilename: buildPubicUrl(orgUrl, file.mx_mapfilename),
|
||||
name: file.mx_filename,
|
||||
url: buildPubicUrl(orgUrl, file.mx_mapfilename),
|
||||
}))
|
||||
})
|
||||
|
||||
subFileList.value = files
|
||||
// 按分类拆分
|
||||
subFileList.value = allFiles
|
||||
.filter(f => f.mx_cate_id === '1')
|
||||
.map(formatFile)
|
||||
|
||||
subFileList2.value = allFiles
|
||||
.filter(f => f.mx_cate_id === '2')
|
||||
.map(formatFile)
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
@@ -150,48 +178,68 @@ async function handleConfirm() {
|
||||
})
|
||||
|
||||
const fileInserts = []
|
||||
const fileUpdates = []
|
||||
|
||||
// 子表
|
||||
for (let index = 0; index < subFileList.value.length; index++) {
|
||||
const fileItem = subFileList.value[index]
|
||||
const allFiles = [
|
||||
...subFileList.value.map(item => ({ ...item, cate: '1' })),
|
||||
...subFileList2.value.map(item => ({ ...item, cate: '2' })),
|
||||
]
|
||||
|
||||
if (fileItem.subid) {
|
||||
// 已上传的文件,无需重复上传
|
||||
continue
|
||||
}
|
||||
const grouped = allFiles.reduce((acc, item) => {
|
||||
if (!acc[item.cate])
|
||||
acc[item.cate] = []
|
||||
acc[item.cate].push(item)
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const res = await uploadContainerFileApi(fileItem.file.path, {
|
||||
jobId: form.value.b_id,
|
||||
containerNo: form.value.b_container_no,
|
||||
fileName: fileItem.name,
|
||||
})
|
||||
for (const cate in grouped) {
|
||||
let index = 1
|
||||
|
||||
const maxIndexNumber = Math.max(
|
||||
0,
|
||||
...subFileList.value.map(item => item.mx_xh || 0),
|
||||
)
|
||||
for (const fileItem of grouped[cate]) {
|
||||
const mx_xh = index++
|
||||
|
||||
if (res.success) {
|
||||
const indexNumber = maxIndexNumber + 1
|
||||
// 已存在 → update
|
||||
if (fileItem.subid) {
|
||||
fileUpdates.push({
|
||||
subid: fileItem.subid,
|
||||
mx_xh,
|
||||
mx_cate_id: cate,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// 新增 → upload
|
||||
const res = await uploadContainerFileApi(fileItem.file.path, {
|
||||
jobId: form.value.b_id,
|
||||
containerNo: form.value.b_container_no,
|
||||
fileName: fileItem.name,
|
||||
})
|
||||
|
||||
if (!res.success)
|
||||
continue
|
||||
|
||||
fileInserts.push({
|
||||
subid: res.data.uid,
|
||||
father: form.value.b_id,
|
||||
mx_xh: indexNumber,
|
||||
mx_xh,
|
||||
mx_filename: res.data.fileName,
|
||||
mx_filesize: fileItem.file.size,
|
||||
mx_fileext: getFileExtension(fileItem.file.name),
|
||||
mx_mapfilename: res.data.path,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: '1',
|
||||
mx_cate_id: cate,
|
||||
})
|
||||
|
||||
fileItem.subid = res.data.uid
|
||||
}
|
||||
}
|
||||
|
||||
if (fileInserts.length === 0) {
|
||||
if (fileInserts.length === 0 && fileUpdates.length === 0) {
|
||||
toast.success('保存成功')
|
||||
|
||||
setTimeout(() => {
|
||||
loadMainData()
|
||||
}, 1000)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -200,7 +248,7 @@ async function handleConfirm() {
|
||||
tableName: 'bf_file',
|
||||
keyField: 'subid',
|
||||
inserts: fileInserts,
|
||||
updates: [],
|
||||
updates: fileUpdates,
|
||||
deletes: [],
|
||||
},
|
||||
]
|
||||
@@ -208,6 +256,10 @@ async function handleConfirm() {
|
||||
saveObjectApi(reqData).then((res) => {
|
||||
if (res.success) {
|
||||
toast.success('保存成功')
|
||||
|
||||
setTimeout(() => {
|
||||
loadMainData()
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -225,6 +277,7 @@ function validateContainerNo(containerNo) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
const templateCollapse = ref<string[]>(['template1'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -272,12 +325,62 @@ function validateContainerNo(containerNo) {
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-collapse v-model="templateCollapse" style="margin-top: 32rpx;">
|
||||
<wd-collapse-item name="template1">
|
||||
<template #title>
|
||||
<view class="template-header">
|
||||
<view class="title">
|
||||
<sar-icon
|
||||
name="file"
|
||||
size="38rpx"
|
||||
style="margin-right: 16rpx;"
|
||||
/>
|
||||
<text>
|
||||
上传模板(参考)
|
||||
</text>
|
||||
</view>
|
||||
<sar-icon
|
||||
:name="templateCollapse.includes('template1') ? 'up' : 'down'"
|
||||
size="38rpx"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
<view class="template-container">
|
||||
<view class="item">
|
||||
<text class="title">
|
||||
1、提空箱拍照模版
|
||||
</text>
|
||||
|
||||
<wd-img
|
||||
style="width:100%;height:400rpx;"
|
||||
src="/static/images/D21304CD0CDAB09EE3349E8B7D078CC9.jpg"
|
||||
:enable-preview="true"
|
||||
@click.stop
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="item" style="margin-left:16rpx">
|
||||
<text class="title">
|
||||
2、装箱拍照模版
|
||||
</text>
|
||||
|
||||
<wd-img
|
||||
style="width:100%;height:400rpx;"
|
||||
src="/static/images/027C52B0A3986905F161127336244D72.jpg"
|
||||
:enable-preview="true"
|
||||
@click.stop
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</wd-collapse-item>
|
||||
</wd-collapse>
|
||||
|
||||
<wd-cell-group custom-class="group" border use-slot style="margin-top: 32rpx;">
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="tupian" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
其他图片
|
||||
装货照片
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
@@ -292,6 +395,27 @@ function validateContainerNo(containerNo) {
|
||||
/>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group custom-class="group" border use-slot style="margin-top: 32rpx;">
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="tupian" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
发货单、签收单、过磅单
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<view class="step-content">
|
||||
<sar-upload
|
||||
v-model="subFileList2"
|
||||
multiple
|
||||
:before-read="beforeRead"
|
||||
:before-remove="beforeRemove"
|
||||
@item-click="onItemClick"
|
||||
@remove="onRemove"
|
||||
/>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
<view class="g3-footer">
|
||||
<view class="footer-main">
|
||||
@@ -465,4 +589,34 @@ page {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 3rpx 6rpx rgba(58, 110, 232, 0.15);
|
||||
}
|
||||
|
||||
.template-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
font-weight: 500;
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.template-container {
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 50%;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
padding-left: 10rpx;
|
||||
border-left: 6rpx solid var(--sar-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -19,7 +19,8 @@ const form = ref({
|
||||
ocrNo: '',
|
||||
})
|
||||
|
||||
const subFileList = ref([])
|
||||
const subFileList = ref([]) // 装货照片
|
||||
const subFileList2 = ref([]) // 发货单、签收单、过磅单
|
||||
|
||||
const tipContainerNo = ref('')
|
||||
|
||||
@@ -167,7 +168,7 @@ async function handleConfirm() {
|
||||
b_ocr_score: form.value.ocrScore || 0.00,
|
||||
}
|
||||
const fileInserts = []
|
||||
|
||||
|
||||
// 主表
|
||||
await uploadContainerFileApi(boxImage.value.path, {
|
||||
jobId: form.value.b_id,
|
||||
@@ -191,31 +192,47 @@ async function handleConfirm() {
|
||||
}
|
||||
})
|
||||
|
||||
// 子表
|
||||
for (let index = 0; index < subFileList.value.length; index++) {
|
||||
const fileItem = subFileList.value[index]
|
||||
const indexMap = {}
|
||||
|
||||
const getNextIndex = (cate) => {
|
||||
if (!indexMap[cate]) {
|
||||
indexMap[cate] = 1
|
||||
}
|
||||
return indexMap[cate]++
|
||||
}
|
||||
|
||||
const allFiles = [
|
||||
...subFileList.value.map(item => ({
|
||||
...item,
|
||||
cate: '1',
|
||||
})),
|
||||
...subFileList2.value.map(item => ({
|
||||
...item,
|
||||
cate: '2',
|
||||
})),
|
||||
]
|
||||
|
||||
for (const fileItem of allFiles) {
|
||||
const res = await uploadContainerFileApi(fileItem.file.path, {
|
||||
jobId: form.value.b_id,
|
||||
containerNo: form.value.b_container_no,
|
||||
fileName: fileItem.name,
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
const indexNumber = index + 2
|
||||
if (!res.success)
|
||||
continue
|
||||
|
||||
fileInserts.push({
|
||||
subid: res.data.uid,
|
||||
father: form.value.b_id,
|
||||
mx_xh: indexNumber,
|
||||
mx_filename: res.data.fileName,
|
||||
mx_filesize: fileItem.file.size,
|
||||
mx_fileext: getFileExtension(fileItem.file.name),
|
||||
mx_mapfilename: res.data.path,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: '1',
|
||||
})
|
||||
}
|
||||
fileInserts.push({
|
||||
subid: res.data.uid,
|
||||
father: form.value.b_id,
|
||||
mx_xh: getNextIndex(fileItem.cate),
|
||||
mx_filename: res.data.fileName,
|
||||
mx_filesize: fileItem.file.size,
|
||||
mx_fileext: getFileExtension(fileItem.file.name),
|
||||
mx_mapfilename: res.data.path,
|
||||
mx_moduleid: 'b_container',
|
||||
mx_cate_id: fileItem.cate,
|
||||
})
|
||||
}
|
||||
|
||||
const reqData = [
|
||||
@@ -271,11 +288,15 @@ async function continueAdd() {
|
||||
form.value.b_id = idRes.data
|
||||
|
||||
subFileList.value = []
|
||||
subFileList2.value = []
|
||||
|
||||
showResult.value = false
|
||||
|
||||
tipContainerNo.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const templateCollapse = ref<string[]>(['template1'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -359,12 +380,62 @@ async function continueAdd() {
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-collapse v-model="templateCollapse" style="margin-top: 32rpx;">
|
||||
<wd-collapse-item name="template1">
|
||||
<template #title>
|
||||
<view class="template-header">
|
||||
<view class="title">
|
||||
<sar-icon
|
||||
name="file"
|
||||
size="38rpx"
|
||||
style="margin-right: 16rpx;"
|
||||
/>
|
||||
<text>
|
||||
上传模板(参考)
|
||||
</text>
|
||||
</view>
|
||||
<sar-icon
|
||||
:name="templateCollapse.includes('template1') ? 'up' : 'down'"
|
||||
size="38rpx"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
<view class="template-container">
|
||||
<view class="item">
|
||||
<text class="title">
|
||||
1、提空箱拍照模版
|
||||
</text>
|
||||
|
||||
<wd-img
|
||||
style="width:100%;height:400rpx;"
|
||||
src="/static/images/D21304CD0CDAB09EE3349E8B7D078CC9.jpg"
|
||||
:enable-preview="true"
|
||||
@click.stop
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="item" style="margin-left:16rpx">
|
||||
<text class="title">
|
||||
2、装箱拍照模版
|
||||
</text>
|
||||
|
||||
<wd-img
|
||||
style="width:100%;height:400rpx;"
|
||||
src="/static/images/027C52B0A3986905F161127336244D72.jpg"
|
||||
:enable-preview="true"
|
||||
@click.stop
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</wd-collapse-item>
|
||||
</wd-collapse>
|
||||
|
||||
<wd-cell-group custom-class="group" border use-slot style="margin-top: 32rpx;">
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="tupian" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
其他图片
|
||||
装货照片
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
@@ -378,6 +449,25 @@ async function continueAdd() {
|
||||
/>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
<wd-cell-group custom-class="group" border use-slot style="margin-top: 32rpx;">
|
||||
<template #title>
|
||||
<view style="display:flex;align-items: center;">
|
||||
<sar-icon family="iconfont" name="tupian" size="38rpx" color="var(--sar-primary)" style="margin-right: 16rpx;" />
|
||||
<text>
|
||||
发货单、签收单、过磅单
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
<view class="step-content">
|
||||
<sar-upload
|
||||
v-model="subFileList2"
|
||||
multiple
|
||||
:before-read="beforeRead"
|
||||
:before-remove="beforeRemove"
|
||||
@item-click="onItemClick"
|
||||
/>
|
||||
</view>
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
<view class="g3-footer">
|
||||
<view class="footer-main">
|
||||
@@ -568,4 +658,34 @@ page {
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 3rpx 6rpx rgba(58, 110, 232, 0.15);
|
||||
}
|
||||
|
||||
.template-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
font-weight: 500;
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.template-container {
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 50%;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
padding-left: 10rpx;
|
||||
border-left: 6rpx solid var(--sar-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 467 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -10,7 +10,7 @@ PUBLIC_SERVER_PORT=8080
|
||||
|
||||
# API
|
||||
# 后端 API 基础地址
|
||||
# PUBLIC_API_BASE_URL=http://ser369.g3soft.cn:80/api
|
||||
PUBLIC_API_BASE_URL=http://192.168.1.137:80/api
|
||||
PUBLIC_API_BASE_URL=http://ser369.g3soft.cn:80/api
|
||||
# PUBLIC_API_BASE_URL=http://192.168.1.137:80/api
|
||||
|
||||
PUBLIC_ALIYUN_BUCKET = g3hd
|
||||
+8
@@ -18,6 +18,7 @@ declare module 'vue' {
|
||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
@@ -27,16 +28,23 @@ declare module 'vue' {
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElResult: typeof import('element-plus/es')['ElResult']
|
||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSplitter: typeof import('element-plus/es')['ElSplitter']
|
||||
ElSplitterPanel: typeof import('element-plus/es')['ElSplitterPanel']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElText: typeof import('element-plus/es')['ElText']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
ElTree: typeof import('element-plus/es')['ElTree']
|
||||
G3Column: typeof import('./src/components/g3-table/g3-column.vue')['default']
|
||||
|
||||
@@ -130,6 +130,9 @@ function handleUpdateDialogClosed() {
|
||||
|
||||
function handleShowUpdateDialog(file) {
|
||||
updateFile.value = JSON.parse(JSON.stringify(file));
|
||||
|
||||
updateFile.value._main = file.mx_cate_id === "0";
|
||||
|
||||
showUpdateDialog.value = true;
|
||||
}
|
||||
|
||||
@@ -162,7 +165,6 @@ async function handleConfirmUpdate() {
|
||||
subid: updateFile.value.subid,
|
||||
mx_filename: updateFile.value.mx_filename,
|
||||
mx_bz: updateFile.value.mx_bz,
|
||||
mx_cate_id: updateFile.value.mx_cate_id,
|
||||
},
|
||||
],
|
||||
deletes: [],
|
||||
@@ -170,7 +172,7 @@ async function handleConfirmUpdate() {
|
||||
];
|
||||
|
||||
// 检查是否设置了箱门照
|
||||
if (updateFile.value.mx_cate_id === "0") {
|
||||
if (updateFile.value._main) {
|
||||
requestData[0].updates[0].mx_xh = "0";
|
||||
|
||||
// 检查数据库表其它是否有文件已经设置了箱门照
|
||||
@@ -178,6 +180,7 @@ async function handleConfirmUpdate() {
|
||||
const res = await loadDataApi("bf_file", searchCondition, "mx_xh", ["subid", "mx_xh"]);
|
||||
|
||||
if (res.success && res.data.length > 0) {
|
||||
// 更新旧数据
|
||||
requestData.push({
|
||||
tableName: "bf_file",
|
||||
keyField: "subid",
|
||||
@@ -185,13 +188,32 @@ async function handleConfirmUpdate() {
|
||||
updates: [
|
||||
{
|
||||
subid: res.data[0].subid,
|
||||
mx_cate_id: "1",
|
||||
mx_cate_id: updateFile.value.mx_cate_id,
|
||||
mx_xh: updateFile.value.mx_xh,
|
||||
},
|
||||
],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
// 更新新数据
|
||||
requestData[0].updates[0].mx_cate_id = "0";
|
||||
|
||||
// 更新主图
|
||||
requestData.push({
|
||||
tableName: "b_container",
|
||||
keyField: "b_id",
|
||||
inserts: [],
|
||||
updates: [
|
||||
{
|
||||
b_id: props.father,
|
||||
b_container_img: extractFilePath(updateFile.value.mx_mapfilename),
|
||||
},
|
||||
],
|
||||
deletes: [],
|
||||
});
|
||||
} else {
|
||||
requestData[0].updates[0].mx_cate_id = "0";
|
||||
|
||||
requestData.push({
|
||||
tableName: "b_container",
|
||||
keyField: "b_id",
|
||||
@@ -215,7 +237,7 @@ async function handleConfirmUpdate() {
|
||||
|
||||
showUpdateDialog.value = false;
|
||||
|
||||
loadFiles()
|
||||
loadFiles();
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error("更新文件时发生错误");
|
||||
@@ -287,7 +309,7 @@ async function loadFiles() {
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await loadDataApi("bf_file", searchCondition, "mx_cate_id,mx_xh");
|
||||
const res = await loadDataApi("bf_file", searchCondition, "mx_cate_id ASC, mx_xh ASC");
|
||||
|
||||
if (res.success) {
|
||||
let datas = res.data.map((item) => {
|
||||
@@ -385,69 +407,75 @@ function handleDrop(e) {
|
||||
|
||||
// 本地上传方法
|
||||
async function uploadLocalFiles(files) {
|
||||
if (files.length > 0) {
|
||||
const currentLength = fileList.value.length;
|
||||
if (!files.length) return;
|
||||
|
||||
Array.from(files).forEach((file, index) => {
|
||||
const fileInfo = {
|
||||
mx_filename: file.name,
|
||||
mx_filesize: file.size,
|
||||
mx_fileext: getFileExtension(file.name),
|
||||
mx_inputuser_id: userStore.userInfo.userid,
|
||||
mx_inputdatetime: "",
|
||||
mx_mapfilename: "",
|
||||
mx_xh: currentLength + index + 1,
|
||||
_content: null,
|
||||
_status: "pending",
|
||||
};
|
||||
const currentLength = fileList.value.length;
|
||||
|
||||
const reader = new FileReader();
|
||||
Array.from(files).forEach((file, index) => {
|
||||
const fileInfo = {
|
||||
mx_filename: file.name,
|
||||
mx_filesize: file.size,
|
||||
mx_fileext: getFileExtension(file.name),
|
||||
mx_inputuser_id: userStore.userInfo.userid,
|
||||
mx_inputdatetime: "",
|
||||
mx_mapfilename: "",
|
||||
mx_xh: currentLength + index + 1,
|
||||
|
||||
reader.onload = async (event) => {
|
||||
const blob = new Blob([event.target.result], { type: file.type });
|
||||
_content: file, // 默认原始文件
|
||||
_status: "pending",
|
||||
};
|
||||
|
||||
if (file.type.startsWith("image/")) {
|
||||
try {
|
||||
const tempUrl = URL.createObjectURL(blob);
|
||||
// ===== 图片处理 =====
|
||||
if (file.type.startsWith("image/")) {
|
||||
const tempUrl = URL.createObjectURL(file);
|
||||
|
||||
if (file.size > 512000) {
|
||||
const { url, size, blob: compressedBlob } = await compressImage(tempUrl);
|
||||
if (file.size > 512000) {
|
||||
compressImage(tempUrl)
|
||||
.then(({ url, size, blob }) => {
|
||||
fileInfo.mx_mapfilename = url;
|
||||
fileInfo.mx_filesize = size;
|
||||
|
||||
fileInfo.mx_mapfilename = url;
|
||||
fileInfo.mx_filesize = size;
|
||||
fileInfo._content = compressedBlob;
|
||||
} else {
|
||||
fileInfo.mx_mapfilename = tempUrl;
|
||||
fileInfo._content = blob;
|
||||
}
|
||||
} catch (err) {
|
||||
// 用压缩后的 File(推荐稳定结构)
|
||||
fileInfo._content = new File([blob], file.name, {
|
||||
type: file.type,
|
||||
});
|
||||
|
||||
fileList.value.push(fileInfo);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("图片压缩失败:", err);
|
||||
fileInfo.mx_mapfilename = URL.createObjectURL(blob);
|
||||
}
|
||||
} else {
|
||||
fileInfo._content = blob;
|
||||
}
|
||||
|
||||
fileInfo.mx_mapfilename = tempUrl;
|
||||
fileInfo._content = file;
|
||||
|
||||
fileList.value.push(fileInfo);
|
||||
});
|
||||
} else {
|
||||
fileInfo.mx_mapfilename = tempUrl;
|
||||
fileInfo._content = file;
|
||||
|
||||
fileList.value.push(fileInfo);
|
||||
};
|
||||
}
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
if (displayMode.value === 0) {
|
||||
if (containerRef.value) {
|
||||
containerRef.value.scrollTop = containerRef.value.scrollHeight;
|
||||
}
|
||||
} else {
|
||||
if (tableRef.value) {
|
||||
tableRef.value.scrollToEndRow();
|
||||
}
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
// ===== 非图片:直接使用原文件 =====
|
||||
fileInfo._content = file;
|
||||
fileList.value.push(fileInfo);
|
||||
});
|
||||
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
if (displayMode.value === 0) {
|
||||
containerRef.value?.scrollTo?.({
|
||||
top: containerRef.value.scrollHeight,
|
||||
});
|
||||
} else {
|
||||
tableRef.value?.scrollToEndRow?.();
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
|
||||
function isImage(fileExtension) {
|
||||
@@ -646,7 +674,13 @@ async function deleteFiles(files) {
|
||||
});
|
||||
}
|
||||
// 保存
|
||||
// 保存
|
||||
async function handleSave() {
|
||||
if (cateId.value !== "1" && cateId.value !== "2") {
|
||||
ElMessage.warning("只允许 装货、发货单 上传");
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
loadingTip.value = "正在保存中 . . .";
|
||||
|
||||
@@ -658,19 +692,19 @@ async function handleSave() {
|
||||
["_content", "_status", "checked"],
|
||||
);
|
||||
|
||||
// 没有变化直接结束
|
||||
if (!hasChanges) {
|
||||
ElMessage.info("没有数据变更");
|
||||
return;
|
||||
}
|
||||
|
||||
const mxXh =
|
||||
fileList.value.length > 0 ? Math.max(...fileList.value.map((item) => item.mx_xh ?? 0)) : 2;
|
||||
// ===============================
|
||||
// 1️⃣ 先处理新增(上传文件)
|
||||
// ===============================
|
||||
const fileInserts = [];
|
||||
|
||||
// 处理新增
|
||||
for (const item of insertdata) {
|
||||
try {
|
||||
const uploadRes = await uploadContainerFileApi(item.mx_mapfilename, {
|
||||
const uploadRes = await uploadContainerFileApi(item._content, {
|
||||
jobId: props.father,
|
||||
fileName: item.mx_filename,
|
||||
containerNo: props.containerNo,
|
||||
@@ -680,31 +714,85 @@ async function handleSave() {
|
||||
throw new Error("上传失败");
|
||||
}
|
||||
|
||||
const insertRes = await insertFileApi({
|
||||
fileInserts.push({
|
||||
subid: uploadRes.data.uid,
|
||||
father: props.father,
|
||||
mx_xh: mxXh + 1,
|
||||
mx_filename: item.mx_filename,
|
||||
mx_filesize: item.mx_filesize,
|
||||
mx_fileext: item.mx_fileext,
|
||||
mx_mapfilename: uploadRes.data.path,
|
||||
mx_moduleid: "b_container",
|
||||
mx_cate_id: "1",
|
||||
mx_cate_id: cateId.value || "1",
|
||||
});
|
||||
|
||||
if (!insertRes.success) {
|
||||
throw new Error("入库失败");
|
||||
}
|
||||
|
||||
console.log(`文件 ${item.mx_filename} 上传成功`);
|
||||
item._status = "";
|
||||
} catch (error) {
|
||||
console.error(`文件 ${item.mx_filename} 处理失败:`, error);
|
||||
ElMessage.error(`文件 ${item.mx_filename} 上传失败,请重试`);
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// 2️⃣ 合并所有数据(旧 + 新 + 更新)
|
||||
// ===============================
|
||||
const mergedList = [
|
||||
...fileList.value
|
||||
.filter((item) => !insertdata.includes(item)) // 去掉旧 insert 原始对象
|
||||
.map((item) => ({
|
||||
...item,
|
||||
type: "update",
|
||||
})),
|
||||
...fileInserts.map((item) => ({
|
||||
...item,
|
||||
type: "insert",
|
||||
})),
|
||||
];
|
||||
|
||||
// ===============================
|
||||
// 3️⃣ 重新排序 mx_xh(核心)
|
||||
// ===============================
|
||||
const ordered = mergedList.map((item, index) => ({
|
||||
...item,
|
||||
mx_xh: index + 1,
|
||||
}));
|
||||
|
||||
// ===============================
|
||||
// 4️⃣ 拆分成 API 结构
|
||||
// ===============================
|
||||
const fileUpdates = ordered
|
||||
.filter((item) => item.type === "update")
|
||||
.map((item) => ({
|
||||
subid: item.subid,
|
||||
mx_xh: item.mx_xh,
|
||||
}));
|
||||
|
||||
const finalInserts = ordered
|
||||
.filter((item) => item.type === "insert")
|
||||
.map(({ type, ...rest }) => rest);
|
||||
|
||||
const fileDeletes = deletedata.map((item) => ({
|
||||
subid: item.subid,
|
||||
}));
|
||||
|
||||
// ===============================
|
||||
// 5️⃣ 统一提交
|
||||
// ===============================
|
||||
const reqData = [
|
||||
{
|
||||
tableName: "bf_file",
|
||||
keyField: "subid",
|
||||
inserts: finalInserts,
|
||||
updates: fileUpdates,
|
||||
deletes: fileDeletes,
|
||||
},
|
||||
];
|
||||
|
||||
await saveObjectApi(reqData);
|
||||
|
||||
ElMessage.success("保存成功");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
ElMessage.error("保存失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
loadFiles();
|
||||
@@ -745,7 +833,6 @@ function onClosed() {
|
||||
}
|
||||
|
||||
function handleTreeNodeClick(data) {
|
||||
console.log(data);
|
||||
cateId.value = data.cateId || "";
|
||||
|
||||
loadFiles();
|
||||
@@ -760,7 +847,7 @@ function handleTreeNodeClick(data) {
|
||||
<template>
|
||||
<el-dialog
|
||||
title="附件管理"
|
||||
width="900"
|
||||
width="1100"
|
||||
draggable
|
||||
modal-class="g3-file-modal"
|
||||
v-bind="$attrs"
|
||||
@@ -783,272 +870,288 @@ function handleTreeNodeClick(data) {
|
||||
/>
|
||||
|
||||
<div class="g3-container">
|
||||
<div v-if="categories[0].children.length > 0" class="g3-category">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
node-key="cateId"
|
||||
:data="categories"
|
||||
:default-expanded-keys="['']"
|
||||
@node-click="handleTreeNodeClick"
|
||||
/>
|
||||
</div>
|
||||
<div class="g3-file-main">
|
||||
<div class="g3-header">
|
||||
<div>
|
||||
<el-checkbox
|
||||
v-model="selectAll"
|
||||
:indeterminate="indeterminate"
|
||||
:disabled="loading"
|
||||
@change="toggleSelectAll"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:disabled="checkedFiles.length === 0 || loading"
|
||||
style="margin-left: 8px"
|
||||
@click="handleDownloadZip"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:download" />
|
||||
</el-icon>
|
||||
打包下载
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
size="small"
|
||||
type="danger"
|
||||
:disabled="checkedFiles.length === 0 || loading"
|
||||
@click="handleBatchDelete()"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
<el-splitter>
|
||||
<el-splitter-panel size="20%" v-if="categories[0].children.length > 0">
|
||||
<div class="g3-category">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
node-key="cateId"
|
||||
:data="categories"
|
||||
:default-expanded-keys="['']"
|
||||
@node-click="handleTreeNodeClick"
|
||||
/>
|
||||
</div>
|
||||
</el-splitter-panel>
|
||||
<el-splitter-panel :min="400">
|
||||
<div class="g3-file-main">
|
||||
<div class="g3-header">
|
||||
<div>
|
||||
<el-checkbox
|
||||
v-model="selectAll"
|
||||
:indeterminate="indeterminate"
|
||||
:disabled="loading"
|
||||
@change="toggleSelectAll"
|
||||
>
|
||||
全选
|
||||
</el-checkbox>
|
||||
|
||||
<div>
|
||||
<el-dropdown>
|
||||
<span class="g3-mode">
|
||||
模式:{{ displayMode === 0 ? "卡片视图" : "列表视图" }}
|
||||
<el-icon class="el-icon--right">
|
||||
<G3Icon icon="lucide:chevron-down" />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleChangeDisplayMode(0)">
|
||||
卡片视图
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="handleChangeDisplayMode(1)">
|
||||
列表视图
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ref="containerRef"
|
||||
v-loading="loading"
|
||||
:element-loading-text="loadingTip"
|
||||
class="g3-main"
|
||||
tabindex="0"
|
||||
@paste="handlePaste"
|
||||
@dragover="handleDragOver"
|
||||
@drop="handleDrop"
|
||||
>
|
||||
<div v-if="fileList.length === 0" class="g3-tip">
|
||||
<el-icon size="64">
|
||||
<G3Icon icon="lucide:cloud-upload" />
|
||||
</el-icon>
|
||||
<div>支持 拖拽文件、粘贴文件、多文件上传</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="displayMode === 0" class="g3-files">
|
||||
<div v-for="(file, index) in fileList" :key="index" class="g3-file-item">
|
||||
<div class="g3-file-checkbox">
|
||||
<el-checkbox v-model="file._checked" size="large" />
|
||||
</div>
|
||||
<!-- pending:未上传,completed:已上传,failed:上传失败 -->
|
||||
<div v-if="file.mx_cate_id === '0'" class="g3-file-status status-primary">
|
||||
<span>箱门照</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="file._status === 'pending' || file._status === 'failed'"
|
||||
:class="`g3-file-status status-${file._status}`"
|
||||
>
|
||||
<span v-if="file._status === 'pending'">未上传</span>
|
||||
<span v-if="file._status === 'failed'">上传失败</span>
|
||||
</div>
|
||||
<div class="g3-file-preview" @click.stop="handleShowPreview(file)">
|
||||
<template v-if="getFileIcon(file.mx_fileext) === 'image'">
|
||||
<el-image class="g3-file-preview-img" :src="file.mx_mapfilename" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<G3Icon :icon="getFileIcon(file.mx_fileext)" size="88" />
|
||||
</template>
|
||||
</div>
|
||||
<div class="g3-file-info">
|
||||
<el-tooltip :content="file.mx_filename">
|
||||
<div class="g3-file-name">
|
||||
{{ file.mx_filename }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div class="g3-file-details">
|
||||
<div>{{ formatFileSize(file.mx_filesize) }}</div>
|
||||
<div>
|
||||
{{ file.mx_updateuser_id || file.mx_inputuser_id }}
|
||||
<template v-if="file.mx_inputdatetime || file.mx_updatedatetime">
|
||||
|
|
||||
{{ formatTime(file.mx_updatedatetime || file.mx_inputdatetime) }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="g3-file-actions">
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
type="danger"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop="handleDeleteOne(file)"
|
||||
>
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop="handleDownloadFile(file)"
|
||||
>
|
||||
<el-button
|
||||
size="small"
|
||||
type="primary"
|
||||
:disabled="checkedFiles.length === 0 || loading"
|
||||
style="margin-left: 8px"
|
||||
@click="handleDownloadZip"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:download" />
|
||||
</el-button>
|
||||
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
|
||||
<el-button type="info" size="small" circle style="margin-left: 12px">
|
||||
<G3Icon icon="lucide:ellipsis" />
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleShowUpdateDialog(file)">
|
||||
修改文件信息
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-icon>
|
||||
打包下载
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
size="small"
|
||||
type="danger"
|
||||
:disabled="checkedFiles.length === 0 || loading"
|
||||
@click="handleBatchDelete()"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-icon>
|
||||
批量删除
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<el-dropdown>
|
||||
<span class="g3-mode">
|
||||
模式:{{ displayMode === 0 ? "卡片视图" : "列表视图" }}
|
||||
<el-icon class="el-icon--right">
|
||||
<G3Icon icon="lucide:chevron-down" />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleChangeDisplayMode(0)">
|
||||
卡片视图
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="handleChangeDisplayMode(1)">
|
||||
列表视图
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="g3-table">
|
||||
<div>
|
||||
<vxe-table
|
||||
ref="tableRef"
|
||||
border
|
||||
stripe
|
||||
header-align="center"
|
||||
:data="fileList"
|
||||
height="100%"
|
||||
show-overflow
|
||||
show-header-overflow
|
||||
:sort-config="{
|
||||
trigger: 'cell',
|
||||
}"
|
||||
:filter-config="{
|
||||
showIcon: false,
|
||||
}"
|
||||
size="small"
|
||||
>
|
||||
<vxe-column type="seq" width="50" title=" " align="center" />
|
||||
<vxe-column width="50" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row._checked" size="large" />
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="mx_filename" title="文件名" sortable align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click.stop="handleShowPreview(row)">
|
||||
{{ row.mx_filename }}
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="mx_inputdatetime" title="上传日期" sortable align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(row.mx_inputdatetime) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
field="mx_fileext"
|
||||
title="文件类型"
|
||||
sortable
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
field="mx_filesize"
|
||||
title="文件大小"
|
||||
sortable
|
||||
width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatFileSize(row.mx_filesize) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column width="180" title="操作">
|
||||
<template #default="{ row }">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 28px;
|
||||
"
|
||||
>
|
||||
|
||||
<div
|
||||
ref="containerRef"
|
||||
v-loading="loading"
|
||||
:element-loading-text="loadingTip"
|
||||
class="g3-main"
|
||||
tabindex="0"
|
||||
@paste="handlePaste"
|
||||
@dragover="handleDragOver"
|
||||
@drop="handleDrop"
|
||||
>
|
||||
<div v-if="fileList.length === 0" class="g3-tip">
|
||||
<el-icon size="64">
|
||||
<G3Icon icon="lucide:cloud-upload" />
|
||||
</el-icon>
|
||||
<div>支持 拖拽文件、粘贴文件、多文件上传</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="displayMode === 0" class="g3-files">
|
||||
<div v-for="(file, index) in fileList" :key="index" class="g3-file-item">
|
||||
<div class="g3-file-checkbox">
|
||||
<el-checkbox v-model="file._checked" size="large" />
|
||||
</div>
|
||||
<!-- pending:未上传,completed:已上传,failed:上传失败 -->
|
||||
<div v-if="file.mx_cate_id === '0'" class="g3-file-status status-primary">
|
||||
<span>箱门照</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="file._status === 'pending' || file._status === 'failed'"
|
||||
:class="`g3-file-status status-${file._status}`"
|
||||
>
|
||||
<span v-if="file._status === 'pending'">未上传</span>
|
||||
<span v-if="file._status === 'failed'">上传失败</span>
|
||||
</div>
|
||||
<div class="g3-file-preview" @click.stop="handleShowPreview(file)">
|
||||
<template v-if="getFileIcon(file.mx_fileext) === 'image'">
|
||||
<el-image class="g3-file-preview-img" :src="file.mx_mapfilename" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<G3Icon :icon="getFileIcon(file.mx_fileext)" size="88" />
|
||||
</template>
|
||||
</div>
|
||||
<div class="g3-file-info">
|
||||
<el-tooltip :content="file.mx_filename">
|
||||
<div class="g3-file-name">
|
||||
{{ file.mx_filename }}
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<div class="g3-file-details">
|
||||
<div>{{ formatFileSize(file.mx_filesize) }}</div>
|
||||
<div>
|
||||
{{ file.mx_updateuser_id || file.mx_inputuser_id }}
|
||||
<template v-if="file.mx_inputdatetime || file.mx_updatedatetime">
|
||||
|
|
||||
{{ formatTime(file.mx_updatedatetime || file.mx_inputdatetime) }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="g3-file-actions">
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
type="danger"
|
||||
link
|
||||
@click.stop="handleDeleteOne(row)"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop="handleDeleteOne(file)"
|
||||
>
|
||||
删除
|
||||
<G3Icon icon="lucide:trash-2" />
|
||||
</el-button>
|
||||
<el-button type="primary" link @click.stop="handleDownloadFile(row)">
|
||||
下载
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
circle
|
||||
@click.stop="handleDownloadFile(file)"
|
||||
>
|
||||
<G3Icon icon="lucide:download" />
|
||||
</el-button>
|
||||
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
|
||||
<el-button type="info" link style="margin-left: 12px"> 更多 </el-button>
|
||||
<el-button type="info" size="small" circle style="margin-left: 12px">
|
||||
<G3Icon icon="lucide:ellipsis" />
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleShowUpdateDialog(row)">
|
||||
<el-dropdown-item @click="handleShowUpdateDialog(file)">
|
||||
修改文件信息
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="g3-table">
|
||||
<div>
|
||||
<vxe-table
|
||||
ref="tableRef"
|
||||
border
|
||||
stripe
|
||||
header-align="center"
|
||||
:data="fileList"
|
||||
height="100%"
|
||||
show-overflow
|
||||
show-header-overflow
|
||||
:sort-config="{
|
||||
trigger: 'cell',
|
||||
}"
|
||||
:filter-config="{
|
||||
showIcon: false,
|
||||
}"
|
||||
size="small"
|
||||
>
|
||||
<vxe-column type="seq" width="50" title=" " align="center" />
|
||||
<vxe-column width="50" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row._checked" size="large" />
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="mx_filename" title="文件名" sortable align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click.stop="handleShowPreview(row)">
|
||||
{{ row.mx_filename }}
|
||||
</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="mx_inputdatetime" title="上传日期" sortable align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatTime(row.mx_inputdatetime) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
field="mx_fileext"
|
||||
title="文件类型"
|
||||
sortable
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
<vxe-column
|
||||
field="mx_filesize"
|
||||
title="文件大小"
|
||||
sortable
|
||||
width="100"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{ formatFileSize(row.mx_filesize) }}
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column width="180" title="操作">
|
||||
<template #default="{ row }">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 28px;
|
||||
"
|
||||
>
|
||||
<el-button
|
||||
v-if="!props.readonly"
|
||||
type="danger"
|
||||
link
|
||||
@click.stop="handleDeleteOne(row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
<el-button type="primary" link @click.stop="handleDownloadFile(row)">
|
||||
下载
|
||||
</el-button>
|
||||
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
|
||||
<el-button type="info" link style="margin-left: 12px"> 更多 </el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="handleShowUpdateDialog(row)">
|
||||
修改文件信息
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-splitter-panel>
|
||||
</el-splitter>
|
||||
</div>
|
||||
|
||||
<template v-if="!props.readonly" #footer>
|
||||
<el-button type="primary" :disabled="loading" @click="handleClickUpload">
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="loading"
|
||||
@click="handleClickUpload"
|
||||
v-if="cateId === '1' || cateId === '2'"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:mouse-pointer" />
|
||||
</el-icon>
|
||||
选择
|
||||
</el-button>
|
||||
<el-button type="primary" :disabled="loading" @click="handleSave">
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="loading"
|
||||
@click="handleSave"
|
||||
v-if="cateId === '1' || cateId === '2'"
|
||||
>
|
||||
<el-icon class="el-icon--left">
|
||||
<G3Icon icon="lucide:upload" />
|
||||
</el-icon>
|
||||
@@ -1107,7 +1210,7 @@ function handleTreeNodeClick(data) {
|
||||
<el-input v-model="updateFile.mx_bz" />
|
||||
<template v-if="updateFile._status !== 'pending'">
|
||||
<div style="margin: 4px 0px">是否为箱门照:</div>
|
||||
<el-switch v-model="updateFile.mx_cate_id" active-value="0" inactive-value="1" />
|
||||
<el-switch v-model="updateFile._main" :active-value="true" :inactive-value="false" />
|
||||
</template>
|
||||
</div>
|
||||
<template #footer>
|
||||
@@ -1143,7 +1246,8 @@ function handleTreeNodeClick(data) {
|
||||
}
|
||||
|
||||
.g3-category {
|
||||
width: 140px;
|
||||
border-right: 1px solid #ddd;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.g3-file-main {
|
||||
@@ -1151,6 +1255,7 @@ function handleTreeNodeClick(data) {
|
||||
padding: 0px 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.g3-main {
|
||||
|
||||
@@ -146,21 +146,12 @@ export async function httpUpload(url, file, extraData = {}, config = {}) {
|
||||
}
|
||||
|
||||
async function appendFile(formData, file) {
|
||||
// ✅ 已经是 File / Blob
|
||||
if (file instanceof File || file instanceof Blob) {
|
||||
formData.append("file", file);
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ 处理 blob:http://xxx
|
||||
if (typeof file === "string" && file.startsWith("blob:")) {
|
||||
const blob = await fetch(file).then((res) => res.blob());
|
||||
|
||||
formData.append("file", blob);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error("不支持的文件类型:" + typeof file);
|
||||
throw new Error("上传只支持 File 或 Blob,不支持字符串");
|
||||
}
|
||||
|
||||
export function reset401Flag() {
|
||||
|
||||
@@ -195,7 +195,7 @@ async function downloadAll() {
|
||||
const containerCountMap = new Map();
|
||||
|
||||
for (const item of records) {
|
||||
const fileRes = await loadDataApi("bf_file", `father='${item.b_id}'`, "mx_xh asc");
|
||||
const fileRes = await loadDataApi("bf_file", `father='${item.b_id}'`, "mx_cate_id asc,mx_xh asc");
|
||||
|
||||
const files = (fileRes.success && fileRes.data) || [];
|
||||
totalFiles += files.length;
|
||||
@@ -320,7 +320,7 @@ async function downloadSlice() {
|
||||
|
||||
containerCountMap.set(containerNo, count + 1);
|
||||
|
||||
const folderPromise = loadDataApi("bf_file", `father='${item.b_id}'`, "mx_xh asc");
|
||||
const folderPromise = loadDataApi("bf_file", `father='${item.b_id}'`, "mx_cate_id asc,mx_xh asc");
|
||||
|
||||
allTasks.push(async () => {
|
||||
const fileRes = await folderPromise;
|
||||
@@ -403,7 +403,7 @@ async function downloadChunk() {
|
||||
|
||||
pageRecords.forEach((item) => {
|
||||
allPageTasks.push(async () => {
|
||||
const fileRes = await loadDataApi("bf_file", `father='${item.b_id}'`, "mx_xh asc");
|
||||
const fileRes = await loadDataApi("bf_file", `father='${item.b_id}'`, "mx_cate_id asc,mx_xh asc");
|
||||
|
||||
if (!fileRes.success) {
|
||||
console.error("获取附件失败:", item.b_container_no);
|
||||
|
||||
@@ -57,9 +57,13 @@ const fileCategories = [
|
||||
cateId: "0",
|
||||
},
|
||||
{
|
||||
label: "其它照片",
|
||||
label: "装货照片",
|
||||
cateId: "1",
|
||||
},
|
||||
{
|
||||
label: "发货单、签收单、过磅单",
|
||||
cateId: "2",
|
||||
},
|
||||
];
|
||||
|
||||
const showPreview = ref(false);
|
||||
@@ -291,7 +295,7 @@ async function handleDownloadOne(data) {
|
||||
});
|
||||
|
||||
try {
|
||||
const fileRes = await loadDataApi("bf_file", `father = ${data.b_id}`, "mx_xh asc");
|
||||
const fileRes = await loadDataApi("bf_file", `father = ${data.b_id}`, "mx_cate_id asc,mx_xh asc");
|
||||
|
||||
if (!fileRes.success) {
|
||||
ElMessage.error("获取附件失败");
|
||||
@@ -365,7 +369,7 @@ async function handleDownloadBatch() {
|
||||
const containerCountMap = new Map();
|
||||
|
||||
for (const item of records) {
|
||||
const fileRes = await loadDataApi("bf_file", `father='${item.b_id}'`, "mx_xh asc");
|
||||
const fileRes = await loadDataApi("bf_file", `father='${item.b_id}'`, "mx_cate_id asc,mx_xh asc");
|
||||
|
||||
const files = (fileRes.success && fileRes.data) || [];
|
||||
totalFiles += files.length;
|
||||
|
||||
Reference in new issue
Block a user