xiatian 3 anni fa
parent
commit
9480ffffd4

+ 67 - 16
examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/core/questions/api/controller/CoursePropertyController.java

@@ -1,49 +1,70 @@
 package cn.com.qmth.examcloud.core.questions.api.controller;
 
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.constraints.NotNull;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.google.common.collect.Maps;
+
 import cn.com.qmth.examcloud.api.commons.enums.DataRuleType;
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
 import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
 import cn.com.qmth.examcloud.core.questions.base.Constants;
+import cn.com.qmth.examcloud.core.questions.base.excel.ExportUtils;
 import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
 import cn.com.qmth.examcloud.core.questions.dao.entity.dto.CoursePropertyDto;
 import cn.com.qmth.examcloud.core.questions.service.CoursePropertyService;
+import cn.com.qmth.examcloud.core.questions.service.bean.CoursePropertyImportInfo;
 import cn.com.qmth.examcloud.web.security.DataRule;
 import cn.com.qmth.examcloud.web.support.ControllerSupport;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * @author weiwenhai
  * @describle 课程属性
  * @date 2017.11.2
  */
-@Controller
+@RestController
 @RequestMapping("${api_cqb}/")
 public class CoursePropertyController extends ControllerSupport {
 
     @Autowired
     private CoursePropertyService coursePropertyService;
 
+    @DataRule(type = DataRuleType.COURSE)
     @ApiOperation(value = "根据orgId查询所有课程属性")
     @GetMapping(value = "/courseProperty/all")
     public ResponseEntity<Object> findAllByOrg() {
         User user = getAccessUser();
-        if (user == null) {
-            throw new StatusException(Constants.SYS_CODE_500, "请先登录!");
-        }
+        UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
 
-        List<CourseProperty> courseProperties = coursePropertyService.findAllByOrgId(user.getRootOrgId());
+        List<CourseProperty> courseProperties = coursePropertyService.findAllByOrgId(user.getRootOrgId(),ud);
         return new ResponseEntity<>(courseProperties, HttpStatus.OK);
     }
 
@@ -166,5 +187,35 @@ public class CoursePropertyController extends ControllerSupport {
         List<CourseProperty> courseProperties = coursePropertyService.findByEnable(courseCode, true,user,ud);
         return new ResponseEntity<>(courseProperties, HttpStatus.OK);
     }
+    
+    @ApiOperation(value = "下载导入模板", notes = "下载导入模板")
+	@GetMapping("/courseProperty/importTemplate")
+	public void getImportTemplate(HttpServletResponse response) {
+		String resoucePath = PathUtil.getResoucePath("templates/coursePropertyImportTemplate.xlsx");
+		exportFile("课程属性导入模板.xlsx", new File(resoucePath));
+	}
+
+	@DataRule(type = DataRuleType.COURSE)
+	@ApiOperation(value = "导入课程属性", notes = "导入")
+	@PostMapping("/courseProperty/import")
+	public Map<String, Object> importCourseProperty(@RequestPart @NotNull(message = "上传文件不能为空!") MultipartFile file) {
+		User user = getAccessUser();
+		UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
+		List<Map<String, Object>> failRecords = coursePropertyService.importCourseProperty(ud, user, getRootOrgId(), file);
+		Map<String, Object> map = Maps.newHashMap();
+		map.put("hasError", CollectionUtils.isNotEmpty(failRecords));
+		map.put("failRecords", failRecords);
+		return map;
+	}
+	
+	@DataRule(type = DataRuleType.COURSE)
+    @ApiOperation(value = "导出课程属性")
+    @RequestMapping(value = "/courseProperty/export", method = RequestMethod.GET)
+    public void exportCourseProperty(@RequestParam(required = false) String name,@RequestParam(required = false) Long courseId, HttpServletResponse response) {
+        User user = getAccessUser();
+        UserDataRule ud = getUserDataRule(DataRuleType.COURSE);
+        List<CoursePropertyImportInfo> dtos = coursePropertyService.exportCourseProperty(ud, user, name,courseId);
+        ExportUtils.exportEXCEL("课程属性", CoursePropertyImportInfo.class, dtos, response);
+    }
 
 }

