Эх сурвалжийг харах

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

chenw 7 жил өмнө
parent
commit
22e73bdc7e
27 өөрчлөгдсөн 805 нэмэгдсэн , 99 устгасан
  1. 6 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/controller/ScoreController.java
  2. 6 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/ScoreService.java
  3. 3 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/NoticeServiceImpl.java
  4. 63 4
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/business/service/impl/ScoreServiceImpl.java
  5. 2 1
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/exception/BizExceptionCode.java
  6. 33 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/interceptor/ServiceFeignInterceptor.java
  7. 14 0
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/mapper/ScoreMapper.java
  8. 11 8
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/wxschool/basic/service/impl/WxNotifyServiceImpl.java
  9. 2 2
      applications/school/school-server/src/main/java/com/usoftchina/smartschool/school/wxschool/mapper/WxNotifyrecordsMapper.java
  10. 2 2
      applications/school/school-server/src/main/resources/mapper/NotifyMapper.xml
  11. 100 0
      applications/school/school-server/src/main/resources/mapper/ScoreMapper.xml
  12. 3 5
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/controller/AccountController.java
  13. 3 2
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/AuthRestInterceptor.java
  14. 33 0
      base-servers/account/account-server/src/main/java/com/usoftchina/smartschool/account/interceptor/ServiceFeignInterceptor.java
  15. 1 1
      base-servers/account/account-server/src/main/resources/config/application-docker-cloud.yml
  16. 1 1
      base-servers/auth/auth-server/src/main/resources/config/application-docker-cloud.yml
  17. 221 0
      framework/core/src/main/java/com/netflix/hystrix/strategy/concurrency/HystrixContextScheduler.java
  18. 4 1
      frontend/pc-web/app/view/Interaction/access/List.js
  19. 63 44
      frontend/pc-web/app/view/Interaction/score/Detail.js
  20. 124 1
      frontend/pc-web/app/view/Interaction/score/DetailController.js
  21. 10 0
      frontend/pc-web/app/view/Interaction/score/DetailModel.js
  22. 1 1
      frontend/pc-web/app/view/Interaction/timetable/List.js
  23. 1 1
      frontend/pc-web/app/view/core/base/BasePanel.js
  24. 70 0
      frontend/pc-web/app/view/core/form/field/ClassComboBox.js
  25. 18 21
      frontend/pc-web/app/view/core/form/field/FileField.js
  26. 7 1
      frontend/pc-web/app/view/core/form/field/RemoteImgField.js
  27. 3 2
      frontend/pc-web/app/view/main/MainController.js

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

@@ -68,4 +68,10 @@ public class ScoreController {
         return Result.success(baseDTO);
     }
 
+    @PostMapping("/deleteDetail/{id}")
+    public Result deleteDetail(@PathVariable("id") Long id){
+        scoreService.deleteDetail(id);
+        return Result.success();
+    }
+
 }

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

@@ -26,4 +26,10 @@ public interface ScoreService {
     ScoreForm getFormdata(Long id);
 
     DocBaseDTO save(ScoreForm data);
+
+    /**
+     * 删除成绩明细
+     * @param id
+     */
+    void deleteDetail(Long id);
 }

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

@@ -148,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;
@@ -161,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());
@@ -176,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);

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

@@ -101,6 +101,7 @@ public class ScoreServiceImpl implements ScoreService{
     }
 
     @Override
+    @Transactional
     public void delete(Long id) {
         if (StringUtils.isEmpty(id) || "0".equals(id)) {
             return;
@@ -112,6 +113,7 @@ 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));
     }
 
@@ -313,6 +315,7 @@ public class ScoreServiceImpl implements ScoreService{
     }
 
     @Override
+    @Transactional
     public DocBaseDTO save(ScoreForm data) {
         if (ObjectUtils.isEmpty(data)){
             throw new BizException(BizExceptionCode.EMPTY_DATA);
@@ -321,9 +324,14 @@ public class ScoreServiceImpl implements ScoreService{
         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);
-        Long classId = sysClazz.getClazz_id();
-        Long gradeId = sysClazz.getGrade_id();
+        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());
@@ -333,7 +341,6 @@ public class ScoreServiceImpl implements ScoreService{
             main.setSi_gradeid(gradeId);
             main.setSi_classid(classId);
             scoreMapper.insertScoreImport(main);
-            Long mId = main.getSi_id();
             if (null != items && items.size() > 0) {
                 for (ScoreImportdetail item : items) {
                     if(!StringUtils.isEmpty(item.getSd_stuNumber()) && !StringUtils.isEmpty(item.getSd_stu())) {
@@ -348,17 +355,69 @@ public class ScoreServiceImpl implements ScoreService{
                             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(mId);
+                    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));
+    }
+
 }

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

@@ -17,7 +17,8 @@ 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,"存在任课班级,无法删除"),

+ 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);
 }

