Compare commits
3 Commits
master
...
codex/prem
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1a806f266 | ||
|
|
2bf0a6db59 | ||
|
|
4bda30f9c2 |
@@ -2,6 +2,7 @@ package com.ruoyi.web.controller.app;
|
||||
|
||||
import com.ruoyi.app.domain.AppBlogArticle;
|
||||
import com.ruoyi.app.mapper.AppBlogArticleMapper;
|
||||
import com.ruoyi.app.mapper.AppResourceMapper;
|
||||
import com.ruoyi.app.service.ImageUrlService;
|
||||
import com.ruoyi.app.service.IAppBlogArticleService;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
@@ -19,7 +20,9 @@ import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文章Controller
|
||||
@@ -39,6 +42,9 @@ public class AppBlogArticleController extends BaseController {
|
||||
@Resource
|
||||
private AppBlogArticleMapper appBlogArticleMapper;
|
||||
|
||||
@Resource
|
||||
private AppResourceMapper appResourceMapper;
|
||||
|
||||
@Resource
|
||||
private ITtFileService fileService;
|
||||
|
||||
@@ -87,6 +93,19 @@ public class AppBlogArticleController extends BaseController {
|
||||
return success(appBlogArticle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取首页四个分类的可见内容数量
|
||||
*/
|
||||
@GetMapping(value = "/app/homeCategoryCounts")
|
||||
public AjaxResult homeCategoryCounts() {
|
||||
Map<String, Long> counts = new LinkedHashMap<>();
|
||||
counts.put("highQuality", appBlogArticleMapper.countByArticleType(7L, 1L));
|
||||
counts.put("resource", appResourceMapper.countByIsShow(1L));
|
||||
counts.put("integral", appBlogArticleMapper.countByArticleType(4L, 1L));
|
||||
counts.put("free", appBlogArticleMapper.countByArticleType(8L, 1L));
|
||||
return success(counts);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增文章
|
||||
*/
|
||||
|
||||
@@ -3,12 +3,16 @@ package com.ruoyi.office.service.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.ruoyi.app.domain.AppBlogArticle;
|
||||
import com.ruoyi.app.domain.AppResource;
|
||||
import com.ruoyi.app.domain.AppResourceList;
|
||||
import com.ruoyi.app.mapper.AppBlogArticleMapper;
|
||||
import com.ruoyi.app.mapper.AppResourceMapper;
|
||||
import com.ruoyi.app.service.IAppResourceService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.office.domain.TtCopyTemplate;
|
||||
@@ -33,6 +37,18 @@ import com.ruoyi.office.service.ITtCodeService;
|
||||
*/
|
||||
@Service
|
||||
public class TtCodeServiceImpl implements ITtCodeService {
|
||||
private static final Pattern PREMIUM_PROJECT_CODE_PATTERN =
|
||||
Pattern.compile("(?i)(?:^|【)\\s*([SK])\\s*\\d+");
|
||||
private static final long SOURCE_SHARE_RESOURCE_TYPE = 5L;
|
||||
private static final long PREMIUM_PROJECT_RESOURCE_TYPE = 6L;
|
||||
private static final long SOURCE_SHARE_ARTICLE_TYPE = 4L;
|
||||
private static final long PREMIUM_SOURCE_ARTICLE_TYPE = 7L;
|
||||
private static final long POINTS_ACCESS_TYPE = 2L;
|
||||
private static final long PAID_ACCESS_TYPE = 3L;
|
||||
private static final String BASIC_SPEC_NAME = "源码 + 数据库 + 论文 + 答辩PPT";
|
||||
private static final String DEPLOYMENT_SPEC_NAME = "源码 + 数据库 + 论文 + 答辩PPT + 项目部署";
|
||||
private static final String DEPLOYMENT_CONTACT = "调试部署加微信:forfeastcoding";
|
||||
|
||||
@Autowired
|
||||
private TtCodeMapper ttCodeMapper;
|
||||
@Autowired
|
||||
@@ -42,6 +58,8 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
@Autowired
|
||||
private AppResourceMapper appResourceMapper;
|
||||
@Autowired
|
||||
private IAppResourceService appResourceService;
|
||||
@Autowired
|
||||
private TtProjectInfoMapper ttProjectInfoMapper;
|
||||
@Autowired
|
||||
private TtCopyTemplateMapper ttCopyTemplateMapper;
|
||||
@@ -150,7 +168,13 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
if (ttProjectInfo == null) {
|
||||
throw new ServiceException("未找到对应的项目清单信息");
|
||||
}
|
||||
ttCode.setDiskLink(ttProjectInfo.getProjectBaiduUrl());
|
||||
String projectSeries = resolveProjectSeries(ttCode, ttProjectInfo);
|
||||
boolean premiumProject = isPremiumProject(projectSeries);
|
||||
if (premiumProject && StringUtils.isEmpty(ttProjectInfo.getProjectUrl())) {
|
||||
throw new ServiceException("该项目未配置夸克网盘链接,无法生成付费规格");
|
||||
}
|
||||
ttCode.setDiskLink(premiumProject
|
||||
? ttProjectInfo.getProjectUrl() : ttProjectInfo.getProjectBaiduUrl());
|
||||
TtFile file = new TtFile();
|
||||
file.setCodeName(ttCode.getCodeName());
|
||||
List<TtFile> fileList = fileMapper.selectTtFileList(file);
|
||||
@@ -160,7 +184,8 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
|
||||
AppBlogArticle existingArticle = appBlogArticleMapper.selectAppBlogArticleByTitle(ttCode.getCodeName());
|
||||
if (existingArticle != null) {
|
||||
if (repairIncompleteConversion(existingArticle, ttProjectInfo, content, firstImageUrl)) {
|
||||
if (repairIncompleteConversion(existingArticle, ttProjectInfo, content,
|
||||
firstImageUrl, projectSeries)) {
|
||||
markCodePublished(ttCode);
|
||||
return "源码转文章成功,已补全资源链接!";
|
||||
}
|
||||
@@ -174,17 +199,16 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
if (!StringUtils.isEmpty(firstImageUrl)) {
|
||||
resource.setShowImg(firstImageUrl);
|
||||
}
|
||||
resource.setResourceType(5L);
|
||||
configureResource(resource, projectSeries);
|
||||
resource.setIsShow(0L);
|
||||
resource.setIsAd(2L);
|
||||
resource.setAdNumber(100L);
|
||||
resource.setPriceFen(0);
|
||||
resource.setCreateTime(new Date());
|
||||
appResourceMapper.insertAppResource(resource);
|
||||
List<AppResourceList> resourceList = buildResourceList(ttProjectInfo, null, projectSeries);
|
||||
resource.setAppResourceListList(resourceList);
|
||||
appResourceService.insertAppResource(resource);
|
||||
//新增文章
|
||||
AppBlogArticle article = new AppBlogArticle();
|
||||
article.setTitle(ttCode.getCodeName());
|
||||
article.setArticleType(4L);
|
||||
article.setArticleType(premiumProject
|
||||
? PREMIUM_SOURCE_ARTICLE_TYPE : SOURCE_SHARE_ARTICLE_TYPE);
|
||||
article.setIsRecommendation(1L);
|
||||
article.setIsShow(1L);
|
||||
article.setIsAd(1L);
|
||||
@@ -195,12 +219,6 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
article.setAppResourceId(resource.getId());
|
||||
article.setCreateTime(new Date());
|
||||
appBlogArticleMapper.insertAppBlogArticle(article);
|
||||
//新增资源网盘链接
|
||||
List<AppResourceList> resourceList = buildResourceList(ttProjectInfo, resource.getId());
|
||||
if (resourceList.size() > 0)
|
||||
{
|
||||
appResourceMapper.batchAppResourceList(resourceList);
|
||||
}
|
||||
markCodePublished(ttCode);
|
||||
return "源码转文章成功!";
|
||||
}
|
||||
@@ -209,7 +227,8 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
* 修复旧转换流程异常后已经生成文章、但尚未写入下载链接的半成品数据。
|
||||
*/
|
||||
private boolean repairIncompleteConversion(AppBlogArticle article, TtProjectInfo projectInfo,
|
||||
String content, String firstImageUrl)
|
||||
String content, String firstImageUrl,
|
||||
String projectSeries)
|
||||
{
|
||||
if (article.getAppResourceId() == null)
|
||||
{
|
||||
@@ -222,7 +241,8 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<AppResourceList> resourceList = buildResourceList(projectInfo, resource.getId());
|
||||
List<AppResourceList> resourceList = buildResourceList(
|
||||
projectInfo, resource.getId(), projectSeries);
|
||||
if (resourceList.isEmpty())
|
||||
{
|
||||
return false;
|
||||
@@ -233,16 +253,20 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
{
|
||||
resource.setShowImg(firstImageUrl);
|
||||
}
|
||||
resource.setPriceFen(0);
|
||||
appResourceMapper.updateAppResource(resource);
|
||||
configureResource(resource, projectSeries);
|
||||
resource.setAppResourceListList(resourceList);
|
||||
appResourceService.updateAppResource(resource);
|
||||
|
||||
article.setContentInfo(content);
|
||||
if (!StringUtils.isEmpty(firstImageUrl))
|
||||
{
|
||||
article.setShowImg(firstImageUrl);
|
||||
}
|
||||
if (isPremiumProject(projectSeries))
|
||||
{
|
||||
article.setArticleType(PREMIUM_SOURCE_ARTICLE_TYPE);
|
||||
}
|
||||
appBlogArticleMapper.updateAppBlogArticle(article);
|
||||
appResourceMapper.batchAppResourceList(resourceList);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -255,9 +279,26 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
return fileList.get(0).getFileUrl();
|
||||
}
|
||||
|
||||
private List<AppResourceList> buildResourceList(TtProjectInfo projectInfo, Long resourceId)
|
||||
private List<AppResourceList> buildResourceList(TtProjectInfo projectInfo, Long resourceId,
|
||||
String projectSeries)
|
||||
{
|
||||
List<AppResourceList> resourceList = new ArrayList<AppResourceList>();
|
||||
if ("K".equals(projectSeries))
|
||||
{
|
||||
addResourceList(resourceList, resourceId, BASIC_SPEC_NAME,
|
||||
projectInfo.getProjectUrl(), 1900, 1);
|
||||
addResourceList(resourceList, resourceId, DEPLOYMENT_SPEC_NAME,
|
||||
DEPLOYMENT_CONTACT, 6600, 2);
|
||||
return resourceList;
|
||||
}
|
||||
if ("S".equals(projectSeries))
|
||||
{
|
||||
addResourceList(resourceList, resourceId, BASIC_SPEC_NAME,
|
||||
projectInfo.getProjectUrl(), 5900, 1);
|
||||
addResourceList(resourceList, resourceId, DEPLOYMENT_SPEC_NAME,
|
||||
DEPLOYMENT_CONTACT, 9900, 2);
|
||||
return resourceList;
|
||||
}
|
||||
addResourceList(resourceList, resourceId, "百度网盘", projectInfo.getProjectBaiduUrl());
|
||||
addResourceList(resourceList, resourceId, "夸克网盘", projectInfo.getProjectUrl());
|
||||
return resourceList;
|
||||
@@ -281,6 +322,57 @@ public class TtCodeServiceImpl implements ITtCodeService {
|
||||
resourceList.add(item);
|
||||
}
|
||||
|
||||
private void addResourceList(List<AppResourceList> resourceList, Long resourceId,
|
||||
String name, String url, int priceFen, int sortOrder)
|
||||
{
|
||||
AppResourceList item = new AppResourceList();
|
||||
item.setAppResourceId(resourceId);
|
||||
item.setListName(name);
|
||||
item.setListUrl(url);
|
||||
item.setPassword("");
|
||||
item.setPriceFen(priceFen);
|
||||
item.setStatus(1);
|
||||
item.setSortOrder(sortOrder);
|
||||
resourceList.add(item);
|
||||
}
|
||||
|
||||
private void configureResource(AppResource resource, String projectSeries)
|
||||
{
|
||||
if (isPremiumProject(projectSeries))
|
||||
{
|
||||
resource.setResourceType(PREMIUM_PROJECT_RESOURCE_TYPE);
|
||||
resource.setIsAd(PAID_ACCESS_TYPE);
|
||||
resource.setAdNumber(0L);
|
||||
resource.setPriceFen("K".equals(projectSeries) ? 1900 : 5900);
|
||||
return;
|
||||
}
|
||||
resource.setResourceType(SOURCE_SHARE_RESOURCE_TYPE);
|
||||
resource.setIsAd(POINTS_ACCESS_TYPE);
|
||||
resource.setAdNumber(100L);
|
||||
resource.setPriceFen(0);
|
||||
}
|
||||
|
||||
private boolean isPremiumProject(String projectSeries)
|
||||
{
|
||||
return "S".equals(projectSeries) || "K".equals(projectSeries);
|
||||
}
|
||||
|
||||
private String resolveProjectSeries(TtCode code, TtProjectInfo projectInfo)
|
||||
{
|
||||
String projectSeries = extractProjectSeries(projectInfo.getProjectNum());
|
||||
return projectSeries == null ? extractProjectSeries(code.getCodeName()) : projectSeries;
|
||||
}
|
||||
|
||||
private String extractProjectSeries(String value)
|
||||
{
|
||||
if (StringUtils.isEmpty(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Matcher matcher = PREMIUM_PROJECT_CODE_PATTERN.matcher(value);
|
||||
return matcher.find() ? matcher.group(1).toUpperCase(Locale.ROOT) : null;
|
||||
}
|
||||
|
||||
private void markCodePublished(TtCode ttCode)
|
||||
{
|
||||
ttCode.setPublishFlag("Y");
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.ruoyi.app.domain.AppResource;
|
||||
import com.ruoyi.app.domain.AppResourceList;
|
||||
import com.ruoyi.app.mapper.AppBlogArticleMapper;
|
||||
import com.ruoyi.app.mapper.AppResourceMapper;
|
||||
import com.ruoyi.app.service.IAppResourceService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.office.domain.TtCode;
|
||||
import com.ruoyi.office.domain.TtCopyTemplate;
|
||||
import com.ruoyi.office.domain.TtFile;
|
||||
@@ -47,6 +49,8 @@ public class TtCodeServiceImplTest
|
||||
@Mock
|
||||
private AppResourceMapper resourceMapper;
|
||||
@Mock
|
||||
private IAppResourceService resourceService;
|
||||
@Mock
|
||||
private TtProjectInfoMapper projectInfoMapper;
|
||||
@Mock
|
||||
private TtCopyTemplateMapper copyTemplateMapper;
|
||||
@@ -68,6 +72,7 @@ public class TtCodeServiceImplTest
|
||||
code.setCodeName("【S009】自习室预约选座系统");
|
||||
|
||||
projectInfo = new TtProjectInfo();
|
||||
projectInfo.setProjectNum("S009");
|
||||
projectInfo.setProjectBaiduUrl("https://pan.baidu.com/s/example");
|
||||
projectInfo.setProjectUrl("https://pan.quark.cn/s/example");
|
||||
|
||||
@@ -80,16 +85,17 @@ public class TtCodeServiceImplTest
|
||||
|
||||
when(copyTemplateMapper.selectTtCopyTemplateByTemplateId(1L)).thenReturn(template);
|
||||
when(codeMapper.selectTtCodeByCodeId(9L)).thenReturn(code);
|
||||
when(projectInfoMapper.selectTtProjectInfoByName(code.getCodeName())).thenReturn(projectInfo);
|
||||
when(projectInfoMapper.selectTtProjectInfoByName(any())).thenReturn(projectInfo);
|
||||
when(fileMapper.selectTtFileList(any())).thenReturn(Arrays.asList(firstImage, secondImage));
|
||||
when(templateRenderer.render(template, code)).thenReturn("模板正文");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillsRequiredResourceListFields()
|
||||
public void createsSPremiumProjectWithPaidSpecs()
|
||||
{
|
||||
projectInfo.setProjectNum(null);
|
||||
when(articleMapper.selectAppBlogArticleByTitle(code.getCodeName())).thenReturn(null);
|
||||
when(resourceMapper.insertAppResource(any())).thenAnswer(invocation -> {
|
||||
when(resourceService.insertAppResource(any())).thenAnswer(invocation -> {
|
||||
AppResource resource = invocation.getArgument(0);
|
||||
resource.setId(100L);
|
||||
return 1;
|
||||
@@ -98,20 +104,45 @@ public class TtCodeServiceImplTest
|
||||
service.transToArticle1(9L, 1L);
|
||||
|
||||
ArgumentCaptor<AppResource> resourceCaptor = ArgumentCaptor.forClass(AppResource.class);
|
||||
verify(resourceMapper).insertAppResource(resourceCaptor.capture());
|
||||
Assert.assertEquals(Integer.valueOf(0), resourceCaptor.getValue().getPriceFen());
|
||||
Assert.assertEquals("https://img.example.com/first.png", resourceCaptor.getValue().getShowImg());
|
||||
verify(resourceService).insertAppResource(resourceCaptor.capture());
|
||||
AppResource resource = resourceCaptor.getValue();
|
||||
Assert.assertEquals(Long.valueOf(6L), resource.getResourceType());
|
||||
Assert.assertEquals(Long.valueOf(3L), resource.getIsAd());
|
||||
Assert.assertEquals(Integer.valueOf(5900), resource.getPriceFen());
|
||||
Assert.assertEquals("https://img.example.com/first.png", resource.getShowImg());
|
||||
Assert.assertEquals("https://pan.quark.cn/s/example", code.getDiskLink());
|
||||
assertPremiumSpecs(resource.getAppResourceListList(), 5900, 9900);
|
||||
|
||||
ArgumentCaptor<AppBlogArticle> articleCaptor = ArgumentCaptor.forClass(AppBlogArticle.class);
|
||||
verify(articleMapper).insertAppBlogArticle(articleCaptor.capture());
|
||||
Assert.assertEquals("https://img.example.com/first.png", articleCaptor.getValue().getShowImg());
|
||||
Assert.assertEquals(Long.valueOf(7L), articleCaptor.getValue().getArticleType());
|
||||
}
|
||||
|
||||
ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class);
|
||||
verify(resourceMapper).batchAppResourceList(listCaptor.capture());
|
||||
List<AppResourceList> items = listCaptor.getValue();
|
||||
Assert.assertEquals(2, items.size());
|
||||
assertResourceListDefaults(items.get(0), 0);
|
||||
assertResourceListDefaults(items.get(1), 1);
|
||||
@Test
|
||||
public void createsKPremiumProjectWithPaidSpecs()
|
||||
{
|
||||
code.setCodeName("【K001】药店进销存系统");
|
||||
projectInfo.setProjectNum(" k001 ");
|
||||
when(resourceService.insertAppResource(any())).thenAnswer(invocation -> {
|
||||
AppResource resource = invocation.getArgument(0);
|
||||
resource.setId(101L);
|
||||
return 1;
|
||||
});
|
||||
|
||||
service.transToArticle1(9L, 1L);
|
||||
|
||||
ArgumentCaptor<AppResource> resourceCaptor = ArgumentCaptor.forClass(AppResource.class);
|
||||
verify(resourceService).insertAppResource(resourceCaptor.capture());
|
||||
AppResource resource = resourceCaptor.getValue();
|
||||
Assert.assertEquals(Long.valueOf(6L), resource.getResourceType());
|
||||
Assert.assertEquals(Long.valueOf(3L), resource.getIsAd());
|
||||
Assert.assertEquals(Integer.valueOf(1900), resource.getPriceFen());
|
||||
assertPremiumSpecs(resource.getAppResourceListList(), 1900, 6600);
|
||||
|
||||
ArgumentCaptor<AppBlogArticle> articleCaptor = ArgumentCaptor.forClass(AppBlogArticle.class);
|
||||
verify(articleMapper).insertAppBlogArticle(articleCaptor.capture());
|
||||
Assert.assertEquals(Long.valueOf(7L), articleCaptor.getValue().getArticleType());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,19 +165,80 @@ public class TtCodeServiceImplTest
|
||||
Assert.assertEquals("源码转文章成功,已补全资源链接!", message);
|
||||
Assert.assertEquals("https://img.example.com/first.png", existingResource.getShowImg());
|
||||
Assert.assertEquals("https://img.example.com/first.png", existingArticle.getShowImg());
|
||||
verify(resourceMapper).updateAppResource(existingResource);
|
||||
Assert.assertEquals(Long.valueOf(6L), existingResource.getResourceType());
|
||||
Assert.assertEquals(Long.valueOf(3L), existingResource.getIsAd());
|
||||
Assert.assertEquals(Long.valueOf(7L), existingArticle.getArticleType());
|
||||
assertPremiumSpecs(existingResource.getAppResourceListList(), 5900, 9900);
|
||||
verify(resourceService).updateAppResource(existingResource);
|
||||
verify(articleMapper).updateAppBlogArticle(existingArticle);
|
||||
verify(resourceMapper).batchAppResourceList(any());
|
||||
verify(resourceMapper, never()).insertAppResource(any());
|
||||
verify(resourceService, never()).insertAppResource(any());
|
||||
verify(articleMapper, never()).insertAppBlogArticle(any());
|
||||
}
|
||||
|
||||
private void assertResourceListDefaults(AppResourceList item, int sortOrder)
|
||||
@Test
|
||||
public void keepsLegacyRulesForOtherProjectSeries()
|
||||
{
|
||||
Assert.assertEquals(Integer.valueOf(0), item.getPriceFen());
|
||||
code.setCodeName("【A001】普通源码项目");
|
||||
projectInfo.setProjectNum("A001");
|
||||
when(resourceService.insertAppResource(any())).thenAnswer(invocation -> {
|
||||
AppResource resource = invocation.getArgument(0);
|
||||
resource.setId(102L);
|
||||
return 1;
|
||||
});
|
||||
|
||||
service.transToArticle1(9L, 1L);
|
||||
|
||||
ArgumentCaptor<AppResource> resourceCaptor = ArgumentCaptor.forClass(AppResource.class);
|
||||
verify(resourceService).insertAppResource(resourceCaptor.capture());
|
||||
AppResource resource = resourceCaptor.getValue();
|
||||
Assert.assertEquals(Long.valueOf(5L), resource.getResourceType());
|
||||
Assert.assertEquals(Long.valueOf(2L), resource.getIsAd());
|
||||
Assert.assertEquals(Integer.valueOf(0), resource.getPriceFen());
|
||||
Assert.assertEquals("https://pan.baidu.com/s/example", code.getDiskLink());
|
||||
Assert.assertEquals("百度网盘", resource.getAppResourceListList().get(0).getListName());
|
||||
Assert.assertEquals("夸克网盘", resource.getAppResourceListList().get(1).getListName());
|
||||
|
||||
ArgumentCaptor<AppBlogArticle> articleCaptor = ArgumentCaptor.forClass(AppBlogArticle.class);
|
||||
verify(articleMapper).insertAppBlogArticle(articleCaptor.capture());
|
||||
Assert.assertEquals(Long.valueOf(4L), articleCaptor.getValue().getArticleType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsPremiumProjectWithoutQuarkLink()
|
||||
{
|
||||
projectInfo.setProjectUrl(null);
|
||||
|
||||
try
|
||||
{
|
||||
service.transToArticle1(9L, 1L);
|
||||
Assert.fail("应拒绝未配置夸克链接的精品项目");
|
||||
}
|
||||
catch (ServiceException exception)
|
||||
{
|
||||
Assert.assertEquals("该项目未配置夸克网盘链接,无法生成付费规格", exception.getMessage());
|
||||
}
|
||||
|
||||
verify(resourceService, never()).insertAppResource(any());
|
||||
verify(articleMapper, never()).insertAppBlogArticle(any());
|
||||
}
|
||||
|
||||
private void assertPremiumSpecs(List<AppResourceList> items, int firstPrice, int secondPrice)
|
||||
{
|
||||
Assert.assertEquals(2, items.size());
|
||||
assertPremiumSpec(items.get(0), "源码 + 数据库 + 论文 + 答辩PPT",
|
||||
"https://pan.quark.cn/s/example", firstPrice, 1);
|
||||
assertPremiumSpec(items.get(1), "源码 + 数据库 + 论文 + 答辩PPT + 项目部署",
|
||||
"调试部署加微信:forfeastcoding", secondPrice, 2);
|
||||
}
|
||||
|
||||
private void assertPremiumSpec(AppResourceList item, String name, String url,
|
||||
int priceFen, int sortOrder)
|
||||
{
|
||||
Assert.assertEquals(name, item.getListName());
|
||||
Assert.assertEquals(url, item.getListUrl());
|
||||
Assert.assertEquals(Integer.valueOf(priceFen), item.getPriceFen());
|
||||
Assert.assertEquals(Integer.valueOf(1), item.getStatus());
|
||||
Assert.assertEquals(Integer.valueOf(sortOrder), item.getSortOrder());
|
||||
Assert.assertEquals(Long.valueOf(100L), item.getAppResourceId());
|
||||
Assert.assertEquals("", item.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,14 @@ public class AppBlogArticle extends BaseEntity
|
||||
/** List-card thumbnail URL (not persisted). */
|
||||
private String showImgThumb;
|
||||
|
||||
/** 视频号演示视频feedId */
|
||||
@Excel(name = "视频号演示视频ID")
|
||||
private String videoFeedId;
|
||||
|
||||
/** 第二个视频号演示视频feedId */
|
||||
@Excel(name = "视频号演示视频ID 2")
|
||||
private String videoFeedId2;
|
||||
|
||||
/** 关联已有资源(关联app_resource id) */
|
||||
@Excel(name = "关联已有资源", readConverterExp = "关=联app_resource,i=d")
|
||||
private Long appResourceId;
|
||||
@@ -171,6 +179,24 @@ public class AppBlogArticle extends BaseEntity
|
||||
{
|
||||
return showImgThumb;
|
||||
}
|
||||
public void setVideoFeedId(String videoFeedId)
|
||||
{
|
||||
this.videoFeedId = videoFeedId;
|
||||
}
|
||||
|
||||
public String getVideoFeedId()
|
||||
{
|
||||
return videoFeedId;
|
||||
}
|
||||
public void setVideoFeedId2(String videoFeedId2)
|
||||
{
|
||||
this.videoFeedId2 = videoFeedId2;
|
||||
}
|
||||
|
||||
public String getVideoFeedId2()
|
||||
{
|
||||
return videoFeedId2;
|
||||
}
|
||||
public void setAppResourceId(Long appResourceId)
|
||||
{
|
||||
this.appResourceId = appResourceId;
|
||||
@@ -260,6 +286,8 @@ public class AppBlogArticle extends BaseEntity
|
||||
.append("contentInfo", getContentInfo())
|
||||
.append("articleType", getArticleType())
|
||||
.append("showImg", getShowImg())
|
||||
.append("videoFeedId", getVideoFeedId())
|
||||
.append("videoFeedId2", getVideoFeedId2())
|
||||
.append("appResourceId", getAppResourceId())
|
||||
.append("lookNumber", getLookNumber())
|
||||
.append("loveNumber", getLoveNumber())
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.ruoyi.app.mapper;
|
||||
import java.util.List;
|
||||
|
||||
import com.ruoyi.app.domain.AppBlogArticle;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
@@ -37,6 +39,10 @@ public interface AppBlogArticleMapper
|
||||
*/
|
||||
public List<AppBlogArticle> selectAppBlogArticleList(AppBlogArticle appBlogArticle);
|
||||
|
||||
/** 查询指定类型的可见文章数量 */
|
||||
@Select("select count(*) from app_blog_article where article_type = #{articleType} and is_show = #{isShow}")
|
||||
public Long countByArticleType(@Param("articleType") Long articleType, @Param("isShow") Long isShow);
|
||||
|
||||
/**
|
||||
* 新增文章
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import com.ruoyi.app.domain.AppResource;
|
||||
import com.ruoyi.app.domain.AppResourceList;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
/**
|
||||
@@ -44,6 +45,10 @@ public interface AppResourceMapper
|
||||
*/
|
||||
public List<AppResource> selectAppResourceList(AppResource appResource);
|
||||
|
||||
/** 查询可见资源数量 */
|
||||
@Select("select count(*) from app_resource where is_show = #{isShow}")
|
||||
public Long countByIsShow(@Param("isShow") Long isShow);
|
||||
|
||||
/**
|
||||
* 新增资源
|
||||
*
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.mapper.SysUserMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -99,7 +100,9 @@ public class AppIntegralRecordServiceImpl implements IAppIntegralRecordService
|
||||
|
||||
@Override
|
||||
public int czAppIntegra(AppIntegralRecord appIntegralRecord) {
|
||||
appIntegralRecord.setSource("充值积分");
|
||||
if (StringUtils.isBlank(appIntegralRecord.getSource())) {
|
||||
appIntegralRecord.setSource("充值积分");
|
||||
}
|
||||
appIntegralRecord.setIsAdd(0L);
|
||||
appIntegralRecord.setIntegralTime(new Date());
|
||||
int count = appIntegralRecordMapper.insertAppIntegralRecord(appIntegralRecord);
|
||||
|
||||
@@ -11,6 +11,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="articleType" column="article_type" />
|
||||
<result property="keyword" column="keyword" />
|
||||
<result property="showImg" column="show_img" />
|
||||
<result property="videoFeedId" column="video_feed_id" />
|
||||
<result property="videoFeedId2" column="video_feed_id_2" />
|
||||
<result property="appResourceId" column="app_resource_id" />
|
||||
<result property="lookNumber" column="look_number" />
|
||||
<result property="loveNumber" column="love_number" />
|
||||
@@ -46,12 +48,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectAppBlogArticleVo">
|
||||
select id, title, content_info, article_type, keyword, show_img, app_resource_id, look_number, weight, love_number, is_recommendation, is_show, is_ad, ad_number, del_flag, create_by, create_time, remark from app_blog_article
|
||||
select id, title, content_info, article_type, keyword, show_img, video_feed_id, video_feed_id_2, app_resource_id, look_number, weight, love_number, is_recommendation, is_show, is_ad, ad_number, del_flag, create_by, create_time, remark from app_blog_article
|
||||
</sql>
|
||||
|
||||
<select id="selectAppBlogArticleList" parameterType="AppBlogArticle" resultMap="AppBlogArticleWithResourceResult">
|
||||
select
|
||||
a.id, a.title, a.content_info, a.article_type, a.keyword, a.show_img, a.app_resource_id,
|
||||
a.id, a.title, a.content_info, a.article_type, a.keyword, a.show_img, a.video_feed_id, a.video_feed_id_2, a.app_resource_id,
|
||||
a.look_number, a.weight, a.love_number, a.is_recommendation, a.is_show, a.is_ad,
|
||||
a.ad_number, a.del_flag, a.create_by, a.create_time, a.remark,
|
||||
r.id as resource_id,
|
||||
@@ -83,6 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</where>
|
||||
<choose>
|
||||
<when test="orderType == 'look_number'"> ORDER BY a.look_number desc, a.create_time desc</when >
|
||||
<when test="orderType == 'create_time'"> ORDER BY a.create_time desc, a.id desc</when>
|
||||
<otherwise> ORDER BY a.weight desc, a.create_time desc</otherwise >
|
||||
</choose>
|
||||
</select>
|
||||
@@ -106,6 +109,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="articleType != null">article_type,</if>
|
||||
<if test="keyword != null and keyword != ''">keyword,</if>
|
||||
<if test="showImg != null">show_img,</if>
|
||||
<if test="videoFeedId != null">video_feed_id,</if>
|
||||
<if test="videoFeedId2 != null">video_feed_id_2,</if>
|
||||
<if test="appResourceId != null">app_resource_id,</if>
|
||||
<if test="lookNumber != null">look_number,</if>
|
||||
<if test="loveNumber != null">love_number,</if>
|
||||
@@ -125,6 +130,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="articleType != null">#{articleType},</if>
|
||||
<if test="keyword != null and keyword != ''">#{keyword},</if>
|
||||
<if test="showImg != null">#{showImg},</if>
|
||||
<if test="videoFeedId != null">#{videoFeedId},</if>
|
||||
<if test="videoFeedId2 != null">#{videoFeedId2},</if>
|
||||
<if test="appResourceId != null">#{appResourceId},</if>
|
||||
<if test="lookNumber != null">#{lookNumber},</if>
|
||||
<if test="loveNumber != null">#{loveNumber},</if>
|
||||
@@ -148,6 +155,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="articleType != null">article_type = #{articleType},</if>
|
||||
<if test="keyword != null and keyword != ''">keyword = #{keyword},</if>
|
||||
<if test="showImg != null">show_img = #{showImg},</if>
|
||||
<if test="videoFeedId != null">video_feed_id = #{videoFeedId},</if>
|
||||
<if test="videoFeedId2 != null">video_feed_id_2 = #{videoFeedId2},</if>
|
||||
<if test="appResourceId != null">app_resource_id = #{appResourceId},</if>
|
||||
<if test="lookNumber != null">look_number = #{lookNumber},</if>
|
||||
<if test="loveNumber != null">love_number = #{loveNumber},</if>
|
||||
|
||||
@@ -187,6 +187,9 @@
|
||||
<!-- 充值积分对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="openCzjf" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="充值来源" prop="source">
|
||||
<el-input v-model="form.source" placeholder="请输入充值来源" />
|
||||
</el-form-item>
|
||||
<el-form-item label="充值分数" prop="integralNumber">
|
||||
<el-input v-model="form.integralNumber" placeholder="请输入充值分数" />
|
||||
</el-form-item>
|
||||
@@ -302,6 +305,7 @@ export default {
|
||||
/** 充值积分按钮操作 */
|
||||
handleCzjf() {
|
||||
this.reset();
|
||||
this.form.source = "充值积分";
|
||||
this.openCzjf = true;
|
||||
this.title = "充值积分";
|
||||
},
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
<el-option v-for="dict in dict.type.article_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键字" prop="keyword">
|
||||
<el-input v-model="queryParams.keyword" placeholder="请输入搜素关键字" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="推荐文章" prop="isRecommendation">
|
||||
<el-select v-model="queryParams.isRecommendation" placeholder="请选择是否为推荐文章" clearable>
|
||||
<el-option v-for="dict in dict.type.sys_yes_no2" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
@@ -58,8 +55,6 @@
|
||||
<dict-tag :options="dict.type.article_type" :value="scope.row.articleType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="搜素关键字" align="center" prop="keyword" />
|
||||
|
||||
<el-table-column label="游览次数" align="center" prop="lookNumber" />
|
||||
<el-table-column label="点赞次数" align="center" prop="loveNumber" />
|
||||
<el-table-column label="权重" align="center" prop="weight" />
|
||||
@@ -80,8 +75,16 @@
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="需要观看几次广告解锁" align="center" prop="adNumber" /> -->
|
||||
<el-table-column label="关联已有资源" align="center" prop="appResourceId" />
|
||||
<el-table-column label="演示视频" align="center" prop="videoFeedId" width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.videoFeedId || scope.row.videoFeedId2 ? 'success' : 'info'" size="mini">
|
||||
{{ scope.row.videoFeedId && scope.row.videoFeedId2
|
||||
? '2个视频'
|
||||
: (scope.row.videoFeedId || scope.row.videoFeedId2 ? '1个视频' : '未配置') }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160px" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
@@ -119,6 +122,20 @@
|
||||
<el-input v-model="form.showImg" placeholder="请输入封面图url" />
|
||||
<image-upload style="margin-top: 10px;" v-model="form.showImg"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="演示视频ID" prop="videoFeedId">
|
||||
<el-input
|
||||
v-model.trim="form.videoFeedId"
|
||||
placeholder="请输入 export/ 开头的视频 feedId,留空表示暂无演示视频"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="演示视频ID 2" prop="videoFeedId2">
|
||||
<el-input
|
||||
v-model.trim="form.videoFeedId2"
|
||||
placeholder="请输入第二个视频的 feedId,留空表示只有一个演示视频"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="权重" prop="weight">
|
||||
<el-input v-model="form.weight" placeholder="请输入权重 999 表示为置顶" />
|
||||
</el-form-item>
|
||||
@@ -283,6 +300,8 @@
|
||||
contentInfo: null,
|
||||
articleType: null,
|
||||
showImg: null,
|
||||
videoFeedId: null,
|
||||
videoFeedId2: null,
|
||||
appResourceId: null,
|
||||
lookNumber: null,
|
||||
loveNumber: null,
|
||||
|
||||
4
sql/article_video_feed_id.sql
Normal file
4
sql/article_video_feed_id.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
-- 为每篇文章单独配置微信视频号演示视频。
|
||||
-- 视频号 finderUserName 由小程序统一配置,此处只保存视频 feedId。
|
||||
ALTER TABLE `app_blog_article`
|
||||
ADD COLUMN `video_feed_id` VARCHAR(255) NULL COMMENT '视频号演示视频feedId' AFTER `show_img`;
|
||||
3
sql/article_video_feed_id_2.sql
Normal file
3
sql/article_video_feed_id_2.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- 每篇文章最多维护两个微信视频号演示视频。
|
||||
ALTER TABLE `app_blog_article`
|
||||
ADD COLUMN `video_feed_id_2` VARCHAR(255) NULL COMMENT '第二个视频号演示视频feedId' AFTER `video_feed_id`;
|
||||
Reference in New Issue
Block a user