Procházet zdrojové kódy

Merge branch 'master' of http://192.168.1.25:3000/lbyzx123/huimv-baqing

xsh_1997 před 2 týdny
rodič
revize
003f7b08b1
17 změnil soubory, kde provedl 308 přidání a 885 odebrání
  1. 31 18
      baqing-admin/src/main/java/com/ruoyi/web/modules/prosperity/domain/BizCommonProsperityProject.java
  2. 2 2
      baqing-admin/src/main/java/com/ruoyi/web/modules/prosperity/mapper/BizCommonProsperityProjectMapper.java
  3. 48 28
      baqing-admin/src/main/java/com/ruoyi/web/modules/prosperity/support/CommonProsperityProjectValidation.java
  4. 40 22
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/ScreenProjectListItemVo.java
  5. 16 23
      baqing-admin/src/main/java/com/ruoyi/web/modules/screen/support/CommonProsperityScreenSupport.java
  6. 36 38
      baqing-admin/src/main/resources/mapper/prosperity/BizCommonProsperityProjectMapper.xml
  7. 4 9
      baqing-admin/src/test/java/com/ruoyi/web/modules/prosperity/controller/BizCommonProsperityProjectControllerApiTest.java
  8. 1 8
      baqing-admin/src/test/java/com/ruoyi/web/modules/prosperity/service/impl/BizCommonProsperityProjectServiceImplTest.java
  9. 21 20
      baqing-admin/src/test/java/com/ruoyi/web/modules/prosperity/support/CommonProsperityProjectValidationTest.java
  10. 3 2
      baqing-admin/src/test/java/com/ruoyi/web/modules/screen/controller/CommonProsperityScreenControllerApiTest.java
  11. 11 32
      baqing-admin/src/test/java/com/ruoyi/web/modules/screen/support/CommonProsperityScreenSupportTest.java
  12. 10 87
      doc/共同富裕/共同富裕项目/共同富裕项目前端技术方案.md
  13. 26 186
      doc/共同富裕/共同富裕项目/共同富裕项目功能需求.md
  14. 20 225
      doc/共同富裕/共同富裕项目/共同富裕项目技术方案.md
  15. 17 170
      doc/共同富裕/共同富裕项目/共同富裕项目管理测试用例.md
  16. 9 7
      doc/大屏/共同富裕/大屏共同富裕技术方案.md
  17. 13 8
      sql/biz_common_prosperity_project.sql

+ 31 - 18
baqing-admin/src/main/java/com/ruoyi/web/modules/prosperity/domain/BizCommonProsperityProject.java

@@ -1,5 +1,6 @@
1
 package com.ruoyi.web.modules.prosperity.domain;
1
 package com.ruoyi.web.modules.prosperity.domain;
2
 
2
 
3
+import java.math.BigDecimal;
3
 import java.util.Date;
4
 import java.util.Date;
4
 import java.util.List;
5
 import java.util.List;
5
 import javax.validation.constraints.NotBlank;
6
 import javax.validation.constraints.NotBlank;
@@ -24,21 +25,23 @@ public class BizCommonProsperityProject extends BaseEntity
24
     @NotNull(message = "项目类型不能为空")
25
     @NotNull(message = "项目类型不能为空")
25
     private Integer projectType;
26
     private Integer projectType;
26
 
27
 
27
-    @NotBlank(message = "项目简介不能为空")
28
-    @Size(min = 1, max = 50, message = "项目简介长度为1到50个字符")
28
+    /** 选填 */
29
+    @Size(max = 50, message = "项目简介长度不能超过50个字符")
29
     private String introduction;
30
     private String introduction;
30
 
31
 
31
-    @NotBlank(message = "项目内容不能为空")
32
-    @Size(min = 1, max = 500, message = "项目内容长度为1到500个字符")
32
+    @NotBlank(message = "建设规模及内容不能为空")
33
+    @Size(min = 1, max = 500, message = "建设规模及内容长度为1到500个字符")
33
     private String projectContent;
34
     private String projectContent;
34
 
35
 
35
-    @NotNull(message = "实施开始日期不能为空")
36
-    @JsonFormat(pattern = "yyyy-MM-dd")
37
-    private Date implStartDate;
36
+    /** 投资金额(万元) */
37
+    private BigDecimal investmentAmount;
38
 
38
 
39
-    @NotNull(message = "实施结束日期不能为空")
40
-    @JsonFormat(pattern = "yyyy-MM-dd")
41
-    private Date implEndDate;
39
+    @NotNull(message = "实施年限不能为空")
40
+    private Integer implYear;
41
+
42
+    /** 实施情况(选填) */
43
+    @Size(max = 500, message = "实施情况长度不能超过500个字符")
44
+    private String implStatus;
42
 
45
 
43
     private String videoFileUrl;
46
     private String videoFileUrl;
44
 
47
 
@@ -113,24 +116,34 @@ public class BizCommonProsperityProject extends BaseEntity
113
         this.projectContent = projectContent;
116
         this.projectContent = projectContent;
114
     }
117
     }
115
 
118
 
116
-    public Date getImplStartDate()
119
+    public BigDecimal getInvestmentAmount()
120
+    {
121
+        return investmentAmount;
122
+    }
123
+
124
+    public void setInvestmentAmount(BigDecimal investmentAmount)
125
+    {
126
+        this.investmentAmount = investmentAmount;
127
+    }
128
+
129
+    public Integer getImplYear()
117
     {
130
     {
118
-        return implStartDate;
131
+        return implYear;
119
     }
132
     }
120
 
133
 
121
-    public void setImplStartDate(Date implStartDate)
134
+    public void setImplYear(Integer implYear)
122
     {
135
     {
123
-        this.implStartDate = implStartDate;
136
+        this.implYear = implYear;
124
     }
137
     }
125
 
138
 
126
-    public Date getImplEndDate()
139
+    public String getImplStatus()
127
     {
140
     {
128
-        return implEndDate;
141
+        return implStatus;
129
     }
142
     }
130
 
143
 
131
-    public void setImplEndDate(Date implEndDate)
144
+    public void setImplStatus(String implStatus)
132
     {
145
     {
133
-        this.implEndDate = implEndDate;
146
+        this.implStatus = implStatus;
134
     }
147
     }
135
 
148
 
136
     public String getVideoFileUrl()
149
     public String getVideoFileUrl()

+ 2 - 2
baqing-admin/src/main/java/com/ruoyi/web/modules/prosperity/mapper/BizCommonProsperityProjectMapper.java

@@ -20,12 +20,12 @@ public interface BizCommonProsperityProjectMapper
20
     int deleteBizCommonProsperityProjectByIds(Long[] ids);
20
     int deleteBizCommonProsperityProjectByIds(Long[] ids);
21
 
21
 
22
     /**
22
     /**
23
-     * 大屏:已发布且实施周期与统计年有交集的项目(分类统计、列表分页共用条件)
23
+     * 大屏:已发布且实施年限等于统计年的项目
24
      */
24
      */
25
     List<BizCommonProsperityProject> selectPublishedForScreen(@Param("statYear") int statYear);
25
     List<BizCommonProsperityProject> selectPublishedForScreen(@Param("statYear") int statYear);
26
 
26
 
27
     /**
27
     /**
28
-     * 大屏:已发布项目涉及的年份(实施起止年的并集,供可选年份下拉)。
28
+     * 大屏:已发布项目的实施年限并集(可选年份下拉)。
29
      */
29
      */
30
     List<String> selectDistinctStatYearsFromPublished();
30
     List<String> selectDistinctStatYearsFromPublished();
31
 }
31
 }

+ 48 - 28
baqing-admin/src/main/java/com/ruoyi/web/modules/prosperity/support/CommonProsperityProjectValidation.java

@@ -1,7 +1,7 @@
1
 package com.ruoyi.web.modules.prosperity.support;
1
 package com.ruoyi.web.modules.prosperity.support;
2
 
2
 
3
+import java.math.BigDecimal;
3
 import java.util.Calendar;
4
 import java.util.Calendar;
4
-import java.util.Date;
5
 import java.util.HashSet;
5
 import java.util.HashSet;
6
 import java.util.List;
6
 import java.util.List;
7
 import java.util.Set;
7
 import java.util.Set;
@@ -32,12 +32,18 @@ public final class CommonProsperityProjectValidation
32
         }
32
         }
33
         if (row.getIntroduction() != null)
33
         if (row.getIntroduction() != null)
34
         {
34
         {
35
-            row.setIntroduction(row.getIntroduction().trim());
35
+            String intro = row.getIntroduction().trim();
36
+            row.setIntroduction(StringUtils.isEmpty(intro) ? null : intro);
36
         }
37
         }
37
         if (row.getProjectContent() != null)
38
         if (row.getProjectContent() != null)
38
         {
39
         {
39
             row.setProjectContent(row.getProjectContent().trim());
40
             row.setProjectContent(row.getProjectContent().trim());
40
         }
41
         }
42
+        if (row.getImplStatus() != null)
43
+        {
44
+            String status = row.getImplStatus().trim();
45
+            row.setImplStatus(StringUtils.isEmpty(status) ? null : status);
46
+        }
41
         if (row.getVideoFileUrl() != null)
47
         if (row.getVideoFileUrl() != null)
42
         {
48
         {
43
             row.setVideoFileUrl(row.getVideoFileUrl().trim());
49
             row.setVideoFileUrl(row.getVideoFileUrl().trim());
@@ -86,15 +92,20 @@ public final class CommonProsperityProjectValidation
86
     {
92
     {
87
         if (projectType == null || projectType < 1 || projectType > 3)
93
         if (projectType == null || projectType < 1 || projectType > 3)
88
         {
94
         {
89
-            throw new ServiceException("项目类型须为1~3(1合作共赢2农文旅融合3认养农业)");
95
+            throw new ServiceException("项目类型须为1~3(1和美乡村建设2人居环境整治提升3其他项目投入)");
90
         }
96
         }
91
     }
97
     }
92
 
98
 
99
+    /** 选填;有值时长度 1~50 */
93
     public static void validateIntroduction(String introduction)
100
     public static void validateIntroduction(String introduction)
94
     {
101
     {
95
-        if (StringUtils.isEmpty(introduction) || introduction.length() < 1 || introduction.length() > 50)
102
+        if (StringUtils.isEmpty(introduction))
103
+        {
104
+            return;
105
+        }
106
+        if (introduction.length() > 50)
96
         {
107
         {
97
-            throw new ServiceException("项目简介须为1~50个字符");
108
+            throw new ServiceException("项目简介不能超过50个字符");
98
         }
109
         }
99
     }
110
     }
100
 
111
 
@@ -102,29 +113,44 @@ public final class CommonProsperityProjectValidation
102
     {
113
     {
103
         if (StringUtils.isEmpty(projectContent) || projectContent.length() < 1 || projectContent.length() > 500)
114
         if (StringUtils.isEmpty(projectContent) || projectContent.length() < 1 || projectContent.length() > 500)
104
         {
115
         {
105
-            throw new ServiceException("项目内容须为1~500个字符");
116
+            throw new ServiceException("建设规模及内容须为1~500个字符");
106
         }
117
         }
107
     }
118
     }
108
 
119
 
109
-    public static void validateImplDateRange(Date implStartDate, Date implEndDate)
120
+    public static void validateInvestmentAmount(BigDecimal amount)
110
     {
121
     {
111
-        if (implStartDate == null)
122
+        if (amount == null)
112
         {
123
         {
113
-            throw new ServiceException("实施开始日期不能为空");
124
+            return;
114
         }
125
         }
115
-        if (implEndDate == null)
126
+        if (amount.compareTo(BigDecimal.ZERO) < 0)
116
         {
127
         {
117
-            throw new ServiceException("实施结束日期不能为空");
128
+            throw new ServiceException("投资金额不能为负数");
118
         }
129
         }
119
-        Calendar start = Calendar.getInstance();
120
-        start.setTime(implStartDate);
121
-        truncateToDay(start);
122
-        Calendar end = Calendar.getInstance();
123
-        end.setTime(implEndDate);
124
-        truncateToDay(end);
125
-        if (end.before(start))
130
+        if (amount.scale() > 4)
126
         {
131
         {
127
-            throw new ServiceException("结束日期不能早于开始日期");
132
+            throw new ServiceException("投资金额最多保留4位小数");
133
+        }
134
+    }
135
+
136
+    public static void validateImplYear(Integer implYear)
137
+    {
138
+        if (implYear == null)
139
+        {
140
+            throw new ServiceException("实施年限不能为空");
141
+        }
142
+        int current = Calendar.getInstance().get(Calendar.YEAR);
143
+        if (implYear < 2000 || implYear > current)
144
+        {
145
+            throw new ServiceException("实施年限不合法");
146
+        }
147
+    }
148
+
149
+    public static void validateImplStatus(String implStatus)
150
+    {
151
+        if (StringUtils.isNotEmpty(implStatus) && implStatus.length() > 500)
152
+        {
153
+            throw new ServiceException("实施情况不能超过500个字符");
128
         }
154
         }
129
     }
155
     }
130
 
156
 
@@ -220,17 +246,11 @@ public final class CommonProsperityProjectValidation
220
         validateProjectType(row.getProjectType());
246
         validateProjectType(row.getProjectType());
221
         validateIntroduction(row.getIntroduction());
247
         validateIntroduction(row.getIntroduction());
222
         validateProjectContent(row.getProjectContent());
248
         validateProjectContent(row.getProjectContent());
223
-        validateImplDateRange(row.getImplStartDate(), row.getImplEndDate());
249
+        validateInvestmentAmount(row.getInvestmentAmount());
250
+        validateImplYear(row.getImplYear());
251
+        validateImplStatus(row.getImplStatus());
224
         validateOperationImages(row.getOperationImages());
252
         validateOperationImages(row.getOperationImages());
225
         validateVideoPair(row.getVideoFileUrl(), row.getVideoFilePath());
253
         validateVideoPair(row.getVideoFileUrl(), row.getVideoFilePath());
226
         validateCoverPair(row.getCoverFileUrl(), row.getCoverFilePath());
254
         validateCoverPair(row.getCoverFileUrl(), row.getCoverFilePath());
227
     }
255
     }
