diff --git a/pom.xml b/pom.xml index 3f0e4094..0816680b 100644 --- a/pom.xml +++ b/pom.xml @@ -276,6 +276,12 @@ gson 2.10.1 + + + com.itextpdf + itextpdf + 5.5.13.2 + diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index 09496110..15372e9b 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -1,5 +1,8 @@ package com.ai.da.common.constant; +import java.util.Arrays; +import java.util.List; + public class CommonConstant { // 单位 秒 10分钟过期 // public static final Long TASK_EXPIRE_TIME = 24 * 60 * 60L; @@ -31,6 +34,29 @@ public class CommonConstant { public static final String PYTHON_PORT_9997 = "9997"; + public static final List AGES_EN = Arrays.asList("Below 20", "20-30", "30-40", "40+"); + public static final List AGES_CN = Arrays.asList("20岁以下", "20-30岁", "30-40岁", "40+岁"); + public static final List IF_HELPFUL_EN = Arrays.asList("Easy to learn and use", "Easy to get trend information", + "Lots of creative design proposals","The AIGC functions for moodboard is helpful","The AIGC functions for design sketches is helpful", + "Easy to select the right color","The Chatbot function is helpful","The print position function is helpful", + "The drawing function is helpful","The export function is useful","Easy to edit the design","Others"); + + public static final List IF_HELPFUL_CN = Arrays.asList("易于学习和使用", "容易获取趋势信息", + "提供大量创意设计方案","AIGC功能对灵感板有帮助","AIGC功能对设计草图有帮助", + "容易选择合适的颜色","聊天机器人功能有帮助","打印位置功能有帮助", + "绘图功能有帮助","导出功能有用","设计编辑简单","其他"); + + public static final List IF_IMPROVE_EN = Arrays.asList("Proposed designs are boring, need more interesting designs", + "Difficult to make changes on design","Only 2D output, no 3D results","Difficult to apply keywords for AIGC generation", + "Clothing is not in the right proportion","Not compatible with pattern making solutions","Improved user interface for better navigation", + "Lack of responsive customer support","Insufficient tutorial or guidance for new users","Limited personalization options for designs","Others"); + + public static final List IF_IMPROVE_CN = Arrays.asList("提供的设计很无聊,需要更多有趣的设计", + "设计修改困难","只有2D输出,没有3D结果","难以选择合适的关键词应用于AIGC生成", + "服装比例不正确","与打版解决方案不兼容","改进用户界面以便更好导航", + "客户支持响应不及时","对新用户的教程或指导不足","设计个性化选项有限","其他"); + + public static final List IS_SUBSCRIBE = Arrays.asList("yes", "no"); } diff --git a/src/main/java/com/ai/da/common/utils/S3Util.java b/src/main/java/com/ai/da/common/utils/S3Util.java index 705aca7b..7e084f6f 100644 --- a/src/main/java/com/ai/da/common/utils/S3Util.java +++ b/src/main/java/com/ai/da/common/utils/S3Util.java @@ -255,6 +255,22 @@ public class S3Util { } } + public String getPreSignedUrl(String path, int expiry, boolean resetCache) { + if (resetCache || LocalCacheUtils.getPresignedUrlCache(path) == null) { + if (!path.contains("/")) { + throw new BusinessException("The path is error!"); + } + int index = path.indexOf("/"); + String bucketName = path.substring(0, index); + String fileName = path.substring(index + 1); + String presignedUrl = getPreSignatureUrl(bucketName, fileName, expiry); + LocalCacheUtils.setPresignedUrlCache(path, presignedUrl); + return presignedUrl; + } else { + return LocalCacheUtils.getPresignedUrlCache(path); + } + } + /** * @param keyName key名称: test/2022/06/123.pdf * @param signatureDurationTime 有效期 单位:秒 diff --git a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java index 4b4526bd..93c00239 100644 --- a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java +++ b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java @@ -7,6 +7,9 @@ import com.ai.da.mapper.primary.DesignMapper; import com.ai.da.mapper.primary.TrialOrderMapper; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.UserDesignStatisticDTO; +import com.ai.da.model.vo.QuestionnaireFeedbackVO; +import com.ai.da.model.vo.QuestionnaireVO; +import com.ai.da.service.ConvenientInquiryService; import io.netty.util.internal.StringUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -30,6 +33,10 @@ public class ConvenientInquiryController { @Resource private DesignMapper designMapper; + @Resource + private ConvenientInquiryService convenientInquiryService; + + @ApiOperation("获取当前所有试用用户") @GetMapping("/getTrial") public Response> getTrial(){ @@ -60,4 +67,18 @@ public class ConvenientInquiryController { } } + + //调查问卷 + @ApiOperation("获取调查问卷统计详情") + @GetMapping("/getQuestionnaireStatistic") + public Response getQuestionnaire(){ + return Response.success(convenientInquiryService.getQuestionnaireInfo()); + } + + @ApiOperation("获取所有调查问卷") + @GetMapping("/getAllQuestionnaire") + public Response> getAllQuestionnaire(){ + return Response.success(convenientInquiryService.getAllQuestionnaire()); + } + } diff --git a/src/main/java/com/ai/da/model/vo/QuestionnaireFeedbackVO.java b/src/main/java/com/ai/da/model/vo/QuestionnaireFeedbackVO.java new file mode 100644 index 00000000..baae7b41 --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/QuestionnaireFeedbackVO.java @@ -0,0 +1,45 @@ +package com.ai.da.model.vo; + +import lombok.Data; + +import java.util.List; + +@Data +public class QuestionnaireFeedbackVO { + private Info age; + private Info question1; + private Info question2; + private Info question3; + private List otherDesignTools; + + public QuestionnaireFeedbackVO() { + } + + public QuestionnaireFeedbackVO(Info age, Info question1, Info question2, Info question3, List otherDesignTools) { + this.age = age; + this.question1 = question1; + this.question2 = question2; + this.question3 = question3; + this.otherDesignTools = otherDesignTools; + } + + public static class Info{ + public List name; + public List values; + public List otherReason; + + public Info() { + } + + public Info(List name, List values) { + this.name = name; + this.values = values; + } + + public Info(List name, List values, List otherReason) { + this.name = name; + this.values = values; + this.otherReason = otherReason; + } + } +} diff --git a/src/main/java/com/ai/da/service/ConvenientInquiryService.java b/src/main/java/com/ai/da/service/ConvenientInquiryService.java new file mode 100644 index 00000000..30bffc86 --- /dev/null +++ b/src/main/java/com/ai/da/service/ConvenientInquiryService.java @@ -0,0 +1,15 @@ +package com.ai.da.service; + +import com.ai.da.mapper.primary.entity.Questionnaire; +import com.ai.da.model.vo.QuestionnaireFeedbackVO; +import com.ai.da.model.vo.QuestionnaireVO; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +public interface ConvenientInquiryService extends IService { + + QuestionnaireFeedbackVO getQuestionnaireInfo(); + + List getAllQuestionnaire(); +} diff --git a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java new file mode 100644 index 00000000..efd00abb --- /dev/null +++ b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java @@ -0,0 +1,217 @@ +package com.ai.da.service.impl; + +import com.ai.da.common.constant.CommonConstant; +import com.ai.da.common.context.UserContext; +import com.ai.da.mapper.primary.QuestionnaireMapper; +import com.ai.da.mapper.primary.entity.Account; +import com.ai.da.mapper.primary.entity.Questionnaire; +import com.ai.da.model.vo.QuestionnaireFeedbackVO; +import com.ai.da.model.vo.QuestionnaireVO; +import com.ai.da.service.AccountService; +import com.ai.da.service.ConvenientInquiryService; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.Font; +import com.itextpdf.text.pdf.BaseFont; +import io.netty.util.internal.StringUtil; +import org.springframework.stereotype.Service; + +import com.itextpdf.text.Document; +import com.itextpdf.text.Paragraph; +import com.itextpdf.text.pdf.PdfWriter; + +import javax.annotation.Resource; +import java.io.FileOutputStream; +import java.io.IOException; + +import java.io.InputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Service +public class ConvenientInquiryServiceImpl extends ServiceImpl implements ConvenientInquiryService { + + @Resource + private AccountService accountService; + + + public QuestionnaireFeedbackVO getQuestionnaireInfo() { + String title = "AiDA_3.0 Feedback Survey--06/2024"; + List questionnaires = queryByTitle(title); + List ageValue = new ArrayList<>(Collections.nCopies(4, 0)); + List question1Value = new ArrayList<>(Collections.nCopies(12, 0)); + List question2Value = new ArrayList<>(Collections.nCopies(11, 0)); + List question3Value = new ArrayList<>(Collections.nCopies(2, 0)); + List question4Value = new ArrayList<>(); + ArrayList othersReason1 = new ArrayList<>(); + ArrayList othersReason2 = new ArrayList<>(); + ArrayList othersReason3 = new ArrayList<>(); + + for (Questionnaire questionnaire : questionnaires) { + QuestionnaireVO questionnaireVO = JSON.parseObject(questionnaire.getQuestionnaireInfo(), QuestionnaireVO.class); + // 统计年龄区间 + String age = questionnaireVO.getAge(); + if (age.contains("20-30")) { + Integer num = ageValue.get(1); + ageValue.set(1, ++num); + } else if (age.contains("30-40")) { + Integer num = ageValue.get(2); + ageValue.set(2, ++num); + } else if (age.contains("40+")) { + Integer num = ageValue.get(3); + ageValue.set(3, ++num); + } else { + Integer num = ageValue.get(0); + ageValue.set(0, ++num); + } + + // How has AiDA been helpful to you? 统计 + List helpful = questionnaireVO.getHelpful(); + helpful.forEach(item -> { + if (item.matches("\\d+")) { + Integer num = question1Value.get(Integer.parseInt(item) - 1); + question1Value.set(Integer.parseInt(item) - 1, ++num); + } else { + Integer num = question1Value.get(11); + question1Value.set(11, ++num); + othersReason1.add(item); + } + }); + + // What do you think AiDA should improve? 统计 + List improve = questionnaireVO.getImprove(); + improve.forEach(item -> { + if (item.matches("\\d+")) { + Integer num = question2Value.get(Integer.parseInt(item) - 1); + question2Value.set(Integer.parseInt(item) - 1, ++num); + } else { + Integer num = question2Value.get(10); + question2Value.set(10, ++num); + othersReason2.add(item); + } + }); + + // Will you subscribe to AiDA 3.0? + String isSubscribe = questionnaireVO.getIsSubscribe(); + if (isSubscribe.equals("yes")) { + Integer num = question3Value.get(0); + question3Value.set(0, ++num); + } else { + Integer num = question3Value.get(1); + question3Value.set(1, ++num); + othersReason3.add(String.join(",", questionnaireVO.getReasonForNotSubscribe())); + } + if (!StringUtil.isNullOrEmpty(questionnaireVO.getDesignTools())) { + question4Value.add(questionnaireVO.getDesignTools()); + } + } + + String language = UserContext.getUserHolder().getLanguage(); + List ageName; + List question1Name; + List question2Name; + if (language.equals("English")) { + ageName = CommonConstant.AGES_EN; + question1Name = CommonConstant.IF_HELPFUL_EN; + question2Name = CommonConstant.IF_IMPROVE_EN; + } else { + ageName = CommonConstant.AGES_CN; + question1Name = CommonConstant.IF_HELPFUL_CN; + question2Name = CommonConstant.IF_IMPROVE_CN; + } + return new QuestionnaireFeedbackVO( + new QuestionnaireFeedbackVO.Info(ageName, ageValue), + new QuestionnaireFeedbackVO.Info(question1Name, question1Value, othersReason1), + new QuestionnaireFeedbackVO.Info(question2Name, question2Value, othersReason2), + new QuestionnaireFeedbackVO.Info(CommonConstant.IS_SUBSCRIBE, question3Value, othersReason3), + question4Value + ); + } + + private List queryByTitle(String title) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("title", title); + return baseMapper.selectList(queryWrapper); + } + + public List getAllQuestionnaire() { + String title = "AiDA_3.0 Feedback Survey--06/2024"; + List questionnaires = queryByTitle(title); + ArrayList questionnaireVOS = new ArrayList<>(); + + questionnaires.forEach(item -> { + QuestionnaireVO questionnaireVO = JSON.parseObject(item.getQuestionnaireInfo(), QuestionnaireVO.class); + questionnaireVOS.add(questionnaireVO); + } + ); + + return questionnaireVOS; + } + + + // 输出为pdf 需要自己组装pdf内容 + // 解决iText不显示中文问题 + public static void main(String[] args) { + try { + // 创建文档 + Document document = new Document(); + PdfWriter.getInstance(document, new FileOutputStream("output.pdf")); + document.open(); + + // 加载字体文件 + InputStream inputStream = ConvenientInquiryServiceImpl.class.getResourceAsStream("/font/msyhl.ttc"); + byte[] fontBytes = toByteArray(inputStream); + inputStream.close(); + + // 创建BaseFont和Font对象 + BaseFont baseFont = BaseFont.createFont("msyhl.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, fontBytes, null); + Font yaHeiFont = new Font(baseFont, 12, Font.NORMAL); + + // 添加带有中文字体的段落 + document.add(new Paragraph("你好,世界!", yaHeiFont)); + + document.close(); + } catch (DocumentException | IOException e) { + e.printStackTrace(); + } + } + + // 将InputStream转换为字节数组 + public static byte[] toByteArray(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int n = 0; + while (-1 != (n = input.read(buffer))) { + output.write(buffer, 0, n); + } + return output.toByteArray(); + } + + /** + * 近期新增用户 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @param userType 用户类型 visitor\trial\official + * @return + */ + public List recentNewUser(String startTime, String endTime, String userType){ + if (StringUtil.isNullOrEmpty(startTime) && StringUtil.isNullOrEmpty(endTime) && StringUtil.isNullOrEmpty(userType)){ + return null; + } + + int type = userType.equals("visitor") ? 0 : userType.equals("trial") ? 1 : 2; + return accountService.getByDateAndUserType(startTime, endTime, type); + } + + // 近期活跃用户 + public List recentActiveUser(String startTime, String endTime){ + return null; + } + + + +} diff --git a/src/main/resources/font/msyhl.ttc b/src/main/resources/font/msyhl.ttc new file mode 100644 index 00000000..c1850925 Binary files /dev/null and b/src/main/resources/font/msyhl.ttc differ