ソースを参照

下载/地址的现实

licailing 4 年 前
コミット
31de273edb

+ 6 - 0
pom.xml

@@ -271,6 +271,12 @@
             <artifactId>hutool-all</artifactId>
             <version>5.3.8</version>
         </dependency>
+        <!-- freemarker -->
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+            <version>2.3.30</version>
+        </dependency>
 
     </dependencies>
 

+ 3 - 0
src/main/java/com/izouma/wenlvju/domain/Rate.java

@@ -134,6 +134,9 @@ public class Rate extends BaseEntity {
     @Transient
     private String organizer;
 
+    @Transient
+    private String address;
+
     @Column(columnDefinition = "TEXT")
     @Convert(converter = RateAuditListConverter.class)
     private List<RateAudit> rateAudits = new ArrayList<>();

+ 2 - 2
src/main/java/com/izouma/wenlvju/enums/RateStatus.java

@@ -14,11 +14,11 @@ public enum RateStatus {
      */
     ASSIGN_EXPERT,
     /*
-    待复审(分配专家组)
+    待专家组考察(分配专家组)
      */
     REVIEW_PENDING,
     /*
-    待提交成绩
+    最终评审
      */
     SUBMIT_GRADE,
     EXPERT_DENY,

+ 57 - 1
src/main/java/com/izouma/wenlvju/service/RateService.java

@@ -1,5 +1,6 @@
 package com.izouma.wenlvju.service;
 
+import com.izouma.wenlvju.config.DateConfig;
 import com.izouma.wenlvju.domain.Rate;
 import com.izouma.wenlvju.dto.PageQuery;
 import com.izouma.wenlvju.dto.RateAudit;
@@ -7,13 +8,27 @@ import com.izouma.wenlvju.enums.RateStatus;
 import com.izouma.wenlvju.exception.BusinessException;
 import com.izouma.wenlvju.repo.RateRepo;
 import com.izouma.wenlvju.utils.JpaUtils;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.Version;
 import lombok.AllArgsConstructor;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.PrintWriter;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @Service
 @AllArgsConstructor
@@ -25,7 +40,7 @@ public class RateService {
         return rateRepo.findAll(JpaUtils.toSpecification(pageQuery, Rate.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    public void audit(Long id, RateStatus status, String remark, int score, Long userId) {
+    public void audit(Long id, RateStatus status, String remark, Long userId) {
         Rate rate = rateRepo.findById(id).orElseThrow(new BusinessException("无记录"));
         rate.setStatus(status);
         RateAudit rateAudit = RateAudit.builder()
@@ -52,4 +67,45 @@ public class RateService {
         rate.setExpertUserId(userId);
         rateRepo.save(rate);
     }
+
+    public void export(HttpServletResponse response, Rate rate) {
+        Map<String, Object> dataMap = new HashMap<>();
+        try {
+            //单位
+            dataMap.put("name", rate.getName());
+            //日期
+            dataMap.put("date", DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT).format(rate.getCreatedAt()));
+            //负责人
+            dataMap.put("owner", rate.getOwner());
+            //电话
+            dataMap.put("phone", rate.getOwnerPhone());
+            //邮箱
+            dataMap.put("email", rate.getOwnerEmail());
+            //承办过
+            dataMap.put("undertake", rate.isUndertakeExamination() ? "是" : "否");
+            //考级机构名称
+            if (rate.isUndertakeExamination()){
+                dataMap.put("examination", String.join(",", rate.getExamination()));
+            }
+            //单位概况
+            dataMap.put("introduction", rate.getIntroduction());
+            //Configuration 用于读取ftl文件
+            Configuration configuration = new Configuration(new Version("2.3.0"));
+
+
+            configuration.setDefaultEncoding("utf-8");
+
+            configuration.setDirectoryForTemplateLoading(new File(Paths.get(System.getProperty("user.dir"), "src", "main", "resources", "templates")
+                    .toString()));//指定ftl所在目录,根据自己的改
+            response.setContentType("application/msword");
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("等级评定申报表", "UTF-8")+".doc");
+            response.setCharacterEncoding("utf-8");
+            PrintWriter out = response.getWriter();
+            Template template = configuration.getTemplate("RateTemplate.ftl", "utf-8");//以utf-8的编码读取ftl文件
+            template.process(dataMap, out);
+            out.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
 }

+ 22 - 5
src/main/java/com/izouma/wenlvju/web/RateController.java

@@ -1,6 +1,8 @@
 package com.izouma.wenlvju.web;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.izouma.wenlvju.domain.Organization;
 import com.izouma.wenlvju.domain.Rate;
 import com.izouma.wenlvju.dto.PageQuery;
@@ -64,11 +66,20 @@ public class RateController extends BaseController {
 
     @PostMapping("/all2")
     public Page<Rate> all2(@RequestBody PageQuery pageQuery) {
-        Map<Long, String> organizationMap = organizationRepo.findAll()
+        Map<Long, Organization> organizationMap = organizationRepo.findAll()
                 .stream()
-                .collect(Collectors.toMap(Organization::getId, Organization::getName));
+                .collect(Collectors.toMap(Organization::getId, organization -> organization));
         return rateService.all(pageQuery).map(rate -> {
-            rate.setOrganizer(organizationMap.get(rate.getOrganizationId()));
+            Organization organization = organizationMap.get(rate.getOrganizationId());
+            if (ObjectUtil.isNotEmpty(organization)) {
+                rate.setOrganizer(organization.getName());
+                String address= "南京市" + organization.getDistrict();
+                if (StrUtil.isNotBlank(organization.getAddress())){
+                    address += organization.getAddress();
+                }
+                rate.setAddress(address);
+            }
+
             return rate;
         });
     }
@@ -91,13 +102,19 @@ public class RateController extends BaseController {
     }
 
     @PostMapping("/audit")
-    public void audit(@RequestParam Long id, @RequestParam RateStatus status, String remark, int score) {
-        rateService.audit(id, status, remark, score, SecurityUtils.getAuthenticatedUser().getId());
+    public void audit(@RequestParam Long id, @RequestParam RateStatus status, String remark) {
+        rateService.audit(id, status, remark, SecurityUtils.getAuthenticatedUser().getId());
     }
 
     @PostMapping("/addExpert")
     public void addExpert(@RequestParam Long id, @RequestParam Long userId) {
         rateService.addExpert(id, userId);
     }
+
+    @GetMapping("/export/{id}")
+    public void export(HttpServletResponse response, @PathVariable Long id) {
+        Rate rate = rateRepo.findById(id).orElseThrow(new BusinessException("无申请"));
+        rateService.export(response, rate);
+    }
 }
 

ファイルの差分が大きいため隠しています
+ 2 - 0
src/main/resources/templates/RateTemplate.ftl


+ 83 - 40
src/main/vue/src/views/RateList.vue

@@ -26,10 +26,24 @@
             <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
             <!-- <el-table-column prop="id" label="ID" width="100"> </el-table-column> -->
             <el-table-column prop="organizer" label="承办单位"> </el-table-column>
-            <el-table-column prop="createdAt" label="申请时间"></el-table-column>
-            <el-table-column prop="year" label="年度"> </el-table-column>
-            <el-table-column prop="status" label="状态" :formatter="statusFormatter"> </el-table-column>
-            <el-table-column label="操作" align="right" fixed="right" min-width="150">
+            <el-table-column prop="createdAt" label="申请时间" min-width="100"></el-table-column>
+            <el-table-column prop="year" label="年度" min-width="60"> </el-table-column>
+            <el-table-column prop="status" label="状态" :formatter="statusFormatter" min-width="100"> </el-table-column>
+            <el-table-column prop="score" label="分数">
+                <template slot-scope="{ row }">
+                    <span v-if="row.score">{{ row.score }}</span>
+                    <span v-else>审核中</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="grade" label="等级">
+                <template slot-scope="{ row }">
+                    <span v-if="row.grade == 'EXCELLENT'"><el-tag type="success">优秀</el-tag></span>
+                    <span v-else-if="row.grade == 'ELIGIBLE'"><el-tag type="success">合格</el-tag></span>
+                    <span v-else-if="row.grade == 'NOT_ELIGIBLE'"><el-tag type="success">不合格</el-tag></span>
+                    <span v-else><el-tag type="info">审核中</el-tag></span>
+                </template>
+            </el-table-column>
+            <el-table-column label="操作" align="right" fixed="right" min-width="200">
                 <template slot-scope="{ row }">
                     <el-button
                         v-if="row.status === 'FIRST_REVIEW_PENDING'"
@@ -51,10 +65,7 @@
                     >
                         驳回
                     </el-button>
-                    <el-button @click="sorce(row)" type="primary" size="mini" plain v-if="row.status === 'EXPERT_PASS'"
-                        >查看分数</el-button
-                    >
-                    <el-button v-if="row.status === 'SUBMIT_GRADE'" @click="dialogScore = true" type="warning" plain
+                    <el-button v-if="row.status === 'SUBMIT_GRADE'" @click="openScore(row)" type="warning" plain
                         >填写分数</el-button
                     >
                     <el-button
@@ -65,14 +76,6 @@
                         v-if="(row.status === 'ASSIGN_EXPERT') & display"
                         >分配专家组</el-button
                     >
-                    <!-- <el-button
-                        @click="supervision(row.id)"
-                        type="success"
-                        size="mini"
-                        plain
-                        v-if="(row.status === 'SUBMIT_GRADE' || row.status === 'REVIEW_PENDING') & display"
-                        >查看专家组</el-button
-                    > -->
                     <el-button @click="editRow(row)" type="primary" size="mini" plain>查看附件</el-button>
                     <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
                 </template>
@@ -114,21 +117,31 @@
             </div>
         </el-dialog>
         <el-dialog title="填写分数等级" :visible.sync="dialogScore" width="400px" center>
-            <div style="margin-bottom: 10px">
-                <label style="margin: 0 10px 0 30px">总分</label><el-input style="width: 220px;"></el-input>
-            </div>
-            <div style="margin-bottom: 10px">
-                <label style="margin: 0 10px 0 30px">等级</label>
-                <el-select style="width: 220px" v-model="grade" placeholder="请选择的等级">
-                    <el-option
-                        v-for="item in gradeOptions"
-                        :key="item.value"
-                        :label="item.label"
-                        :value="item.value"
-                    ></el-option>
-                </el-select>
-            </div>
-            <div style="margin-left: 230px"><el-button type="primary">提交</el-button></div>
+            <el-form :model="scoreInfo" style="width: 400px;" label-width="70px">
+                <el-form-item
+                    label="总分"
+                    prop="score"
+                    :rules="{ required: true, message: '请输入分数', trigger: 'blur' }"
+                >
+                    <el-input-number type="number" v-model="scoreInfo.score" placeholder="分数" style="width: 220px;">
+                    </el-input-number>
+                </el-form-item>
+                <el-form-item
+                    label="等级"
+                    prop="grade"
+                    :rules="{ required: true, message: '请输入等级', trigger: 'blur' }"
+                >
+                    <el-select style="width: 220px" v-model="scoreInfo.grade" placeholder="请选择的等级">
+                        <el-option
+                            v-for="item in gradeOptions"
+                            :key="item.value"
+                            :label="item.label"
+                            :value="item.value"
+                        ></el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item><el-button type="primary" size="mini" @click="saveScore()">提交</el-button></el-form-item>
+            </el-form>
         </el-dialog>
     </div>
 </template>
@@ -148,10 +161,10 @@ export default {
             statusOptions: [
                 { label: '等待初审', value: 'FIRST_REVIEW_PENDING' },
                 { label: '待分配专家组', value: 'ASSIGN_EXPERT' },
-                { label: '待复审', value: 'REVIEW_PENDING' },
+                { label: '待专家组考察', value: 'REVIEW_PENDING' },
                 { label: '初审驳回', value: 'FIRST_REVIEW_DENY' },
-                { label: '待提交成绩', value: 'SUBMIT_GRADE' },
-                { label: '专家拒绝', value: 'EXPERT_DENY' }
+                { label: '最终评审', value: 'SUBMIT_GRADE' },
+                { label: '待提交纸质材料', value: 'SUBMIT_PAPER_MATERIALS' }
             ],
             supervisor: [],
             dialogVisible: false,
@@ -163,7 +176,10 @@ export default {
                 { label: '合格', value: 'ELIGIBLE' },
                 { label: '不合格', value: 'NOT_ELIGIBLE' }
             ],
-            grade: ''
+            scoreInfo: {
+                score: 0,
+                grade: ''
+            }
         };
     },
     created() {
@@ -195,6 +211,13 @@ export default {
             });
     },
     methods: {
+        gradeFormatter(row, column, cellValue, index) {
+            let selectedOption = this.gradeOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
         statusFormatter(row, column, cellValue, index) {
             let selectedOption = this.statusOptions.find(i => i.value === cellValue);
             if (selectedOption) {
@@ -357,11 +380,6 @@ export default {
                     this.$message.error(e.error);
                 });
         },
-        sorce(row) {
-            this.$alert('专家打出的分数为:' + row.score, '分数', {
-                confirmButtonText: '确定'
-            });
-        },
         getAdmin() {
             let data = this.userInfo.authorities;
             data.forEach(element => {
@@ -369,6 +387,31 @@ export default {
                     this.display = true;
                 }
             });
+        },
+        openScore(row) {
+            this.dialogScore = true;
+            this.sorceInfo = row;
+        },
+        saveScore() {
+            this.scoreInfo.status = 'SUBMIT_PAPER_MATERIALS';
+            this.$http
+                .post(
+                    '/rate/save',
+                    {
+                        ...this.scoreInfo
+                    },
+                    { body: 'json' }
+                )
+                .then(res => {
+                    this.$message.success('OK');
+                    this.dialogScore = false;
+                    this.scoreInfo = '';
+                    this.getData();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
         }
     }
 };

+ 29 - 4
src/main/vue/src/views/organization/RateOrganizerList.vue

@@ -36,6 +36,9 @@
             <el-table-column label="操作" align="center" fixed="right" min-width="150">
                 <template slot-scope="{ row }">
                     <el-button @click="editRow(row)" type="primary" size="mini" plain>编辑资料</el-button>
+                    <el-button @click="word(row)" type="primary" :loading="downloading" size="mini" class="filter-item"
+                        >导出
+                    </el-button>
                     <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
                 </template>
             </el-table-column>
@@ -77,11 +80,12 @@ export default {
             url: '/rate/all',
             downloading: false,
             statusOptions: [
-                { label: '初审中', value: 'FIRST_REVIEW_PENDING' },
-                { label: '待复审', value: 'REVIEW_PENDING' },
+                { label: '等待初审', value: 'FIRST_REVIEW_PENDING' },
+                { label: '待分配专家组', value: 'ASSIGN_EXPERT' },
+                { label: '待专家组考察', value: 'REVIEW_PENDING' },
                 { label: '初审驳回', value: 'FIRST_REVIEW_DENY' },
-                { label: '待提交成绩', value: 'SUBMIT_GRADE' },
-                { label: '专家拒绝', value: 'EXPERT_DENY' }
+                { label: '最终评审', value: 'SUBMIT_GRADE' },
+                { label: '待提交纸质材料', value: 'SUBMIT_PAPER_MATERIALS' }
             ]
         };
     },
@@ -178,6 +182,27 @@ export default {
                         this.$message.error(e.error);
                     }
                 });
+        },
+        word(row) {
+            this.downloading = true;
+            this.$axios
+                .get('/rate/export/' + row.id)
+                .then(res => {
+                    console.log(res);
+                    this.downloading = false;
+                    const downloadUrl = window.URL.createObjectURL(new Blob([res.data]));
+                    const link = document.createElement('a');
+                    link.href = downloadUrl;
+                    link.setAttribute('download', res.headers['content-disposition'].split('filename=')[1]);
+                    document.body.appendChild(link);
+                    link.click();
+                    link.remove();
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.downloading = false;
+                    this.$message.error(e.error);
+                });
         }
     }
 };

+ 52 - 1
src/test/java/com/izouma/wenlvju/GenCodeTest.java

@@ -7,6 +7,7 @@ import com.izouma.wenlvju.utils.FileUtils;
 import freemarker.template.Configuration;
 import freemarker.template.Template;
 import freemarker.template.TemplateException;
+import freemarker.template.Version;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -14,8 +15,11 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 import org.springframework.util.ResourceUtils;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.io.*;
 import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
 import java.util.*;
 
 @RunWith(SpringRunner.class)
@@ -108,7 +112,8 @@ public class GenCodeTest {
     public void testFreemarker() throws IOException, TemplateException {
         Template temp = cfg.getTemplate("ControllerTemplate.ftl");
         Map data = new HashMap();
-        String json = FileUtils.readFile(Paths.get(System.getProperty("user.dir"), "src", "main", "resources", "genjson", "TestGenCode.json").toString());
+        String json = FileUtils.readFile(Paths.get(System.getProperty("user.dir"), "src", "main", "resources", "genjson", "TestGenCode.json")
+                .toString());
         Gson gson = new Gson();
         GenCode model = gson.fromJson(json, GenCode.class);
         data.put("model", model);
@@ -117,4 +122,50 @@ public class GenCodeTest {
         temp.process(data, out);
 
     }
+
+    @Test
+    public void test(HttpServletResponse response, HttpServletRequest request) {
+        Map<String, Object> dataMap = new HashMap<>();
+        try {
+            //单位
+            dataMap.put("name", "走马");
+            //日期
+            dataMap.put("data", new SimpleDateFormat("yyyy年MM月dd日").format(new SimpleDateFormat("yyyy-MM-dd").parse("2018-09-19")));
+            //负责人
+            dataMap.put("owner", "张三");
+            //电话
+            dataMap.put("phone", "123456");
+            //邮箱
+            dataMap.put("email", "123@qq.com");
+            //承办过
+            dataMap.put("undertake", "是");
+            //考级机构名称
+            dataMap.put("examination", "机构1,机构2");
+            //单位概况
+            dataMap.put("introduction", "这是一个介绍");
+            //Configuration 用于读取ftl文件
+            Configuration configuration = new Configuration(new Version("2.3.0"));
+            configuration.setDefaultEncoding("utf-8");
+
+//            configuration.setDirectoryForTemplateLoading(new File("/Users/qiufangchao/Desktop/project/wenlvju/src/main/resources/templates"));
+//
+//            //输出文档路径及名称
+//            File outFile = new File("D:/123.doc");
+//
+//            //以utf-8的编码读取ftl文件
+//            Template template = configuration.getTemplate("RateTemplate.ftl", "utf-8");
+//            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"), 10240);
+
+            configuration.setDirectoryForTemplateLoading(new File(request.getRealPath("/") + "/templates"));//指定ftl所在目录,根据自己的改
+            response.setContentType("application/msword");
+            response.setHeader("Content-Disposition", "attachment;filename=\"" + new String("申报表.doc".getBytes("GBK"), "iso8859-1") + "\"");
+            response.setCharacterEncoding("utf-8");//此句非常关键,不然word文档全是乱码
+            PrintWriter out = response.getWriter();
+            Template template = configuration.getTemplate("RateTemplate.ftl", "utf-8");//以utf-8的编码读取ftl文件
+            template.process(dataMap, out);
+            out.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
 }

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません