1.前端技术:V3 + Ant Design Vue
2.后端技术:Java
图片上传/回显:
文件上传回显:
表结构:单文件/图片上传为A表对文件C表 (A表field字段 对应 C表id字段)
如图:A表中的 vehicle_driving_license 和 driver_license 存的是C表中的id字段
表结构:多文件/图片上传为A表对文件B表 中的Biz字段,B表中的file_id字段对应C表中的id字段,(B表的 Biz 字段和 file_id 字段是一对多的存在关系)
如图:A表中的 house_type_file_id 和 house_type_balcony_close_file_id 、house_type_balcony_bisect_file_id、house_type_shearwall_file_id 存的是B表中的Biz_id字段,B表中的 field_id 字段对应 C表中的 id 字段,(B表中的Biz_id字段 与 field_id 字段是一对多的关系)
上传:(上传功能不分单个多个)java后台代码(controller):
@OperationLog
@ApiOperation("上传文件")
@PostMapping("/upload")
public ApiResult<FileInfo> upload(@RequestParam MultipartFile file, HttpServletRequest request) {
FileInfo result = null;
try {
String dir = getUploadDir();
File upload = FileServerUtil.upload(file, dir, config.getUploadUuidName());
String path = upload.getAbsolutePath().replace("\\", "/").substring(dir.length() - 1);
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/upload");
requestURL = "/api/file-info/file/";
String requestURL2 = "/api/file-info";
/*if(requestURL.contains("10.1.140.88")){
requestURL = "https://10.1.140.88/api/file";
}
if(requestURL.contains("djshemei.com")){
requestURL = "https://10.1.140.88/api/file";
}*/
String originalName = file.getOriginalFilename();
result = new FileInfo();
result.setId(SnowFlakeGenerator.nextId());
String contentType = FileServerUtil.getContentType(upload);
result.setFileType(contentType);
result.setFileName(StrUtil.isBlank(originalName) ? upload.getName() : originalName);
result.setFilePath(path);
result.setUrlPath(requestURL+result.getId());
result.setUrl(requestURL2 + "/" + path);
//这个用户应该是这个找登录用户
User loginUser = getLoginUser();
result.setCreUserId(Long.valueOf(loginUser.getUserId()));
result.setCreUserName(loginUser.getUsername());
result.setCreateTime(LocalDateTime.now());
fileInfoService.save(result);
return success(result);
} catch (Exception e) {
e.printStackTrace();
return fail("上传失败", result).setError(e.toString());
}
}
前端:api代码:
/**
* 上传文件
*/
export async function uploadFile(file, opt) {
const formData = new FormData();
formData.append('file', file);
const res = await request.post('/community/file-info/upload', formData, opt);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
在页面引入使用
<a-row>
<a-col :span="12">
<a-form-item label="行驶证">
<ele-image-upload
class="imagestype"
:limit="1"
v-model:value="form1.vehicleDrivingLicenseField"
@upload="onUpload1"
@remove="onRemove1"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="驾驶证">
<ele-image-upload
class="imagestype"
:limit="1"
v-model:value="form1.driverLicenseField"
@upload="onUpload2"
@remove="onRemove2"
/>
</a-form-item>
</a-col>
</a-row>
使用方法:
const onUpload1 = ({ file }) => {
uploadFile(file)
.then((data) => {
console.log(data, 'data');
form1.vehicleDrivingLicenseFieldId1 = data.id;
})
.catch((e) => {
item.status = 'exception';
message.error(e.message);
});
};
数据结构:
// 图片
const form1 = reactive({
vehicleDrivingLicenseField: [],
vehicleDrivingLicenseFieldId1: '',
driverLicenseField: [],
driverLicenseFieldId2: ''
});
图片回显:java代码 (controller)
@ApiOperation("查询文件")
@GetMapping("/queryFile/{id}")
public ApiResult<?> getFileInfoByRoomCar (@PathVariable("id") Long id, HttpServletRequest request ) {
List<RoomCar> roomCarServiceList = roomCarService.list(new QueryWrapper<RoomCar>().eq("car_id", id));
if(roomCarServiceList.size() == 0){
return success(new ArrayList<>());
}else{
List<FileInfo> fileIdList = fileInfoService.list(new QueryWrapper<FileInfo>().in("id", roomCarServiceList.stream().map(RoomCar::getVehicleDrivingLicense).collect(Collectors.toList())));
if (fileIdList.size() > 0) {
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/room-car/queryFile/"+id);
for (FileInfo record : fileIdList) {
if (StrUtil.isNotBlank(record.getFilePath())) {
record.setDownloadUrl(requestURL + "/file-info/" + record.getFilePath());
record.setUrl(requestURL + "/file-info/" + record.getFilePath());
}
}
}
List<FileInfo> fileIdList1 = fileInfoService.list(new QueryWrapper<FileInfo>().in("id", roomCarServiceList.stream().map(RoomCar::getDriverLicense).collect(Collectors.toList())));
if (fileIdList1.size() > 0) {
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/room-car/queryFile/"+id);
for (FileInfo record : fileIdList1) {
if (StrUtil.isNotBlank(record.getFilePath())) {
record.setDownloadUrl(requestURL + "/file-info/" + record.getFilePath());
record.setUrl(requestURL + "/file-info/" + record.getFilePath());
}
}
}
HashMap<String, List<FileInfo>> data = new HashMap<>();
data.put("vehicleDrivingLicenseField", fileIdList);
data.put("driverLicenseField", fileIdList1);
return success(data);
}
}
前端api:
export async function queryItem(id) {
const res = await request.get('/community/decoration-manage/queryFile/' + id);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
页面引入使用:
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignObject(form, {
...props.data
});
isUpdate.value = true;
showFile.value = true;
changeRoomType(props.data.roomTypeId);
// driverLicense
// vehicleDrivingLicense
queryItem(props.data.carId)
.then((res) => {
form1.vehicleDrivingLicenseField =
res.data.vehicleDrivingLicenseField;
form1.driverLicenseField = res.data.driverLicenseField;
})
.catch((e) => {
message.error(e.message);
});
loadingData();
} else {
showFile.value = false;
isUpdate.value = false;
loadingData();
}
} else {
form1.vehicleDrivingLicenseField = [];
form1.driverLicenseField = [];
resetFields();
}
}
);
多文件上传跟单文件上传一样的,不一样的是显示的方式:
多文件回显后端 Java代码(controller):
@ApiOperation("查询文件")
@GetMapping("/queryFile/{id}")
public ApiResult<?> getFileInfoByRegionalHouseTypeId(@PathVariable("id") Long id, HttpServletRequest request ) {
BaseRegionalHouseType mainRec = baseRegionalHouseTypeService.getByIdRel(id);
List<FileInfo> house_type_file = new ArrayList<>();
List<FileInfo> house_type_balcony_close_file = new ArrayList<>();
List<FileInfo> house_type_balcony_bisect_file = new ArrayList<>();
List<FileInfo> house_type_shearwall_file = new ArrayList<>();
Long bizId;
bizId = mainRec.getHouseTypeFileId();
if (bizId != null) {
house_type_file = fileInfoService.getfileinfobybiz(bizId);
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/base-regional-house-type/queryFile/"+id);
for (FileInfo record : house_type_file) {
if (StrUtil.isNotBlank(record.getFilePath())) {
record.setDownloadUrl(requestURL + "/file-info/download/" + record.getFilePath());
}
}
}
bizId = mainRec.getHouseTypeBalconyCloseFileId();
if (bizId != null) {
house_type_balcony_close_file = fileInfoService.getfileinfobybiz(bizId);
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/base-regional-house-type/queryFile/"+id);
for (FileInfo record : house_type_balcony_close_file) {
if (StrUtil.isNotBlank(record.getFilePath())) {
record.setDownloadUrl(requestURL + "/file-info/download/" + record.getFilePath());
}
}
}
bizId = mainRec.getHouseTypeBalconyBisectFileId();
if (bizId != null) {
house_type_balcony_bisect_file = fileInfoService.getfileinfobybiz(bizId);
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/base-regional-house-type/queryFile/"+id);
for (FileInfo record : house_type_balcony_bisect_file) {
if (StrUtil.isNotBlank(record.getFilePath())) {
record.setDownloadUrl(requestURL + "/file-info/download/" + record.getFilePath());
}
}
}
bizId = mainRec.getHouseTypeShearwallFileId();
if (bizId != null) {
house_type_shearwall_file = fileInfoService.getfileinfobybiz(bizId);
String requestURL = StrUtil.removeSuffix(request.getRequestURL(), "/base-regional-house-type/queryFile/"+id);
for (FileInfo record : house_type_shearwall_file) {
if (StrUtil.isNotBlank(record.getFilePath())) {
record.setDownloadUrl(requestURL + "/file-info/download/" + record.getFilePath());
}
}
}
HashMap<String, List<FileInfo>> data = new HashMap<>();
data.put("house_type_file", house_type_file);
data.put("house_type_balcony_close_file", house_type_balcony_close_file);
data.put("house_type_balcony_bisect_file", house_type_balcony_bisect_file);
data.put("house_type_shearwall_file", house_type_shearwall_file);
return success(data);
}
前端api:
export async function queryHouse(id) {
const res = await request.get('/community/base-regional-house-type/queryFile/' + id);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
页面使用:
<template>
<ele-modal
:width="1200"
:visible="visible"
:confirm-loading="loading"
title="文件管理"
:body-style="{ paddingBottom: '8px' }"
@update:visible="updateVisible"
@ok="save"
>
<div class="ele-body">
<a-card :bordered="false">
<div class="content">
<div class="loudong">
<div>
<div
style="font-size: 18px; font-weight: 600; margin-bottom: 25px"
>文件上传</div
>
<a-row type="flex" style="margin: 20px -15px">
<a-col :span="24">
<a-button
type="text"
@click="typeclick(0)"
:class="btn == 0 ? 'btnColor' : ''"
style="width: 150px"
>户型图</a-button
>
</a-col>
</a-row>
<a-row type="flex" style="margin: 20px -15px">
<a-col :span="24">
<a-button
type="text"
@click="typeclick(1)"
:class="btn == 1 ? 'btnColor' : ''"
style="width: 150px"
>封闭阳台方案</a-button
>
</a-col>
</a-row>
<a-row type="flex" style="margin: 20px -15px">
<a-col :span="24">
<a-button
type="text"
@click="typeclick(2)"
:class="btn == 2 ? 'btnColor' : ''"
style="width: 150px"
>封闭阳台剖面图</a-button
>
</a-col>
</a-row>
<a-row type="flex" style="margin: 20px -15px">
<a-col :span="24">
<a-button
type="text"
@click="typeclick(3)"
:class="btn == 3 ? 'btnColor' : ''"
style="width: 150px"
>剪力墙标识图</a-button
>
</a-col>
</a-row>
</div>
</div>
<div class="content-right">
<div class="ele-body" style="margin-top: -40px">
<div class="content">
<div class="content-right">
<div class="content-right-header" style="margin-top: 30px">
<a-upload
:show-upload-list="false"
:customRequest="onUploadCardf"
>
<a-button type="primary" class="ele-btn-icon">
<template #icon>
<upload-outlined />
</template>
<span>上传</span>
</a-button>
</a-upload>
</div>
<!-- 表格 -->
<ele-pro-table
bordered
ref="tableRef"
row-key="id"
:columns="columns"
:datasource="datasource"
:toolkit="false"
:scroll="{ x: 800 }"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'action'">
<a-space>
<a
:href="record.downloadUrl"
target="_blank"
:disabled="
record.downloadUrl != null ? disabled : true
"
>下载</a
>
<a-divider type="vertical" />
<a-popconfirm
placement="topRight"
title="确定要删除此文件吗?"
@confirm="remove(record, index)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</div>
</div>
</div>
</div>
</div>
</a-card>
<!-- <spbuilding-edit
v-model:visible="showEdit"
:data="current"
@done="reload"
/>
<bar-code :data="barcodedata" v-model:visible="showBarcode" /> -->
</div>
</ele-modal>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue';
import {
getfileinfobybiz,
uploadFile,
removeFile
} from '@/api/system/file-info';
import useFormData from '@/utils/use-form-data';
import { Form, message } from 'ant-design-vue/es';
import { messageLoading } from 'ele-admin-pro/es';
import {
saveHouse,
queryHouse
} from '@/api/baseRegionalPark/base-regional-house-type';
import { CloudUploadOutlined, FileTextOutlined } from '@ant-design/icons-vue';
// import FileUpload from './file-upload.vue';
const emit = defineEmits(['done', 'update:visible']);
const useForm = Form.useForm;
const props = defineProps({
data: Object,
visible: Boolean
});
// 表单
const { form, resetFields, assignFields } = useFormData({
regionalHouseTypeId: '',
// 户型图id
houseTypeFileId: '',
// 封闭阳台方案id
houseTypeBalconyCloseFileId: '',
// 封闭阳台剖面图id
houseTypeBalconyBisectFileId: '',
// 剪力墙标识图id
houseTypeShearwallFileId: '',
house_type_file: [],
house_type_balcony_close_file: [],
house_type_balcony_bisect_file: [],
house_type_shearwall_file: []
});
// 按钮颜色
const btn = ref(0);
// 确定数据
const datas = ref({
regionalHouseTypeId: '',
house_type_file: [],
house_type_balcony_close_file: [],
house_type_balcony_bisect_file: [],
house_type_shearwall_file: [],
downloadUrl:"",
// 户型图id
houseTypeFileId: '',
// 封闭阳台方案id
houseTypeBalconyCloseFileId: '',
// 封闭阳台剖面图id
houseTypeBalconyBisectFileId: '',
// 剪力墙标识图id
houseTypeShearwallFileId: '',
});
const typeclick = (type) => {
switch (type) {
case 0:
btn.value = 0;
datasource.value = datas.value.house_type_file;
break;
case 1:
btn.value = 1;
datasource.value = datas.value.house_type_balcony_close_file;
break;
case 2:
btn.value = 2;
datasource.value = datas.value.house_type_balcony_bisect_file;
break;
case 3:
btn.value = 3;
datasource.value = datas.value.house_type_shearwall_file;
break;
}
};
const findPicIds = ref([]);
// 表格实例
const tableRef = ref(null);
// 导入请求状态
const loading = ref(false);
const isAdmin = ref(false);
// 保存按钮
const save = () => {
saveHouse(datas.value).then((res) => {
if (res.code == 0) {
message.success('保存成功');
emit('done');
emit('update:visible', false);
} else {
message.error(res.msg);
}
});
};
// 表格列配置
const columns = ref([
{
title: '序号',
key: 'index',
width: 48,
align: 'center',
fixed: 'left',
hideInSetting: true,
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
},
{
title: '文件名',
dataIndex: 'fileName'
},
{
title: '文件类型',
dataIndex: 'fileType'
},
{
title: '创建人',
dataIndex: 'creUserName'
},
{
title: '创建时间',
dataIndex: 'createTime'
},
{
title: '操作',
key: 'action',
width: 160,
align: 'center',
hideInSetting: true
}
]);
//上传文件
const onUploadCardf = (d) => {
uploadFile(d.file, {
onUploadProgress: (e) => {
if (e.lengthComputable) {
d.progress = (e.loaded / e.total) * 100;
}
}
})
.then((data) => {
d.status = 'done';
if (btn.value == 0) {
datas.value.house_type_file.push(data);
} else if (btn.value == 1) {
datas.value.house_type_balcony_close_file.push(data);
} else if (btn.value == 2) {
datas.value.house_type_balcony_bisect_file.push(data);
} else if (btn.value == 3) {
datas.value.house_type_shearwall_file.push(data);
}
message.success('上传成功');
})
.catch((e) => {
message.error(e.message);
});
};
// /* 删除单个 */
const remove = (row, index) => {
const hide = message.loading('请求中..', 0);
removeFile(row.id)
.then((msg) => {
var arr = [];
if(btn.value ==0 ){
arr = datas.value.house_type_file.filter((d) => d.id != row.id);
datas.value.house_type_file = arr;
}
if(btn.value ==1 ){
arr = datas.value.house_type_balcony_close_file.filter((d) => d.id != row.id);
datas.value.house_type_balcony_close_file = arr;
}
if(btn.value ==2 ){
arr = datas.value.house_type_balcony_bisect_file.filter((d) => d.id != row.id);
datas.value.house_type_balcony_bisect_file = arr;
}
if(btn.value ==3 ){
arr = datas.value.house_type_shearwall_file.filter((d) => d.id != row.id);
datas.value.house_type_shearwall_file = arr;
}
typeclick(btn.value);
hide();
message.success(msg);
})
.catch((e) => {
hide();
message.error(e.message);
});
};
// // 表格数据源
const datasource = ref([]);
/* 更新visible */
const updateVisible = (value) => {
emit('update:visible', value);
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (!props.data) {
alert('数据为空,请确保传递正确数据');
return;
}
console.log(props.data);
datas.value.regionalHouseTypeId = props.data.regionalHouseTypeId;
queryHouse(datas.value.regionalHouseTypeId).then((res) => {
datas.value.house_type_file = res.data.house_type_file;
datas.value.house_type_balcony_close_file = res.data.house_type_balcony_close_file;
datas.value.house_type_balcony_bisect_file = res.data.house_type_balcony_bisect_file;
datas.value.house_type_shearwall_file = res.data.house_type_shearwall_file;
// 默认选中第一个
typeclick(0);
});
}
}
);
</script>
<style lang="less" scoped>
// .ele-body {
// height: 100%;
// }
.btnColor {
background-color: #f4fbf8;
color: #1677ff;
}
.content {
display: flex;
.loudong {
width: 280px;
margin-right: 15px;
padding: 15px;
// height: 80vh;
background: #fff;
overflow: auto;
box-sizing: border-box;
}
.search {
width: 100%;
padding: 20px 10px 0px 20px;
background: #f6f5f5;
margin-bottom: 5px;
}
.content-right {
flex: 1;
}
}
</style>
还有一个小细节,java存储文件id的字段一定不要忽略修改的时候传来的null
用注解:
@TableField(updateStrategy = FieldStrategy.IGNORED)
就ok啦,暂时先做个笔记,后面有空再慢慢写注解