feat(ai-web): 完成图片上传和显示

This commit is contained in:
v-zhangjc9
2025-06-16 13:38:42 +08:00
parent 13de694e37
commit 807ddbe5cb
6 changed files with 86 additions and 30 deletions

View File

@@ -11,7 +11,7 @@ import org.springframework.context.annotation.Configuration;
@Data @Data
@Configuration @Configuration
@ConfigurationProperties(prefix = "file-store") @ConfigurationProperties(prefix = "file-store")
public class FileStoreConfiguration { public class FileStoreProperties {
private String downloadPrefix; private String downloadPrefix;
private String uploadPath; private String uploadPath;
} }

View File

@@ -7,7 +7,7 @@ import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisResponse; import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisResponse;
import com.lanyuanxiaoyao.service.ai.web.configuration.FileStoreConfiguration; import com.lanyuanxiaoyao.service.ai.web.configuration.FileStoreProperties;
import com.lanyuanxiaoyao.service.ai.web.entity.vo.DataFileVO; import com.lanyuanxiaoyao.service.ai.web.entity.vo.DataFileVO;
import com.lanyuanxiaoyao.service.ai.web.service.DataFileService; import com.lanyuanxiaoyao.service.ai.web.service.DataFileService;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@@ -41,17 +41,17 @@ import org.springframework.web.multipart.MultipartFile;
@RestController @RestController
@RequestMapping("/upload") @RequestMapping("/upload")
public class DataFileController { public class DataFileController {
private final FileStoreConfiguration fileStoreConfiguration; private final FileStoreProperties fileStoreProperties;
private final DataFileService dataFileService; private final DataFileService dataFileService;
private final String uploadFolderPath; private final String uploadFolderPath;
private final String cacheFolderPath; private final String cacheFolderPath;
private final String sliceFolderPath; private final String sliceFolderPath;
public DataFileController(FileStoreConfiguration fileStoreConfiguration, DataFileService dataFileService) { public DataFileController(FileStoreProperties fileStoreProperties, DataFileService dataFileService) {
this.fileStoreConfiguration = fileStoreConfiguration; this.fileStoreProperties = fileStoreProperties;
this.dataFileService = dataFileService; this.dataFileService = dataFileService;
this.uploadFolderPath = fileStoreConfiguration.getUploadPath(); this.uploadFolderPath = fileStoreProperties.getUploadPath();
this.cacheFolderPath = StrUtil.format("{}/cache", uploadFolderPath); this.cacheFolderPath = StrUtil.format("{}/cache", uploadFolderPath);
this.sliceFolderPath = StrUtil.format("{}/slice", uploadFolderPath); this.sliceFolderPath = StrUtil.format("{}/slice", uploadFolderPath);
} }
@@ -60,7 +60,7 @@ public class DataFileController {
public AmisResponse<FinishResponse> upload(@RequestParam("file") MultipartFile file) throws IOException { public AmisResponse<FinishResponse> upload(@RequestParam("file") MultipartFile file) throws IOException {
String filename = file.getOriginalFilename(); String filename = file.getOriginalFilename();
Long id = dataFileService.initialDataFile(filename); Long id = dataFileService.initialDataFile(filename);
String url = StrUtil.format("{}/upload/download/{}", fileStoreConfiguration.getDownloadPrefix(), id); String url = StrUtil.format("{}/upload/download/{}", fileStoreProperties.getDownloadPrefix(), id);
byte[] bytes = file.getBytes(); byte[] bytes = file.getBytes();
String originMd5 = SecureUtil.md5(new ByteArrayInputStream(bytes)); String originMd5 = SecureUtil.md5(new ByteArrayInputStream(bytes));
File targetFile = new File(StrUtil.format("{}/{}", uploadFolderPath, originMd5)); File targetFile = new File(StrUtil.format("{}/{}", uploadFolderPath, originMd5));
@@ -80,7 +80,7 @@ public class DataFileController {
} }
@GetMapping("/download/{id}") @GetMapping("/download/{id}")
public void download(@PathVariable Long id, HttpServletResponse response) throws IOException { public void download(@PathVariable("id") Long id, HttpServletResponse response) throws IOException {
DataFileVO dataFile = dataFileService.downloadFile(id); DataFileVO dataFile = dataFileService.downloadFile(id);
File targetFile = new File(dataFile.getPath()); File targetFile = new File(dataFile.getPath());
response.setHeader("Content-Type", dataFile.getType()); response.setHeader("Content-Type", dataFile.getType());
@@ -157,7 +157,7 @@ public class DataFileController {
request.uploadId, request.uploadId,
request.filename, request.filename,
request.uploadId.toString(), request.uploadId.toString(),
StrUtil.format("{}/upload/download/{}", fileStoreConfiguration.getDownloadPrefix(), request.uploadId) StrUtil.format("{}/upload/download/{}", fileStoreProperties.getDownloadPrefix(), request.uploadId)
)); ));
} else { } else {
throw new RuntimeException("合并文件失败"); throw new RuntimeException("合并文件失败");

View File

@@ -1,13 +1,19 @@
package com.lanyuanxiaoyao.service.ai.web.controller.feedback; package com.lanyuanxiaoyao.service.ai.web.controller.feedback;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisCrudResponse;
import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisResponse; import com.lanyuanxiaoyao.service.ai.core.entity.amis.AmisResponse;
import com.lanyuanxiaoyao.service.ai.web.configuration.FileStoreProperties;
import com.lanyuanxiaoyao.service.ai.web.entity.Feedback;
import com.lanyuanxiaoyao.service.ai.web.service.feedback.FeedbackService; import com.lanyuanxiaoyao.service.ai.web.service.feedback.FeedbackService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList; import org.eclipse.collections.api.list.ImmutableList;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -16,27 +22,49 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("feedback") @RequestMapping("feedback")
public class FeedbackController { public class FeedbackController {
private final FileStoreProperties fileStoreProperties;
private final FeedbackService feedbackService; private final FeedbackService feedbackService;
public FeedbackController(FeedbackService feedbackService) { public FeedbackController(FileStoreProperties fileStoreProperties, FeedbackService feedbackService) {
this.fileStoreProperties = fileStoreProperties;
this.feedbackService = feedbackService; this.feedbackService = feedbackService;
} }
@PostMapping("add") @PostMapping("add")
public void add( public void add(@RequestBody CreateItem item) {
@RequestParam("source") String source, log.info("Enter method: add[item]. item:{}", item);
@RequestParam(value = "pictures", required = false) ImmutableList<Long> pictures feedbackService.add(item.source, ObjectUtil.defaultIfNull(item.pictures, Lists.immutable.empty()));
) {
feedbackService.add(source, ObjectUtil.defaultIfNull(pictures, Lists.immutable.empty()));
} }
@GetMapping("list") @GetMapping("list")
public AmisResponse<?> list() { public AmisCrudResponse list() {
return AmisResponse.responseCrudData(feedbackService.list()); return AmisResponse.responseCrudData(feedbackService.list().collect(feedback -> new ListItem(fileStoreProperties, feedback)));
} }
@GetMapping("delete") @GetMapping("delete")
public void delete(@RequestParam("id") Long id) { public void delete(@RequestParam("id") Long id) {
feedbackService.remove(id); feedbackService.remove(id);
} }
@Data
public static final class CreateItem {
private String source;
private ImmutableList<Long> pictures;
}
@Data
public static final class ListItem {
private Long id;
private String source;
private ImmutableList<String> pictures;
private Feedback.Status status;
public ListItem(FileStoreProperties fileStoreProperties, Feedback feedback) {
this.id = feedback.getId();
this.source = feedback.getSource();
this.pictures = feedback.getPictureIds()
.collect(id -> StrUtil.format("{}/upload/download/{}", fileStoreProperties.getDownloadPrefix(), id));
this.status = feedback.getStatus();
}
}
} }

View File

@@ -51,9 +51,7 @@ public class FeedbackService {
.precompileSql(), .precompileSql(),
SnowflakeId.next(), SnowflakeId.next(),
source, source,
ObjectUtil.isEmpty(pictureIds) ObjectUtil.isEmpty(pictureIds) ? null : pictureIds.makeString(",")
? null
: pictureIds.makeString(",")
); );
} }

View File

@@ -169,7 +169,7 @@ deploy:
jdk: "jdk17" jdk: "jdk17"
replicas: 1 replicas: 1
arguments: arguments:
"[file-store.download-prefix]": 'http://132.126.207.130:35690/hudi_services/ai_knowledge' "[file-store.download-prefix]": 'http://132.126.207.130:35690/hudi_services/service_ai_web'
"[file-store.upload-path]": ${deploy.runtime.data-path}/knowledge "[file-store.upload-path]": ${deploy.runtime.data-path}/knowledge
"[spring.datasource.url]": ${deploy.runtime.database.config.url} "[spring.datasource.url]": ${deploy.runtime.database.config.url}
"[spring.datasource.username]": ${deploy.runtime.database.config.username} "[spring.datasource.username]": ${deploy.runtime.database.config.username}

View File

@@ -1,9 +1,25 @@
import React from 'react' import React from 'react'
import {amisRender, commonInfo, crudCommonOptions} from '../../../util/amis.tsx' import styled from 'styled-components'
import {amisRender, commonInfo, crudCommonOptions, mappingField, mappingItem} from '../../../util/amis.tsx'
const FeedbackDiv = styled.div`
.feedback-list-images {
.antd-Img-container {
width: 32px;
height: 32px;
}
}
`
const statusMapping = [
mappingItem('分析中', 'ANALYSIS_PROCESSING', 'label-warning'),
mappingItem('分析完成', 'ANALYSIS_SUCCESS', 'label-primary'),
mappingItem('处理完成', 'FINISHED', 'label-success'),
]
const Feedback: React.FC = () => { const Feedback: React.FC = () => {
return ( return (
<div className="feedback"> <FeedbackDiv className="feedback">
{amisRender( {amisRender(
{ {
type: 'page', type: 'page',
@@ -28,10 +44,7 @@ const Feedback: React.FC = () => {
body: { body: {
debug: commonInfo.debug, debug: commonInfo.debug,
type: 'form', type: 'form',
api: { api: `${commonInfo.baseAiUrl}/feedback/add`,
url: `${commonInfo.baseAiUrl}/feedback/add`,
dataType: 'form',
},
body: [ body: [
{ {
type: 'editor', type: 'editor',
@@ -50,12 +63,14 @@ const Feedback: React.FC = () => {
label: '相关截图', label: '相关截图',
autoUpload: false, autoUpload: false,
multiple: true, multiple: true,
joinValues: false,
extractValue: true,
// 5MB 5242880 // 5MB 5242880
// 100MB 104857600 // 100MB 104857600
// 500MB 524288000 // 500MB 524288000
// 1GB 1073741824 // 1GB 1073741824
maxSize: 5242880, maxSize: 5242880,
receiver: `${commonInfo.baseAiUrl}/upload` receiver: `${commonInfo.baseAiUrl}/upload`,
}, },
], ],
}, },
@@ -66,11 +81,26 @@ const Feedback: React.FC = () => {
{ {
name: 'id', name: 'id',
label: '编号', label: '编号',
width: 150,
},
{
name: 'source',
label: '故障描述',
},
{
name: 'pictures',
label: '相关截图',
width: 200,
className: 'feedback-list-images',
type: 'images',
enlargeAble: true,
enlargeWithGallary: true,
}, },
{ {
name: 'status',
label: '状态', label: '状态',
width: 80, width: 80,
align: 'center',
...mappingField('status', statusMapping),
}, },
{ {
type: 'operation', type: 'operation',
@@ -101,7 +131,7 @@ const Feedback: React.FC = () => {
], ],
}, },
)} )}
</div> </FeedbackDiv>
) )
} }