+ 7 - 3
examcloud-core-questions-dao/src/main/java/cn/com/qmth/examcloud/core/questions/dao/CoursePropertyRepo.java

@@ -5,6 +5,7 @@ import org.springframework.data.mongodb.repository.MongoRepository;
 import org.springframework.data.repository.query.QueryByExampleExecutor;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author weiwenhai
@@ -13,9 +14,6 @@ import java.util.List;
  */
 public interface CoursePropertyRepo extends MongoRepository<CourseProperty, String>, QueryByExampleExecutor<CourseProperty> {
 
-    //查询所有课程属性
-    List<CourseProperty> findByOrgId(Long orgId);
-
     //根据属性名查询
     CourseProperty findByOrgIdAndName(Long orgId, String name);
 
@@ -33,4 +31,10 @@ public interface CoursePropertyRepo extends MongoRepository<CourseProperty, Stri
     //根据id集合查询
     List<CourseProperty> findByIdIn(List<String> ids);
 
+	CourseProperty findByOrgIdAndCourseIdAndName(Long rootOrgId, Long courseId, String propertyName);
+
+	List<CourseProperty> findByOrgIdAndCourseIdIn(Long orgId, Set<Long> refIds);
+
+	List<CourseProperty> findByOrgId(Long orgId);
+
 }

+ 2 - 0
examcloud-core-questions-dao/src/main/java/cn/com/qmth/examcloud/core/questions/dao/PropertyRepo.java

@@ -22,4 +22,6 @@ public interface PropertyRepo extends MongoRepository<Property, String>, QueryBy
 	//根据课程属性id,一级id,属性名称查询
     Property findByOrgIdAndCoursePropertyIdAndParentIdAndCode(Long orgId, String coursePropertyId, String parentId, String code);
 
+	List<Property> findByCoursePropertyIdOrderByNumber(String id);
+
 }

+ 15 - 5
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/CoursePropertyService.java

@@ -1,13 +1,18 @@
 package cn.com.qmth.examcloud.core.questions.service;
 
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.web.multipart.MultipartFile;
+
 import cn.com.qmth.examcloud.api.commons.security.bean.User;
 import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
 import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
 import cn.com.qmth.examcloud.core.questions.dao.entity.dto.CoursePropertyDto;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-
-import java.util.List;
+import cn.com.qmth.examcloud.core.questions.service.bean.CoursePropertyImportInfo;
+import cn.com.qmth.examcloud.core.questions.service.bean.paper.PaperAnswerDomain;
 
 /**
  * @author weiwenhai
@@ -18,8 +23,9 @@ public interface CoursePropertyService {
 
     /**
      * 查询所有课程属性
+     * @param ud 
      */
-    List<CourseProperty> findAllByOrgId(Long orgId);
+    List<CourseProperty> findAllByOrgId(Long orgId, UserDataRule ud);
 
     /**
      * 查询所有课程属性带分页
@@ -56,4 +62,8 @@ public interface CoursePropertyService {
      */
     void updateCoursePropertyStatus(String coursePropertyId, Boolean enable);
 
+	List<Map<String, Object>> importCourseProperty(UserDataRule ud, User user, Long rootOrgId, MultipartFile dataFile);
+
+	List<CoursePropertyImportInfo> exportCourseProperty(UserDataRule ud, User user, String name, Long courseId);
+
 }

+ 98 - 0
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/bean/CoursePropertyImportInfo.java

