Просмотр исходного кода

Merge branch 'test' of http://git.izouma.com/licailing/wenlvju into test

 Conflicts:
	src/main/java/com/izouma/wenlvju/service/performance/ProgrammeService.java
	src/main/java/com/izouma/wenlvju/utils/FileUtils.java
	src/main/resources/application.yaml
	src/main/vue/src/views/performance/ProgrammeOrgList.vue
	src/main/vue/src/views/user/UserList.vue
	src/test/java/com/izouma/wenlvju/repo/UserRepoTest.java
xuqiang 4 лет назад
Родитель
Сommit
ff85d32086
80 измененных файлов с 4673 добавлено и 664 удалено
  1. 12 0
      pom.xml
  2. 1 1
      src/main/h5/public/index.html
  3. 2 2
      src/main/h5/src/plugins/http.js
  4. 5 0
      src/main/h5/src/router/index.js
  5. 41 2
      src/main/h5/src/views/Home.vue
  6. 674 0
      src/main/h5/src/views/TrainingInstitution.vue
  7. 49 42
      src/main/h5/src/views/loginHome.vue
  8. 30 0
      src/main/java/com/izouma/wenlvju/domain/Announcement.java
  9. 2 0
      src/main/java/com/izouma/wenlvju/domain/Rate.java
  10. 152 0
      src/main/java/com/izouma/wenlvju/domain/TrainingInstitution.java
  11. 2 0
      src/main/java/com/izouma/wenlvju/domain/performance/Participant.java
  12. 2 0
      src/main/java/com/izouma/wenlvju/domain/performance/Performance.java
  13. 25 18
      src/main/java/com/izouma/wenlvju/dto/ProgrammeShowDTO.java
  14. 2 0
      src/main/java/com/izouma/wenlvju/dto/RateDTO.java
  15. 45 0
      src/main/java/com/izouma/wenlvju/dto/TrainingInstitutionDTO.java
  16. 12 0
      src/main/java/com/izouma/wenlvju/enums/AnnouncementType.java
  17. 26 0
      src/main/java/com/izouma/wenlvju/enums/GradingOrganizationDTO.java
  18. 16 0
      src/main/java/com/izouma/wenlvju/repo/AnnouncementRepo.java
  19. 3 0
      src/main/java/com/izouma/wenlvju/repo/RateRepo.java
  20. 30 0
      src/main/java/com/izouma/wenlvju/repo/TrainingInstitutionRepo.java
  21. 7 0
      src/main/java/com/izouma/wenlvju/repo/performance/ParticipantRepo.java
  22. 4 0
      src/main/java/com/izouma/wenlvju/security/WebSecurityConfig.java
  23. 20 0
      src/main/java/com/izouma/wenlvju/service/AnnouncementService.java
  24. 19 25
      src/main/java/com/izouma/wenlvju/service/RateExpertAuditService.java
  25. 211 22
      src/main/java/com/izouma/wenlvju/service/RateService.java
  26. 98 0
      src/main/java/com/izouma/wenlvju/service/TrainingInstitutionService.java
  27. 25 0
      src/main/java/com/izouma/wenlvju/service/UserService.java
  28. 23 0
      src/main/java/com/izouma/wenlvju/service/performance/ParticipantService.java
  29. 184 119
      src/main/java/com/izouma/wenlvju/service/performance/ProgrammeService.java
  30. 30 0
      src/main/java/com/izouma/wenlvju/service/storage/AliStorageService.java
  31. 116 31
      src/main/java/com/izouma/wenlvju/utils/FileUtils.java
  32. 60 0
      src/main/java/com/izouma/wenlvju/web/AnnouncementController.java
  33. 11 1
      src/main/java/com/izouma/wenlvju/web/AuthenticationController.java
  34. 6 3
      src/main/java/com/izouma/wenlvju/web/GradingOrganizationController.java
  35. 16 2
      src/main/java/com/izouma/wenlvju/web/RateController.java
  36. 1 1
      src/main/java/com/izouma/wenlvju/web/RateExpertAuditController.java
  37. 102 0
      src/main/java/com/izouma/wenlvju/web/TrainingInstitutionController.java
  38. 29 7
      src/main/java/com/izouma/wenlvju/web/performance/ProgrammeController.java
  39. 3 6
      src/main/resources/application.yaml
  40. 1 0
      src/main/resources/genjson/Announcement.json
  41. 0 0
      src/main/resources/genjson/TrainingInstitution.json
  42. 0 0
      src/main/resources/templates/RateTemplate.ftl
  43. 1 0
      src/main/vue/package.json
  44. 5 1
      src/main/vue/src/components/OrganizationLog.vue
  45. 3 0
      src/main/vue/src/components/ProgrammeLog.vue
  46. 328 0
      src/main/vue/src/components/ProgrammeLog1.vue
  47. 6 3
      src/main/vue/src/components/RichText.vue
  48. 2 0
      src/main/vue/src/main.js
  49. 1 0
      src/main/vue/src/mixins/pageableTable.js
  50. 53 1
      src/main/vue/src/router.js
  51. 94 0
      src/main/vue/src/views/AnnouncementDetail.vue
  52. 106 0
      src/main/vue/src/views/AnnouncementEdit.vue
  53. 169 0
      src/main/vue/src/views/AnnouncementList.vue
  54. 12 6
      src/main/vue/src/views/Dashboard.vue
  55. 26 13
      src/main/vue/src/views/Login.vue
  56. 180 0
      src/main/vue/src/views/TrainingInstitutionEdit.vue
  57. 279 0
      src/main/vue/src/views/TrainingInstitutionList.vue
  58. 1 0
      src/main/vue/src/views/performance/ArrangeJudgeList.vue
  59. 3 1
      src/main/vue/src/views/performance/PerformanceEdit.vue
  60. 13 4
      src/main/vue/src/views/performance/ProgrammeEdit.vue
  61. 388 0
      src/main/vue/src/views/performance/ProgrammeGOList.vue
  62. 255 129
      src/main/vue/src/views/performance/ProgrammeList.vue
  63. 126 34
      src/main/vue/src/views/performance/ProgrammeOrgList.vue
  64. 3 7
      src/main/vue/src/views/performance/ProgrammeScoreList.vue
  65. 7 24
      src/main/vue/src/views/rate/RateDistrictList.vue
  66. 2 30
      src/main/vue/src/views/rate/RateDistrictListDone.vue
  67. 10 24
      src/main/vue/src/views/rate/RateDistrictListPending.vue
  68. 3 62
      src/main/vue/src/views/rate/RateList.vue
  69. 35 1
      src/main/vue/src/views/rate/RateListDone.vue
  70. 56 1
      src/main/vue/src/views/rate/RateListPending.vue
  71. 49 6
      src/main/vue/src/views/rate/RateOrganizerList.vue
  72. 0 1
      src/main/vue/src/views/user/UserList.vue
  73. 103 0
      src/main/vue/src/widgets/BoardWidget.vue
  74. 101 0
      src/main/vue/src/widgets/PolicyWidget.vue
  75. 16 0
      src/main/vue/yarn.lock
  76. 13 2
      src/test/java/com/izouma/wenlvju/repo/RepoTest.java
  77. 1 1
      src/test/java/com/izouma/wenlvju/repo/UserRepoTest.java
  78. 60 28
      src/test/java/com/izouma/wenlvju/service/RateServiceTest.java
  79. 5 3
      src/test/java/com/izouma/wenlvju/service/sms/NjwlSmsServiceTest.java
  80. 61 0
      src/test/java/com/izouma/wenlvju/web/TrainingInstitutionControllerTest.java

+ 12 - 0
pom.xml

@@ -304,6 +304,18 @@
             <artifactId>jave-all-deps</artifactId>
             <version>3.1.1</version>
         </dependency>
+
+        <!-- 解压rar -->
+        <dependency>
+            <groupId>com.github.junrar</groupId>
+            <artifactId>junrar</artifactId>
+            <version>4.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.11.2</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 1 - 1
src/main/h5/public/index.html

@@ -5,7 +5,7 @@
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
     <link rel="icon" href="<%= BASE_URL %>favicon.ico">
-    <title><%= htmlWebpackPlugin.options.title %></title>
+    <title>宁艺通</title>
   </head>
   <body>
     <noscript>

+ 2 - 2
src/main/h5/src/plugins/http.js