+ 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);
 }

+ 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>

+ 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>

+ 3 - 5
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,12 +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(BaseContextHolder.getUserId());
+        account.setId(userId);
         account.setUser_pass(accountService.getEncryptedPassword(password, account.getSalt()));
         accountService.updateByPrimaryKeySelective(account);
         return Result.success();

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

@@ -32,14 +32,15 @@ public class AuthRestInterceptor extends HandlerInterceptorAdapter {
                 token = headers.nextElement();
             }
             if (!StringUtils.isEmpty(token)) {
-                JwtInfo infoFromToken = JwtHelper.getInfoFromToken(token, "auth/pub.key");
+                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());
+                        infoFromToken.getSchool_id(), token, infoFromToken.getUserName());*/
             }
         } else {
             // no mapping

+ 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;
+    }*/
+}

+ 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:

+ 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();
+        }
+    }
+
+}

+ 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',

+ 63 - 44
frontend/pc-web/app/view/Interaction/score/Detail.js

@@ -31,19 +31,61 @@ Ext.define('school.view.interaction.score.Detail', {
             }, {
                 xtype: 'datefield',
                 name: 'si_examdate',
-                fieldLabel: '考试时间'
+                fieldLabel: '考试时间',
+                allowBlank: false
             }, {
                 xtype: 'textfield',
                 name: 'si_examscope',
                 fieldLabel: '考试范围'
             }, {
+            //     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,10 +104,11 @@ 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: {},
@@ -75,54 +118,22 @@ Ext.define('school.view.interaction.score.Detail', {
                     hidden: true
                 }, {
                     text: '学生编号',
-                    dataIndex: 'sd_stuNumber'
+                    dataIndex: 'sd_stuNumber',
+                    allowBlank: false,
+                    editor: {
+                        xtype: 'textfield'
+                    }
                 }, {
                     text: '姓名',
                     dataIndex: 'sd_stu',
+                    allowBlank: false,
                     editor: {
-                        addTitle: '学生',
                         xtype: 'dbfindtrigger',
-                        //数据接口
-                        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
-                        }]
                     }
                 }, {
                     text: '科目',
                     dataIndex: 'sd_subject',
+                    allowBlank: false,
                     editor: {
                         xtype: 'subjectcombo',
                         valueField: 'subject_name',
@@ -131,6 +142,7 @@ Ext.define('school.view.interaction.score.Detail', {
                 }, {
                     text: '成绩',
                     dataIndex: 'sd_score',
+                    allowBlank: false,
                     editor: {
                         xtype: 'numberfield',
                         minValue: 0
@@ -150,6 +162,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',

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

@@ -2,6 +2,90 @@ 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,
+        form = me.getView(),
+        formItems = form.formItems,
+        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 +120,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);
+    },
 });

+ 10 - 0
frontend/pc-web/app/view/Interaction/score/DetailModel.js

@@ -10,4 +10,14 @@ Ext.define('school.view.interaction.score.DetailModel', {
         showDeleteBtn: true,
         showLogBtn: false
     },
+
+    formulas: {
+        si_publish_change: {
+            bind: '{si_publish}',
+            get: function(v) {
+                let view = this.getView();
+                view.setEditable(v != 1);
+            }
+        }
+    }
 });

+ 1 - 1
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',

+ 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)
                         });
                     };

+ 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();
+    },
+
 });

+ 18 - 21
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;			
@@ -228,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;
 	}
 });

+ 7 - 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);
     },
 
     /**

+ 3 - 2
frontend/pc-web/app/view/main/MainController.js

@@ -110,11 +110,12 @@ Ext.define('school.view.main.MainController', {
                         handler: function(btn) {
                             var window = btn.up('window'),
                             form = window.down('form'),
-                            values = form.getValues();
+                            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,
+                                url: '/api/account/account/password/reset?password=' + values.password1 + '&userId=' + userId,
                                 method: 'POST',
                             }).then(function(res) {
                                 window.setLoading(false);