@@ -0,0 +1,98 @@
+package cn.com.qmth.examcloud.core.questions.service.bean;
+
+import cn.com.qmth.examcloud.core.questions.base.excel.ExcelProperty;
+
+public class CoursePropertyImportInfo {
+
+	@ExcelProperty(name = "课程代码", width = 30, index = 1)
+	private String courseCode;
+	
+	@ExcelProperty(name = "课程名称", width = 30, index = 2)
+	private String courseName;
+	
+	private Long courseId;
+	
+	@ExcelProperty(name = "属性名称", width = 30, index = 3)
+	private String propertyName;
+	
+	@ExcelProperty(name = "一级属性编号", width = 30, index = 4)
+	private String firstPropertyCode;
+	
+	@ExcelProperty(name = "一级属性内容", width = 30, index = 5)
+	private String firstPropertyName;
+	
+	@ExcelProperty(name = "二级属性编号", width = 30, index = 6)
+	private String secondPropertyCode;
+	
+	@ExcelProperty(name = "二级属性内容", width = 30, index = 7)
+	private String secondPropertyName;
+
+	
+
+	public Long getCourseId() {
+		return courseId;
+	}
+
+	public void setCourseId(Long courseId) {
+		this.courseId = courseId;
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+
+	public void setPropertyName(String propertyName) {
+		this.propertyName = propertyName;
+	}
+
+	public String getFirstPropertyCode() {
+		return firstPropertyCode;
+	}
+
+	public void setFirstPropertyCode(String firstPropertyCode) {
+		this.firstPropertyCode = firstPropertyCode;
+	}
+
+	public String getFirstPropertyName() {
+		return firstPropertyName;
+	}
+
+	public void setFirstPropertyName(String firstPropertyName) {
+		this.firstPropertyName = firstPropertyName;
+	}
+
+	public String getSecondPropertyCode() {
+		return secondPropertyCode;
+	}
+
+	public void setSecondPropertyCode(String secondPropertyCode) {
+		this.secondPropertyCode = secondPropertyCode;
+	}
+
+	public String getSecondPropertyName() {
+		return secondPropertyName;
+	}
+
+	public void setSecondPropertyName(String secondPropertyName) {
+		this.secondPropertyName = secondPropertyName;
+	}
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+	public String getCourseName() {
+		return courseName;
+	}
+
+	public void setCourseName(String courseName) {
+		this.courseName = courseName;
+	}
+	
+	
+	
+}

+ 408 - 16
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/CoursePropertyServiceImpl.java

@@ -1,16 +1,14 @@
 package cn.com.qmth.examcloud.core.questions.service.impl;
 
-import cn.com.qmth.examcloud.api.commons.security.bean.User;
-import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
-import cn.com.qmth.examcloud.commons.exception.StatusException;
-import cn.com.qmth.examcloud.core.questions.base.Constants;
-import cn.com.qmth.examcloud.core.questions.base.Model;
-import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
-import cn.com.qmth.examcloud.core.questions.dao.entity.dto.CoursePropertyDto;
-import cn.com.qmth.examcloud.core.questions.service.CoursePropertyService;
-import cn.com.qmth.examcloud.support.cache.CacheHelper;
-import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,10 +20,38 @@ import org.springframework.data.mongodb.core.MongoTemplate;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.web.multipart.MultipartFile;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.examcloud.api.commons.security.bean.User;
+import cn.com.qmth.examcloud.api.commons.security.bean.UserDataRule;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.helpers.poi.ExcelReader;
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLog;
+import cn.com.qmth.examcloud.commons.logging.ExamCloudLogFactory;
+import cn.com.qmth.examcloud.commons.util.PathUtil;
+import cn.com.qmth.examcloud.core.basic.api.CourseCloudService;
+import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
+import cn.com.qmth.examcloud.core.basic.api.request.GetCourseReq;
+import cn.com.qmth.examcloud.core.basic.api.response.GetCourseResp;
+import cn.com.qmth.examcloud.core.questions.base.Constants;
+import cn.com.qmth.examcloud.core.questions.base.Model;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
+import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
+import cn.com.qmth.examcloud.core.questions.dao.PropertyRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Course;
+import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Property;
+import cn.com.qmth.examcloud.core.questions.dao.entity.dto.CoursePropertyDto;
+import cn.com.qmth.examcloud.core.questions.service.CoursePropertyService;
+import cn.com.qmth.examcloud.core.questions.service.bean.CoursePropertyImportInfo;
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
+import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
+import cn.com.qmth.examcloud.web.config.SystemProperties;
 
 /**
  * @author weiwenhai
@@ -34,16 +60,36 @@ import java.util.List;
  */
 @Service("coursePropertyService")
 public class CoursePropertyServiceImpl implements CoursePropertyService {
+	private static final ExamCloudLog log = ExamCloudLogFactory.getLog(CoursePropertyService.class);
+	
+	private static final String[] EXCEL_HEADER = new String[] { "课程代码", "课程名称", "属性名称", "一级属性编号", "一级属性内容", "二级属性编号",
+	"二级属性内容" };
 
     @Autowired
     private CoursePropertyRepo coursePropertyRepo;
+    
+	@Autowired
+	private PropertyRepo propertyRepo;
+    
+    @Autowired
+    private CourseCloudService courseCloudService;
 
     @Autowired
     private MongoTemplate mongoTemplate;
+    
+    @Autowired
+    private SystemProperties systemProperties;
 
     @Override
-    public List<CourseProperty> findAllByOrgId(Long orgId) {
-        return coursePropertyRepo.findByOrgId(orgId);
+    public List<CourseProperty> findAllByOrgId(Long orgId,UserDataRule ud) {
+    	if (ud.assertEmptyQueryResult()) {
+            return Lists.newArrayList();
+        }
+    	if (ud.assertNeedQueryRefIds()) {
+    		return coursePropertyRepo.findByOrgIdAndCourseIdIn(orgId,ud.getRefIds());
+    	}else {
+    		return coursePropertyRepo.findByOrgId(orgId);
+    	}
     }
 
     @Override
@@ -193,5 +239,351 @@ public class CoursePropertyServiceImpl implements CoursePropertyService {
         courseProperty.setUpdateTime(new Date());
         coursePropertyRepo.save(courseProperty);
     }
+    
+    @Transactional
+	@Override
+	public List<Map<String, Object>> importCourseProperty(UserDataRule ud, User user, Long rootOrgId, MultipartFile dataFile) {
+    	File file = new File(systemProperties.getTempDataDir() + File.separator + UUID.randomUUID() + ".xlsx");
+        try {
+            file.createNewFile();
+            dataFile.transferTo(file);
+            return disposeImportCourseProperty(ud, user, rootOrgId, file);
+        } catch (Exception e) {
+            throw new StatusException("500", "导入课程属性失败:" + e.getMessage(), e);
+        } finally {
+            FileUtil.deleteFile(file.getAbsolutePath());
+        }
+    }
+    
+	private List<Map<String, Object>> disposeImportCourseProperty(UserDataRule ud, User user, Long rootOrgId, File file) {
+		List<String[]> lineList = null;
+		try {
+			lineList = ExcelReader.readSheetBySax(PathUtil.getCanonicalPath(file), 1, 7);
+		} catch (Exception e) {
+			throw new StatusException("100110", "Excel 解析失败",e );
+		}
+
+		if (CollectionUtils.isEmpty(lineList)) {
+			throw new StatusException("100111", "Excel无内容");
+		}
+
+		if (10001 < lineList.size()) {
+			throw new StatusException("100112", "数据行数不能超过10000");
+		}
+
+		List<Map<String, Object>> failRecords = Collections.synchronizedList(new ArrayList<Map<String, Object>>());
+
+		List<CoursePropertyImportInfo> courseList = Lists.newArrayList();
+		Map<String, Course> cousreMap = new HashMap<>();
+		for (int i = 0; i < lineList.size(); i++) {
+			String[] line = lineList.get(i);
+			if (0 == i) {
+				if (headerError(line)) {
+					throw new StatusException("100111", "Excel表头错误");
+				}
+				continue;
+			}
+
+			boolean hasError = false;
+			StringBuilder msg = new StringBuilder();
+
+			CoursePropertyImportInfo courseInfo = new CoursePropertyImportInfo();
+
+			String courseCode = trimAndNullIfBlank(line[0]);
+			if (StringUtils.isBlank(courseCode)) {
+				msg.append("  课程代码不能为空");
+				hasError = true;
+			} else if (!checkCourseExist(cousreMap, courseCode, rootOrgId)) {
+				msg.append("  课程代码不存在");
+				hasError = true;
+			} else if ("false".equals(cousreMap.get(courseCode).getEnable())) {
+				msg.append("  课程已禁用");
+				hasError = true;
+			}
+			
+			courseInfo.setCourseCode(courseCode);
+			
+			if(cousreMap.get(courseCode)!=null) {
+				courseInfo.setCourseId(Long.valueOf(cousreMap.get(courseCode).getId()));
+			}
+
+			String propertyName = trimAndNullIfBlank(line[2]);
+			if (StringUtils.isBlank(propertyName)) {
+				msg.append("  属性名称不能为空");
+				hasError = true;
+			} else if (propertyName.length() > 100) {
+				msg.append("  属性名称不能超过100个字符");
+				hasError = true;
+			}
+			courseInfo.setPropertyName(propertyName);
+
+			String firstCode = trimAndNullIfBlank(line[3]);
+			if (StringUtils.isBlank(firstCode)) {
+				msg.append("  一级属性编号不能为空");
+				hasError = true;
+			} else if (firstCode.length() > 100) {
+				msg.append("  一级属性编号不能超过100个字符");
+				hasError = true;
+			}
+			courseInfo.setFirstPropertyCode(firstCode);
+
+			String firstName = trimAndNullIfBlank(line[4]);
+			if (StringUtils.isNotBlank(firstName) && firstName.length() > 100) {
+				msg.append("  一级属性内容不能超过100个字符");
+				hasError = true;
+			}
+			courseInfo.setFirstPropertyName(firstName);
+
+			String secCode = trimAndNullIfBlank(line[5]);
+			if (StringUtils.isNotBlank(secCode) && secCode.length() > 100) {
+				msg.append("  二级属性编号不能超过100个字符");
+				hasError = true;
+			}
+			courseInfo.setSecondPropertyCode(secCode);
+
+			String secName = trimAndNullIfBlank(line[6]);
+			if (StringUtils.isNotBlank(secName) && secName.length() > 100) {
+				msg.append("  二级属性内容不能超过100个字符");
+				hasError = true;
+			}
+			courseInfo.setSecondPropertyName(secName);
+
+			if (hasError) {
+				failRecords.add(newError(i + 1, msg.toString()));
+			} else {
+				courseList.add(courseInfo);
+			}
+
+		}
+
+		if (CollectionUtils.isNotEmpty(failRecords)) {
+			return failRecords;
+		}
+
+		for (int i = 0; i < courseList.size(); i++) {
+			CoursePropertyImportInfo cur = courseList.get(i);
+			try {
+				saveCoursePropertyInfo(user, ud, cur);
+			} catch (StatusException e) {
+				failRecords.add(newError(i + 2, e.getDesc()));
+			} catch (Exception e) {
+				failRecords.add(newError(i + 2, "系统异常"));
+				log.error("课程属性导入系统异常", e);
+			}
+		}
+		if (CollectionUtils.isNotEmpty(failRecords)) {
+			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+		}
+
+		return failRecords;
+	}
+
+	private void saveCoursePropertyInfo(User user, UserDataRule ud, CoursePropertyImportInfo cur) {
+		if(ud.assertEmptyQueryResult()) {
+			throw new StatusException(" 课程不在该账号负责的课程中");
+		}
+		if (ud.assertNeedQueryRefIds() && !ud.getRefIds().contains(cur.getCourseId())) {
+			throw new StatusException(" 课程不在该账号负责的课程中");
+		}
+		CourseProperty c = coursePropertyRepo.findByOrgIdAndCourseIdAndName(user.getRootOrgId(),cur.getCourseId(), cur.getPropertyName());
+		if(c==null) {
+			c=new CourseProperty();
+			c.setCourseId(cur.getCourseId());
+			c.setCourseCode(cur.getCourseCode());
+			c.setName(cur.getPropertyName());
+			c.setOrgId(user.getRootOrgId());
+			c.setEnable(true);
+			coursePropertyRepo.save(c);
+		}
+		
+		Property first=propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdAndCode(user.getRootOrgId(), c.getId(), Property.ROOT_PARENT_ID, cur.getFirstPropertyCode());
+		if(first!=null) {
+			first.setName(cur.getFirstPropertyName());
+		}else {
+			if(StringUtils.isBlank(cur.getFirstPropertyName())) {
+				throw new StatusException(" 一级属性内容不能为空");
+			}
+			first=new Property();
+			first.setParentId(Property.ROOT_PARENT_ID);
+			first.setOrgId(user.getRootOrgId());
+			first.setCoursePropertyId(c.getId());
+			first.setCode(cur.getFirstPropertyCode());
+			first.setName(cur.getFirstPropertyName());
+			Integer number = 0;
+            List<Property> parentProperties = propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdOrderByNumber(first.getOrgId(), first.getCoursePropertyId(), first.getParentId());
+            if (parentProperties != null && parentProperties.size() > 0) {
+                number = parentProperties.get(parentProperties.size() - 1).getNumber();
+            }
+
+            first.setNumber(number + 1);
+		}
+		propertyRepo.save(first);
+		
+		if(StringUtils.isNotBlank(cur.getSecondPropertyCode())&&StringUtils.isBlank(cur.getSecondPropertyName())) {
+			throw new StatusException(" 二级属性内容不能为空");
+		}
+		if(StringUtils.isNotBlank(cur.getSecondPropertyCode())){
+			Property sec=propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdAndCode(user.getRootOrgId(), c.getId(), first.getId(), cur.getSecondPropertyCode());
+			if(sec!=null) {
+				sec.setName(cur.getSecondPropertyName());
+			}else {
+				sec=new Property();
+				sec.setParentId(first.getId());
+				sec.setOrgId(user.getRootOrgId());
+				sec.setCoursePropertyId(c.getId());
+				sec.setCode(cur.getSecondPropertyCode());
+				sec.setName(cur.getSecondPropertyName());
+				Integer number = 0;
+	            List<Property> parentProperties = propertyRepo.findByOrgIdAndCoursePropertyIdAndParentIdOrderByNumber(sec.getOrgId(), sec.getCoursePropertyId(), sec.getParentId());
+	            if (parentProperties != null && parentProperties.size() > 0) {
+	                number = parentProperties.get(parentProperties.size() - 1).getNumber();
+	            }
+
+	            sec.setNumber(number + 1);
+			}
+			propertyRepo.save(sec);
+		}
+		
+	}
+
+	private boolean checkCourseExist(Map<String, Course> cousre, String courseCode, Long rootOrgId) {
+		if (cousre.get(courseCode) != null) {
+			return true;
+		}
+		GetCourseReq req=new GetCourseReq();
+		req.setRootOrgId(rootOrgId);
+		req.setCode(courseCode);
+		GetCourseResp res=courseCloudService.getCourse(req);
+		if (res.getCourseBean() == null) {
+			return false;
+		} else {
+			cousre.put(courseCode, of(res.getCourseBean()));
+			return true;
+		}
+	}
+	
+	private Course of(CourseBean b) {
+		Course c=new Course();
+		c.setCode(b.getCode());
+		c.setEnable(b.getEnable()!=null?null:b.getEnable().toString());
+		c.setId(b.getId()+"");
+		c.setLevel(b.getLevel());
+		c.setName(b.getName());
+		c.setOrgId(b.getRootOrgId()+"");
+		return c;
+	}
+
+	private Map<String, Object> newError(int lineNum, String msg) {
+		Map<String, Object> map = Maps.newHashMap();
+		map.put("lineNum", lineNum);
+		map.put("msg", msg);
+		return map;
+	}
+
+	private String trimAndNullIfBlank(String s) {
+		if (StringUtils.isBlank(s)) {
+			return null;
+		}
+		return s.trim();
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @param header
+	 * @author WANGWEI
+	 */
+	private boolean headerError(String[] header) {
+		for (int i = 0; i < EXCEL_HEADER.length; i++) {
+			if (null == header[i]) {
+				return true;
+			}
+			if (!EXCEL_HEADER[i].equals(header[i].trim())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public List<CoursePropertyImportInfo> exportCourseProperty(UserDataRule userDataRule, User user, String name, Long courseId) {
+		if (userDataRule.assertEmptyQueryResult()) {
+            return Lists.newArrayList();
+        }
+
+        Query query = new Query();
+
+        query.addCriteria(Criteria.where("orgId").is(user.getRootOrgId()));
+
+        if (courseId != null) {
+            if (!userDataRule.getRefIds().contains(courseId)) {
+                return Lists.newArrayList();
+            }
+            query.addCriteria(Criteria.where("courseId").is(courseId));
+        } else {
+            if (userDataRule.assertNeedQueryRefIds()) {
+                query.addCriteria(Criteria.where("courseId").in(userDataRule.getRefIds()));
+            }
+        }
+
+        if (StringUtils.isNotBlank(name)) {
+            query.addCriteria(Criteria.where("name").regex(name.trim()));
+        }
+
+
+        query.with(Sort.by(new Sort.Order(Sort.Direction.DESC, "updateTime")));
+        List<CourseProperty> coursePros = mongoTemplate.find(query, CourseProperty.class);
+
+		List<CoursePropertyImportInfo> ret=new ArrayList<>();
+		if(!CollectionUtils.isEmpty(coursePros)) {
+			for(CourseProperty cp:coursePros) {
+				fillProperty(ret, cp);
+			}
+		}
+		return ret;
+	}
+	
+	private void fillProperty(List<CoursePropertyImportInfo> ret,CourseProperty cp) {
+		List<Property> ps=propertyRepo.findByCoursePropertyIdOrderByNumber(cp.getId());
+		if(!CollectionUtils.isEmpty(ps)) {
+			Map<String,List<Property>> secPs=new HashMap<>();
+			for(Property p:ps) {
+				if(!Property.ROOT_PARENT_ID.equals(p.getParentId())) {
+					List<Property> list=secPs.get(p.getParentId());
+					if(list==null) {
+						list=new ArrayList<>();
+						secPs.put(p.getParentId(), list);
+					}
+					list.add(p);
+				}
+			}
+			
+			for(Property p:ps) {
+				if(Property.ROOT_PARENT_ID.equals(p.getParentId())) {
+					CoursePropertyImportInfo info=new CoursePropertyImportInfo();
+					info.setCourseCode(cp.getCourseCode());
+					info.setCourseName(CacheHelper.getCourse(cp.getCourseId()).getName());
+					info.setPropertyName(cp.getName());
+					info.setFirstPropertyCode(p.getCode());
+					info.setFirstPropertyName(p.getName());
+					ret.add(info);
+					List<Property> secPsList=secPs.get(p.getId());
+					if(!CollectionUtils.isEmpty(secPsList)) {
+						for(Property sec:secPsList) {
+							CoursePropertyImportInfo secinfo=new CoursePropertyImportInfo();
+							secinfo.setCourseCode(cp.getCourseCode());
+							secinfo.setCourseName(CacheHelper.getCourse(cp.getCourseId()).getName());
+							secinfo.setPropertyName(cp.getName());
+							secinfo.setFirstPropertyCode(p.getCode());
+							secinfo.setFirstPropertyName(p.getName());
+							secinfo.setSecondPropertyCode(sec.getCode());
+							secinfo.setSecondPropertyName(sec.getName());
+							ret.add(secinfo);
+						}
+					}
+				}
+			}
+		}
+	}
 
 }

BIN
examcloud-core-questions-starter/src/main/resources/templates/coursePropertyImportTemplate.xlsx