物料新增批量导入照片按钮
This commit is contained in:
@@ -77,3 +77,8 @@ export function parseImportMaterial(data: FormData) {
|
|||||||
export function importMaterial(data: any) {
|
export function importMaterial(data: any) {
|
||||||
return http.post(`${BASE_URL}/import`, data)
|
return http.post(`${BASE_URL}/import`, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @desc 解析物料信息导入数据 */
|
||||||
|
export function uploadMaterialPhotos(data: FormData) {
|
||||||
|
return http.post(`${BASE_URL}/import/uploadMaterialPhotos`, data)
|
||||||
|
}
|
||||||
|
|||||||
134
src/views/material/PhotosImport.vue
Normal file
134
src/views/material/PhotosImport.vue
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<a-drawer
|
||||||
|
v-model:visible="visible"
|
||||||
|
title="批量导入物料照片"
|
||||||
|
:mask-closable="false"
|
||||||
|
:esc-to-close="false"
|
||||||
|
:width="width >= 600 ? 600 : '100%'"
|
||||||
|
ok-text="确认导入"
|
||||||
|
cancel-text="取消导入"
|
||||||
|
@before-ok="save"
|
||||||
|
@close="reset"
|
||||||
|
>
|
||||||
|
<a-form ref="formRef" :model="form" size="large" auto-label-width>
|
||||||
|
<fieldset>
|
||||||
|
<legend>zip文件上传</legend>
|
||||||
|
<div class="file-box">
|
||||||
|
<a-upload
|
||||||
|
draggable
|
||||||
|
:custom-request="handleUpload"
|
||||||
|
:limit="1"
|
||||||
|
:show-retry-button="false"
|
||||||
|
:show-cancel-button="false"
|
||||||
|
tip="仅支持zip格式"
|
||||||
|
:file-list="uploadFile"
|
||||||
|
accept=".zip"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</a-form>
|
||||||
|
</a-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { type FormInstance, Message, type RequestOption } from '@arco-design/web-vue'
|
||||||
|
import { useWindowSize } from '@vueuse/core'
|
||||||
|
import { uploadMaterialPhotos } from '@/apis/material/materialInfo'
|
||||||
|
import { useResetReactive } from '@/hooks'
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'save-success'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const { width } = useWindowSize()
|
||||||
|
|
||||||
|
const visible = ref(false)
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const uploadFile = ref([])
|
||||||
|
// 新增:保存上传的文件对象
|
||||||
|
const uploadFileObj = ref<File | null>(null)
|
||||||
|
|
||||||
|
// 移除不必要的表单字段,只保留空对象即可
|
||||||
|
const [form, resetForm] = useResetReactive({})
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const reset = () => {
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
uploadFile.value = []
|
||||||
|
uploadFileObj.value = null // 重置文件对象
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改上传逻辑:仅保存文件对象,不做解析
|
||||||
|
const handleUpload = (options: RequestOption) => {
|
||||||
|
const { onProgress, onError, onSuccess, fileItem } = options
|
||||||
|
onProgress(100) // 直接标记上传完成(仅前端显示)
|
||||||
|
|
||||||
|
// 保存文件对象供后续提交使用
|
||||||
|
uploadFileObj.value = fileItem.file as File
|
||||||
|
uploadFile.value = [fileItem] // 更新文件列表显示
|
||||||
|
|
||||||
|
Message.success('文件已选择,点击确认导入即可上传')
|
||||||
|
onSuccess({}) // 通知上传组件完成
|
||||||
|
return {
|
||||||
|
abort() {
|
||||||
|
// 空实现,取消时会走reset逻辑
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行导入:直接上传文件到后端
|
||||||
|
const save = async () => {
|
||||||
|
try {
|
||||||
|
// 校验是否选择了文件
|
||||||
|
if (!uploadFileObj.value) {
|
||||||
|
Message.warning('请先选择要上传的ZIP文件')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建FormData
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('zipFile', uploadFileObj.value) // 后端接收参数名保持为zipFile
|
||||||
|
|
||||||
|
// 调用后端照片批量导入接口
|
||||||
|
await uploadMaterialPhotos(formData)
|
||||||
|
|
||||||
|
Message.success('物料照片批量导入成功!')
|
||||||
|
emit('save-success') // 通知父组件刷新列表
|
||||||
|
visible.value = false // 关闭抽屉
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
Message.error('物料照片导入失败,请重试!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开抽屉
|
||||||
|
const onOpen = () => {
|
||||||
|
reset()
|
||||||
|
visible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ onOpen })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
fieldset {
|
||||||
|
padding: 15px 15px 0 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border: 1px solid var(--color-neutral-3);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset legend {
|
||||||
|
color: rgb(var(--gray-10));
|
||||||
|
padding: 2px 5px 2px 5px;
|
||||||
|
border: 1px solid var(--color-neutral-3);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-box {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -33,8 +33,11 @@
|
|||||||
<template #icon><icon-download /></template>
|
<template #icon><icon-download /></template>
|
||||||
<template #default>导出</template>
|
<template #default>导出</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
|
<a-button v-permission="['admin:materialInfo:import']" @click="onPhotosImport">
|
||||||
|
<template #icon><icon-upload /></template>
|
||||||
|
<template #default>照片批量导入</template>
|
||||||
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
<!-- 物料照片插槽:核心新增部分 -->
|
|
||||||
<template #photoUrl="{ record }">
|
<template #photoUrl="{ record }">
|
||||||
<div class="photo-container">
|
<div class="photo-container">
|
||||||
<img
|
<img
|
||||||
@@ -65,12 +68,14 @@
|
|||||||
|
|
||||||
<MaterialInfoAddModal ref="MaterialInfoAddModalRef" @save-success="search" />
|
<MaterialInfoAddModal ref="MaterialInfoAddModalRef" @save-success="search" />
|
||||||
<MaterialInfoImportDrawer ref="MaterialInfoImportDrawerRef" @save-success="search" />
|
<MaterialInfoImportDrawer ref="MaterialInfoImportDrawerRef" @save-success="search" />
|
||||||
|
<PhotosImport ref="PhotosImportRef" @save-success="search"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import MaterialInfoAddModal from './MaterialInfoAddModal.vue'
|
import MaterialInfoAddModal from './MaterialInfoAddModal.vue'
|
||||||
import MaterialInfoImportDrawer from './MaterialInfoImportDrawer.vue'
|
import MaterialInfoImportDrawer from './MaterialInfoImportDrawer.vue'
|
||||||
|
import PhotosImport from '@/views/material/PhotosImport.vue';
|
||||||
import { type MaterialInfoQuery, type MaterialInfoResp, deleteMaterialInfo, exportMaterialInfo, listMaterialInfo } from '@/apis/material/materialInfo'
|
import { type MaterialInfoQuery, type MaterialInfoResp, deleteMaterialInfo, exportMaterialInfo, listMaterialInfo } from '@/apis/material/materialInfo'
|
||||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||||
import { useDownload, useTable } from '@/hooks'
|
import { useDownload, useTable } from '@/hooks'
|
||||||
@@ -153,6 +158,11 @@ const MaterialInfoImportDrawerRef = ref<InstanceType<typeof MaterialInfoImportDr
|
|||||||
const onImport = () => {
|
const onImport = () => {
|
||||||
MaterialInfoImportDrawerRef.value?.onOpen()
|
MaterialInfoImportDrawerRef.value?.onOpen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PhotosImportRef = ref<InstanceType<typeof PhotosImport>>()
|
||||||
|
const onPhotosImport = () => {
|
||||||
|
PhotosImportRef.value?.onOpen()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ const reset = () => {
|
|||||||
|
|
||||||
const onDelete = (record: UserResp) => {
|
const onDelete = (record: UserResp) => {
|
||||||
return handleDelete(() => deleteUser(record.id), {
|
return handleDelete(() => deleteUser(record.id), {
|
||||||
content: `是否确定删除用户「${record.nickname}(${record.username})」?`,
|
content: `是否确定删除用户「${record.username}」?`,
|
||||||
showModal: true,
|
showModal: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -227,11 +227,6 @@ const onUpdate = (record: UserResp) => {
|
|||||||
UserAddDrawerRef.value?.onUpdate(record.id)
|
UserAddDrawerRef.value?.onUpdate(record.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserDetailDrawerRef = ref<InstanceType<typeof UserDetailDrawer>>()
|
|
||||||
const onDetail = (record: UserResp) => {
|
|
||||||
UserDetailDrawerRef.value?.onOpen(record.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
const UserResetPwdModalRef = ref<InstanceType<typeof UserResetPwdModal>>()
|
const UserResetPwdModalRef = ref<InstanceType<typeof UserResetPwdModal>>()
|
||||||
const onResetPwd = (record: UserResp) => {
|
const onResetPwd = (record: UserResp) => {
|
||||||
UserResetPwdModalRef.value?.onOpen(record.id)
|
UserResetPwdModalRef.value?.onOpen(record.id)
|
||||||
|
|||||||
Reference in New Issue
Block a user