228
-
229
-    private static void truncateToDay(Calendar cal)
230
-    {
231
-        cal.set(Calendar.HOUR_OF_DAY, 0);
232
-        cal.set(Calendar.MINUTE, 0);
233
-        cal.set(Calendar.SECOND, 0);
234
-        cal.set(Calendar.MILLISECOND, 0);
235
-    }
236
 }
256
 }

+ 40 - 22
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/domain/vo/ScreenProjectListItemVo.java

@@ -1,36 +1,44 @@
1
 package com.ruoyi.web.modules.screen.domain.vo;
1
 package com.ruoyi.web.modules.screen.domain.vo;
2
 
2
 
3
 import java.io.Serializable;
3
 import java.io.Serializable;
4
+import java.math.BigDecimal;
4
 import java.util.List;
5
 import java.util.List;
6
+
5
 /**
7
 /**
6
  * 共富项目列表项(分页 {@code /bigScreen/commonProsperity/projects})。
8
  * 共富项目列表项(分页 {@code /bigScreen/commonProsperity/projects})。
7
  */
9
  */
8
 public class ScreenProjectListItemVo implements Serializable
10
 public class ScreenProjectListItemVo implements Serializable
9
 {
11
 {
10
     private static final long serialVersionUID = 1L;
12
     private static final long serialVersionUID = 1L;
11
-    /** 项目 ID */
13
+
12
     private Long id;
14
     private Long id;
13
-    /** 项目类型码 */
15
+
14
     private Integer projectType;
16
     private Integer projectType;
15
-    /** 类型名称 */
17
+
16
     private String projectTypeName;
18
     private String projectTypeName;
17
-    /** 项目名称 */
19
+
18
     private String projectName;
20
     private String projectName;
19
-    /** 简介 */
21
+
20
     private String introduction;
22
     private String introduction;
21
-    /** 项目内容 */
23
+
24
+    /** 建设规模及内容 */
22
     private String projectContent;
25
     private String projectContent;
23
-    /** 实施开始 yyyy-MM-dd */
24
-    private String implStartDate;
25
-    /** 实施结束 yyyy-MM-dd */
26
-    private String implEndDate;
27
-    /** 封面 URL */
26
+
27
+    /** 投资金额(万元) */
28
+    private BigDecimal investmentAmount;
29
+
30
+    /** 实施年限 */
31
+    private Integer implYear;
32
+
33
+    /** 实施情况 */
34
+    private String implStatus;
35
+
28
     private String coverFileUrl;
36
     private String coverFileUrl;
29
-    /** 视频 URL */
37
+
30
     private String videoFileUrl;
38
     private String videoFileUrl;
31
-    /** 发布时间 */
39
+
32
     private String publishTime;
40
     private String publishTime;
33
-    /** 运营图片列表 */
41
+
34
     private List<ScreenProjectOpImageVo> operationImages;
42
     private List<ScreenProjectOpImageVo> operationImages;
35
 
43
 
36
     public Long getId()
44
     public Long getId()
@@ -93,24 +101,34 @@ public class ScreenProjectListItemVo implements Serializable
93
         this.projectContent = projectContent;
101
         this.projectContent = projectContent;
94
     }
102
     }
95
 
103
 
96
-    public String getImplStartDate()
104
+    public BigDecimal getInvestmentAmount()
105
+    {
106
+        return investmentAmount;
107
+    }
108
+
109
+    public void setInvestmentAmount(BigDecimal investmentAmount)
110
+    {
111
+        this.investmentAmount = investmentAmount;
112
+    }
113
+
114
+    public Integer getImplYear()
97
     {
115
     {
98
-        return implStartDate;
116
+        return implYear;
99
     }
117
     }
100
 
118
 
101
-    public void setImplStartDate(String implStartDate)
119
+    public void setImplYear(Integer implYear)
102
     {
120
     {
103
-        this.implStartDate = implStartDate;
121
+        this.implYear = implYear;
104
     }
122
     }
105
 
123
 
106
-    public String getImplEndDate()
124
+    public String getImplStatus()
107
     {
125
     {
108
-        return implEndDate;
126
+        return implStatus;
109
     }
127
     }
110
 
128
 
111
-    public void setImplEndDate(String implEndDate)
129
+    public void setImplStatus(String implStatus)
112
     {
130
     {
113
-        this.implEndDate = implEndDate;
131
+        this.implStatus = implStatus;
114
     }
132
     }
115
 
133
 
116
     public String getCoverFileUrl()
134
     public String getCoverFileUrl()

+ 16 - 23
baqing-admin/src/main/java/com/ruoyi/web/modules/screen/support/CommonProsperityScreenSupport.java

@@ -9,7 +9,6 @@ import java.util.Collections;
9
 import java.util.Comparator;
9
 import java.util.Comparator;
10
 import java.util.Date;
10
 import java.util.Date;
11
 import java.util.HashMap;
11
 import java.util.HashMap;
12
-import java.util.HashSet;
13
 import java.util.List;
12
 import java.util.List;
14
 import java.util.Map;
13
 import java.util.Map;
15
 import java.util.Set;
14
 import java.util.Set;
@@ -25,12 +24,12 @@ import com.ruoyi.web.modules.screen.domain.vo.ScreenProjectOpImageVo;
25
  */
24
  */
26
 public final class CommonProsperityScreenSupport
25
 public final class CommonProsperityScreenSupport
27
 {
26
 {
28
-    private static final String DATE_FMT = "yyyy-MM-dd";
29
-
30
     private static final String DATETIME_FMT = "yyyy-MM-dd HH:mm:ss";
27
     private static final String DATETIME_FMT = "yyyy-MM-dd HH:mm:ss";
31
 
28
 
32
-    /** 1 合作共赢 → 共富项目;2 农文旅;3 认养 */
33
-    private static final String[] TYPE_NAMES = { null, "共富项目", "农文旅项目", "认养项目" };
29
+    /** 1 和美乡村建设;2 人居环境整治提升;3 其他项目投入 */
30
+    private static final String[] TYPE_NAMES = {
31
+            null, "和美乡村建设项目", "人居环境整治提升项目", "其他项目投入"
32
+    };
34
 
33
 
35
     private CommonProsperityScreenSupport()
34
     private CommonProsperityScreenSupport()
36
     {
35
     {
@@ -46,27 +45,21 @@ public final class CommonProsperityScreenSupport
46
     }
45
     }
47
 
46
 
48
     /**
47
     /**
49
-     * 已发布且实施周期与统计年 Y 有交集
48
+     * 已发布且实施年限等于统计年 Y
50
      */
49
      */
51
-    public static boolean intersectsStatYear(BizCommonProsperityProject project, int statYear)
50
+    public static boolean matchesStatYear(BizCommonProsperityProject project, int statYear)
52
     {
51
     {
53
         if (project == null || project.getPublishStatus() == null || project.getPublishStatus() != 1)
52
         if (project == null || project.getPublishStatus() == null || project.getPublishStatus() != 1)
54
         {
53
         {
55
             return false;
54
             return false;
56
         }
55
         }
57
-        Date start = project.getImplStartDate();
58
-        Date end = project.getImplEndDate();
59
-        if (start == null || end == null)
60
-        {
61
-            return false;
62
-        }
63
-        Calendar yearStart = Calendar.getInstance();
64
-        yearStart.clear();
65
-        yearStart.set(statYear, Calendar.JANUARY, 1, 0, 0, 0);
66
-        Calendar yearEnd = Calendar.getInstance();
67
-        yearEnd.clear();
68
-        yearEnd.set(statYear, Calendar.DECEMBER, 31, 23, 59, 59);
69
-        return !start.after(yearEnd.getTime()) && !end.before(yearStart.getTime());
56
+        return project.getImplYear() != null && project.getImplYear() == statYear;
57
+    }
58
+
59
+    /** @deprecated 使用 {@link #matchesStatYear};保留别名避免旧测试编译失败时遗漏 */
60
+    public static boolean intersectsStatYear(BizCommonProsperityProject project, int statYear)
61
+    {
62
+        return matchesStatYear(project, statYear);
70
     }
63
     }
71
 
64
 
72
     public static List<ProjectTypeStatVo> buildProjectTypeStats(List<BizCommonProsperityProject> projects)
65
     public static List<ProjectTypeStatVo> buildProjectTypeStats(List<BizCommonProsperityProject> projects)
@@ -156,7 +149,6 @@ public final class CommonProsperityScreenSupport
156
             return Collections.emptyList();
149
             return Collections.emptyList();
157
         }
150
         }
158
         List<ScreenProjectListItemVo> list = new ArrayList<>(projects.size());
151
         List<ScreenProjectListItemVo> list = new ArrayList<>(projects.size());
159
-        SimpleDateFormat dateFmt = new SimpleDateFormat(DATE_FMT);
160
         SimpleDateFormat dateTimeFmt = new SimpleDateFormat(DATETIME_FMT);
152
         SimpleDateFormat dateTimeFmt = new SimpleDateFormat(DATETIME_FMT);
161
         for (BizCommonProsperityProject p : projects)
153
         for (BizCommonProsperityProject p : projects)
