瀏覽代碼

Merge branch 'dev' of ssh://10.10.100.21/source/smartschool-platform into dev

RaoMeng 7 年之前
父節點
當前提交
ea06d31dbb
共有 91 個文件被更改,包括 2384 次插入167 次删除
  1. 5 3
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/listener/AccessControlListener.java
  2. 7 17
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/lib/DahuaLibrary.java
  3. 10 10
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDataAnalyzeService.java
  4. 1 1
      applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDeviceService.java
  5. 7 6
      applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/event/AccessControlEvent.java
  6. 17 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/ClassServiceImpl.java
  7. 6 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/CurriculumServiceImpl.java
  8. 28 4
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/GradeServiceImpl.java
  9. 9 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolServiceImpl.java
  10. 9 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolTemplateServiceImpl.java
  11. 14 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/StudentServiceImpl.java
  12. 13 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SubjectServiceImpl.java
  13. 13 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/TeacherServiceImpl.java
  14. 13 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/controller/ScoreController.java
  15. 11 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/ScoreService.java
  16. 17 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java
  17. 19 7
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java
  18. 119 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java
  19. 3 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java
  20. 33 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/interceptor/ServiceFeignInterceptor.java
  21. 14 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/ScoreMapper.java
  22. 2 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysClazzMapper.java
  23. 8 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysStudentMapper.java
  24. 8 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/Operation.java
  25. 11 8
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/wxschool/basic/service/impl/WxNotifyServiceImpl.java
  26. 2 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/wxschool/mapper/WxNotifyrecordsMapper.java
  27. 1 4
      applications/school/school-server/src/main/resources/application.yml
  28. 4 1
      applications/school/school-server/src/main/resources/config/application-dev.yml
  29. 2 2
      applications/school/school-server/src/main/resources/mapper/NotifyMapper.xml
  30. 3 0
      applications/school/school-server/src/main/resources/mapper/SchoolTemplateMapper.xml
  31. 100 0
      applications/school/school-server/src/main/resources/mapper/ScoreMapper.xml
  32. 4 0
      applications/school/school-server/src/main/resources/mapper/SysClazzMapper.xml
  33. 17 1
      applications/school/school-server/src/main/resources/mapper/SysStudentMapper.xml
  34. 5 0
      base-servers/account/account-server/pom.xml
  35. 3 4
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/controller/AccountController.java
  36. 56 0
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/AuthRestInterceptor.java
  37. 23 0
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/InterceptorConfig.java
  38. 33 0
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/ServiceFeignInterceptor.java
  39. 二進制
      base-servers/account/account-server/src/main/resources/auth/pub.key
  40. 1 1
      base-servers/account/account-server/src/main/resources/config/application-docker-cloud.yml
  41. 16 1
      base-servers/account/account-server/src/main/resources/mapper/AccountMapper.xml
  42. 1 1
      base-servers/auth/auth-server/src/main/resources/config/application-docker-cloud.yml
  43. 221 0
      framework/core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextScheduler.java
  44. 10 4
      frontend/pc-web/app/model/Score.js
  45. 4 1
      frontend/pc-web/app/view/Interaction/access/List.js
  46. 10 2
      frontend/pc-web/app/view/Interaction/homework/List.js
  47. 1 1
      frontend/pc-web/app/view/Interaction/mailbox/List.js
  48. 10 11
      frontend/pc-web/app/view/Interaction/notice/List.js
  49. 108 14
      frontend/pc-web/app/view/Interaction/score/Detail.js
  50. 122 1
      frontend/pc-web/app/view/Interaction/score/DetailController.js
  51. 12 2
      frontend/pc-web/app/view/Interaction/score/DetailModel.js
  52. 5 4
      frontend/pc-web/app/view/Interaction/score/List.js
  53. 1 1
      frontend/pc-web/app/view/Interaction/score/ListController.js
  54. 12 2
      frontend/pc-web/app/view/Interaction/timetable/List.js
  55. 68 0
      frontend/pc-web/app/view/Interaction/timetable/ListController.js
  56. 110 0
      frontend/pc-web/app/view/analysis/attence/Chart1.js
  57. 113 0
      frontend/pc-web/app/view/analysis/attence/Chart2.js
  58. 19 0
      frontend/pc-web/app/view/analysis/attence/Panel.js
  59. 60 0
      frontend/pc-web/app/view/analysis/attence/PanelModel.js
  60. 123 0
      frontend/pc-web/app/view/analysis/consumption/Chart1.js
  61. 71 0
      frontend/pc-web/app/view/analysis/consumption/Chart2.js
  62. 23 0
      frontend/pc-web/app/view/analysis/consumption/Panel.js
  63. 50 0
      frontend/pc-web/app/view/analysis/consumption/PanelModel.js
  64. 127 0
      frontend/pc-web/app/view/analysis/score/Chart1.js
  65. 118 0
      frontend/pc-web/app/view/analysis/score/Chart2.js
  66. 23 0
      frontend/pc-web/app/view/analysis/score/Panel.js
  67. 63 0
      frontend/pc-web/app/view/analysis/score/PanelModel.js
  68. 1 1
      frontend/pc-web/app/view/auth/Login.scss
  69. 2 0
      frontend/pc-web/app/view/basic/class/ClassDetail.js
  70. 8 1
      frontend/pc-web/app/view/basic/student/StudentDetail.js
  71. 1 1
      frontend/pc-web/app/view/core/base/BasePanel.js
  72. 10 7
      frontend/pc-web/app/view/core/chart/ChartBase.js
  73. 70 0
      frontend/pc-web/app/view/core/form/field/ClassComboBox.js
  74. 23 24
      frontend/pc-web/app/view/core/form/field/FileField.js
  75. 8 1
      frontend/pc-web/app/view/core/form/field/RemoteImgField.js
  76. 3 0
      frontend/pc-web/app/view/core/form/field/dbfind/Trigger.js
  77. 4 0
      frontend/pc-web/app/view/main/Main.js
  78. 74 0
      frontend/pc-web/app/view/main/MainController.js
  79. 2 1
      frontend/pc-web/ext/packages/modern-locale/overrides/zh_CN/field/Text.js
  80. 二進制
      frontend/pc-web/packages/font-school/resources/fonts/iconfont.eot
  81. 0 0
      frontend/pc-web/packages/font-school/resources/fonts/iconfont.js
  82. 0 0
      frontend/pc-web/packages/font-school/resources/fonts/iconfont.svg
  83. 二進制
      frontend/pc-web/packages/font-school/resources/fonts/iconfont.ttf
  84. 二進制
      frontend/pc-web/packages/font-school/resources/fonts/iconfont.woff
  85. 二進制
      frontend/pc-web/packages/font-school/resources/fonts/iconfont.woff2
  86. 4 0
      frontend/pc-web/packages/font-school/sass/etc/icons.scss
  87. 0 2
      frontend/pc-web/packages/font-school/sass/src/all.scss
  88. 二進制
      frontend/pc-web/resources/images/auth-background.jpg
  89. 16 0
      frontend/pc-web/resources/json/navigation.json
  90. 5 0
      frontend/wechat-web/src/modules/hiPages/approvel-detail/ApprovelDetail.js
  91. 1 1
      frontend/wechat-web/src/modules/hiPages/approvel-detail/ItemApprovel.js

+ 5 - 3
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/listener/AccessControlListener.java

@@ -3,6 +3,7 @@ package com.usoftchina.smartschool.device.client.listener;
 import com.usoftchina.smartschool.device.client.po.AccessControl;
 import com.usoftchina.smartschool.device.client.service.AccessControlService;
 import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.device.dto.DeviceInfo;
 import com.usoftchina.smartschool.device.event.AccessControlEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,15 +32,16 @@ public class AccessControlListener {
     @EventListener(AccessControlEvent.class)
     public void onAccessControlEvent(AccessControlEvent event) {
         AccessControlInfo info = event.getAccessControlInfo();
-        AccessControl accessControl = accessControlService.findById(event.getDeviceId());
+        DeviceInfo device = event.getDevice();
+        AccessControl accessControl = accessControlService.findById(device.getId());
         // 通过门禁设备绑定的访问类型,来设置本次事件的访问类型
         if (accessControl.isEntryType()) {
             info.setEventType(AccessControlInfo.EventType.ENTRY);
         } else {
             info.setEventType(AccessControlInfo.EventType.EXIT);
         }
-        if(logger.isDebugEnabled()) {
-            logger.debug(info.toString());
+        if (logger.isDebugEnabled()) {
+            logger.debug("Device[{}] Port[{}] AccessControlEvent[{}]", device.getIp(), device.getPort(), info.toString());
         }
         try {
             accessControlService.saveRecord(info);

+ 7 - 17
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/lib/DahuaLibrary.java

@@ -1467,30 +1467,20 @@ public interface DahuaLibrary extends Library {
         public String toString() {
             return "DEV_EVENT_ACCESS_CTL_INFO{" +
                     "nChannelID=" + nChannelID +
-                    ", szName=" + new String(szName) +
+                    ", szName=" + new String(szName).trim() +
                     ", PTS=" + PTS +
                     ", UTC=" + UTC +
                     ", nEventID=" + nEventID +
-                    ", stuObject=" + stuObject +
-                    ", stuFileInfo=" + stuFileInfo +
                     ", emEventType=" + emEventType +
                     ", bStatus=" + bStatus +
                     ", emCardType=" + emCardType +
                     ", emOpenMethod=" + emOpenMethod +
-                    ", szCardNo=" + new String(szCardNo) +
-                    ", szPwd=" + new String(szPwd) +
-                    ", szReaderID=" + new String(szReaderID) +
-                    ", szUserID=" + new String(szUserID) +
-                    ", szSnapURL=" + new String(szSnapURL) +
-                    ", nErrorCode=" + nErrorCode +
-                    ", nPunchingRecNo=" + nPunchingRecNo +
-                    ", nNumbers=" + nNumbers +
-                    ", byImageIndex=" + byImageIndex +
-                    ", dwSnapFlagMask=" + dwSnapFlagMask +
-                    ", emAttendanceState=" + emAttendanceState +
-                    ", szClassNumber=" + new String(szClassNumber) +
-                    ", szPhoneNumber=" + new String(szPhoneNumber) +
-                    ", szCardName=" + new String(szCardName, DEFAULT_CHARSET) +
+                    ", szCardNo=" + new String(szCardNo).trim() +
+                    ", szUserID=" + new String(szUserID).trim() +
+                    ", szSnapURL=" + new String(szSnapURL).trim() +
+                    ", szClassNumber=" + new String(szClassNumber).trim() +
+                    ", szPhoneNumber=" + new String(szPhoneNumber).trim() +
+                    ", szCardName=" + new String(szCardName, DEFAULT_CHARSET).trim() +
                     ", uSimilarity=" + (uSimilarity & 0x0ffffffff) +
                     '}';
         }

+ 10 - 10
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDataAnalyzeService.java

@@ -9,6 +9,7 @@ import com.usoftchina.smartschool.device.dahua.lib.DahuaLibrary.*;
 import com.usoftchina.smartschool.device.dahua.lib.DahuaSdk;
 import com.usoftchina.smartschool.device.dahua.lib.DahuaSdkException;
 import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.device.dto.DeviceInfo;
 import com.usoftchina.smartschool.device.event.AccessControlEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,14 +40,14 @@ public class DahuaDataAnalyzeService {
     /**
      * 启动智能数据监听
      *
-     * @param deviceId 门禁设备ID
+     * @param device 门禁设备
      * @param loginHandle 登录句柄
      */
-    public void startListen(String deviceId, NativeLong loginHandle) {
+    public void startListen(DeviceInfo device, NativeLong loginHandle) {
         long key = loginHandle.longValue();
         if (key != 0 && !analyzerHandles.containsKey(key)) {
             NativeLong lAnalyzerHandle = sdk.getInstance().CLIENT_RealLoadPictureEx(loginHandle, 0,
-                    DahuaEvents.EVENT_IVS_ALL, true, new AnalyzerDataCallBack(deviceId),
+                    DahuaEvents.EVENT_IVS_ALL, true, new AnalyzerDataCallBack(device),
                     new NativeLong(), null);
             analyzerHandles.put(key, lAnalyzerHandle);
         }
@@ -56,11 +57,11 @@ public class DahuaDataAnalyzeService {
      * 智能分析数据回调
      */
     class AnalyzerDataCallBack implements fAnalyzerDataCallBack {
-        private final String deviceId;
+        private final DeviceInfo device;
 
-        public AnalyzerDataCallBack(String deviceId) {
+        public AnalyzerDataCallBack(DeviceInfo device) {
             super();
-            this.deviceId = deviceId;
+            this.device = device;
         }
 
         @Override
@@ -73,18 +74,17 @@ public class DahuaDataAnalyzeService {
                 case DahuaEvents.EVENT_IVS_ACCESS_CTL:
                     DEV_EVENT_ACCESS_CTL_INFO info = new DEV_EVENT_ACCESS_CTL_INFO(pAlarmInfo);
                     if (logger.isDebugEnabled()) {
-                        logger.debug(info.toString());
+                        logger.debug("Device[{}] Port[{}] CallBack[{}]", device.getIp(), device.getPort(), info.toString());
                     }
                     AccessControlInfo accessControlInfo = new AccessControlInfo();
                     if (dwBufSize > 0) {
                         accessControlInfo.setImageData(pBuffer.getByteArray(0, dwBufSize));
                     }
-                    accessControlInfo.setCardNo(new String(info.szCardNo));
+                    accessControlInfo.setCardNo(new String(info.szCardNo).trim());
                     accessControlInfo.setEventType(convertEventType(info.emEventType));
                     accessControlInfo.setOpenMethod(convertOpenMethod(info.emOpenMethod));
                     accessControlInfo.setEventTime(info.UTC.toDate());
-                    SpringContextHolder.getContext().publishEvent(new AccessControlEvent(this,
-                            deviceId, accessControlInfo));
+                    SpringContextHolder.getContext().publishEvent(new AccessControlEvent(this, device, accessControlInfo));
                     // 其他地方可通过监听 AccessControlEvent 来扩展
                     break;
                 /**

+ 1 - 1
applications/device/device-sdk-dahua/src/main/java/com/usoftchina/smartschool/device/dahua/service/DahuaDeviceService.java

@@ -44,7 +44,7 @@ public class DahuaDeviceService implements DeviceApi {
             NativeLong loginHandle = login(info.getIp(), info.getPort(), info.getUsername(), info.getPassword());
             loginHandles.put(id, loginHandle);
             // 开启智能事件监听
-            dataAnalyzeService.startListen(info.getId(), loginHandle);
+            dataAnalyzeService.startListen(info, loginHandle);
         }
     }
 

+ 7 - 6
applications/device/device-sdk/src/main/java/com/usoftchina/smartschool/device/event/AccessControlEvent.java

@@ -1,6 +1,7 @@
 package com.usoftchina.smartschool.device.event;
 
 import com.usoftchina.smartschool.device.dto.AccessControlInfo;
+import com.usoftchina.smartschool.device.dto.DeviceInfo;
 import org.springframework.context.ApplicationEvent;
 
 /**
@@ -11,22 +12,22 @@ import org.springframework.context.ApplicationEvent;
  */
 public class AccessControlEvent extends ApplicationEvent {
 
-    private final String deviceId;
+    private final DeviceInfo device;
     private final AccessControlInfo accessControlInfo;
 
-    public AccessControlEvent(Object source, String deviceId, AccessControlInfo accessControlInfo) {
+    public AccessControlEvent(Object source, DeviceInfo device, AccessControlInfo accessControlInfo) {
         super(source);
-        this.deviceId = deviceId;
+        this.device = device;
         this.accessControlInfo = accessControlInfo;
     }
 
     /**
-     * 产生事件的门禁设备ID
+     * 产生事件的门禁设备
      *
      * @return
      */
-    public String getDeviceId() {
-        return deviceId;
+    public DeviceInfo getDevice() {
+        return device;
     }
 
     public AccessControlInfo getAccessControlInfo() {

+ 17 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/ClassServiceImpl.java

@@ -3,6 +3,7 @@ package com.usoftchina.smartschool.school.basic.service.impl;
 import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.school.basic.service.ClassService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.SysClazzMapper;
@@ -32,6 +33,11 @@ public class ClassServiceImpl implements ClassService{
     private SysStudentMapper sysStudentMapper;
     @Autowired
     private SysTeacherMapper sysTeacherMapper;
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "Class";
+    private static final String NAME = "班级资料";
 
     @Override
     public ClassForm getFormdata(Long id) {
@@ -69,6 +75,7 @@ public class ClassServiceImpl implements ClassService{
         //更新从表数据
         List<SysTeacherClazz> updateDetails = new ArrayList<>();
         //新增
+        DocBaseDTO docBaseDTO = null;
         if (StringUtils.isEmpty(id) || "0".equals(id.toString())) {
             clazz.setClazz_status(1);
             clazz.setClazz_nickname(clazz.getClazz_grade() + clazz.getClazz_name());
@@ -78,7 +85,9 @@ public class ClassServiceImpl implements ClassService{
                 teacher.setClazz_id(clazz.getClazz_id());
                 sysClazzMapper.insertTeacher(teacher);
             }
-            return new DocBaseDTO(clazz.getClazz_id());
+            docBaseDTO = new DocBaseDTO(clazz.getClazz_id(), CODE, NAME);
+            messageLogService.save(docBaseDTO);
+            return docBaseDTO;
         }
         //更新
         sysClazzMapper.updateByPrimaryKeySelective(clazz);
@@ -109,7 +118,9 @@ public class ClassServiceImpl implements ClassService{
                 sysClazzMapper.updateTeacher(item);
             }
         }
-        return new DocBaseDTO(clazz.getClazz_id());
+        docBaseDTO = new DocBaseDTO(clazz.getClazz_id(), CODE, NAME);
+        messageLogService.update(docBaseDTO);
+        return docBaseDTO;
     }
 
     @Override
@@ -133,12 +144,16 @@ public class ClassServiceImpl implements ClassService{
         if (check > 0) {
             throw new BizException(BizExceptionCode.EXISTS_CURRICULUM);
         }
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE, NAME);
         sysClazzMapper.deleteByPrimaryKey(id);
         sysStudentMapper.deleteTeacher(id);
+        messageLogService.delete(docBaseDTO);
     }
 
     @Override
     public void deleteDetail(Long id) {
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE, NAME);
         sysTeacherMapper.deleteDetail(id);
+        messageLogService.deleteDetail(docBaseDTO);
     }
 }

+ 6 - 1
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/CurriculumServiceImpl.java

@@ -15,6 +15,7 @@ import com.usoftchina.smartschool.school.mapper.DataImportMapper;
 import com.usoftchina.smartschool.school.mapper.SysClazzMapper;
 import com.usoftchina.smartschool.school.mapper.SysGradeMapper;
 import com.usoftchina.smartschool.school.po.DataImportDetail;
+import com.usoftchina.smartschool.school.po.Operation;
 import com.usoftchina.smartschool.school.po.SubjectDO;
 import com.usoftchina.smartschool.school.wxschool.utils.ObjectUtils;
 import com.usoftchina.smartschool.school.wxschool.utils.StringUtils;
@@ -181,7 +182,7 @@ public class CurriculumServiceImpl implements CurriculumService {
                     curriculumMapper.updateDetailSelective(updateList);
                 }
             }
-            messageLogService.save(new DocBaseDTO(main.getId(), CODE, NAME));
+            messageLogService.update(new DocBaseDTO(main.getId(), CODE, NAME));
         }
         return new DocBaseDTO(main.getId(), CODE, NAME);
     }
@@ -312,6 +313,8 @@ public class CurriculumServiceImpl implements CurriculumService {
 
         curriculumMapper.updateByPublish(id);
         curriculumMapper.updateByPublishFrom(id, 1L);
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE,  NAME);
+        messageLogService.customizeLog(docBaseDTO, Operation.PUBLISH);
     }
 
     @Override
@@ -332,6 +335,8 @@ public class CurriculumServiceImpl implements CurriculumService {
         }
         curriculumMapper.updateByRepublish(id);
         curriculumMapper.updateByPublishFrom(id, 0L);
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE,  NAME);
+        messageLogService.customizeLog(docBaseDTO, Operation.REPUBLISH);
     }
 
     @Override

+ 28 - 4
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/GradeServiceImpl.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.school.basic.service.GradeService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.*;
@@ -46,6 +47,12 @@ public class GradeServiceImpl implements GradeService{
     @Autowired
     private HomeWorkMapper homeWorkMapper;
 
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "Grade";
+    private static final String NAME = "年级资料";
+
     @Override
     public TreeNode getSchoolTree() {
         Long school_id = BaseContextHolder.getSchoolId();
@@ -152,6 +159,12 @@ public class GradeServiceImpl implements GradeService{
                 throw new BizException(12345, err.toString());
             }
             for (SysClazz  cla : clazzes) {
+                Integer check = 0;
+                //检测班级
+                check = sysClazzMapper.countClazz(cla.getClazz_name(), cla.getClazz_grade() ,schoolId);
+                if (check > 0) {
+                    throw new BizException(BizExceptionCode.EXISTS_CLAZZ);
+                }
                 sysClazzMapper.insertSelective(cla);
             }
             dataImportMapper.updateDataImport(id);
@@ -173,7 +186,9 @@ public class GradeServiceImpl implements GradeService{
             throw new BizException(BizExceptionCode.REPEAT_GRADE_NAME);
         }
         sysGradeMapper.insertGrade(sysGrade);
-        return new DocBaseDTO(sysGrade.getGrade_id());
+        DocBaseDTO docBaseDTO = new DocBaseDTO(sysGrade.getGrade_id(), CODE,  NAME);
+        messageLogService.save(docBaseDTO);
+        return docBaseDTO;
     }
 
     @Override
@@ -191,7 +206,8 @@ public class GradeServiceImpl implements GradeService{
         sysClazz.setClazz_grade(gradeData.getGrade_name());
         sysClazz.setClazz_nickname(gradeData.getGrade_name()+sysClazz.getClazz_name());
         sysClazzMapper.insertSelective(sysClazz);
-        return new DocBaseDTO(sysClazz.getClazz_id());
+        DocBaseDTO docBaseDTO = new DocBaseDTO(sysClazz.getClazz_id(), "Class", "班级资料");
+        return docBaseDTO;
     }
 
     @Override
@@ -205,7 +221,9 @@ public class GradeServiceImpl implements GradeService{
         if (check > 0) {
             throw new BizException(BizExceptionCode.EXISTS_CLASS);
         }
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE,  NAME);
         sysGradeMapper.deleteByPrimaryKey(id);
+        messageLogService.delete(docBaseDTO);
     }
 
     @Override
@@ -224,17 +242,19 @@ public class GradeServiceImpl implements GradeService{
         if (check > 0) {
             throw new BizException(BizExceptionCode.EXISTS_TEACHER);
         }
-        //课表检测
+        //检测课表发布
         check = sysStudentMapper.repeatCurriculum(id);
         if (check > 0) {
             throw new BizException(BizExceptionCode.EXISTS_CURRICULUM);
         }
-        //检测科目
+        //检测作业发布
         check = homeWorkMapper.homeWorkRelease(id);
         if(check > 0){
             throw new BizException(BizExceptionCode.HOMEWORK_RELEASE);
         }
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, "Class", "班级资料");
         sysClazzMapper.deleteByPrimaryKey(id);
+        messageLogService.delete(docBaseDTO);
     }
 
     @Override
@@ -248,7 +268,9 @@ public class GradeServiceImpl implements GradeService{
             List<SysClazz> clazzList = sysClazzMapper.selectBygrade(grade.getGrade_id());
             sysStudentMapper.updateGradeName(grade.getGrade_name(), clazzList);
         }
+        DocBaseDTO docBaseDTO = new DocBaseDTO(grade.getGrade_id(), CODE,  NAME);
         sysGradeMapper.updateByPrimaryKeySelective(grade);
+        messageLogService.update(docBaseDTO);
     }
 
     @Override
@@ -261,6 +283,8 @@ public class GradeServiceImpl implements GradeService{
         if (!oldClazz.getClazz_name().equals(sysClass.getClazz_name())) {
             sysStudentMapper.updateClazzName(sysClass.getClazz_name(), sysClass.getClazz_id());
         }
+        DocBaseDTO docBaseDTO = new DocBaseDTO(sysClass.getClazz_id(), "Class", "班级资料");
         sysClazzMapper.updateByPrimaryKeySelective(sysClass);
+        messageLogService.update(docBaseDTO);
     }
 }

+ 9 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolServiceImpl.java

@@ -3,6 +3,8 @@ package com.usoftchina.smartschool.school.basic.service.impl;
 import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.school.basic.service.SchoolService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.SysSchoolMapper;
 import com.usoftchina.smartschool.school.po.SysSchool;
@@ -20,6 +22,12 @@ public class SchoolServiceImpl implements SchoolService {
     @Autowired
     private SysSchoolMapper sysSchoolMapper;
 
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "School";
+    private static final String NAME = "学校信息";
+
     @Override
     public SysSchool getFormData(Long id) {
         if (null == id || "0".equals(id)) {
@@ -36,6 +44,7 @@ public class SchoolServiceImpl implements SchoolService {
             throw new BizException(BizExceptionCode.USELESS_DATA);
         }
         sysSchoolMapper.updateByPrimaryKeySelective(school);
+        messageLogService.update(new DocBaseDTO(school.getSchool_id(), CODE, NAME));
     }
 
     @Override

+ 9 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SchoolTemplateServiceImpl.java

@@ -6,6 +6,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.basic.service.SchoolTemplateService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
@@ -31,6 +32,12 @@ public class SchoolTemplateServiceImpl implements SchoolTemplateService {
     @Autowired
     private SchoolTemplateMapper schoolTemplateMapper;
 
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "SchoolTemplate";
+    private static final String NAME = "消息模板";
+
     @Override
     public PageInfo<SchoolTemplate> getListData(PageRequest page, ListReqDTO listReqDTO) {
         PageHelper.startPage(page.getNumber(), page.getSize());
@@ -64,9 +71,11 @@ public class SchoolTemplateServiceImpl implements SchoolTemplateService {
         //新增
         if (StringUtils.isEmpty(formdata.getSt_id()) || "0".equals(formdata.getSt_id().toString())) {
             schoolTemplateMapper.insertSelective(formdata);
+            messageLogService.save(new DocBaseDTO(formdata.getSt_id(), CODE, NAME));
         } else {
             //更新
             schoolTemplateMapper.updateByPrimaryKeySelective(formdata);
+            messageLogService.update(new DocBaseDTO(formdata.getSt_id(), CODE, NAME));
         }
         return new DocBaseDTO(formdata.getSt_id());
     }

+ 14 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/StudentServiceImpl.java

@@ -10,6 +10,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.basic.service.StudentService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
@@ -47,6 +48,11 @@ public class StudentServiceImpl implements StudentService{
     private SysGradeMapper sysGradeMapper;
     @Autowired
     private SysClazzMapper sysClazzMapper;
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "Student";
+    private static final String NAME = "学生信息";
 
     @Override
     public PageInfo<SysStudent> getListData(PageRequest page, ListReqDTO listReqDTO) {
@@ -119,7 +125,9 @@ public class StudentServiceImpl implements StudentService{
                     sysStudentMapper.insertrelation(id, pr_id, item.getPs_relation());
                 }
             }
-            return new DocBaseDTO(id, null, "student");
+            DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE,  NAME);
+            messageLogService.save(docBaseDTO);
+            return docBaseDTO;
         }
         //更新学生
         if(sysStudentMapper.count(student.getStu_number(), student.getSchool_id()) > 0 &&
@@ -172,7 +180,9 @@ public class StudentServiceImpl implements StudentService{
                 sysStudentMapper.updateRelation(item.getParent_stu_id(), item.getPs_relation());
             }
         }
-        return new DocBaseDTO(id);
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE,  NAME);
+        messageLogService.update(docBaseDTO);
+        return docBaseDTO;
     }
 
     private Long createAccount(String mobile){
@@ -291,6 +301,7 @@ public class StudentServiceImpl implements StudentService{
         }
         sysStudentMapper.deleteByPrimaryKey(id);
         sysStudentMapper.deleteRelation(id);
+        messageLogService.delete(new DocBaseDTO(id, CODE, NAME));
     }
 
     @Override
@@ -311,5 +322,6 @@ public class StudentServiceImpl implements StudentService{
             return;
         }
         sysStudentMapper.deleteRelationById(id);
+        messageLogService.deleteDetail(new DocBaseDTO(id, CODE, NAME));
     }
 }

+ 13 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/SubjectServiceImpl.java

@@ -6,6 +6,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.basic.service.SubjectService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
@@ -27,7 +28,11 @@ public class SubjectServiceImpl implements SubjectService {
 
     @Autowired
     private SubjectMapper subjectMapper;
+    @Autowired
+    private MessageLogService messageLogService;
 
+    private static final String CODE = "Subject";
+    private static final String NAME = "科目信息";
 
     @Override
     public PageInfo<Subject> getListData(PageRequest page, ListReqDTO listReqDTO) {
@@ -51,6 +56,7 @@ public class SubjectServiceImpl implements SubjectService {
         Long id = formdata.getSubject_id();
         Long school = BaseContextHolder.getSchoolId();
         Integer check = 0;
+        DocBaseDTO docBaseDTO = null;
         if (StringUtils.isEmpty(id) || "0".equals(id.toString())) {
             formdata.setSchool_id(school);
             formdata.setSubject_status(1);
@@ -60,7 +66,9 @@ public class SubjectServiceImpl implements SubjectService {
                 throw new BizException(BizExceptionCode.EXISTS_SUBJECT);
             }
             subjectMapper.insertSelective(formdata);
-           id = formdata.getSubject_id();
+            id = formdata.getSubject_id();
+            docBaseDTO = new DocBaseDTO(id, CODE, NAME);
+            messageLogService.save(docBaseDTO);
         } else {
             //更新
             check = subjectMapper.checkSubject(formdata.getSubject_name(), BaseContextHolder.getSchoolId());
@@ -68,8 +76,10 @@ public class SubjectServiceImpl implements SubjectService {
                 throw new BizException(BizExceptionCode.EXISTS_SUBJECT);
             }
             subjectMapper.updateByPrimaryKeySelective(formdata);
+            docBaseDTO = new DocBaseDTO(formdata.getSubject_id(), CODE,  NAME);
+            messageLogService.update(docBaseDTO);
         }
-        return new DocBaseDTO(formdata.getSubject_id());
+        return docBaseDTO;
     }
 
     @Override
@@ -101,5 +111,6 @@ public class SubjectServiceImpl implements SubjectService {
             throw new BizException(BizExceptionCode.EXISTS_TEACHER_CLASS);
         }
         subjectMapper.deleteByPrimaryKey(id);
+        messageLogService.delete(new DocBaseDTO(id, CODE,  NAME));
     }
 }

+ 13 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/basic/service/impl/TeacherServiceImpl.java

@@ -10,6 +10,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.basic.service.TeacherService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
@@ -42,6 +43,11 @@ public class TeacherServiceImpl implements TeacherService{
     private DataImportMapper dataImportMapper;
     @Autowired
     private AccountApi accountApi;
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "Teacher";
+    private static final String NAME = "教职工信息";
 
     @Override
     public PageInfo<SysTeacher> getListData(PageRequest page, ListReqDTO listReqDTO) {
@@ -78,6 +84,7 @@ public class TeacherServiceImpl implements TeacherService{
         Long school_id = BaseContextHolder.getSchoolId();
         formdata.setSchool_id(school_id);
         formdata.setTeacher_status(1);
+        DocBaseDTO docBaseDTO = null;
         //新增教师
         if (StringUtils.isEmpty(formdata.getTeacher_id()) || "0".equals(formdata.getTeacher_id().toString())) {
             if(sysTeacherMapper.count(formdata.getTeacher_number(), formdata.getSchool_id()) > 0){
@@ -89,7 +96,8 @@ public class TeacherServiceImpl implements TeacherService{
                 formdata.setUser_id(userId);
             }
             sysTeacherMapper.insertSelective(formdata);
-
+            docBaseDTO = new DocBaseDTO(formdata.getTeacher_id(), CODE,  NAME);
+            messageLogService.save(docBaseDTO);
         } else {
             //更新教师
             if(sysTeacherMapper.count(formdata.getTeacher_number(), formdata.getSchool_id()) > 0 &&
@@ -97,8 +105,10 @@ public class TeacherServiceImpl implements TeacherService{
                 throw new BizException(BizExceptionCode.REPEAT_TEACHER_NUMBER);
             }
             sysTeacherMapper.updateByPrimaryKeySelective(formdata);
+            docBaseDTO = new DocBaseDTO(formdata.getTeacher_id(), CODE,  NAME);
+            messageLogService.update(docBaseDTO);
         }
-        return new DocBaseDTO(formdata.getTeacher_id(), null, null);
+        return docBaseDTO;
     }
 
     /**
@@ -199,6 +209,7 @@ public class TeacherServiceImpl implements TeacherService{
         }
         sysTeacherMapper.deleteByPrimaryKey(id);
         sysTeacherMapper.deleteRelation(id);
+        messageLogService.delete(new DocBaseDTO(id, CODE,  NAME));
     }
 
     @Override

+ 13 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/controller/ScoreController.java

@@ -6,6 +6,7 @@ import com.usoftchina.smartschool.page.PageDefault;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.business.service.ScoreService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
 import com.usoftchina.smartschool.school.po.ScoreForm;
 import com.usoftchina.smartschool.school.po.ScoreImportList;
@@ -61,4 +62,16 @@ public class ScoreController {
         return Result.success();
     }
 
+    @PostMapping("/save")
+    public Result save(@RequestBody ScoreForm data) {
+        DocBaseDTO baseDTO = scoreService.save(data);
+        return Result.success(baseDTO);
+    }
+
+    @PostMapping("/deleteDetail/{id}")
+    public Result deleteDetail(@PathVariable("id") Long id){
+        scoreService.deleteDetail(id);
+        return Result.success();
+    }
+
 }

+ 11 - 1
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/ScoreService.java

@@ -3,8 +3,10 @@ package com.usoftchina.smartschool.school.business.service;
 import com.github.pagehelper.PageInfo;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
+import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
-import com.usoftchina.smartschool.school.po.*;
+import com.usoftchina.smartschool.school.po.ScoreForm;
+import com.usoftchina.smartschool.school.po.ScoreImportList;
 
 /**
  * @author: guq
@@ -22,4 +24,12 @@ public interface ScoreService {
     void publish(Long id);
 
     ScoreForm getFormdata(Long id);
+
+    DocBaseDTO save(ScoreForm data);
+
+    /**
+     * 删除成绩明细
+     * @param id
+     */
+    void deleteDetail(Long id);
 }

+ 17 - 1
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/HomeWorkServiceImpl.java

@@ -6,6 +6,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.business.service.HomeWorkService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
@@ -50,6 +51,13 @@ public class HomeWorkServiceImpl implements HomeWorkService{
     private WechatApi wechatApi;
     @Autowired
     private SchoolTemplateMapper schoolTemplateMapper;
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "HomeWork";
+    private static final String NAME = "作业";
+
+
     @Value("${smartschool.domain.wechat}")
     private String wechatBaseUrl;
 
@@ -60,6 +68,7 @@ public class HomeWorkServiceImpl implements HomeWorkService{
         }
         Long school_id = BaseContextHolder.getSchoolId();
         formdata.setSchool_id(school_id);
+        DocBaseDTO docBaseDTO = null;
         //新增
         if (StringUtils.isEmpty(formdata.getTask_id()) || "0".equals(formdata.getTask_id().toString())) {
             formdata.setTask_status(2);
@@ -75,14 +84,18 @@ public class HomeWorkServiceImpl implements HomeWorkService{
             formdata.setTask_creator(Creator);
             */
             homeWorkMapper.insertSelective(formdata);
+            docBaseDTO = new DocBaseDTO(formdata.getTask_id(), CODE, NAME);
+            messageLogService.save(docBaseDTO);
         } else {
             //更新
             homeWorkMapper.updateByPrimaryKeySelective(formdata);
+            docBaseDTO = new DocBaseDTO(formdata.getTask_id(), CODE,  NAME);
+            messageLogService.update(docBaseDTO);
             if(formdata.getTask_status()==1){
                 publish(formdata.getTask_id());
             }
         }
-        return new DocBaseDTO(formdata.getTask_id());
+        return docBaseDTO;
     }
 
     @Override
@@ -108,6 +121,7 @@ public class HomeWorkServiceImpl implements HomeWorkService{
             throw new BizException(BizExceptionCode.TASK_RELEASE_STATUS);
         }
         homeWorkMapper.deleteByPrimaryKey(id);
+        messageLogService.delete(new DocBaseDTO(id, CODE,  NAME));
     }
 
     @Override
@@ -169,6 +183,8 @@ public class HomeWorkServiceImpl implements HomeWorkService{
             wechatApi.largeMessages(transferDTO);
         }
         homeWorkMapper.updateByPublish(id);
+        DocBaseDTO docBaseDTO = new DocBaseDTO(id, CODE, NAME);
+        messageLogService.customizeLog(docBaseDTO, Operation.PUBLISH);
     }
 
     /**

+ 19 - 7
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java

@@ -6,6 +6,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.business.service.NoticeService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
@@ -14,10 +15,7 @@ import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.NoticeMapper;
 import com.usoftchina.smartschool.school.mapper.SchoolTemplateMapper;
 import com.usoftchina.smartschool.school.mapper.SysSchoolMapper;
-import com.usoftchina.smartschool.school.po.Notify;
-import com.usoftchina.smartschool.school.po.SchoolNoticer;
-import com.usoftchina.smartschool.school.po.SchoolTemplate;
-import com.usoftchina.smartschool.school.po.SysSchool;
+import com.usoftchina.smartschool.school.po.*;
 import com.usoftchina.smartschool.utils.DateUtils;
 import com.usoftchina.smartschool.utils.StringUtils;
 import com.usoftchina.smartschool.wechat.api.WechatApi;
@@ -50,6 +48,12 @@ public class NoticeServiceImpl implements NoticeService{
     @Autowired
     private SchoolTemplateMapper schoolTemplateMapper;
 
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "Notice";
+    private static final String NAME = "学校通知";
+
     @Value("${smartschool.domain.wechat}")
     private String baseWechatUrl;
 
@@ -61,6 +65,7 @@ public class NoticeServiceImpl implements NoticeService{
         }
         Long school_id = BaseContextHolder.getSchoolId();
         formdata.setSchool_id(school_id);
+        DocBaseDTO docBaseDTO = null;
         //新增
         if (StringUtils.isEmpty(formdata.getNotify_id()) || "0".equals(formdata.getNotify_id().toString())) {
             formdata.setNotify_status(2);
@@ -68,15 +73,18 @@ public class NoticeServiceImpl implements NoticeService{
             Calendar calendar= Calendar.getInstance();
             formdata.setCreate_date(calendar.getTime());
             noticeMapper.insertSelective(formdata);
-
+            docBaseDTO = new DocBaseDTO(formdata.getNotify_id(), CODE,  NAME);
+            messageLogService.save(docBaseDTO);
         } else {
             //更新
             noticeMapper.updateByPrimaryKeySelective(formdata);
+            docBaseDTO = new DocBaseDTO(formdata.getNotify_id(), CODE,  NAME);
+            messageLogService.update(docBaseDTO);
             if(formdata.getNotify_status()==1){
                 publish(formdata.getNotify_id());
             }
         }
-        return new DocBaseDTO(formdata.getNotify_id());
+        return docBaseDTO;
     }
 
     @Override
@@ -111,6 +119,7 @@ public class NoticeServiceImpl implements NoticeService{
             throw new BizException(BizExceptionCode.NOTICE_RELEASE_STATUS);
         }
         noticeMapper.deleteByPrimaryKey(id);
+        messageLogService.delete(new DocBaseDTO(id, CODE,  NAME));
     }
 
     @Override
@@ -139,6 +148,7 @@ public class NoticeServiceImpl implements NoticeService{
         if (StringUtils.isEmpty(template) || StringUtils.isEmpty(template.getSt_templateid())) {
             throw new BizException(BizExceptionCode.NULL_TEMPLATE);
         }
+        List<SchoolNoticer> noticerList = new ArrayList<>();
         noticers.forEach(noticer -> {
             MessageInfoDTO msg = new MessageInfoDTO();
             String endUrl = null;
@@ -152,6 +162,7 @@ public class NoticeServiceImpl implements NoticeService{
                     noticer.setType("0");
                     noticer.setPersonId(noticer.getPersonId().split(",")[0]);
                 }
+                noticerList.add(noticer);
                 String url = baseWechatUrl + "/notifyDetail" + endUrl;
                 msg.setUrl(url);
                 msg.setTitle(data.getNotify_title());
@@ -167,7 +178,7 @@ public class NoticeServiceImpl implements NoticeService{
                 msgs.add(msg);
             }
         });
-        noticeMapper.insertDetailBySelective(noticers, id);
+        noticeMapper.insertDetailBySelective(noticerList, id);
         if (msgs.size() > 0) {
             TransferDTO transferDTO = new TransferDTO();
             transferDTO.setData(msgs);
@@ -175,5 +186,6 @@ public class NoticeServiceImpl implements NoticeService{
             wechatApi.largeMessages(transferDTO);
         }
         noticeMapper.updateByPublish(id);
+        messageLogService.customizeLog(new DocBaseDTO(id, CODE, NAME), Operation.PUBLISH);
     }
 }

+ 119 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java

@@ -7,6 +7,7 @@ import com.usoftchina.smartschool.context.BaseContextHolder;
 import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.page.PageRequest;
 import com.usoftchina.smartschool.school.business.service.ScoreService;
+import com.usoftchina.smartschool.school.common.service.MessageLogService;
 import com.usoftchina.smartschool.school.dto.BatchDealBaseDTO;
 import com.usoftchina.smartschool.school.dto.DocBaseDTO;
 import com.usoftchina.smartschool.school.dto.ListReqDTO;
@@ -14,6 +15,7 @@ import com.usoftchina.smartschool.school.enums.NoticeTemplate;
 import com.usoftchina.smartschool.school.exception.BizExceptionCode;
 import com.usoftchina.smartschool.school.mapper.*;
 import com.usoftchina.smartschool.school.po.*;
+import com.usoftchina.smartschool.school.wxschool.utils.ObjectUtils;
 import com.usoftchina.smartschool.utils.CollectionUtils;
 import com.usoftchina.smartschool.utils.DateUtils;
 import com.usoftchina.smartschool.wechat.api.WechatApi;
@@ -66,6 +68,12 @@ public class ScoreServiceImpl implements ScoreService{
     @Autowired
     private SubjectMapper subjectMapper;
 
+    @Autowired
+    private MessageLogService messageLogService;
+
+    private static final String CODE = "Score";
+    private static final String NAME = "成绩发布";
+
     @Override
     public PageInfo<ScoreImportList> getListData(PageRequest page, ListReqDTO listReqDTO) {
         PageHelper.startPage(page.getNumber(), page.getSize());
@@ -93,6 +101,7 @@ public class ScoreServiceImpl implements ScoreService{
     }
 
     @Override
+    @Transactional
     public void delete(Long id) {
         if (StringUtils.isEmpty(id) || "0".equals(id)) {
             return;
@@ -104,6 +113,8 @@ public class ScoreServiceImpl implements ScoreService{
             throw new BizException(BizExceptionCode.EXISTS_TEACHER_CLASS);
         }
         scoreMapper.deleteByPrimaryKey(id);
+        scoreMapper.deleteByPrimaryDetailKey(id);
+        messageLogService.delete(new DocBaseDTO(id, CODE, NAME));
     }
 
     @Override
@@ -287,6 +298,7 @@ public class ScoreServiceImpl implements ScoreService{
         }
         //更新已转标志
         scoreMapper.updateTurnPublish(id);
+        messageLogService.customizeLog(new DocBaseDTO(id, CODE, NAME), Operation.PUBLISH);
     }
 
     @Override
@@ -301,4 +313,111 @@ public class ScoreServiceImpl implements ScoreService{
         form.setItems(detail);
         return form;
     }
+
+    @Override
+    @Transactional
+    public DocBaseDTO save(ScoreForm data) {
+        if (ObjectUtils.isEmpty(data)){
+            throw new BizException(BizExceptionCode.EMPTY_DATA);
+        }
+        ScoreImport main = data.getMain();
+        List<ScoreImportdetail> items = data.getItems();
+        Long schoolId = BaseContextHolder.getSchoolId();
+        //Long gradeId = sysGradeMapper.selectByName(main.getSi_grade(), schoolId).getGrade_id();
+
+        Long classId = 0L;
+        Long gradeId = 0L;
+        SysClazz sysClazz = sysClazzMapper.selectByClazzName(main.getSi_grade(), main.getSi_class() , schoolId);
+        if(sysClazz != null) {
+            classId = sysClazz.getClazz_id();
+            gradeId = sysClazz.getGrade_id();
+        }
+        if (null == main.getSi_id() || 0 == main.getSi_id()){
+            main.setSi_date(new Date());
+            main.setSi_creator(BaseContextHolder.getUserName());
+            main.setSi_creatorid(BaseContextHolder.getUserId());
+            main.setSchool_id(schoolId);
+            main.setSi_publish(0);
+            main.setSi_gradeid(gradeId);
+            main.setSi_classid(classId);
+            scoreMapper.insertScoreImport(main);
+            if (null != items && items.size() > 0) {
+                for (ScoreImportdetail item : items) {
+                    if(!StringUtils.isEmpty(item.getSd_stuNumber()) && !StringUtils.isEmpty(item.getSd_stu())) {
+                        Integer check = 0;
+                        //学生检测
+                        check = sysStudentMapper.count(item.getSd_stuNumber(), schoolId);
+                        if (check < 1) {
+                            throw new BizException(BizExceptionCode.NONSTU);
+                        }
+                        check = sysStudentMapper.countName(item.getSd_stu(), schoolId);
+                        if (check < 1) {
+                            throw new BizException(BizExceptionCode.NONSTU);
+                        }
+                        SysStudent sysStudent = sysStudentMapper.selectByStudent(item.getSd_stu() ,classId,schoolId);
+                        if(sysStudent == null){
+                            throw new BizException(BizExceptionCode.NONSTUS);
+                        }
+                        Long stuId = sysStudent.getStu_id();
+                        item.setSd_stuid(stuId);
+                    }
+                    item.setSchool_id(schoolId);
+                    item.setSd_siid(main.getSi_id());
+                    //插入从表
+                    scoreMapper.insertScoreImportDetail(item);
+                }
+            }
+
+        }else{
+            scoreMapper.updateScoreImport(main);
+            if (null != items && items.size() > 0) {
+                List<ScoreImportdetail> insertList = new ArrayList<ScoreImportdetail>();
+                List<ScoreImportdetail> updateList = new ArrayList<ScoreImportdetail>();
+                for (ScoreImportdetail item : items) {
+
+                    if(!StringUtils.isEmpty(item.getSd_stuNumber()) && !StringUtils.isEmpty(item.getSd_stu())) {
+                        Integer check = 0;
+                        //学生检测
+                        check = sysStudentMapper.count(item.getSd_stuNumber(), schoolId);
+                        if (check < 1) {
+                            throw new BizException(BizExceptionCode.NONSTU);
+                        }
+                        check = sysStudentMapper.countName(item.getSd_stu(), schoolId);
+                        if (check < 1) {
+                            throw new BizException(BizExceptionCode.NONSTU);
+                        }
+                        SysStudent sysStudent = sysStudentMapper.selectByStudent(item.getSd_stu() ,classId,schoolId);
+                        if(sysStudent == null){
+                            throw new BizException(BizExceptionCode.NONSTUS);
+                        }
+                        Long stuId = sysStudent.getStu_id();
+                        item.setSd_stuid(stuId);
+                    }
+                    item.setSchool_id(schoolId);
+                    item.setSd_siid(main.getSi_id());
+
+                    if(item.getSd_id() != null && 0 != item.getSd_id()) {
+                        updateList.add(item);
+                    }else {
+                        insertList.add(item);
+                    }
+                    if (insertList.size() > 0) {
+                        scoreMapper.insertDetailSelective(insertList);
+                    }
+                    if (updateList.size() > 0) {
+                        scoreMapper.updateDetailSelective(updateList);
+                    }
+
+                }
+            }
+        }
+        return new DocBaseDTO(main.getSi_id(), CODE, NAME);
+    }
+
+    @Override
+    public void deleteDetail(Long id) {
+        scoreMapper.deleteDetail(id);
+        messageLogService.deleteDetail(new DocBaseDTO(id, CODE, NAME));
+    }
+
 }

+ 3 - 1
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java

@@ -17,12 +17,14 @@ public enum BizExceptionCode implements BaseExceptionCode {
     NONCLAZZ(500005, "班级名称不存在"),
     EXAM_SCOPE(5000014, "考试范围只有全年级和班级"),
     REPEAT_TEACHER_NUMBER(500006, "教师工号重复"),
-    NONSTU(500006, "学生不存在"),
+    NONSTU(500007, "学生不存在"),
+    NONSTUS(500008, "这个班没有这个学生"),
     EXISTS_TEACHER(500004,"存在任课教师,无法删除"),
     EXISTS_CURRICULUM(500005,"存在课表,无法删除"),
     EXISTS_TEACHER_CLASS(500006,"存在任课班级,无法删除"),
     TEACHERS_EXISTS_CLASS(500006,"%s存在任课班级,无法删除"),
     EXISTS_SUBJECT(500007,"科目已存在"),
+    EXISTS_CLAZZ(500008,"班级可能存在重复"),
     EXISTS_SUBJECT_TEACHER(5000012, "该课程存在班级与任课教师,禁止删除"),
     EXISTS_SCORE_PUBLISH(5000013, "存在已发布成绩,禁止删除"),
     EXISTS_CLASS(500011, "存在班级,无法删除"),

+ 33 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/interceptor/ServiceFeignInterceptor.java

@@ -0,0 +1,33 @@
+package com.usoftchina.smartschool.school.interceptor;
+
+import com.usoftchina.smartschool.context.BaseContextHolder;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author yingp
+ * @date 2018/10/2
+ */
+public class ServiceFeignInterceptor implements RequestInterceptor {
+    /*@Autowired
+    private AuthConfig authConfig;*/
+
+    private static final String AUTHHEADER = "Authorization";
+
+    private Logger logger = LoggerFactory.getLogger(ServiceFeignInterceptor.class);
+
+    public ServiceFeignInterceptor() {
+    }
+
+    @Override
+    public void apply(RequestTemplate requestTemplate) {
+        logger.debug("{}: {}", AUTHHEADER, BaseContextHolder.getToken());
+        requestTemplate.header(AUTHHEADER, BaseContextHolder.getToken());
+    }
+
+    /*public void setAuthConfig(AuthConfig authConfig) {
+        this.authConfig = authConfig;
+    }*/
+}

+ 14 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/ScoreMapper.java

@@ -10,6 +10,8 @@ import java.util.List;
 public interface ScoreMapper {
     int deleteByPrimaryKey(Long score_id);
 
+    int deleteByPrimaryDetailKey(Long sd_siid);
+
     int insert(StuScoreDO record);
 
     int insertSelective(StuScoreDO record);
@@ -26,6 +28,8 @@ public interface ScoreMapper {
 
     int insertScoreImport(ScoreImport scoreImport);
 
+    int updateScoreImport(ScoreImport scoreImport);
+
     void insertScoreImportDetail(ScoreImportdetail detail);
 
     List<ScoreImportdetail> selectDetail(Long id);
@@ -43,4 +47,14 @@ public interface ScoreMapper {
     Long selectCountBySubjectAndCode(@Param("si_id") Long si_id, @Param("stu_number") String stu_number, @Param("subject")String subject);
 
     List<ScoreNoticer> selectWechatMsg(Long id);
+
+    void insertDetailSelective(List<ScoreImportdetail> scoreImportdetail);
+
+    void updateDetailSelective(List<ScoreImportdetail> scoreImportdetail);
+
+    /**
+     * 删除成绩表明细行
+     * @param sd_id
+     */
+    void deleteDetail(@Param("sd_id") Long sd_id);
 }

+ 2 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysClazzMapper.java

@@ -36,4 +36,6 @@ public interface SysClazzMapper {
     int countClazz(@Param("clazz_name") String clazz_name, @Param("clazz_grade") String clazz_grade, @Param("school_id") Long school_id);
 
     Integer teacherClazz(@Param("subject_name") String subject_name, @Param("clazz_id") Long clazz_id);
+
+    SysClazz selectByClazzName(@Param("clazz_grade") String clazz_grade, @Param("clazz_name") String clazz_name, @Param("school_id") Long school_id);
 }

+ 8 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/SysStudentMapper.java

@@ -96,4 +96,12 @@ public interface SysStudentMapper {
      * @return
      */
     int updateClazzName(@Param("clazz_name") String clazz_name, @Param("clazz_id") Long clazz_id);
+
+    SysStudent selectByStudent(@Param("stu_name") String stu_name, @Param("clazz_id") Long clazz_id , @Param("school_id") Long school_id);
+
+    /**
+     * 学生信息:姓名重复
+     * @return
+     */
+    int countName(@Param("stu_name") String stu_name, @Param("school_id") Long school_id);
 }

+ 8 - 0
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/po/Operation.java

@@ -14,6 +14,14 @@ public enum Operation {
      * 删除
      */
     DELETE("删除操作", "删除成功"),
+    /**
+     * 发布
+     */
+    PUBLISH("发布操作", "发布成功"),
+    /**
+     * 取消发布
+     */
+    REPUBLISH("取消发布操作", "取消发布成功"),
     /**
      * 删除明细
      */

+ 11 - 8
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/wxschool/basic/service/impl/WxNotifyServiceImpl.java

@@ -7,6 +7,7 @@ import com.usoftchina.smartschool.school.wxschool.basic.service.WxNotifyService;
 import com.usoftchina.smartschool.school.wxschool.mapper.*;
 import com.usoftchina.smartschool.school.wxschool.utils.ObjectUtils;
 import com.usoftchina.smartschool.wechat.api.WxPushApi;
+import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -231,10 +232,11 @@ public class WxNotifyServiceImpl implements WxNotifyService {
 	 */
 	public NotifyDO getNotifyDetails(Long stuId,Long notifyId) throws Exception {
 		NotifyDO notifyDO = notifyMapper.get(notifyId);
-		NotifyrecordsDO byStu = notifyrecordsMapper.getByStu(stuId, notifyId);
-		if (ObjectUtils.isNotEmpty(byStu)){
-			byStu.setIsRead(2);
-			int update = notifyrecordsMapper.update(byStu);
+		List<NotifyrecordsDO> byStu = notifyrecordsMapper.getByStu(stuId, notifyId);
+		if (CollectionUtils.isNotEmpty(byStu)){
+		    NotifyrecordsDO notifyrecordsDO = byStu.get(0);
+            notifyrecordsDO.setIsRead(2);
+			int update = notifyrecordsMapper.update(notifyrecordsDO);
 			if (update>0){
 				return getNotifyDetail(stuId,0L,notifyDO);
 			}else {
@@ -252,10 +254,11 @@ public class WxNotifyServiceImpl implements WxNotifyService {
 	 */
 	public NotifyDO getNotifyDetailsByTeacher(Long notifyId, Long teacherId) throws Exception {
 		NotifyDO notifyDO = notifyMapper.get(notifyId);
-		NotifyrecordsDO byTeacher = notifyrecordsMapper.getByTeacher(notifyId, teacherId);
-		if (ObjectUtils.isNotEmpty(byTeacher)){
-			byTeacher.setIsRead(2);
-			int update = notifyrecordsMapper.update(byTeacher);
+        List<NotifyrecordsDO> byTeacher = notifyrecordsMapper.getByTeacher(notifyId, teacherId);
+		if (CollectionUtils.isNotEmpty(byTeacher)){
+            NotifyrecordsDO notifyrecordsDO = byTeacher.get(0);
+            notifyrecordsDO.setIsRead(2);
+			int update = notifyrecordsMapper.update(notifyrecordsDO);
 			if (update>0){
 				return getNotifyDetail(0L,teacherId,notifyDO);
 			}else {

+ 2 - 2
applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/wxschool/mapper/WxNotifyrecordsMapper.java

@@ -30,7 +30,7 @@ public interface WxNotifyrecordsMapper {
 	
 	int batchRemove(Long[] reIds);
 
-	NotifyrecordsDO getByStu(@Param("stuId") Long stuId, @Param("notifyId") Long notifyId);
+	List<NotifyrecordsDO> getByStu(@Param("stuId") Long stuId, @Param("notifyId") Long notifyId);
 
-	NotifyrecordsDO getByTeacher(@Param("notifyId") Long notifyId, @Param("teacherId") Long teacherId);
+	List<NotifyrecordsDO> getByTeacher(@Param("notifyId") Long notifyId, @Param("teacherId") Long teacherId);
 }

+ 1 - 4
applications/school/school-server/src/main/resources/application.yml

@@ -90,7 +90,4 @@ hystrix:
                         timeoutInMilliseconds: 4000
 smartschool:
   domain:
-    wechat: https://school-wechat.ubtob.com
-logging:
-  level:
-    com.usoftchina.smartschool.school: debug
+    wechat: https://school-wechat.ubtob.com

+ 4 - 1
applications/school/school-server/src/main/resources/config/application-dev.yml

@@ -12,4 +12,7 @@ eureka:
       defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@127.0.0.1:9500/eureka/
 smartschool:
   domain:
-    wechat: https://school-wechat.ubtob.com
+    wechat: https://school-wechat.ubtob.com
+logging:
+  level:
+    com.usoftchina.smartschool.school: debug

+ 2 - 2
applications/school/school-server/src/main/resources/mapper/NotifyMapper.xml

@@ -238,7 +238,7 @@
       (
       #{notice_id,jdbcType=VARCHAR},
       <choose>
-        <when test="item.type == 1">
+        <when test='item.type == "1"'>
           #{item.personId,jdbcType=VARCHAR},
         </when>
         <otherwise>
@@ -246,7 +246,7 @@
         </otherwise>
       </choose>
       <choose>
-        <when test="item.type == 0">
+        <when test='item.type == "0"'>
           #{item.personId,jdbcType=VARCHAR},
         </when>
         <otherwise>

+ 3 - 0
applications/school/school-server/src/main/resources/mapper/SchoolTemplateMapper.xml

@@ -28,6 +28,9 @@
       #{st_templateid,jdbcType=VARCHAR}, #{st_schoolid,jdbcType=BIGINT})
   </insert>
   <insert id="insertSelective" parameterType="com.usoftchina.smartschool.school.po.SchoolTemplate" >
+    <selectKey  resultType="java.lang.Long" keyProperty="st_id">
+      SELECT LAST_INSERT_ID() AS ID
+    </selectKey>
     insert into school_template
     <trim prefix="(" suffix=")" suffixOverrides="," >
       <if test="st_code != null" >

+ 100 - 0
applications/school/school-server/src/main/resources/mapper/ScoreMapper.xml

@@ -31,6 +31,10 @@
     delete from Score_Import
     where si_id = #{si_id,jdbcType=BIGINT}
   </delete>
+  <delete id="deleteByPrimaryDetailKey" parameterType="java.lang.Long" >
+    delete from score_importdetail
+    where sd_siid = #{sd_siid,jdbcType=BIGINT}
+  </delete>
   <insert id="insert" parameterType="com.usoftchina.smartschool.school.po.StuScore" >
     insert into stu_score (score_id, score_type, score_name,
     stu_id, score_total, score_num,
@@ -432,4 +436,100 @@
 	  where sd_siid=#{id}     and  ifnull(sys_parents.openid,'') != '' and  parents_status=1
   </select>
 
+  <update id="updateScoreImport" parameterType="com.usoftchina.smartschool.school.po.ScoreImport" >
+    update score_import
+    <set >
+      <if test="si_date != null" >
+        si_date = #{si_date,jdbcType=TIMESTAMP},
+      </if>
+      <if test="si_creator != null" >
+        si_creator = #{si_creator,jdbcType=VARCHAR},
+      </if>
+      <if test="si_creatorid != null" >
+        si_creatorid = #{si_creatorid,jdbcType=BIGINT},
+      </if>
+      <if test="si_examtitle != null" >
+        si_examtitle = #{si_examtitle,jdbcType=VARCHAR},
+      </if>
+      <if test="si_examscope != null" >
+        si_examscope = #{si_examscope,jdbcType=VARCHAR},
+      </if>
+      <if test="si_term != null" >
+        si_term = #{si_term,jdbcType=VARCHAR},
+      </if>
+      <if test="si_class != null" >
+        si_class = #{si_class,jdbcType=VARCHAR},
+      </if>
+      <if test="si_classid != null" >
+        si_classid = #{si_classid,jdbcType=BIGINT},
+      </if>
+      <if test="si_grade != null" >
+        si_grade = #{si_grade,jdbcType=VARCHAR},
+      </if>
+      <if test="si_gradeid != null" >
+        si_gradeid = #{si_gradeid,jdbcType=BIGINT},
+      </if>
+      <if test="school_id != null" >
+        school_id = #{school_id,jdbcType=BIGINT},
+      </if>
+      <if test="si_examdate != null" >
+        si_examdate = #{si_examdate,jdbcType=TIMESTAMP},
+      </if>
+      <if test="si_publish != null" >
+        si_publish = #{si_publish,jdbcType=INTEGER},
+      </if>
+    </set>
+    where si_id = #{si_id,jdbcType=INTEGER}
+  </update>
+
+  <insert id="insertDetailSelective" parameterType="java.util.List">
+    insert into score_importdetail
+    (sd_siid,sd_stuid,sd_stu,sd_score,
+    sd_subject,sd_remark,school_id,sd_stuNumber
+    ) values
+      <foreach collection="list" item="item" index="index" open="" close="" separator=",">
+      (
+      #{item.sd_siid, jdbcType=BIGINT},#{item.sd_stuid,jdbcType=BIGINT},#{item.sd_stu,jdbcType=VARCHAR},#{item.sd_score,jdbcType=INTEGER},#{item.sd_subject,jdbcType=VARCHAR},
+      #{item.sd_remark,jdbcType=VARCHAR},#{item.school_id,jdbcType=BIGINT},#{item.sd_stuNumber,jdbcType=VARCHAR}
+      )
+      </foreach>
+  </insert>
+
+  <update id="updateDetailSelective" parameterType="com.usoftchina.smartschool.school.po.ScoreImportdetail">
+    <foreach collection="list" item="item" index="index" separator=";">
+      update score_importdetail
+      <set>
+        <if test="item.sd_siid != null">
+            sd_siid = #{item.sd_siid, jdbcType=BIGINT},
+        </if>
+        <if test="item.sd_stuid != null">
+          sd_stuid = #{item.sd_stuid,jdbcType=BIGINT},
+        </if>
+        <if test="item.sd_stu != null">
+          sd_stu = #{item.sd_stu,jdbcType=VARCHAR},
+        </if>
+        <if test="item.sd_score != null">
+          sd_score = #{item.sd_score,jdbcType=INTEGER},
+        </if>
+        <if test="item.sd_subject != null">
+          sd_subject = #{item.sd_subject,jdbcType=VARCHAR},
+        </if>
+        <if test="item.sd_remark != null">
+          sd_remark = #{item.sd_remark,jdbcType=VARCHAR},
+        </if>
+        <if test="item.school_id != null">
+          school_id = #{item.school_id,jdbcType=BIGINT},
+        </if>
+        <if test="item.sd_stuNumber != null">
+          sd_stuNumber = #{item.sd_stuNumber,jdbcType=VARCHAR},
+        </if>
+      </set>
+      WHERE sd_id= #{item.sd_id,jdbcType=BIGINT}
+    </foreach>
+  </update>
+
+  <delete id="deleteDetail">
+    DELETE FROM score_importdetail where sd_id = #{sd_id}
+  </delete>
+
 </mapper>

+ 4 - 0
applications/school/school-server/src/main/resources/mapper/SysClazzMapper.xml

@@ -260,4 +260,8 @@
     </where>
   </select>
 
+  <select id="selectByClazzName" resultMap="BaseResultMap">
+    select * from sys_clazz where clazz_grade=#{clazz_grade} and clazz_name=#{clazz_name} and school_id=#{school_id}
+  </select>
+
 </mapper>

+ 17 - 1
applications/school/school-server/src/main/resources/mapper/SysStudentMapper.xml

@@ -479,7 +479,7 @@
   </select>
 
   <select id="repeatCurriculum" parameterType="long" resultType="integer">
-    select count(1) from clazz_curriculum where clazz_id = #{id} and clazz_curriculum.cur_status=1
+    select count(1) from clazz_main_curriculum where clazz_id = #{id} and clazz_main_curriculum.mcur_status=1
   </select>
 
   <select id="count" resultType="int">
@@ -514,4 +514,20 @@
   <update id="updateClazzName">
     update sys_student set stu_class = #{clazz_name} where clazz_id = #{clazz_id}
   </update>
+
+    <select id="selectByStudent" resultMap="BaseResultMap">
+    select * from sys_student where stu_name=#{stu_name} and clazz_id=#{clazz_id} and school_id=#{school_id}
+  </select>
+
+    <select id="countName" resultType="int">
+        select count(*) from sys_student
+        <where>
+            <if test="stu_name != null">
+                stu_name = #{stu_name}
+            </if>
+            <if test="school_id != null">
+                and school_id=#{school_id}
+            </if>
+        </where>
+    </select>
 </mapper>

+ 5 - 0
base-servers/account/account-server/pom.xml

@@ -54,6 +54,11 @@
       <artifactId>account-dto</artifactId>
       <version>1.0.0-SNAPSHOT</version>
     </dependency>
+    <dependency>
+      <groupId>com.usoftchina.smartschool</groupId>
+      <artifactId>auth-dto</artifactId>
+      <version>1.0.0-SNAPSHOT</version>
+    </dependency>
   </dependencies>
 
   <build>

+ 3 - 4
base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/controller/AccountController.java

@@ -5,8 +5,6 @@ import com.usoftchina.smartschool.account.dto.AccountRegDTO;
 import com.usoftchina.smartschool.account.po.Account;
 import com.usoftchina.smartschool.account.service.AccountService;
 import com.usoftchina.smartschool.base.Result;
-import com.usoftchina.smartschool.context.BaseContextHolder;
-import com.usoftchina.smartschool.exception.BizException;
 import com.usoftchina.smartschool.exception.ExceptionCode;
 import com.usoftchina.smartschool.utils.BeanMapper;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -103,11 +101,12 @@ public class AccountController {
      * @return
      */
     @PostMapping("/password/reset")
-    public Result resetPassword(@RequestParam("password") String password){
-        Account account = accountService.findByPrimaryKey(BaseContextHolder.getUserId());
+    public Result resetPassword(@RequestParam("password") String password, @RequestParam("userId") Long userId){
+        Account account = accountService.findByPrimaryKey(userId);
         if (null == account) {
             return Result.error(ExceptionCode.USER_NOT_EXIST);
         }
+        account.setId(userId);
         account.setUser_pass(accountService.getEncryptedPassword(password, account.getSalt()));
         accountService.updateByPrimaryKeySelective(account);
         return Result.success();

+ 56 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/AuthRestInterceptor.java

@@ -0,0 +1,56 @@
+package com.usoftchina.smartschool.account.interceptor;
+
+import com.usoftchina.smartschool.auth.jwt.JwtHelper;
+import com.usoftchina.smartschool.auth.jwt.JwtInfo;
+import com.usoftchina.smartschool.context.BaseContextHolder;
+import com.usoftchina.smartschool.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Enumeration;
+
+/**
+ * @author chenwei
+ * @date 2019/2/18
+ */
+public class AuthRestInterceptor extends HandlerInterceptorAdapter {
+
+    private static final Logger logger = LoggerFactory.getLogger(AuthRestInterceptor.class);
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (handler instanceof HandlerMethod) {
+            HandlerMethod handlerMethod = (HandlerMethod) handler;
+            String token = null;
+            Enumeration<String> headers = request.getHeaders("Authorization");
+            while(headers.hasMoreElements()){
+                //取最后一个元素
+                token = headers.nextElement();
+            }
+            if (!StringUtils.isEmpty(token)) {
+                logger.debug("token={}", token);
+                /*JwtInfo infoFromToken = JwtHelper.getInfoFromToken(token, "auth/pub.key");
+                BaseContextHolder.setAppId(infoFromToken.getAppId());
+                BaseContextHolder.setUserId(infoFromToken.getUserId());
+                BaseContextHolder.setUserName(infoFromToken.getUserName());
+                BaseContextHolder.setSchoolId(infoFromToken.getSchool_id());
+                BaseContextHolder.setToken(token);
+                logger.info("request={} school_id={} token={} \\r\\n userName={}  ", request.getRequestURI(),
+                        infoFromToken.getSchool_id(), token, infoFromToken.getUserName());*/
+            }
+        } else {
+            // no mapping
+        }
+        return super.preHandle(request, response, handler);
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        BaseContextHolder.remove();
+        super.afterCompletion(request, response, handler, ex);
+    }
+}

+ 23 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/InterceptorConfig.java

@@ -0,0 +1,23 @@
+package com.usoftchina.smartschool.account.interceptor;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author: ChenWei
+ * @create: 2019-03-018 15:03
+ **/
+@Configuration
+public class InterceptorConfig implements WebMvcConfigurer {
+    @Bean
+    public AuthRestInterceptor authRestInterceptor() {
+        return new AuthRestInterceptor();
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(authRestInterceptor());
+    }
+}

+ 33 - 0
base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/ServiceFeignInterceptor.java

@@ -0,0 +1,33 @@
+package com.usoftchina.smartschool.account.interceptor;
+
+import com.usoftchina.smartschool.context.BaseContextHolder;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author yingp
+ * @date 2018/10/2
+ */
+public class ServiceFeignInterceptor implements RequestInterceptor {
+    /*@Autowired
+    private AuthConfig authConfig;*/
+
+    private static final String AUTHHEADER = "Authorization";
+
+    private Logger logger = LoggerFactory.getLogger(ServiceFeignInterceptor.class);
+
+    public ServiceFeignInterceptor() {
+    }
+
+    @Override
+    public void apply(RequestTemplate requestTemplate) {
+        logger.debug("{}: {}", AUTHHEADER, BaseContextHolder.getToken());
+        requestTemplate.header(AUTHHEADER, BaseContextHolder.getToken());
+    }
+
+    /*public void setAuthConfig(AuthConfig authConfig) {
+        this.authConfig = authConfig;
+    }*/
+}

二進制
base-servers/account/account-server/src/main/resources/auth/pub.key


+ 1 - 1
base-servers/account/account-server/src/main/resources/config/application-docker-cloud.yml

@@ -1,6 +1,6 @@
 eureka:
   instance:
-    hostname: smartschool-school-server
+    hostname: smartschool-account-server
     prefer-ip-address: false
   client:
     serviceUrl:

+ 16 - 1
base-servers/account/account-server/src/main/resources/mapper/AccountMapper.xml

@@ -47,7 +47,22 @@
 
   </update>
   <update id="updateByPrimaryKeySelective">
-
+    UPDATE sys_user
+    <set>
+      <if test="user_phone != null">
+        user_phone = #{user_phone, jdbcType=VARCHAR},
+      </if>
+      <if test="user_pass != null">
+        user_pass = #{user_pass, jdbcType=VARCHAR},
+      </if>
+      <if test="user_phone != null">
+        user_code = #{user_code, jdbcType=VARCHAR},
+      </if>
+      <if test="user_phone != null">
+        salt = #{salt, jdbcType=VARCHAR},
+      </if>
+    </set>
+    WHERE USER_ID = #{id, jdbcType=BIGINT}
   </update>
 
   <select id="selectTeacherName" resultType="string">

+ 1 - 1
base-servers/auth/auth-server/src/main/resources/config/application-docker-cloud.yml

@@ -1,6 +1,6 @@
 eureka:
   instance:
-    hostname: smartschool-school-server
+    hostname: smartschool-auth-server
     prefer-ip-address: false
   client:
     serviceUrl:

+ 221 - 0
framework/core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextScheduler.java

@@ -0,0 +1,221 @@
+/**
+ * Copyright 2013 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.netflix.hystrix.strategy.concurrency;
+
+import java.util.concurrent.*;
+
+import com.alibaba.ttl.TtlRunnable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import rx.*;
+import rx.functions.Action0;
+import rx.functions.Func0;
+import rx.internal.schedulers.ScheduledAction;
+import rx.subscriptions.*;
+
+import com.netflix.hystrix.HystrixThreadPool;
+import com.netflix.hystrix.strategy.HystrixPlugins;
+
+/**
+ * 处理Hystrix线程隔离导致ThreadLocal数据丢失问题
+ * @author: guq
+ * @create: 2019-01-10 11:05
+ */
+public class HystrixContextScheduler extends Scheduler {
+
+    private final HystrixConcurrencyStrategy concurrencyStrategy;
+    private final Scheduler actualScheduler;
+    private final HystrixThreadPool threadPool;
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(HystrixContextScheduler.class);
+
+    public HystrixContextScheduler(Scheduler scheduler) {
+        this.actualScheduler = scheduler;
+        this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
+        this.threadPool = null;
+    }
+
+    public HystrixContextScheduler(HystrixConcurrencyStrategy concurrencyStrategy, Scheduler scheduler) {
+        this.actualScheduler = scheduler;
+        this.concurrencyStrategy = concurrencyStrategy;
+        this.threadPool = null;
+    }
+
+    public HystrixContextScheduler(HystrixConcurrencyStrategy concurrencyStrategy, HystrixThreadPool threadPool) {
+        this(concurrencyStrategy, threadPool, new Func0<Boolean>() {
+            @Override
+            public Boolean call() {
+                return true;
+            }
+        });
+    }
+
+    public HystrixContextScheduler(HystrixConcurrencyStrategy concurrencyStrategy, HystrixThreadPool threadPool, Func0<Boolean> shouldInterruptThread) {
+        this.concurrencyStrategy = concurrencyStrategy;
+        this.threadPool = threadPool;
+        this.actualScheduler = new ThreadPoolScheduler(threadPool, shouldInterruptThread);
+    }
+
+    @Override
+    public Worker createWorker() {
+        return new HystrixContextSchedulerWorker(actualScheduler.createWorker());
+    }
+
+    private class HystrixContextSchedulerWorker extends Worker {
+
+        private final Worker worker;
+
+        private HystrixContextSchedulerWorker(Worker actualWorker) {
+            this.worker = actualWorker;
+        }
+
+        @Override
+        public void unsubscribe() {
+            worker.unsubscribe();
+        }
+
+        @Override
+        public boolean isUnsubscribed() {
+            return worker.isUnsubscribed();
+        }
+
+        @Override
+        public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {
+            if (threadPool != null) {
+                if (!threadPool.isQueueSpaceAvailable()) {
+                    throw new RejectedExecutionException("Rejected command because thread-pool queueSize is at rejection threshold.");
+                }
+            }
+            return worker.schedule(new HystrixContexSchedulerAction(concurrencyStrategy, action), delayTime, unit);
+        }
+
+        @Override
+        public Subscription schedule(Action0 action) {
+            if (threadPool != null) {
+                if (!threadPool.isQueueSpaceAvailable()) {
+                    throw new RejectedExecutionException("Rejected command because thread-pool queueSize is at rejection threshold.");
+                }
+            }
+            return worker.schedule(new HystrixContexSchedulerAction(concurrencyStrategy, action));
+        }
+
+    }
+
+    private static class ThreadPoolScheduler extends Scheduler {
+
+        private final HystrixThreadPool threadPool;
+        private final Func0<Boolean> shouldInterruptThread;
+
+        public ThreadPoolScheduler(HystrixThreadPool threadPool, Func0<Boolean> shouldInterruptThread) {
+            this.threadPool = threadPool;
+            this.shouldInterruptThread = shouldInterruptThread;
+        }
+
+        @Override
+        public Worker createWorker() {
+            return new ThreadPoolWorker(threadPool, shouldInterruptThread);
+        }
+
+    }
+
+    /**
+     * Purely for scheduling work on a thread-pool.
+     * <p>
+     * This is not natively supported by RxJava as of 0.18.0 because thread-pools
+     * are contrary to sequential execution.
+     * <p>
+     * For the Hystrix case, each Command invocation has a single action so the concurrency
+     * issue is not a problem.
+     */
+    private static class ThreadPoolWorker extends Worker {
+
+        private final HystrixThreadPool threadPool;
+        private final CompositeSubscription subscription = new CompositeSubscription();
+        private final Func0<Boolean> shouldInterruptThread;
+
+        public ThreadPoolWorker(HystrixThreadPool threadPool, Func0<Boolean> shouldInterruptThread) {
+            this.threadPool = threadPool;
+            this.shouldInterruptThread = shouldInterruptThread;
+        }
+
+        @Override
+        public void unsubscribe() {
+            subscription.unsubscribe();
+        }
+
+        @Override
+        public boolean isUnsubscribed() {
+            return subscription.isUnsubscribed();
+        }
+
+        @Override
+        public Subscription schedule(final Action0 action) {
+            if (subscription.isUnsubscribed()) {
+                // don't schedule, we are unsubscribed
+                return Subscriptions.unsubscribed();
+            }
+
+            // This is internal RxJava API but it is too useful.
+            ScheduledAction sa = new ScheduledAction(action);
+
+            subscription.add(sa);
+            sa.addParent(subscription);
+
+            ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPool.getExecutor();
+            Runnable runnable = TtlRunnable.get(sa);
+            FutureTask<?> f = (FutureTask<?>) executor.submit(runnable);
+            sa.add(new FutureCompleterWithConfigurableInterrupt(f, shouldInterruptThread, executor));
+
+            return sa;
+        }
+
+        @Override
+        public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {
+            throw new IllegalStateException("Hystrix does not support delayed scheduling");
+        }
+    }
+
+    /**
+     * Very similar to rx.internal.schedulers.ScheduledAction.FutureCompleter, but with configurable interrupt behavior
+     */
+    private static class FutureCompleterWithConfigurableInterrupt implements Subscription {
+        private final FutureTask<?> f;
+        private final Func0<Boolean> shouldInterruptThread;
+        private final ThreadPoolExecutor executor;
+
+        private FutureCompleterWithConfigurableInterrupt(FutureTask<?> f, Func0<Boolean> shouldInterruptThread, ThreadPoolExecutor executor) {
+            this.f = f;
+            this.shouldInterruptThread = shouldInterruptThread;
+            this.executor = executor;
+        }
+
+        @Override
+        public void unsubscribe() {
+            executor.remove(f);
+            if (shouldInterruptThread.call()) {
+                f.cancel(true);
+            } else {
+                f.cancel(false);
+            }
+        }
+
+        @Override
+        public boolean isUnsubscribed() {
+            return f.isCancelled();
+        }
+    }
+
+}

+ 10 - 4
frontend/pc-web/app/model/Score.js

@@ -4,13 +4,19 @@
 Ext.define('school.model.Score', {
     extend: 'school.model.Base',
     fields: [{
-        name: 'number', // 学号
-        type: 'int'
+        name: 'sd_stuNumber', // 学号
+        type: 'string'
+    }, {
+        name: 'sd_stu', // 姓名
+        type: 'string'
     }, {
-        name: 'name', // 姓名
+        name: 'sd_subject',
         type: 'string'
     }, {
-        name: 'score', // 成绩
+        name: 'sd_score',
         type: 'float'
+    }, {
+        name: 'sd_remark',
+        type: 'string'
     }]
 });

+ 4 - 1
frontend/pc-web/app/view/Interaction/access/List.js

@@ -81,7 +81,10 @@ Ext.define('school.view.interaction.access.List', {
                     hidden: true
                 }, {
                     text: '类型',
-                    dataIndex: 'record_type'
+                    dataIndex: 'record_type',
+                    renderer: function(v,m,r) {
+                        return v == 1 ? '入校' : (v == 2 ? '出校' : '其他')
+                    }
                 }, {
                     text: '学号',
                     dataIndex: 'stu_number',

+ 10 - 2
frontend/pc-web/app/view/Interaction/homework/List.js

@@ -193,11 +193,19 @@ Ext.define('school.view.interaction.homework.List', {
                 }, {
                     text: '标题',
                     dataIndex: 'task_title',
-                    width: 120
+                    width: 250
                 }, {
                     text: '内容',
                     dataIndex: 'task_context',
-                    width: 300
+                    width: 300,
+                    xtype: 'widgetcolumn',
+                    tdCls: 'content-column',
+                    widget: {
+                        xtype: 'textareatrigger',
+                        winTitle: '内容',
+                        margin: '0',
+                        editable: false
+                    },
                 }, {
                     text: '发布人',
                     dataIndex: 'creator',

+ 1 - 1
frontend/pc-web/app/view/Interaction/mailbox/List.js

@@ -118,7 +118,7 @@ Ext.define('school.view.interaction.mailbox.List', {
                 columns : [{
                     text: '标题',
                     dataIndex: 'mailbox_title',
-                    width: 120
+                    width: 250
                 }, {
                     text: '内容',
                     dataIndex: 'mailbox_context',

+ 10 - 11
frontend/pc-web/app/view/Interaction/notice/List.js

@@ -139,20 +139,19 @@ Ext.define('school.view.interaction.notice.List', {
                 }, {
                     text: '标题',
                     dataIndex: 'notify_title',
-                    width: 120,
-                    // tdCls: 'x-detail-column',
-                    // listeners: {
-                    //     click: function(view, td, row, col, e, record, tr, eOpts, event) {
-                    //         let gridConfig = me.gridConfig;
-                    //         school.util.BaseUtil.openTab(gridConfig.addXtype, gridConfig.addTitle + '(' + record.get('notify_title') + ')', gridConfig.addXtype + record.get(gridConfig.idField), {
-                    //             initId: record.get(gridConfig.idField)
-                    //         });
-                    //     }
-                    // }
+                    width: 250
                 }, {
                     text: '内容',
                     dataIndex: 'notify_details',
-                    width: 300
+                    width: 300,
+                    xtype: 'widgetcolumn',
+                    tdCls: 'content-column',
+                    widget: {
+                        xtype: 'textareatrigger',
+                        winTitle: '内容',
+                        margin: '0',
+                        editable: false
+                    },
                 }, {
                     text: '发布人',
                     dataIndex: 'creator',

+ 108 - 14
frontend/pc-web/app/view/Interaction/score/Detail.js

@@ -12,7 +12,7 @@ Ext.define('school.view.interaction.score.Detail', {
     // _readUrl: 'http://10.1.80.36:9520/api/school/score/read',
     _readUrl: '/api/school/score/read',
     // _saveUrl: 'http://10.1.80.47:9520/api/school/score/save',
-    // _saveUrl: '/api/sale/sss/update',
+    _saveUrl: '/api/school/score/save',
     // _deleteUrl: 'http://10.1.80.47:9520/api/school/score/delete',
     _deleteUrl: '/api/school/score/delete',
     
@@ -29,21 +29,79 @@ Ext.define('school.view.interaction.score.Detail', {
                 name: 'si_examtitle',
                 fieldLabel: '考试标题'
             }, {
-                xtype: 'textfield',
+                xtype: 'datefield',
                 name: 'si_examdate',
-                fieldLabel: '考试时间'
+                fieldLabel: '考试时间',
+                allowBlank: false
             }, {
-                xtype: 'textfield',
+            //     xtype: 'textfield',
+            //     name: 'si_examscope',
+            //     fieldLabel: '考试范围'
+            // }, {
+                xtype: 'combobox',
                 name: 'si_examscope',
-                fieldLabel: '考试范围'
+                fieldLabel: '考试范围',
+                editable: false,
+                queryModel: 'local',
+                valueField: 'name',
+                displayField: 'name',
+                store: Ext.create('Ext.data.Store', {
+                    fields: ['name'],
+                    data: [
+                        {name: '全年级'},
+                        {name: '班级'}
+                    ]
+                }),
+                defaultValue: '班级'
             }, {
+            //     xtype: 'hidden',
+            //     name: 'task_gradeid',
+            //     fieldLabel: '年级ID'
+            // }, {
                 xtype: 'gradecombo',
                 name: 'si_grade',
-                fieldLabel: '年级'
+                fieldLabel: '年级',
+                listeners: {
+                    select: function (combo, record, eOpts) {
+                        let viewModel = me.getViewModel();
+                        // viewModel.set('task_gradeid', record.get('grade_id'));
+                        viewModel.set('clazz_id', null);
+                        viewModel.set('si_class', null);
+                    }
+                },
+                allowBlank: false
+            }, {
+                xtype: 'hidden',
+                name: 'clazz_id',
+                fieldLabel: '班级ID'
             }, {
                 xtype: 'classcombo',
                 name: 'si_class',
-                fieldLabel: '班级'
+                fieldLabel: '班级',
+                listeners: {
+                    expand: function (combo, eOpts) {
+                        combo.store.clearFilter();
+
+                        var gradeCombo = combo.up('form').getForm().findField('si_grade');
+                        var gradeName = gradeCombo.getValue();
+
+                        var filter = new Ext.util.Filter({
+                            property: 'clazz_grade',
+                            value: gradeName
+                        });
+
+                        if (!!gradeName) {
+                            combo.store.setFilters([filter]);
+                        }
+                    },
+                    select: function (combo, record, eOpts) {
+                        let viewModel = me.getViewModel();
+                        viewModel.set('clazz_id', record.get('clazz_id'));
+                        // viewModel.set('task_gradeid', record.get('grade_id'));
+                        viewModel.set('si_grade', record.get('clazz_grade'));
+                    }
+                },
+                allowBlank: false
             }, {
                 xtype: 'combobox',
                 name: 'si_publish',
@@ -62,28 +120,56 @@ Ext.define('school.view.interaction.score.Detail', {
             }, {
                 name: "score",
                 xtype: "detailGridField",
+                idColumn: 'sd_id',
                 detnoColumn: 'no',
                 storeModel: 'school.model.Score',
-                deleteDetailUrl: '/api/sale/sale/deleteDetail',
-                allowEmpty: true,
+                deleteDetailUrl: '/api/school/score/deleteDetail',
+                allowEmpty: false,
                 showCount: false,
                 emptyRows: 10,
                 rowViewModel: {},
                 columns: [{
+                    text: 'ID',
+                    dataIndex: 'sd_id',
+                    hidden: true
+                }, {
                     text: '学生编号',
-                    dataIndex: 'sd_stuNumber'
+                    dataIndex: 'sd_stuNumber',
+                    allowBlank: false,
+                    editor: {
+                        xtype: 'textfield'
+                    }
                 }, {
                     text: '姓名',
-                    dataIndex: 'sd_stu'
+                    dataIndex: 'sd_stu',
+                    allowBlank: false,
+                    editor: {
+                        xtype: 'dbfindtrigger',
+                    }
                 }, {
                     text: '科目',
-                    dataIndex: 'sd_subject'
+                    dataIndex: 'sd_subject',
+                    allowBlank: false,
+                    editor: {
+                        xtype: 'subjectcombo',
+                        valueField: 'subject_name',
+                        hideLabel: true
+                    }
                 }, {
                     text: '成绩',
-                    dataIndex: 'sd_score'
+                    dataIndex: 'sd_score',
+                    allowBlank: false,
+                    editor: {
+                        xtype: 'numberfield',
+                        minValue: 0
+                    }
                 }, {
                     text: '备注',
-                    dataIndex: 'sd_remark'
+                    dataIndex: 'sd_remark',
+                    editor: {
+                        xtype: 'textfield'
+                    },
+                    width: 200
                 }]
             }],
             applyBtns: [{
@@ -92,6 +178,13 @@ Ext.define('school.view.interaction.score.Detail', {
                 bind: {
                     hidden: '{!showDeleteBtn || !si_id || si_publish == 1}'
                 },
+            }, {
+                apply: true,
+                text: '保存',
+                bind: {
+                    hidden: '{!showSaveBtn || si_publish == 1}',
+                    disabled: '{!base.valid}'
+                }
             }],
             toolBtns: [{
                 xtype: 'button',
@@ -108,6 +201,7 @@ Ext.define('school.view.interaction.score.Detail', {
     },
 
     refresh: function() {
+        Ext.StoreMgr.get('store_subject').load();
         Ext.StoreMgr.get('store_grade').load();
         Ext.StoreMgr.get('store_class').load();
     }

+ 122 - 1
frontend/pc-web/app/view/Interaction/score/DetailController.js

@@ -2,6 +2,88 @@ Ext.define('school.view.interaction.score.DetailController', {
     extend: 'school.view.core.form.FormPanelController',
     alias: 'controller.interaction-score-detail',
 
+    init: function (form) {
+        var me = this;
+        this.control({
+            'dbfindtrigger[name=sd_stu]':{
+                beforerender:function(f){
+                    Ext.apply(f,{
+                        addTitle: '学生',
+                        //数据接口
+                        dataUrl:'/api/school/student/list',
+                        //联想设置
+                        dbtpls:[{
+                            field:'stu_name',width:150
+                        }],
+                        dbfinds:[{
+                            from: 'stu_name', to: 'sd_stu',
+                        }, {
+                            from: 'stu_number', to: 'sd_stuNumber'
+                        }],
+                        defaultCondition: "1=1",
+                        dbSearchFields:[{
+                            emptyText:'请输入学生学号或姓名',
+                            xtype : "textfield", 
+                            name : "search", 
+                            getCondition: function(v) {
+                                return "(upper(stu_name) like '%"+v.toUpperCase()+"%' or upper(stu_number) like '%"+v.toUpperCase()+"%')";
+                            },
+                            allowBlank : true, 
+                            width:300
+                        }],
+                        //放大镜窗口列表
+                        dbColumns:[{
+                            text: "ID",
+                            dataIndex: "stu_id",
+                            hidden:true,
+                            xtype: "numbercolumn"
+                        }, {
+                            text: '工号',
+                            dataIndex: 'stu_number',
+                            width: 110
+                        }, {
+                            text: "姓名",
+                            dataIndex: "stu_name",
+                            width: 110
+                        }]
+                    }) ; 
+                },
+                beforequery: function(f) {
+                    var defaultCondition = this.getDefaultCondition(1);
+                    if(!defaultCondition) {
+                        return false;
+                    }
+                    Ext.apply(f, {
+                        defaultCondition: defaultCondition
+                    });
+                },
+                beforetriggerclick: function(f) {
+                    var defaultCondition = this.getDefaultCondition(1);
+                    if(!defaultCondition) {
+                        return false;
+                    }
+                    Ext.apply(f, {
+                        defaultCondition: defaultCondition
+                    });
+                }
+            },
+        });
+    },
+
+    getDefaultCondition: function(idx) {
+        var me = this,
+        viewModel = me.getViewModel(),
+        gradeName = viewModel.get('si_grade'),
+        clazzName = viewModel.get('si_class');
+
+        if(gradeName && clazzName) {
+            return 'stu_grade=\'' + gradeName + '\' and stu_class = \'' + clazzName + '\'';
+        }else {
+            school.util.BaseUtil.showErrorToast('请先选择【' + '<span style="color: red;">班级</span>】');
+            return null;
+        }
+    },
+
     onAfterSave: function(localJson) {
         var form = this.getView();
         var id = localJson.data.id;
@@ -36,5 +118,44 @@ Ext.define('school.view.interaction.score.DetailController', {
             view.setLoading(false);
             school.util.BaseUtil.showErrorToast('发布失败: ' + e.message);
         });
-    }
+    },
+
+    /**
+     * 清空所有从表数据
+     */
+    clearDetails: function() {
+        var me = this;
+        
+        me.clearDetail0();
+    },
+
+    /**
+     * 清空第一个从表数据
+     */
+    clearDetail0: function(f, n, o) {
+        var me = this,
+        form = me.getView(),
+        grid = form.query('detailGridField')[0];
+        me.clearDetail(grid);
+    },
+
+    /**
+     * 清空一个从表数据
+     */
+    clearDetail: function(grid) {
+        var datas = [],
+        emptyRows = grid.emptyRows,
+        detnoColumn = grid.detnoColumn,
+        detno = 0,
+        store = grid.getStore();
+        
+        Ext.Array.each(new Array(emptyRows), function() {
+            detno += 1;
+            var data = {};
+            data[detnoColumn] = detno;
+            datas.push(data);
+        })
+        store.removeAll();
+        store.add(datas);
+    },
 });

+ 12 - 2
frontend/pc-web/app/view/Interaction/score/DetailModel.js

@@ -3,11 +3,21 @@ Ext.define('school.view.interaction.score.DetailModel', {
     alias: 'viewmodel.interaction-score-detail',
 
     data: {
-        showAddBtn: false,
+        showAddBtn: true,
         showRefreshBtn: true,
         showCopyBtn: false,
-        showSaveBtn: false,
+        showSaveBtn: true,
         showDeleteBtn: true,
         showLogBtn: false
     },
+
+    formulas: {
+        si_publish_change: {
+            bind: '{si_publish}',
+            get: function(v) {
+                let view = this.getView();
+                view.setEditable(v != 1);
+            }
+        }
+    }
 });

+ 5 - 4
frontend/pc-web/app/view/Interaction/score/List.js

@@ -97,10 +97,10 @@ Ext.define('school.view.interaction.score.List', {
                 },
                 hiddenTools: false,
                 toolBtns: [{
-                //     xtype: 'button',
-                //     text: '新增',
-                //     handler: 'onAddClick'
-                // }, {
+                    xtype: 'button',
+                    text: '新增',
+                    handler: 'onAddClick'
+                }, {
                     xtype: 'importbutton',
                     text: '导入',
                     belong: me,
@@ -241,6 +241,7 @@ Ext.define('school.view.interaction.score.List', {
     },
 
     refresh: function() {
+        Ext.StoreMgr.get('store_subject').load();
         Ext.StoreMgr.get('store_grade').load();
         Ext.StoreMgr.get('store_class').load();
         this.items.items[0].store.load();

+ 1 - 1
frontend/pc-web/app/view/Interaction/score/ListController.js

@@ -3,6 +3,6 @@ Ext.define('school.view.interaction.score.ListController', {
     alias: 'controller.interaction-score-list',
 
     onAddClick: function() {
-        school.util.BaseUtil.openTab('interaction-score-detail', '录入成绩', 'interaction-score-detail-add'); 
+        school.util.BaseUtil.openTab('interaction-score-detail', '成绩录入', 'interaction-score-detail-add'); 
     }
 });

+ 12 - 2
frontend/pc-web/app/view/Interaction/timetable/List.js

@@ -118,7 +118,7 @@ Ext.define('school.view.interaction.timetable.List', {
                 })()
             }, {
                 xtype: 'combobox',
-                name: 'status',
+                name: 'mcur_status',
                 fieldLabel: '发布状态',
                 displayField: 'name',
                 valueField: 'value',
@@ -168,6 +168,13 @@ Ext.define('school.view.interaction.timetable.List', {
                         var g = me.down('grid');
                         g.store.loadPage(g.store.currentPage);
                     }
+                }, {
+                    xtype: 'button',
+                    text: '发布',
+                    type: 'publish',
+                    path: 'batchPublish',
+                    reference: 'publish',
+                    handler: 'onPublishClick'
                 }, {
                     xtype: 'button',
                     text: '删除',
@@ -246,7 +253,10 @@ Ext.define('school.view.interaction.timetable.List', {
                     renderer: function(v) {
                         return v == '1' ? '已生效' : '未生效'
                     }
-                }]
+                }],
+                listeners: {
+                    selectionchange: 'selectionchange'
+                }
             },
         });
         this.callParent(arguments);

+ 68 - 0
frontend/pc-web/app/view/Interaction/timetable/ListController.js

@@ -4,5 +4,73 @@ Ext.define('school.view.interaction.timetable.ListController', {
 
     onAddClick: function() {
         school.util.BaseUtil.openTab('interaction-timetable-detail', '新增课程表', 'interaction-timetable-detail-add'); 
+    },
+
+    selectionchange: function(table, selected, eOpts) {
+        let me = this,
+        refs = me.getReferences(),
+        btn = refs.publish,
+        type = btn.type;
+
+        btn.setDisabled(false);
+        if(selected.length == 1) {
+            btn.setText(selected[0].get('status') == '1' ? '取消发布' : '发布');
+            btn.type = (selected[0].get('status') == '1' ? 'republish' : 'publish');
+            btn.path = (selected[0].get('status') == '1' ? 'batchRepublish' : 'batchPublish');
+            return;
+        }else if(selected.length == 0) {
+            btn.setText('发布');
+            btn.type = 'publish';
+            btn.path = 'batchPublish';
+            return;
+        }else {
+            for(let i = 0; i < selected.length; i++) {
+                let s = selected[i];
+                if((s.get('status') == '1' && type == 'publish') || (s.get('status') == '0' && type == 'republish')) {
+                    btn.setDisabled(true);
+                    return;
+                }
+            }
+        }
+    },
+
+    onPublishClick: function() {
+        let me = this,
+        view = me.getView(),
+        grid = view.down('grid'),
+        selectedRecords = grid.getSelection(),
+        refs = me.getReferences(),
+        btn = refs.publish,
+        path = btn.path,
+        data;
+
+        data = selectedRecords.map(function (r) {
+            return {
+                id: r.get('id')
+            };
+        });
+
+        if (data.length == 0) {
+            school.util.BaseUtil.showErrorToast('请先勾选需要发布的记录');
+            return;
+        }
+
+        grid.setLoading(true);
+        school.util.BaseUtil.request({
+            // url: 'http://10.1.80.36:9520/api/school/curriculum/batchDelete',
+            url: '/api/school/curriculum/' + path,
+            method: 'POST',
+            params: JSON.stringify({
+                baseDTOs: data
+            })
+        }).then(function (res) {
+            grid.setLoading(false);
+            school.util.BaseUtil.showSuccessToast('操作成功');
+            grid.store.loadPage(grid.store.currentPage);
+            grid.getSelectionModel().deselectAll();
+        }).catch(function (e) {
+            grid.setLoading(false);
+            school.util.BaseUtil.showErrorToast('操作失败: ' + e.message);
+        });
     }
 });

+ 110 - 0
frontend/pc-web/app/view/analysis/attence/Chart1.js

@@ -0,0 +1,110 @@
+Ext.define('school.view.analysis.attence.Chart1', {
+    extend: 'school.view.core.chart.ChartBase',
+    xtype: 'attence-chart1',
+
+    title: '初三年级本周准勤率',
+
+    initComponent: function () {
+        var me = this;
+
+        Ext.apply(me, {
+            items: [{
+                xtype: 'echartsbase',
+                bind: {
+                    store: '{chart1}',
+                },
+                createOption: me.createOption.bind(me)
+            }]
+        });
+
+        me.callParent(arguments);
+    },
+
+    createOption: function (store) {
+        var me = this,
+        fields = [],
+        cFields = ['一班', '二班', '三班', '四班'],
+        c1 = [],
+        c2 = [],
+        c3 = [],
+        c4 = [],
+        cDatas = [],
+        o;
+
+        store.each(function (d) {
+            var d = d.data;
+            fields.push(d.day);
+            c1.push(d.c1);
+            c2.push(d.c2);
+            c3.push(d.c3);
+            c4.push(d.c4);
+        });
+
+        cDatas.push(c1, c2, c3, c4);
+
+        return {
+            grid: {
+                left: 0,
+                right: 0,
+                top: 40,
+                bottom: 5,
+                borderColor: '#E5EAEF',
+                containLabel: true
+            },
+            xAxis: {
+                type: 'category',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                axisLabel: {
+                    color: '#485465',
+                    interval: 0
+                },
+                data: fields,
+            },
+            yAxis: {
+                type: 'value',
+                min: 85,
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                splitLine: {
+                    lineStyle: {
+                        color: ['#E5EAEF']
+                    }
+                },
+                axisLabel: {
+                    color: '#485465'
+                }
+            },
+            legend: {
+                data: cFields
+            },
+            series: me.getSeries(cFields, cDatas)
+        };
+    },
+
+    getSeries: function(fields, datas) {
+        let series = [];
+
+        for(let i = fields.length - 1; i >= 0 ; i--) {
+            let s = {
+                name: fields[i],
+                type: 'line',
+                label: {
+                    normal: {
+                        show: true
+                    }
+                },
+                data: datas[i]
+            };
+            series.push(s);
+        }
+
+        return series;
+    }
+});

+ 113 - 0
frontend/pc-web/app/view/analysis/attence/Chart2.js

@@ -0,0 +1,113 @@
+Ext.define('school.view.analysis.attence.Chart2', {
+    extend: 'school.view.core.chart.ChartBase',
+    xtype: 'attence-chart2',
+
+    title: '初三年级今日迟到人数',
+
+    initComponent: function () {
+        var me = this;
+
+        Ext.apply(me, {
+            items: [{
+                xtype: 'echartsbase',
+                bind: {
+                    store: '{chart2}',
+                },
+                createOption: me.createOption
+            }]
+        });
+
+        me.callParent(arguments);
+    },
+
+    createOption: function (store) {
+        var fields = [],
+            data = [];
+
+        store.each(function (d) {
+            var d = d.data;
+            fields.push(d.class);
+            data.push(d.count);
+        });
+        return {
+            color: [
+                '#34BAF6'
+            ],
+            grid: {
+                left: 0,
+                right: 0,
+                top: 40,
+                bottom: 5,
+                borderColor: '#E5EAEF',
+                containLabel: true
+            },
+            tooltip: {
+                trigger: 'axis',
+                formatter: function (params, ticket, callback) {
+                    var name = '',
+                    series = [];
+
+                    for(var x = 0; x < params.length; x++) {
+                        var p = params[x],
+                        marker = p.marker,
+                        seriesName = p.seriesName,
+                        name = p.name,
+                        value = p.value;
+
+                        value = school.util.BaseUtil.numberFormat(value, 4, true);
+
+                        series.push(marker + value);
+                    }
+
+                    if(name.length > 9) {
+                        name = Ext.String.insert(name, '<br/>', 7)
+                    }
+        
+
+                    return name + ': ' + '<br/>' + series.join('<br/>');
+                }
+            },
+            xAxis: {
+                type: 'category',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                axisLabel: {
+                    color: '#485465',
+                    interval: 0
+                },
+                data: fields,
+            },
+            yAxis: {
+                type: 'value',
+                interval: 1,
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                splitLine: {
+                    lineStyle: {
+                        color: ['#E5EAEF']
+                    }
+                },
+                axisLabel: {
+                    color: '#485465'
+                }
+            },
+            series: [{
+                type: 'bar',
+                barWidth: 25,
+                data: data,
+                label: {
+                    normal: {
+                        show: true,
+                        position: 'outside'
+                    }
+                },
+            }]
+        };
+    }
+});

+ 19 - 0
frontend/pc-web/app/view/analysis/attence/Panel.js

@@ -0,0 +1,19 @@
+Ext.define('school.view.analysis.attence.Panel', {
+    extend: 'Ext.panel.Panel',
+    xtype: 'analysis-attence',
+
+    viewModel: 'analysis-attence',
+    layout: 'responsivecolumn',
+    scrollable: true,
+
+    defaults: {
+        userCls: 'big-50 small-100',
+        padding: 10
+    },
+
+    items: [{
+        xtype: 'attence-chart1'
+    }, {
+        xtype: 'attence-chart2'
+    }]
+});

+ 60 - 0
frontend/pc-web/app/view/analysis/attence/PanelModel.js

@@ -0,0 +1,60 @@
+Ext.define('school.view.analysis.attence.PanelModel', {
+    extend: 'Ext.app.ViewModel',
+    alias: 'viewmodel.analysis-attence',
+
+    data: {
+    },
+
+    stores: {
+        chart1: {
+            fields: ['day', 'c1', 'c2', 'c3', 'c4'],
+            data: [{
+                day: '周一',
+                c1: '95.49',
+                c2: '98.13',
+                c3: '91.02',
+                c4: '92.64',
+            }, {
+                day: '周二',
+                c1: '96.49',
+                c2: '99.13',
+                c3: '93.02',
+                c4: '95.43',
+            }, {
+                day: '周三',
+                c1: '100',
+                c2: '98.34',
+                c3: '90.62',
+                c4: '97.13',
+            }, {
+                day: '周四',
+                c1: '100',
+                c2: '93.23',
+                c3: '98.23',
+                c4: '91.44',
+            }, {
+                day: '周五',
+                c1: '96.82',
+                c2: '94.68',
+                c3: '91.32',
+                c4: '94.54',
+            }]
+        },
+        chart2: {
+            fields: ['class', 'count'],
+            data: [{
+                class: '一班',
+                count: '2'
+            }, {
+                class: '二班',
+                count: '1'
+            }, {
+                class: '三班',
+                count: '3'
+            }, {
+                class: '四班',
+                count: '3'
+            }]
+        }
+    }
+});

+ 123 - 0
frontend/pc-web/app/view/analysis/consumption/Chart1.js

@@ -0,0 +1,123 @@
+Ext.define('school.view.analysis.consumption.Chart1', {
+    extend: 'school.view.core.chart.ChartBase',
+    xtype: 'consumption-chart1',
+
+    title: '各年级学生月校园平均消费统计',
+
+    initComponent: function () {
+        var me = this;
+
+        Ext.apply(me, {
+            items: [{
+                xtype: 'echartsbase',
+                bind: {
+                    store: '{chart1}',
+                },
+                createOption: me.createOption.bind(me)
+            }]
+        });
+
+        me.callParent(arguments);
+    },
+
+    createOption: function (store) {
+        var me = this,
+        fields = [],
+        gFields = ['初一', '初二', '初三'],
+        g1 = [],
+        g2 = [],
+        g3 = [],
+        gDatas = [],
+        o;
+
+        store.each(function (d) {
+            var d = d.data;
+            fields.push(d.month);
+            g1.push(d.g1);
+            g2.push(d.g2);
+            g3.push(d.g3);
+        });
+
+        gDatas.push(g1, g2, g3);
+
+        o = {
+            color: [
+                '#1EC09F',
+                '#27A7FF',
+                '#4E84F5',
+                '#FDC200',
+                '#76DDFB',
+                '#FE7D6B',
+            ],
+            grid: {
+                left: 0,
+                right: 0,
+                top: 60,
+                bottom: 5,
+                borderColor: '#E5EAEF',
+                containLabel: true
+            },
+            tooltip : {
+                trigger: 'axis',
+                axisPointer : {
+                    type : 'shadow'
+                }
+            },
+            legend: {
+                data: gFields
+            },
+            xAxis: {
+                type: 'category',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                axisLabel: {
+                    color: '#485465',
+                    interval: 0
+                },
+                data: fields,
+            },
+            yAxis: {
+                type: 'value',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                splitLine: {
+                    lineStyle: {
+                        color: ['#E5EAEF']
+                    }
+                },
+                axisLabel: {
+                    color: '#485465'
+                }
+            },
+            series: me.getSeries(gFields, gDatas)
+        };
+
+        return o;
+    },
+
+    getSeries: function(fields, datas) {
+        let series = [];
+
+        for(let i = fields.length - 1; i >= 0 ; i--) {
+            let s = {
+                name: fields[i],
+                type: 'line',
+                label: {
+                    normal: {
+                        show: true
+                    }
+                },
+                data: datas[i]
+            };
+            series.push(s);
+        }
+
+        return series;
+    }
+});

+ 71 - 0
frontend/pc-web/app/view/analysis/consumption/Chart2.js

@@ -0,0 +1,71 @@
+Ext.define('school.view.analysis.consumption.Chart2', {
+    extend: 'school.view.core.chart.ChartBase',
+    xtype: 'consumption-chart2',
+
+    title: '学生校园消费占比分析',
+
+    initComponent: function () {
+        var me = this;
+
+        Ext.apply(me, {
+            items: [{
+                xtype: 'echartsbase',
+                bind: {
+                    store: '{chart2}',
+                },
+                createOption: me.createOption.bind(me)
+            }]
+        });
+
+        me.callParent(arguments);
+    },
+
+    createOption: function (store) {
+        var me = this,
+        fields = [],
+        data = [];
+
+        store.each(function (d) {
+            var d = d.data;
+            fields.push(d.type);
+            data.push({
+                name: d.type,
+                value: d.money
+            });
+        });
+
+        o = {
+            grid: {
+                left: 0,
+                right: 0,
+                top: 60,
+                bottom: 5,
+                borderColor: '#E5EAEF',
+                containLabel: true
+            },
+            tooltip : {
+                trigger: 'item',
+                formatter: "{a} <br/>{b} : {d}%"
+            },
+            legend: {
+                data: fields
+            },
+            series : [{
+                name: '消费类别',
+                type: 'pie',
+                radius : '55%',
+                // center: ['40%', '50%'],
+                data: data,
+                itemStyle: {
+                    emphasis: {
+                        shadowBlur: 10,
+                        shadowOffsetX: 0,
+                        shadowColor: 'rgba(0, 0, 0, 0.5)'
+                    }
+                }
+            }]
+        };
+
+        return o;
+    }
+});

+ 23 - 0
frontend/pc-web/app/view/analysis/consumption/Panel.js

@@ -0,0 +1,23 @@
+/**
+ * 成绩分析
+ */
+Ext.define('school.view.analysis.consumption.Panel', {
+    extend: 'Ext.panel.Panel',
+    xtype: 'analysis-consumption',
+
+    viewModel: 'analysis-consumption',
+
+    layout: 'responsivecolumn',
+    scrollable: true,
+
+    defaults: {
+        userCls: 'big-50 small-100',
+        padding: 10
+    },
+
+    items: [{
+        xtype: 'consumption-chart1'
+    }, {
+        xtype: 'consumption-chart2'
+    }]
+});

+ 50 - 0
frontend/pc-web/app/view/analysis/consumption/PanelModel.js

@@ -0,0 +1,50 @@
+Ext.define('school.view.analysis.consumption.PanelModel', {
+    extend: 'Ext.app.ViewModel',
+    alias: 'viewmodel.analysis-consumption',
+
+    data: {
+    },
+
+    stores: {
+        chart1: {
+            fields: ['month', 'g1', 'g2', 'g3'],
+            data: [{
+                month: '二月',
+                g1: '334.62',
+                g2: '347.98',
+                g3: '399.17'
+            }, {
+                month: '三月',
+                g1: '784.62',
+                g2: '766.23',
+                g3: '832.63'
+            }, {
+                month: '四月',
+                g1: '692.34',
+                g2: '834.63',
+                g3: '823.93'
+            }, {
+                month: '五月',
+                g1: '723.23',
+                g2: '818.03',
+                g3: '821.92'
+            }]
+        },
+        chart2: {
+            fields: ['type', 'money'],
+            data: [{
+                type: '饮食类',
+                money: 73.33
+            }, {
+                type: '学习用品类',
+                money: 14.81
+            }, {
+                type: '日常用品类',
+                money: 4.44
+            }, {
+                type: '其他',
+                money: 7.42
+            }]
+        }
+    }
+});

+ 127 - 0
frontend/pc-web/app/view/analysis/score/Chart1.js

@@ -0,0 +1,127 @@
+Ext.define('school.view.analysis.score.Chart1', {
+    extend: 'school.view.core.chart.ChartBase',
+    xtype: 'score-chart1',
+
+    title: '初三年级期中数学成绩综合统计',
+
+    initComponent: function () {
+        var me = this;
+
+        Ext.apply(me, {
+            items: [{
+                xtype: 'echartsbase',
+                bind: {
+                    store: '{chart1}',
+                },
+                createOption: me.createOption.bind(me)
+            }]
+        });
+
+        me.callParent(arguments);
+    },
+
+    createOption: function (store) {
+        var me = this,
+        fields = [],
+        lvsFields = ['优秀', '良好', '及格', '不及格'],
+        lv1 = [],
+        lv2 = [],
+        lv3 = [],
+        lv4 = [],
+        lvDatas = [],
+        o;
+
+        store.each(function (d) {
+            var d = d.data;
+            fields.push(d.class);
+            lv1.push(d.lv1);
+            lv2.push(d.lv2);
+            lv3.push(d.lv3);
+            lv4.push(d.lv4);
+        });
+
+        lvDatas.push(lv1, lv2, lv3, lv4);
+
+        o = {
+            color: [
+                '#1EC09F',
+                '#27A7FF',
+                '#4E84F5',
+                '#FDC200',
+                '#76DDFB',
+                '#FE7D6B',
+            ],
+            grid: {
+                left: 0,
+                right: 0,
+                top: 60,
+                bottom: 5,
+                borderColor: '#E5EAEF',
+                containLabel: true
+            },
+            tooltip : {
+                trigger: 'axis',
+                axisPointer : {
+                    type : 'shadow'
+                }
+            },
+            legend: {
+                data: lvsFields
+            },
+            xAxis: {
+                type: 'category',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                axisLabel: {
+                    color: '#485465',
+                    interval: 0
+                },
+                data: fields,
+            },
+            yAxis: {
+                type: 'value',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                splitLine: {
+                    lineStyle: {
+                        color: ['#E5EAEF']
+                    }
+                },
+                axisLabel: {
+                    color: '#485465'
+                }
+            },
+            series: me.getSeries(lvsFields, lvDatas)
+        };
+
+        return o;
+    },
+
+    getSeries: function(fields, datas) {
+        let series = [];
+
+        for(let i = fields.length - 1; i >= 0 ; i--) {
+            let s = {
+                name: fields[i],
+                type: 'bar',
+                stack: '总量',
+                barWidth: 50,
+                label: {
+                    normal: {
+                        show: true
+                    }
+                },
+                data: datas[i]
+            };
+            series.push(s);
+        }
+
+        return series;
+    }
+});

+ 118 - 0
frontend/pc-web/app/view/analysis/score/Chart2.js

@@ -0,0 +1,118 @@
+Ext.define('school.view.analysis.score.Chart2', {
+    extend: 'school.view.core.chart.ChartBase',
+    xtype: 'score-chart2',
+
+    title: '初三年级期中各科成绩平均分分析',
+
+    initComponent: function () {
+        var me = this;
+
+        Ext.apply(me, {
+            items: [{
+                xtype: 'echartsbase',
+                bind: {
+                    store: '{chart2}',
+                },
+                createOption: me.createOption.bind(me)
+            }]
+        });
+
+        me.callParent(arguments);
+    },
+
+    createOption: function (store) {
+        var me = this,
+        fields = [],
+        lvsFields = ['语文', '数学', '英语'],
+        lv1 = [],
+        lv2 = [],
+        lv3 = [],
+        lvDatas = [],
+        o;
+
+        store.each(function (d) {
+            var d = d.data;
+            fields.push(d.class);
+            lv1.push(d.yuwen);
+            lv2.push(d.shuxue);
+            lv3.push(d.yingyu);
+        });
+
+        lvDatas.push(lv1, lv2, lv3);
+
+        o = {
+            color: [
+                '#FE7D6B',
+                '#4E84F5',
+                '#C2EAFC',
+                '#76DDFB'
+            ],
+            grid: {
+                left: 0,
+                right: 0,
+                top: 60,
+                bottom: 5,
+                borderColor: '#E5EAEF',
+                containLabel: true
+            },
+            tooltip : {
+                trigger: 'axis',
+                axisPointer : {
+                    type : 'shadow'
+                }
+            },
+            legend: {
+                data: lvsFields
+            },
+            xAxis: {
+                type: 'category',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                axisLabel: {
+                    color: '#485465',
+                    interval: 0
+                },
+                data: fields,
+            },
+            yAxis: {
+                type: 'value',
+                axisLine: {
+                    lineStyle: {
+                        color: '#E5EAEF',
+                    }
+                },
+                splitLine: {
+                    lineStyle: {
+                        color: ['#E5EAEF']
+                    }
+                },
+                axisLabel: {
+                    color: '#485465'
+                }
+            },
+            series: me.getSeries(lvsFields, lvDatas)
+        };
+
+        return o;
+    },
+
+    getSeries: function(fields, datas) {
+        let series = [];
+
+        for(let i = 0; i < fields.length; i++) {
+            let s = {
+                name: fields[i],
+                type: 'bar',
+                barWidth: 18,
+                barCategoryGap: 0,
+                data: datas[i]
+            };
+            series.push(s);
+        }
+
+        return series;
+    }
+});

+ 23 - 0
frontend/pc-web/app/view/analysis/score/Panel.js

@@ -0,0 +1,23 @@
+/**
+ * 成绩分析
+ */
+Ext.define('school.view.analysis.score.Panel', {
+    extend: 'Ext.panel.Panel',
+    xtype: 'analysis-score',
+
+    viewModel: 'analysis-score',
+
+    layout: 'responsivecolumn',
+    scrollable: true,
+
+    defaults: {
+        userCls: 'big-50 small-100',
+        padding: 10
+    },
+
+    items: [{
+        xtype: 'score-chart1'
+    }, {
+        xtype: 'score-chart2'
+    }]
+});

+ 63 - 0
frontend/pc-web/app/view/analysis/score/PanelModel.js

@@ -0,0 +1,63 @@
+Ext.define('school.view.analysis.score.PanelModel', {
+    extend: 'Ext.app.ViewModel',
+    alias: 'viewmodel.analysis-score',
+
+    data: {
+    },
+
+    stores: {
+        chart1: {
+            // lv1-4: 优秀、良好、及格、不及格
+            fields: ['class', 'lv1', 'lv2', 'lv3', 'lv4'],
+            data: [{
+                class: '一班',
+                lv1: '16',
+                lv2: '22',
+                lv3: '25',
+                lv4: '36'
+            }, {
+                class: '二班',
+                lv1: '8',
+                lv2: '16',
+                lv3: '43',
+                lv4: '29'
+            }, {
+                class: '三班',
+                lv1: '18',
+                lv2: '13',
+                lv3: '28',
+                lv4: '39'
+            }, {
+                class: '四班',
+                lv1: '15',
+                lv2: '16',
+                lv3: '32',
+                lv4: '35'
+            }]
+        },
+        chart2: {
+            fields: ['class', 'yuwen', 'shuxue', 'yingyu'],
+            data: [{
+                class: '一班',
+                yuwen: '84.91',
+                shuxue: '76.50',
+                yingyu: '83.01'
+            }, {
+                class: '二班',
+                yuwen: '82.34',
+                shuxue: '73.41',
+                yingyu: '85.33'
+            }, {
+                class: '三班',
+                yuwen: '75.77',
+                shuxue: '76.98',
+                yingyu: '79.46'
+            }, {
+                class: '四班',
+                yuwen: '78.01',
+                shuxue: '72.65',
+                yingyu: '74.32'
+            }]
+        }
+    }
+});

+ 1 - 1
frontend/pc-web/app/view/auth/Login.scss

@@ -21,7 +21,7 @@ $social-weixin-btn-background: dynamic(#00d500);
         .auth-title {
             text-align: center;
             img {
-              height: 58px;
+              height: 40px;
             }
         }
     }

+ 2 - 0
frontend/pc-web/app/view/basic/class/ClassDetail.js

@@ -28,6 +28,7 @@ Ext.define('school.view.basic.class.ClassDetail', {
                 xtype: "textfield",
                 name: "clazz_name",
                 fieldLabel: "班级名称",
+                readOnly: true,
                 columnWidth: 0.5,
                 group: '班级信息',
                 allowBlank: false
@@ -40,6 +41,7 @@ Ext.define('school.view.basic.class.ClassDetail', {
                 name: 'clazz_grade',
                 fieldLabel: '所属年级',
                 columnWidth: 0.5,
+                readOnly: true,
                 group: '班级信息',
                 allowBlank: false
             }, {

+ 8 - 1
frontend/pc-web/app/view/basic/student/StudentDetail.js

@@ -177,7 +177,9 @@ Ext.define('school.view.basic.student.StudentDetail', {
                     dataIndex: 'pa_phone',
                     width: 180,
                     editor: {
-                        xtype: 'numberfield'
+                        xtype: 'numberfield',
+                        maxLength: 11,
+                        minLength: 11,
                     }
                 }, {
                     text: '关系',
@@ -193,6 +195,11 @@ Ext.define('school.view.basic.student.StudentDetail', {
                         }),
                         queryMode: 'local'
                     },
+                }, {
+                    text: '状态',
+                    dataIndex: 'parents_status',
+                    hidden: true,
+                    defaultValue: 1
                 }]
             }],
         });

+ 1 - 1
frontend/pc-web/app/view/core/base/BasePanel.js

@@ -47,7 +47,7 @@ Ext.define('school.view.core.base.BasePanel', {
                 if(!gridConfig.disableDetail && !c.listeners['click']) {
                     // c.tdCls = c.tdCls ? (c.tdCls + ' x-detail-column') : 'x-detail-column'
                     c.listeners['click'] = function(view, td, row, col, e, record, tr, eOpts, event) {
-                        school.util.BaseUtil.openTab(gridConfig.addXtype, gridConfig.addTitle + '(' + record.get(gridConfig.codeField) + ')', gridConfig.addXtype + record.get(gridConfig.idField), {
+                        school.util.BaseUtil.openTab(gridConfig.addXtype, gridConfig.addTitle + '(' + record.get(gridConfig.codeField) + ')', gridConfig.addXtype + '-' +  record.get(gridConfig.idField), {
                             initId: record.get(gridConfig.idField)
                         });
                     };

+ 10 - 7
frontend/pc-web/app/view/core/chart/ChartBase.js

@@ -1,7 +1,7 @@
 Ext.define('school.view.core.chart.ChartBase', {
     extend: 'Ext.panel.Panel',
 
-    height: 370,
+    minHeight: 370,
     bodyPadding: '16 16 16 0',
 
     layout: 'fit',
@@ -24,12 +24,7 @@ Ext.define('school.view.core.chart.ChartBase', {
         Ext.apply(me, {
             title: Ext.create('Ext.panel.Header', {
                 title: me.getTitleHtml(),
-                width: '100%',
-                // listeners: {
-                //     boxready: function() {
-                //         debugger
-                //     }
-                // }
+                width: '100%'
             }),
             cls: 'quick-graph-panel ' + (me.cls || '')
         });
@@ -37,6 +32,14 @@ Ext.define('school.view.core.chart.ChartBase', {
         me.callParent(arguments);
     },
 
+    listeners: {
+        boxready: function(p) {
+            var owner = p.ownerCt;
+            var pHeight = owner.getBox().height;
+            this.setHeight(pHeight);
+        }
+    },
+
     getTitleHtml: function() {
         var me = this,
         title = me.title || '',

+ 70 - 0
frontend/pc-web/app/view/core/form/field/ClassComboBox.js

@@ -34,4 +34,74 @@ Ext.define('school.view.core.form.field.ClassComboBox', {
         me.callParent(arguments);
     },
 
+    assertValue: function() {
+        var me = this,
+            rawValue = me.getRawValue(),
+            displayValue = me.getDisplayValue(),
+            lastRecords = me.lastSelectedRecords,
+            preventChange = false,
+            value, rec;
+ 
+        if (me.forceSelection) {
+            if (me.multiSelect) {
+                // For multiselect, check that the current displayed value matches the current 
+                // selection, if it does not then revert to the most recent selection. 
+                if (rawValue !== displayValue) {
+                    me.setRawValue(displayValue);
+                }
+            } else {
+                // For single-select, match the displayed value to a record and select it, 
+                // if it does not match a record then revert to the most recent selection. 
+                rec = me.findRecordByDisplay(rawValue);
+                if (!rec) {
+                    if (lastRecords && (!me.allowBlank || me.rawValue)) {
+                        rec = lastRecords[0];
+                    } 
+                    // if we have a custom displayTpl it's likely that findRecordByDisplay won't 
+                    // find the value based on RawValue, so we give it another try using the data 
+                    // stored in displayTplData if there is any. 
+                    else if (me.displayTplData && me.displayTplData.length) {
+                        rec = me.findRecordByValue(me.displayTplData[0][me.valueField]);
+                    }
+                } 
+                // Prevent an issue where we have duplicate display values with 
+                // different underlying values. 
+                else if (me.getDisplayValue([me.getRecordDisplayData(rec)]) === displayValue) {
+                    rec = null;
+                    preventChange = true;
+                }
+ 
+                if (rec) {
+                    me.select(rec, true);
+                    me.fireEvent('select', me, rec);
+                } else if (!preventChange) {
+                    if (lastRecords) {
+                        delete me.lastSelectedRecords;
+                    }
+                    // We need to reset any value that could have been set in the dom before or during a store load 
+                    // for remote combos.  If we don't reset this, then ComboBox#getValue() will think that the value 
+                    // has changed and will then set `undefined` as the .value for forceSelection combos.  This then 
+                    // gets changed AGAIN to `null`, which will get set into the model field for editors. This is BAD. 
+                    me.setRawValue('');
+                }
+            }
+        }
+        // we can only call getValue() in this process if forceSelection is false 
+        // otherwise it will break the grid edit on tab 
+        /**
+         * 注释掉了会二次触发select事件的代码
+         * 因为第二次触发select时通过findRecordByDisplay方法得到的record因为班级重名拿到的可能不一致了
+         * 曾尝试通过修改findRecordByDisplay方法拿到正确的record
+         * 未果
+        else if ((value = me.getValue()) && value == rawValue) {
+            rec = me.findRecordByDisplay(value);
+            if (rec && (rec !== (lastRecords && lastRecords[0]) || me.displayField !== me.valueField)) {
+                me.select(rec, true);
+                me.fireEvent('select', me, rec);
+            }
+        }
+        */
+        me.collapse();
+    },
+
 });

+ 23 - 24
frontend/pc-web/app/view/core/form/field/FileField.js

@@ -27,6 +27,9 @@ Ext.define('school.view.core.form.field.FileField', {
 		bodyStyle: 'padding:2px;background:#f7f7f7',
 		layout: 'hbox',
 		items: [{
+			xtype: 'hidden',
+			name: 'value'
+		}, {
 			xtype: 'filefield',
 			name: 'file',
 			cls:'x-form-filefield',
@@ -36,17 +39,6 @@ Ext.define('school.view.core.form.field.FileField', {
 			buttonConfig:{
 				cls:'x-filefield-button'
 			},
-			createFileInput : function() {
-	            var me = this;
-	            me.fileInputEl = me.button.el.createChild({
-	            name: me.getName(),
-	            cls: Ext.baseCSSPrefix + 'form-file-input',
-	            tag: 'input',
-	            type: 'file',
-	            multiple:'multiple',
-	            size: 1
-	           }).on('change', me.onFileChange, me);
-	        },
 			listeners: {
 				change: function(field){
 					if(!!field.value){
@@ -58,12 +50,23 @@ Ext.define('school.view.core.form.field.FileField', {
 	}],
 	setValue: function(value){
 		this.value = value;
-		this.dirty = true;
+		this.getValueField().setValue(value);
 		this.publishState('value', value);
 	},
-	getValue: function (){
-		return this.down('hidden').value;
-	},
+	getValue: function() {
+        return this.getValueField().value;
+    },
+
+    getValueField: function () {
+        return this.items.items[0].items.items[0];
+    },
+
+    isValid: function () {
+        return this.getValueField().isValid();
+    },
+    isDirty: function () {
+        return this.getValueField().isDirty();
+    },
 	renderMF: function(f){
 		f.setHtml(null);
 		var form = f.ownerCt;			
@@ -121,13 +124,15 @@ Ext.define('school.view.core.form.field.FileField', {
 						});
 						me.add(field);
 						var oldValue = me.value;
-						var arr = oldValue ? oldValue.replace(/[ \[ | \] ]/g, '').split(',') : [];
+						var arr = oldValue ? oldValue.replace(/[ \[ | \" | \" | \] ]/g, '').split(',') : [];
 						arr.push(data.accessPath);
-						var val = '[' + arr.join(',') + ']';
+						var val = '["' + arr.join(',') + '"]';
 						me.setValue(val);
 					}
+					field.reset();
 				}else{
 					school.util.BaseUtil.showErrorToast('上传失败: ' + res.message);
+					field.reset();
 				}
 			},
 			failure: function (response, opts) {
@@ -150,7 +155,7 @@ Ext.define('school.view.core.form.field.FileField', {
 			url : '/api/file/info',
 			async: false,
 			params: {
-				accessPath:  paths.replace(/[ \[ | \] ]/g, '')
+				accessPath:  paths.replace(/[ \[ | \" | \" | \] ]/g, '')
 			},
 			method : 'GET',
 			callback : function(options,success,response){
@@ -226,11 +231,5 @@ Ext.define('school.view.core.form.field.FileField', {
 		var arr=['php','php2','php3', 'php5', 'phtml', 'asp', 'aspx', 'ascx', 'jsp', 'cfm', 'cfc', 'pl','pl','bat',  'dll', 'reg', 'cgi','war'];
 	    var suffix=fileName.substring(fileName.lastIndexOf(".")+1);
 	    return Ext.Array.contains(arr,suffix);
-	},
-	isValid:function(){
-		return true;
-	},
-	isDirty:function(){
-		return this.dirty;
 	}
 });

+ 8 - 1
frontend/pc-web/app/view/core/form/field/RemoteImgField.js

@@ -116,8 +116,14 @@ Ext.define('school.view.core.form.field.RemoteImgField', {
         return this.getValueField().isDirty();
     },
 
-    setReadOnly: function () {
+    setReadOnly: function (val) {
+        var me = this,
+        items = me.items.items,
+        imgPath = items[0],
+        fileField = items[2];
 
+        imgPath.setReadOnly(val);
+        fileField.button.setDisabled(val);
     },
 
     /**
@@ -192,6 +198,7 @@ Ext.define('school.view.core.form.field.RemoteImgField', {
             if(yes == 'yes') {
                 imgPath.setValue(null);
                 img.setSrc(null);
+                fileField.reset();
                 fileField.setHidden(false);
                 img.setHidden(true);
         

+ 3 - 0
frontend/pc-web/app/view/core/form/field/dbfind/Trigger.js

@@ -196,6 +196,9 @@ Ext.define('school.view.core.form.field.dbfind.Trigger', {
             var me = f;
             var dbfinds = me.dbfinds,
                 data;
+            if(!me.strict) {
+                return;
+            }
             if (f.value && f.value != '') {
                 //添加默认条件
                 var searchField = null;

+ 4 - 0
frontend/pc-web/app/view/main/Main.js

@@ -70,6 +70,10 @@ Ext.define('school.view.main.Main', {
                     menu: {
                         cls:'x-main-menu2 sa-nav-menu', 
                         items: [{
+                            text: '修改密码',
+                            iconCls: 'x-fa fa-edit sa-navicon',
+                            handler: 'onResetPassword'
+                        }, {
                             text: '退出',
                             iconCls:'x-fa fa-power-off sa-navicon',
                             handler: 'onLogout'

+ 74 - 0
frontend/pc-web/app/view/main/MainController.js

@@ -58,6 +58,80 @@ Ext.define('school.view.main.MainController', {
         Ext.resumeLayouts(true);
     },
 
+    onResetPassword: function() {
+        var win = Ext.getCmp('resetpassword');
+        if(!win) {
+            win = Ext.create('Ext.window.Window', {
+                title: '修改密码',
+                width: 400,
+                height: 260,
+                padding: 20,
+                modal: true,
+                items: [{
+                    xtype: 'form',
+                    items: [{
+                        xtype: 'textfield',
+                        cls: 'auth-textbox',
+                        fieldLabel: '新密码',
+                        emptyText: '请输入新密码',
+                        inputType: 'password',
+                        name: 'password1',
+                        allowBlank : false,
+                        listeners: {
+                            change: function(field) {
+                                var form = field.up('form'),
+                                field2 = form.getForm().findField('password2');
+
+                                field2.isValid();
+                            }
+                        }
+                    }, {
+                        xtype: 'textfield',
+                        cls: 'auth-textbox',
+                        fieldLabel: '新密码确认',
+                        emptyText: '请再次输入新密码',
+                        inputType: 'password',
+                        name: 'password2',
+                        allowBlank : false,
+                        validator: function (val) {
+                            var field = this,
+                            form = field.up('form'),
+                            field1 = form.getForm().findField('password1'),
+                            value1 = field1.getValue();
+
+                            var errMsg = "两次输入密码不一致";
+                            return (value1 == val) ? true : errMsg;
+                        }
+                    }],
+                    bbar: ['->', {
+                        xtype: 'button',
+                        text: '确认修改',
+                        formBind: true,
+                        handler: function(btn) {
+                            var window = btn.up('window'),
+                            form = window.down('form'),
+                            values = form.getValues(),
+                            userId = school.util.BaseUtil.getCurrentUser().id;
+    
+                            window.setLoading(true);
+                            school.util.BaseUtil.request({
+                                url: '/api/account/account/password/reset?password=' + values.password1 + '&userId=' + userId,
+                                method: 'POST',
+                            }).then(function(res) {
+                                window.setLoading(false);
+                                school.util.BaseUtil.showSuccessToast('修改密码成功');
+                            }).catch(function(e) {
+                                window.setLoading(false);
+                                school.util.BaseUtil.showErrorToast('修改密码失败: ' + e.message);
+                            });
+                        }
+                    }, '->']
+                }]
+            });
+        }
+        win.show();
+    },
+
     onLogout: function() {
         this.fireEvent('logout');
     }

+ 2 - 1
frontend/pc-web/ext/packages/modern-locale/overrides/zh_CN/field/Text.js

@@ -5,7 +5,8 @@
 Ext.define('Ext.locale.zh_CN.field.Text', {
     override: 'Ext.form.field.Text',
 
-    maxLengthText: '字段长度不能超过 {0}个字符',
+    maxLengthText: '字段长度不能大于 {0}个字符',
+    minLengthText: '字段长度不能小于 {0}个字符',
 
     config: {
         requiredMessage: '必填项',

二進制
frontend/pc-web/packages/font-school/resources/fonts/iconfont.eot


File diff suppressed because it is too large
+ 0 - 0
frontend/pc-web/packages/font-school/resources/fonts/iconfont.js


File diff suppressed because it is too large
+ 0 - 0
frontend/pc-web/packages/font-school/resources/fonts/iconfont.svg


二進制
frontend/pc-web/packages/font-school/resources/fonts/iconfont.ttf


二進制
frontend/pc-web/packages/font-school/resources/fonts/iconfont.woff


二進制
frontend/pc-web/packages/font-school/resources/fonts/iconfont.woff2


+ 4 - 0
frontend/pc-web/packages/font-school/sass/etc/icons.scss

@@ -22,6 +22,10 @@
   content: "\e904";
 }
 
+.ss-nav-analysis:before {
+  content: "\e642";
+}
+
 .ss-nav-info:before {
   content: "\e903";
 }

File diff suppressed because it is too large
+ 0 - 2
frontend/pc-web/packages/font-school/sass/src/all.scss


二進制
frontend/pc-web/resources/images/auth-background.jpg


+ 16 - 0
frontend/pc-web/resources/json/navigation.json

@@ -50,6 +50,22 @@
         "text": "出入校记录",
         "view": "interaction-access-list"
     }]
+}, {
+    "text": "数据分析",
+    "iconCls": "x-ss ss-nav-analysis",
+    "items": [{
+        "id": "analysis-score",
+        "text": "成绩分析",
+        "view": "analysis-score"
+    }, {
+        "id": "analysis-attence",
+        "text": "考勤分析",
+        "view": "analysis-attence"
+    }, {
+        "id": "analysis-consumption",
+        "text": "消费分析",
+        "view": "analysis-consumption"
+    }]
 }, {
     "text": "系统设置",
     "iconCls": "x-ss ss-nav-setting",

+ 5 - 0
frontend/wechat-web/src/modules/hiPages/approvel-detail/ApprovelDetail.js

@@ -179,6 +179,11 @@ class ApprovelDetail extends Component{
         if(order == 0){
             return
         }
+        if(this.state.approveOpinion.length == 0 || this.state.approveOpinion == ''){
+            this.setState({
+                approveOpinion:'-'
+            })
+        }
         let params = {
             teacherId:this.teacherId,
             approveId:this.state.approveId,

+ 1 - 1
frontend/wechat-web/src/modules/hiPages/approvel-detail/ItemApprovel.js

@@ -21,7 +21,7 @@ export default class ItemApprovel extends Component{
                     <div style={{width:10,height:10,background:'#BDBDBD',borderRadius:'30px'}}></div>
                     <div style={{marginLeft:10,width:"62%"}}>
                         <div ><span style={{color:'#000000',fontSize:15}}>{this.props.itemdata.value }</span><span style={{color:'#666666',fontSize:12,marginLeft:10}}>{this.props.approveDate}</span></div>
-                        <div style={{color:"#666666",fontSize:12,marginTop:5,wordWrap:'break-word'}}><span>{(this.props.suggest.value==null || this.props.suggest.value==undefined)?"":"(审批语:"+this.props.suggest.value+")"}</span></div>
+                        <div style={{color:"#666666",fontSize:12,marginTop:5,wordWrap:'break-word'}}><span>{(this.props.suggest.value == null || this.props.suggest.value == undefined)?"":"(审批语:"+this.props.suggest.value+")"}</span></div>
                     </div>
                     <div style={{fontSize:12,textAlign:'right'}} className={this.props.approveStatus == 1?'doing':'done'}>
                         {this.props.approveStatus == 1 ? '等待审批' : (this.props.approveStatus == 2 ? '已同意' : '已拒绝')}</div>

Some files were not shown because too many files changed in this diff