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
@Configuration
@ConfigurationProperties(prefix = "file-store")
public class FileStoreConfiguration {
public class FileStoreProperties {
private String downloadPrefix;
private String uploadPath;
}

View File

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

View File

@@ -1,13 +1,19 @@
package com.lanyuanxiaoyao.service.ai.web.controller.feedback;
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.web.configuration.FileStoreProperties;
import com.lanyuanxiaoyao.service.ai.web.entity.Feedback;
import com.lanyuanxiaoyao.service.ai.web.service.feedback.FeedbackService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.list.ImmutableList;
import org.springframework.web.bind.annotation.GetMapping;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@@ -16,27 +22,49 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("feedback")
public class FeedbackController {
private final FileStoreProperties fileStoreProperties;
private final FeedbackService feedbackService;
public FeedbackController(FeedbackService feedbackService) {
public FeedbackController(FileStoreProperties fileStoreProperties, FeedbackService feedbackService) {
this.fileStoreProperties = fileStoreProperties;
this.feedbackService = feedbackService;
}
@PostMapping("add")
public void add(
@RequestParam("source") String source,
@RequestParam(value = "pictures", required = false) ImmutableList<Long> pictures
) {
feedbackService.add(source, ObjectUtil.defaultIfNull(pictures, Lists.immutable.empty()));
public void add(@RequestBody CreateItem item) {
log.info("Enter method: add[item]. item:{}", item);
feedbackService.add(item.source, ObjectUtil.defaultIfNull(item.pictures, Lists.immutable.empty()));
}
@GetMapping("list")
public AmisResponse<?> list() {
return AmisResponse.responseCrudData(feedbackService.list());
public AmisCrudResponse list() {
return AmisResponse.responseCrudData(feedbackService.list().collect(feedback -> new ListItem(fileStoreProperties, feedback)));
}
@GetMapping("delete")
public void delete(@RequestParam("id") Long 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(),
SnowflakeId.next(),
source,
ObjectUtil.isEmpty(pictureIds)
? null
: pictureIds.makeString(",")
ObjectUtil.isEmpty(pictureIds) ? null : pictureIds.makeString(",")
);
}

View File

@@ -169,7 +169,7 @@ deploy:
jdk: "jdk17"
replicas: 1
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
"[spring.datasource.url]": ${deploy.runtime.database.config.url}
"[spring.datasource.username]": ${deploy.runtime.database.config.username}

View File

@@ -1,9 +1,25 @@
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 = () => {
return (
<div className="feedback">
<FeedbackDiv className="feedback">
{amisRender(
{
type: 'page',
@@ -28,10 +44,7 @@ const Feedback: React.FC = () => {
body: {
debug: commonInfo.debug,
type: 'form',
api: {
url: `${commonInfo.baseAiUrl}/feedback/add`,
dataType: 'form',
},
api: `${commonInfo.baseAiUrl}/feedback/add`,
body: [
{
type: 'editor',
@@ -50,12 +63,14 @@ const Feedback: React.FC = () => {
label: '相关截图',
autoUpload: false,
multiple: true,
joinValues: false,
extractValue: true,
// 5MB 5242880
// 100MB 104857600
// 500MB 524288000
// 1GB 1073741824
maxSize: 5242880,
receiver: `${commonInfo.baseAiUrl}/upload`
receiver: `${commonInfo.baseAiUrl}/upload`,
},
],
},
@@ -66,11 +81,26 @@ const Feedback: React.FC = () => {
{
name: 'id',
label: '编号',
width: 150,
},
{
name: 'source',
label: '故障描述',
},
{
name: 'pictures',
label: '相关截图',
width: 200,
className: 'feedback-list-images',
type: 'images',
enlargeAble: true,
enlargeWithGallary: true,
},
{
name: 'status',
label: '状态',
width: 80,
align: 'center',
...mappingField('status', statusMapping),
},
{
type: 'operation',
@@ -101,7 +131,7 @@ const Feedback: React.FC = () => {
],
},
)}
</div>
</FeedbackDiv>
)
}