162
         {
154
         {
@@ -167,8 +159,9 @@ public final class CommonProsperityScreenSupport
167
             vo.setProjectName(p.getProjectName());
159
             vo.setProjectName(p.getProjectName());
168
             vo.setIntroduction(p.getIntroduction());
160
             vo.setIntroduction(p.getIntroduction());
169
             vo.setProjectContent(p.getProjectContent());
161
             vo.setProjectContent(p.getProjectContent());
170
-            vo.setImplStartDate(formatDate(p.getImplStartDate(), dateFmt));
171
-            vo.setImplEndDate(formatDate(p.getImplEndDate(), dateFmt));
162
+            vo.setInvestmentAmount(p.getInvestmentAmount());
163
+            vo.setImplYear(p.getImplYear());
164
+            vo.setImplStatus(p.getImplStatus());
172
             vo.setCoverFileUrl(p.getCoverFileUrl());
165
             vo.setCoverFileUrl(p.getCoverFileUrl());
173
             vo.setVideoFileUrl(p.getVideoFileUrl());
166
             vo.setVideoFileUrl(p.getVideoFileUrl());
174
             vo.setPublishTime(formatDate(p.getPublishTime(), dateTimeFmt));
167
             vo.setPublishTime(formatDate(p.getPublishTime(), dateTimeFmt));

+ 36 - 38
baqing-admin/src/main/resources/mapper/prosperity/BizCommonProsperityProjectMapper.xml

@@ -3,31 +3,32 @@
3
 <mapper namespace="com.ruoyi.web.modules.prosperity.mapper.BizCommonProsperityProjectMapper">
3
 <mapper namespace="com.ruoyi.web.modules.prosperity.mapper.BizCommonProsperityProjectMapper">
4
 
4
 
5
     <resultMap type="com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProject" id="BizCommonProsperityProjectResult">
5
     <resultMap type="com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProject" id="BizCommonProsperityProjectResult">
6
-        <id     property="id"              column="id"/>
7
-        <result property="projectName"     column="project_name"/>
8
-        <result property="projectType"     column="project_type"/>
9
-        <result property="introduction"    column="introduction"/>
10
-        <result property="projectContent"  column="project_content"/>
11
-        <result property="implStartDate"   column="impl_start_date"/>
12
-        <result property="implEndDate"     column="impl_end_date"/>
13
-        <result property="videoFileUrl"    column="video_file_url"/>
14
-        <result property="videoFilePath"   column="video_file_path"/>
15
-        <result property="coverFileUrl"    column="cover_file_url"/>
16
-        <result property="coverFilePath"   column="cover_file_path"/>
17
-        <result property="publishStatus"   column="publish_status"/>
18
-        <result property="publishTime"     column="publish_time"/>
19
-        <result property="offlineTime"     column="offline_time"/>
20
-        <result property="opImageCount"    column="op_image_count"/>
21
-        <result property="createBy"        column="create_by"/>
22
-        <result property="createTime"      column="create_time"/>
23
-        <result property="updateBy"        column="update_by"/>
24
-        <result property="updateTime"      column="update_time"/>
25
-        <result property="remark"          column="remark"/>
6
+        <id     property="id"                column="id"/>
7
+        <result property="projectName"       column="project_name"/>
8
+        <result property="projectType"       column="project_type"/>
9
+        <result property="introduction"      column="introduction"/>
10
+        <result property="projectContent"    column="project_content"/>
11
+        <result property="investmentAmount"  column="investment_amount"/>
12
+        <result property="implYear"          column="impl_year"/>
13
+        <result property="implStatus"        column="impl_status"/>
14
+        <result property="videoFileUrl"      column="video_file_url"/>
15
+        <result property="videoFilePath"     column="video_file_path"/>
16
+        <result property="coverFileUrl"      column="cover_file_url"/>
17
+        <result property="coverFilePath"     column="cover_file_path"/>
18
+        <result property="publishStatus"     column="publish_status"/>
19
+        <result property="publishTime"       column="publish_time"/>
20
+        <result property="offlineTime"       column="offline_time"/>
21
+        <result property="opImageCount"      column="op_image_count"/>
22
+        <result property="createBy"          column="create_by"/>
23
+        <result property="createTime"        column="create_time"/>
24
+        <result property="updateBy"          column="update_by"/>
25
+        <result property="updateTime"        column="update_time"/>
26
+        <result property="remark"            column="remark"/>
26
     </resultMap>
27
     </resultMap>
27
 
28
 
28
     <sql id="selectVo">
29
     <sql id="selectVo">
29
         select p.id, p.project_name, p.project_type, p.introduction, p.project_content,
30
         select p.id, p.project_name, p.project_type, p.introduction, p.project_content,
30
-               p.impl_start_date, p.impl_end_date,
31
+               p.investment_amount, p.impl_year, p.impl_status,
31
                p.video_file_url, p.video_file_path, p.cover_file_url, p.cover_file_path,
32
                p.video_file_url, p.video_file_path, p.cover_file_url, p.cover_file_path,
32
                p.publish_status, p.publish_time, p.offline_time,
33
                p.publish_status, p.publish_time, p.offline_time,
33
                p.create_by, p.create_time, p.update_by, p.update_time, p.remark,
34
                p.create_by, p.create_time, p.update_by, p.update_time, p.remark,
@@ -37,7 +38,7 @@
37
 
38
 
38
     <sql id="selectVoById">
39
     <sql id="selectVoById">
39
         select id, project_name, project_type, introduction, project_content,
40
         select id, project_name, project_type, introduction, project_content,
40
-               impl_start_date, impl_end_date,
41
+               investment_amount, impl_year, impl_status,
41
                video_file_url, video_file_path, cover_file_url, cover_file_path,
42
                video_file_url, video_file_path, cover_file_url, cover_file_path,
42
                publish_status, publish_time, offline_time,
43
                publish_status, publish_time, offline_time,
43
                create_by, create_time, update_by, update_time, remark
44
                create_by, create_time, update_by, update_time, remark
@@ -58,6 +59,9 @@
58
             <if test="projectType != null">
59
             <if test="projectType != null">
59
                 and p.project_type = #{projectType}
60
                 and p.project_type = #{projectType}
60
             </if>
61
             </if>
62
+            <if test="implYear != null">
63
+                and p.impl_year = #{implYear}
64
+            </if>
61
             <if test="publishStatus != null">
65
             <if test="publishStatus != null">
62
                 and p.publish_status = #{publishStatus}
66
                 and p.publish_status = #{publishStatus}
63
             </if>
67
             </if>
@@ -68,13 +72,13 @@
68
     <insert id="insertBizCommonProsperityProject" parameterType="com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProject" useGeneratedKeys="true" keyProperty="id">
72
     <insert id="insertBizCommonProsperityProject" parameterType="com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProject" useGeneratedKeys="true" keyProperty="id">
69
         insert into biz_common_prosperity_project (
73
         insert into biz_common_prosperity_project (
70
             project_name, project_type, introduction, project_content,
74
             project_name, project_type, introduction, project_content,
71
-            impl_start_date, impl_end_date,
75
+            investment_amount, impl_year, impl_status,
72
             video_file_url, video_file_path, cover_file_url, cover_file_path,
76
             video_file_url, video_file_path, cover_file_url, cover_file_path,
73
             publish_status, publish_time, offline_time,
77
             publish_status, publish_time, offline_time,
74
             create_by, create_time, remark
78
             create_by, create_time, remark
75
         ) values (
79
         ) values (
76
             #{projectName}, #{projectType}, #{introduction}, #{projectContent},
80
             #{projectName}, #{projectType}, #{introduction}, #{projectContent},
77
-            #{implStartDate}, #{implEndDate},
81
+            #{investmentAmount}, #{implYear}, #{implStatus},
78
             #{videoFileUrl}, #{videoFilePath}, #{coverFileUrl}, #{coverFilePath},
82
             #{videoFileUrl}, #{videoFilePath}, #{coverFileUrl}, #{coverFilePath},
79
             #{publishStatus}, #{publishTime}, #{offlineTime},
83
             #{publishStatus}, #{publishTime}, #{offlineTime},
80
             #{createBy}, sysdate(), #{remark}
84
             #{createBy}, sysdate(), #{remark}
@@ -87,8 +91,9 @@
87
             project_type = #{projectType},
91
             project_type = #{projectType},
88
             introduction = #{introduction},
92
             introduction = #{introduction},
89
             project_content = #{projectContent},
93
             project_content = #{projectContent},
90
-            impl_start_date = #{implStartDate},
91
-            impl_end_date = #{implEndDate},
94
+            investment_amount = #{investmentAmount},
95
+            impl_year = #{implYear},
96
+            impl_status = #{implStatus},
92
             video_file_url = #{videoFileUrl},
97
             video_file_url = #{videoFileUrl},
93
             video_file_path = #{videoFilePath},
98
             video_file_path = #{videoFilePath},
94
             cover_file_url = #{coverFileUrl},
99
             cover_file_url = #{coverFileUrl},
@@ -111,8 +116,7 @@
111
 
116
 
112
     <sql id="screenPublishedWhere">
117
     <sql id="screenPublishedWhere">
113
         where p.publish_status = 1
118
         where p.publish_status = 1
114
-          and p.impl_start_date &lt;= concat(#{statYear}, '-12-31')
115
-          and p.impl_end_date &gt;= concat(#{statYear}, '-01-01')
119
+          and p.impl_year = #{statYear}
116
     </sql>
120
     </sql>
117
 
121
 
118
     <select id="selectPublishedForScreen" resultMap="BizCommonProsperityProjectResult">
122
     <select id="selectPublishedForScreen" resultMap="BizCommonProsperityProjectResult">
@@ -122,16 +126,10 @@
122
     </select>
126
     </select>
123
 
127
 
124
     <select id="selectDistinctStatYearsFromPublished" resultType="string">
128
     <select id="selectDistinctStatYearsFromPublished" resultType="string">
125
-        select distinct y from (
126
-            select cast(year(impl_start_date) as char) as y
127
-            from biz_common_prosperity_project
128
-            where publish_status = 1
129
-            union
130
-            select cast(year(impl_end_date) as char) as y
131
-            from biz_common_prosperity_project
132
-            where publish_status = 1
133
-        ) t
134
-        where y is not null and y != ''
129
+        select distinct cast(impl_year as char) as y
130
+        from biz_common_prosperity_project
131
+        where publish_status = 1
132
+          and impl_year is not null
135
         order by y desc
133
         order by y desc
136
     </select>
134
     </select>
137
 </mapper>
135
 </mapper>

+ 4 - 9
baqing-admin/src/test/java/com/ruoyi/web/modules/prosperity/controller/BizCommonProsperityProjectControllerApiTest.java

@@ -338,15 +338,10 @@ class BizCommonProsperityProjectControllerApiTest
338
         r.setProjectName("共富项目");
338
         r.setProjectName("共富项目");
339
         r.setProjectType(1);
339
         r.setProjectType(1);
340
         r.setIntroduction("简介");
340
         r.setIntroduction("简介");
341
-        r.setProjectContent("项目内容描述");
342
-        Calendar cal = Calendar.getInstance();
343
-        cal.set(2026, Calendar.JANUARY, 1, 0, 0, 0);
344
-        cal.set(Calendar.MILLISECOND, 0);
345
-        r.setImplStartDate(cal.getTime());
346
-        Calendar end = Calendar.getInstance();
347
-        end.set(2026, Calendar.DECEMBER, 31, 0, 0, 0);
348
-        end.set(Calendar.MILLISECOND, 0);
349
-        r.setImplEndDate(end.getTime());
341
+        r.setProjectContent("建设规模及内容描述");
342
+        r.setInvestmentAmount(new java.math.BigDecimal("100"));
343
+        r.setImplYear(Calendar.getInstance().get(Calendar.YEAR));
344
+        r.setImplStatus("实施中");
350
         r.setPublishStatus(0);
345
         r.setPublishStatus(0);
351
         r.setOperationImages(Collections.singletonList(sampleImage(1)));
346
         r.setOperationImages(Collections.singletonList(sampleImage(1)));
352
         return r;
347
         return r;

+ 1 - 8
baqing-admin/src/test/java/com/ruoyi/web/modules/prosperity/service/impl/BizCommonProsperityProjectServiceImplTest.java

@@ -182,14 +182,7 @@ class BizCommonProsperityProjectServiceImplTest
182
         r.setProjectType(1);
182
         r.setProjectType(1);
183
         r.setIntroduction("简介");
183
         r.setIntroduction("简介");
184
         r.setProjectContent("内容");
184
         r.setProjectContent("内容");
185
-        Calendar cal = Calendar.getInstance();
186
-        cal.set(2026, Calendar.JANUARY, 1, 0, 0, 0);
187
-        cal.set(Calendar.MILLISECOND, 0);
188
-        r.setImplStartDate(cal.getTime());
189
-        Calendar end = Calendar.getInstance();
190
-        end.set(2026, Calendar.DECEMBER, 31, 0, 0, 0);
191
-        end.set(Calendar.MILLISECOND, 0);
192
-        r.setImplEndDate(end.getTime());
185
+        r.setImplYear(Calendar.getInstance().get(Calendar.YEAR));
193
         r.setOperationImages(Collections.singletonList(sampleImage(1)));
186
         r.setOperationImages(Collections.singletonList(sampleImage(1)));
194
         return r;
187
         return r;
195
     }
188
     }

+ 21 - 20
baqing-admin/src/test/java/com/ruoyi/web/modules/prosperity/support/CommonProsperityProjectValidationTest.java

@@ -3,6 +3,7 @@ package com.ruoyi.web.modules.prosperity.support;
3
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
3
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
4
 import static org.junit.jupiter.api.Assertions.assertThrows;
4
 import static org.junit.jupiter.api.Assertions.assertThrows;
5
 
5
 
6
+import java.math.BigDecimal;
6
 import java.util.ArrayList;
7
 import java.util.ArrayList;
7
 import java.util.Arrays;
8
 import java.util.Arrays;
8
 import java.util.Calendar;
9
 import java.util.Calendar;
@@ -12,7 +13,6 @@ import org.junit.jupiter.api.DisplayName;
12
 import org.junit.jupiter.api.Test;
13
 import org.junit.jupiter.api.Test;
13
 import com.ruoyi.common.constant.Constants;
14
 import com.ruoyi.common.constant.Constants;
14
 import com.ruoyi.common.exception.ServiceException;
15
 import com.ruoyi.common.exception.ServiceException;
15
-import com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProject;
16
 import com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProjectOpImage;
16
 import com.ruoyi.web.modules.prosperity.domain.BizCommonProsperityProjectOpImage;
17
 
17
 
18
 /**
18
 /**
@@ -44,10 +44,11 @@ class CommonProsperityProjectValidationTest
44
     }
44
     }
45
 
45
 
46
     @Test
46
     @Test
47
-    @DisplayName("GTFY-XM-UT-007 简介/内容字数")
47
+    @DisplayName("GTFY-XM-UT-007 简介选填/内容字数")
48
     void ut007_introContent()
48
     void ut007_introContent()
49
     {
49
     {
50
-        assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateIntroduction(""));
50
+        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateIntroduction(null));
51
+        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateIntroduction(""));
51
         assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateIntroduction(longStr(51)));
52
         assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateIntroduction(longStr(51)));
52
         assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateProjectContent(""));
53
         assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateProjectContent(""));
53
         assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateProjectContent(longStr(501)));
54
         assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateProjectContent(longStr(501)));
@@ -56,24 +57,24 @@ class CommonProsperityProjectValidationTest
56
     }
57
     }
57
 
58
 
58
     @Test
59
     @Test
59
-    @DisplayName("GTFY-XM-UT-008 实施日期区间")
60
-    void ut008_implDateRange()
60
+    @DisplayName("GTFY-XM-UT-008 实施年限")
61
+    void ut008_implYear()
61
     {
62
     {
62
-        Calendar start = Calendar.getInstance();
63
-        start.set(2026, Calendar.JANUARY, 10, 0, 0, 0);
64
-        start.set(Calendar.MILLISECOND, 0);
65
-        Calendar endBefore = Calendar.getInstance();
66
-        endBefore.set(2026, Calendar.JANUARY, 9, 0, 0, 0);
67
-        endBefore.set(Calendar.MILLISECOND, 0);
68
-        assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateImplDateRange(
69
-                start.getTime(), endBefore.getTime()));
70
-        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateImplDateRange(
71
-                start.getTime(), start.getTime()));
72
-        Calendar endAfter = Calendar.getInstance();
73
-        endAfter.set(2026, Calendar.JANUARY, 15, 0, 0, 0);
74
-        endAfter.set(Calendar.MILLISECOND, 0);
75
-        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateImplDateRange(
76
-                start.getTime(), endAfter.getTime()));
63
+        int current = Calendar.getInstance().get(Calendar.YEAR);
64
+        assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateImplYear(null));
65
+        assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateImplYear(1999));
66
+        assertThrows(ServiceException.class, () -> CommonProsperityProjectValidation.validateImplYear(current + 1));
67
+        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateImplYear(current));
68
+    }
69
+
70
+    @Test
71
+    @DisplayName("GTFY-XM-UT-008b 投资金额")
72
+    void ut008b_investment()
73
+    {
74
+        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateInvestmentAmount(null));
75
+        assertDoesNotThrow(() -> CommonProsperityProjectValidation.validateInvestmentAmount(BigDecimal.ZERO));
76
+        assertThrows(ServiceException.class,
77
+                () -> CommonProsperityProjectValidation.validateInvestmentAmount(new BigDecimal("-1")));
77
     }
78
     }
78
 
79
 
79
     @Test
80
     @Test

+ 3 - 2
baqing-admin/src/test/java/com/ruoyi/web/modules/screen/controller/CommonProsperityScreenControllerApiTest.java

@@ -142,7 +142,7 @@ class CommonProsperityScreenControllerApiTest
142
     {
142
     {
143
         when(commonProsperityScreenService.loadDashboard("2026")).thenReturn(sampleDashboard(true, true));
143
         when(commonProsperityScreenService.loadDashboard("2026")).thenReturn(sampleDashboard(true, true));
144
         mockMvc.perform(get("/bigScreen/commonProsperity/dashboard").param("statYear", "2026"))
144
         mockMvc.perform(get("/bigScreen/commonProsperity/dashboard").param("statYear", "2026"))
145
-                .andExpect(jsonPath("$.data.projectTypeStats[0].projectTypeName").value("共富项目"))
145
+                .andExpect(jsonPath("$.data.projectTypeStats[0].projectTypeName").value("和美乡村建设项目"))
146
                 .andExpect(jsonPath("$.data.projectTypeStats[0].ratio").exists());
146
                 .andExpect(jsonPath("$.data.projectTypeStats[0].ratio").exists());
147
     }
147
     }
148
 
148
 
@@ -154,7 +154,8 @@ class CommonProsperityScreenControllerApiTest
154
         item.setId(1L);
154
         item.setId(1L);
155
         item.setProjectName("示范");
155
         item.setProjectName("示范");
156
         item.setProjectType(1);
156
         item.setProjectType(1);
157
-        item.setProjectTypeName("共富项目");
157
+        item.setProjectTypeName("和美乡村建设项目");
158
+        item.setImplYear(2026);
158
         when(commonProsperityScreenService.listPublishedProjects("2026")).thenReturn(Collections.singletonList(item));
159
         when(commonProsperityScreenService.listPublishedProjects("2026")).thenReturn(Collections.singletonList(item));
159
         mockMvc.perform(get("/bigScreen/commonProsperity/projects").param("statYear", "2026"))
160
         mockMvc.perform(get("/bigScreen/commonProsperity/projects").param("statYear", "2026"))
160
                 .andExpect(status().isOk())
161
                 .andExpect(status().isOk())

+ 11 - 32
baqing-admin/src/test/java/com/ruoyi/web/modules/screen/support/CommonProsperityScreenSupportTest.java

@@ -8,7 +8,6 @@ import java.math.BigDecimal;
8
 import java.util.Arrays;
8
 import java.util.Arrays;
9
 import java.util.Calendar;
9
 import java.util.Calendar;
10
 import java.util.Collections;
10
 import java.util.Collections;
11
-import java.util.Date;
12
 import java.util.List;
11
 import java.util.List;
13
 import java.util.Map;
12
 import java.util.Map;
14
 import org.junit.jupiter.api.DisplayName;
13
 import org.junit.jupiter.api.DisplayName;
@@ -25,31 +24,21 @@ class CommonProsperityScreenSupportTest
25
 {
24
 {
26
 
25
 
27
     @Test
26
     @Test
28
-    @DisplayName("DP-GTFY-UT-006 实施周期与统计年交集")
29
-    void ut006_intersectsStatYear()
27
+    @DisplayName("DP-GTFY-UT-006 实施年限等于统计年")
28
+    void ut006_matchesStatYear()
30
     {
29
     {
31
-        assertTrue(CommonProsperityScreenSupport.intersectsStatYear(published(2025, 1, 1, 2027, 12, 31), 2026));
32
-        assertFalse(CommonProsperityScreenSupport.intersectsStatYear(published(2024, 1, 1, 2024, 12, 31), 2026));
33
-        assertTrue(CommonProsperityScreenSupport.intersectsStatYear(published(2026, 1, 1, 2026, 12, 31), 2026));
30
+        assertTrue(CommonProsperityScreenSupport.matchesStatYear(published(2026), 2026));
31
+        assertFalse(CommonProsperityScreenSupport.matchesStatYear(published(2024), 2026));
32
+        assertTrue(CommonProsperityScreenSupport.intersectsStatYear(published(2026), 2026));
34
     }
33
     }
35
 
34
 
36
     @Test
35
     @Test
37
     @DisplayName("DP-GTFY-UT-007 未发布排除")
36
     @DisplayName("DP-GTFY-UT-007 未发布排除")
38
     void ut007_unpublishedExcluded()
37
     void ut007_unpublishedExcluded()
39
     {
38
     {
40
-        BizCommonProsperityProject p = published(2026, 1, 1, 2026, 12, 31);
39
+        BizCommonProsperityProject p = published(2026);
41
         p.setPublishStatus(0);
40
         p.setPublishStatus(0);
42
-        assertFalse(CommonProsperityScreenSupport.intersectsStatYear(p, 2026));
43
-    }
44
-
45
-    @Test
46
-    @DisplayName("DP-GTFY-UT-008 边界日期含端点")
47
-    void ut008_boundaryDates()
48
-    {
49
-        assertTrue(CommonProsperityScreenSupport.intersectsStatYear(
50
-                published(2026, 12, 31, 2027, 6, 1), 2026));
51
-        assertTrue(CommonProsperityScreenSupport.intersectsStatYear(
52
-                published(2025, 6, 1, 2026, 1, 1), 2026));
41
+        assertFalse(CommonProsperityScreenSupport.matchesStatYear(p, 2026));
53
     }
42
     }
54
 
43
 
55
     @Test
44
     @Test
@@ -57,9 +46,7 @@ class CommonProsperityScreenSupportTest
57
     void ut009_typeStatsRatio()
46
     void ut009_typeStatsRatio()
58
     {
47
     {
59
         List<BizCommonProsperityProject> projects = Arrays.asList(
48
         List<BizCommonProsperityProject> projects = Arrays.asList(
60
-                published(2026, 1, 1, 2026, 12, 31),
61
-                published(2026, 1, 1, 2026, 12, 31),
62
-                published(2026, 1, 1, 2026, 12, 31));
49
+                published(2026), published(2026), published(2026));
63
         projects.get(0).setProjectType(1);
50
         projects.get(0).setProjectType(1);
64
         projects.get(1).setProjectType(1);
51
         projects.get(1).setProjectType(1);
65
         projects.get(2).setProjectType(2);
52
         projects.get(2).setProjectType(2);
@@ -70,6 +57,7 @@ class CommonProsperityScreenSupportTest
70
         assertEquals(1, stats.get(1).getCount().intValue());
57
         assertEquals(1, stats.get(1).getCount().intValue());
71
         BigDecimal sum = stats.stream().map(ProjectTypeStatVo::getRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
58
         BigDecimal sum = stats.stream().map(ProjectTypeStatVo::getRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
72
         assertEquals(0, sum.compareTo(BigDecimal.ONE));
59
         assertEquals(0, sum.compareTo(BigDecimal.ONE));
60
+        assertEquals("和美乡村建设项目", stats.get(0).getProjectTypeName());
73
     }
61
     }
74
 
62
 
75
     @Test
63
     @Test
@@ -114,21 +102,12 @@ class CommonProsperityScreenSupportTest
114
         assertEquals("a", map.get(1L).get(0).getFileUrl());
102
         assertEquals("a", map.get(1L).get(0).getFileUrl());
115
     }
103
     }
116
 
104
 
117
-    private static BizCommonProsperityProject published(int y1, int m1, int d1, int y2, int m2, int d2)
105
+    private static BizCommonProsperityProject published(int implYear)
118
     {
106
     {
119
         BizCommonProsperityProject p = new BizCommonProsperityProject();
107
         BizCommonProsperityProject p = new BizCommonProsperityProject();
120
         p.setPublishStatus(1);
108
         p.setPublishStatus(1);
121
-        p.setImplStartDate(date(y1, m1, d1));
122
-        p.setImplEndDate(date(y2, m2, d2));
109
+        p.setImplYear(implYear);
123
         p.setProjectType(1);
110
         p.setProjectType(1);
124
         return p;
111
         return p;
125
     }
112
     }
126
-
127
-    private static Date date(int y, int m, int d)
128
-    {
129
-        Calendar c = Calendar.getInstance();
130
-        c.clear();
131
-        c.set(y, m - 1, d, 0, 0, 0);
132
-        return c.getTime();
133
-    }
134
 }
113
 }

+ 10 - 87
doc/共同富裕/共同富裕项目/共同富裕项目前端技术方案.md

@@ -1,95 +1,18 @@
1
 # 共同富裕项目 — 前端技术方案
1
 # 共同富裕项目 — 前端技术方案
2
 
2
 
3
-> 依据:`doc/共同富裕/共同富裕项目/共同富裕项目技术方案.md`、`共同富裕项目功能需求.md`;页面布局对齐 `ruoyi-ui/src/views/breedingStandards/breedingManage/index.vue`;请求与表单字段统一 **小驼峰**。
4
-
5
----
6
-
7
-## 1. 页面与路由
8
-
9
-| 项 | 说明 |
10
-| --- | --- |
11
-| **Vue 路径** | `ruoyi-ui/src/views/commonProsperity/project/index.vue` |
12
-| **组件名** | `CommonProsperityProject` |
13
-| **菜单配置** | 若依「菜单管理」组件路径:`commonProsperity/project/index` |
14
-| **权限前缀** | `commonProsperity:project:` |
15
-
16
----
17
-
18
-## 2. API 模块
19
-
20
 | 项 | 说明 |
3
 | 项 | 说明 |
21
 | --- | --- |
4
 | --- | --- |
22
-| **文件** | `ruoyi-ui/src/api/commonProsperity/project.js` |
23
-| **Base Path** | `/commonProsperity/project` |
5
+| 页面 | `ruoyi-ui/src/views/commonProsperity/project/index.vue` |
6
+| API | `ruoyi-ui/src/api/commonProsperity/project.js` |
7
+| i18n | `lang/zh|bo/commonProsperity.js` → `project` |
24
 
8
 
25
-封装方法:`listCommonProsperityProject`、`getCommonProsperityProject`、`addCommonProsperityProject`、`updateCommonProsperityProject`、`delCommonProsperityProject`、`publishCommonProsperityProject`、`offlineCommonProsperityProject`。
26
-
27
----
28
-
29
-## 3. 列表与查询
30
-
31
-- **分页**:`pageNum`、`pageSize`(默认 20)。
32
-- **筛选**:`projectName`(项目名称模糊);`projectType`(1~3 精确,可空);`publishStatus`(0 未发布 / 1 已发布,可空)。
33
-- **表格列**:项目名称、项目类型、简介、实施开始/结束、运营图片数量、封面缩略图、发布状态、发布日期、创建时间、操作列。
34
-
35
----
36
-
37
-## 4. 表单与上传
38
-
39
-| 字段 | 规则 |
40
-| --- | --- |
41
-| `projectName` | 必填,1~20 字 |
42
-| `projectType` | 必填,1 合作共赢 / 2 农文旅融合 / 3 认养农业 |
43
-| `introduction` | 必填,1~50 字 |
44
-| `projectContent` | 必填,1~500 字 |
45
-| 实施日期 `implDateRange` | 必填;`daterange` 选区间,提交拆为 `implStartDate`、`implEndDate` |
46
-| `operationImages` | 必填,1~3 项;元素 `{ fileUrl, filePath, sortOrder }` |
47
-| `videoFileUrl` / `videoFilePath` | 选填;mp4,≤100MB |
48
-| `coverFileUrl` / `coverFilePath` | 选填;jpg/jpeg/png,≤10MB |
9
+## 表单
49
 
10
 
50
-- **上传**:`POST /common/upload`;运营图 `picture-card` 限 3;视频单文件按钮上传;封面 `picture-card` 限 1。
51
-- **编辑态**:仅 `publishStatus === 0` 时可保存与替换附件。
11
+- 必填:名称、类型、建设规模及内容、实施年限、运营图片 1~3
12
+- 选填:简介、投资金额、实施情况、视频、封面
13
+- 新增默认 `implYear = 当前年`
14
+- 年份下拉:`[当前年-5, 当前年]`(**上限为当前年**,不含未来年)
52
 
15
 
53
----
16
+## 筛选 / 列表
54
 
17
 
55
-## 5. 操作按钮与状态机
56
-
57
-| 按钮 | 显示条件 | 权限标识 |
58
-| --- | --- | --- |
59
-| 查看 | 有 query 权限 | `commonProsperity:project:query` |
60
-| 编辑 | 未发布 | `commonProsperity:project:edit` |
61
-| 删除 | 未发布 | `commonProsperity:project:remove` |
62
-| 发布 | 未发布 | `commonProsperity:project:publish` |
63
-| 下架 | 已发布 | `commonProsperity:project:offline` |
64
-
65
-下架后可再次编辑、发布,**无须新建**记录。
66
-
67
----
68
-
69
-## 6. 国际化
70
-
71
-| 项 | 说明 |
72
-| --- | --- |
73
-| **语言包** | `src/lang/zh/commonProsperity.js`、`src/lang/bo/commonProsperity.js`(`common` / `status` / `project`) |
74
-| **注册** | `zh-CN.js`、`bo.js` 中 `import commonProsperity` |
75
-| **Mixin** | `src/mixins/commonProsperityLocaleMixin.js`(`cpT`、`cpCommon`、`publishStatusText`) |
76
-| **组件** | `data.cpNs = 'project'`,页面文案键 `commonProsperity.project.*`,通用键 `commonProsperity.common.*` |
77
-
78
----
79
-
80
-## 7. 联调说明
81
-
82
-1. 确认后端 `CommonProsperityProjectController`(或等价实现)已部署,`VUE_APP_BASE_API` 代理正确。
83
-2. 执行 `sql/biz_common_prosperity_project.sql`(若尚未建表)并配置菜单、按钮权限与技术方案 §4 一致。
84
-3. 列表字段 `opImageCount`、`operationImages` 与后端子表约定一致。
85
-4. App 端「共富项目」列表可复用同一接口并固定 `publishStatus=1`。
86
-
87
----
88
-
89
-## 8. 修订记录
90
-
91
-| 版本 | 说明 |
92
-| --- | --- |
93
-| 1.0 | 初版:双卡片布局;运营图 1~3、视频/封面选填;发布/下架状态矩阵 |
94
-| 1.1 | 国际化独立为 `commonProsperity.js`,不再放入 `policy.js` |
95
-| 1.2 | 实施日期改为 `daterange` 单控件(对齐 `doc/前端设计/前端设计.md` 日期范围规范) |
18
+筛选:名称、类型、实施年限、发布状态。列表展示实施年限(非日期区间)。

+ 26 - 186
doc/共同富裕/共同富裕项目/共同富裕项目功能需求.md

@@ -5,210 +5,50 @@
5
 | 项 | 说明 |
5
 | 项 | 说明 |
6
 | --- | --- |
6
 | --- | --- |
7
 | 模块名称 | 共同富裕项目 |
7
 | 模块名称 | 共同富裕项目 |
8
-| 目标 | 对共富类项目进行录入、查询、维护与发布管理,支撑面向使用方的项目展示与查阅 |
9
-| 关联系统 | 业务后台;移动端「养殖资讯」等渠道可按产品约定展示已发布项目(见 **§8**) |
10
-| 修订依据 | 同目录 `共同富裕项目-草稿.md` |
8
+| 目标 | 对共富类项目进行录入、查询、维护与发布管理 |
9
+| 修订依据 | 交接表 `共同富裕项目.xlsx`(原功能修改);**全量覆盖**旧字段模型 |
11
 
10
 
12
-本文档仅描述**功能需求与业务规则**,不涉及库表结构、接口路径、请求体字段命名及技术栈选型
11
+无需导入/导出
13
 
12
 
14
 ---
13
 ---
15
 
14
 
16
-## 2. 术语与状态
15
+## 2. 项目类型(单选)
17
 
16
 
18
-### 2.1 项目类型(枚举,单选)
17
+1. **和美乡村建设项目**
18
+2. **人居环境整治提升项目**
19
+3. **其他项目投入**
19
 
20
 
20
-- **合作共赢**
21
-- **农文旅融合**
22
-- **认养农业**
23
-
24
-### 2.2 发布状态(互斥,单值)
25
-
26
-| 取值 | 含义概要 |
27
-| --- | --- |
28
-| **未发布** | 新建草稿或已下架回流;对外不可见(与产品「前台 / App 展示」定义一致);在满足矩阵规则下可编辑、可删除、可发布 |
29
-| **已发布** | 对外可见或可检索(与产品定义一致);**不允许修改**;**不允许直接删除**,须先执行 **下架** |
30
-
31
-**下架回流:** 对已发布项目执行「下架」后,发布状态回到 **未发布**,允许再次编辑并在校验通过后 **再次发布**,**无须新建**一条记录。
32
-
33
-### 2.3 实施周期说明
34
-
35
-「实施日期」由 **开始日期**、**结束日期** 两个自然日字段组成,表示项目计划实施的时间区间;校验规则见 **§5.1**。
36
-
37
----
38
-
39
-## 3. 功能范围
40
-
41
-- 共富项目的新增、修改、删除、分页列表查询、详情查看
42
-- 运营图片(多张)、运营视频、封面等附件的上传、替换、展示及删除时的存储联动清理
43
-- 发布、下架及发布状态约束下的操作权限控制
44
-- 按项目名称、项目类型、发布状态等条件的组合查询
45
-- 面向使用方的业务错误与校验提示(见第 **7** 章)
46
-
47
----
48
-
49
-## 4. 业务流程概览
50
-
51
-下列顺序描述**典型闭环**;具体操作禁忌以 **第 6 节矩阵** 为准。
52
-
53
-1. **新建**:录入必填项,上传运营图片及可选的视频、封面 → 初始为 **未发布**。
54
-2. **维护**:在 **未发布** 下可反复修改字段与附件,直至内容定稿。
55
-3. **发布**:在 **未发布** 且满足发布前置校验时执行「发布」→ **已发布**。
56
-4. **对外展示**:**已发布** 项目按产品约定在后台列表、移动端「共富项目」等渠道展示;后台详情为只读维护视角。
57
-5. **下架**:在 **已发布** 下执行「下架」→ 回到 **未发布**,结束对外展示。
58
-6. **再编辑 / 再发布**:下架后可修改并再次发布(重复步骤 2~3)。
59
-7. **删除**:仅在 **未发布** 下允许删除整条记录及关联附件;**已发布** 须先下架。
60
-
61
-```mermaid
62
-stateDiagram-v2
63
-    [*] --> 未发布: 新建
64
-    未发布 --> 已发布: 发布
65
-    已发布 --> 未发布: 下架
66
-    未发布 --> [*]: 删除
67
-```
21
+发布状态:**未发布 / 已发布**(已发布不可改、不可删,须先下架)。
68
 
22
 
69
 ---
23
 ---
70
 
24
 
71
-## 5. 详细功能需求
72
-
73
-### 5.1 新增共富项目
25
+## 3. 字段
74
 
26
 
75
 | 字段 | 规则 |
27
 | 字段 | 规则 |
76
 | --- | --- |
28
 | --- | --- |
77
-| 项目名称 | **必填**;长度 **1~20** 个字符(字符计数规则与项目全局一致) |
78
-| 项目类型 | **必填**;单选,取值限定为第 **2.1** 节 |
79
-| 项目简介 | **必填**;长度 **1~50** 个字符 |
80
-| 项目内容 | **必填**;长度 **1~500** 个字符 |
81
-| 实施开始日期 | **必填**;格式 **YYYY-MM-DD** |
82
-| 实施结束日期 | **必填**;格式 **YYYY-MM-DD**;须 **≥ 实施开始日期** |
83
-| 运营图片 | **必填**;**1~3 张**图片;每张通过独立上传;允许后缀:`jpg`、`jpeg`、`png`(若产品要求支持 `webp` 等可追加);单张 ≤ **10 MB** |
84
-| 运营视频 | **选填**;**单个**视频上传;允许后缀:`mp4`(若产品要求支持 `mov`、`webm` 等可追加);单文件大小上限与项目视频上传规范一致(未单独约定时建议 ≤ **100 MB**,须在实现前与产品确认) |
85
-| 封面 | **选填**;**单个**图片上传;允许后缀:`jpg`、`jpeg`、`png`;单文件 ≤ **10 MB** |
86
-
87
-**必填字段汇总:** 项目名称、项目类型、项目简介、项目内容、实施开始日期、实施结束日期、运营图片(至少 1 张、最多 3 张)。
88
-
89
-**校验:**
90
-
91
-- 实施结束日期早于开始日期时,须拒绝保存并提示(如「结束日期不能早于开始日期」)。
92
-- 运营图片数量少于 1 张或多于 3 张时,须拒绝保存并提示。
93
-- 须校验附件类型(后缀与白名单 / 项目安全规范一致)与大小;超限或格式不符时给出**可区分**的错误提示。
94
-- 若业务要求项目名称在适用范围(如租户 / 组织)内唯一,应在评审时单独约定并写入本节。
95
-
96
-**初始状态:** 新建成功后,发布状态为 **未发布**。
97
-
98
----
99
-
100
-### 5.2 查询共富项目列表
101
-
102
-- **项目名称:** 对「项目名称」进行**模糊**匹配;名称为空时不按名称过滤。
103
-- **项目类型:** **精确**匹配筛选;未选择时不按类型过滤。
104
-- **发布状态(建议):** 列表宜支持按 **未发布 / 已发布** 筛选,便于运营人员区分待发布与已上线内容。
105
-- **分页:** 支持分页;默认 **每页 20 条**,默认首页为第一页;单页条数上限与项目列表通用规范一致(若有)。
106
-- **排序:** 默认按 **创建时间倒序**(最新在前);次要排序键与项目列表规范一致(若有)。
107
-
108
-**列表宜展示:** 项目名称、项目类型、项目简介(可截断)、实施开始/结束日期、发布状态、封面缩略图(若有)、运营图片数量提示,以及当前状态下可执行的操作入口。
109
-
110
----
111
-
112
-### 5.3 修改共富项目
113
-
114
-- **状态约束:** **仅未发布**(含新建后未发布、**已从已发布下架回流**)允许修改。**已发布**状态下**不允许修改**(列表 / 详情不提供可提交的编辑入口,或仅为只读;任何保存类修改须被拒绝并给出明确业务原因,如「已发布项目请先下架后再编辑」)。
115
-- **可修改项:** 项目名称、项目类型、项目简介、项目内容、实施开始日期、实施结束日期、运营图片、运营视频、封面。
116
-- **保存约束:** **§5.1** 中全部必填规则在修改时仍须满足;运营图片仍须保持 **1~3 张**;日期区间、附件格式与大小规则与新增一致。
117
-- **附件替换:**
118
-  - 替换、增删运营图片或更换封面、运营视频时,保存成功后须清理被移除的旧文件,避免存储残留。
119
-  - 若用户将运营图片删至 0 张再提交,须按校验拒绝。
120
-
121
----
122
-
123
-### 5.4 删除共富项目
124
-
125
-- **允许删除:** 发布状态为 **未发布** 的记录。
126
-- **不允许删除:** 发布状态为 **已发布** 的记录;须先执行「下架」(见 **5.6**)回到 **未发布** 后再删除。
127
-- **删除后果:** 删除本条业务记录时,须**同步删除**关联存储中的全部运营图片、运营视频(若有)、封面(若有),避免存储残留。
128
-- **确认:** 删除前宜弹出确认提示,避免误删。
129
-
130
----
131
-
132
-### 5.5 查看共富项目详情
133
-
134
-- **展示内容:** 项目名称、项目类型、项目简介、项目内容、实施开始日期、实施结束日期、运营图片(可预览)、运营视频(若有,可播放或下载入口)、封面(若有)、当前 **发布状态**;宜展示创建人、创建时间、发布时间、下架时间、最后修改人、最后修改时间(若系统有审计字段)。
135
-- **权限与交互:**
136
-  - **未发布:** 具备权限的用户可进入编辑流程(见 **5.3**);可提供「发布」入口。
137
-  - **已发布:** 详情为 **只读**(无保存类编辑);可提供「下架」操作入口。
138
-- **在线预览:** 运营图片、封面、运营视频的在线预览能力按项目通用附件组件约定;若 App 端仅展示已发布数据,须与后台发布状态联动。
139
-
140
----
141
-
142
-### 5.6 发布与下架
143
-
144
-#### 发布
145
-
146
-- **前置条件:**
147
-  - 当前发布状态为 **未发布**;
148
-  - 必填字段均已满足 **5.1** 规则(含项目名称、项目类型、项目简介、项目内容、实施日期区间、至少 1 张且至多 3 张运营图片)。
149
-- **操作结果:** 发布状态变为 **已发布**;记录发布时间;内容按产品约定对外可见(如移动端「共富项目」栏目可展示)。
150
-- **失败处理:** 校验不通过时须给出明确原因(如必填项缺失、图片数量不符、日期非法等),不变更发布状态。
151
-
152
-#### 下架
153
-
154
-- **前置条件:** 当前发布状态为 **已发布**。
155
-- **操作结果:**
156
-  - 发布状态变为 **未发布**;
157
-  - 对外展示 / 检索可见性结束(与产品「前台 / App 是否展示」定义一致);
158
-  - 记录下架时间(若系统支持);
159
-  - 允许用户再次修改(**5.3**)并在满足条件后 **再次发布**,**无须新建**记录。
160
-- **说明:** 下架**不删除**业务记录与已上传附件,仅变更发布状态与对外可见性。
161
-
162
----
163
-
164
-## 6. 状态与操作矩阵(汇总)
165
-
166
-便于评审与测试用例编写。
167
-
168
-| 当前发布状态 | 查看 | 修改 | 发布 | 下架 | 删除 |
169
-| --- | --- | --- | --- | --- | --- |
170
-| 未发布 | ✓ | ✓ | ✓ | — | ✓ |
171
-| 已发布 | ✓ | ✗ | — | ✓ | ✗ |
172
-
173
-**补充:** 从「已发布」下架后,记录回到 **未发布**,操作权限按上表第一行执行。
29
+| 项目名称 | 必填;1~20 字 |
30
+| 项目类型 | 必填;上表三类 |
31
+| 项目简介 | **选填**;≤50 字 |
32
+| 建设规模及内容 | 必填;1~500 字(原「项目内容」更名) |
33
+| 投资金额 | 选填;万元;≥0 |
34
+| 实施年限 | 必填;自然年;**新增默认本年**;可选范围上限为**当前年**(不可选未来年) |
35
+| 实施情况 | 选填;≤500 字 |
36
+| 运营图片 | 必填;1~3 张;jpg/jpeg/png |
37
+| 运营视频 | 选填;mp4 |
38
+| 封面 | 选填;jpg/jpeg/png |
174
 
39
 
175
 ---
40
 ---
176
 
41
 
177
-## 7. 错误与提示约定
42
+## 4. 列表与筛选
178
 
43
 
179
-- 业务与校验错误宜采用项目统一的 **`code`、`msg`、`data`** 结构呈现,便于前端统一处理(不涉及具体协议与路径设计)。
180
-- 常见提示宜可区分,例如:
181
-  - 必填项缺失、字段超长、实施日期区间不合法;
182
-  - 运营图片数量不足或超出上限;
183
-  - 图片 / 视频 / 封面格式不支持、文件大小超限、上传失败;
184
-  - 已发布不可编辑、已发布不可删除须先下架;
185
-  - 发布 / 下架操作失败原因。
186
-
187
----
188
-
189
-## 8. 非功能需求(建议)
190
-
191
-| 类别 | 建议 |
192
-| --- | --- |
193
-| 权限 | 菜单与按钮级权限:新增、编辑、删除、发布、下架、查看等是否分角色 |
194
-| 审计 | 关键操作记操作日志(新增、修改、发布、下架、删除) |
195
-| 安全 | 上传文件类型校验、存储路径不可预测;视频与图片下载 / 预览鉴权 |
196
-| 性能 | 列表查询响应时间满足后台通用体验;多图与视频若后续需直传或分片再扩展 |
197
-| 多端展示 | 与 `ruoyi-ui-app` 等端「共富项目」栏目联动时,仅拉取 **已发布** 数据;下架后前台不再展示 |
198
-| 双语 | 若前台面向藏汉双语用户,展示文案与后台字段标签须与项目 i18n 规范一致(具体范围在 UI 设计阶段确认) |
44
+- **筛选**:项目名称(模糊)、项目类型、实施年限、发布状态
45
+- **列表列**:项目名称、类型、简介、实施年限、运营图片数、封面、发布状态、发布日期、创建时间
199
 
46
 
200
 ---
47
 ---
201
 
48
 
202
-## 9. 修订说明(相对草稿)
49
+## 5. 修订记录
203
 
50
 
204
-| 草稿问题 | 优化处理 |
51
+| 版本 | 说明 |
205
 | --- | --- |
52
 | --- | --- |
206
-| 第 6 条「已发布的**补贴**」 | 更正为 **已发布的共富项目** |
207
-| 发布 / 下架与改删规则分散 | 增补 **§4 流程概览**、**§5.6 发布与下架**、**§6 操作矩阵**;明确已发布不可改、不可删 |
208
-| 「修改:所有均可修改」与发布状态矛盾 | 明确 **仅未发布可改**;已发布须先下架 |
209
-| 运营视频、封面是否必填未写清 | **运营图片必填(1~3 张)**;**运营视频、封面选填** |
210
-| 项目名称仅写「不超过 20 字」 | 明确为 **1~20** 字符;简介、内容为 **1~50 / 1~500** |
211
-| 实施日期未写先后关系 | 补充结束日期 **≥** 开始日期 |
212
-| 查询条件较简略 | 补充发布状态筛选、默认排序、列表展示建议 |
213
-| 删除 / 替换附件未写清理策略 | 在 **§5.3、§5.4** 明确须联动清理存储文件 |
214
-| 第 7、8 条接口与技术栈 | 错误结构仅保留 **§7** 呈现约定;技术栈移至技术方案文档 |
53
+| 2.1 | 实施年限可选上限改为当前年(不可选未来年) |
54
+| 2.0 | 全量覆盖:类型枚举更换;简介改选填;实施起止日→实施年限;新增投资金额、实施情况 |

+ 20 - 225
doc/共同富裕/共同富裕项目/共同富裕项目技术方案.md

@@ -1,239 +1,34 @@
1
 # 共同富裕项目 — 技术方案
1
 # 共同富裕项目 — 技术方案
2
 
2
 
3
-> 依据:同目录 `共同富裕项目功能需求.md`。本模块为共富项目 CRUD + **发布/下架** + **运营图片(1~3 张)**;运营视频、封面选填。
3
+## 1. 表结构
4
 
4
 
5
----
5
+见 `sql/biz_common_prosperity_project.sql`(**DROP 后重建**,全量覆盖)。
6
 
6
 
7
-## 1. 技术架构
7
+主表关键列:
8
 
8
 
9
-|  | 说明 |
9
+|  | 说明 |
10
 | --- | --- |
10
 | --- | --- |
11
-| **后端** | RuoYi **v3.9.2**(**springboot2** 分支):JDK 8、Spring Boot 2.x、Spring MVC、MyBatis、Druid |
12
-| **数据库** | MySQL **5.7.39**,InnoDB,`utf8mb4` |
13
-| **前端** | 若依 Vue2;图片/视频/封面上传复用 `POST /common/upload` |
14
-| **代码包** | `com.ruoyi.web.modules.commonprosperity`(建议) |
11
+| `project_type` | 1 和美乡村建设 / 2 人居环境整治提升 / 3 其他项目投入 |
12
+| `introduction` | 选填 |
13
+| `project_content` | 建设规模及内容 |
14
+| `investment_amount` | 投资金额(万元) |
15
+| `impl_year` | 实施年限(校验:≥2000 且 ≤当前年) |
16
+| `impl_status` | 实施情况 |
15
 
17
 
16
-**分层**:`Controller`(校验、权限、`AjaxResult` / `TableDataInfo`)→ `Service`(发布状态机、运营图子表维护、删物理文件)→ `Mapper`/XML → `domain`。
18
+运营图片子表不变:`biz_common_prosperity_project_op_image`。
17
 
19
 
18
-**发布状态(摘要)**
20
+## 2. 接口
19
 
21
 
20
-| 操作 | 前置 `publish_status` | 结果 |
21
-| --- | --- | --- |
22
-| 新增 / 修改 / 删除 / 发布 | `0`(未发布) | 发布 → `1`,写 `publish_time`;删除 → 删主表 + 子表 + 物理文件 |
23
-| 下架 | `1`(已发布) | `0`,写 `offline_time`;**不删**附件 |
24
-| 修改 / 删除 / 发布 | `1` | **拒绝** |
22
+Base:`/commonProsperity/project`(CRUD + publish/offline 不变)。
25
 
23
 
26
-**附件**:表内存 URL + 存储路径(`file_path`);**不入库**文件大小。运营图片用**子表**(1~3 条),封面与运营视频存**主表**
24
+列表筛选增加 `implYear`。
27
 
25
 
28
----
26
+## 3. 大屏
29
 
27
 
30
-## 2. 数据库设计
28
+- 筛选:`publish_status=1 AND impl_year=#{statYear}`
29
+- 类型名称与后台枚举一致
30
+- 列表项字段:`implYear`(不再返回起止日期)
31
 
31
 
32
-### 2.1 主表 `biz_common_prosperity_project`
32
+## 4. 主要类
33
 
33
 
34
-| 字段 | 类型 | 非空 | 默认值 | 说明 |
35
-| --- | --- | --- | --- | --- |
36
-| `id` | `bigint(20)` | Y | 自增 | 主键 |
37
-| `project_name` | `varchar(64)` | Y | — | 项目名称(**1~20** 字) |
38
-| `project_type` | `tinyint(4)` | Y | — | `1` 合作共赢,`2` 农文旅融合,`3` 认养农业 |
39
-| `introduction` | `varchar(200)` | Y | — | 项目简介(**1~50** 字) |
40
-| `project_content` | `varchar(600)` | Y | — | 项目内容(**1~500** 字) |
41
-| `impl_start_date` | `date` | Y | — | 实施开始日期 |
42
-| `impl_end_date` | `date` | Y | — | 实施结束日期(≥ 开始日) |
43
-| `video_file_url` | `varchar(512)` | N | NULL | 运营视频 URL,选填 |
44
-| `video_file_path` | `varchar(512)` | N | NULL | 运营视频存储路径,选填 |
45
-| `cover_file_url` | `varchar(512)` | N | NULL | 封面 URL,选填 |
46
-| `cover_file_path` | `varchar(512)` | N | NULL | 封面存储路径,选填 |
47
-| `publish_status` | `tinyint(4)` | Y | `0` | `0` 未发布,`1` 已发布 |
48
-| `publish_time` | `datetime` | N | NULL | 发布时间 |
49
-| `offline_time` | `datetime` | N | NULL | 下架时间 |
50
-| `create_by` / `create_time` / `update_by` / `update_time` | 若依惯例 | — | — | 审计 |
51
-| `remark` | `varchar(500)` | N | NULL | 备注 |
52
-
53
-**索引**:`PRIMARY KEY (id)`;`KEY idx_create_time (create_time)`;`KEY idx_project_type (project_type)`;`KEY idx_publish (publish_status)`;`KEY idx_impl_start (impl_start_date)`。
54
-
55
-### 2.2 子表 `biz_common_prosperity_project_op_image`(运营图片)
56
-
57
-| 字段 | 类型 | 非空 | 默认值 | 说明 |
58
-| --- | --- | --- | --- | --- |
59
-| `id` | `bigint(20)` | Y | 自增 | 主键 |
60
-| `project_id` | `bigint(20)` | Y | — | 关联主表 `id` |
61
-| `file_url` | `varchar(512)` | Y | — | 图片访问 URL |
62
-| `file_path` | `varchar(512)` | Y | — | 图片存储路径 |
63
-| `sort_order` | `tinyint(4)` | Y | `1` | 排序 `1`~`3`(展示顺序) |
64
-| `create_time` | `datetime` | N | NULL | 创建时间 |
65
-
66
-**索引**:`PRIMARY KEY (id)`;`KEY idx_project_id (project_id)`。
67
-
68
-**约束(Service 层)**:每个 `project_id` 对应 **1~3** 条记录;`sort_order` 在同一项目内不重复。
69
-
70
-### 2.3 DDL(MySQL 5.7)
71
-
72
-```sql
73
-CREATE TABLE `biz_common_prosperity_project` (
74
-  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
75
-  `project_name` varchar(64) NOT NULL COMMENT '项目名称',
76
-  `project_type` tinyint(4) NOT NULL COMMENT '1合作共赢 2农文旅融合 3认养农业',
77
-  `introduction` varchar(200) NOT NULL COMMENT '项目简介',
78
-  `project_content` varchar(600) NOT NULL COMMENT '项目内容',
79
-  `impl_start_date` date NOT NULL COMMENT '实施开始日期',
80
-  `impl_end_date` date NOT NULL COMMENT '实施结束日期',
81
-  `video_file_url` varchar(512) DEFAULT NULL COMMENT '运营视频URL',
82
-  `video_file_path` varchar(512) DEFAULT NULL COMMENT '运营视频存储路径',
83
-  `cover_file_url` varchar(512) DEFAULT NULL COMMENT '封面URL',
84
-  `cover_file_path` varchar(512) DEFAULT NULL COMMENT '封面存储路径',
85
-  `publish_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0未发布 1已发布',
86
-  `publish_time` datetime DEFAULT NULL COMMENT '发布时间',
87
-  `offline_time` datetime DEFAULT NULL COMMENT '下架时间',
88
-  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
89
-  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
90
-  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
91
-  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
92
-  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
93
-  PRIMARY KEY (`id`),
94
-  KEY `idx_create_time` (`create_time`),
95
-  KEY `idx_project_type` (`project_type`),
96
-  KEY `idx_publish` (`publish_status`),
97
-  KEY `idx_impl_start` (`impl_start_date`)
98
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共同富裕项目';
99
-
100
-CREATE TABLE `biz_common_prosperity_project_op_image` (
101
-  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
102
-  `project_id` bigint(20) NOT NULL COMMENT '项目ID',
103
-  `file_url` varchar(512) NOT NULL COMMENT '图片URL',
104
-  `file_path` varchar(512) NOT NULL COMMENT '图片存储路径',
105
-  `sort_order` tinyint(4) NOT NULL DEFAULT '1' COMMENT '排序1-3',
106
-  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
107
-  PRIMARY KEY (`id`),
108
-  KEY `idx_project_id` (`project_id`)
109
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共同富裕项目-运营图片';
110
-```
111
-
112
-### 2.4 枚举常量
113
-
114
-| 字段 | 值 | 含义 |
115
-| --- | --- | --- |
116
-| `project_type` | `1` | 合作共赢 |
117
-| | `2` | 农文旅融合 |
118
-| | `3` | 认养农业 |
119
-| `publish_status` | `0` | 未发布 |
120
-| | `1` | 已发布 |
121
-
122
----
123
-
124
-## 3. 接口设计
125
-
126
-**统一响应**:`AjaxResult`(`code` / `msg` / `data`)或分页 `TableDataInfo`(`rows`、`total`)。
127
-
128
-**权限标识(示例)**:`commonProsperity:project:list|query|add|edit|remove|publish|offline`
129
-
130
-**Base Path(示例)**:`/commonProsperity/project`
131
-
132
-| # | 说明 | Method | URI | 权限 | 要点 |
133
-| --- | --- | --- | --- | --- | --- |
134
-| 3.1 | 分页列表 | GET | `/commonProsperity/project/list` | `commonProsperity:project:list` | Query **3.1.1**;排序 `create_time DESC, id DESC`;`rows` 含 `opImageCount`(子表 count) |
135
-| 3.2 | 详情 | GET | `/commonProsperity/project/{id}` | `commonProsperity:project:query` | 主表全字段 + `operationImages[]`(按 `sort_order` 升序) |
136
-| 3.3 | 新增 | POST | `/commonProsperity/project` | `commonProsperity:project:add` | Body **3.3.1**;事务写主表 + 子表;`publish_status=0` |
137
-| 3.4 | 修改 | PUT | `/commonProsperity/project` | `commonProsperity:project:edit` | **仅** `publish_status=0`;全量替换子表;删被移除图片及旧视频/封面物理文件 |
138
-| 3.5 | 删除 | DELETE | `/commonProsperity/project/{ids}` | `commonProsperity:project:remove` | **仅** `publish_status=0`;删主表、子表及全部关联物理文件 |
139
-| 3.6 | 发布 | POST | `/commonProsperity/project/publish/{id}` | `commonProsperity:project:publish` | 前置 `0`;校验必填与子表 1~3 张;`publish_status=1`,`publish_time=now()` |
140
-| 3.7 | 下架 | POST | `/commonProsperity/project/offline/{id}` | `commonProsperity:project:offline` | 前置 `1`;`publish_status=0`,`offline_time=now()` |
141
-
142
-#### 3.1.1 列表 Query
143
-
144
-| 参数 | 类型 | 必填 | 说明 |
145
-| --- | --- | --- | --- |
146
-| `pageNum` / `pageSize` | int | N | 默认 `1` / `20` |
147
-| `projectName` | string | N | 项目名称**模糊**匹配 |
148
-| `projectType` | int | N | `1`~`3` 精确匹配 |
149
-| `publishStatus` | int | N | `0` / `1` 精确匹配 |
150
-
151
-> **App / 前台**:调用同一列表接口时固定传 `publishStatus=1`,仅展示已发布项目。
152
-
153
-#### 3.3.1 新增 / 修改 Body(JSON,驼峰)
154
-
155
-| 字段 | 必填 | 说明 |
156
-| --- | --- | --- |
157
-| `id` | 修改 Y | 主键 |
158
-| `projectName` | Y | 1~20 字符 |
159
-| `projectType` | Y | `1`~`3` |
160
-| `introduction` | Y | 1~50 字符 |
161
-| `projectContent` | Y | 1~500 字符 |
162
-| `implStartDate` | Y | `yyyy-MM-dd` |
163
-| `implEndDate` | Y | ≥ `implStartDate` |
164
-| `operationImages` | Y | 数组,**1~3** 项;每项见下表 |
165
-| `videoFileUrl` / `videoFilePath` | N | 运营视频;二者同时有或同时无 |
166
-| `coverFileUrl` / `coverFilePath` | N | 封面;二者同时有或同时无 |
167
-| `remark` | N | 备注 |
168
-
169
-**`operationImages[]` 元素**
170
-
171
-| 字段 | 必填 | 说明 |
172
-| --- | --- | --- |
173
-| `fileUrl` | Y | 上传 `/common/upload` 返回的 `url` |
174
-| `filePath` | Y | 上传返回的 `fileName`(存储路径) |
175
-| `sortOrder` | Y | `1`~`3`,同请求内不重复 |
176
-
177
-**列表/详情响应(除 Body 字段外)**
178
-
179
-| 字段 | 说明 |
180
-| --- | --- |
181
-| `publishStatus` / `publishTime` / `offlineTime` | 发布状态与时间 |
182
-| `opImageCount` | 仅列表:运营图片数量 |
183
-| `operationImages` | 仅详情:图片数组 |
184
-| `createBy` / `createTime` / `updateBy` / `updateTime` | 审计字段 |
185
-
186
-### 3.4 服务端校验(摘要)
187
-
188
-| 项 | 规则 |
189
-| --- | --- |
190
-| 项目名称 | 非空,1~20 |
191
-| 项目类型 | ∈ {1,2,3} |
192
-| 项目简介 | 非空,1~50 |
193
-| 项目内容 | 非空,1~500 |
194
-| 实施日期 | `implEndDate` ≥ `implStartDate` |
195
-| 运营图片 | 1~3 张;后缀 `jpg,jpeg,png`;单张 ≤ **10 MB** |
196
-| 运营视频 | 可空;有则后缀 `mp4`(可扩展);≤ **100 MB**(与产品确认) |
197
-| 封面 | 可空;有则 `jpg,jpeg,png`;≤ **10 MB** |
198
-| 状态 | 已发布禁止修改、删除;未发布禁止下架 |
199
-
200
-### 3.5 附件与 Service 流程
201
-
202
-1. 前端 `POST /common/upload` → 取 `url`、`fileName`(作 `filePath`)。  
203
-2. 新增:插主表 → 批量插子表。  
204
-3. 修改:比对旧子表 path、旧视频/封面 path → 事务内更新主表、**删子表再插** → 提交后删差异物理文件。  
205
-4. 删除 / 下架:下架不删文件;删除主记录时删子表并删全部 `file_path` / `video_file_path` / `cover_file_path`。
206
-
207
----
208
-
209
-## 4. 菜单与权限 SQL(示例)
210
-
211
-| 类型 | 名称 | 权限标识 |
212
-| --- | --- | --- |
213
-| 目录 | 共同富裕 | — |
214
-| 菜单 | 共同富裕项目 | `commonProsperity:project:list` |
215
-| 按钮 | 查询 | `commonProsperity:project:query` |
216
-| 按钮 | 新增 | `commonProsperity:project:add` |
217
-| 按钮 | 修改 | `commonProsperity:project:edit` |
218
-| 按钮 | 删除 | `commonProsperity:project:remove` |
219
-| 按钮 | 发布 | `commonProsperity:project:publish` |
220
-| 按钮 | 下架 | `commonProsperity:project:offline` |
221
-
222
-组件路径建议:`commonProsperity/project/index`;API 文件 `ruoyi-ui/src/api/commonProsperity/project.js`。
223
-
224
----
225
-
226
-## 5. 交付清单
227
-
228
-- [ ] `biz_common_prosperity_project`、`biz_common_prosperity_project_op_image` DDL 及菜单权限 SQL(`sql/biz_common_prosperity_project.sql`)
229
-- [ ] `BizCommonProsperityProject` Domain(含 `operationImages` 非表字段)、子表 Mapper、Service、Controller
230
-- [ ] 前端:列表筛选、表单多图上传(限 3)、视频/封面、发布/下架与状态矩阵
231
-- [ ] 用例:运营图 1~3 校验、发布/下架、已发布不可改删、改图删旧文件、App 仅 `publishStatus=1`
232
-
233
----
234
-
235
-## 6. 修订记录
236
-
237
-| 版本 | 说明 |
238
-| --- | --- |
239
-| 1.0 | 初稿:对齐功能需求;主表 + 运营图片子表;发布/下架与产业政策宣传一致 |
34
+`BizCommonProsperityProject*`、`CommonProsperityProjectValidation/Rules`、`CommonProsperityScreenSupport`

Diff nebyl zobrazen, protože je příliš veliký
+ 17 - 170
doc/共同富裕/共同富裕项目/共同富裕项目管理测试用例.md


+ 9 - 7
doc/大屏/共同富裕/大屏共同富裕技术方案.md

@@ -54,12 +54,12 @@
54
 | 项 | 条件 |
54
 | 项 | 条件 |
55
 | --- | --- |
55
 | --- | --- |
56
 | 发布状态 | `publish_status = 1` |
56
 | 发布状态 | `publish_status = 1` |
57
-| 实施周期与 **Y** 有交集 | `impl_start_date <= CONCAT(#{statYear}, '-12-31')` AND `impl_end_date >= CONCAT(#{statYear}, '-01-01')` |
58
-| 列表默认排序 | `publish_time DESC, id DESC`(与功能需求 §5.11.1 一致;若产品改按 `impl_start_date` 倒序,仅改 `ORDER BY`) |
57
+| 实施年限等于 **Y** | `impl_year = #{statYear}` |
58
+| 列表默认排序 | `publish_time DESC, id DESC` |
59
 | 分类统计 | 在上述集合上 `GROUP BY project_type`,得各类型 `count`、`ratio`(`ratio = count / total`,`total=0` 时占比均为 0) |
59
 | 分类统计 | 在上述集合上 `GROUP BY project_type`,得各类型 `count`、`ratio`(`ratio = count / total`,`total=0` 时占比均为 0) |
60
 | 运营图 | `biz_common_prosperity_project_op_image` 按 `project_id IN (...)`,`sort_order ASC` |
60
 | 运营图 | `biz_common_prosperity_project_op_image` 按 `project_id IN (...)`,`sort_order ASC` |
61
 
61
 
62
-**`project_type` 枚举**:`1` 合作共赢 → 展示「共富项目」;`2` 农文旅融合;`3` 认养农业
62
+**`project_type` 枚举**:`1` 和美乡村建设项目;`2` 人居环境整治提升项目;`3` 其他项目投入
63
 
63
 
64
 ### 2.3 可选表 `biz_common_prosperity_screen_cache`(性能优化)
64
 ### 2.3 可选表 `biz_common_prosperity_screen_cache`(性能优化)
65
 
65
 
@@ -80,7 +80,7 @@
80
 | 表 | 建议 |
80
 | 表 | 建议 |
81
 | --- | --- |
81
 | --- | --- |
82
 | `biz_common_prosperity_achievement` | 沿用 `uk_stat_period` / `idx_stat_period` |
82
 | `biz_common_prosperity_achievement` | 沿用 `uk_stat_period` / `idx_stat_period` |
83
-| `biz_common_prosperity_project` | 沿用 `idx_publish`、`idx_impl_start`;可选复合 `idx_screen (publish_status, impl_start_date, impl_end_date)` |
83
+| `biz_common_prosperity_project` | 沿用 `idx_publish`、`idx_impl_year` |
84
 
84
 
85
 ### 2.5 Mapper 扩展(建议方法名)
85
 ### 2.5 Mapper 扩展(建议方法名)
86
 
86
 
@@ -154,7 +154,7 @@
154
 | 字段 | 类型 | 说明 |
154
 | 字段 | 类型 | 说明 |
155
 | --- | --- | --- |
155
 | --- | --- | --- |
156
 | `projectType` | int | `1` / `2` / `3` |
156
 | `projectType` | int | `1` / `2` / `3` |
157
-| `projectTypeName` | string | 共富项目 / 农文旅项目 / 认养项目 |
157
+| `projectTypeName` | string | 和美乡村建设项目 / 人居环境整治提升项目 / 其他项目投入 |
158
 | `count` | int | 数量 |
158
 | `count` | int | 数量 |
159
 | `ratio` | decimal | 占比 0~1;`hasProjectData=false` 时三项 `count=0`、`ratio=0` |
159
 | `ratio` | decimal | 占比 0~1;`hasProjectData=false` 时三项 `count=0`、`ratio=0` |
160
 
160
 
@@ -172,7 +172,7 @@
172
     "monthly": [{ "month": 1, "collectiveEconomyIncome": 10.00 }]
172
     "monthly": [{ "month": 1, "collectiveEconomyIncome": 10.00 }]
173
   },
173
   },
174
   "projectTypeStats": [
174
   "projectTypeStats": [
175
-    { "projectType": 1, "projectTypeName": "共富项目", "count": 5, "ratio": 0.50 }
175
+    { "projectType": 1, "projectTypeName": "和美乡村建设项目", "count": 5, "ratio": 0.50 }
176
   ]
176
   ]
177
 }
177
 }
178
 ```
178
 ```
@@ -216,7 +216,9 @@
216
 | `projectName` | string | 项目名称 |
216
 | `projectName` | string | 项目名称 |
217
 | `introduction` | string | 简介 |
217
 | `introduction` | string | 简介 |
218
 | `projectContent` | string | 内容 |
218
 | `projectContent` | string | 内容 |
219
-| `implStartDate` / `implEndDate` | string | `yyyy-MM-dd` |
219
+| `implYear` | int | 实施年限 |
220
+| `investmentAmount` | number | 投资金额(万元),可空 |
221
+| `implStatus` | string | 实施情况,可空 |
220
 | `coverFileUrl` | string | 封面 URL,可空 |
222
 | `coverFileUrl` | string | 封面 URL,可空 |
221
 | `videoFileUrl` | string | 运营视频 URL,可空 |
223
 | `videoFileUrl` | string | 运营视频 URL,可空 |
222
 | `publishTime` | string | 发布时间 |
224
 | `publishTime` | string | 发布时间 |

+ 13 - 8
sql/biz_common_prosperity_project.sql

@@ -1,12 +1,15 @@
1
-CREATE TABLE IF NOT EXISTS `biz_common_prosperity_project` (
1
+-- 共同富裕项目(物理删除;全量覆盖建表)
2
+DROP TABLE IF EXISTS `biz_common_prosperity_project`;
3
+
4
+CREATE TABLE `biz_common_prosperity_project` (
2
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
5
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
3
   `project_name` varchar(64) NOT NULL COMMENT '项目名称',
6
   `project_name` varchar(64) NOT NULL COMMENT '项目名称',
4
-  `project_type` tinyint(4) NOT NULL COMMENT '1合作共赢 2农文旅融合 3认养农业',
5
-  `introduction` varchar(200) NOT NULL COMMENT '项目简介',
6
-  `project_content` varchar(600) NOT NULL COMMENT '项目内容',
7
-  `impl_start_date` date NOT NULL COMMENT '实施开始日期',
8
-  `impl_end_date` date NOT NULL COMMENT '实施结束日期',
7
+  `project_type` tinyint(4) NOT NULL COMMENT '1和美乡村建设 2人居环境整治提升 3其他项目投入',
8
+  `introduction` varchar(200) DEFAULT NULL COMMENT '项目简介(选填)',
9
+  `project_content` varchar(600) NOT NULL COMMENT '建设规模及内容',
10
+  `investment_amount` decimal(18,4) DEFAULT NULL COMMENT '投资金额(万元)',
11
+  `impl_year` int(11) NOT NULL COMMENT '实施年限(年)',
12
+  `impl_status` varchar(500) DEFAULT NULL COMMENT '实施情况',
9
   `video_file_url` varchar(512) DEFAULT NULL COMMENT '运营视频URL',
13
   `video_file_url` varchar(512) DEFAULT NULL COMMENT '运营视频URL',
10
   `video_file_path` varchar(512) DEFAULT NULL COMMENT '运营视频存储路径',
14
   `video_file_path` varchar(512) DEFAULT NULL COMMENT '运营视频存储路径',
11
   `cover_file_url` varchar(512) DEFAULT NULL COMMENT '封面URL',
15
   `cover_file_url` varchar(512) DEFAULT NULL COMMENT '封面URL',
@@ -23,11 +26,12 @@ CREATE TABLE IF NOT EXISTS `biz_common_prosperity_project` (
23
   KEY `idx_create_time` (`create_time`),
26
   KEY `idx_create_time` (`create_time`),
24
   KEY `idx_project_type` (`project_type`),
27
   KEY `idx_project_type` (`project_type`),
25
   KEY `idx_publish` (`publish_status`),
28
   KEY `idx_publish` (`publish_status`),
26
-  KEY `idx_impl_start` (`impl_start_date`)
29
+  KEY `idx_impl_year` (`impl_year`)
27
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共同富裕项目';
30
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共同富裕项目';
28
 
31
 
29
 -- 共同富裕项目-运营图片
32
 -- 共同富裕项目-运营图片
30
-CREATE TABLE IF NOT EXISTS `biz_common_prosperity_project_op_image` (
33
+DROP TABLE IF EXISTS `biz_common_prosperity_project_op_image`;
34
+CREATE TABLE `biz_common_prosperity_project_op_image` (
31
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
35
   `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
32
   `project_id` bigint(20) NOT NULL COMMENT '项目ID',
36
   `project_id` bigint(20) NOT NULL COMMENT '项目ID',
33
   `file_url` varchar(512) NOT NULL COMMENT '图片URL',
37
   `file_url` varchar(512) NOT NULL COMMENT '图片URL',