@@ -4,9 +4,9 @@ import qs from "qs";
 let baseUrl = "http://localhost:8080";
 switch (process.env.NODE_ENV) {
   case "development":
+    baseUrl = "http://yskj.njlyw.cn:8081";
     // baseUrl = "http://wljtest.izouma.com";
-    baseUrl = "http://localhost:8080";
-    // baseUrl = 'http://192.168.50.190:8080';
+    // baseUrl = 'http://localhost:8080';
     break;
   case "test":
     baseUrl = "http://localhost:8080";

+ 5 - 0
src/main/h5/src/router/index.js

@@ -14,6 +14,11 @@ const routes = [
     name: "home",
     component: () => import("../views/Home.vue")
   },
+  {
+    path: "/trainingInstitution",
+    name: "trainingInstitution",
+    component: () => import("../views/TrainingInstitution.vue")
+  },
   {
     path: "/login",
     name: "login",

+ 41 - 2
src/main/h5/src/views/Home.vue

@@ -19,6 +19,18 @@
     <div style="margin-top:20px" v-if="info.video">
       <video-upload v-model="info2" class="width"></video-upload>
     </div>
+    <div style="margin-top:20px" v-else-if="info.annex">
+      <van-image
+        fit="cover"
+        style="padding:0 16px"
+        v-for="(a, index) in list"
+        :key="index"
+        @click="preview(index, a)"
+        :src="a"
+        width="92%"
+        height="150px"
+      />
+    </div>
     <div class="base">
       <div class="base-info">
         <div class="base-info-item">
@@ -29,9 +41,29 @@
           <div class="text1">专业</div>
           <div class="text2">{{ info.specialty }}</div>
         </div>
+        <div class="base-info-item">
+          <div class="text1">节目状态</div>
+          <div class="text2" v-if="info.programmeStatus == 'SUBMIT'">
+            审核中
+          </div>
+          <div class="text2" v-else-if="info.programmeStatus == 'AUDIT_FAILED'">
+            考级机构审核未通过
+          </div>
+          <div
+            class="text2"
+            v-else-if="info.programmeStatus == 'REVIEW_FAILED'"
+          >
+            审核未通过
+          </div>
+          <div class="text2" v-else>未提交</div>
+        </div>
+      </div>
+      <div class="base-info">
+        <img class="left-icon icon" src="../assets/icon_lianjie.png" alt="" />
+        <img class="right-icon icon" src="../assets/icon_lianjie.png" alt="" />
         <div v-for="(time, index) in info.participants" :key="index">
           <div class="base-info-item">
-            <div class="text1">参演时间</div>
+            <div class="text1">出生日期</div>
             <div class="text2">
               {{ time.birthday }}
             </div>
@@ -89,7 +121,7 @@
           </div>
         </div>
       </div> -->
-      <div class="base-info">
+      <div class="base-info" v-if="info.score">
         <img class="left-icon icon" src="../assets/icon_lianjie.png" alt="" />
         <img class="right-icon icon" src="../assets/icon_lianjie.png" alt="" />
         <div class="score">
@@ -171,6 +203,7 @@
 
 <script>
 import { mapState } from "vuex";
+import { ImagePreview } from "vant";
 // import QrcodeVue from "qrcode.vue";
 export default {
   name: "home",
@@ -185,6 +218,7 @@ export default {
       info: {},
       info2: {},
       persons: [],
+      list: [],
       isAdmin: false,
       scores: [],
       score: "",
@@ -244,6 +278,9 @@ export default {
     // this.getInfo();
   },
   methods: {
+    preview(index = 0, list = []) {
+      ImagePreview([list]);
+    },
     next() {
       this.nowActive = this.nowActive + 1;
       this.persons = [];
@@ -275,6 +312,8 @@ export default {
         })
         .then(res => {
           this.info = res;
+          this.list = { src: res.annex };
+          // console.log(this.list);
           this.info2 = {
             src: this.info.video
           };

+ 674 - 0
src/main/h5/src/views/TrainingInstitution.vue

@@ -0,0 +1,674 @@
+<template>
+  <div class="page">
+    <van-form ref="form" @submit="submit" :submit-on-enter="false">
+      <van-popover v-model="showPopover" trigger="click">
+        <template #reference>
+          <van-field
+            name="企业名称"
+            label="企业名称"
+            placeholder="请输入企业名称"
+            v-model="form.name"
+            :rules="[{ required: true, message: '请填写企业名称' }]"
+            @change="like"
+          />
+        </template>
+
+        <van-cell-group>
+          <van-cell
+            v-for="(item, index) in list"
+            :key="index"
+            :title="item"
+            @click="choose(item)"
+          />
+        </van-cell-group>
+      </van-popover>
+      <van-field
+        name="注册号"
+        label="注册号/统一社会信用代码"
+        placeholder="请输入注册号/统一社会信用代码"
+        v-model="form.uscc"
+        :rules="[{ required: true, message: '请填写注册号/统一社会信用代码' }]"
+      />
+      <van-field
+        name="是否从事文化艺术类校外培训"
+        label="是否从事文化艺术类校外培训"
+        :rules="[
+          {
+            validator: val => {
+              return val || val === false;
+            },
+            message: '请选择'
+          }
+        ]"
+      >
+        <template #input>
+          <van-radio-group
+            v-model="form.engagedInTraining"
+            direction="horizontal"
+          >
+            <van-radio :name="true"> 是</van-radio>
+            <van-radio :name="false">否</van-radio>
+          </van-radio-group>
+        </template>
+      </van-field>
+      <div style="margin:30px" v-if="!form.id">
+        <van-button
+          class="submit"
+          native-type="button"
+          round
+          block
+          type="info"
+          @click="byUscc"
+        >
+          查询
+        </van-button>
+      </div>
+      <template v-else-if="form.engagedInTraining">
+        <van-field
+          type="textarea"
+          name="经营范围"
+          label="经营范围"
+          placeholder="请输入经营范围"
+          v-model="form.businessScope"
+          autosize
+        />
+        <van-field
+          name="企业住所"
+          label="企业住所"
+          placeholder="请输入企业住所"
+          v-model="form.address"
+        />
+        <van-field
+          name="生产经营场所"
+          label="生产经营场所"
+          placeholder="请输入生产经营场所"
+          v-model="form.businessPremise"
+        />
+        <van-field
+          name="生产法人姓名"
+          label="生产法人姓名"
+          placeholder="请输入生产法人姓名"
+          v-model="form.privacyPolicy"
+        />
+        <!-- <van-field
+          type="tel"
+          maxlength="11"
+          name="生产短信号码"
+          label="生产短信号码"
+          placeholder="请输入短信号码"
+          v-model="form.phone"
+        /> -->
+        <van-field
+          type="digit"
+          name="企业联系方式"
+          label="企业联系方式"
+          placeholder="请输入企业联系方式"
+          v-model="form.contactPhone"
+        />
+        <van-field
+          name="所属管区"
+          label="所属管区"
+          placeholder="请输入所属管区"
+          v-model="form.district"
+        />
+        <van-field
+          type="number"
+          name="注册资本"
+          label="注册资本(万)"
+          placeholder="请输入注册资本"
+          v-model="form.registeredCapital"
+        />
+        <van-field
+          name="单位性质"
+          label="单位性质"
+          placeholder="请输入单位性质"
+          v-model="form.category"
+          readonly
+          @click="showType = true"
+        />
+
+        <van-action-sheet
+          v-model="showType"
+          :actions="types"
+          cancel-text="取消"
+          close-on-click-action
+          @select="onSelect"
+        />
+        <!-- <van-popup v-model="showArea" position="bottom">
+  <van-area
+    :area-list="areaList"
+    @confirm="onConfirm"
+    @cancel="showArea = false"
+  />
+</van-popup> -->
+
+        <van-field
+          name="专业种类"
+          label="专业种类"
+          placeholder="请输入专业种类"
+        >
+          <template #input>
+            <van-checkbox-group v-model="form.specialty" direction="horizontal">
+              <van-checkbox
+                :name="item"
+                v-for="(item, index) in specialtyOptions"
+                :key="index"
+                >{{ item }}</van-checkbox
+              >
+              <div class="extra-content">
+                <van-checkbox class="extra" name="其他">其他</van-checkbox>
+                <van-field
+                  v-if="showExtra"
+                  class="input"
+                  type="text"
+                  placeholder="请输入"
+                  v-model="extra"
+                  size="small"
+                />
+              </div>
+            </van-checkbox-group>
+          </template>
+        </van-field>
+        <van-field
+          type="digit"
+          name="培训点数量三楼及以下"
+          label="培训点数量三楼及以下"
+          placeholder="请输入培训点数量三楼及以下"
+          v-model="form.trainingSite"
+        />
+        <van-field
+          type="digit"
+          name="培训点数量四楼及以上"
+          label="培训点数量四楼及以上"
+          placeholder="请输入培训点数量四楼及以上"
+          v-model="form.trainingSiteFour"
+        />
+        <van-field
+          type="number"
+          name="总面积"
+          label="总面积(建筑面积)"
+          placeholder="请输入总面积(建筑面积)"
+          v-model="form.area"
+        />
+        <van-field
+          type="digit"
+          name="教室数量"
+          label="教室数量"
+          placeholder="请输入教室数量"
+          v-model="form.classroomNum"
+          :rules="[{ required: true, message: '请填写教室数量' }]"
+        />
+
+        <div class="panel">
+          <van-divider content-position="left">教师人数统计</van-divider>
+          <van-field
+            type="digit"
+            name="专职数量"
+            label="专职数量"
+            placeholder="请输入专职数量"
+            v-model="form.fullTimeNum"
+            @change="changeNum"
+            :rules="[{ required: true, message: '请填写专职数量' }]"
+          />
+          <van-field
+            type="digit"
+            name="兼职数量"
+            label="兼职数量"
+            placeholder="请输入兼职数量"
+            v-model="form.partTimeNum"
+            @change="changeNum"
+            :rules="[{ required: true, message: '请填写兼职数量' }]"
+          />
+          <van-field
+            type="digit"
+            name="教师总数"
+            label="教师总数"
+            placeholder="请输入教师总数"
+            v-model="form.teacherNum"
+            :rules="[{ required: true, message: '请填写教师总数' }]"
+          />
+        </div>
+        <div class="panel">
+          <van-divider content-position="left">教师专业人数统计</van-divider>
+
+          <van-field
+            type="digit"
+            name="音乐类"
+            label="音乐类"
+            placeholder="请输入音乐类"
+            v-model="form.musicNum"
+            @focus="focusNum('musicNum')"
+            @blur="blurNum('musicNum')"
+            @input="changeClass($event, 'musicNum')"
+            :rules="[
+              {
+                validator: val => {
+                  return !isMore;
+                },
+                message: '教师总数为' + form.teacherNum
+              }
+            ]"
+          />
+          <van-field
+            type="digit"
+            name="舞蹈类"
+            label="舞蹈类"
+            placeholder="请输入舞蹈类"
+            v-model="form.danceNum"
+            @focus="focusNum('danceNum')"
+            @blur="blurNum('danceNum')"
+            @input="changeClass($event, 'danceNum')"
+            :rules="[
+              {
+                validator: val => {
+                  return !isMore;
+                },
+                message: '教师总数为' + form.teacherNum
+              }
+            ]"
+          />
+          <van-field
+            type="digit"
+            name="美术类"
+            label="美术类"
+            placeholder="请输入美术类"
+            v-model="form.artNum"
+            @focus="focusNum('artNum')"
+            @blur="blurNum('artNum')"
+            @input="changeClass($event, 'artNum')"
+            :rules="[
+              {
+                validator: val => {
+                  return !isMore;
+                },
+                message: '教师总数为' + form.teacherNum
+              }
+            ]"
+          />
+          <van-field
+            type="digit"
+            name="戏剧戏曲"
+            label="戏剧戏曲"
+            placeholder="请输入戏剧戏曲"
+            v-model="form.theatreOperaNum"
+            @focus="focusNum('theatreOperaNum')"
+            @blur="blurNum('theatreOperaNum')"
+            @input="changeClass($event, 'theatreOperaNum')"
+            :rules="[
+              {
+                validator: val => {
+                  return !isMore;
+                },
+                message: '教师总数为' + form.teacherNum
+              }
+            ]"
+          />
+          <van-field
+            type="digit"
+            name="曲艺类"
+            label="曲艺类"
+            placeholder="请输入曲艺类"
+            v-model="form.folkMusicNum"
+            @focus="focusNum('folkMusicNum')"
+            @blur="blurNum('folkMusicNum')"
+            @input="changeClass($event, 'folkMusicNum')"
+            :rules="[
+              {
+                validator: val => {
+                  return !isMore;
+                },
+                message: '教师总数为' + form.teacherNum
+              }
+            ]"
+          />
+        </div>
+
+        <van-field
+          type="digit"
+          name="有教师资格证"
+          label="有教师资格证"
+          placeholder="请输入有教师资格证"
+          v-model="form.qualificationNum"
+          :rules="[{ required: true, message: '请填写有教师资格证' }]"
+        />
+        <van-field
+          type="digit"
+          name="年培训人数"
+          label="年培训人数"
+          placeholder="请输入年培训人数"
+          v-model="form.traineesPerYearNum"
+          :rules="[{ required: true, message: '请填写年培训人数' }]"
+        />
+        <van-field
+          name="是否是艺术水平考级考点"
+          label="是否是艺术水平考级考点"
+          placeholder="请输入是否是艺术水平考级考点"
+        >
+          <template #input>
+            <van-radio-group v-model="form.examPoint" direction="horizontal">
+              <van-radio :name="true"> 是</van-radio>
+              <van-radio :name="false">否</van-radio>
+            </van-radio-group>
+          </template>
+        </van-field>
+        <van-field
+          name="艺术水平考级机构名称"
+          label="艺术水平考级机构名称"
+          placeholder="请输入艺术水平考级机构名称"
+          v-model="form.gradingOrganization"
+        />
+        <van-field
+          type="textarea"
+          name="备注"
+          label="备注"
+          placeholder="请输入备注"
+          v-model="form.remark"
+        />
+
+        <div class="bottom">
+          <van-button
+            @click="saveWeb"
+            class="preview"
+            color="#ffcf6a"
+            block
+            round
+            native-type="button"
+            style="margin-right:12px"
+            >暂存</van-button
+          >
+          <van-button
+            class="submit"
+            round
+            block
+            type="info"
+            native-type="submit"
+            >提交</van-button
+          >
+        </div>
+      </template>
+    </van-form>
+
+    <van-divider> 技术客服:19951988293</van-divider>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      form: {
+        examPoint: false
+      },
+      list: [],
+      showPopover: false,
+      activeNames: "1",
+      isMore: false,
+      showType: false,
+      types: [
+        { name: "企业" },
+        { name: "社会组织" },
+        { name: "事业单位" },
+        { name: "其他" }
+      ],
+      extra: "",
+      specialtyOptions: ["音乐类", "舞蹈类", "美术类", "戏曲戏剧类", "曲艺类"]
+    };
+  },
+  mounted() {
+    let data = JSON.parse(
+      window.localStorage.getItem("trainingInstitution") || "{}"
+    );
+    data.specialty = this.setSpecialty(data.specialty);
+    this.form = data;
+  },
+  computed: {
+    showExtra() {
+      let special = [...this.form.specialty];
+      return special.includes("其他");
+    }
+  },
+  methods: {
+    onSelect(val) {
+      this.form.category = val.name;
+    },
+    like(info, key = "") {
+      this.$toast.loading({
+        message: "加载中...",
+        forbidClick: true,
+        duration: 0
+      });
+      this.showPopover = false;
+      let data = { search: this.form.name, size: 4, query: {} };
+      if (key) {
+        data.query[key] = this.form[key];
+      }
+      this.$http
+        .post("/trainingInstitution/name", data, { body: "json" })
+        .then(res => {
+          this.$toast.clear();
+          this.list = res.content;
+          setTimeout(() => {
+            this.$nextTick(() => {
+              this.showPopover = true;
+            });
+          }, 500);
+        });
+    },
+    setSpecialty(specialty) {
+      if (specialty) {
+        specialty = specialty.split(",");
+        specialty.forEach((item, index) => {
+          if (!this.specialtyOptions.includes(item)) {
+            specialty[index] = "其他";
+            this.extra = item;
+          }
+        });
+        return specialty;
+      } else {
+        return [];
+      }
+    },
+    byUscc() {
+      this.$refs.form.validate().then(() => {
+        this.$toast.loading({
+          message: "加载中...",
+          forbidClick: true,
+          duration: 0
+        });
+        this.extra = "";
+        this.$http
+          .post(
+            `/trainingInstitution/byUscc?name=${this.form.name}&uscc=${this.form.uscc}`
+          )
+          .then(res => {
+            res.category = res.category || "";
+            res.specialty = this.setSpecialty(res.specialty);
+            this.$toast.clear();
+            this.form = { ...res, ...this.form };
+            if (!this.form.engagedInTraining) {
+              this.submit();
+            }
+          })
+          .catch(e => {
+            this.$toast(e.error);
+          });
+      });
+    },
+    choose(info) {
+      this.form.name = info;
+      // this.form = { examPoint: false, ...info };
+      this.showPopover = false;
+    },
+    submit() {
+      if (!this.form.id) {
+        return;
+      }
+      this.$toast.loading({
+        message: "加载中...",
+        forbidClick: true,
+        duration: 0
+      });
+      let data = { ...this.form };
+      data.specialty.forEach((item, index) => {
+        if (!this.specialtyOptions.includes(item)) {
+          data.specialty[index] = this.extra;
+        }
+      });
+      data.specialty = data.specialty.filter(item => {
+        return item;
+      });
+      data.specialty = data.specialty.join(",");
+      this.$http
+        .post("/trainingInstitution/save", data, { body: "json" })
+        .then(res => {
+          this.$toast.clear();
+          window.localStorage.removeItem("trainingInstitution");
+          this.$dialog({
+            title: "提交成功",
+            message: "信息已经提交成功,感谢您的配合。",
+            showConfirmButton: false
+          });
+        })
+        .catch(e => {
+          this.$toast(e.error);
+        });
+    },
+    saveWeb() {
+      let form = { ...this.form };
+      form.specialty.forEach((item, index) => {
+        if (!this.specialtyOptions.includes(item)) {
+          form.specialty[index] = this.extra;
+        }
+      });
+      form.specialty = form.specialty.filter(item => {
+        return item;
+      });
+      form.specialty = form.specialty.join(",");
+      let data = JSON.stringify(form);
+      window.localStorage.setItem("trainingInstitution", data);
+      this.$toast.success("暂存成功");
+    },
+    changeNum() {
+      this.$nextTick(() => {
+        this.form.teacherNum =
+          Number(this.form.partTimeNum) + Number(this.form.fullTimeNum);
+      });
+    },
+    changeClass(val, label) {
+      let keys = {
+        musicNum: "音乐类",
+        danceNum: "舞蹈类",
+        artNum: "美术类",
+        theatreOperaNum: "戏剧戏曲",
+        folkMusicNum: "曲艺类"
+      };
+      let total = Number(val);
+      Object.keys(keys).forEach(item => {
+        if (label !== item) {
+          total += Number(this.form[item]);
+        }
+      });
+      if (total > this.form.teacherNum) {
+        this.isMore = true;
+        this.$refs.form.validate(keys[label]);
+      } else {
+        this.isMore = false;
+      }
+    },
+    focusNum(key) {
+      if (!Number(this.form[key])) {
+        this.form[key] = "";
+      }
+    },
+    blurNum(key) {
+      this.form[key] = Number(this.form[key]);
+    },
+    changeExtra(val) {
+      console.log(val);
+      if (val) {
+        this.$refs.extra.focus();
+      }
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.page {
+  position: relative;
+  padding-bottom: 100px;
+}
+/deep/.van-field {
+  margin: 16px 16px 0;
+  width: calc(100vw - 32px);
+  border-radius: 12px;
+  flex-direction: column;
+
+  .van-field__label {
+    font-size: 18px;
+    font-weight: bold;
+    color: #313233;
+    line-height: 28px;
+    width: auto;
+  }
+  .van-field__value {
+    margin-top: 14px;
+    font-size: 16px;
+    line-height: 32px;
+  }
+}
+
+.bottom {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 6px 26px calc(env(safe-area-inset-bottom) + 6px);
+  background-color: #fff;
+  z-index: 20;
+
+  display: flex;
+
+  .preview {
+    min-width: 82px;
+    width: 82px;
+  }
+  .submit {
+    flex-grow: 1;
+    // margin-left: 13px;
+  }
+}
+.panel {
+  padding: 30px 0;
+}
+.panel + .panel {
+  padding-top: 0;
+}
+
+.van-checkbox {
+  margin-bottom: 5px;
+}
+.extra-content {
+  display: flex;
+  align-items: center;
+}
+.van-divider {
+  font-size: 16px;
+}
+
+/deep/.input {
+  margin: 0;
+  width: calc(100vw - 240px);
+  border: 1px solid #ccc;
+  padding: 0px 12px;
+  border-radius: 0;
+  .van-field__value {
+    margin-top: 0;
+    line-height: 24px;
+    font-size: 14px;
+  }
+}
+
+.tips {
+}
+</style>

+ 49 - 42
src/main/h5/src/views/loginHome.vue

@@ -74,10 +74,45 @@ export default {
         message: "加载中...",
         forbidClick: true
       });
+      // this.$http
+      //   .post("/programme/getAuth", {
+      //     phone: this.ruleForm.phone,
+      //     id: this.$route.query.programmeId
+      //   })
+      //   .then(res => {
+      //     window.localStorage.setItem("loginPhone", res.phone);
+      //     if (res.token) {
+      //       window.localStorage.setItem("loginPhoneToken", res.token);
+      //       localStorage.setItem("token", res.token);
+      //       return this.$store.dispatch("getUserInfo");
+      //     } else {
+      //       return Promise.resolve();
+      //     }
+      //   })
+      //   .then(() => {
+      //     this.$toast.clear();
+      //     this.$router.replace({ path: "/home", query: this.$route.query });
+      //   })
+      //   .catch(e => {
+      //     if (e) {
+      //       this.$toast(e.error);
+      //       this.isSend = false;
+      //       this.ruleForm = {
+      //         phone: "",
+      //         code: ""
+      //       };
+      //     }
+      //   });
       this.$http
-        .post("/programme/getAuth", {
+        .get("/sms/verify", {
           phone: this.ruleForm.phone,
-          id: this.$route.query.programmeId
+          code: this.ruleForm.code
+        })
+        .then(() => {
+          return this.$http.post("/programme/getAuth", {
+            phone: this.ruleForm.phone,
+            id: this.$route.query.programmeId
+          });
         })
         .then(res => {
           window.localStorage.setItem("loginPhone", res.phone);
@@ -104,34 +139,6 @@ export default {
           }
         });
       // this.$http
-      //   .get("/sms/verify", {
-      //     phone: this.ruleForm.phone,
-      //     code: this.ruleForm.code
-      //   })
-      //   .then(() => {
-      //     return this.$http.post("/performanceApply/getAuth", {
-      //       phone: this.ruleForm.phone,
-      //       id: this.$route.query.performanceApplyId
-      //     });
-      //   })
-      //   .catch(e => {
-      //     this.$toast(e.error || "登录失败");
-      //     return Promise.reject();
-      //   })
-      //   .then(res => {
-      //     localStorage.setItem("token", res);
-      //     return this.$store.dispatch("getUserInfo");
-      //   })
-      //   .then(() => {
-      //     this.$toast.clear();
-      //     this.$router.replace({ path: "/" });
-      //   })
-      //   .catch(e => {
-      //     if (e) {
-      //       this.$toast(e.error);
-      //     }
-      //   });
-      // this.$http
       //   .post("/auth/phoneLogin", {
       //     phone: this.ruleForm.phone
       //   })
@@ -154,18 +161,18 @@ export default {
         return;
       }
 
-      // this.$http
-      //   .get("/sms/sendVerify", {
-      //     phone: this.ruleForm.phone
-      //   })
-      //   .then(res => {
-      //     this.$toast.success("发送成功");
-      this.isSend = true;
-      this.changeTime(60);
-      // })
-      // .catch(e => {
-      //   this.$toast(e.error);
-      // });
+      this.$http
+        .get("/sms/sendVerify", {
+          phone: this.ruleForm.phone
+        })
+        .then(res => {
+          this.$toast.success("发送成功");
+          this.isSend = true;
+          this.changeTime(60);
+        })
+        .catch(e => {
+          this.$toast(e.error);
+        });
     },
     changeTime(num) {
       this.num = num;

+ 30 - 0
src/main/java/com/izouma/wenlvju/domain/Announcement.java

@@ -0,0 +1,30 @@
+package com.izouma.wenlvju.domain;
+
+import com.izouma.wenlvju.enums.AnnouncementType;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.Where;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Builder
+@Where(clause = "del = 0")
+public class Announcement extends BaseEntity {
+    private String title;
+
+    @Enumerated(EnumType.STRING)
+    private AnnouncementType type;
+
+    @Column(columnDefinition = "TEXT")
+    private String content;
+}

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

@@ -162,6 +162,8 @@ public class Rate extends BaseEntity {
     @ApiModelProperty(value = "变更地址")
     private String changeAddress;
 
+    private String pdfUrl;
+
     public String getDetailAddress() {
         String str = "江苏省南京市" + this.district;
 

+ 152 - 0
src/main/java/com/izouma/wenlvju/domain/TrainingInstitution.java

@@ -0,0 +1,152 @@
+package com.izouma.wenlvju.domain;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.izouma.wenlvju.annotations.Searchable;
+import com.izouma.wenlvju.utils.excel.BooleanConverter;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Entity
+@ApiModel("培训机构")
+public class TrainingInstitution extends BaseEntity {
+    @Searchable
+    @ExcelProperty(value = "企业名称")
+    @ApiModelProperty("企业名称")
+    private String name;
+
+    @ExcelProperty(value = "注册号")
+    @ApiModelProperty("注册号")
+    private String uscc;
+
+    @ApiModelProperty(value = "是否从事文化艺术类校外培训")
+    @ExcelProperty(value = "是否从事文化艺术类校外培训", converter = BooleanConverter.class)
+    private boolean engagedInTraining;
+
+    @ExcelProperty(value = "经营范围")
+    @Column(columnDefinition = "TEXT")
+    @ApiModelProperty("经营范围")
+    private String businessScope;
+
+    @ExcelProperty(value = "企业住所")
+    @ApiModelProperty("企业住所")
+    private String address;
+
+    @ExcelProperty(value = "生产经营场所")
+    @ApiModelProperty("生产经营场所")
+    private String businessPremise;
+
+    @ExcelProperty(value = "法人姓名")
+    @ApiModelProperty(value = "法人姓名")
+    private String privacyPolicy;
+
+    @ExcelIgnore
+    @ApiModelProperty(value = "短信发送号码")
+    private String phone;
+
+    @ExcelProperty(value = "企业联系方式")
+    @ApiModelProperty(value = "企业联系方式")
+    private String contactPhone;
+
+    @ExcelProperty(value = "所属管区")
+    @ApiModelProperty(value = "所属管区")
+    private String district;
+
+    @ExcelProperty(value = "注册资本(万)")
+    @ApiModelProperty(value = "注册资本(万)")
+    private BigDecimal registeredCapital;
+
+    @ExcelProperty(value = "单位性质")
+    @ApiModelProperty(value = "单位性质")
+    private String category;
+
+    @ExcelProperty(value = "专业种类")
+    @ApiModelProperty(value = "专业种类")
+    private String specialty;
+
+    @ExcelProperty(value = "培训点数量三楼及以下")
+    @ApiModelProperty(value = "培训点数量三楼及以下")
+    private int trainingSite;
+
+    @ExcelProperty(value = "培训点数量四楼及以上")
+    @ApiModelProperty(value = "培训点数量四楼及以上")
+    private int trainingSiteFour;
+
+    @ExcelProperty(value = "总面积")
+    @ApiModelProperty(value = "总面积")
+    private double area;
+
+    @ExcelProperty(value = "教室数量")
+    @ApiModelProperty(value = "教室数量")
+    private int classroomNum;
+
+    @ExcelProperty(value = "教师总数")
+    @ApiModelProperty(value = "教师总数")
+    private int teacherNum;
+
+    @ExcelProperty(value = "专职数量")
+    @ApiModelProperty(value = "专职数量")
+    private int fullTimeNum;
+
+    @ExcelProperty(value = "兼职数量")
+    @ApiModelProperty(value = "兼职数量")
+    private int partTimeNum;
+
+    @ExcelProperty(value = "音乐类")
+    @ApiModelProperty(value = "音乐类")
+    private int musicNum;
+
+    @ExcelProperty(value = "舞蹈类")
+    @ApiModelProperty(value = "舞蹈类")
+    private int danceNum;
+
+    @ExcelProperty(value = "美术类")
+    @ApiModelProperty(value = "美术类")
+    private int artNum;
+
+    @ExcelProperty(value = "戏剧戏曲类")
+    @ApiModelProperty(value = "戏剧戏曲类")
+    private int theatreOperaNum;
+
+    @ExcelProperty(value = "曲艺类")
+    @ApiModelProperty(value = "曲艺类")
+    private int folkMusicNum;
+
+    @ExcelProperty(value = "有教师资格证")
+    @ApiModelProperty(value = "有教师资格证")
+    private int qualificationNum;
+
+    @ExcelProperty(value = "年培训人数")
+    @ApiModelProperty(value = "年培训人数")
+    private long traineesPerYearNum;
+
+    @ExcelProperty(value = "是否是艺术水平考级考点", converter = BooleanConverter.class)
+    @ApiModelProperty(value = "是否是艺术水平考级考点")
+    private boolean examPoint;
+
+    @ExcelProperty(value = "艺术水平考级机构名称")
+    @ApiModelProperty(value = "艺术水平考级机构名称")
+    private String gradingOrganization;
+
+    @ExcelProperty(value = "备注")
+    @Column(columnDefinition = "TEXT")
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    private boolean submit;
+
+    private LocalDateTime firstWrite;
+}

+ 2 - 0
src/main/java/com/izouma/wenlvju/domain/performance/Participant.java

@@ -21,6 +21,8 @@ import java.time.LocalDate;
 @ApiModel(value = "参演人员")
 @Where(clause = "del = 0")
 public class Participant extends BaseEntity {
+    private Long performanceId;
+
     private Long programmeId;
 
     @ApiModelProperty(value = "姓名")

+ 2 - 0
src/main/java/com/izouma/wenlvju/domain/performance/Performance.java

@@ -72,6 +72,8 @@ public class Performance extends BaseEntity {
     @ApiModelProperty(value = "复审比例")
     private BigDecimal reviewRatio;
 
+    private boolean close;
+
     @Transient
     private long programmeNum;
 }

+ 25 - 18
src/main/java/com/izouma/wenlvju/dto/ProgrammeShowDTO.java

@@ -4,72 +4,79 @@ import cn.hutool.core.bean.BeanUtil;
 import com.alibaba.excel.annotation.ExcelIgnore;
 import com.alibaba.excel.annotation.ExcelProperty;
 import com.izouma.wenlvju.annotations.EnumFormat;
-import com.izouma.wenlvju.domain.performance.Participant;
 import com.izouma.wenlvju.domain.performance.Programme;
 import com.izouma.wenlvju.enums.CompetitionGroup;
+import com.izouma.wenlvju.enums.ProgrammeStatus;
 import com.izouma.wenlvju.utils.excel.EnumExcelConverter;
-import com.izouma.wenlvju.utils.excel.LocalDateConverter;
-import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
-import java.time.LocalDate;
 import java.util.List;
 
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class ProgrammeShowDTO {
+    @ExcelProperty(value = "节目编号")
     private Long id;
 
-    @ApiModelProperty(value = "活动名称")
+    @ExcelIgnore
     private String performance;
 
-    @ApiModelProperty(value = "节目名称")
+    @ExcelProperty(value = "节目名称")
     private String name;
 
-    @ApiModelProperty(value = "参赛专业")
+    @ExcelProperty(value = "参赛专业")
     private String specialty;
 
-    @ApiModelProperty(value = "参赛组别")
+    @EnumFormat(value = CompetitionGroup.class,
+            fromExcel = {"个人", "集体"},
+            toJavaEnum = {"SINGLE", "COLLECTIVE"})
+    @ExcelProperty(value = "参赛组别", converter = EnumExcelConverter.class)
+    @Enumerated(EnumType.STRING)
     private CompetitionGroup competitionGroup;
 
-    @ApiModelProperty(value = "参赛级别")
+    @ExcelProperty(value = "参赛级别")
     private String level;
 
-    @ApiModelProperty(value = "作品时长")
+    @ExcelProperty(value = "作品时长")
     private int durationOfWork;
 
-    @ApiModelProperty(value = "指导老师")
+    @ExcelProperty(value = "指导老师")
     private String instructor;
 
-    @ApiModelProperty(value = "考级机构")
+    @ExcelProperty(value = "考级机构")
     private String gradingOrganization;
 
-    @ApiModelProperty(value = "承办单位")
+    @ExcelProperty(value = "承办单位")
     private String organization;
 
-    @ApiModelProperty(value = "考级点")
+    @ExcelProperty(value = "考级点")
     private String examPoint;
 
-    @ApiModelProperty(value = "联系人")
+    @ExcelProperty(value = "联系人")
     private String contact;
 
-    @ApiModelProperty(value = "参赛人数")
+    @ExcelProperty(value = "参赛人数")
     private int quantity;
 
-    @ApiModelProperty(value = "评分")
+    @ExcelProperty(value = "评分")
     private Double score;
 
+    @ExcelIgnore
     private String video;
 
+    @ExcelIgnore
     private String annex;
 
+    @ExcelIgnore
+    private ProgrammeStatus programmeStatus;
+
+    @ExcelIgnore
     private List<ParticipantDTO> participants;
 
     public ProgrammeShowDTO(Programme programme) {

+ 2 - 0
src/main/java/com/izouma/wenlvju/dto/RateDTO.java

@@ -88,6 +88,8 @@ public class RateDTO {
     @ApiModelProperty(value = "等级")
     private String grade;
 
+    private int sort;
+
     @ExcelIgnore
     @ApiModelProperty(value = "驳回时间")
     private LocalDateTime rejectedAt;

+ 45 - 0
src/main/java/com/izouma/wenlvju/dto/TrainingInstitutionDTO.java

@@ -0,0 +1,45 @@
+package com.izouma.wenlvju.dto;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.izouma.wenlvju.domain.TrainingInstitution;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@ApiModel("培训机构")
+public class TrainingInstitutionDTO {
+    @ExcelProperty(value = "编号")
+    private Long id;
+
+    @ExcelProperty(value = "企业名称")
+    @ApiModelProperty("企业名称")
+    private String name;
+
+    @ExcelProperty(value = "注册号")
+    @ApiModelProperty("注册号")
+    private String uscc;
+
+    @ExcelProperty(value = "法人姓名")
+    @ApiModelProperty(value = "法人姓名")
+    private String privacyPolicy;
+
+    @ExcelProperty(value = "固定电话")
+    @ApiModelProperty(value = "固定电话")
+    private String contactPhone;
+
+    @ExcelProperty(value = "移动电话")
+    @ApiModelProperty(value = "移动电话")
+    private String phone;
+
+    public TrainingInstitutionDTO(TrainingInstitution trainingInstitution) {
+        BeanUtil.copyProperties(trainingInstitution, this);
+    }
+}

+ 12 - 0
src/main/java/com/izouma/wenlvju/enums/AnnouncementType.java

@@ -0,0 +1,12 @@
+package com.izouma.wenlvju.enums;
+
+public enum AnnouncementType {
+    /**
+     * 通知
+     */
+    NOTIFICATION,
+    /**
+     * 政策
+     */
+    POLICY
+}

+ 26 - 0
src/main/java/com/izouma/wenlvju/enums/GradingOrganizationDTO.java

@@ -0,0 +1,26 @@
+package com.izouma.wenlvju.enums;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.izouma.wenlvju.domain.BaseEntity;
+import com.izouma.wenlvju.domain.GradingOrganization;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel(value = "考级机构")
+public class GradingOrganizationDTO extends BaseEntity {
+    @ExcelProperty(value = "编号")
+    private Long id;
+
+    @ExcelProperty(value = "名称")
+    private String name;
+
+    public GradingOrganizationDTO(GradingOrganization gradingOrganization) {
+        BeanUtil.copyProperties(gradingOrganization, this);
+    }
+}

+ 16 - 0
src/main/java/com/izouma/wenlvju/repo/AnnouncementRepo.java

@@ -0,0 +1,16 @@
+package com.izouma.wenlvju.repo;
+
+import com.izouma.wenlvju.domain.Announcement;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+
+public interface AnnouncementRepo extends JpaRepository<Announcement, Long>, JpaSpecificationExecutor<Announcement> {
+    @Query("update Announcement t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+}

+ 3 - 0
src/main/java/com/izouma/wenlvju/repo/RateRepo.java

@@ -30,4 +30,7 @@ public interface RateRepo extends JpaRepository<Rate, Long>, JpaSpecificationExe
 
     @Query(nativeQuery = true, value = "select count(1) from rate where del=0 and (expert_user_id = ?1 or find_in_set(?1,expert_member_user_id))")
     Long countByExpertId(Long userId);
+
+    List<Rate> findAllByStatusAndYearOrderByScoreDesc(RateStatus status, String year);
+
 }

+ 30 - 0
src/main/java/com/izouma/wenlvju/repo/TrainingInstitutionRepo.java

@@ -0,0 +1,30 @@
+package com.izouma.wenlvju.repo;
+
+import com.izouma.wenlvju.domain.TrainingInstitution;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+import javax.transaction.Transactional;
+import java.util.List;
+
+public interface TrainingInstitutionRepo extends JpaRepository<TrainingInstitution, Long>, JpaSpecificationExecutor<TrainingInstitution> {
+    @Query("update TrainingInstitution t set t.del = true where t.id = ?1")
+    @Modifying
+    @Transactional
+    void softDelete(Long id);
+
+    @Query(nativeQuery = true, value = "select DISTINCT phone from training_institution where submit = false and phone REGEXP '^[1][356789][0-9]{9}$'")
+    List<String> findAllBySubmitFalseAndPhoneIsNotNull();
+
+    @Query(nativeQuery = true, value = "select DISTINCT phone from training_institution where submit = false and phone REGEXP '^[1][356789][0-9]{9}$' limit 2000,2000")
+    List<String> findAllBySubmitFalseAndPhoneIsNotNullLimit();
+
+    List<TrainingInstitution> findAllByPhoneIsNull();
+
+    @Query(nativeQuery = true, value = "select name from training_institution where name like ?1 limit ?2,?3")
+    List<String> findAllByNameLike(String name, int page, int size);
+
+    TrainingInstitution findByUscc(String uscc);
+}

+ 7 - 0
src/main/java/com/izouma/wenlvju/repo/performance/ParticipantRepo.java

@@ -16,7 +16,14 @@ public interface ParticipantRepo extends JpaRepository<Participant, Long>, JpaSp
     @Transactional
     void softDelete(Long id);
 
+    @Query("update Participant t set t.del = true where t.programmeId = ?1")
+    @Modifying
+    @Transactional
+    void softDeleteProgrammeId(Long programmeId);
+
     List<Participant> findAllByProgrammeIdIn(Collection<Long> ids);
 
     List<Participant> findAllByProgrammeId(Long id);
+
+    List<Participant> findByIdNoAndPerformanceId(String idNo, Long performanceId);
 }

+ 4 - 0
src/main/java/com/izouma/wenlvju/security/WebSecurityConfig.java

@@ -71,8 +71,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/district/NJ").permitAll()
                 .antMatchers("/setting/byFlag").permitAll()
                 .antMatchers("/programme/getShow/**").permitAll()
+                .antMatchers("/programme/excelGO").permitAll()
+                .antMatchers("/programme/showAll").permitAll()
                 .antMatchers("/programme/getAuth").permitAll()
                 .antMatchers("/programme/getScore/**").permitAll()
+                .antMatchers("/organization/byName").permitAll()
                 .antMatchers("/programmeScore/breakdown").permitAll()
                 .antMatchers("/participant/byProgramme").permitAll()
                 .antMatchers("/upload/**").permitAll()
@@ -81,6 +84,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/auth/**").permitAll()
                 .antMatchers("/captcha/**").permitAll()
                 .antMatchers("/admin/**").permitAll()
+                .antMatchers("/trainingInstitution/**").permitAll()
                 .antMatchers("/systemVariable/all").permitAll()
                 .antMatchers("/**/excel").permitAll()
                 .antMatchers("/wx/**").permitAll()

+ 20 - 0
src/main/java/com/izouma/wenlvju/service/AnnouncementService.java

@@ -0,0 +1,20 @@
+package com.izouma.wenlvju.service;
+
+import com.izouma.wenlvju.domain.Announcement;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.repo.AnnouncementRepo;
+import com.izouma.wenlvju.utils.JpaUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+@Service
+@AllArgsConstructor
+public class AnnouncementService {
+
+    private AnnouncementRepo announcementRepo;
+
+    public Page<Announcement> all(PageQuery pageQuery) {
+        return announcementRepo.findAll(JpaUtils.toSpecification(pageQuery, Announcement.class), JpaUtils.toPageRequest(pageQuery));
+    }
+}

+ 19 - 25
src/main/java/com/izouma/wenlvju/service/RateExpertAuditService.java

@@ -2,16 +2,12 @@ package com.izouma.wenlvju.service;
 
 import cn.hutool.core.util.ObjectUtil;
 import com.izouma.wenlvju.domain.Rate;
-import com.izouma.wenlvju.domain.RateAudit;
 import com.izouma.wenlvju.domain.RateExpertAudit;
 import com.izouma.wenlvju.dto.PageQuery;
-import com.izouma.wenlvju.enums.OrganizationGrade;
 import com.izouma.wenlvju.enums.RateStatus;
 import com.izouma.wenlvju.exception.BusinessException;
-import com.izouma.wenlvju.repo.RateAuditRepo;
 import com.izouma.wenlvju.repo.RateExpertAuditRepo;
 import com.izouma.wenlvju.repo.RateRepo;
-import com.izouma.wenlvju.service.sms.NjwlSmsService;
 import com.izouma.wenlvju.utils.JpaUtils;
 import com.izouma.wenlvju.utils.ObjUtils;
 import lombok.AllArgsConstructor;
@@ -26,8 +22,6 @@ public class RateExpertAuditService {
 
     private final RateExpertAuditRepo rateExpertAuditRepo;
     private final RateRepo            rateRepo;
-    private final NjwlSmsService      njwlSmsService;
-    private final RateAuditRepo       rateAuditRepo;
 
     public Page<RateExpertAudit> all(PageQuery pageQuery) {
         return rateExpertAuditRepo.findAll(JpaUtils.toSpecification(pageQuery, RateExpertAudit.class), JpaUtils.toPageRequest(pageQuery));
@@ -53,30 +47,30 @@ public class RateExpertAuditService {
         });
     }
 
-    public void grade(Long rateId, Long userId) {
+    public void grade(Long rateId) {
         List<RateExpertAudit> audits = rateExpertAuditRepo.findAllByRateId(rateId);
         int sum = audits.stream().mapToInt(RateExpertAudit::getExpertScore).sum();
-        OrganizationGrade grade;
-        if (sum >= 40) {
-            grade = OrganizationGrade.EXCELLENT;
-        } else if (sum >= 20) {
-            grade = OrganizationGrade.ELIGIBLE;
-        } else {
-            grade = OrganizationGrade.NOT_ELIGIBLE;
-        }
+//        OrganizationGrade grade;
+//        if (sum >= 40) {
+//            grade = OrganizationGrade.EXCELLENT;
+//        } else if (sum >= 20) {
+//            grade = OrganizationGrade.ELIGIBLE;
+//        } else {
+//            grade = OrganizationGrade.NOT_ELIGIBLE;
+//        }
         Rate rate = rateRepo.findById(rateId).orElseThrow(new BusinessException("无申请"));
         rate.setScore(sum + 40);
-        rate.setGrade(grade);
-        rate.setStatus(RateStatus.SUBMIT_PAPER_MATERIALS);
+//        rate.setGrade(grade);
+        rate.setStatus(RateStatus.SUBMIT_GRADE);
         rateRepo.save(rate);
-        RateAudit rateAudit = RateAudit.builder()
-                .userId(userId)
-                .rateId(rateId)
-                .remark("市政管理员已评审完成,请你单位在5个工作日内将纸质申请材料(2份)送属地区文化行政主管部门。")
-                .status(RateStatus.SUBMIT_PAPER_MATERIALS.toString())
-                .build();
-        rateAuditRepo.save(rateAudit);
+//        RateAudit rateAudit = RateAudit.builder()
+//                .userId(userId)
+//                .rateId(rateId)
+//                .remark("市政管理员已评审完成,请你单位在5个工作日内将纸质申请材料(2份)送属地区文化行政主管部门。")
+//                .status(RateStatus.SUBMIT_PAPER_MATERIALS.toString())
+//                .build();
+//        rateAuditRepo.save(rateAudit);
         // 市区评分发送短信
-        njwlSmsService.sendSms(rate.getOwnerPhone(), "请你单位在5个工作日内将纸质申请材料(2份)送属" + rate.getDistrict() + "文化和旅游局文化行政主管部门,期不送,作自动放弃处理。");
+//        njwlSmsService.sendSms(rate.getOwnerPhone(), "请你单位在5个工作日内将纸质申请材料(2份)送属" + rate.getDistrict() + "文化和旅游局文化行政主管部门,期不送,作自动放弃处理。");
     }
 }

+ 211 - 22
src/main/java/com/izouma/wenlvju/service/RateService.java

@@ -9,11 +9,13 @@ import com.izouma.wenlvju.domain.*;
 import com.izouma.wenlvju.dto.PageQuery;
 import com.izouma.wenlvju.dto.ReviewTime;
 import com.izouma.wenlvju.enums.AuthorityName;
+import com.izouma.wenlvju.enums.OrganizationGrade;
 import com.izouma.wenlvju.enums.RateStatus;
 import com.izouma.wenlvju.exception.BusinessException;
 import com.izouma.wenlvju.repo.*;
 import com.izouma.wenlvju.security.Authority;
 import com.izouma.wenlvju.service.sms.NjwlSmsService;
+import com.izouma.wenlvju.utils.FileUtils;
 import com.izouma.wenlvju.utils.JpaUtils;
 import com.izouma.wenlvju.utils.ObjUtils;
 import com.lowagie.text.Document;
@@ -28,6 +30,8 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.pdfbox.io.MemoryUsageSetting;
 import org.apache.pdfbox.multipdf.PDFMergerUtility;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.domain.Page;
 import org.springframework.stereotype.Service;
 
@@ -44,16 +48,25 @@ import java.util.stream.Collectors;
 
 @Service
 @Slf4j
-@AllArgsConstructor
+//@AllArgsConstructor
 public class RateService {
 
-    private final RateRepo                rateRepo;
-    private final CollaborateRepo         collaborateRepo;
-    private final GradingOrganizationRepo gradingOrganizationRepo;
-    private final RateAuditRepo           rateAuditRepo;
-    private final UserRepo                userRepo;
-    private final NjwlSmsService          njwlSmsService;
-    private final OrganizationRepo        organizationRepo;
+    @Autowired
+    private RateRepo                rateRepo;
+    @Autowired
+    private CollaborateRepo         collaborateRepo;
+    @Autowired
+    private GradingOrganizationRepo gradingOrganizationRepo;
+    @Autowired
+    private RateAuditRepo           rateAuditRepo;
+    @Autowired
+    private UserRepo                userRepo;
+    @Autowired
+    private NjwlSmsService          njwlSmsService;
+    @Autowired
+    private OrganizationRepo        organizationRepo;
+    @Value("${storage.local_path}")
+    private String                  localPath;
 
     public Page<Rate> all(PageQuery pageQuery) {
         return rateRepo.findAll(JpaUtils.toSpecification(pageQuery, Rate.class), JpaUtils.toPageRequest(pageQuery));
@@ -227,11 +240,17 @@ public class RateService {
                 .status(status.toString())
                 .build();
         rateAuditRepo.save(rateAudit);
-        if (RateStatus.COMPLETE.equals(status)) {
-            njwlSmsService.sendSms(rate.getOwnerPhone(), "等级评定结果公告已发布,请在南京市文化和旅游局官方网站(http://wlj.nanjing.gov.cn/)上查询。");
-        }
+//        if (RateStatus.COMPLETE.equals(status)) {
+//            njwlSmsService.sendSms(rate.getOwnerPhone(), "等级评定结果公告已发布,请在南京市文化和旅游局官方网站(http://wlj.nanjing.gov.cn/)上查询。");
+//        }
     }
 
+    /**
+     * 生成word模版
+     *
+     * @param rate
+     * @return
+     */
     public String export(Rate rate) {
         Map<String, Object> dataMap = new HashMap<>();
         try {
@@ -249,6 +268,7 @@ public class RateService {
             //承办过
             dataMap.put("undertake", rate.isUndertakeExamination() ? "是" : "否");
             //考级机构名称
+            dataMap.put("examination", "");
             Set<Long> ids = collaborateRepo.findAllByRateId(rate.getId())
                     .stream()
                     .map(Collaborate::getGradingOrganizationId)
@@ -263,6 +283,9 @@ public class RateService {
 
             //单位概况
             dataMap.put("introduction", rate.getIntroduction());
+            //等级
+            dataMap.put("grade", rate.getGrade().getDesc());
+
             //Configuration 用于读取ftl文件
             Configuration configuration = new Configuration(new Version("2.3.0"));
 
@@ -290,7 +313,12 @@ public class RateService {
         this.addList(imageUrllist, rate.getFinance());
         this.addList(imageUrllist, rate.getProperty());
 
-        String filename = "img.pdf";
+        if (CollUtil.isEmpty(imageUrllist)) {
+            return;
+        }
+
+        String filename = "img" + UUID.randomUUID() + ".pdf";
+        File file = null;
 
         Document doc = new Document(PageSize.A4, 20, 20, 20, 20);
         try {
@@ -308,10 +336,13 @@ public class RateService {
                 png1.setAlignment(Image.MIDDLE);
                 png1.scalePercent(percent + 3);// 表示是原来图像的比例;
                 doc.add(png1);
+
+
             }
 //            b = os.toByteArray();
 
-            File file = new File(filename);
+            file = new File(filename);
+
             InputStream is = new FileInputStream(file);
             files.add(is);
 
@@ -319,6 +350,7 @@ public class RateService {
             e.printStackTrace();
         } finally {
             doc.close();
+            FileUtils.delFiles(file);
         }
     }
 
@@ -376,15 +408,35 @@ public class RateService {
         urls.forEach(privacy -> {
             num.getAndIncrement();
             if ("doc".equals(getSuffix(privacy)) || "docx".equals(getSuffix(privacy))) {
-                InputStream is1 = HttpRequest.get(privacy)
-                        .stream();
+                InputStream is1;
+                if (privacy.contains("http")) {
+                    is1 = HttpRequest.get(privacy)
+                            .stream();
+                } else {
+                    try {
+                        is1 = new FileInputStream(privacy);
+                    } catch (FileNotFoundException e) {
+                        throw new BusinessException("找不到文件");
+                    }
+                }
                 InputStream stream = HttpRequest.post("http://convert.izouma.com/word2pdf")
                         .accept("*/*")
                         .part("file", "审核材料.docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", is1)
                         .stream();
                 files.add(stream);
             } else if ("pdf".equals(getSuffix(privacy))) {
-                InputStream stream = HttpRequest.get(privacy).stream();
+                InputStream stream;
+                if (privacy.contains("http")) {
+                    stream = HttpRequest.get(privacy)
+                            .stream();
+                } else {
+                    try {
+                        stream = new FileInputStream(privacy);
+                    } catch (FileNotFoundException e) {
+                        throw new BusinessException("找不到文件");
+                    }
+                }
+//                InputStream stream = HttpRequest.get(privacy).stream();
                 files.add(stream);
             }
         });
@@ -433,11 +485,17 @@ public class RateService {
         return url.substring(index + 1);
     }
 
-    public void exportPdf(Long id, HttpServletResponse response) throws IOException {
+    /**
+     * 合并并下载pdf
+     *
+     * @param id
+     * @param response
+     * @throws IOException
+     */
+    public void exportPdf1(Long id, HttpServletResponse response) throws IOException {
         Rate rate = rateRepo.findById(id).orElseThrow(new BusinessException("无记录"));
         List<InputStream> files = this.upLoad1(rate);
 
-
         // pdf合并工具类
         PDFMergerUtility mergePdf = new PDFMergerUtility();
         mergePdf.addSources(files);
@@ -448,10 +506,6 @@ public class RateService {
 
         mergePdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
 
-        // 设置合并生成pdf文件名称
-//        String targetPath = "/Users/qiufangchao/Desktop/result.pdf";
-//        mergePdf.setDestinationFileName(targetPath);
-
         for (InputStream is : files) {
             is.close();
         }
@@ -466,6 +520,76 @@ public class RateService {
         outputStream.close();
     }
 
+    /**
+     * 下载pdf
+     *
+     * @param id
+     * @param response
+     * @throws IOException
+     */
+    public byte[] exportPdf(Long id, HttpServletResponse response) throws IOException {
+        Rate rate = rateRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+
+        // 设置response的Header
+        response.setContentType("application/pdf");
+        response.addHeader("Content-Disposition", "attachment;filename=" + "result.pdf");
+
+        String pdfUrl = rate.getPdfUrl();
+
+        int start = pdfUrl.indexOf("/pdf");
+        String end = pdfUrl.substring(start + 1);
+        File file = new File(localPath + end);
+
+        // 以流的形式下载文件。
+        InputStream fis = new BufferedInputStream(new FileInputStream(file));
+        byte[] buffer = new byte[fis.available()];
+
+        fis.read(buffer);
+        fis.close();
+
+        //删除文件
+        FileUtils.delFiles(file);
+        return buffer;
+
+//        OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
+//        toClient.write(buffer);
+//        toClient.flush();
+//        toClient.close();
+
+    }
+
+    /**
+     * 合并pdf
+     *
+     * @param rate
+     * @throws IOException
+     */
+    public void mergePdf(Rate rate) throws IOException {
+        List<InputStream> files = this.upLoad1(rate);
+
+        String targetPath = "/Users/qiufangchao/Desktop/rate/material" + rate.getId() + ".pdf";
+        // pdf合并工具类
+        PDFMergerUtility mergePdf = new PDFMergerUtility();
+
+        mergePdf.addSources(files);
+        // 设置合并生成pdf文件名称
+        mergePdf.setDestinationFileName(targetPath);
+        try {
+            mergePdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
+            for (InputStream is : files) {
+                is.close();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 选专家发消息
+     *
+     * @param rate
+     * @return
+     */
     public Map<String, String> reviewTimesMessage(Rate rate) {
         List<Long> ids = new ArrayList<>(rate.getExpertMemberUserId());
         ids.add(rate.getExpertUserId());
@@ -606,4 +730,69 @@ public class RateService {
         map.put("phone", phone);
         return map;
     }
+
+    /**
+     * 发短信
+     *
+     * @param announcement 是否公告短信
+     */
+    public void batchSendSms(boolean announcement) {
+        List<Rate> rates = rateRepo.findAllByStatusAndYearOrderByScoreDesc(RateStatus.SUBMIT_PAPER_MATERIALS, String.valueOf(LocalDate.now()
+                .getYear()));
+        String phones = rates.stream().map(Rate::getOwnerPhone).collect(Collectors.joining(","));
+
+        if (announcement) {
+            njwlSmsService.sendSms(phones, "等级评定结果公告已发布,请在南京市文化和旅游局官方网站(http://wlj.nanjing.gov.cn/)上查询。");
+        } else {
+            njwlSmsService.sendSms(phones, "【宁艺通】2021年南京考级承办单位等级评定工作已完成,拟评定结果已在南京市文化和旅游局官网公示。请你单位登陆“宁艺通”等级评定系统下载打印等级评定材料,并于11月15日前将纸质申报表及完整佐证材料(各2份)送属地区文化和旅游局履行线下审核程序,逾期不送,作自动放弃处理。");
+        }
+    }
+
+    /**
+     * 等级
+     */
+    public void gradeRatio(double excellent, double eligible, Long userId) {
+        List<Rate> rates = rateRepo.findAllByStatusAndYearOrderByScoreDesc(RateStatus.SUBMIT_GRADE, String.valueOf(LocalDate.now()
+                .getYear()));
+//        rates.sort((a, b) -> Integer.compare(b.getScore(), a.getSort()));
+        int size = rates.size();
+        int excellentSum = (int) Math.round(size * excellent / 100);
+        if (excellentSum >= size) {
+            rates.forEach(rate -> {
+                rate.setGrade(OrganizationGrade.EXCELLENT);
+                rate.setStatus(RateStatus.SUBMIT_PAPER_MATERIALS);
+                RateAudit rateAudit = RateAudit.builder()
+                        .userId(userId)
+                        .rateId(rate.getId())
+                        .remark("市政管理员已评审完成,请你单位在5个工作日内将纸质申请材料(2份)送属地区文化行政主管部门。")
+                        .status(RateStatus.SUBMIT_PAPER_MATERIALS.toString())
+                        .build();
+                rateAuditRepo.save(rateAudit);
+            });
+            rateRepo.saveAll(rates);
+            return;
+        }
+
+        int eligibleSum = (int) Math.round(size * eligible / 100);
+        int total = eligibleSum + excellentSum;
+        for (int i = 0; i < size; i++) {
+            Rate rate = rates.get(i);
+            if (i < excellentSum) {
+                rate.setGrade(OrganizationGrade.EXCELLENT);
+            } else if (i < total) {
+                rate.setGrade(OrganizationGrade.ELIGIBLE);
+            } else {
+                rate.setGrade(OrganizationGrade.NOT_ELIGIBLE);
+            }
+            rate.setStatus(RateStatus.SUBMIT_PAPER_MATERIALS);
+            RateAudit rateAudit = RateAudit.builder()
+                    .userId(userId)
+                    .rateId(rate.getId())
+                    .remark("市政管理员已评审完成,请你单位在5个工作日内将纸质申请材料(2份)送属地区文化行政主管部门。")
+                    .status(RateStatus.SUBMIT_PAPER_MATERIALS.toString())
+                    .build();
+            rateAuditRepo.save(rateAudit);
+        }
+        rateRepo.saveAll(rates);
+    }
 }

+ 98 - 0
src/main/java/com/izouma/wenlvju/service/TrainingInstitutionService.java

@@ -0,0 +1,98 @@
+package com.izouma.wenlvju.service;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.EasyExcel;
+import com.izouma.wenlvju.domain.TrainingInstitution;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.dto.TrainingInstitutionDTO;
+import com.izouma.wenlvju.exception.BusinessException;
+import com.izouma.wenlvju.repo.TrainingInstitutionRepo;
+import com.izouma.wenlvju.service.sms.NjwlSmsService;
+import com.izouma.wenlvju.utils.JpaUtils;
+import com.izouma.wenlvju.utils.excel.UploadDataListener;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.transaction.Transactional;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+@AllArgsConstructor
+public class TrainingInstitutionService {
+
+    private TrainingInstitutionRepo trainingInstitutionRepo;
+    private NjwlSmsService          njwlSmsService;
+
+    public Page<TrainingInstitution> all(PageQuery pageQuery) {
+        return trainingInstitutionRepo.findAll(JpaUtils.toSpecification(pageQuery, TrainingInstitution.class), JpaUtils.toPageRequest(pageQuery));
+    }
+
+    public void batchSend(List<String> phones) throws InterruptedException {
+
+        int count = phones.size() / 980;
+        String body = "尊敬的调研对象:\n" +
+                "您好,为贯彻落实国家、省、市关于“双减”工作相关文件精神,了解和掌握我市文化艺术类校外培训机构相关情况,市文旅局决定开展全市文化艺术类校外培训机构网上问卷调查,如从事文化艺术类校外培训,请登录:http://wljtest.izouma.com/h5/trainingInstitution,填写调查问卷,如不从事文化艺术类校外培训,请忽略本条信息,谢谢。\n";
+        for (int i = 0; i <= count; i++) {
+            int start = i * 980;
+            int end = start + 980;
+            if (end > phones.size()) {
+                end = phones.size();
+            }
+            List<String> result = phones.subList(start, end);
+            String sendPhone = String.join(",", result);
+//            System.out.println(sendPhone);
+            njwlSmsService.sendSms(sendPhone, body);
+//            System.out.println("start:" + start + ",end:" + end);
+            // 睡眠5分钟
+            Thread.sleep(2 * 60 * 1000);
+        }
+
+    }
+
+    @Transactional(rollbackOn = Exception.class)
+    public void upload(MultipartFile file) throws IOException, InterruptedException {
+        UploadDataListener<TrainingInstitutionDTO> listener = new UploadDataListener<>();
+        List<TrainingInstitutionDTO> dtos = EasyExcel.read(file.getInputStream(), TrainingInstitutionDTO.class, listener)
+                .sheet()
+                .doReadSync();
+        List<Long> ids = dtos.stream().map(TrainingInstitutionDTO::getId).collect(Collectors.toList());
+        List<TrainingInstitution> all = trainingInstitutionRepo.findAllById(ids);
+        Map<Long, TrainingInstitution> tiMap = all
+                .stream()
+                .collect(Collectors.toMap(TrainingInstitution::getId, trainingInstitution -> trainingInstitution));
+
+        dtos.forEach(dto -> {
+            TrainingInstitution trainingInstitution = tiMap.get(dto.getId());
+            if (ObjectUtil.isNotNull(trainingInstitution)) {
+                trainingInstitution.setPhone(dto.getPhone());
+                trainingInstitutionRepo.save(trainingInstitution);
+            }
+        });
+
+        // 发送短信
+        this.batchSend(dtos.stream().map(TrainingInstitutionDTO::getPhone).collect(Collectors.toList()));
+
+    }
+
+    public List<String> byName(PageQuery pageQuery) {
+        String name = "%" + pageQuery.getSearch() + "%";
+        PageRequest pageRequest = JpaUtils.toPageRequest(pageQuery);
+        return trainingInstitutionRepo.findAllByNameLike(name, pageRequest.getPageNumber(), pageRequest.getPageSize());
+    }
+
+    public TrainingInstitution byUscc(String name, String uscc) {
+        TrainingInstitution byUscc = trainingInstitutionRepo.findByUscc(uscc.trim());
+        if (ObjectUtil.isNotNull(byUscc)) {
+            if (byUscc.getName().equals(name.trim())) {
+                return byUscc;
+            }
+        }
+        throw new BusinessException("企业名称或税号不正确");
+    }
+}

+ 25 - 0
src/main/java/com/izouma/wenlvju/service/UserService.java

@@ -5,6 +5,7 @@ import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.izouma.wenlvju.config.Constants;
 import com.izouma.wenlvju.domain.*;
 import com.izouma.wenlvju.domain.performance.Participant;
@@ -365,4 +366,28 @@ public class UserService {
         map.put("token", token);
         return map;
     }
+
+    public String byPhone(String account) {
+        User user = userRepo.findByUsernameAndDelFalse(account);
+        if (ObjectUtil.isNotNull(user)) {
+            return account;
+        }
+        User byPhone = userRepo.findByPhoneAndDelFalse(account);
+        if (ObjectUtil.isNotNull(byPhone)) {
+            return byPhone.getUsername();
+        }
+        return null;
+    }
+
+    public void forgetPassword(String name, String phone, String password) {
+        User user = userRepo.findByPhoneAndDelFalse(phone);
+        if (ObjectUtil.isNull(user)) {
+            throw new BusinessException("此手机号并未注册!");
+        }
+        if (StrUtil.isEmpty(name) || !user.getWork().contains(name.trim())) {
+            throw new BusinessException("企业名称不正确");
+        }
+        user.setPassword(new BCryptPasswordEncoder().encode(password));
+        userRepo.save(user);
+    }
 }

+ 23 - 0
src/main/java/com/izouma/wenlvju/service/performance/ParticipantService.java

@@ -1,5 +1,7 @@
 package com.izouma.wenlvju.service.performance;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import com.izouma.wenlvju.domain.performance.Participant;
 import com.izouma.wenlvju.dto.PageQuery;
 import com.izouma.wenlvju.exception.BusinessException;
@@ -27,9 +29,30 @@ public class ParticipantService {
             if (participant.getId() != null) {
                 Participant orig = participantRepo.findById(participant.getId())
                         .orElseThrow(new BusinessException("无记录"));
+
+                if (!participant.isDel() && StrUtil.isNotEmpty(participant.getIdNo())) {
+                    List<Participant> byIdNo = participantRepo.findByIdNoAndPerformanceId(participant.getIdNo(), participant.getPerformanceId());
+                    if (CollUtil.isNotEmpty(byIdNo)) {
+                        if (byIdNo.size() > 1) {
+                            throw new BusinessException("一人只能报一个节目");
+                        } else {
+                            if (!byIdNo.get(0).getId().equals(participant.getId())) {
+                                throw new BusinessException("一人只能报一个节目");
+                            }
+                        }
+                    }
+                }
+
                 ObjUtils.merge(orig, participant);
                 participantRepo.save(orig);
             } else {
+                if (StrUtil.isNotEmpty(participant.getIdNo())) {
+                    List<Participant> byIdNo = participantRepo.findByIdNoAndPerformanceId(participant.getIdNo(), participant.getPerformanceId());
+                    if (CollUtil.isNotEmpty(byIdNo)) {
+                        throw new BusinessException("一人只能报一个节目");
+                    }
+                }
+
                 participantRepo.save(participant);
             }
         });

+ 184 - 119
src/main/java/com/izouma/wenlvju/service/performance/ProgrammeService.java

@@ -40,12 +40,13 @@ import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
 import javax.transaction.Transactional;
 import java.io.*;
-import java.math.BigDecimal;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 @Service
@@ -98,9 +99,9 @@ public class ProgrammeService {
             if (ProgrammeStatus.INITIAL.equals(orig.getProgrammeStatus())) {
                 Performance performance = performanceRepo.findById(orig.getPerformanceId())
                         .orElseThrow(new BusinessException("无展演活动"));
-                if (LocalDate.now().isAfter(performance.getEndDate())) {
-                    throw new BusinessException("活动已报名结束!");
-                }
+//                if (LocalDate.now().isAfter(performance.getEndDate())) {
+//                    throw new BusinessException("活动已报名结束!");
+//                }
             }
             ObjUtils.merge(orig, record);
             orig.setParentSpecialtyId(artTypeService.getParent(orig.getSpecialtyId()));
@@ -108,9 +109,9 @@ public class ProgrammeService {
         } else {
             Performance performance = performanceRepo.findById(record.getPerformanceId())
                     .orElseThrow(new BusinessException("无展演活动"));
-            if (LocalDate.now().isAfter(performance.getEndDate())) {
-                throw new BusinessException("活动已报名结束!");
-            }
+//            if (LocalDate.now().isAfter(performance.getEndDate())) {
+//                throw new BusinessException("活动已报名结束!");
+//            }
             record.setParentSpecialtyId(artTypeService.getParent(record.getSpecialtyId()));
             record = programmeRepo.save(record);
         }
@@ -126,6 +127,28 @@ public class ProgrammeService {
         return record;
     }
 
+    public Page<Programme> all2(PageQuery pageQuery) {
+        Map<String, Object> query = pageQuery.getQuery();
+        Object code = query.get("code");
+        String artCode = null;
+        if (ObjectUtil.isNotNull(code)) {
+            artCode = Convert.convert(String.class, code);
+            query.remove("code");
+        }
+
+        List<ArtType> artTypes = artTypeRepo.findAll();
+
+        String finalArtCode = artCode;
+        return programmeRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
+            List<Predicate> and = JpaUtils.toPredicates(pageQuery, Programme.class, root, criteriaQuery, criteriaBuilder);
+            if (StrUtil.isNotBlank(finalArtCode)) {
+                and.add(root.get("specialtyId").in(artTypeService.getIds(artTypes, finalArtCode)));
+            }
+            return criteriaBuilder.and(and.toArray(new Predicate[0]));
+
+        }), JpaUtils.toPageRequest(pageQuery));
+    }
+
 
     public Page<ProgrammeDTO> backAll(PageQuery pageQuery) {
         Map<String, Object> query = pageQuery.getQuery();
@@ -139,7 +162,7 @@ public class ProgrammeService {
         List<ArtType> artTypes = artTypeRepo.findAll();
 
         String finalArtCode = artCode;
-        Page<Programme> all = programmeRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
+        Page<Programme> all =  programmeRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
             List<Predicate> and = JpaUtils.toPredicates(pageQuery, Programme.class, root, criteriaQuery, criteriaBuilder);
             if (StrUtil.isNotBlank(finalArtCode)) {
                 and.add(root.get("specialtyId").in(artTypeService.getIds(artTypes, finalArtCode)));
@@ -241,135 +264,177 @@ public class ProgrammeService {
     }
 
     @Transactional(rollbackOn = Exception.class)
-    public void upload(MultipartFile file, Long userId) throws IOException {
+    public void upload(MultipartFile file, Long userId) throws Exception {
         Organization organization = organizationRepo.findByUserId(userId).orElseThrow(new BusinessException("无记录"));
-        Long performance = performanceRepo.findNow(LocalDate.now());
-        if (ObjectUtil.isNull(performance)) {
-            throw new BusinessException("没有正在报名中的展演活动");
-        }
-
-        File destDir = TempFile.createTempDirectory("import");
-        ZipUtil.unzip(file.getInputStream(), destDir, StandardCharsets.UTF_8);
-
-//        File xlsxFile = FileUtils.findExcel1(destDir);
-//        if (xlsxFile == null) {
-//            Map<String, File> map = FileUtils.findExcel(destDir);
-//            if (map == null) return;
-//
-//            xlsxFile = map.get("file");
-//            destDir = map.get("destDir");
+//        Long performance = performanceRepo.findNow(LocalDate.now());
+//        if (ObjectUtil.isNull(performance)) {
+//            throw new BusinessException("没有正在报名中的展演活动");
 //        }
-        File xlsxFile = FileUtils.folderMethod1(destDir, null);
-        if (xlsxFile == null) {
-            return;
-        }
-        InputStream indicatorStream = new FileInputStream(xlsxFile);
-        UploadDataListener<ProgUploadDTO> listener = new UploadDataListener<>();
-        List<ProgUploadDTO> dtos = EasyExcel.read(indicatorStream, ProgUploadDTO.class, listener).sheet().doReadSync();
 
-//        Map<String, Long> performanceMap = performanceRepo.findAll()
-//                .stream()
-//                .collect(Collectors.toMap(Performance::getName, Performance::getId));
+        // 临时开启
+        Long performance = performanceRepo.findByYear(String.valueOf(LocalDate.now().getYear())).getId();
 
-        Map<Integer, Map<String, Long>> mapMap = settingRepo.findAllByFlagIn(CollUtil.newArrayList(3, 4))
-                .stream()
-                .collect(Collectors.groupingBy(Setting::getFlag, Collectors.toMap(Setting::getName, Setting::getId)));
+        File destDir = TempFile.createTempDirectory("import");
+        try {
 
-        Map<String, Long> gradeMap = gradingOrganizationRepo.findAll()
-                .stream()
-                .collect(Collectors.toMap(GradingOrganization::getName, GradingOrganization::getId));
 
-        Map<String, ArtType> artTypeMap = artTypeRepo.findAll()
-                .stream()
-                .collect(Collectors.toMap(ArtType::getName, artType -> artType));
-
-
-        List<Participant> participants = new ArrayList<>();
-        Long pid = null;
-        for (ProgUploadDTO dto : dtos) {
-            if (dto.getName() != null && dto.getSpecialty() != null) {
-                Programme programme = new Programme(dto);
-                ArtType specialty = artTypeMap.get(dto.getSpecialty());
-                programme.setOrganizationId(organization.getId());
-                programme.setGradingOrganizationId(gradeMap.get(dto.getGradingOrganization()));
-                programme.setPerformanceId(performance);
-                programme.setSpecialtyId(specialty.getId());
-                String level = dto.getLevel();
-                if (StrUtil.isNotBlank(level)) {
-                    level = level.substring(0, 2);
-                }
-                if (dto.getCompetitionGroup().equals(CompetitionGroup.SINGLE)) {
-                    programme.setLevelSettingId(mapMap.get(3).get(level));
-                } else if (dto.getCompetitionGroup().equals(CompetitionGroup.COLLECTIVE)) {
-                    programme.setLevelSettingId(mapMap.get(4).get(level));
+            String originalFilename = file.getOriginalFilename();
+            boolean zip = Pattern.matches("zip", FilenameUtils.getExtension(originalFilename));
+            boolean rar = false;
+            if (!zip) {
+                rar = Pattern.matches("rar", FilenameUtils.getExtension(originalFilename));
+            }
+            try {
+                if (rar) {
+                    FileUtils.unrar(file.getInputStream(), destDir);
+                } else if (zip) {
+                    try {
+                        ZipUtil.unzip(file.getInputStream(), destDir, StandardCharsets.UTF_8);
+                    } catch (Exception e) {
+                        ZipUtil.unzip(file.getInputStream(), destDir, Charset.forName("gbk"));
+                    }
                 }
+            } catch (Exception e) {
+                throw new BusinessException("最能上传zip或者rar压缩包");
+            }
 
-                File uploadFile = FileUtils.folderMethod1(destDir, dto.getName());
-                if (dto.getVideo() != null) {
-//                    File uploadFile = new File(destDir, dto.getVideo());
-                    uploadFile = FileUtils.folderMethod1(destDir, dto.getVideo());
-                }
-                if (ObjectUtil.isNotNull(uploadFile) && uploadFile.exists()) {
-                    // 视频
-                    if (!specialty.getCode().startsWith("03")) {
-                        // 上传
-                        String videoPath = "video/" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date())
-                                + RandomStringUtils.randomAlphabetic(8)
-                                + "." + FilenameUtils.getExtension(uploadFile.getName());
-                        String url = storageService.uploadFromInputStream(new FileInputStream(uploadFile), videoPath);
-                        VideoObject vo = new VideoObject();
-                        vo.setSrc(url);
-                        programme.setVideo(vo);
+
+            File xlsxFile = FileUtils.findInDir(destDir, null);
+            if (xlsxFile == null) {
+                return;
+            }
+            InputStream indicatorStream = new FileInputStream(xlsxFile);
+            UploadDataListener<ProgUploadDTO> listener = new UploadDataListener<>();
+            List<ProgUploadDTO> dtos = EasyExcel.read(indicatorStream, ProgUploadDTO.class, listener)
+                    .sheet()
+                    .doReadSync();
+
+            Map<Integer, Map<String, Long>> mapMap = settingRepo.findAllByFlagIn(CollUtil.newArrayList(3, 4))
+                    .stream()
+                    .collect(Collectors.groupingBy(Setting::getFlag, Collectors.toMap(Setting::getName, Setting::getId)));
+
+            Map<String, Long> gradeMap = gradingOrganizationRepo.findAll()
+                    .stream()
+                    .collect(Collectors.toMap(GradingOrganization::getName, GradingOrganization::getId));
+
+            Map<String, ArtType> artTypeMap = artTypeRepo.findAll()
+                    .stream()
+                    .collect(Collectors.toMap(ArtType::getName, artType -> artType));
+
+
+            List<Participant> participants = new ArrayList<>();
+            Long pid = null;
+            for (ProgUploadDTO dto : dtos) {
+                if (dto.getName() != null && dto.getSpecialty() != null) {
+                    Programme programme = new Programme(dto);
+                    ArtType specialty = artTypeMap.get(dto.getSpecialty());
+                    programme.setOrganizationId(organization.getId());
+                    programme.setGradingOrganizationId(gradeMap.get(dto.getGradingOrganization()));
+                    programme.setPerformanceId(performance);
+
+                    // 专业
+                    if (ObjectUtil.isNotNull(specialty)) {
+                        programme.setSpecialtyId(specialty.getId());
                     } else {
-                        // 图片
-                        programme.setAnnex(this.saveImg(uploadFile));
+                        throw new BusinessException("专业名称不正确,仔细核对专业表");
                     }
 
-                }
+                    // 节目状态
+                    programme.setProgrammeStatus(ProgrammeStatus.INITIAL);
+                    String level = dto.getLevel();
+                    if (StrUtil.isNotBlank(level)) {
+                        level = level.substring(0, 2);
+                    }
+                    if (dto.getCompetitionGroup().equals(CompetitionGroup.SINGLE)) {
+                        programme.setLevelSettingId(mapMap.get(3).get(level));
+                    } else if (dto.getCompetitionGroup().equals(CompetitionGroup.COLLECTIVE)) {
+                        programme.setLevelSettingId(mapMap.get(4).get(level));
+                    }
 
-                pid = programmeRepo.save(programme).getId();
-            }
+                    File uploadFile = FileUtils.findInDir(destDir, dto.getName());
+                    if (dto.getVideo() != null) {
+                        uploadFile = FileUtils.findInDir(destDir, dto.getVideo());
+                    }
+                    if (ObjectUtil.isNotNull(uploadFile) && uploadFile.exists()) {
+                        // 视频
+                        if (ObjectUtil.isNotNull(specialty)) {
+                            if (!specialty.getCode().startsWith("03")) {
+                                // 上传
+                                String videoPath = "video/" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date())
+                                        + RandomStringUtils.randomAlphabetic(8)
+                                        + "." + FilenameUtils.getExtension(uploadFile.getName());
+                                String url = storageService.uploadFromInputStream(new FileInputStream(uploadFile), videoPath);
+                                VideoObject vo = new VideoObject();
+                                vo.setSrc(url);
+                                programme.setVideo(vo);
+                            } else {
+                                // 图片
+                                programme.setAnnex(this.saveImg(uploadFile));
+                            }
+                        }
 
-            Participant participant = new Participant(dto);
-            if (ObjectUtil.isNotNull(dto.getParticipantBirthday())) {
-                if (dto.getParticipantBirthday().contains("/")) {
-                    LocalDate birthday = LocalDate.parse(dto.getParticipantBirthday(), DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT1));
-                    participant.setBirthday(birthday);
-                } else if (dto.getParticipantBirthday().contains("-")) {
-                    LocalDate birthday = LocalDate.parse(dto.getParticipantBirthday(), DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT));
-                    participant.setBirthday(birthday);
-                } else {
-                    throw new BusinessException("日期格式错误!");
+
+                    }
+
+                    pid = programmeRepo.save(programme).getId();
                 }
 
+                Participant participant = new Participant(dto);
+                if (ObjectUtil.isNotNull(dto.getParticipantBirthday())) {
+                    if (dto.getParticipantBirthday().contains("/")) {
+                        try {
+                            LocalDate birthday = LocalDate.parse(dto.getParticipantBirthday(), DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT1));
+                            participant.setBirthday(birthday);
+                        } catch (Exception e) {
+                            throw new BusinessException("日期格式错误");
+                        }
+
+                    } else if (dto.getParticipantBirthday().contains("-")) {
+                        try {
+                            LocalDate birthday = LocalDate.parse(dto.getParticipantBirthday(), DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT));
+                            participant.setBirthday(birthday);
+                        } catch (Exception e) {
+                            throw new BusinessException("日期格式错误");
+                        }
+                    } else {
+                        throw new BusinessException("日期格式错误!");
+                    }
+
 
-            }
+                }
 
-            participant.setProgrammeId(pid);
-            participants.add(participant);
-            File uploadImg;
-            if (dto.getImg() != null) {
+                participant.setProgrammeId(pid);
+                participant.setPerformanceId(performance);
+                participants.add(participant);
+                File uploadImg;
+                if (dto.getImg() != null) {
 //                File uploadFile = new File(destDir, dto.getImg());
-                uploadImg = FileUtils.folderMethod1(destDir, dto.getImg());
-            } else {
-                uploadImg = FileUtils.folderMethod1(destDir, dto.getIdNo() + "证件照");
-            }
-            if (ObjectUtil.isNotNull(uploadImg) && uploadImg.exists()) {
-                participant.setImg(this.saveImg(uploadImg));
-            }
+                    uploadImg = FileUtils.findInDir(destDir, dto.getImg());
+                } else {
+                    uploadImg = FileUtils.findInDir(destDir, dto.getIdNo() + "证件照");
+                }
+                if (ObjectUtil.isNotNull(uploadImg) && uploadImg.exists()) {
+                    participant.setImg(this.saveImg(uploadImg));
+                }
 
-            File uploadCertificate;
-            if (dto.getCertificate() != null) {
-                uploadCertificate = FileUtils.folderMethod1(destDir, dto.getCertificate());
-            } else {
-                uploadCertificate = FileUtils.folderMethod1(destDir, dto.getIdNo() + "证书");
-            }
-            if (ObjectUtil.isNotNull(uploadCertificate) && uploadCertificate.exists()) {
-                participant.setCertificate(this.saveImg(uploadCertificate));
+                File uploadCertificate;
+                if (dto.getCertificate() != null) {
+                    uploadCertificate = FileUtils.findInDir(destDir, dto.getCertificate());
+                } else {
+                    uploadCertificate = FileUtils.findInDir(destDir, dto.getIdNo() + "证书");
+                }
+                if (ObjectUtil.isNotNull(uploadCertificate) && uploadCertificate.exists()) {
+                    participant.setCertificate(this.saveImg(uploadCertificate));
+                }
             }
-        }
 
-        participantRepo.saveAll(participants);
+            participantRepo.saveAll(participants);
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            FileUtils.delFiles(destDir);
+
+        }
     }
 
     private String saveImg(File uploadFile) throws FileNotFoundException {
@@ -562,19 +627,19 @@ public class ProgrammeService {
             List<Programme> programmes = programmeRepo.findAllByPerformanceIdAndProgrammeStatusAndReviewArrangeIdIsNull(performanceId, ProgrammeStatus.SUBMIT);
             if (CollUtil.isNotEmpty(programmes)) {
                 this.sort(programmes);
-                return this.toShowDTOList(programmes, performance.getName());
+                return this.toShowDTOList(programmes);
             }
             return null;
         }
         List<Programme> programmes = programmeRepo.findAllByPerformanceIdAndProgrammeStatusAndArrangeIdIsNull(performanceId, ProgrammeStatus.SUBMIT);
         if (CollUtil.isNotEmpty(programmes)) {
             this.sort(programmes);
-            return this.toShowDTOList(programmes, performance.getName());
+            return this.toShowDTOList(programmes);
         }
         return null;
     }
 
-    private List<ProgrammeShowDTO> toShowDTOList(List<Programme> programmes, String name) {
+    public List<ProgrammeShowDTO> toShowDTOList(List<Programme> programmes) {
         Map<Long, String> settingMap = settingRepo.findAllByFlagIn(CollUtil.newArrayList(3, 4))
                 .stream()
                 .collect(Collectors.toMap(Setting::getId, Setting::getName));

+ 30 - 0
src/main/java/com/izouma/wenlvju/service/storage/AliStorageService.java

@@ -1,6 +1,10 @@
 package com.izouma.wenlvju.service.storage;
 
+import com.aliyun.oss.OSS;
 import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.model.CopyObjectRequest;
+import com.aliyun.oss.model.CopyObjectResult;
 import com.aliyun.oss.model.ObjectMetadata;
 import com.izouma.wenlvju.exception.BusinessException;
 import lombok.Data;
@@ -67,4 +71,30 @@ public class AliStorageService implements StorageService {
         return ossDomain + "/" + path;
     }
 
+    public void rename(String sourceKey, String destinationKey) {
+        // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
+//        String sourceKey = "application.txt";
+
+        // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
+//        String destinationKey = sourceKey;
+
+        // 创建OSSClient实例。
+        OSS ossClient = new OSSClientBuilder().build(ossEndPoint, accessKeyId, accessKeySecret);
+
+        // 创建CopyObjectRequest对象。
+        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(ossBucketName, sourceKey, ossBucketName, destinationKey);
+
+        // 设置新的文件元信息。
+        ObjectMetadata meta = new ObjectMetadata();
+//        meta.setContentType("text/txt");
+        copyObjectRequest.setNewObjectMetadata(meta);
+
+        // 复制文件。
+        CopyObjectResult result = ossClient.copyObject(copyObjectRequest);
+        System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
+
+        // 关闭OSSClient。
+        ossClient.shutdown();
+    }
+
 }

+ 116 - 31
src/main/java/com/izouma/wenlvju/utils/FileUtils.java

@@ -1,7 +1,13 @@
 package com.izouma.wenlvju.utils;
 
-import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
+import com.github.junrar.Archive;
+import com.github.junrar.exception.RarException;
+import com.github.junrar.rarfile.FileHeader;
+import com.izouma.wenlvju.exception.BusinessException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.*;
@@ -12,7 +18,10 @@ import java.nio.file.attribute.PosixFileAttributes;
 import java.nio.file.attribute.PosixFilePermission;
 import java.nio.file.attribute.PosixFilePermissions;
 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+@Slf4j
 public class FileUtils {
 
     public static String getExtension(String fileName) {
@@ -202,43 +211,57 @@ public class FileUtils {
 
     }
 
+    public static File findInDir(File dir, String fileName) {
+        if (dir.isDirectory()) {
+            for (File file : dir.listFiles()) {
+                if (file.isDirectory()) {
+                    File f = findInDir(file, fileName);
+                    if (f != null) {
+                        return f;
+                    }
+                } else {
+                    if (fileName != null) {
+                        if (file.getName().contains(fileName)) {
+                            return file;
+                        }
 
-    public static Map<String, File> findExcel(File dir) {
-        if (!(dir.exists() && dir.isDirectory())) return null;
-        for (File file : dir.listFiles()) {
-            String name = file.getName().toLowerCase();
-            if ((name.endsWith(".xlsx") || name.endsWith(".xls")) && !name.startsWith(".") && !file.isHidden()) {
-                Map<String, File> fileMap = new HashMap<>();
-                fileMap.put("file", file);
-                fileMap.put("destDir", dir);
-                return fileMap;
-            } else if (file.isDirectory() && !file.isHidden()) {
-                return findExcel(file);
+                    } else if (!file.isHidden() && Pattern.matches("xls|xlsx", FilenameUtils.getExtension(file.getName()))) {
+                        return file;
+                    }
+                }
             }
-        }
-        return null;
-    }
-
-    public static File findByName(File dir, String fileName) {
-        if (!(dir.exists() && dir.isDirectory())) return null;
-        for (File file : dir.listFiles()) {
-            String name = file.getName().toLowerCase();
-            if (name.contains(fileName)) {
-                return file;
+        } else if (fileName != null) {
+            if (dir.getName().contains(fileName)) {
+                return dir;
             }
+
+        } else if (!dir.isHidden() && Pattern.matches("xls|xlsx", FilenameUtils.getExtension(dir.getName()))) {
+            return dir;
         }
         return null;
     }
 
-    public static File findExcel1(File dir) {
-        if (!(dir.exists() && dir.isDirectory())) return null;
-        for (File file : dir.listFiles()) {
-            String name = file.getName().toLowerCase();
-            if ((name.endsWith(".xlsx") || name.endsWith(".xls")) && !name.startsWith(".") && !file.isHidden()) {
-                return file;
+    public static boolean delFiles(File file) {
+        try {
+            boolean result;
+            //目录
+            if (file.isDirectory()) {
+                 File[] childrenFiles = file.listFiles();
+
+                for (File childFile : childrenFiles) {
+                    result = delFiles(childFile);
+                    if (!result) {
+                        return result;
+                    }
+                }
             }
+            //删除 文件、空目录
+            result = file.delete();
+            return result;
+        } catch (Exception e) {
+            log.error("删除失败", e);
         }
-        return null;
+        return false;
     }
 
     public static File folderMethod1(File file, String fileName) {
@@ -248,7 +271,9 @@ public class FileUtils {
             if (null == file.listFiles()) {
                 return null;
             }
-            list.addAll(Arrays.asList(file.listFiles()));
+
+            list.addAll(CollUtil.newArrayList(file.listFiles()));
+
             while (!list.isEmpty()) {
                 File[] files = list.removeFirst().listFiles();
                 if (null == files) {
@@ -264,7 +289,7 @@ public class FileUtils {
                                 return f;
                             }
                         } else {
-                            if ((name.endsWith(".xlsx") || name.endsWith(".xls")) && !name.startsWith(".") && !file.isHidden()) {
+                            if ((name.endsWith(".xlsx") || name.endsWith(".xls")) && !name.startsWith(".") && !f.isHidden()) {
                                 return f;
                             }
                         }
@@ -275,4 +300,64 @@ public class FileUtils {
         }
         return null;
     }
+
+    public static void unrar(InputStream sourceRar, File destDir) throws Exception {
+        Archive archive = null;
+        FileOutputStream fos = null;
+        System.out.println("Starting 开始解压...");
+        try {
+            archive = new Archive(sourceRar);
+            FileHeader fh = archive.nextFileHeader();
+            File destFileName;
+            while (fh != null) {
+
+                //中文名称乱码
+                String fileName = fh.getFileNameW().replaceAll("/", File.separator).replaceAll("\\\\", File.separator);
+                if (StringUtils.isBlank(fileName)) {
+                    fileName = fh.getFileNameString()
+                            .replaceAll("/", File.separator)
+                            .replaceAll("\\\\", File.separator);
+                }
+
+//                String compressFileName = fh.getFileNameString().trim();
+                destFileName = new File(destDir.getAbsolutePath() + "/" + fileName);
+                if (fh.isDirectory()) {
+                    if (!destFileName.exists()) {
+                        destFileName.mkdirs();
+                    }
+                    fh = archive.nextFileHeader();
+                    continue;
+                }
+                if (!destFileName.getParentFile().exists()) {
+                    destFileName.getParentFile().mkdirs();
+                }
+
+                fos = new FileOutputStream(destFileName);
+                archive.extractFile(fh, fos);
+                fos.close();
+                fos = null;
+                fh = archive.nextFileHeader();
+            }
+
+            archive.close();
+            archive = null;
+            System.out.println("解压完毕...");
+        } catch (Exception e) {
+            throw e;
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (Exception e) {
+                }
+            }
+            if (archive != null) {
+                try {
+                    archive.close();
+                } catch (Exception e) {
+                }
+            }
+        }
+    }
+
 }

+ 60 - 0
src/main/java/com/izouma/wenlvju/web/AnnouncementController.java

@@ -0,0 +1,60 @@
+package com.izouma.wenlvju.web;
+import com.izouma.wenlvju.domain.Announcement;
+import com.izouma.wenlvju.service.AnnouncementService;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.exception.BusinessException;
+import com.izouma.wenlvju.repo.AnnouncementRepo;
+import com.izouma.wenlvju.utils.ObjUtils;
+import com.izouma.wenlvju.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+@RestController
+@RequestMapping("/announcement")
+@AllArgsConstructor
+public class AnnouncementController extends BaseController {
+    private AnnouncementService announcementService;
+    private AnnouncementRepo announcementRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public Announcement save(@RequestBody Announcement record) {
+        if (record.getId() != null) {
+            Announcement orig = announcementRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+            return announcementRepo.save(orig);
+        }
+        return announcementRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<Announcement> all(@RequestBody PageQuery pageQuery) {
+        return announcementService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public Announcement get(@PathVariable Long id) {
+        return announcementRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        announcementRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<Announcement> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+}
+

+ 11 - 1
src/main/java/com/izouma/wenlvju/web/AuthenticationController.java

@@ -19,6 +19,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Map;
@@ -35,7 +36,8 @@ public class AuthenticationController {
 
     @PostMapping("/login")
     public String loginByUserPwd(String username, String password, Integer expiration) {
-        Authentication authentication = authenticate(username, password);
+        String account = userService.byPhone(username);
+        Authentication authentication = authenticate(account, password);
         JwtUser jwtUser = (JwtUser) authentication.getPrincipal();
         return jwtTokenUtil.generateToken(jwtUser);
 
@@ -57,6 +59,9 @@ public class AuthenticationController {
         try {
             User user = userService.loginByPhone(phone);
             return jwtTokenUtil.generateToken(JwtUserFactory.create(user));
+        } catch (NullPointerException e) {
+            log.error("loginByPhone", e);
+            throw new AuthenticationException("该手机号未注册", e);
         } catch (Exception e) {
             log.error("loginByPhone", e);
             throw new AuthenticationException("登陆错误", e);
@@ -103,4 +108,9 @@ public class AuthenticationController {
             throw new AuthenticationException("用户名或密码错误", e);
         }
     }
+
+    @PostMapping("/forgetPW")
+    public void forgetPassword(@RequestParam String name, @RequestParam String phone, @RequestParam String password) {
+        userService.forgetPassword(name, phone, password);
+    }
 }

+ 6 - 3
src/main/java/com/izouma/wenlvju/web/GradingOrganizationController.java

@@ -1,5 +1,7 @@
 package com.izouma.wenlvju.web;
+
 import com.izouma.wenlvju.domain.GradingOrganization;
+import com.izouma.wenlvju.enums.GradingOrganizationDTO;
 import com.izouma.wenlvju.service.GradingOrganizationService;
 import com.izouma.wenlvju.dto.PageQuery;
 import com.izouma.wenlvju.exception.BusinessException;
@@ -20,13 +22,14 @@ import java.util.List;
 @AllArgsConstructor
 public class GradingOrganizationController extends BaseController {
     private GradingOrganizationService gradingOrganizationService;
-    private GradingOrganizationRepo gradingOrganizationRepo;
+    private GradingOrganizationRepo    gradingOrganizationRepo;
 
     @PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
     public GradingOrganization save(@RequestBody GradingOrganization record) {
         if (record.getId() != null) {
-            GradingOrganization orig = gradingOrganizationRepo.findById(record.getId()).orElseThrow(new BusinessException("无记录"));
+            GradingOrganization orig = gradingOrganizationRepo.findById(record.getId())
+                    .orElseThrow(new BusinessException("无记录"));
             ObjUtils.merge(orig, record);
             return gradingOrganizationRepo.save(orig);
         }
@@ -54,7 +57,7 @@ public class GradingOrganizationController extends BaseController {
     @GetMapping("/excel")
     @ResponseBody
     public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
-        List<GradingOrganization> data = all(pageQuery).getContent();
+        List<GradingOrganizationDTO> data = all(pageQuery).map(GradingOrganizationDTO::new).getContent();
         ExcelUtils.export(response, data);
     }
 }

+ 16 - 2
src/main/java/com/izouma/wenlvju/web/RateController.java

@@ -137,12 +137,13 @@ public class RateController extends BaseController {
     }
 
     @GetMapping(value = "/exportPdf/{id}", produces = "application/pdf;charset=utf-8")
-    public void exportPdf(@PathVariable Long id, HttpServletResponse response) {
+    public byte[] exportPdf(@PathVariable Long id, HttpServletResponse response) {
         try {
-            rateService.exportPdf(id, response);
+            return rateService.exportPdf(id, response);
         } catch (IOException e) {
             e.printStackTrace();
         }
+        return null;
     }
 
     @OperLog(value = "等级评定", type = "修改", desc = "对等级评定申请进行操作")
@@ -181,10 +182,23 @@ public class RateController extends BaseController {
         return rateRepo.countAllByOrganizationIdAndYear(id, year) == 0;
     }
 
+    @ApiOperation("提交纸质材料")
     @PostMapping("/paperMaterial")
     public void paperMaterial(@RequestParam Long id, @RequestParam RateStatus status, String remark) {
         rateService.paperMaterial(id, status, remark, SecurityUtils.getAuthenticatedUser().getId());
     }
 
+    @ApiOperation("批量发送短信")
+    @PostMapping("/batchSendSms")
+    public void batchSendSms(boolean announcement) {
+        rateService.batchSendSms(announcement);
+    }
+
+    @ApiOperation("设置等级比例")
+    @PostMapping("/gradeRatio")
+    public void gradeRatio(double excellent, double eligible) {
+        rateService.gradeRatio(excellent, eligible, SecurityUtils.getAuthenticatedUser().getId());
+    }
+
 }
 

+ 1 - 1
src/main/java/com/izouma/wenlvju/web/RateExpertAuditController.java

@@ -52,7 +52,7 @@ public class RateExpertAuditController extends BaseController {
 
     @PostMapping("/grade")
     public void grade(Long rateId) {
-        rateExpertAuditService.grade(rateId, SecurityUtils.getAuthenticatedUser().getId());
+        rateExpertAuditService.grade(rateId);
     }
 
 

+ 102 - 0
src/main/java/com/izouma/wenlvju/web/TrainingInstitutionController.java

@@ -0,0 +1,102 @@
+package com.izouma.wenlvju.web;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.izouma.wenlvju.domain.TrainingInstitution;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.dto.TrainingInstitutionDTO;
+import com.izouma.wenlvju.exception.BusinessException;
+import com.izouma.wenlvju.repo.TrainingInstitutionRepo;
+import com.izouma.wenlvju.service.TrainingInstitutionService;
+import com.izouma.wenlvju.utils.ObjUtils;
+import com.izouma.wenlvju.utils.excel.ExcelUtils;
+import lombok.AllArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/trainingInstitution")
+@AllArgsConstructor
+public class TrainingInstitutionController extends BaseController {
+    private TrainingInstitutionService trainingInstitutionService;
+    private TrainingInstitutionRepo    trainingInstitutionRepo;
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/save")
+    public TrainingInstitution save(@RequestBody TrainingInstitution record) {
+        if (record.getId() != null) {
+            TrainingInstitution orig = trainingInstitutionRepo.findById(record.getId())
+                    .orElseThrow(new BusinessException("无记录"));
+            ObjUtils.merge(orig, record);
+
+            orig.setSubmit(true);
+            if (ObjectUtil.isNull(orig.getFirstWrite())) {
+                orig.setFirstWrite(LocalDateTime.now());
+            }
+            return trainingInstitutionRepo.save(orig);
+        }
+        return trainingInstitutionRepo.save(record);
+    }
+
+
+    //@PreAuthorize("hasRole('ADMIN')")
+    @PostMapping("/all")
+    public Page<TrainingInstitution> all(@RequestBody PageQuery pageQuery) {
+        return trainingInstitutionService.all(pageQuery);
+    }
+
+    @GetMapping("/get/{id}")
+    public TrainingInstitution get(@PathVariable Long id) {
+        return trainingInstitutionRepo.findById(id).orElseThrow(new BusinessException("无记录"));
+    }
+
+    @PostMapping("/del/{id}")
+    public void del(@PathVariable Long id) {
+        trainingInstitutionRepo.softDelete(id);
+    }
+
+    @GetMapping("/excel")
+    @ResponseBody
+    public void excel(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<TrainingInstitution> data = all(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
+    @GetMapping("/excel1")
+    @ResponseBody
+    public void excel1(HttpServletResponse response) throws IOException {
+        List<TrainingInstitution> data = trainingInstitutionRepo.findAllByPhoneIsNull();
+        List<TrainingInstitutionDTO> dtos = data.stream()
+                .map(TrainingInstitutionDTO::new)
+                .collect(Collectors.toList());
+        ExcelUtils.export(response, dtos);
+    }
+
+    @GetMapping("/batchSend")
+    public void batchSend() throws InterruptedException {
+        List<String> phones = trainingInstitutionRepo.findAllBySubmitFalseAndPhoneIsNotNull();
+        trainingInstitutionService.batchSend(phones);
+    }
+
+    @PostMapping("/upload")
+    public void uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
+        trainingInstitutionService.upload(file);
+    }
+
+    @PostMapping("/name")
+    public Page<String> name(@RequestBody PageQuery pageQuery) {
+        return trainingInstitutionService.all(pageQuery).map(TrainingInstitution::getName);
+    }
+
+    @PostMapping("/byUscc")
+    public TrainingInstitution byUscc(@RequestParam String name, @RequestParam String uscc) {
+        return trainingInstitutionService.byUscc(name, uscc);
+    }
+}
+

+ 29 - 7
src/main/java/com/izouma/wenlvju/web/performance/ProgrammeController.java

@@ -7,6 +7,7 @@ import com.izouma.wenlvju.dto.*;
 import com.izouma.wenlvju.enums.ProgrammeStatus;
 import com.izouma.wenlvju.enums.SignedIn;
 import com.izouma.wenlvju.exception.BusinessException;
+import com.izouma.wenlvju.repo.performance.ParticipantRepo;
 import com.izouma.wenlvju.repo.performance.PerformanceRepo;
 import com.izouma.wenlvju.repo.performance.ProgrammeRepo;
 import com.izouma.wenlvju.service.UserService;
@@ -18,6 +19,7 @@ import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -37,6 +39,7 @@ public class ProgrammeController extends BaseController {
     private ProgrammeRepo    programmeRepo;
     private UserService      userService;
     private PerformanceRepo  performanceRepo;
+    private ParticipantRepo  participantRepo;
 
     //@PreAuthorize("hasRole('ADMIN')")
     @PostMapping("/save")
@@ -82,6 +85,8 @@ public class ProgrammeController extends BaseController {
     @PostMapping("/del/{id}")
     public void del(@PathVariable Long id) {
         programmeRepo.softDelete(id);
+        // 删除参演人员
+        participantRepo.softDeleteProgrammeId(id);
     }
 
     @GetMapping("/excel")
@@ -91,6 +96,13 @@ public class ProgrammeController extends BaseController {
         ExcelUtils.export(response, data);
     }
 
+    @GetMapping("/excelGO")
+    @ResponseBody
+    public void excelGO(HttpServletResponse response, PageQuery pageQuery) throws IOException {
+        List<ProgrammeShowDTO> data = this.showAll(pageQuery).getContent();
+        ExcelUtils.export(response, data);
+    }
+
     @GetMapping(value = "/excelTemp", produces = "application/vnd.ms-excel;charset=utf-8")
     public void excelTemp(HttpServletResponse response) throws IOException {
 //        ExcelUtils.export1(response, ProgrammeDTO.class);
@@ -98,13 +110,15 @@ public class ProgrammeController extends BaseController {
     }
 
     @PostMapping("/upload")
-    public void uploadFile(@RequestParam("file") MultipartFile file) {
-        try {
-            programmeService.upload(file, SecurityUtils.getAuthenticatedUser().getId());
-        } catch (IOException e) {
-            log.error("上传失败", e);
-            throw new BusinessException("上传失败", e.getMessage());
-        }
+    public void uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
+        programmeService.upload(file, SecurityUtils.getAuthenticatedUser().getId());
+//        try {
+//            programmeService.upload(file, SecurityUtils.getAuthenticatedUser().getId());
+//        } catch (Exception e) {
+//            log.error("上传失败", e);
+////            throw new BusinessException("上传失败", e.getMessage());
+//            throw e;
+//        }
     }
 
     @ApiOperation("移出分组")
@@ -179,6 +193,14 @@ public class ProgrammeController extends BaseController {
         return programmeService.toShowDTO(programme);
     }
 
+    @PostMapping("/showAll")
+    @ApiOperation("考级机构查看节目信息")
+    public Page<ProgrammeShowDTO> showAll(@RequestBody PageQuery pageQuery) {
+        Page<Programme> all = programmeService.all2(pageQuery);
+        return new PageImpl<>(programmeService.toShowDTOList(all.getContent()), all.getPageable()
+                , all.getTotalElements());
+    }
+
     @ApiOperation("获取手机号/token")
     @PostMapping("/getAuth")
     public Map<String, String> getAuth(@RequestParam Long id, @RequestParam String phone) {

+ 3 - 6
src/main/resources/application.yaml

@@ -9,15 +9,12 @@ server:
         whitelabel:
             enabled: false
     tomcat:
-        max-http-form-post-size: 200MB
+        max-http-form-post-size: 400MB
 spring:
     profiles:
         active: dev
     datasource:
         url: jdbc:mysql://mysql.izouma.com/exam?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
-#        url: jdbc:mysql://localhost:3306/exam_test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2b8
-#        username: root
-#        password: 123456
         username: microball
         password: 2wsx@WSX#EDC
         hikari:
@@ -46,8 +43,8 @@ spring:
                 min_idle: 0
     servlet:
         multipart:
-            max_file_size: 200MB
-            max_request_size: 200MB
+            max_file_size: 400MB
+            max_request_size: 400MB
     freemarker:
         settings:
             number_format: 0

+ 1 - 0
src/main/resources/genjson/Announcement.json

@@ -0,0 +1 @@
+{"tableName":"Announcement","className":"Announcement","remark":"通知公告","genTable":true,"genClass":true,"genList":true,"genForm":true,"genRouter":true,"javaPath":"/Users/qiufangchao/Desktop/project/wenlvju/src/main/java/com/izouma/wenlvju","viewPath":"/Users/qiufangchao/Desktop/project/wenlvju/src/main/vue/src/views","routerPath":"/Users/qiufangchao/Desktop/project/wenlvju/src/main/vue/src","resourcesPath":"/Users/qiufangchao/Desktop/project/wenlvju/src/main/resources","dataBaseType":"Mysql","fields":[{"name":"title","modelName":"title","remark":"标题","showInList":true,"showInForm":true,"formType":"singleLineText"},{"name":"content","modelName":"content","remark":"内容","showInList":true,"showInForm":true,"formType":"richText"}],"readTable":false,"dataSourceCode":"dataSource","genJson":"","subtables":[],"update":false,"basePackage":"com.izouma.wenlvju","tablePackage":"com.izouma.wenlvju.domain.Announcement"}

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/main/resources/genjson/TrainingInstitution.json


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
src/main/resources/templates/RateTemplate.ftl


+ 1 - 0
src/main/vue/package.json

@@ -31,6 +31,7 @@
     "vue-avatar-cropper": "^1.0.5",
     "vue-axios": "^2.1.5",
     "vue-chartjs": "^3.5.0",
+    "vue-clipboard2": "^0.3.3",
     "vue-grid-layout": "^2.3.7",
     "vue-i18n": "^8.18.2",
     "vue-router": "^3.3.4",

+ 5 - 1
src/main/vue/src/components/OrganizationLog.vue

@@ -135,7 +135,11 @@
                             </el-form-item>
                             <el-form-item label="营业执照" prop="businessLicense" class="address">
                                 <!-- <single-upload v-model="formData.businessLicense"></single-upload> -->
-                                <img style="width:100px;height100px" :src="formData.businessLicense" alt="" />
+                                <el-image
+                                    style="width:100px;height100px"
+                                    :src="formData.businessLicense"
+                                    :preview-src-list="[formData.businessLicense]"
+                                ></el-image>
                             </el-form-item>
                         </div>
                     </el-collapse-transition>

+ 3 - 0
src/main/vue/src/components/ProgrammeLog.vue

@@ -83,6 +83,9 @@
                             <el-form-item prop="instructor" label="指导老师">
                                 <el-input v-model="formData.instructor" class="width" readonly></el-input>
                             </el-form-item>
+                            <el-form-item prop="instructorPhone" label="联系方式">
+                                <el-input v-model="formData.instructorPhone" class="width" readonly></el-input>
+                            </el-form-item>
                             <div
                                 v-if="
                                     formData.specialty == '中国画' ||

+ 328 - 0
src/main/vue/src/components/ProgrammeLog1.vue

@@ -0,0 +1,328 @@
+<template>
+    <el-dialog
+        v-loading="saving"
+        @close="closeDialog"
+        title="节目详情"
+        center
+        :visible.sync="dialogVisible"
+        width="800px"
+    >
+        <div class="edit-view">
+            <el-form
+                :model="formData"
+                :rules="rules"
+                ref="form"
+                label-width="80px"
+                label-position="right"
+                size="small"
+                style="max-width: 700px;"
+            >
+                <el-timeline>
+                    <el-timeline-item placement="top" size="normal" timestamp="节目信息">
+                        <el-card shadow="hover" :body-style="{ padding: '20px' }">
+                            <el-form-item prop="name" label="节目名称">
+                                <el-input v-model="formData.name" class="width" readonly></el-input>
+                            </el-form-item>
+                            <el-form-item prop="specialtyId" label="参赛专业">
+                                <el-input v-model="formData.specialty" class="width" readonly></el-input>
+                            </el-form-item>
+                            <el-form-item prop="competitionGroup" label="参赛组别">
+                                <el-select
+                                    v-model="formData.competitionGroup"
+                                    class="width"
+                                    clearable
+                                    filterable
+                                    placeholder="请选择"
+                                    disabled
+                                >
+                                    <el-option
+                                        v-for="(item, index) in competitionGroupOptions"
+                                        :key="index"
+                                        :label="item.label"
+                                        :value="item.value"
+                                    >
+                                    </el-option>
+                                </el-select>
+                            </el-form-item>
+                            <el-form-item prop="levelSettingId" label="参赛级别" v-if="formData.competitionGroup">
+                                <el-input v-model="formData.level" class="width" readonly></el-input>
+                            </el-form-item>
+                            <el-form-item
+                                prop="durationOfWork"
+                                label="作品时长"
+                                v-if="
+                                    formData.specialtyId !== 187 &&
+                                        formData.specialtyId !== 188 &&
+                                        formData.specialtyId !== 189 &&
+                                        formData.specialtyId !== 190 &&
+                                        formData.specialtyId !== 191 &&
+                                        formData.specialtyId !== 192 &&
+                                        formData.specialtyId !== 193 &&
+                                        formData.specialtyId !== 194 &&
+                                        formData.specialtyId !== 589 &&
+                                        formData.specialtyId !== 590 &&
+                                        formData.specialtyId !== 591 &&
+                                        formData.specialtyId !== 592 &&
+                                        formData.specialtyId !== 593 &&
+                                        formData.specialtyId !== 594 &&
+                                        formData.specialtyId !== 595 &&
+                                        formData.specialtyId !== 596 &&
+                                        formData.specialtyId !== 597 &&
+                                        formData.specialtyId !== 598 &&
+                                        formData.specialtyId !== 599 &&
+                                        formData.specialtyId !== 600 &&
+                                        formData.specialtyId !== 601 &&
+                                        formData.specialtyId !== 602 &&
+                                        formData.specialtyId !== 603 &&
+                                        formData.specialtyId !== 604 &&
+                                        formData.specialtyId !== 605
+                                "
+                            >
+                                <el-input v-model="formData.durationOfWork" class="width" readonly></el-input>
+                            </el-form-item>
+                            <el-form-item prop="instructor" label="指导老师">
+                                <el-input v-model="formData.instructor" class="width" readonly></el-input>
+                            </el-form-item>
+                            <div
+                                v-if="
+                                    formData.specialty == '中国画' ||
+                                        formData.specialty == '美术' ||
+                                        formData.specialty == '西画' ||
+                                        formData.specialty == '书法' ||
+                                        formData.specialty == '漫画' ||
+                                        formData.specialty == '手工技艺' ||
+                                        formData.specialty == '摄影' ||
+                                        formData.specialty == '篆刻' ||
+                                        formData.specialty == '人物' ||
+                                        formData.specialty == '山水' ||
+                                        formData.specialty == '花鸟' ||
+                                        formData.specialty == '素描' ||
+                                        formData.specialty == '速写' ||
+                                        formData.specialty == '水粉画' ||
+                                        formData.specialty == '水彩画' ||
+                                        formData.specialty == '油画' ||
+                                        formData.specialty == '软笔书法' ||
+                                        formData.specialty == '硬笔书法' ||
+                                        formData.specialty == '剪纸' ||
+                                        formData.specialty == '泥塑' ||
+                                        formData.specialty == '年画' ||
+                                        formData.specialty == '皮影制作' ||
+                                        formData.specialty == '陶艺' ||
+                                        formData.specialty == '染织' ||
+                                        formData.specialty == '版画'
+                                "
+                            >
+                                <el-form-item prop="annex" v-if="formData.annex" label="作品图片">
+                                    <img class="imgBox" :src="formData.annex" alt="" />
+                                </el-form-item>
+                            </div>
+                            <div v-else>
+                                <el-form-item prop="video" label="作品视频" v-if="formData.video">
+                                    <video-upload v-model="videos" class="width" :readonly="true"></video-upload>
+                                </el-form-item>
+                            </div>
+                        </el-card>
+                    </el-timeline-item>
+                    <el-collapse-transition>
+                        <div v-show="showMore">
+                            <el-timeline-item placement="top" size="normal" timestamp="单位信息">
+                                <el-card shadow="hover" :body-style="{ padding: '20px' }">
+                                    <el-form-item prop="gradingOrganizationId" label="考级机构">
+                                        <el-input
+                                            v-model="formData.gradingOrganization"
+                                            class="width"
+                                            readonly
+                                        ></el-input>
+                                    </el-form-item>
+                                    <el-form-item prop="organizationId" label="承办单位">
+                                        <el-input v-model="formData.organization" class="width" readonly></el-input>
+                                    </el-form-item>
+                                    <el-form-item prop="examPoint" label="考级点">
+                                        <el-input v-model="formData.examPoint" class="width" readonly></el-input>
+                                    </el-form-item>
+                                    <el-form-item prop="contact" label="联系人">
+                                        <el-input v-model="formData.contact" class="width" readonly></el-input>
+                                    </el-form-item>
+                                    <el-form-item prop="phone" label="联系电话">
+                                        <el-input v-model="formData.phone" class="width" readonly></el-input>
+                                    </el-form-item>
+                                </el-card>
+                            </el-timeline-item>
+
+                            <el-timeline-item placement="top" size="normal" timestamp="参演人员">
+                                <el-card shadow="hover" :body-style="{ padding: '20px' }">
+                                    <el-table
+                                        :data="participants"
+                                        ref="table"
+                                        header-row-class-name="table-header-row"
+                                        header-cell-class-name="table-header-cell"
+                                        row-class-name="table-row"
+                                        cell-class-name="table-cell"
+                                    >
+                                        <el-table-column prop="img" label="证件照">
+                                            <template slot-scope="{ row }">
+                                                <el-image
+                                                    style="width: 30px; height: 30px;"
+                                                    :src="row.img"
+                                                    fit="cover"
+                                                    :preview-src-list="[row.img]"
+                                                ></el-image>
+                                            </template>
+                                        </el-table-column>
+                                        <el-table-column prop="name" label="姓名" min-width="80"> </el-table-column>
+                                        <el-table-column prop="birthday" label="出生年月" min-width="100">
+                                        </el-table-column>
+                                        <el-table-column prop="sex" label="性别" min-width="70"> </el-table-column>
+                                        <el-table-column prop="phone" label="联系方式" min-width="100">
+                                        </el-table-column>
+                                        <el-table-column prop="certificate" label="考级证书">
+                                            <template slot-scope="{ row }">
+                                                <el-image
+                                                    style="width: 30px; height: 30px;"
+                                                    :src="row.certificate"
+                                                    fit="cover"
+                                                    :preview-src-list="[row.certificate]"
+                                                ></el-image>
+                                            </template>
+                                        </el-table-column>
+                                        <el-table-column prop="idNo" label="身份证号" min-width="100">
+                                        </el-table-column>
+                                    </el-table>
+                                </el-card>
+                            </el-timeline-item>
+                        </div>
+                    </el-collapse-transition>
+                    <div style="width:100%;textAlign:center">
+                        <el-button
+                            class="more"
+                            round
+                            type="primary"
+                            :plain="!showMore"
+                            :icon="showMore ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
+                            @click="showMore = !showMore"
+                        ></el-button>
+                    </div>
+                </el-timeline>
+                <!-- <el-form-item> </el-form-item> -->
+            </el-form>
+            <!-- <div class="btn">
+                <el-button @click="$router.go(-1)">返回</el-button>
+            </div> -->
+        </div>
+    </el-dialog>
+</template>
+<script>
+import delChild from '@/mixins/delChild';
+import { mapState } from 'vuex';
+export default {
+    name: 'ProgrammeShow',
+    mixins: [delChild],
+    props: ['dialogVisible'],
+    created() {},
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            show: false,
+            showMore: false,
+            videos: {},
+            level: '',
+            rules: {
+                phone: [
+                    {
+                        pattern: /^1[3-9]\d{9}$/,
+                        message: '请输入正确的手机号',
+                        trigger: 'blur'
+                    }
+                ]
+            },
+            competitionGroupOptions: [
+                { label: '个人', value: 'SINGLE' },
+                { label: '集体', value: 'COLLECTIVE' }
+            ],
+            levelSingleOptions: [],
+            levelCollectiveOptions: [],
+            gradingOrganizationIdOptions: [],
+            organizationIdOptions: [],
+            artTypes: [],
+            optionProps: {
+                value: 'id',
+                label: 'name',
+                children: 'children',
+                multiple: false,
+                emitPath: false,
+                checkStrictly: true,
+                expandTrigger: 'hover'
+            },
+            participants: [],
+            programmeId: ''
+        };
+    },
+    methods: {
+        dataApi(id) {
+            if (id) {
+                this.$http
+                    .get('programme/getShow/' + id)
+                    .then(res => {
+                        this.formData = res;
+                        this.participants = res.participants;
+                        // console.log(res);
+                        this.videos = {
+                            src: res.video
+                        };
+                    })
+                    .catch(e => {
+                        console.log(e);
+                        this.$message.error(e.error);
+                    });
+            }
+        },
+        closeDialog() {
+            this.$emit('close');
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.edit-view {
+    padding: 0 0;
+    background-color: transparent;
+}
+.width {
+    width: 260px;
+}
+// /deep/ .el-timeline-item {
+//     padding-bottom: 35px;
+// }
+.imgBox {
+    width: 178px;
+    height: 178px;
+    border-radius: 4px;
+}
+.btn {
+    position: fixed;
+    bottom: 0;
+    width: 100%;
+    background: #ffffff;
+    height: 50px;
+    line-height: 50px;
+    z-index: 999;
+    margin-left: -20px;
+    padding-left: 20px;
+}
+/deep/.el-input.is-disabled .el-input__inner {
+    background-color: #ffffff;
+    color: #606266;
+}
+/deep/.el-timeline-item__timestamp {
+    color: #0561d9;
+    line-height: 1;
+    font-size: 14px;
+}
+/deep/.el-timeline-item__node {
+    background-color: #5b9bed;
+}
+/deep/.el-timeline-item__tail {
+    border-left: 2px solid #7cace9;
+}
+</style>

+ 6 - 3
src/main/vue/src/components/RichText.vue

@@ -42,14 +42,17 @@ export default {
                 menubar: false,
                 branding: false,
                 statusbar: false,
-                height: 400,
+                height: 600,
+                width: 700,
                 toolbar:
-                    'undo redo | styleselect bold italic strikethrough forecolor backcolor  | image media link blockquote visualblocks insert | formatselect | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | preview fullscreen code help',
+                    'undo redo  | indent2em bold italic strikethrough forecolor backcolor fontsizeselect lineheight | image media link blockquote visualblocks insert  | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | preview fullscreen code help',
                 plugins: [
-                    'advlist autolink lists link image charmap print preview anchor textcolor',
+                    'advlist autolink indent2em lists link image charmap print preview anchor textcolor',
                     'searchreplace visualblocks code fullscreen',
                     'insertdatetime media table contextmenu paste code help imagetools'
                 ],
+                lineheight_formats: '1 1.1 1.2 1.3 1.4 1.5 2',
+                fontsize_formats: '8px 10px 12px 14px 16px 18px 24px 36px 48px',
                 images_upload_url: this.$baseUrl + '/upload/file',
                 images_upload_handler: (blobInfo, success, failure) => {
                     let formData = new FormData();

+ 2 - 0
src/main/vue/src/main.js

@@ -18,6 +18,7 @@ import DistrictSelect from '@/components/DistrictSelect';
 import Formatters from '@/mixins/formatters';
 import 'normalize.css/normalize.css';
 import 'element-ui/lib/theme-chalk/index.css';
+import VueClipboard from 'vue-clipboard2';
 // 修改 el-dialog 默认点击遮照为不关闭
 ElementUI.Dialog.props.closeOnClickModal.default = false;
 
@@ -46,6 +47,7 @@ Vue.config.productionTip = false;
 Vue.use(ElementUI, { size: 'small' });
 Vue.use(http);
 Vue.use(dataExport);
+Vue.use(VueClipboard);
 Vue.component('sortable-header', SortableHeader);
 Vue.component('multi-upload', MultiUpload);
 Vue.component('single-upload', SingleUpload);

+ 1 - 0
src/main/vue/src/mixins/pageableTable.js

@@ -154,6 +154,7 @@ export default {
                 })
                 .catch(_ => {});
             this.sortStr = sortStr;
+            console.log(this.sortStr);
             this.getData();
         }
     }

+ 53 - 1
src/main/vue/src/router.js

@@ -781,6 +781,49 @@ const router = new Router({
                     meta: {
                         title: '节目评审'
                     }
+                },
+                {
+                    path: '/trainingInstitutionEdit',
+                    name: 'TrainingInstitutionEdit',
+                    component: () =>
+                        import(/* webpackChunkName: "trainingInstitutionEdit" */ '@/views/TrainingInstitutionEdit.vue'),
+                    meta: {
+                        title: '培训机构编辑'
+                    }
+                },
+                {
+                    path: '/trainingInstitutionList',
+                    name: 'TrainingInstitutionList',
+                    component: () =>
+                        import(/* webpackChunkName: "trainingInstitutionList" */ '@/views/TrainingInstitutionList.vue'),
+                    meta: {
+                        title: '培训机构'
+                    }
+                },
+                {
+                    path: '/announcementEdit',
+                    name: 'AnnouncementEdit',
+                    component: () => import(/* webpackChunkName: "announcementEdit" */ '@/views/AnnouncementEdit.vue'),
+                    meta: {
+                        title: '通知公告编辑'
+                    }
+                },
+                {
+                    path: '/announcementDetail',
+                    name: 'AnnouncementDetail',
+                    component: () =>
+                        import(/* webpackChunkName: "announcementEdit" */ '@/views/AnnouncementDetail.vue'),
+                    meta: {
+                        title: '通知公告'
+                    }
+                },
+                {
+                    path: '/announcementList',
+                    name: 'AnnouncementList',
+                    component: () => import(/* webpackChunkName: "announcementList" */ '@/views/AnnouncementList.vue'),
+                    meta: {
+                        title: '通知公告'
+                    }
                 }
                 /**INSERT_LOCATION**/
             ]
@@ -792,6 +835,15 @@ const router = new Router({
             meta: {
                 title: '登录'
             }
+        },
+        /**初审 */
+        {
+            path: '/programmeGOList',
+            name: 'ProgrammegoList',
+            component: () => import(/* webpackChunkName: "programmeList" */ '@/views/performance/ProgrammeGOList.vue'),
+            meta: {
+                title: '节目列表'
+            }
         }
     ]
 });
@@ -815,7 +867,7 @@ router.beforeEach((to, from, next) => {
         return;
     }
     // console.log(store.state.isORGANIZER);
-    if (!store.state.userInfo && to.path !== '/login') {
+    if (!store.state.userInfo && to.path !== '/login' && to.path !== '/programmeGOList') {
         store
             .dispatch('getUserInfo')
             .then(() => {

+ 94 - 0
src/main/vue/src/views/AnnouncementDetail.vue

@@ -0,0 +1,94 @@
+<template>
+    <div class="edit-view">
+        <div class="title">{{ formData.title }}</div>
+        <div class="time">发布时间:{{ formData.createdAt }}</div>
+        <div class="content" v-html="formData.content"></div>
+    </div>
+</template>
+<script>
+export default {
+    name: 'AnnouncementEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('announcement/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {}
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/announcement/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/announcement/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.title {
+    font-size: 24px;
+    text-align: center;
+    padding: 20px;
+    font-weight: bold;
+}
+.time {
+    font-size: 12px;
+    text-align: right;
+    margin-right: 50px;
+    padding: 10px;
+}
+
+.content {
+    padding: 20px 50px;
+}
+</style>

+ 106 - 0
src/main/vue/src/views/AnnouncementEdit.vue

@@ -0,0 +1,106 @@
+<template>
+    <div class="edit-view">
+        <el-form
+            :model="formData"
+            :rules="rules"
+            ref="form"
+            label-width="52px"
+            label-position="right"
+            size="small"
+            style="max-width: 700px;"
+        >
+            <el-form-item prop="title" label="标题">
+                <el-input v-model="formData.title"></el-input>
+            </el-form-item>
+            <el-form-item prop="type" label="类型">
+                <el-radio-group v-model="formData.type">
+                    <el-radio v-for="item in typeOptions" :key="item.value" :label="item.value">{{
+                        item.label
+                    }}</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item prop="content" label="内容">
+                <rich-text v-model="formData.content"></rich-text>
+            </el-form-item>
+            <el-form-item>
+                <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>
+                <el-button @click="onDelete" :loading="saving" type="danger" v-if="formData.id">删除 </el-button>
+                <el-button @click="$router.go(-1)">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+<script>
+export default {
+    name: 'AnnouncementEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('announcement/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {},
+            typeOptions: [
+                { label: '通知公告', value: 'NOTIFICATION' },
+                { label: '政策文件', value: 'POLICY' }
+            ]
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/announcement/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/announcement/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 169 - 0
src/main/vue/src/views/AnnouncementList.vue

@@ -0,0 +1,169 @@
+<template>
+    <div class="list-view">
+        <div class="filters-container">
+            <el-input placeholder="输入关键字" v-model="search" clearable class="filter-item"></el-input>
+            <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">搜索 </el-button>
+            <el-button @click="addRow" type="primary" icon="el-icon-plus" class="filter-item">添加 </el-button>
+            <el-button
+                @click="download"
+                type="primary"
+                icon="el-icon-download"
+                :loading="downloading"
+                class="filter-item"
+                >导出EXCEL
+            </el-button>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <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="title" label="标题"> </el-table-column>
+            <el-table-column prop="type" label="类型" :formatter="typeFormatter"> </el-table-column>
+            <el-table-column prop="content" label="内容"> </el-table-column>
+            <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="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+
+export default {
+    name: 'AnnouncementList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/announcement/all',
+            downloading: false,
+            typeOptions: [
+                { label: '通知公告', value: 'NOTIFICATION' },
+                { label: '政策文件', value: 'POLICY' }
+            ]
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        typeFormatter(row, column, cellValue, index) {
+            let selectedOption = this.typeOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        beforeGetData() {
+            return { search: this.search };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/announcementEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/announcementEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/announcement/excel', {
+                    responseType: 'blob',
+                    params: { size: 10000 }
+                })
+                .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);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/announcement/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 12 - 6
src/main/vue/src/views/Dashboard.vue

@@ -33,6 +33,8 @@
 <script>
 import { GridLayout, GridItem } from 'vue-grid-layout';
 import UserWidget from '../widgets/UserWidget';
+import BoardWidget from '../widgets/BoardWidget.vue';
+import PolicyWidget from '../widgets/PolicyWidget.vue';
 import UserWidget2 from '../widgets/UserWidget2';
 import LineChartWidget from '../widgets/LineChartWidget';
 import BarChartWidget from '../widgets/BarChartWidget';
@@ -43,11 +45,13 @@ export default {
     data() {
         return {
             layout: [
-                { x: 0, y: 0, w: 6, h: 4, i: '0', name: 'UserWidget' },
-                { x: 6, y: 0, w: 6, h: 4, i: '1', name: 'UserWidget2' },
-                { x: 0, y: 4, w: 6, h: 6, i: '2', name: 'BarChartWidget' },
-                { x: 0, y: 10, w: 6, h: 6, i: '3', name: 'LineChartWidget' },
-                { x: 6, y: 4, w: 6, h: 12, i: '4', name: 'PieChartWidget' }
+                { x: 0, y: 0, w: 12, h: 6, i: '0', name: 'BoardWidget' },
+                { x: 6, y: 0, w: 12, h: 6, i: '1', name: 'PolicyWidget' }
+                // { x: 0, y: 0, w: 6, h: 4, i: '2', name: 'UserWidget' },
+                // { x: 6, y: 4, w: 6, h: 4, i: '3', name: 'UserWidget2' },
+                // { x: 0, y: 8, w: 6, h: 6, i: '4', name: 'BarChartWidget' },
+                // { x: 0, y: 10, w: 6, h: 6, i: '5', name: 'LineChartWidget' },
+                // { x: 6, y: 8, w: 6, h: 12, i: '6', name: 'PieChartWidget' }
             ],
             editable: false
         };
@@ -65,7 +69,9 @@ export default {
         UserWidget2,
         LineChartWidget,
         BarChartWidget,
-        PieChartWidget
+        PieChartWidget,
+        BoardWidget,
+        PolicyWidget
     }
 };
 </script>

+ 26 - 13
src/main/vue/src/views/Login.vue

@@ -499,25 +499,38 @@ export default {
             this.$refs.registerForm.validate(valid => {
                 if (valid) {
                     this.loading = true;
+
                     this.$http
-                        .post(
-                            '/user/regOrganization',
-                            // {
-                            // username: this.registerInfo.username,
-                            // password: this.registerInfo.password
-                            // },
-                            this.registerInfo,
-                            { body: 'json' }
-                        )
+                        .get('/organization/byName', { name: this.registerInfo.organizationName }, { body: 'json' })
                         .then(res => {
-                            this.loading = false;
-                            this.$message.success('注册成功');
-                            this.register = false;
+                            if (res != null || res != 'undefind') {
+                                this.$confirm('该承办单位已有人注册,注册手机号为' + res + ',是否继续注册', '提示', {
+                                    confirmButtonText: '继续注册',
+                                    cancelButtonText: '返回登录',
+                                    type: 'warning'
+                                })
+                                    .then(() => {
+                                        this.$http
+                                            .post('/user/regOrganization', this.registerInfo, { body: 'json' })
+                                            .then(res => {
+                                                this.loading = false;
+                                                this.$message.success('注册成功');
+                                                this.register = false;
+                                            })
+                                            .catch(e => {
+                                                console.log(e);
+                                                this.loading = false;
+                                            });
+                                    })
+                                    .catch(() => {
+                                        this.loading = false;
+                                        this.register = false;
+                                    });
+                            }
                         })
                         .catch(e => {
                             console.log(e);
                             this.loading = false;
-                            this.$message.error(e.error);
                         });
                 }
             });

+ 180 - 0
src/main/vue/src/views/TrainingInstitutionEdit.vue

@@ -0,0 +1,180 @@
+<template>
+    <div class="edit-view">
+        <el-form
+            :model="formData"
+            :rules="rules"
+            ref="form"
+            label-width="178px"
+            label-position="right"
+            size="small"
+            style="max-width: 700px;"
+        >
+            <el-form-item prop="name" label="企业名称">
+                <el-input v-model="formData.name"></el-input>
+            </el-form-item>
+            <el-form-item prop="uscc" label="注册号">
+                <el-input v-model="formData.uscc"></el-input>
+            </el-form-item>
+            <el-form-item prop="businessScope" label="经营范围">
+                <el-input type="textarea" v-model="formData.businessScope"></el-input>
+            </el-form-item>
+            <el-form-item prop="address" label="企业住所">
+                <el-input v-model="formData.address"></el-input>
+            </el-form-item>
+            <el-form-item prop="businessPremise" label="生产经营场所">
+                <el-input v-model="formData.businessPremise"></el-input>
+            </el-form-item>
+            <el-form-item prop="privacyPolicy" label="法人姓名">
+                <el-input v-model="formData.privacyPolicy"></el-input>
+            </el-form-item>
+            <el-form-item prop="phone" label="短信号码">
+                <el-input v-model="formData.phone"></el-input>
+            </el-form-item>
+            <el-form-item prop="contactPhone" label="企业联系方式">
+                <el-input v-model="formData.contactPhone"></el-input>
+            </el-form-item>
+            <el-form-item prop="district" label="所属管区">
+                <el-input v-model="formData.district"></el-input>
+            </el-form-item>
+            <el-form-item prop="registeredCapital" label="注册资本(万)">
+                <el-input-number type="number" v-model="formData.registeredCapital"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="category" label="单位性质">
+                <el-input v-model="formData.category"></el-input>
+            </el-form-item>
+            <el-form-item prop="specialty" label="专业种类">
+                <el-input v-model="formData.specialty"></el-input>
+            </el-form-item>
+            <el-form-item prop="trainingSite" label="培训点数量三楼及以下">
+                <el-input-number type="number" v-model="formData.trainingSite"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="trainingSiteFour" label="培训点数量四楼及以上">
+                <el-input-number type="number" v-model="formData.trainingSiteFour"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="area" label="总面积">
+                <el-input v-model="formData.area"></el-input>
+            </el-form-item>
+            <el-form-item prop="classroomNum" label="教室数量">
+                <el-input-number type="number" v-model="formData.classroomNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="teacherNum" label="教师总数">
+                <el-input-number type="number" v-model="formData.teacherNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="fullTimeNum" label="专职数量">
+                <el-input-number type="number" v-model="formData.fullTimeNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="partTimeNum" label="兼职数量">
+                <el-input-number type="number" v-model="formData.partTimeNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="musicNum" label="音乐类">
+                <el-input-number type="number" v-model="formData.musicNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="danceNum" label="舞蹈类">
+                <el-input-number type="number" v-model="formData.danceNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="artNum" label="美术类">
+                <el-input-number type="number" v-model="formData.artNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="theatreOperaNum" label="戏剧戏曲">
+                <el-input-number type="number" v-model="formData.theatreOperaNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="folkMusicNum" label="曲艺类">
+                <el-input-number type="number" v-model="formData.folkMusicNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="qualificationNum" label="有教师资格证">
+                <el-input-number type="number" v-model="formData.qualificationNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="traineesPerYearNum" label="年培训人数">
+                <el-input-number type="number" v-model="formData.traineesPerYearNum"></el-input-number>
+            </el-form-item>
+            <el-form-item prop="examPoint" label="是否是艺术水平考级考点">
+                <!-- <el-input v-model="formData.examPoint"></el-input> -->
+                <el-radio-group v-model="formData.examPoint">
+                    <el-radio :label="true">是</el-radio>
+                    <el-radio :label="false">否</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item prop="gradingOrganization" label="艺术水平考级机构名称">
+                <el-input v-model="formData.gradingOrganization"></el-input>
+            </el-form-item>
+            <el-form-item prop="remark" label="备注">
+                <el-input v-model="formData.remark"></el-input>
+            </el-form-item>
+            <el-form-item>
+                <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>
+                <el-button @click="onDelete" :loading="saving" type="danger" v-if="formData.id">删除 </el-button>
+                <el-button @click="$router.go(-1)">取消</el-button>
+            </el-form-item>
+        </el-form>
+    </div>
+</template>
+<script>
+export default {
+    name: 'TrainingInstitutionEdit',
+    created() {
+        if (this.$route.query.id) {
+            this.$http
+                .get('trainingInstitution/get/' + this.$route.query.id)
+                .then(res => {
+                    this.formData = res;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.$message.error(e.error);
+                });
+        }
+    },
+    data() {
+        return {
+            saving: false,
+            formData: {},
+            rules: {}
+        };
+    },
+    methods: {
+        onSave() {
+            this.$refs.form.validate(valid => {
+                if (valid) {
+                    this.submit();
+                } else {
+                    return false;
+                }
+            });
+        },
+        submit() {
+            let data = { ...this.formData };
+
+            this.saving = true;
+            this.$http
+                .post('/trainingInstitution/save', data, { body: 'json' })
+                .then(res => {
+                    this.saving = false;
+                    this.$message.success('成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.saving = false;
+                    this.$message.error(e.error);
+                });
+        },
+        onDelete() {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/trainingInstitution/del/${this.formData.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.$router.go(-1);
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        console.log(e);
+                        this.$message.error((e || {}).error || '删除失败');
+                    }
+                });
+        }
+    }
+};
+</script>
+<style lang="less" scoped></style>

+ 279 - 0
src/main/vue/src/views/TrainingInstitutionList.vue

@@ -0,0 +1,279 @@
+<template>
+    <div class="list-view">
+        <div class="filters-container">
+            <el-input placeholder="输入关键字" v-model="search" clearable class="filter-item"></el-input>
+            <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">搜索 </el-button>
+            <!-- <el-button @click="addRow" type="primary" icon="el-icon-plus" class="filter-item">添加 </el-button> -->
+            <el-button @click="download" type="primary" icon="el-icon-download" :loading="downloading"
+                >导出所有
+            </el-button>
+            <el-button @click="downloadTel" type="primary" icon="el-icon-download" :loading="downloading"
+                >导出固定电话
+            </el-button>
+            <el-upload
+                :action="uploadUrl"
+                :before-upload="beforeUpload"
+                :headers="headers"
+                :show-file-list="false"
+                ref="upload"
+                :on-success="onSuccess"
+                class="uploader"
+                :on-error="onfail"
+                :loading="loading"
+                :disabled="loading"
+            >
+                <el-button slot="trigger" type="primary" icon="el-icon-upload2" :loading="loading" :disabled="loading"
+                    >批量上传</el-button
+                >
+            </el-upload>
+            <el-button @click="sendSms" type="primary">短信通知 </el-button>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="ID" width="80"> </el-table-column>
+            <el-table-column prop="name" label="企业名称"> </el-table-column>
+            <el-table-column prop="uscc" label="注册号"> </el-table-column>
+            <el-table-column prop="businessScope" label="经营范围"> </el-table-column>
+            <el-table-column prop="address" label="企业住所"> </el-table-column>
+            <el-table-column prop="businessPremise" label="生产经营场所"> </el-table-column>
+            <el-table-column prop="privacyPolicy" label="法人姓名"> </el-table-column>
+            <el-table-column prop="phone" label="短信号码"> </el-table-column>
+            <el-table-column prop="contactPhone" label="企业联系方式"> </el-table-column>
+            <el-table-column prop="district" label="所属管区"> </el-table-column>
+            <el-table-column prop="registeredCapital" label="注册资本(万)"> </el-table-column>
+            <el-table-column prop="engagedInTraining" label="是否从事文化艺术类校外培训"> </el-table-column>
+            <el-table-column prop="category" label="单位性质"> </el-table-column>
+            <el-table-column prop="specialty" label="专业种类"> </el-table-column>
+            <el-table-column prop="trainingSite" label="培训点数量三楼及以下"> </el-table-column>
+            <el-table-column prop="trainingSiteFour" label="培训点数量四楼及以上"> </el-table-column>
+            <el-table-column prop="area" label="总面积"> </el-table-column>
+            <el-table-column prop="classroomNum" label="教室数量"> </el-table-column>
+            <el-table-column prop="teacherNum" label="教师总数"> </el-table-column>
+            <el-table-column prop="fullTimeNum" label="专职数量"> </el-table-column>
+            <el-table-column prop="partTimeNum" label="兼职数量"> </el-table-column>
+            <el-table-column prop="musicNum" label="音乐类"> </el-table-column>
+            <el-table-column prop="danceNum" label="舞蹈类"> </el-table-column>
+            <el-table-column prop="artNum" label="美术类"> </el-table-column>
+            <el-table-column prop="theatreOperaNum" label="戏剧戏曲"> </el-table-column>
+            <el-table-column prop="folkMusicNum" label="曲艺类"> </el-table-column>
+            <el-table-column prop="qualificationNum" label="有教师资格证"> </el-table-column>
+            <el-table-column prop="traineesPerYearNum" label="年培训人数"> </el-table-column>
+            <el-table-column prop="examPoint" label="是否是艺术水平考级考点"> </el-table-column>
+            <el-table-column prop="gradingOrganization" label="艺术水平考级机构名称"> </el-table-column>
+            <el-table-column prop="remark" label="备注"> </el-table-column>
+            <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="deleteRow(row)" type="danger" size="mini" plain>删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <!-- <div class="multiple-mode-wrapper">
+                <el-button v-if="!multipleMode" @click="toggleMultipleMode(true)">批量编辑</el-button>
+                <el-button-group v-else>
+                    <el-button @click="operation1">批量操作1</el-button>
+                    <el-button @click="operation2">批量操作2</el-button>
+                    <el-button @click="toggleMultipleMode(false)">取消</el-button>
+                </el-button-group>
+            </div> -->
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+import resolveUrl from 'resolve-url';
+
+export default {
+    name: 'TrainingInstitutionList',
+    mixins: [pageableTable],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/trainingInstitution/all',
+            downloading: false,
+            loading: false,
+            uploadUrl: ''
+        };
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        },
+        headers() {
+            return {
+                Authorization: 'Bearer ' + sessionStorage.getItem('token')
+            };
+        }
+    },
+    created() {
+        this.uploadUrl = resolveUrl(this.$baseUrl, 'trainingInstitution/upload');
+    },
+    methods: {
+        beforeGetData() {
+            return {
+                search: this.search,
+                sort: 'firstWrite,desc'
+            };
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/trainingInstitutionEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        editRow(row) {
+            this.$router.push({
+                path: '/trainingInstitutionEdit',
+                query: {
+                    id: row.id
+                }
+            });
+        },
+        download() {
+            this.downloading = true;
+            this.$axios
+                .get('/trainingInstitution/excel', {
+                    responseType: 'blob',
+                    params: { size: 100000 }
+                })
+                .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);
+                });
+        },
+        downloadTel() {
+            this.downloading = true;
+            this.$axios
+                .get('/trainingInstitution/excel1', {
+                    responseType: 'blob',
+                    params: { size: 50000 }
+                })
+                .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);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        deleteRow(row) {
+            this.$alert('删除将无法恢复,确认要删除么?', '警告', { type: 'error' })
+                .then(() => {
+                    return this.$http.post(`/trainingInstitution/del/${row.id}`);
+                })
+                .then(() => {
+                    this.$message.success('删除成功');
+                    this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        },
+        sendSms() {
+            this.$alert('确认发送短信吗?', '提示')
+                .then(() => {
+                    return this.$http.get(`/trainingInstitution/batchSend`);
+                })
+                .then(() => {
+                    this.$message.success('发送成功');
+                    // this.getData();
+                })
+                .catch(e => {
+                    if (e !== 'cancel') {
+                        this.$message.error(e.error);
+                    }
+                });
+        },
+        upload() {},
+        onfail(e) {
+            console.log(e);
+            this.$message.error('失败:' + e);
+            this.loading = false;
+            this.getData();
+        },
+        onSuccess() {
+            this.$message.success('上传成功');
+            this.loading = false;
+            this.getData();
+        },
+        beforeUpload() {
+            return this.$confirm('确认要上传文件吗?', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                this.loading = true;
+            });
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.uploader {
+    display: inline-block;
+    margin: 0 10px;
+}
+</style>

+ 1 - 0
src/main/vue/src/views/performance/ArrangeJudgeList.vue

@@ -72,6 +72,7 @@
                             :plain="!showMore"
                             :icon="showMore ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
                             @click="showMore = !showMore"
+                            size="mini"
                             >{{ showMore ? '隐藏查询区域' : '显示查询区域' }}</el-button
                         >
                     </div>

+ 3 - 1
src/main/vue/src/views/performance/PerformanceEdit.vue

@@ -120,7 +120,9 @@
             <el-form-item prop="codeImg" label="活动工作群">
                 <single-upload v-model="formData.codeImg"></single-upload>
             </el-form-item>
-            <!-- <el-form-item> </el-form-item> -->
+            <el-form-item prop="close" label="开启">
+                <el-switch v-model="formData.close"></el-switch>
+            </el-form-item>
         </el-form>
         <div class="btn">
             <el-button @click="onSave" :loading="saving" type="primary">保存</el-button>

+ 13 - 4
src/main/vue/src/views/performance/ProgrammeEdit.vue

@@ -540,7 +540,8 @@ export default {
                 .map(item => {
                     return {
                         ...item,
-                        programmeId: this.programmeId
+                        programmeId: this.programmeId,
+                        performanceId: this.formData.performanceId
                     };
                 });
 
@@ -587,10 +588,18 @@ export default {
 
                     this.programmeId = res.id;
                     this.$nextTick(() => {
-                        this.$http.post('/participant/batchSave', this.saveOtherJson, { body: 'json' });
+                        this.$http
+                            .post('/participant/batchSave', this.saveOtherJson, { body: 'json' })
+                            .then(() => {
+                                this.$message.success('成功');
+                                this.$router.go(-1);
+                            })
+                            .catch(e => {
+                                console.log(e);
+                                this.saving = false;
+                                this.$message.error(e.error);
+                            });
                     });
-                    this.$message.success('成功');
-                    this.$router.go(-1);
                 })
                 .catch(e => {
                     console.log(e);

+ 388 - 0
src/main/vue/src/views/performance/ProgrammeGOList.vue

@@ -0,0 +1,388 @@
+<template>
+    <div class="list-view">
+        <div class="filters-container">
+            <el-form :model="form" inline size="mini" label-width="100px">
+                <el-form-item>
+                    <!-- <el-button @click="getData" type="primary" icon="el-icon-search">查询 </el-button>
+                    <el-button @click="clearSearch" type="primary">清空 </el-button> -->
+                    <!-- <el-button @click="addRow" type="primary" icon="el-icon-plus">添加 </el-button> -->
+                    <el-button
+                        @click="download"
+                        type="primary"
+                        icon="el-icon-download"
+                        :loading="downloading"
+                        :disabled="totalElements < 1"
+                        >导出
+                    </el-button>
+                </el-form-item>
+            </el-form>
+        </div>
+        <el-table
+            :data="tableData"
+            row-key="id"
+            ref="table"
+            empty-text="暂无数据"
+            header-row-class-name="table-header-row"
+            header-cell-class-name="table-header-cell"
+            row-class-name="table-row"
+            cell-class-name="table-cell"
+            :height="tableHeight"
+        >
+            <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
+            <el-table-column prop="id" label="节目编号" width="80" fixed="left"> </el-table-column>
+            <el-table-column prop="name" label="节目名称" fixed="left"> </el-table-column>
+            <el-table-column prop="specialty" label="参赛专业"> </el-table-column>
+            <el-table-column
+                prop="competitionGroup"
+                label="参赛组别"
+                :formatter="competitionGroupFormatter"
+                min-width="70"
+            >
+            </el-table-column>
+            <el-table-column prop="level" label="参赛级别" min-width="70"> </el-table-column>
+            <!-- <el-table-column prop="durationOfWork" label="作品时长" min-width="70"> </el-table-column> -->
+            <el-table-column prop="quantity" label="参赛人数" min-width="70"> </el-table-column>
+            <el-table-column prop="contact" label="联系人" min-width="68"> </el-table-column>
+            <el-table-column prop="gradingOrganizationId" label="考级机构" show-overflow-tooltip min-width="160">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+                <template slot-scope="{ row }">
+                    <span>{{ row.gradingOrganization }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="organizationId" label="承办单位" min-width="160">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+                <template slot-scope="{ row }">
+                    <span>{{ row.organization }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="examPoint" label="考级点" min-width="160">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+            </el-table-column>
+            <el-table-column
+                prop="programmeStatus"
+                label="节目状态"
+                min-width="100"
+                :formatter="programmeStatusFormatter"
+            ></el-table-column>
+            <el-table-column label="操作" align="left" fixed="right" min-width="180">
+                <template slot-scope="{ row, $index }">
+                    <el-button @click="showRow(row)" size="mini" plain>查看</el-button>
+                    <el-button type="warning" @click="playVideo(row, $index)" size="mini" plain>查看作品</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <div class="pagination-wrapper">
+            <el-pagination
+                background
+                @size-change="onSizeChange"
+                @current-change="onCurrentChange"
+                :current-page="page"
+                :page-sizes="[10, 20, 30, 40, 50]"
+                :page-size="pageSize"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalElements"
+            >
+            </el-pagination>
+        </div>
+        <el-dialog
+            :title="programme.name"
+            class="videoDialog"
+            destroy-on-close
+            center
+            append-to-body
+            :visible.sync="showViedo"
+            width="auto"
+        >
+            <video
+                :src="programme.video"
+                controls
+                style="max-height: 600px; max-width: 100%; margin: 0 auto"
+                v-if="programme.video"
+            >
+                您的浏览器不支持 video 标签。
+            </video>
+            <img
+                style="max-height: 600px; max-width: 100%; display: block; margin: auto"
+                :src="programme.annex"
+                alt=""
+                v-if="programme.annex"
+            />
+            <div style="display: block; margin: 10px;">
+                <el-button size="mini" @click="move(-1)" :disabled="index == 0">上一个</el-button>
+                <el-button size="mini" @click="move(1)" :disabled="(page - 1) * pageSize + index == totalElements - 1"
+                    >下一个</el-button
+                >
+                <el-button @click="showViedo = false" size="mini">关闭</el-button>
+            </div>
+        </el-dialog>
+        <programme-log :dialogVisible="isShow" @close="isShow = false" ref="public"></programme-log>
+    </div>
+</template>
+<script>
+import delChild from '@/mixins/delChild';
+import { mapState } from 'vuex';
+import pageableTable from '@/mixins/pageableTable';
+import ProgrammeLog from '@/components/ProgrammeLog1.vue';
+export default {
+    name: 'ProgrammeList',
+    mixins: [pageableTable, delChild],
+    data() {
+        return {
+            multipleMode: false,
+            search: '',
+            url: '/programme/showAll',
+            downloading: false,
+            competitionGroupOptions: [
+                { label: '个人', value: 'SINGLE' },
+                { label: '集体', value: 'COLLECTIVE' }
+            ],
+            form: {},
+            levelSingleOptions: [],
+            levelCollectiveOptions: [],
+            dialogUrl: '',
+            dialogCode: false,
+            isShow: false,
+            gradingOrganizationIdOptions: [],
+            organizationIdOptions: [],
+            performanceId: '',
+            performances: [],
+            performance: {},
+            artTypes: [],
+            optionProps: {
+                value: 'id',
+                label: 'name',
+                children: 'children',
+                multiple: false,
+                emitPath: false,
+                checkStrictly: true,
+                expandTrigger: 'hover'
+            },
+            showViedo: false,
+            showImg: false,
+            videoUrl: '',
+            annex: '',
+            programmeStatusOptions: [
+                { label: '未提交', value: 'INITIAL' },
+                { label: '已提交', value: 'SUBMIT' },
+                { label: '初选未通过', value: 'AUDIT_FAILED' },
+                { label: '审核未通过', value: 'REVIEW_FAILED' }
+            ],
+            showMore: false,
+            programme: {},
+            index: 0
+        };
+    },
+    created() {},
+    components: {
+        ProgrammeLog
+    },
+    computed: {
+        selection() {
+            return this.$refs.table.selection.map(i => i.id);
+        }
+    },
+    methods: {
+        programmeStatusFormatter(row, column, cellValue, index) {
+            let selectedOption = this.programmeStatusOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        competitionGroupFormatter(row, column, cellValue, index) {
+            let selectedOption = this.competitionGroupOptions.find(i => i.value === cellValue);
+            if (selectedOption) {
+                return selectedOption.label;
+            }
+            return '';
+        },
+        beforeGetData() {
+            let data = {
+                query: {}
+            };
+            if (this.$route.query.gid) {
+                data.query.gradingOrganizationId = this.$route.query.gid;
+            } else {
+                data.query.gradingOrganizationId = 0;
+            }
+            return data;
+        },
+        toggleMultipleMode(multipleMode) {
+            this.multipleMode = multipleMode;
+            if (!multipleMode) {
+                this.$refs.table.clearSelection();
+            }
+        },
+        addRow() {
+            this.$router.push({
+                path: '/programmeEdit',
+                query: {
+                    ...this.$route.query
+                }
+            });
+        },
+        showRow(row) {
+            this.isShow = true;
+            this.$refs.public.dataApi(row.id);
+        },
+        download() {
+            this.downloading = true;
+
+            let data = {
+                sort: 'gradingOrganizationId,asc;organizationId,asc;examPoint,asc',
+                size: 2000,
+                query: {
+                    programmeStatus: 'SUBMIT'
+                }
+            };
+            if (this.$route.query.gid) {
+                data.query.gradingOrganizationId = this.$route.query.gid;
+            } else {
+                data.query.gradingOrganizationId = 0;
+            }
+            this.$axios
+                .get('/programme/excelGO', {
+                    responseType: 'blob',
+                    params: data
+                })
+                .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);
+                });
+        },
+        operation1() {
+            this.$notify({
+                title: '提示',
+                message: this.selection
+            });
+        },
+        operation2() {
+            this.$message('操作2');
+        },
+        clearSearch() {
+            this.form = {};
+            this.getData();
+        },
+        getCode(value) {
+            return this.forTree(this.artTypes, value).code;
+        },
+        forTree(list, value) {
+            var result = null;
+            if (!list) {
+                return;
+            }
+            for (var i in list) {
+                if (result !== null) {
+                    break;
+                }
+                var item = list[i];
+                if (item.id == value) {
+                    result = item;
+                    break;
+                } else if (item.children && item.children.length > 0) {
+                    result = this.forTree(item.children, value);
+                }
+            }
+            return result;
+        },
+        // closeEvent() {
+        //     document.exitPictureInPicture();
+        // },
+        // playVideo(row) {
+        //     if (row.video) {
+        //         this.showViedo = true;
+        //         this.videoUrl = row.video;
+        //     } else {
+        //         this.$message.success('暂无视频');
+        //     }
+        // },
+        playImg(row) {
+            if (row.annex) {
+                this.showImg = true;
+                this.annex = row.annex;
+            } else {
+                this.$message.success('暂无图片');
+            }
+        },
+        playVideo(row, index) {
+            this.index = index;
+            this.showViedo = true;
+            this.programme = row;
+        },
+        move(direction) {
+            const end = direction + this.index;
+            this.programme = { ...this.tableData[end] };
+            this.index = end;
+        }
+    }
+};
+</script>
+<style lang="less" scoped>
+.right {
+    float: right;
+}
+/deep/.el-form-item--mini.el-form-item,
+.el-form-item--small.el-form-item {
+    margin-bottom: 10px;
+}
+.videoDialog {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    .el-dialog {
+        max-width: 900px;
+        margin-top: 0px;
+
+        .close {
+            position: absolute;
+            right: 0px;
+            top: -42px;
+            width: 71px;
+            height: 32px;
+            background: #00000015;
+
+            font-size: 12px;
+            color: #fdffff;
+            line-height: 32px;
+            text-align: center;
+            cursor: pointer;
+
+            &:hover {
+                background: #00000055;
+            }
+        }
+    }
+    .el-dialog__header {
+        display: none;
+    }
+
+    .el-dialog__body {
+        padding: 0;
+
+        video {
+            display: block;
+            height: auto;
+            width: 100%;
+            outline: none;
+        }
+    }
+}
+</style>

+ 255 - 129
src/main/vue/src/views/performance/ProgrammeList.vue

@@ -7,7 +7,6 @@
                         <el-form-item label="展演活动名称">
                             <el-select
                                 v-model="performanceId"
-                                clearable
                                 filterable
                                 placeholder="展演活动名称"
                                 style="width: 100%"
@@ -22,51 +21,6 @@
                             </el-select>
                         </el-form-item>
                     </el-col>
-                    <el-col :span="8">
-                        <el-form-item label="考级机构名称">
-                            <el-select
-                                v-model="form.gradingOrganizationId"
-                                clearable
-                                filterable
-                                placeholder="考级机构"
-                                style="width: 100%"
-                            >
-                                <el-option
-                                    v-for="item in gradingOrganizationIdOptions"
-                                    :key="item.value"
-                                    :label="item.label"
-                                    :value="item.value"
-                                >
-                                </el-option>
-                            </el-select>
-                        </el-form-item>
-                    </el-col>
-                    <el-col :span="8">
-                        <el-form-item label="承办单位名称">
-                            <el-select
-                                v-model="form.organizationId"
-                                clearable
-                                filterable
-                                placeholder="承办单位"
-                                style="width: 100%"
-                            >
-                                <el-option
-                                    v-for="item in organizationIdOptions"
-                                    :key="item.value"
-                                    :label="item.label"
-                                    :value="item.value"
-                                >
-                                </el-option>
-                            </el-select>
-                        </el-form-item>
-                    </el-col>
-                </el-row>
-                <el-row>
-                    <el-col :span="8"
-                        ><el-form-item label="考级点名称">
-                            <el-input placeholder="考级点名称" v-model="search" clearable></el-input> </el-form-item
-                    ></el-col>
-
                     <el-col :span="8">
                         <el-form-item label="参赛专业">
                             <el-cascader
@@ -82,59 +36,153 @@
                             </el-cascader>
                         </el-form-item>
                     </el-col>
-                    <el-col :span="8"
-                        ><el-form-item label="参赛组别">
-                            <el-select v-model="form.competitionGroup" clearable filterable placeholder="参赛组别">
-                                <el-option
-                                    v-for="item in competitionGroupOptions"
-                                    :key="item.value"
-                                    :label="item.label"
-                                    :value="item.value"
-                                >
-                                </el-option>
-                            </el-select> </el-form-item
-                    ></el-col>
-                    <el-col :span="8"
-                        ><el-form-item label="参赛级别" v-if="form.competitionGroup">
-                            <el-select
-                                v-model="form.levelSettingId"
-                                clearable
-                                filterable
-                                placeholder="参赛级别"
-                                style="width: 100%"
-                                v-if="form.competitionGroup == 'SINGLE'"
-                            >
+                    <el-col :span="8">
+                        <el-form-item label="节目状态">
+                            <el-select v-model="form.programmeStatus" clearable>
                                 <el-option
-                                    v-for="item in levelSingleOptions"
+                                    v-for="item in programmeStatusOptions"
                                     :key="item.value"
                                     :label="item.label"
                                     :value="item.value"
-                                >
-                                    <span style="float: left">{{ item.label }}</span>
-                                    <span style="float: right; color: #8492a6; font-size: 13px">{{ item.desc }}</span>
-                                </el-option>
+                                ></el-option>
                             </el-select>
-                            <el-select
-                                v-model="form.levelSettingId"
-                                clearable
-                                filterable
-                                placeholder="请选择"
-                                style="width: 100%"
-                                v-else
+                        </el-form-item>
+                    </el-col>
+                </el-row>
+                <el-collapse-transition>
+                    <div v-show="showMore">
+                        <el-row>
+                            <el-col :span="8">
+                                <el-form-item label="考级机构名称">
+                                    <el-select
+                                        v-model="form.gradingOrganizationId"
+                                        clearable
+                                        filterable
+                                        placeholder="考级机构"
+                                        style="width: 100%"
+                                    >
+                                        <el-option
+                                            v-for="item in gradingOrganizationIdOptions"
+                                            :key="item.value"
+                                            :label="item.label"
+                                            :value="item.value"
+                                        >
+                                        </el-option>
+                                    </el-select>
+                                </el-form-item>
+                            </el-col>
+                            <el-col :span="8">
+                                <el-form-item label="承办单位名称">
+                                    <el-select
+                                        v-model="form.organizationId"
+                                        clearable
+                                        filterable
+                                        placeholder="承办单位"
+                                        style="width: 100%"
+                                    >
+                                        <el-option
+                                            v-for="item in organizationIdOptions"
+                                            :key="item.value"
+                                            :label="item.label"
+                                            :value="item.value"
+                                        >
+                                        </el-option>
+                                    </el-select>
+                                </el-form-item>
+                            </el-col>
+
+                            <el-col :span="8"
+                                ><el-form-item label="考级点名称">
+                                    <el-input
+                                        placeholder="考级点名称"
+                                        v-model="search"
+                                        clearable
+                                    ></el-input> </el-form-item
+                            ></el-col>
+                        </el-row>
+                        <el-row>
+                            <el-col :span="8">
+                                <el-form-item label="节目名称">
+                                    <el-input placeholder="节目名称" v-model="form.name" clearable></el-input>
+                                </el-form-item>
+                            </el-col>
+                            <el-col :span="8"
+                                ><el-form-item label="参赛组别">
+                                    <el-select
+                                        v-model="form.competitionGroup"
+                                        clearable
+                                        filterable
+                                        placeholder="参赛组别"
+                                    >
+                                        <el-option
+                                            v-for="item in competitionGroupOptions"
+                                            :key="item.value"
+                                            :label="item.label"
+                                            :value="item.value"
+                                        >
+                                        </el-option>
+                                    </el-select> </el-form-item
+                            ></el-col>
+
+                            <el-col :span="8"
+                                ><el-form-item label="参赛级别" v-if="form.competitionGroup">
+                                    <el-select
+                                        v-model="form.levelSettingId"
+                                        clearable
+                                        filterable
+                                        placeholder="参赛级别"
+                                        style="width: 100%"
+                                        v-if="form.competitionGroup == 'SINGLE'"
+                                    >
+                                        <el-option
+                                            v-for="item in levelSingleOptions"
+                                            :key="item.value"
+                                            :label="item.label"
+                                            :value="item.value"
+                                        >
+                                            <span style="float: left">{{ item.label }}</span>
+                                            <span style="float: right; color: #8492a6; font-size: 13px">{{
+                                                item.desc
+                                            }}</span>
+                                        </el-option>
+                                    </el-select>
+                                    <el-select
+                                        v-model="form.levelSettingId"
+                                        clearable
+                                        filterable
+                                        placeholder="请选择"
+                                        style="width: 100%"
+                                        v-else
+                                    >
+                                        <el-option
+                                            v-for="item in levelCollectiveOptions"
+                                            :key="item.value"
+                                            :label="item.label"
+                                            :value="item.value"
+                                        >
+                                            <span style="float: left">{{ item.label }}</span>
+                                            <span style="float: right; color: #8492a6; font-size: 13px">{{
+                                                item.desc
+                                            }}</span>
+                                        </el-option>
+                                    </el-select>
+                                </el-form-item></el-col
                             >
-                                <el-option
-                                    v-for="item in levelCollectiveOptions"
-                                    :key="item.value"
-                                    :label="item.label"
-                                    :value="item.value"
-                                >
-                                    <span style="float: left">{{ item.label }}</span>
-                                    <span style="float: right; color: #8492a6; font-size: 13px">{{ item.desc }}</span>
-                                </el-option>
-                            </el-select>
-                        </el-form-item></el-col
+                        </el-row>
+                    </div>
+                </el-collapse-transition>
+                <div style="width:100%;textAlign:center;margin-bottom:10px;">
+                    <el-button
+                        class="more"
+                        round
+                        type="primary"
+                        :plain="!showMore"
+                        :icon="showMore ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
+                        @click="showMore = !showMore"
+                        size="mini"
+                        >{{ showMore ? '隐藏查询区域' : '显示查询区域' }}</el-button
                     >
-                </el-row>
+                </div>
                 <el-form-item>
                     <el-button @click="getData" type="primary" icon="el-icon-search">查询 </el-button>
                     <el-button @click="clearSearch" type="primary">清空 </el-button>
@@ -177,20 +225,41 @@
             <el-table-column prop="quantity" label="参赛人数" min-width="70"> </el-table-column>
             <el-table-column prop="contact" label="联系人" min-width="68"> </el-table-column>
             <el-table-column prop="phone" label="联系电话" min-width="95"> </el-table-column>
-            <el-table-column prop="gradingOrganization" label="考级机构" show-overflow-tooltip min-width="160">
+            <el-table-column prop="gradingOrganizationId" label="考级机构" show-overflow-tooltip min-width="130">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+                <template slot-scope="{ row }">
+                    <span>{{ row.gradingOrganization }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="organizationId" label="承办单位" min-width="170">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+                <template slot-scope="{ row }">
+                    <span>{{ row.organization }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="examPoint" label="考级点" min-width="160">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
             </el-table-column>
-            <el-table-column prop="organization" label="承办单位" min-width="160"> </el-table-column>
-            <el-table-column prop="examPoint" label="考级点" min-width="160"> </el-table-column>
             <el-table-column
                 prop="programmeStatus"
                 label="节目状态"
-                min-width="180"
+                min-width="90"
                 :formatter="programmeStatusFormatter"
-            ></el-table-column>
+            >
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+            </el-table-column>
             <el-table-column label="操作" align="left" fixed="right" min-width="260">
-                <template slot-scope="{ row }">
+                <template slot-scope="{ row, $index }">
                     <el-button @click="showRow(row)" size="mini" plain>查看</el-button>
-                    <el-button
+                    <!-- <el-button
                         type="warning"
                         @click="playImg(row)"
                         v-if="
@@ -223,8 +292,8 @@
                         size="mini"
                         plain
                         >浏览图片</el-button
-                    >
-                    <el-button type="warning" @click="playVideo(row)" v-else size="mini" plain>浏览视频</el-button>
+                    > -->
+                    <el-button type="warning" @click="playVideo(row, $index)" size="mini" plain>查看作品</el-button>
                     <el-button
                         @click="audit(row, 'AUDIT_FAILED')"
                         type="danger"
@@ -242,7 +311,6 @@
                         >撤回</el-button
                     >
                     <!-- <el-button @click="showCode(row)" type="primary" size="mini" plain>查看二维码</el-button> -->
-                    <!-- <el-button @click="deleteRow(row)" type="danger" size="mini" plain>删除</el-button> -->
                 </template>
             </el-table-column>
         </el-table>
@@ -274,23 +342,61 @@
             </div>
         </el-dialog>
 
-        <el-dialog class="videoDialog" destroy-on-close center append-to-body :visible.sync="showViedo" width="70%">
+        <!-- <el-dialog class="videoDialog" destroy-on-close center append-to-body :visible.sync="showViedo" width="70%">
+            <video
+                :src="programme.video"
+                controls
+                style="height: 600px; width: 85%; margin: 0 auto"
+                v-if="programme.video"
+            >
+                您的浏览器不支持 video 标签。
+            </video>
+            <div style="width: 85%; height:600px;margin: 0 auto" v-if="programme.annex">
+                <img style="max-height:100%; max-width: 100%; " :src="programme.annex" alt="" />
+            </div>
+            <div style="margin: 10px 10px">
+                <el-button size="mini" @click="move(-1)" :disabled="index == 0">上一个</el-button>
+                <el-button size="mini" @click="move(1)" :disabled="(page - 1) * pageSize + index == totalElements - 1"
+                    >下一个</el-button
+                >
+                <el-button @click="showViedo = false" size="mini">关闭</el-button>
+            </div>
+        </el-dialog> -->
+        <el-dialog
+            :title="programme.name"
+            class="videoDialog"
+            destroy-on-close
+            center
+            append-to-body
+            :visible.sync="showViedo"
+            width="auto"
+        >
             <video
-                :src="videoUrl"
-                controlsList="nodownload noremote footbar"
+                :src="programme.video"
                 controls
-                style="height: 600px; width: 100%"
-                oncontextmenu="return false;"
-                ref="video"
-                v-if="showViedo"
+                style="max-height: 600px; max-width: 100%; margin: 0 auto"
+                v-if="programme.video"
             >
                 您的浏览器不支持 video 标签。
             </video>
+            <img
+                style="max-height: 600px; max-width: 100%; display: block; margin: auto"
+                :src="programme.annex"
+                alt=""
+                v-if="programme.annex"
+            />
+            <div style="display: block; margin: 10px;">
+                <el-button size="mini" @click="move(-1)" :disabled="index == 0">上一个</el-button>
+                <el-button
+                    size="mini"
+                    @click="move(1)"
+                    :disabled="(page - 1) * pageSize + index == totalElements - 1 || index >= pageSize - 1"
+                    >下一个</el-button
+                >
+                <el-button @click="showViedo = false" size="mini">关闭</el-button>
+            </div>
         </el-dialog>
         <programme-log :dialogVisible="isShow" @close="isShow = false" ref="public"></programme-log>
-        <el-dialog class="videoDialog" destroy-on-close center append-to-body :visible.sync="showImg" width="35%">
-            <img style="height: 100%; width: 100%;" :src="annex" alt="" />
-        </el-dialog>
     </div>
 </template>
 <script>
@@ -343,7 +449,10 @@ export default {
                 { label: '已提交', value: 'SUBMIT' },
                 { label: '初选未通过', value: 'AUDIT_FAILED' },
                 { label: '审核未通过', value: 'REVIEW_FAILED' }
-            ]
+            ],
+            showMore: false,
+            programme: {},
+            index: 0
         };
     },
     created() {
@@ -480,7 +589,6 @@ export default {
         },
         beforeGetData() {
             let data = {
-                sort: 'createdAt,desc',
                 query: {}
             };
             if (this.form.competitionGroup) {
@@ -504,6 +612,12 @@ export default {
             if (this.review) {
                 data.query.programmeStatus = 'SUBMIT';
             }
+            if (this.form.name) {
+                data.query.name = this.form.name;
+            }
+            if (this.form.programmeStatus) {
+                data.query.programmeStatus = this.form.programmeStatus;
+            }
             return data;
         },
         toggleMultipleMode(multipleMode) {
@@ -528,7 +642,8 @@ export default {
             this.downloading = true;
 
             let data = {
-                sort: 'createdAt,desc',
+                sort: 'programmeStatus,desc',
+                size: 1000,
                 query: {}
             };
             if (this.form.competitionGroup) {
@@ -549,6 +664,12 @@ export default {
             if (this.performanceId) {
                 data.query.performanceId = this.performanceId;
             }
+            if (this.form.name) {
+                data.query.name = this.form.name;
+            }
+            if (this.form.programmeStatus) {
+                data.query.programmeStatus = this.form.programmeStatus;
+            }
 
             this.$axios
                 .get('/programme/excel', {
@@ -599,14 +720,9 @@ export default {
         showCode(row) {
             this.dialogCode = true;
             this.dialogUrl =
-                'http://wljtest.izouma.com/h5/home?performanceId=' + row.performanceId + '&programmeId=' + row.id;
+                'http://yskj.njlyw.cn:8081/h5/home?performanceId=' + row.performanceId + '&programmeId=' + row.id;
         },
         clearSearch() {
-            // this.competitionGroup = '';
-            // this.levelSettingId = '';
-            // this.gradingOrganizationId = '';
-            // this.organizationId = '';
-            // this.specialtyId = '';
             this.form = {};
             this.getData();
         },
@@ -635,14 +751,14 @@ export default {
         // closeEvent() {
         //     document.exitPictureInPicture();
         // },
-        playVideo(row) {
-            if (row.video) {
-                this.showViedo = true;
-                this.videoUrl = row.video;
-            } else {
-                this.$message.success('暂无视频');
-            }
-        },
+        // playVideo(row) {
+        //     if (row.video) {
+        //         this.showViedo = true;
+        //         this.videoUrl = row.video;
+        //     } else {
+        //         this.$message.success('暂无视频');
+        //     }
+        // },
         playImg(row) {
             if (row.annex) {
                 this.showImg = true;
@@ -689,6 +805,16 @@ export default {
                     });
                     this.$set(row, 'loading', false);
                 });
+        },
+        playVideo(row, index) {
+            this.index = index;
+            this.showViedo = true;
+            this.programme = row;
+        },
+        move(direction) {
+            const end = direction + this.index;
+            this.programme = { ...this.tableData[end] };
+            this.index = end;
         }
     }
 };

+ 126 - 34
src/main/vue/src/views/performance/ProgrammeOrgList.vue

@@ -130,6 +130,7 @@
                 <el-form-item>
                     <el-button @click="canAdd" type="primary" icon="el-icon-search">查询 </el-button>
                     <el-button @click="addRow" type="primary" icon="el-icon-plus" v-if="add">添加 </el-button>
+                    <!-- <el-button @click="addRow" type="primary" icon="el-icon-plus">添加 </el-button> -->
                     <el-upload
                         :action="uploadUrl"
                         :before-upload="beforeUpload"
@@ -139,9 +140,40 @@
                         :on-success="onSuccess"
                         class="uploader"
                         :on-error="onfail"
+                        :loading="loading"
+                        :disabled="loading"
                     >
-                        <el-button slot="trigger" type="primary" icon="el-icon-upload2" v-if="add">批量上传</el-button>
+                        <el-button
+                            slot="trigger"
+                            type="primary"
+                            icon="el-icon-upload2"
+                            v-if="add"
+                            :loading="loading"
+                            :disabled="loading"
+                            >批量上传</el-button
+                        >
                     </el-upload>
+                    <!-- <el-upload
+                        :action="uploadUrl"
+                        :before-upload="beforeUpload"
+                        :headers="headers"
+                        :show-file-list="false"
+                        ref="upload"
+                        :on-success="onSuccess"
+                        class="uploader"
+                        :on-error="onfail"
+                        :loading="loading"
+                        :disabled="loading"
+                    >
+                        <el-button
+                            slot="trigger"
+                            type="primary"
+                            icon="el-icon-upload2"
+                            :loading="loading"
+                            :disabled="loading"
+                            >批量上传</el-button
+                        >
+                    </el-upload> -->
                     <el-button
                         @click="download"
                         type="primary"
@@ -167,7 +199,7 @@
             :height="tableHeight"
         >
             <el-table-column v-if="multipleMode" align="center" type="selection" width="50"> </el-table-column>
-            <el-table-column prop="id" label="编号" width="80"> </el-table-column>
+            <el-table-column prop="id" label="编号" width="80" fixed="left"> </el-table-column>
             <el-table-column prop="name" label="节目名称" fixed="left"> </el-table-column>
             <el-table-column prop="specialty" label="参赛专业"> </el-table-column>
             <el-table-column
@@ -182,28 +214,50 @@
             <el-table-column prop="quantity" label="参赛人数" min-width="70"> </el-table-column>
             <el-table-column prop="contact" label="联系人" min-width="68"> </el-table-column>
             <!-- <el-table-column prop="phone" label="联系电话" min-width="95"> </el-table-column> -->
-            <el-table-column prop="gradingOrganization" label="考级机构" show-overflow-tooltip min-width="160">
+            <el-table-column prop="gradingOrganizationId" label="考级机构" show-overflow-tooltip min-width="160">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+                <template slot-scope="{ row }">
+                    <span>{{ row.gradingOrganization }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="organizationId" label="承办单位" min-width="180">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+                <template slot-scope="{ row }">
+                    <span>{{ row.organization }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column prop="examPoint" label="考级点" min-width="160">
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
             </el-table-column>
-            <el-table-column prop="organization" label="承办单位" min-width="180"> </el-table-column>
             <el-table-column
                 prop="programmeStatus"
                 label="节目状态"
                 min-width="180"
                 :formatter="programmeStatusFormatter"
-            ></el-table-column>
+            >
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
+            </el-table-column>
             <!-- <el-table-column prop="examPoint" label="考级点" min-width="160"> </el-table-column> -->
             <el-table-column label="操作" align="center" fixed="right" min-width="300">
-                <template slot-scope="{ row }">
+                <template slot-scope="{ row, $index }">
                     <el-button @click="showRow(row)" size="mini" plain>查看</el-button>
                     <el-button
                         type="success"
                         @click="editRow(row)"
                         size="mini"
                         plain
-                        v-if="row.programmeStatus == 'INITIAL'"
+                        v-if="row.programmeStatus == 'INITIAL' && add"
                         >编辑</el-button
                     >
-                    <el-button
+                    <!-- <el-button
                         type="warning"
                         @click="playImg(row)"
                         v-if="
@@ -237,7 +291,8 @@
                         plain
                         >浏览图片</el-button
                     >
-                    <el-button type="warning" @click="playVideo(row)" v-else size="mini" plain>浏览视频</el-button>
+                    <el-button type="warning" @click="playVideo(row)" v-else size="mini" plain>浏览视频</el-button> -->
+                    <el-button type="warning" @click="playVideo(row, $index)" size="mini" plain>查看作品</el-button>
                     <el-button
                         @click="showCode(row)"
                         type="primary"
@@ -278,21 +333,39 @@
             </div>
         </el-dialog>
 
-        <el-dialog class="videoDialog" destroy-on-close center append-to-body :visible.sync="showViedo" width="70%">
+        <el-dialog
+            :title="programme.name"
+            class="videoDialog"
+            destroy-on-close
+            center
+            append-to-body
+            :visible.sync="showViedo"
+            width="auto"
+        >
             <video
-                :src="videoUrl"
-                controlsList="nodownload noremote footbar"
+                :src="programme.video"
                 controls
-                style="height: 100%; max-width: 100%"
-                oncontextmenu="return false;"
-                ref="video"
-                v-if="showViedo"
+                style="max-height: 600px; max-width: 100%; margin: 0 auto"
+                v-if="programme.video"
             >
                 您的浏览器不支持 video 标签。
             </video>
-        </el-dialog>
-        <el-dialog class="videoDialog" destroy-on-close center append-to-body :visible.sync="showImg" width="35%">
-            <img style="height: 100%; max-width: 100%" :src="annex" alt="" />
+            <img
+                style="max-height: 600px; max-width: 100%; display: block; margin: auto"
+                :src="programme.annex"
+                alt=""
+                v-if="programme.annex"
+            />
+            <div style="display: block; margin: 10px">
+                <el-button size="mini" @click="move(-1)" :disabled="index == 0">上一个</el-button>
+                <el-button
+                    size="mini"
+                    @click="move(1)"
+                    :disabled="(page - 1) * pageSize + index == totalElements - 1 || index >= pageSize - 1"
+                    >下一个</el-button
+                >
+                <el-button @click="showViedo = false" size="mini">关闭</el-button>
+            </div>
         </el-dialog>
     </div>
 </template>
@@ -347,7 +420,10 @@ export default {
                 { label: '已提交', value: 'SUBMIT' },
                 { label: '初选未通过', value: 'AUDIT_FAILED' },
                 { label: '审核未通过', value: 'REVIEW_FAILED' }
-            ]
+            ],
+            loading: false,
+            programme: {},
+            index: 0
         };
     },
     created() {
@@ -477,7 +553,6 @@ export default {
         },
         beforeGetData() {
             let data = {
-                sort: 'createdAt,desc',
                 query: {
                     organizationId: this.organization.id,
                     performanceId: Number(this.$route.query.pid)
@@ -540,7 +615,8 @@ export default {
             this.downloading = true;
 
             let data = {
-                sort: 'createdAt,desc',
+                sort: 'programmeStatus,desc',
+                size: 1000,
                 query: {
                     organizationId: this.organization.id
                 }
@@ -589,6 +665,7 @@ export default {
                 });
         },
         downloadTemp() {
+            this.downloading = true;
             this.$axios
                 .get('/programme/excelTemp', {
                     responseType: 'blob'
@@ -636,7 +713,7 @@ export default {
         showCode(row) {
             this.dialogCode = true;
             this.dialogUrl =
-                'http://wljtest.izouma.com/h5/home?performanceId=' + row.performanceId + '&programmeId=' + row.id;
+                'http://yskj.njlyw.cn:8081/h5/home?performanceId=' + row.performanceId + '&programmeId=' + row.id;
         },
         clearSearch() {
             this.form = {};
@@ -667,11 +744,11 @@ export default {
         // closeEvent() {
         //     document.exitPictureInPicture();
         // },
-        playVideo(row) {
-            console.log(row);
-            this.showViedo = true;
-            this.videoUrl = row.video;
-        },
+        // playVideo(row) {
+        //     console.log(row);
+        //     this.showViedo = true;
+        //     this.videoUrl = row.video;
+        // },
         playImg(row) {
             console.log(row);
             this.showImg = true;
@@ -680,11 +757,13 @@ export default {
         upload() {},
         onfail(e) {
             console.log(e);
-            this.$message.error('失败');
+            this.$message.error('失败:' + e);
+            this.loading = false;
             this.getData();
         },
         onSuccess() {
             this.$message.success('上传成功');
+            this.loading = false;
             this.getData();
         },
         beforeUpload() {
@@ -692,18 +771,31 @@ export default {
                 confirmButtonText: '确定',
                 cancelButtonText: '取消',
                 type: 'warning'
+            }).then(() => {
+                this.loading = true;
             });
         },
         canAdd() {
             let data = this.performances.find(item => {
                 return item.id == this.performanceId;
             });
-            if (data.endDate >= this.currentTime) {
-                this.add = true;
-            } else {
-                this.add = false;
-            }
+            // if (data.endDate >= this.currentTime) {
+            //     this.add = true;
+            // } else {
+            //     this.add = false;
+            // }
+            this.add = data.close;
             this.getData();
+        },
+        playVideo(row, index) {
+            this.index = index;
+            this.showViedo = true;
+            this.programme = row;
+        },
+        move(direction) {
+            const end = direction + this.index;
+            this.programme = { ...this.tableData[end] };
+            this.index = end;
         }
     }
 };

+ 3 - 7
src/main/vue/src/views/performance/ProgrammeScoreList.vue

@@ -183,7 +183,7 @@
                         <el-button
                             size="mini"
                             @click="move(1)"
-                            :disabled="(page - 1) * pageSize + index == totalElements - 1"
+                            :disabled="(page - 1) * pageSize + index == totalElements - 1 || index >= pageSize - 1"
                             >下一个</el-button
                         >
                         <el-button @click="showViedo = false" size="mini">关闭</el-button>
@@ -464,12 +464,8 @@ export default {
         },
         playVideo(row, index) {
             this.index = index;
-            if (row.video) {
-                this.showViedo = true;
-                this.programme = row;
-            } else {
-                this.$message.success('暂无视频');
-            }
+            this.showViedo = true;
+            this.programme = row;
         },
         move(direction) {
             const end = direction + this.index;

+ 7 - 24
src/main/vue/src/views/rate/RateDistrictList.vue

@@ -280,25 +280,6 @@
             >
             </el-pagination>
         </div>
-        <!-- <el-dialog title="退回缘由" :visible.sync="dialogDismiss" width="500px" center>
-            <div style="height: 150px;width:330px;margin:2px auto">
-                <label style="margin-right: 10px">退回缘由</label>
-                <el-select
-                    v-model="reason"
-                    filterable
-                    allow-create
-                    default-first-option
-                    clearable
-                    placeholder="请选择缘由"
-                    style="width: 70%"
-                >
-                    <el-option v-for="item in dismissReason" :key="item" :label="item" :value="item"> </el-option>
-                </el-select>
-                <div style="margin: 45px 0 0 240px">
-                    <el-button type="primary" @click="saveDismiss">确认</el-button>
-                </div>
-            </div>
-        </el-dialog> -->
         <el-dialog title="退回缘由" :visible.sync="dialogDismiss" width="500px" center>
             <div style="height: 150px;width:400px;margin:2px auto">
                 <el-input
@@ -354,7 +335,7 @@ export default {
         },
         ...mapState(['userInfo']),
         moreWidth() {
-            let larges = ['FIRST_REVIEW_COMPLETED', 'FIRST_REVIEW_COMPLETED', 'ACCEPT'];
+            let larges = ['FIRST_REVIEW_COMPLETED', 'FIRST_REVIEW_COMPLETED', 'ACCEPT', 'REVIEW_DENY'];
             let mendus = ['SUBMIT_PAPER_MATERIALS'];
 
             let list = [...this.tableData];
@@ -363,9 +344,8 @@ export default {
                 if (larges.includes(list[i].status)) {
                     size = 300;
                     break;
-                }
-                if (mendus.includes(list[i].status)) {
-                    size = 200;
+                } else if (mendus.includes(list[i].status)) {
+                    size = 220;
                     continue;
                 }
             }
@@ -393,7 +373,10 @@ export default {
             return '';
         },
         beforeGetData() {
-            let data = { sort: 'createdAt,desc', query: { submit: true, district: this.userInfo.district } };
+            let data = {
+                sort: 'sort,desc;score,desc;',
+                query: { submit: true, district: this.userInfo.district }
+            };
             if (this.search) {
                 data.search = this.search;
             }

+ 2 - 30
src/main/vue/src/views/rate/RateDistrictListDone.vue

@@ -178,14 +178,6 @@
                     >
                         退回申请
                     </el-button>
-                    <!-- <el-button
-                        @click="supervision(row.id)"
-                        type="success"
-                        size="mini"
-                        plain
-                        v-if="(row.status === 'ASSIGN_EXPERT') & display"
-                        >分配专家组</el-button
-                    > -->
                     <el-button
                         v-if="row.status === 'SUBMIT_PAPER_MATERIALS'"
                         type="success"
@@ -220,25 +212,6 @@
             >
             </el-pagination>
         </div>
-        <!-- <el-dialog title="退回缘由" :visible.sync="dialogDismiss" width="500px" center>
-            <div style="height: 150px;width:330px;margin:2px auto">
-                <label style="margin-right: 10px">退回缘由</label>
-                <el-select
-                    v-model="reason"
-                    filterable
-                    allow-create
-                    default-first-option
-                    clearable
-                    placeholder="请选择缘由"
-                    style="width: 70%"
-                >
-                    <el-option v-for="item in dismissReason" :key="item" :label="item" :value="item"> </el-option>
-                </el-select>
-                <div style="margin: 45px 0 0 240px">
-                    <el-button type="primary" @click="saveDismiss">确认</el-button>
-                </div>
-            </div>
-        </el-dialog> -->
         <el-dialog title="退回缘由" :visible.sync="dialogDismiss" width="500px" center>
             <div style="height: 150px;width:400px;margin:2px auto">
                 <el-input
@@ -305,7 +278,7 @@ export default {
                     break;
                 }
                 if (mendus.includes(list[i].status)) {
-                    size = 200;
+                    size = 220;
                     continue;
                 }
             }
@@ -341,7 +314,7 @@ export default {
             //     }
             // };
             let data = {
-                sort: 'createdAt,desc',
+                sort: 'sort,desc;score,desc;',
                 query: {
                     submit: true,
                     district: this.userInfo.district,
@@ -350,7 +323,6 @@ export default {
                         'ASSIGN_EXPERT',
                         'REVIEW_PENDING',
                         'SUBMIT_GRADE',
-                        'SUBMIT_PAPER_MATERIALS',
                         'COLLECT_PAPER_MATERIALS',
                         'COMPLETE'
                     ]

+ 10 - 24
src/main/vue/src/views/rate/RateDistrictListPending.vue

@@ -212,25 +212,6 @@
             >
             </el-pagination>
         </div>
-        <!-- <el-dialog title="退回缘由" :visible.sync="dialogDismiss" width="500px" center>
-            <div style="height: 150px;width:330px;margin:2px auto">
-                <label style="margin-right: 10px">退回缘由</label>
-                <el-select
-                    v-model="reason"
-                    filterable
-                    allow-create
-                    default-first-option
-                    clearable
-                    placeholder="请选择缘由"
-                    style="width: 70%"
-                >
-                    <el-option v-for="item in dismissReason" :key="item" :label="item" :value="item"> </el-option>
-                </el-select>
-                <div style="margin: 45px 0 0 240px">
-                    <el-button type="primary" @click="saveDismiss">确认</el-button>
-                </div>
-            </div>
-        </el-dialog> -->
         <el-dialog title="退回缘由" :visible.sync="dialogDismiss" width="500px" center>
             <div style="height: 150px;width:400px;margin:2px auto">
                 <el-input
@@ -295,9 +276,8 @@ export default {
                 if (larges.includes(list[i].status)) {
                     size = 300;
                     break;
-                }
-                if (mendus.includes(list[i].status)) {
-                    size = 200;
+                } else if (mendus.includes(list[i].status)) {
+                    size = 220;
                     continue;
                 }
             }
@@ -326,11 +306,17 @@ export default {
         },
         beforeGetData() {
             let data = {
-                sort: 'createdAt,desc',
+                sort: 'sort,desc;score,desc;',
                 query: {
                     submit: true,
                     district: this.userInfo.district,
-                    status: ['FIRST_REVIEW_PENDING', 'ACCEPT', 'FIRST_REVIEW_COMPLETED', 'REVIEW_DENY']
+                    status: [
+                        'FIRST_REVIEW_PENDING',
+                        'ACCEPT',
+                        'FIRST_REVIEW_COMPLETED',
+                        'REVIEW_DENY',
+                        'SUBMIT_PAPER_MATERIALS'
+                    ]
                 }
             };
             if (this.search) {

+ 3 - 62
src/main/vue/src/views/rate/RateList.vue

@@ -1,68 +1,6 @@
 <template>
     <div class="list-view">
         <div class="filters-container">
-            <!-- <el-input placeholder="输入关键字" v-model="search" clearable class="filter-item"></el-input>
-             <el-button @click="addRow" type="primary" icon="el-icon-plus" class="filter-item">创建申请 </el-button> -->
-            <!-- <el-button
-                @click="download"
-                type="primary"
-                icon="el-icon-download"
-                :loading="downloading"
-                class="filter-item"
-                :disabled="totalElements <= 0"
-                >导出EXCEL
-            </el-button>
-            <el-select v-model="year" placeholder="请选择年度" class="filter-item" clearable>
-                <el-option v-for="item in years" :key="item" :value="item" :label="item + '年'"></el-option>
-            </el-select>
-            <el-select v-model="agency" placeholder="所属考级机构" multiple class="filter-item">
-                <el-option
-                    v-for="(item, index) in examination"
-                    :key="index"
-                    :value="item.value"
-                    :label="item.label"
-                ></el-option>
-            </el-select>
-            <el-input
-                placeholder="输入承办单位名称"
-                v-model="search"
-                clearable
-                class="filter-item"
-                @change="getData"
-            ></el-input>
-            <el-select
-                style="width: 220px"
-                v-model="status"
-                placeholder="请选择的状态"
-                class="filter-item"
-                multiple
-                clearable
-                @change="getData"
-            >
-                <el-option
-                    v-for="item in statusOptions"
-                    :key="item.value"
-                    :label="item.label"
-                    :value="item.value"
-                ></el-option>
-            </el-select>
-            <el-select
-                style="width: 220px"
-                v-model="grade"
-                placeholder="请选择的等级"
-                class="filter-item"
-                multiple
-                clearable
-                @change="getData"
-            >
-                <el-option
-                    v-for="item in gradeOptions"
-                    :key="item.value"
-                    :label="item.label"
-                    :value="item.value"
-                ></el-option>
-            </el-select> -->
-            <!-- <el-button @click="getData" type="primary" icon="el-icon-search" class="filter-item">搜索 </el-button> -->
             <div>
                 <el-col :span="7">
                     <span class="span-size">申请年度</span>
@@ -193,6 +131,9 @@
                     <span v-if="row.score">{{ row.score }}</span>
                     <span v-else>暂无</span>
                 </template>
+                <template slot="header" slot-scope="{ column }">
+                    <sortable-header :column="column" :current-sort="sort" @changeSort="changeSort"> </sortable-header>
+                </template>
             </el-table-column>
             <el-table-column prop="grade" label="等级">
                 <template slot-scope="{ row }">

+ 35 - 1
src/main/vue/src/views/rate/RateListDone.vue

@@ -122,6 +122,12 @@
                         :disabled="totalElements <= 0"
                         >导出EXCEL
                     </el-button>
+                    <el-button type="primary" :loading="downloading" class="filter-item" @click="batchSendSms(true)"
+                        >公告短信通知
+                    </el-button>
+                    <el-button type="primary" :loading="downloading" class="filter-item" @click="batchSendSms(false)"
+                        >提交材料短信通知
+                    </el-button>
                 </el-col>
             </div>
         </div>
@@ -345,7 +351,7 @@ export default {
         },
         beforeGetData() {
             let data = {
-                sort: 'sort,desc;createdAt,desc',
+                sort: 'sort,desc;score,desc;createdAt,desc',
                 query: {
                     submit: true,
                     status: ['REVIEW_PENDING', 'SUBMIT_PAPER_MATERIALS', 'COMPLETE']
@@ -603,6 +609,34 @@ export default {
                     });
                     this.$set(row, 'loading', false);
                 });
+        },
+        batchSendSms(res) {
+            this.$confirm('发送短信后不可撤回,确认发送吗?', '提示', {
+                confirmButtonText: '确认',
+                cancelButtonText: '取消',
+                type: 'warning'
+            })
+                .then(() => {
+                    this.$http
+                        .post('/rate/batchSendSms', {
+                            announcement: res
+                        })
+                        .then(res => {
+                            this.$message.success('发送成功');
+                            this.getData();
+                        })
+                        .catch(e => {
+                            console.log(e);
+                            this.$message.error(e.error);
+                        });
+                })
+                .catch(() => {
+                    this.$message({
+                        type: 'info',
+                        message: '已取消'
+                    });
+                    this.$set(row, 'loading', false);
+                });
         }
     }
 };

+ 56 - 1
src/main/vue/src/views/rate/RateListPending.vue

@@ -122,6 +122,7 @@
                         :disabled="totalElements <= 0"
                         >导出EXCEL
                     </el-button>
+                    <el-button @click="dialogRatio = true" type="primary">设置等级</el-button>
                 </el-col>
             </div>
         </div>
@@ -256,6 +257,35 @@
                 </div>
             </div>
         </el-dialog>
+        <el-dialog title="等级比例" :visible.sync="dialogRatio" width="500px" center>
+            <div style="height: 150px;width:400px;margin:0 0 2px 80px">
+                <el-form :form="ratioForm">
+                    <el-form-item label="优秀比例(%)">
+                        <el-input-number
+                            v-model="ratioForm.excellent"
+                            :min="0"
+                            :max="100"
+                            @change="changeEligible"
+                            style="width: 160px"
+                        ></el-input-number>
+                    </el-form-item>
+                    <el-form-item label="合格比例(%)">
+                        <el-input-number
+                            v-model="ratioForm.eligible"
+                            :min="0"
+                            :max="100"
+                            @change="changeExcellent"
+                            style="width: 160px"
+                        ></el-input-number>
+                    </el-form-item>
+                    <el-form-item>
+                        <el-button style="margin-left: 170px" type="primary" size="mini" @click="gradeRatio"
+                            >确定</el-button
+                        >
+                    </el-form-item>
+                </el-form>
+            </div>
+        </el-dialog>
     </div>
 </template>
 <script>
@@ -291,7 +321,9 @@ export default {
             year: '',
             districts: [],
             district: '',
-            dateRange: ''
+            dateRange: '',
+            dialogRatio: false,
+            ratioForm: {}
         };
     },
     created() {
@@ -612,6 +644,29 @@ export default {
                     });
                     this.$set(row, 'loading', false);
                 });
+        },
+        changeEligible(res) {
+            this.ratioForm.eligible = 100 - res;
+        },
+        changeExcellent(res) {
+            this.ratioForm.excellent = 100 - res;
+        },
+        gradeRatio() {
+            this.$http
+                .post('/rate/gradeRatio', {
+                    excellent: this.ratioForm.excellent,
+                    eligible: this.ratioForm.eligible
+                })
+                .then(res => {
+                    this.$message.success('等级设置成功');
+                    this.getData();
+                    this.dialogRatio = false;
+                })
+                .catch(e => {
+                    console.log(e);
+                    this.dialogRatio = false;
+                    this.$message.error(e.error);
+                });
         }
     }
 };

+ 49 - 6
src/main/vue/src/views/rate/RateOrganizerList.vue

@@ -49,7 +49,7 @@
                     <span v-else><el-tag type="info">暂无</el-tag></span>
                 </template>
             </el-table-column>
-            <el-table-column label="操作" align="center" fixed="right" min-width="150">
+            <el-table-column label="操作" align="center" fixed="right" min-width="160">
                 <template slot-scope="{ row }">
                     <el-button @click="editRow(row)" type="primary" size="mini" plain>
                         <span v-if="row.status == 'FIRST_REVIEW_DENY' || !row.submit">编辑资料</span>
@@ -65,7 +65,7 @@
                         >撤回
                     </el-button>
                     <el-button
-                        @click="word(row)"
+                        @click="aletrLog(row)"
                         type="primary"
                         :loading="downloading"
                         size="mini"
@@ -98,6 +98,22 @@
             >
             </el-pagination>
         </div>
+        <el-dialog title="提示信息" width="500px" :visible.sync="dialogVisible" center>
+            <div>
+                <span class="content"
+                    >下载文件需要合并所有上传的信息,并转成pdf,可能会比较大。如遇无法下载,可试以下方法:</span
+                ><br />
+                <span class="content">1.点击复制链接按钮,复制下载地址用任何其他方式下载;</span><br />
+                <span class="content">2.刷新页面,查看网络是否流畅;</span><br />
+                <span class="content">3.更换最新的谷歌(chrome)浏览器,再点击下载文件;</span><br />
+                <span class="content">4.如还是长时间没有反应,可联系技术支持微信:PrettyFairyLi;</span><br />
+                <span class="content">链接地址:{{ rate.pdfUrl }}</span>
+            </div>
+            <div style="float: right; padding: 10px;">
+                <el-button size="mini" @click="copy">复制链接</el-button>
+                <el-button @click="word()" type="primary" size="mini">继续下载</el-button>
+            </div>
+        </el-dialog>
     </div>
 </template>
 <script>
@@ -114,7 +130,9 @@ export default {
             search: '',
             url: '/rate/all',
             downloading: false,
-            canApply: false
+            canApply: false,
+            dialogVisible: false,
+            rate: {}
         };
     },
     created() {
@@ -214,10 +232,15 @@ export default {
                     }
                 });
         },
-        word(row) {
+        aletrLog(row) {
+            this.rate = row;
+            this.dialogVisible = true;
+        },
+        word() {
             this.downloading = true;
+            console.log(this.rate);
             this.$axios
-                .get('/rate/exportPdf/' + row.id, { responseType: 'blob' })
+                .get('/rate/exportPdf/' + this.rate.id, { responseType: 'blob' })
                 .then(res => {
                     console.log(res);
                     this.downloading = false;
@@ -233,6 +256,8 @@ export default {
                     console.log(e);
                     this.downloading = false;
                     this.$message.error(e.error);
+                    this.rate = {};
+                    this.dialogVisible = false;
                 });
             // this.$axios
             //     .get('/rate/export/' + row.id)
@@ -272,8 +297,26 @@ export default {
                         this.$message.error((e || {}).error || '撤回失败');
                     }
                 });
+        },
+        copy() {
+            this.$copyText(this.rate.pdfUrl).then(
+                e => {
+                    this.$message.success('复制成功');
+                },
+                e => {
+                    this.$message.warning('复制失败');
+                }
+            );
         }
     }
 };
 </script>
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.content {
+    font-size: 14px;
+    line-height: 25px;
+}
+/deep/ .el-dialog {
+    height: 330px;
+}
+</style>

+ 0 - 1
src/main/vue/src/views/user/UserList.vue

@@ -101,7 +101,6 @@ export default {
             if (this.search) {
                 data.search = this.search;
                 data.page = 0;
-                console.log();
             }
             console.log(this.getAdmin());
             if (!this.getAdmin()) {

+ 103 - 0
src/main/vue/src/widgets/BoardWidget.vue

@@ -0,0 +1,103 @@
+<template>
+    <widget-card :bodyStyle="bodyStyle" ref="container">
+        <template slot="header">
+            通知通告
+        </template>
+        <div class="boardList" :style="{ height: height + 'px' }">
+            <router-link
+                :underline="false"
+                :to="{
+                    path: '/announcementDetail',
+                    query: {
+                        id: item.id
+                    }
+                }"
+                class="board-item"
+                v-for="(item, index) in tableData"
+                :key="index"
+            >
+                <span>{{ item.title }}</span>
+                <span>{{ item.createdAt }}</span>
+            </router-link>
+            <div class="empty" v-if="isEmpty">暂无数据</div>
+        </div>
+    </widget-card>
+</template>
+<script>
+import WidgetCard from './WidgetCard';
+
+export default {
+    data() {
+        return {
+            bodyStyle: {},
+            tableData: [],
+            height: 200,
+            isEmpty: false
+        };
+    },
+    components: {
+        WidgetCard
+    },
+    mounted() {
+        this.$nextTick(() => {
+            this.height = this.$refs.container.$el.offsetHeight - 100;
+        });
+        this.$http
+            .post('/announcement/all', { size: 10, query: { type: 'NOTIFICATION' } }, { body: 'json' })
+            .then(res => {
+                this.tableData = res.content;
+                this.isEmpty = res.empty;
+            });
+    }
+};
+</script>
+<style lang="less" scoped>
+.info {
+    flex-grow: 1;
+    text-align: right;
+    .text {
+        color: #999;
+        font-size: 16px;
+        margin-bottom: 12px;
+    }
+    .num {
+        font-size: 20px;
+        color: #333;
+    }
+}
+.boardList {
+    .board-item + .board-item {
+        margin-top: 20px;
+    }
+    .board-item {
+        font-size: 14px;
+        margin-right: 15px;
+        line-height: 20px;
+        display: flex;
+        justify-content: space-between;
+
+        span {
+            &:first-child {
+                color: #000;
+                font-weight: bold;
+                white-space: nowrap;
+                text-overflow: ellipsis;
+                overflow: hidden;
+                word-break: break-all;
+            }
+            &:last-child {
+                color: #999;
+                flex-shrink: 0;
+            }
+        }
+    }
+    overflow: auto;
+}
+
+.empty {
+    font-size: 12px;
+    color: #999;
+    text-align: center;
+    padding: 50px;
+}
+</style>

+ 101 - 0
src/main/vue/src/widgets/PolicyWidget.vue

@@ -0,0 +1,101 @@
+<template>
+    <widget-card :bodyStyle="bodyStyle" ref="container">
+        <template slot="header">
+            政策文件
+        </template>
+        <div class="boardList" :style="{ height: height + 'px' }">
+            <router-link
+                :underline="false"
+                :to="{
+                    path: '/announcementDetail',
+                    query: {
+                        id: item.id
+                    }
+                }"
+                class="board-item"
+                v-for="(item, index) in tableData"
+                :key="index"
+            >
+                <span>{{ item.title }}</span>
+                <span>{{ item.createdAt }}</span>
+            </router-link>
+            <div class="empty" v-if="isEmpty">暂无数据</div>
+        </div>
+    </widget-card>
+</template>
+<script>
+import WidgetCard from './WidgetCard';
+
+export default {
+    data() {
+        return {
+            bodyStyle: {},
+            tableData: [],
+            height: 200,
+            isEmpty: false
+        };
+    },
+    components: {
+        WidgetCard
+    },
+    mounted() {
+        this.$nextTick(() => {
+            this.height = this.$refs.container.$el.offsetHeight - 100;
+        });
+        this.$http.post('/announcement/all', { size: 10, query: { type: 'POLICY' } }, { body: 'json' }).then(res => {
+            this.tableData = res.content;
+            this.isEmpty = res.empty;
+        });
+    }
+};
+</script>
+<style lang="less" scoped>
+.info {
+    flex-grow: 1;
+    text-align: right;
+    .text {
+        color: #999;
+        font-size: 16px;
+        margin-bottom: 12px;
+    }
+    .num {
+        font-size: 20px;
+        color: #333;
+    }
+}
+.boardList {
+    .board-item + .board-item {
+        margin-top: 20px;
+    }
+    .board-item {
+        font-size: 14px;
+        margin-right: 15px;
+        line-height: 20px;
+        display: flex;
+        justify-content: space-between;
+
+        span {
+            &:first-child {
+                color: #000;
+                font-weight: bold;
+                white-space: nowrap;
+                text-overflow: ellipsis;
+                overflow: hidden;
+                word-break: break-all;
+            }
+            &:last-child {
+                color: #999;
+                flex-shrink: 0;
+            }
+        }
+    }
+    overflow: auto;
+}
+
+.empty {
+    font-size: 12px;
+    color: #999;
+    text-align: center;
+    padding: 50px;
+}
+</style>

+ 16 - 0
src/main/vue/yarn.lock

@@ -2349,6 +2349,15 @@ cli-width@^2.0.0:
   resolved "https://registry.npm.taobao.org/cli-width/download/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
   integrity sha1-sEM9C06chH7xiGik7xb9X8gnHEg=
 
+clipboard@^2.0.0:
+  version "2.0.8"
+  resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
+  integrity sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==
+  dependencies:
+    good-listener "^1.2.2"
+    select "^1.1.2"
+    tiny-emitter "^2.0.0"
+
 clipboard@^2.0.6:
   version "2.0.6"
   resolved "https://registry.npm.taobao.org/clipboard/download/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
@@ -8379,6 +8388,13 @@ vue-cli-plugin-style-resources-loader@^0.1.4:
   resolved "https://registry.npm.taobao.org/vue-cli-plugin-style-resources-loader/download/vue-cli-plugin-style-resources-loader-0.1.4.tgz#6087a86132ea8125aa89e5f8e0a978fbc8cf6f59"
   integrity sha1-YIeoYTLqgSWqieX44Kl4+8jPb1k=
 
+vue-clipboard2@^0.3.3:
+  version "0.3.3"
+  resolved "https://registry.yarnpkg.com/vue-clipboard2/-/vue-clipboard2-0.3.3.tgz#331fec85f9d4f175eb0d4feaef4d77338562af36"
+  integrity sha512-aNWXIL2DKgJyY/1OOeITwAQz1fHaCIGvUFHf9h8UcoQBG5a74MkdhS/xqoYe7DNZdQmZRL+TAdIbtUs9OyVjbw==
+  dependencies:
+    clipboard "^2.0.0"
+
 vue-eslint-parser@^7.0.0:
   version "7.1.0"
   resolved "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.1.0.tgz?cache=0&sync_timestamp=1589539313907&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-eslint-parser%2Fdownload%2Fvue-eslint-parser-7.1.0.tgz#9cdbcc823e656b087507a1911732b867ac101e83"

+ 13 - 2
src/test/java/com/izouma/wenlvju/repo/RepoTest.java

@@ -206,7 +206,18 @@ public class RepoTest extends ApplicationTests {
 
     @Test
     public void test6() {
-        String phone = "18205083565";
-        System.out.println(phone.replace(phone.substring(3, phone.length() - 4), "****"));
+//        String phone = "18205083565";
+//        System.out.println(phone.replace(phone.substring(3, phone.length() - 4), "****"));
+        int sum1 = Math.round(75 * 20 / 100);
+        System.out.println(sum1);
+        int sum2 = Math.round(75 * 80 / 100);
+        System.out.println(sum1 + sum2);
+    }
+
+    @Test
+    public void test7(){
+        String url = "http://yskj.njlyw.cn:8081/files/pdf/material12409.pdf";
+        int start = url.indexOf("/pdf");
+        System.out.println(url.substring(start));
     }
 }

+ 1 - 1
src/test/java/com/izouma/wenlvju/repo/UserRepoTest.java

@@ -74,7 +74,7 @@ public class UserRepoTest {
 
     @Test
     public void test3() {
-        System.out.println(jwtTokenUtil.generateToken(JwtUserFactory.create(userRepo.findById(15132L)
+        System.out.println(jwtTokenUtil.generateToken(JwtUserFactory.create(userRepo.findById(17369L)
                 .orElseThrow(new BusinessException("用户不存在")))));
     }
 

+ 60 - 28
src/test/java/com/izouma/wenlvju/service/RateServiceTest.java

@@ -4,6 +4,7 @@ package com.izouma.wenlvju.service;
 import com.github.kevinsawicki.http.HttpRequest;
 import com.izouma.wenlvju.ApplicationTests;
 import com.izouma.wenlvju.domain.Rate;
+import com.izouma.wenlvju.enums.RateStatus;
 import com.izouma.wenlvju.exception.BusinessException;
 import com.izouma.wenlvju.repo.RateRepo;
 import com.lowagie.text.Document;
@@ -33,32 +34,44 @@ public class RateServiceTest extends ApplicationTests {
     }
 
     @Test
-    public void test2() throws UnsupportedEncodingException {
+    public void test2() {
 
-        Rate rate = rateRepo.findById(625L).orElseThrow(new BusinessException("无记录"));
-        List<InputStream> files = rateService.upLoad1(rate);
+//        Rate rate = rateRepo.findById(11825L).orElseThrow(new BusinessException("无记录"));
+        List<Rate> rates = rateRepo.findAllByStatusAndYearOrderByScoreDesc(RateStatus.COLLECT_PAPER_MATERIALS, "2021");
+        rates.forEach(rate -> {
 
-        String targetPath = "/Users/qiufangchao/Desktop/result.pdf";
-        // pdf合并工具类
-        PDFMergerUtility mergePdf = new PDFMergerUtility();
-//        for (File f : files) {
-//            if (f.exists() && f.isFile()) {
-        // 循环添加要合并的pdf
-//                mergePdf.addSource(f);
-//            }
-//        }
-        mergePdf.addSources(files);
-        // 设置合并生成pdf文件名称
-        mergePdf.setDestinationFileName(targetPath);
-        // 合并pdf
-        try {
-            mergePdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
-            for (InputStream is : files) {
-                is.close();
+            List<InputStream> files = null;
+            try {
+                files = rateService.upLoad1(rate);
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
             }
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
+
+            String targetPath = "/Users/qiufangchao/Desktop/rate/material" + rate.getId() + ".pdf";
+//            if (!new File(targetPath).exists()) {
+            // pdf合并工具类
+            PDFMergerUtility mergePdf = new PDFMergerUtility();
+            //for (File f : files) {
+            //      if (f.exists() && f.isFile()) {
+            // 循环添加要合并的pdf
+            //           mergePdf.addSource(f);
+            //      }
+            // }
+            mergePdf.addSources(files);
+            // 设置合并生成pdf文件名称
+            mergePdf.setDestinationFileName(targetPath);
+            // 合并pdf
+            try {
+                mergePdf.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
+                for (InputStream is : files) {
+                    is.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+//            }
+        });
+
 //        System.out.println(writer.toString());
 //        new File(targetPath);
 
@@ -122,9 +135,6 @@ public class RateServiceTest extends ApplicationTests {
 
     @Test
     public void test8() {
-
-//        String img = "https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/image/2021-04-29-12-39-59rzhrQYhu.jpg";
-
         Rate rate = rateRepo.findById(625L).orElseThrow(new BusinessException("wu"));
         List<String> imageUrllist = rate.getBusiness();
 
@@ -165,9 +175,31 @@ public class RateServiceTest extends ApplicationTests {
         System.out.println(rateService.reviewTimesMessage(rate));
     }
 
-
     @Test
     public void test10() {
-        System.out.println(rateRepo.countByExpertId(700l));
+        System.out.println(rateRepo.countByExpertId(700L));
     }
+
+    @Test
+    public void test11() {
+        Rate rate = rateRepo.findById(11825L).orElseThrow(new BusinessException("无记录"));
+        try {
+            rateService.mergePdf(rate);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    @Test
+    public void test12() {
+        List<Rate> rates = rateRepo.findAllByStatusAndYearOrderByScoreDesc(RateStatus.SUBMIT_PAPER_MATERIALS, "2021");
+        rates.forEach(rate -> {
+            String url = "/Users/qiufangchao/Desktop/rate/material" + rate.getId() + ".pdf";
+            rate.setPdfUrl(url);
+        });
+        rateRepo.saveAll(rates);
+
+    }
+
 }

+ 5 - 3
src/test/java/com/izouma/wenlvju/service/sms/NjwlSmsServiceTest.java

@@ -11,10 +11,12 @@ public class NjwlSmsServiceTest extends ApplicationTests {
 
     @Test
     public void test() {
-        njwlSmsService.sendSms("19951988293", "test");
+//        njwlSmsService.sendSms("15605172272", "【宁艺通】2021年南京考级承办单位等级评定工作已完成,拟评定结果已在南京市文化和旅游局官网公示。请你单位登陆“宁艺通”等级评定系统下载打印等级评定材料,并于11月15日前将纸质申报表及完整佐证材料(各2份)送属地区文化和旅游局履行线下审核程序,逾期不送,作自动放弃处理。");
+        String body = "尊敬的调研对象:\n" +
+                "您好,为贯彻落实国家、省、市关于“双减”工作相关文件精神,了解和掌握我市文化艺术类校外培训机构相关情况,市文旅局决定开展全市文化艺术类校外培训机构网上问卷调查,如从事文化艺术类校外培训,请登录:http://wljtest.izouma.com/h5/trainingInstitution,填写调查问卷,如不从事文化艺术类校外培训,请忽略本条信息,谢谢。\n";
+        ;
+        njwlSmsService.sendSms("19951988293", body);
         // {"expiryDate":"1623808467934","tokenKey":"1fb4796840d8a7b8d43e022e5a1f693c","data":{"phone":"19951988293","message":"test"},"appId":"189610","operationType":"ADD"}
-
-
     }
 
     @Test

+ 61 - 0
src/test/java/com/izouma/wenlvju/web/TrainingInstitutionControllerTest.java

@@ -0,0 +1,61 @@
+package com.izouma.wenlvju.web;
+
+
+import com.izouma.wenlvju.ApplicationTests;
+import com.izouma.wenlvju.converter.StringArrayConverter;
+import com.izouma.wenlvju.domain.TrainingInstitution;
+import com.izouma.wenlvju.dto.PageQuery;
+import com.izouma.wenlvju.repo.TrainingInstitutionRepo;
+import com.izouma.wenlvju.service.TrainingInstitutionService;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TrainingInstitutionControllerTest extends ApplicationTests {
+
+    @Autowired
+    private TrainingInstitutionController trainingInstitutionController;
+
+    @Autowired
+    private TrainingInstitutionService trainingInstitutionService;
+
+    @Autowired
+    private TrainingInstitutionRepo trainingInstitutionRepo;
+
+    @Test
+    public void test() throws InterruptedException {
+        long count = trainingInstitutionRepo.count();
+
+        PageQuery pageQuery = new PageQuery();
+        pageQuery.setSize(1000);
+        for (int i = 5; i < count / 1000; i++) {
+            pageQuery.setPage(i);
+            List<TrainingInstitution> content = trainingInstitutionController.all(pageQuery).getContent();
+            List<TrainingInstitution> result = new ArrayList<>();
+            content.forEach(t -> {
+                if (t.getPhone() != null && (t.getPhone().length() < 11 || t.getPhone().contains("-"))) {
+                    t.setPhone(null);
+                    result.add(t);
+                }
+
+            });
+            trainingInstitutionRepo.saveAll(result);
+            System.out.println(i);
+//            Thread.sleep(5 * 60 * 1000);
+//            Thread.sleep(30 * 1000);
+        }
+
+//        System.out.println("12".split(","));
+    }
+
+    @Test
+    public void test1() throws InterruptedException {
+        List<String> phones = trainingInstitutionRepo.findAllBySubmitFalseAndPhoneIsNotNull();
+        trainingInstitutionService.batchSend(phones);
+
+    }
+
+
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов