lige
2024-04-18 ed277ece348dae9bc6e36c0fc9f69ae8a3825912
填鸭表单
18个文件已修改
89个文件已添加
6640 ■■■■■ 已修改文件
ltkj-admin/src/main/java/com/ltkj/web/controller/system/TjSurveyQuestionController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/controller/system/TjSurveyTemplateController.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/tduck/UserFormController.java 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/tduck/UserFormResultController.java 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/tduck/UserFormSettingController.java 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/tduck/WxJsApiController.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/resources/application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/resources/config/ehcache.xml 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-common/pom.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-common/src/main/java/com/ltkj/common/utils/http/HttpUtils.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyOptions.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyQuestion.java 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyRecord.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyTempQues.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyTemplate.java 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/mapper/TjSurveyQuestionMapper.java 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/mapper/TjSurveyTemplateMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/service/ITjSurveyQuestionService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/service/ITjSurveyTemplateService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/service/impl/TjSurveyQuestionServiceImpl.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/java/com/ltkj/hosp/service/impl/TjSurveyTemplateServiceImpl.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/resources/mapper/hosp/TjSurveyQuestionMapper.xml 273 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-hosp/src/main/resources/mapper/hosp/TjSurveyTemplateMapper.xml 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/constant/CommonConstants.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/constant/FormConstants.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/constant/FormRedisKeyConstants.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/constant/FormSettingConstants.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/constant/ResponseCodeConstants.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/FormTemplateCategoryEntity.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/FormThemeEntity.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/PageRequest.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/SysBaseEntity.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/TBaseEntity.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormDataEntity.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormEntity.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormItemEntity.java 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormLogicEntity.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormSettingEntity.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormThemeEntity.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormViewCountEntity.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/EsTypeEnum.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormItemTypeEnum.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormLogicConditionExpressionEnum.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormPermsBtnTypeEnum.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormSourceTypeEnum.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormStatusEnum.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormTypeEnum.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/enums/TimeRangeEnum.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/handler/AutoFillMetaInfoHandler.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/handler/BooleanTypeHandler.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/handler/JacksonTypeHandler.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/handler/LongToStringSerializer.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/FormTemplateCategoryMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/FormThemeMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormDataMapper.java 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormItemMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormLogicMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormSettingMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormThemeMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormViewCountMapper.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/request/CheckWritePwdRequest.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormItemRequest.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormRequest.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormResultRequest.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormTemplateTypeRequest.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/request/SortFormItemRequest.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/FormTemplateCategoryService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/FormThemeService.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormDataService.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormItemService.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormLogicService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormSettingService.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormThemeService.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormViewCountService.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/data/FormDataBaseService.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/data/FormDataMysqlService.java 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/FormTemplateCategoryServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/FormThemeServiceImpl.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormDataServiceImpl.java 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormItemServiceImpl.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormLogicServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormSettingServiceImpl.java 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormThemeServiceImpl.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormViewCountServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/struct/CheckboxSchemaStruct.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/struct/FormDataFilterStruct.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/struct/FormSettingSchemaStruct.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/struct/InputResultStruct.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/struct/OptionQuotaListStruct.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/struct/WriteSettingSchemaStruct.java 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/CacheUtils.java 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/FormDataUtils.java 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/HtmlUtils.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/IDictEnum.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/JsonUtils.java 276 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/LongToStringSerializer.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/Result.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/ShortIdUtils.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/SortUtils.java 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/utils/ValidatorUtils.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/vo/FormDataTableVO.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/vo/FormFieldVO.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/vo/OperateFormItemVO.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-system/src/main/java/com/ltkj/tduck/vo/UserFormDetailVO.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ltkj-admin/src/main/java/com/ltkj/web/controller/system/TjSurveyQuestionController.java
@@ -62,7 +62,7 @@
     */
    //@PreAuthorize("@ss.hasPermi('hosp:question:query')")
    @GetMapping(value = "/{qid}")
    public AjaxResult getInfo(@PathVariable("qid") Long qid) {
    public AjaxResult getInfo(@PathVariable("qid") String qid) {
        return success(tjSurveyQuestionService.selectTjSurveyQuestionByQid(qid));
    }
@@ -92,7 +92,7 @@
    //@PreAuthorize("@ss.hasPermi('hosp:question:remove')")
    @Log(title = "问卷问题", businessType = BusinessType.DELETE)
    @DeleteMapping("/{qids}")
    public AjaxResult remove(@PathVariable Long[] qids) {
    public AjaxResult remove(@PathVariable String[] qids) {
        return toAjax(tjSurveyQuestionService.deleteTjSurveyQuestionByQids(qids));
    }
}
ltkj-admin/src/main/java/com/ltkj/web/controller/system/TjSurveyTemplateController.java
@@ -6,11 +6,18 @@
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ltkj.hosp.domain.TjSurveyOptions;
import com.ltkj.hosp.domain.TjSurveyQuestion;
import com.ltkj.hosp.domain.TjSurveyTempQues;
import com.ltkj.hosp.service.ITjSurveyQuestionService;
import com.ltkj.system.service.ISysConfigService;
import com.ltkj.tduck.domain.UserFormEntity;
import com.ltkj.tduck.enums.FormSourceTypeEnum;
import com.ltkj.tduck.enums.FormStatusEnum;
import com.ltkj.tduck.service.UserFormService;
import com.ltkj.tduck.utils.ShortIdUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -40,6 +47,37 @@
    @Autowired
    private ITjSurveyQuestionService tjSurveyQuestionService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private UserFormService formService;
    /**
     * 判断是否开启填鸭表单设计
     */
    @ApiOperation(value = "判断是否开启填鸭表单设计")
    @GetMapping(value = "/needDesign")
    public AjaxResult needDesign() {
        final String call = configService.selectConfigByKey("need_design");
        return AjaxResult.success(call);
    }
    /**
     * 判断该模板是否可删除
     */
    @ApiOperation(value = "判断该模板是否可删除")
    @GetMapping(value = "/canDelete")
    public AjaxResult canDelete(Long id) {
//        List<FwdPlanInfoVo> fwdPlanInfoVos = fwdSqlMapper.canDelete(id);
//        if (fwdPlanInfoVos!=null && fwdPlanInfoVos.size()>0){
//            return AjaxResult.success(false);
//        }
        return AjaxResult.success(false);
    }
    /**
     * 查询问卷模板列表
@@ -73,26 +111,52 @@
        return success(tjSurveyTemplateService.selectTjSurveyTemplateByMid(mid));
    }
    /**
     * 获取问卷模板
     */
//    /**
//     * 获取问卷模板
//     */
//    @GetMapping("/getQuesByMid")
//    @ApiOperation(value = "获取问卷模板信息")
//    public AjaxResult getQuesByMid(@RequestParam Long mid) {
//        List<TjSurveyQuestion> l1=new ArrayList<>();
//        TjSurveyTemplate byId = tjSurveyTemplateService.selectTjSurveyTemplateByMid(mid);
//        List<TjSurveyTempQues> tjSurveyTempQuesList = byId.getTjSurveyTempQuesList();
//        if (tjSurveyTempQuesList!=null){
//            for (TjSurveyTempQues tjSurveyTempQues : tjSurveyTempQuesList) {
//                TjSurveyQuestion byId1 = tjSurveyQuestionService.selectTjSurveyQuestionByQid(tjSurveyTempQues.getQid());
//                if (byId1!=null){
//                    l1.add(byId1);
//                }
//            }
//            return AjaxResult.success(l1);
//        }
//        return AjaxResult.success("暂无信息");
//    }
    @GetMapping("/getQuesByMid")
    @ApiOperation(value = "获取问卷模板信息")
    public AjaxResult getQuesByMid(@RequestParam Long mid) {
        List<TjSurveyQuestion> l1=new ArrayList<>();
        TjSurveyTemplate byId = tjSurveyTemplateService.selectTjSurveyTemplateByMid(mid);
        List<TjSurveyTempQues> tjSurveyTempQuesList = byId.getTjSurveyTempQuesList();
        if (tjSurveyTempQuesList!=null){
            for (TjSurveyTempQues tjSurveyTempQues : tjSurveyTempQuesList) {
                TjSurveyQuestion byId1 = tjSurveyQuestionService.selectTjSurveyQuestionByQid(tjSurveyTempQues.getQid());
                if (byId1!=null){
                    l1.add(byId1);
        TjSurveyTemplate byId = tjSurveyTemplateService.selectTemplateByMid1(Long.valueOf(mid));
        if(null !=byId){
            if ("1".equals(byId.getQybz())){
                return AjaxResult.success("该问卷模板不存在或已停用");
                }
            //判断是否有问题
            if(byId.getDesignId()!=null){
                return AjaxResult.success(byId.getDesignId());
            }
            return AjaxResult.success(l1);
            LambdaQueryWrapper<TjSurveyQuestion> wq1=new LambdaQueryWrapper<>();
            wq1.eq(TjSurveyQuestion::getMid,byId.getMid());
            final List<TjSurveyQuestion> list1 = tjSurveyQuestionService.list(wq1);
            for (TjSurveyQuestion tjSurveyQuestion : list1) {
                final List<TjSurveyOptions> tjSurveyOptions = tjSurveyQuestionService.selectOptionsByQid(tjSurveyQuestion.getQid());
                tjSurveyQuestion.setTjSurveyOptionsList(tjSurveyOptions);
            }
            return AjaxResult.success(list1);
        }
        return AjaxResult.success("暂无信息");
    }
    /**
     * 新增问卷模板
@@ -101,7 +165,33 @@
    @Log(title = "问卷模板", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody TjSurveyTemplate tjSurveyTemplate) {
        return toAjax(tjSurveyTemplateService.insertTjSurveyTemplate(tjSurveyTemplate));
//        return toAjax(tjSurveyTemplateService.insertTjSurveyTemplate(tjSurveyTemplate));
        final String call = configService.selectConfigByKey("need_design");
        //判断是否开启填鸭表单设计
        if ("true".equals(call)){
            UserFormEntity form=new UserFormEntity();
            form.setFormKey(ShortIdUtils.genId());
            form.setName("<h2 style=\"text-align: center;\">"+tjSurveyTemplate.getTempName()+"</h2>");
            form.setStatus(1);
            form.setSourceType(1);
            form.setCreateTime(new DateTime());
            form.setType("1");
            form.setDeleted(false);
            final boolean save = formService.save(form);
            if (save){
                tjSurveyTemplate.setDesignId(form.getFormKey());
                final int i = tjSurveyTemplateService.insertTjSurveyTemplate(tjSurveyTemplate);
                if (i==1) {
                    return AjaxResult.success(form);
                }
            }
        }else{
            final int i = tjSurveyTemplateService.insertTjSurveyTemplate(tjSurveyTemplate);
            if (i==1) {
                return AjaxResult.success(false);
            }
        }
        return AjaxResult.success(false);
    }
    /**
@@ -123,4 +213,23 @@
    public AjaxResult remove(@PathVariable Long[] mids) {
        return toAjax(tjSurveyTemplateService.deleteTjSurveyTemplateByMids(mids));
    }
    /**
     * 问卷启用禁用
     */
    @GetMapping("/updateQybz")
    @ApiOperation(value = "问卷启用禁用")
    public AjaxResult updateQybz(@RequestParam Long mid,@RequestParam String qybz) {
        final TjSurveyTemplate byId = tjSurveyTemplateService.selectTemplateByMid1(mid);
        byId.setQybz(qybz);
        if ("0".equals(qybz) && tjSurveyTemplateService.qybzTjSurveyTemplateByQy(byId.getMid())==1){
            return AjaxResult.success("启用成功!");
        }else if ("1".equals(qybz) && tjSurveyTemplateService.qybzTjSurveyTemplateByJy(byId.getMid())==1){
            return AjaxResult.success("禁用成功!");
        }else {
            return AjaxResult.error("出错了,请联系工作人员!");
        }
    }
}
ltkj-admin/src/main/java/com/ltkj/web/tduck/UserFormController.java
New file
@@ -0,0 +1,311 @@
package com.ltkj.web.tduck;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ltkj.common.core.domain.AjaxResult;
import com.ltkj.tduck.constant.CommonConstants;
import com.ltkj.tduck.domain.*;
import com.ltkj.tduck.enums.FormStatusEnum;
import com.ltkj.tduck.enums.FormTypeEnum;
import com.ltkj.tduck.request.QueryFormItemRequest;
import com.ltkj.tduck.request.QueryFormRequest;
import com.ltkj.tduck.request.QueryFormTemplateTypeRequest;
import com.ltkj.tduck.request.SortFormItemRequest;
import com.ltkj.tduck.service.*;
import com.ltkj.tduck.utils.FormDataUtils;
import com.ltkj.tduck.utils.Result;
import com.ltkj.tduck.utils.SortUtils;
import com.ltkj.tduck.utils.ValidatorUtils;
import com.ltkj.tduck.vo.FormFieldVO;
import com.ltkj.tduck.vo.OperateFormItemVO;
import com.ltkj.tduck.vo.UserFormDetailVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
/**
 * 用户表单
 **/
@RequiredArgsConstructor
@RestController
@Slf4j
//@RequestMapping("/tduck-api")
public class UserFormController {
    @Resource
    private final UserFormService formService;
    @Resource
    private final UserFormItemService formItemService;
    @Resource
    private final FormTemplateCategoryService formTemplateCategoryService;
    @Resource
    private final SortUtils sortUtils;
    private final UserFormThemeService userFormThemeService;
    private final UserFormLogicService userFormLogicService;
    /**
     * 查询表单
     */
    @GetMapping("/user/form/{key}")
    public AjaxResult queryFormByKey(@PathVariable @NotBlank String key) {
        return AjaxResult.success(formService.getByKey(key));
    }
    /**
     * 项目表单项查询
     */
    @GetMapping("/user/form/item/list")
    public AjaxResult queryFormItems(QueryFormItemRequest request) {
        ValidatorUtils.validateEntity(request);
//        FormAuthUtils.hasPermission(request.getKey());
        List<UserFormItemEntity> itemEntityList = formItemService.list(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, request.getKey()).eq(ObjectUtil.isNotNull(request.getDisplayType()), UserFormItemEntity::getDisplayType, request.getDisplayType()));
        itemEntityList.sort(Comparator.comparing(UserFormItemEntity::getSort));
        return AjaxResult.success(itemEntityList);
    }
    /**
     * 分页查询项目分类
     *
     * @return
     */
    @GetMapping("/form/template/type/list")
    public AjaxResult queryFormTemplateTypes(QueryFormTemplateTypeRequest.List request) {
        return AjaxResult.success(formTemplateCategoryService.list(Wrappers.<FormTemplateCategoryEntity>lambdaQuery()
                .orderByDesc(FormTemplateCategoryEntity::getSort)));
    }
    /**
     * 表单更新
     *
     * @param form
     */
    @PostMapping("/user/form/update")
    public AjaxResult updateForm(@RequestBody UserFormEntity form) {
//        ValidatorUtils.validateEntity(form, AddGroup.class);
        UserFormEntity oldForm = formService.getByKey(form.getFormKey());
        if (ObjectUtil.isNotNull(oldForm)) {
            form.setId(oldForm.getId());
            formService.updateById(form);
        }
        return AjaxResult.success();
    }
    /**
     * 项目表单项创建
     *
     * @param entity
     */
    @PostMapping("/user/form/item/create")
    public AjaxResult createFormItem(@RequestBody UserFormItemEntity entity) {
//        ValidatorUtils.validateEntity(entity, AddGroup.class);
        if (ObjectUtil.isNull(entity.getDisplayType())) {
            entity.setDisplayType(false);
        }
        if (ObjectUtil.isNull(entity.getHideType())) {
            entity.setHideType(false);
        }
        //排序下标计算
        entity.setSort(sortUtils.getInitialSortPosition(entity.getFormKey()));
        entity.setSpecialType(formItemService.isSpecialTypeItem(entity));
        entity.setCreateTime(new Date());
        boolean save = formItemService.save(entity);
        return AjaxResult.success(new OperateFormItemVO(entity.getSort(), entity.getId(), save, false));
    }
    /**
     * 批量项目表单项创建
     */
    @PostMapping("/user/form/item/batch/create")
    public AjaxResult batchCreateFormItem(@RequestBody List<UserFormItemEntity> itemEntityList) {
        //排序下标计算
        itemEntityList.forEach(item -> item.setSort(sortUtils.getInitialSortPosition(item.getFormKey())));
        itemEntityList.forEach(item -> item.setDisplayType(false));
        itemEntityList.forEach(item -> item.setHideType(false));
        itemEntityList.forEach(item -> item.setSpecialType(false));
        boolean save = formItemService.saveBatch(itemEntityList);
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.put("code", 200);
        ajaxResult.put("data", null);
        ajaxResult.put("msg", null);
        return ajaxResult;
    }
    /**
     * 表单项删除
     */
    @PostMapping("/user/form/item/delete")
    public AjaxResult deleteFormItem(@RequestBody UserFormItemEntity request) {
//        FormAuthUtils.hasPermission(request.getFormKey());
        boolean delete = formItemService.remove(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, request.getFormKey()).eq(UserFormItemEntity::getFormItemId, request.getFormItemId()));
        return AjaxResult.success(delete);
    }
    /**
     * 表单项更新
     *
     * @param request
     */
    @PostMapping("/user/form/item/update")
    public AjaxResult updateFormItem(@RequestBody UserFormItemEntity request) {
//        FormAuthUtils.hasPermission(request.getFormKey());
//        ValidatorUtils.validateEntity(request, UpdateGroup.class);
        request.setSpecialType(formItemService.isSpecialTypeItem(request));
        boolean update = formItemService.update(request, Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, request.getFormKey()).eq(UserFormItemEntity::getFormItemId, request.getFormItemId()));
        return AjaxResult.success(update);
    }
    /**
     * 表单项排序
     *
     * @param request
     */
    @PostMapping("/user/form/item/sort")
    public AjaxResult sortFormItem(@RequestBody SortFormItemRequest request) {
//        ValidatorUtils.validateEntity(request);
        if (ObjectUtil.isNull(request.getAfterPosition()) && ObjectUtil.isNull(request.getBeforePosition())) {
            return AjaxResult.success();
        }
        UserFormItemEntity itemEntity = formItemService.getOne(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, request.getFormKey()).eq(UserFormItemEntity::getFormItemId, request.getFormItemId()));
        Long sort = sortUtils.calcSortPosition(request.getBeforePosition(), request.getAfterPosition(), request.getFormKey());
        if (sortUtils.sortAllList(request.getBeforePosition(), request.getAfterPosition(), request.getFormKey(), sort)) {
            return AjaxResult.success(new OperateFormItemVO(itemEntity.getSort(), itemEntity.getId(), true, true));
        }
        itemEntity.setSort(sort);
        boolean b = formItemService.updateById(itemEntity);
        return AjaxResult.success(new OperateFormItemVO(itemEntity.getSort(), itemEntity.getId(), b, false));
    }
    /**
     * 查询表单详情
     * 包含表单信息 表单字段信息 表单主题
     *
     * @param key
     */
    @GetMapping("/user/form/details/{key}")
    @PermitAll
    public AjaxResult queryFormDetails(@PathVariable @NotBlank String key) {
        UserFormEntity form = formService.getByKey(key);
        if (ObjectUtil.isNull(form)) {
            return AjaxResult.success();
        }
        List<UserFormItemEntity> formItemList = formItemService.list(Wrappers.<UserFormItemEntity>lambdaQuery().ne(UserFormItemEntity::getHideType, 1).eq(UserFormItemEntity::getFormKey, key));
        formItemList.sort(Comparator.comparing(UserFormItemEntity::getSort));
        UserFormThemeEntity theme = userFormThemeService.getByKey(key);
        UserFormLogicEntity formLogic = userFormLogicService.getOne(Wrappers.<UserFormLogicEntity>lambdaQuery().eq(UserFormLogicEntity::getFormKey, key));
        // 如果是考试 移除正确答案 避免把正确答案返回到前端
        if (form.getType() == FormTypeEnum.EXAM.getValue().toString()) {
            formItemList.forEach(item -> {
                JSONObject schemeJson = JSONUtil.parseObj(item.getScheme());
                if (schemeJson.containsKey("examConfig")) {
                    schemeJson.getJSONObject("examConfig").remove("answer");
                }
                item.setScheme(schemeJson);
            });
        }
        return AjaxResult.success(new UserFormDetailVO(new UserFormDetailVO.UserForm(form), formItemList, theme, formLogic));
    }
    /**
     * 发布表单
     */
    @PostMapping("/user/form/publish")
    public AjaxResult publishForm(@RequestBody UserFormEntity request) {
//        FormAuthUtils.hasPermission(request.getFormKey());
        long count = formItemService.count(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, request.getFormKey()));
        if (count == CommonConstants.ConstantNumber.ZERO) {
            return AjaxResult.error("无有效表单项,无法发布");
        }
        UserFormEntity entity = formService.getByKey(request.getFormKey());
        entity.setStatus(2);
        return AjaxResult.success(formService.updateById(entity));
    }
    /**
     * 停止收集
     *
     * @param request
     */
    @PostMapping("/user/form/stop")
    public Result stopForm(@RequestBody UserFormEntity request) {
//        FormAuthUtils.hasPermission(request.getFormKey());
        UserFormEntity entity = formService.getByKey(request.getFormKey());
        entity.setStatus(3);
        return Result.success(formService.updateById(entity));
    }
    /**
     * 查询我的表单分页
     */
    @GetMapping("/user/form/page")
    public Result queryMyForms(@RequestAttribute Long userId, QueryFormRequest.Page request) {
        LambdaQueryWrapper<UserFormEntity> queryWrapper = Wrappers.<UserFormEntity>lambdaQuery().eq(UserFormEntity::getUserId, userId)
                .eq(ObjectUtil.isNotNull(request.getFolder()), UserFormEntity::getFolder, request.getFolder())
                .eq(ObjectUtil.isNotNull(request.getType()), UserFormEntity::getType, request.getType())
                .eq(UserFormEntity::getDeleted, 0).func(i -> {
                    // 通过文件名搜索时 可以搜索到子文件夹下的表单
                    if (StrUtil.isNotBlank(request.getName()) && request.getFolderId() == 0) {
                    } else {
                        i.eq(UserFormEntity::getFolderId, request.getFolderId());
                    }
                }).eq(ObjectUtil.isNotNull(request.getStatus()), UserFormEntity::getStatus, request.getStatus()).like(StrUtil.isNotBlank(request.getName()),
                        UserFormEntity::getName, request.getName()).le(ObjectUtil.isNotNull(request.getEndDateTime()), UserFormEntity::getUpdateTime,
                        request.getEndDateTime()).ge(ObjectUtil.isNotNull(request.getBeginDateTime()), UserFormEntity::getUpdateTime,
                        request.getBeginDateTime()).orderByDesc(UserFormEntity::getFolder)
//                .orderByDesc(TBaseEntity::getCreateTime)
                ;
        return Result.success(formService.page(request.toMybatisPage(), queryWrapper));
    }
    /**
     * 获取表单字段 包括系统默认字段
     */
    @GetMapping("/user/form/fields/{formKey}")
    public Result queryUserFormFields(@PathVariable String formKey) {
        return Result.success(formItemService.listAllFormFields(formKey));
    }
    /**
     * 获取表单固定字段
     * 所有表单都包含 用于查看详情右侧显示
     */
    @GetMapping("/user/form/fixed/fields/{formKey}")
    public Result queryUserFormFixedFields(@PathVariable String formKey) {
        // 查询表单类型
        UserFormEntity userFormEntity = formService.getByKey(formKey);
        List<FormFieldVO> fields = new ArrayList<>();
        FormDataUtils.addFormBaseDataField(fields);
        fields.add(new FormFieldVO("submitUaOs", "操作系统"));
        fields.add(new FormFieldVO("submitUaDevice", "设备"));
        fields.add(new FormFieldVO(UserFormDataEntity.Fields.submitBrowser, "浏览器"));
        fields.add(new FormFieldVO(UserFormDataEntity.Fields.submitAddress, "地址"));
        fields.add(new FormFieldVO(UserFormDataEntity.Fields.submitRequestIp, "IP"));
        fields.add(new FormFieldVO(UserFormDataEntity.Fields.wxUserInfo, "微信用户"));
        return Result.success(fields);
    }
}
ltkj-admin/src/main/java/com/ltkj/web/tduck/UserFormResultController.java
New file
@@ -0,0 +1,254 @@
package com.ltkj.web.tduck;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ltkj.common.core.domain.AjaxResult;
import com.ltkj.common.utils.SecurityUtils;
import com.ltkj.common.utils.http.HttpUtils;
import com.ltkj.tduck.domain.UserFormDataEntity;
import com.ltkj.tduck.domain.UserFormViewCountEntity;
import com.ltkj.tduck.request.QueryFormResultRequest;
import com.ltkj.tduck.service.UserFormDataService;
import com.ltkj.tduck.service.UserFormViewCountService;
import com.ltkj.tduck.utils.Result;
import com.ltkj.tduck.utils.ValidatorUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * 表单数据
 *
 * @author : smalljop
 * @description : 表单数据页 当前用户自己使用接口
 * @create : 2020-11-18 18:17
 **/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/user/form/data")
public class UserFormResultController {
    private final UserFormDataService formResultService;
//    private final UserFormSettingService userFormSettingService;
//    private final FormDataImportUtils formDataImportUtils;
//    private final FormDataExportUtils formDataExportUtils;
//    private final UserFormService userFormService;
    private final UserFormViewCountService userFormViewCountService;
//    private final MailService mailService;
//    private final WxMpUserMsgService userMsgService;
    private final ConcurrentMap<String, Integer> viewFormMap = new ConcurrentHashMap<>();
    /**
     * 根据体检号获取问卷记录
     */
    @GetMapping("getRecordByTjNumber")
    public AjaxResult getRecordByTjNumber(String tjNumber) {
        LambdaQueryWrapper<UserFormDataEntity> wq=new LambdaQueryWrapper<>();
        wq.eq(UserFormDataEntity::getTjNumber,tjNumber);
        final List<UserFormDataEntity> list = formResultService.list(wq);
        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.put("code", 200);
        ajaxResult.put("data", list);
        ajaxResult.put("msg", null);
        return ajaxResult;
    }
    /***
     * 查看表单
     * 记录查看的IP 统计查看用户数
     */
    @GetMapping("view/{formKey}")
    @PermitAll
    public Result<Void> viewForm(HttpServletRequest request, @PathVariable("formKey") String formKey) {
        if (viewFormMap.containsKey(formKey)) {
            userFormViewCountService.increment(formKey);
        } else {
            // 不存在则添加
            Long count = userFormViewCountService.count(formKey);
            if (count == 0) {
                UserFormViewCountEntity entity = new UserFormViewCountEntity();
                entity.setFormKey(formKey);
                entity.setCount(1L);
                userFormViewCountService.save(entity);
            }
            viewFormMap.put(formKey, 1);
        }
        return Result.success();
    }
    /**
     * 查询数据
     *
     * @param request 查询条件
     * @return 数据
     */
    @PostMapping("query")
    public Result queryFormDataTable(@RequestBody QueryFormResultRequest request) {
//        FormAuthUtils.hasPermission(request.getFormKey());
        return Result.success(formResultService.listFormDataTable(request));
    }
    /**
     * 获取某条数据详情
     *
     * @param dataId 数据ID
     * @return 数据详情
     */
    @GetMapping("details/{dataId}")
    @PermitAll
    public Result getFormDataDetails(@PathVariable("dataId") String dataId) {
        return formResultService.getFormDataDetails(dataId);
    }
//
//
//    /**
//     * 填写附件导出
//     *
//     * @param request 请求
//     * @return 文件
//     */
//    @PostMapping("/download/file")
//    public Result downloadFormResultFile(@RequestBody QueryFormResultRequest request) {
//        return formResultService.downloadFormResultFile(request);
//    }
    /**
     * 填写
     *
     * @param entity  填写数据
     * @param request 请求
     * @return
     */
    @PostMapping("/create")
    public AjaxResult createFormResult(@RequestBody UserFormDataEntity entity, HttpServletRequest request) {
        ValidatorUtils.validateEntity(entity);
        entity.setSubmitRequestIp(HttpUtils.getIpAddr(request));
        // 如果已经登陆了也记录用户信息 try catch 避免抛出异常
        entity.setCreateBy(SecurityUtils.getUserId() != null ? String.valueOf(SecurityUtils.getUserId()) : null);
        Map<String, Object> result = formResultService.saveFormResult(entity);
        return AjaxResult.success(result);
    }
    /**
     * 公开填写
     *
     * @param entity  填写数据
     * @param request 请求
     */
    @PostMapping("/public/create")
    @PermitAll
    public Result<Map<String, Object>> createPublicFormResult(@RequestBody UserFormDataEntity entity, HttpServletRequest request) {
        ValidatorUtils.validateEntity(entity);
        entity.setSubmitRequestIp(HttpUtils.getIpAddr(request));
//        Result<Boolean> userFormSettingStatus = userFormSettingService.getUserFormWriteSettingStatus(entity.getFormKey(), entity.getSubmitRequestIp(), entity.getWxOpenId(), CommonConstants.ConstantNumber.ONE);
//        if (StrUtil.isNotBlank(userFormSettingStatus.getMsg())) {
//            return Result.failed(userFormSettingStatus.getMsg());
//        }
        // 如果已经登陆了也记录用户信息 try catch 避免抛出异常
        entity.setCreateBy(SecurityUtils.getUserId() != null ? String.valueOf(SecurityUtils.getUserId()) : null);
        Map<String, Object> result = formResultService.saveFormResult(entity);
//        ThreadUtil.execAsync(() -> {
//            sendWriteResultNotify(entity.getFormKey());
//        });
        return Result.success(result);
//        return Result.success();
    }
//
//    /**
//     * 批量删除
//     *
//     * @param formKey    表单key
//     * @param dataIdList 数据ID
//     * @return Result
//     */
//    @PostMapping("/delete/{formKey}")
//    public Result deleteFormData(@RequestBody List<String> dataIdList, @PathVariable("formKey") String formKey) {
//        formResultService.deleteByIds(dataIdList, formKey);
//        return Result.success();
//    }
//    /**
//     * 更新
//     *
//     * @param entity  填写数据
//     * @param request 请求
//     * @return Result
//     */
//    @PostMapping("/update")
//    @PermitAll
//    public Result<Void> updateFormResult(@RequestBody UserFormDataEntity entity, HttpServletRequest request) {
//        ValidatorUtils.validateEntity(entity);
//        try {
//            entity.setUpdateBy(String.valueOf(SecurityUtils.getUserId()));
//        } catch (Exception ignored) {
//        }
//        formResultService.updateFormResult(entity);
//        return Result.success();
//    }
//
//    /**
//     * 下载导入模板
//     *
//     * @param response 响应
//     * @param formKey  表单key
//     */
//    @GetMapping("/import/template")
//    public void downloadImportTemplate(HttpServletResponse response, String formKey) {
//        formDataImportUtils.importTemplateExcel(response, formKey);
//    }
//
//    /**
//     * 导出表单数据
//     */
//    @PostMapping("export")
//    public void exportFormData(@RequestBody ExportRequest.FormData exportRequest) {
//        formDataExportUtils.exportData(exportRequest);
//    }
//
//    /**
//     * 导入表单数据
//     *
//     * @param file 文件
//     * @return Result
//     */
//    @PostMapping("import")
//    public Result importFormData(@RequestParam("file") MultipartFile file, UserFormDataEntity dataEntity) throws IOException {
//        return Result.success(formDataImportUtils.importFile(file.getInputStream(), dataEntity.getFormKey()));
//    }
//
//
//    private void sendWriteResultNotify(String formKey) {
//        FormSettingSchemaStruct formSettingSchema = userFormSettingService.getFormSettingSchema(formKey);
//        if (ObjectUtil.isNull(formSettingSchema)) {
//            return;
//        }
//        UserFormEntity form = userFormService.getByKey(formKey);
//        if (StrUtil.isNotBlank(formSettingSchema.getNewWriteNotifyEmail())) {
//            mailService.sendTemplateHtmlMail(formSettingSchema.getNewWriteNotifyEmail(), "新回复通知", "mail/form-write-notify", MapUtil.of("projectName", form.getName()));
//        }
//
//        if (StrUtil.isNotBlank(formSettingSchema.getNewWriteNotifyWx())) {
//            List<String> openIdList = StrUtil.splitTrim(formSettingSchema.getNewWriteNotifyWx(), ";");
//            openIdList.stream().forEach(openId -> {
//                userMsgService.sendKfTextMsg("", openId, "收到新的反馈,请去Pc端查看");
//            });
//        }
//    }
}
ltkj-admin/src/main/java/com/ltkj/web/tduck/UserFormSettingController.java
New file
@@ -0,0 +1,143 @@
package com.ltkj.web.tduck;
import cn.hutool.core.util.ObjectUtil;
import com.ltkj.common.utils.http.HttpUtils;
import com.ltkj.tduck.domain.UserFormSettingEntity;
import com.ltkj.tduck.request.CheckWritePwdRequest;
import com.ltkj.tduck.service.UserFormSettingService;
import com.ltkj.tduck.utils.CacheUtils;
import com.ltkj.tduck.utils.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
 * 表单设置
 *
 * @author : smalljop
 * @description : 表单设置
 * @create : 2020-11-18 18:17
 **/
@Slf4j
@RestController
@RequiredArgsConstructor
public class UserFormSettingController {
    private final UserFormSettingService userFormSettingService;
//    private final WxMpUserService wxMpUserService;
    private final CacheUtils cacheUtils;
//    private final WxMpService wxMpService;
    /**
     * 保存表单设置
     */
    @PostMapping("/user/form/setting/save")
    public Result<Boolean> saveFormSetting(@RequestBody Map<String, Object> setting) {
        String formKey = setting.get("formKey").toString();
//        FormAuthUtils.hasPermission(formKey);
        return Result.success(userFormSettingService.saveFormSetting(setting));
    }
    /**
     * 表单提交设置查询
     */
    @GetMapping("/user/form/setting/{key}")
    public Result<Map<String, Object>> queryFormSettingByKey(@PathVariable("key") String formKey) {
        UserFormSettingEntity setting = userFormSettingService.getFormSettingByKey(formKey);
        if (ObjectUtil.isNull(setting)) {
            return Result.success();
        }
        Map<String, Object> settings = setting.getSettings();
        settings.put(UserFormSettingEntity.Fields.formKey, formKey);
        return Result.success(settings);
    }
    /**
     * 当前填写设置的状态
     *
     * @param formKey  表单key
     * @param wxOpenId 微信openid
     * @param type     类型 1公开填写 2.指定填写
     */
    @GetMapping("/user/form/setting-status")
    @PermitAll
    public Result<Boolean> querySettingStatus(@RequestParam String formKey, @RequestParam(required = false) String wxOpenId, @RequestParam(required = false) Integer type, HttpServletRequest request) {
        return userFormSettingService.getUserFormWriteSettingStatus(formKey, HttpUtils.getIpAddr(request), wxOpenId, type);
    }
    /**
     * 填写微信通知二维码
     */
    @GetMapping("/user/form/wx/notify-qrcode")
    public Result<String> getWxNotifyQrCode(@RequestParam("key") String formKey) throws Exception {
//        String loginSceneStr = JsonUtils.objToJson(new WxMpQrCodeGenRequest(WxMpQrCodeGenRequest.QrCodeType.SUB_NOTIFY, formKey));
//        //5分钟有效
//        WxMpQrCodeTicket ticket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(loginSceneStr, 10 * 60);
//        String subNotifyQrcodeUrl = wxMpService.getQrcodeService().qrCodePictureUrl(ticket.getTicket());
//        return Result.success(subNotifyQrcodeUrl);
        return Result.success();
    }
    /**
     * 填写微信通知二维码
     */
    @PostMapping("/user/form/wx/delete/notify-user")
    public Result<Boolean> deleteWxNotifyQrCode(@RequestParam("key") String key, @RequestParam("openId") String openId) {
//        cacheUtils.removeList(StrUtil.format(WxMpRedisKeyConstants.WX_MP_SUB_NOTIFY, key), openId);
        return Result.success(true);
    }
    /**
     * 获取表单微信通知用户
     */
    @GetMapping("/user/form/wx/notify-user")
    public Result getWxNotifyUser(@RequestParam("key") String formKey, @RequestParam(required = false) String openIdStr) {
//        Set<Object> subNotifyUsers = null;
//        if (StrUtil.isNotBlank(openIdStr)) {
//            subNotifyUsers = Sets.newHashSet(StrUtil.splitTrim(openIdStr, ";"));
//        } else {
//            List coll = cacheUtils.getList(StrUtil.format(WxMpRedisKeyConstants.WX_MP_SUB_NOTIFY, formKey), String.class);
//            subNotifyUsers = Collections.singleton(coll.stream().collect(Collectors.toSet()));
//        }
//        return Result.success(wxMpUserService.listWxMpUserByOpenId(subNotifyUsers).stream().map(item -> new WxMpUserVO(item.getNickname(), item.getHeadImgUrl(), item.getOpenId())).collect(Collectors.toList()));
        return Result.success();
    }
    /**
     * 公开接口
     * 表单填写时需要的设置
     */
    @GetMapping("/user/form/public/settings/{key}")
    @PermitAll
    public Result queryPublicFormSettingByKey(@PathVariable("key") String formKey) {
//        FormSettingSchemaStruct formSettingSchema = userFormSettingService.getFormSettingSchema(formKey);
        return Result.success();
    }
    /**
     * 公开接口
     * 检查填写密码是否正确
     */
    @PostMapping("/user/form/public/checkWritePwd")
    @PermitAll
    public Result<Boolean> checkWritePwd(@RequestBody @Validated CheckWritePwdRequest request) {
//        FormSettingSchemaStruct formSettingSchema = userFormSettingService.getFormSettingSchema(request.getFormKey());
//        if (formSettingSchema.getWritePassword().equals(request.getPassword())) {
//            return Result.success(true);
//        }
//        return Result.failed("密码输入错误");
        return Result.success(true);
    }
}
ltkj-admin/src/main/java/com/ltkj/web/tduck/WxJsApiController.java
New file
@@ -0,0 +1,74 @@
package com.ltkj.web.tduck;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.ltkj.tduck.utils.Result;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.security.PermitAll;
import javax.validation.constraints.NotBlank;
/**
 * @author : smalljop
 * @description : 微信公众号网页
 * @create : 2020-12-02 13:40
 **/
@AllArgsConstructor
@RestController
@RequestMapping("/wx/jsapi/")
public class WxJsApiController {
//    private final WxMpService wxService;
    /**
     * 用户授权url
     *
     * @return hcah
     */
    @GetMapping("/authorization/url")
    @PermitAll
    public Result getAuthorizationUrl(@RequestParam @NotBlank String url) {
        String appId = "11111";
        String authorizationUrl = StrUtil.format("https://open.weixin.qq.com/connect/oauth2/authorize?appid={}&redirect_uri={}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect", appId, URLUtil.encode(url));
        return Result.success(authorizationUrl);
    }
    /**
     * 根据code获取用户信息
     *
     * @param code
     * @return
     */
    @GetMapping("/authorization/user/info")
    @PermitAll
    public Result greetUser(@RequestParam @NotBlank String code)  {
//        WxOAuth2UserInfo userInfo = null;
//        try {
//            WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
//            userInfo = wxService.getOAuth2Service().getUserInfo(accessToken, null);
//        } catch (WxErrorException e) {
//            return Result.success();
//        }
//        return Result.success(userInfo);
        return Result.success();
    }
    /**
     * 获取jsapi签名
     */
    @GetMapping("/signature")
    @PermitAll
    public Result getSignature(@RequestParam String url) throws Exception {
//        WxJsapiSignature signature = wxService.createJsapiSignature(url);
//        return Result.success(signature);
        return Result.success();
    }
}
ltkj-admin/src/main/resources/application.yml
@@ -70,6 +70,10 @@
    restart:
      # 热部署开关
      enabled: true
  cache:
    type: ehcache
    ehcache:
      config: classpath:config/ehcache.xml
  # redis 配置
#  redis:
#    # 地址
ltkj-admin/src/main/resources/config/ehcache.xml
New file
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd">
    <!--timeToIdleSeconds 当缓存闲置n秒后销毁 -->
    <!--timeToLiveSeconds 当缓存存活n秒后销毁 -->
    <!-- 缓存配置
        name:缓存名称。
        maxElementsInMemory:缓存最大个数。
        eternal:对象是否永久有效,一但设置了,timeout将不起作用。
        timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
        timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
        overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。 diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
        maxElementsOnDisk:硬盘最大缓存个数。
        diskPersistent:是否缓存虚拟机重启期数据 Whether the disk
        store persists between restarts of the Virtual Machine. The default value
        is false.
        diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。  memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是
LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
        clearOnFlush:内存数量最大时是否清除。 -->
    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir"/>
    <!-- 默认缓存 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
    <!--    持久化cache-->
    <cache name="eternal_cache"
           maxElementsInMemory="10000"
           eternal="true"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="10"/>
    <!-- 临时cache -->
    <cache name="temp_cache"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="300"
           timeToLiveSeconds="300"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>
ltkj-common/pom.xml
@@ -22,6 +22,27 @@
<!--        </repository>-->
<!--    </repositories>-->
    <dependencies>
        <!--以下tduck-->
        <dependency>
            <groupId>com.aventrix.jnanoid</groupId>
            <artifactId>jnanoid</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>2.16.0</version>
        </dependency>
        <!-- ehcache缓存 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.9.1</version><!--$NO-MVN-MAN-VER$ -->
        </dependency>
        <!--以上tduck-->
<!--        <dependency>-->
<!--            <groupId>e-iceblue</groupId>-->
<!--            <artifactId>spire.pdf</artifactId>-->
ltkj-common/src/main/java/com/ltkj/common/utils/http/HttpUtils.java
@@ -17,7 +17,10 @@
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import com.ltkj.common.constant.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -216,4 +219,43 @@
            return true;
        }
    }
    /**
     * 获取请求IP地址
     *
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        //"***.***.***.***".length() = 15
        if (StrUtil.isNotBlank(ip) && ip.length() > 15) {
            if (ip.indexOf(CharUtil.COMMA) > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        //处理获取多个ip地址情况 nginx多层代理会出现多个ip 第一个为真实ip地址
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
}
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyOptions.java
@@ -39,7 +39,7 @@
     */
    @ApiModelProperty(value = "问题")
    @Excel(name = "问题")
    private Long qid;
    private String qid;
    /**
     * 选项
@@ -56,37 +56,7 @@
    private String score;
    public void setOid(Long oid) {
        this.oid = oid;
    }
    public Long getOid() {
        return oid;
    }
    public void setQid(Long qid) {
        this.qid = qid;
    }
    public Long getQid() {
        return qid;
    }
    public void setOoption(String ooption) {
        this.ooption = ooption;
    }
    public String getOoption() {
        return ooption;
    }
    public void setScore(String score) {
        this.score = score;
    }
    public String getScore() {
        return score;
    }
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyQuestion.java
@@ -32,10 +32,10 @@
    /**
     * id
     */
    @ApiModelProperty(value = "主键id")
    @TableId
    @JsonSerialize(using = ToStringSerializer.class)
    private Long qid;
//    @ApiModelProperty(value = "主键id")
//    @TableId
//    @JsonSerialize(using = ToStringSerializer.class)
    private String qid;
    /**
     * 问题
@@ -58,6 +58,16 @@
    @Excel(name = "是否必填",dictType="sys_yes_no")
    private String isRequired;
    private String keywords;
    private String sort;
    private Long mid;
    @TableField(exist = false)
    private TjSurveyTemplate template;
    /**
     * 问卷选项信息
     */
@@ -65,47 +75,7 @@
    @TableField(exist = false)
    private List<TjSurveyOptions> tjSurveyOptionsList;
    public void setQid(Long qid) {
        this.qid = qid;
    }
    public Long getQid() {
        return qid;
    }
    public void setQuestion(String question) {
        this.question = question;
    }
    public String getQuestion() {
        return question;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getType() {
        return type;
    }
    public void setIsRequired(String isRequired) {
        this.isRequired = isRequired;
    }
    public String getIsRequired() {
        return isRequired;
    }
    public List<TjSurveyOptions> getTjSurveyOptionsList() {
        return tjSurveyOptionsList;
    }
    public void setTjSurveyOptionsList(List<TjSurveyOptions> tjSurveyOptionsList) {
        this.tjSurveyOptionsList = tjSurveyOptionsList;
    }
    @Override
    public String toString() {
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyRecord.java
@@ -110,86 +110,14 @@
    @Excel(name = "标志")
    private String fromBy;
    private Long fmId;
    /**
     * 问卷记录详情信息
     */
    @ApiModelProperty(value = "问卷记录详情信息")
    @TableField(exist = false)
    private List<TjSurveyRecordDetail> tjSurveyRecordDetailList;
    public void setRid(Long rid) {
        this.rid = rid;
    }
    public Long getRid() {
        return rid;
    }
    public void setTjnumber(Long tjnumber) {
        this.tjnumber = tjnumber;
    }
    public Long getTjnumber() {
        return tjnumber;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getPhone() {
        return phone;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserName() {
        return userName;
    }
    public void setMid(Long mid) {
        this.mid = mid;
    }
    public Long getMid() {
        return mid;
    }
    public void setMname(String mname) {
        this.mname = mname;
    }
    public String getMname() {
        return mname;
    }
    public void setQid(Long qid) {
        this.qid = qid;
    }
    public Long getQid() {
        return qid;
    }
    public void setQname(String qname) {
        this.qname = qname;
    }
    public String getQname() {
        return qname;
    }
    public List<TjSurveyRecordDetail> getTjSurveyRecordDetailList() {
        return tjSurveyRecordDetailList;
    }
    public void setTjSurveyRecordDetailList(List<TjSurveyRecordDetail> tjSurveyRecordDetailList) {
        this.tjSurveyRecordDetailList = tjSurveyRecordDetailList;
    }
    @Override
    public String toString() {
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyTempQues.java
@@ -46,7 +46,7 @@
     */
    @ApiModelProperty(value = "问题id")
    @Excel(name = "问题id")
    private Long qid;
    private String qid;
    /**
     * 问题名
@@ -56,37 +56,6 @@
    private String qname;
    public void setTqid(Long tqid) {
        this.tqid = tqid;
    }
    public Long getTqid() {
        return tqid;
    }
    public void setMid(Long mid) {
        this.mid = mid;
    }
    public Long getMid() {
        return mid;
    }
    public void setQid(Long qid) {
        this.qid = qid;
    }
    public Long getQid() {
        return qid;
    }
    public void setQname(String qname) {
        this.qname = qname;
    }
    public String getQname() {
        return qname;
    }
    @Override
ltkj-hosp/src/main/java/com/ltkj/hosp/domain/TjSurveyTemplate.java
@@ -53,44 +53,22 @@
    /**
     * 表单设计绑定
     */
    private String designId;
    /*启用标志*/
    private String qybz;
    /**
     * 问卷模板问题信息
     */
    @ApiModelProperty(value = "问卷模板问题信息")
    @TableField(exist = false)
    private List<TjSurveyTempQues> tjSurveyTempQuesList;
    public void setMid(Long mid) {
        this.mid = mid;
    }
    public Long getMid() {
        return mid;
    }
    public void setTempName(String tempName) {
        this.tempName = tempName;
    }
    public String getTempName() {
        return tempName;
    }
    public void setTempType(String tempType) {
        this.tempType = tempType;
    }
    public String getTempType() {
        return tempType;
    }
    public List<TjSurveyTempQues> getTjSurveyTempQuesList() {
        return tjSurveyTempQuesList;
    }
    public void setTjSurveyTempQuesList(List<TjSurveyTempQues> tjSurveyTempQuesList) {
        this.tjSurveyTempQuesList = tjSurveyTempQuesList;
    }
    @Override
    public String toString() {
ltkj-hosp/src/main/java/com/ltkj/hosp/mapper/TjSurveyQuestionMapper.java
@@ -1,11 +1,13 @@
package com.ltkj.hosp.mapper;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.hosp.domain.TjSurveyQuestion;
import com.ltkj.hosp.domain.TjSurveyOptions;
import com.ltkj.hosp.domain.TjSurveyQuestion;
import com.ltkj.hosp.domain.TjSurveyTempQues;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
 * 问卷问题Mapper接口
@@ -21,7 +23,12 @@
     * @param qid 问卷问题主键
     * @return 问卷问题
     */
    public TjSurveyQuestion selectTjSurveyQuestionByQid(Long qid);
    public TjSurveyQuestion selectTjSurveyQuestionByQid(String qid);
    /*根据问题查询选项集合*/
    public List<TjSurveyOptions> selectOptionsByQid(String qid);
    /**
     * 查询问卷问题列表
@@ -39,6 +46,15 @@
     */
    public int insertTjSurveyQuestion(TjSurveyQuestion tjSurveyQuestion);
    /**
     * 新增问卷
     *
     * @param tjSurveyOptions 问卷
     * @return 结果
     */
    public int insertTjSurveyOptions(TjSurveyOptions tjSurveyOptions);
    /**
     * 修改问卷问题
     *
@@ -53,7 +69,10 @@
     * @param qid 问卷问题主键
     * @return 结果
     */
    public int deleteTjSurveyQuestionByQid(Long qid);
    public int deleteTjSurveyQuestionByQid(String qid);
    public int deleteTjSurveyQuestionByMid(Long mid);
    /**
     * 批量删除问卷问题
@@ -61,7 +80,7 @@
     * @param qids 需要删除的数据主键集合
     * @return 结果
     */
    public int deleteTjSurveyQuestionByQids(Long[] qids);
    public int deleteTjSurveyQuestionByQids(String[] qids);
        /**
         * 批量删除问卷选项
@@ -69,7 +88,7 @@
         * @param qids 需要删除的数据主键集合
         * @return 结果
         */
        public int deleteTjSurveyOptionsByQids(Long[] qids);
    public int deleteTjSurveyOptionsByQids(String[] qids);
        /**
         * 批量新增问卷选项
@@ -86,5 +105,12 @@
         * @param qid 问卷问题ID
         * @return 结果
         */
        public int deleteTjSurveyOptionsByQid(Long qid);
    public int deleteTjSurveyOptionsByQid(String qid);
    @Select("SELECT * FROM tj_survey_temp_ques a WHERE a.mid=#{mid} AND a.deleted=0")
    List<TjSurveyTempQues> selectOptionsByMid(String mid);
    List<TjSurveyQuestion> getOptionsByMid(String mid);
}
ltkj-hosp/src/main/java/com/ltkj/hosp/mapper/TjSurveyTemplateMapper.java
@@ -24,6 +24,11 @@
     */
    public TjSurveyTemplate selectTjSurveyTemplateByMid(Long mid);
    public TjSurveyTemplate selectTemplateByMid1(Long mid);
    public int qybzTjSurveyTemplateByQy(Long mid);
    public int qybzTjSurveyTemplateByJy(Long mid);
    /**
     * 查询问卷模板列表
     *
ltkj-hosp/src/main/java/com/ltkj/hosp/service/ITjSurveyQuestionService.java
@@ -1,10 +1,11 @@
package com.ltkj.hosp.service;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.hosp.domain.TjSurveyOptions;
import com.ltkj.hosp.domain.TjSurveyQuestion;
import com.ltkj.hosp.domain.TjTeamSelectRecord;
import com.ltkj.hosp.domain.TjSurveyTempQues;
import java.util.List;
/**
 * 问卷问题Service接口
@@ -19,8 +20,9 @@
     * @param qid 问卷问题主键
     * @return 问卷问题
     */
    public TjSurveyQuestion selectTjSurveyQuestionByQid(Long qid);
    public TjSurveyQuestion selectTjSurveyQuestionByQid(String qid);
    public List<TjSurveyOptions> selectOptionsByQid(String qid);
    /**
     * 查询问卷问题列表
     *
@@ -51,7 +53,7 @@
     * @param qids 需要删除的问卷问题主键集合
     * @return 结果
     */
    public int deleteTjSurveyQuestionByQids(Long[] qids);
    public int deleteTjSurveyQuestionByQids(String[] qids);
    /**
     * 删除问卷问题信息
@@ -59,5 +61,10 @@
     * @param qid 问卷问题主键
     * @return 结果
     */
    public int deleteTjSurveyQuestionByQid(Long qid);
    public int deleteTjSurveyQuestionByQid(String qid);
    List<TjSurveyTempQues> selectOptionsByMid(String mid);
    List<TjSurveyQuestion> getOptionsByMid(String mid);
}
ltkj-hosp/src/main/java/com/ltkj/hosp/service/ITjSurveyTemplateService.java
@@ -21,6 +21,11 @@
     */
    public TjSurveyTemplate selectTjSurveyTemplateByMid(Long mid);
    public TjSurveyTemplate selectTemplateByMid1(Long mid);
    public int qybzTjSurveyTemplateByQy(Long mid);
    public int qybzTjSurveyTemplateByJy(Long mid);
    /**
     * 查询问卷模板列表
     *
ltkj-hosp/src/main/java/com/ltkj/hosp/service/impl/TjSurveyQuestionServiceImpl.java
@@ -1,22 +1,20 @@
package com.ltkj.hosp.service.impl;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.common.utils.DateUtils;
import com.ltkj.hosp.domain.TjTeamSelectRecord;
import com.ltkj.hosp.mapper.TjTeamSelectRecordMapper;
import com.ltkj.common.utils.SecurityUtils;
import com.ltkj.common.utils.StringUtils;
import com.ltkj.hosp.domain.TjSurveyOptions;
import com.ltkj.hosp.domain.TjSurveyQuestion;
import com.ltkj.hosp.domain.TjSurveyTempQues;
import com.ltkj.hosp.mapper.TjSurveyQuestionMapper;
import com.ltkj.hosp.service.ITjSurveyQuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import com.ltkj.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ltkj.hosp.domain.TjSurveyOptions;
import com.ltkj.hosp.mapper.TjSurveyQuestionMapper;
import com.ltkj.hosp.domain.TjSurveyQuestion;
import com.ltkj.hosp.service.ITjSurveyQuestionService;
import java.util.List;
/**
 * 问卷问题Service业务层处理
@@ -36,8 +34,13 @@
     * @return 问卷问题
     */
    @Override
    public TjSurveyQuestion selectTjSurveyQuestionByQid(Long qid) {
    public TjSurveyQuestion selectTjSurveyQuestionByQid(String qid) {
        return tjSurveyQuestionMapper.selectTjSurveyQuestionByQid(qid);
    }
    @Override
    public List<TjSurveyOptions> selectOptionsByQid(String qid) {
        return tjSurveyQuestionMapper.selectOptionsByQid(qid);
    }
    /**
@@ -61,7 +64,9 @@
    @Override
    public int insertTjSurveyQuestion(TjSurveyQuestion tjSurveyQuestion) {
        tjSurveyQuestion.setCreateTime(DateUtils.getNowDate());
        tjSurveyQuestion.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        int rows = tjSurveyQuestionMapper.insertTjSurveyQuestion(tjSurveyQuestion);
        System.out.println(tjSurveyQuestion);
        insertTjSurveyOptions(tjSurveyQuestion);
        return rows;
    }
@@ -76,8 +81,7 @@
    @Override
    public int updateTjSurveyQuestion(TjSurveyQuestion tjSurveyQuestion) {
        tjSurveyQuestion.setUpdateTime(DateUtils.getNowDate());
        tjSurveyQuestionMapper.deleteTjSurveyOptionsByQid(tjSurveyQuestion.getQid())
        ;
        tjSurveyQuestionMapper.deleteTjSurveyOptionsByQid(tjSurveyQuestion.getQid());
        insertTjSurveyOptions(tjSurveyQuestion);
        return tjSurveyQuestionMapper.updateTjSurveyQuestion(tjSurveyQuestion);
    }
@@ -90,7 +94,7 @@
     */
    @Transactional
    @Override
    public int deleteTjSurveyQuestionByQids(Long[] qids) {
    public int deleteTjSurveyQuestionByQids(String[] qids) {
        tjSurveyQuestionMapper.deleteTjSurveyOptionsByQids(qids);
        return tjSurveyQuestionMapper.deleteTjSurveyQuestionByQids(qids);
    }
@@ -103,9 +107,19 @@
     */
    @Transactional
    @Override
    public int deleteTjSurveyQuestionByQid(Long qid) {
    public int deleteTjSurveyQuestionByQid(String qid) {
        tjSurveyQuestionMapper.deleteTjSurveyOptionsByQid(qid);
        return tjSurveyQuestionMapper.deleteTjSurveyQuestionByQid(qid);
    }
    @Override
    public List<TjSurveyTempQues> selectOptionsByMid(String mid) {
        return tjSurveyQuestionMapper.selectOptionsByMid(mid);
    }
    @Override
    public List<TjSurveyQuestion> getOptionsByMid(String mid) {
        return tjSurveyQuestionMapper.getOptionsByMid(mid);
    }
    /**
@@ -115,19 +129,21 @@
     */
    public void insertTjSurveyOptions(TjSurveyQuestion tjSurveyQuestion) {
        List<TjSurveyOptions> tjSurveyOptionsList = tjSurveyQuestion.getTjSurveyOptionsList();
        Long qid = tjSurveyQuestion.getQid();
        String qid = tjSurveyQuestion.getQid();
        if (StringUtils.isNotNull(tjSurveyOptionsList)) {
            List<TjSurveyOptions> list = new ArrayList<TjSurveyOptions>();
            for (TjSurveyOptions tjSurveyOptions : tjSurveyOptionsList) {
                tjSurveyOptions.setQid(qid);
                tjSurveyOptions.setDeleted(0);
                tjSurveyOptions.setCreateBy(SecurityUtils.getLoginUser().getUsername());
                tjSurveyOptions.setCreateTime(DateUtils.getNowDate());
                list.add(tjSurveyOptions);
            }
            if (list.size() > 0) {
                for (TjSurveyOptions tjSurveyOptions : list) {
                    tjSurveyOptions.setDeleted(0);
                    tjSurveyQuestionMapper.insertTjSurveyOptions(tjSurveyOptions);
                }
                tjSurveyQuestionMapper.batchTjSurveyOptions(list);
            }
        }
    }
ltkj-hosp/src/main/java/com/ltkj/hosp/service/impl/TjSurveyTemplateServiceImpl.java
@@ -40,6 +40,22 @@
        return tjSurveyTemplateMapper.selectTjSurveyTemplateByMid(mid);
    }
    @Override
    public TjSurveyTemplate selectTemplateByMid1(Long mid) {
        return tjSurveyTemplateMapper.selectTemplateByMid1(mid);
    }
    @Override
    public int qybzTjSurveyTemplateByQy(Long mid) {
        return tjSurveyTemplateMapper.qybzTjSurveyTemplateByQy(mid);
    }
    @Override
    public int qybzTjSurveyTemplateByJy(Long mid) {
        return tjSurveyTemplateMapper.qybzTjSurveyTemplateByJy(mid);
    }
    /**
     * 查询问卷模板列表
     *
ltkj-hosp/src/main/resources/mapper/hosp/TjSurveyQuestionMapper.xml
@@ -15,6 +15,9 @@
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
        <result property="deleted" column="deleted"/>
        <result property="keywords" column="keywords"/>
        <result property="sort" column="sort"/>
        <result property="mid" column="mid"/>
    </resultMap>
    <resultMap id="TjSurveyQuestionTjSurveyOptionsResult" type="TjSurveyQuestion" extends="TjSurveyQuestionResult">
@@ -45,7 +48,10 @@
               create_time,
               update_by,
               update_time,
               deleted
               deleted,
               keywords,
               sort,
               mid
        from tj_survey_question
    </sql>
@@ -64,7 +70,7 @@
        </where>
    </select>
    <select id="selectTjSurveyQuestionByQid" parameterType="Long"
    <select id="selectTjSurveyQuestionByQid" parameterType="String"
            resultMap="TjSurveyQuestionTjSurveyOptionsResult">
        select a.qid,
               a.question,
@@ -76,6 +82,8 @@
               a.update_by,
               a.update_time,
               a.deleted,
               a.keywords,
               a.sort,
               b.oid         as
                   sub_oid,
               b.qid         as
@@ -101,10 +109,103 @@
        where a.qid = #{qid}
    </select>
    <insert id="insertTjSurveyQuestion" parameterType="TjSurveyQuestion" useGeneratedKeys="true"
            keyProperty="qid">
    <select id="getOptionsByMid" parameterType="String"
            resultMap="TjSurveyQuestionTjSurveyOptionsResult">
        select a.qid,
               a.question,
               a.type,
               a.is_required,
               a.remark,
               a.create_by,
               a.create_time,
               a.update_by,
               a.update_time,
               a.deleted,
               a.keywords,
               a.sort,
               b.oid         as
                   sub_oid,
               b.qid         as
                   sub_qid,
               b.ooption      as
                   sub_ooption,
               b.score       as
                   sub_score,
               b.remark      as
                   sub_remark,
               b.create_by   as
                   sub_create_by,
               b.create_time as
                   sub_create_time,
               b.update_by   as
                   sub_update_by,
               b.update_time as
                   sub_update_time,
               b.deleted     as
                   sub_deleted
        from tj_survey_question a
                 left join tj_survey_options b on b.qid = a.qid
        where a.mid = #{mid}
    </select>
    <select id="selectOptionsByQid" parameterType="String" resultType="TjSurveyOptions">
        select oid,qid,ooption,score,remark,create_by,create_time,update_by,update_time,deleted from tj_survey_options
        where qid = #{qid}
    </select>
<!--    <insert id="insertTjSurveyQuestion" parameterType="TjSurveyQuestion" useGeneratedKeys="true"-->
<!--            keyProperty="qid">-->
<!--        insert into tj_survey_question-->
<!--        <trim prefix="(" suffix=")" suffixOverrides=",">-->
<!--            <if test="question != null and question != ''">question,-->
<!--            </if>-->
<!--            <if test="type != null and type != ''">type,-->
<!--            </if>-->
<!--            <if test="isRequired != null and isRequired != ''">is_required,-->
<!--            </if>-->
<!--            <if test="remark != null">remark,-->
<!--            </if>-->
<!--            <if test="createBy != null">create_by,-->
<!--            </if>-->
<!--            <if test="createTime != null">create_time,-->
<!--            </if>-->
<!--            <if test="updateBy != null">update_by,-->
<!--            </if>-->
<!--            <if test="updateTime != null">update_time,-->
<!--            </if>-->
<!--            <if test="deleted != null">deleted,-->
<!--            </if>-->
<!--        </trim>-->
<!--        <trim prefix="values (" suffix=")" suffixOverrides=",">-->
<!--            <if test="question != null and question != ''">#{question},-->
<!--            </if>-->
<!--            <if test="type != null and type != ''">#{type},-->
<!--            </if>-->
<!--            <if test="isRequired != null and isRequired != ''">#{isRequired},-->
<!--            </if>-->
<!--            <if test="remark != null">#{remark},-->
<!--            </if>-->
<!--            <if test="createBy != null">#{createBy},-->
<!--            </if>-->
<!--            <if test="createTime != null">#{createTime},-->
<!--            </if>-->
<!--            <if test="updateBy != null">#{updateBy},-->
<!--            </if>-->
<!--            <if test="updateTime != null">#{updateTime},-->
<!--            </if>-->
<!--            <if test="deleted != null">#{deleted},-->
<!--            </if>-->
<!--        </trim>-->
<!--    </insert>-->
    <insert id="insertTjSurveyQuestion" parameterType="TjSurveyQuestion">
        insert into tj_survey_question
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="qid != null and qid != ''">qid,
            </if>
            <if test="question != null and question != ''">question,
            </if>
            <if test="type != null and type != ''">type,
@@ -121,10 +222,17 @@
            </if>
            <if test="updateTime != null">update_time,
            </if>
            <if test="deleted != null">deleted,
            <if test="keywords != null">keywords,
            </if>
            <if test="sort != null">sort,
            </if>
            <if test="mid != null">mid,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="qid != null and qid != ''">#{qid},
            </if>
            <if test="question != null and question != ''">#{question},
            </if>
            <if test="type != null and type != ''">#{type},
@@ -141,10 +249,14 @@
            </if>
            <if test="updateTime != null">#{updateTime},
            </if>
            <if test="deleted != null">#{deleted},
            <if test="keywords != null">#{keywords},
            </if>
            <if test="sort != null">#{sort},</if>
            <if test="mid != null">#{mid},</if>
        </trim>
    </insert>
    <update id="updateTjSurveyQuestion" parameterType="TjSurveyQuestion">
        update tj_survey_question
@@ -176,51 +288,132 @@
            <if test="deleted != null">deleted =
                #{deleted},
            </if>
            <if test="mid != null">mid =
                #{mid},
            </if>
            <if test="keywords != null">keywords =
                #{keywords},
            </if>
            <if test="sort != null">sort =
                #{sort},
            </if>
        </trim>
        where qid = #{qid}
    </update>
    <delete id="deleteTjSurveyQuestionByQid" parameterType="Long">
        delete
        from tj_survey_question
        where qid = #{qid}
    </delete>
    <update id="deleteTjSurveyQuestionByQid" parameterType="TjSurveyQuestion">
        update tj_survey_question SET deleted = 1 where qid = #{qid}
    </update>
    <delete id="deleteTjSurveyQuestionByQids" parameterType="String">
        delete from tj_survey_question where qid in
    <update id="deleteTjSurveyQuestionByMid" parameterType="Long">
        update tj_survey_question SET deleted = 1 where mid = #{mid}
    </update>
<!--    <delete id="deleteTjSurveyQuestionByQid" parameterType="String">-->
<!--        delete-->
<!--        from tj_survey_question-->
<!--        where qid = #{qid}-->
<!--    </delete>-->
    <update id="deleteTjSurveyQuestionByQids" parameterType="Long">
        update tj_survey_question set deleted=1 where mid in
        <foreach item="mid" collection="array" open="(" separator="," close=")">
            #{mid}
        </foreach>
    </update>
    <update id="deleteTjSurveyOptionsByQids" parameterType="Long">
        update tj_survey_options set deleted=1 where qid in
        <foreach item="qid" collection="array" open="(" separator="," close=")">
            #{qid}
        </foreach>
    </delete>
    </update>
    <delete id="deleteTjSurveyOptionsByQids" parameterType="String">
        delete from tj_survey_options where qid in
        <foreach item="qid" collection="array" open="(" separator="," close=")">
            #{qid}
        </foreach>
    </delete>
<!--    <delete id="deleteTjSurveyQuestionByQids" parameterType="String">-->
<!--        delete from tj_survey_question where qid in-->
<!--        <foreach item="qid" collection="array" open="(" separator="," close=")">-->
<!--            #{qid}-->
<!--        </foreach>-->
<!--    </delete>-->
    <delete id="deleteTjSurveyOptionsByQid" parameterType="Long">
        delete
        from tj_survey_options
        where qid = #{qid}
    </delete>
<!--    <delete id="deleteTjSurveyOptionsByQids" parameterType="String">-->
<!--        delete from tj_survey_options where qid in-->
<!--        <foreach item="qid" collection="array" open="(" separator="," close=")">-->
<!--            #{qid}-->
<!--        </foreach>-->
<!--    </delete>-->
    <insert id="batchTjSurveyOptions">
<!--    <delete id="deleteTjSurveyOptionsByQid" parameterType="String">-->
<!--        delete-->
<!--        from tj_survey_options-->
<!--        where qid = #{qid}-->
<!--    </delete>-->
    <update id="deleteTjSurveyOptionsByQid" parameterType="TjSurveyOptions">
        update tj_survey_options SET deleted = 1 where qid = #{qid}
    </update>
    <insert id="insertTjSurveyOptions" parameterType="TjSurveyOptions">
        insert into tj_survey_options
        ( oid , qid , ooption , score , remark , create_by , create_time , update_by , update_time , deleted) values
        <foreach item="item" index="index" collection="list" separator=",">
            ( #{item.oid
                }, #{item.qid
                }, #{item.ooption
                }, #{item.score
                }, #{item.remark
                }, #{item.createBy
                }, #{item.createTime
                }, #{item.updateBy
                }, #{item.updateTime
                }, #{item.deleted
                })
        </foreach>
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="qid != null and qid != ''">qid,
            </if>
            <if test="ooption != null and ooption != ''">ooption,
            </if>
            <if test="score != null and score != ''">score,
            </if>
            <if test="remark != null">remark,
            </if>
            <if test="createBy != null">create_by,
            </if>
            <if test="createTime != null">create_time,
            </if>
            <if test="updateBy != null">update_by,
            </if>
            <if test="updateTime != null">update_time,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="qid != null and qid != ''">#{qid},
            </if>
            <if test="ooption != null and ooption != ''">#{ooption},
            </if>
            <if test="score != null and score != ''">#{score},
            </if>
            <if test="remark != null">#{remark},
            </if>
            <if test="createBy != null">#{createBy},
            </if>
            <if test="createTime != null">#{createTime},
            </if>
            <if test="updateBy != null">#{updateBy},
            </if>
            <if test="updateTime != null">#{updateTime},
            </if>
        </trim>
    </insert>
<!--    <insert id="batchTjSurveyOptions">-->
<!--        insert into tj_survey_options-->
<!--        ( oid , qid , ooption , score , remark , create_by , create_time , update_by , update_time , deleted) values-->
<!--        <foreach item="item" index="index" collection="list" separator=",">-->
<!--            ( #{item.oid-->
<!--                }, #{item.qid-->
<!--                }, #{item.ooption-->
<!--                }, #{item.score-->
<!--                }, #{item.remark-->
<!--                }, #{item.createBy-->
<!--                }, #{item.createTime-->
<!--                }, #{item.updateBy-->
<!--                }, #{item.updateTime-->
<!--                }, #{item.deleted-->
<!--                })-->
<!--        </foreach>-->
<!--    </insert>-->
</mapper>
ltkj-hosp/src/main/resources/mapper/hosp/TjSurveyTemplateMapper.xml
@@ -14,6 +14,8 @@
            <result property="updateBy" column="update_by"/>
            <result property="updateTime" column="update_time"/>
            <result property="deleted" column="deleted"/>
        <result property="designId" column="design_id"/>
        <result property="qybz" column="qybz"/>
    </resultMap>
        <resultMap id="TjSurveyTemplateTjSurveyTempQuesResult" type="TjSurveyTemplate" extends="TjSurveyTemplateResult">
@@ -34,7 +36,17 @@
        </resultMap>
    <sql id="selectTjSurveyTemplateVo">
        select mid, temp_name, temp_type, remark, create_by, create_time, update_by, update_time, deleted
        select mid,
               temp_name,
               temp_type,
               remark,
               create_by,
               create_time,
               update_by,
               update_time,
               deleted,
               qybz,
               design_id
        from tj_survey_template
    </sql>
@@ -55,20 +67,69 @@
    <select id="selectTjSurveyTemplateByMid" parameterType="Long"
            resultMap="TjSurveyTemplateTjSurveyTempQuesResult">
            select a.mid, a.temp_name, a.temp_type, a.remark, a.create_by, a.create_time, a.update_by, a.update_time, a.deleted,
        select a.mid,
               a.temp_name,
               a.temp_type,
               a.remark,
               a.create_by,
               a.create_time,
               a.update_by,
               a.update_time,
               a.deleted,
               a.design_id,
               a.qybz,
 b.tqid as
                sub_tqid, b.mid as
                sub_mid, b.qid as
                sub_qid, b.qname as
                sub_qname, b.create_by as
                sub_create_by, b.create_time as
                sub_create_time, b.update_by as
                sub_update_by, b.update_time as
                sub_update_time, b.deleted as
                   sub_tqid,
               b.mid         as
                   sub_mid,
               b.qid         as
                   sub_qid,
               b.qname       as
                   sub_qname,
               b.create_by   as
                   sub_create_by,
               b.create_time as
                   sub_create_time,
               b.update_by   as
                   sub_update_by,
               b.update_time as
                   sub_update_time,
               b.deleted     as
                sub_deleted
            from tj_survey_template a
            left join tj_survey_temp_ques b on b.mid = a.mid
            where a.mid = #{mid}
    </select>
    <update id="qybzTjSurveyTemplateByQy" parameterType="Long">
        update tj_survey_template
        set qybz=0
        where mid = #{mid}
    </update>
    <update id="qybzTjSurveyTemplateByJy" parameterType="Long">
        update tj_survey_template
        set qybz=1
        where mid = #{mid}
    </update>
    <select id="selectTemplateByMid1" parameterType="Long"
            resultType="TjSurveyTemplate">
        select mid,
               temp_name,
               temp_type,
               remark,
               create_by,
               create_time,
               update_by,
               update_time,
               deleted,
               qybz,
               design_id
        from tj_survey_template
        where mid = #{mid}
          AND deleted = 0
    </select>
    <insert id="insertTjSurveyTemplate" parameterType="TjSurveyTemplate" useGeneratedKeys="true"
@@ -91,6 +152,10 @@
                    </if>
                    <if test="deleted != null">deleted,
                    </if>
            <if test="designId != null">design_id,
            </if>
            <if test="qybz != null">qybz,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
                    <if test="tempName != null">#{tempName},
@@ -108,6 +173,10 @@
                    <if test="updateTime != null">#{updateTime},
                    </if>
                    <if test="deleted != null">#{deleted},
            </if>
            <if test="designId != null">#{designId},
            </if>
            <if test="qybz != null">#{qybz},
                    </if>
        </trim>
    </insert>
@@ -139,13 +208,20 @@
                    <if test="deleted != null">deleted =
                        #{deleted},
                    </if>
            <if test="designId != null">design_id =
                #{designId},
            </if>
            <if test="qybz != null">qybz =
                #{qybz},
            </if>
        </trim>
        where mid = #{mid}
    </update>
    <delete id="deleteTjSurveyTemplateByMid" parameterType="Long">
        delete
        from tj_survey_template where mid = #{mid}
        from tj_survey_template
        where mid = #{mid}
    </delete>
    <delete id="deleteTjSurveyTemplateByMids" parameterType="String">
@@ -164,7 +240,8 @@
        <delete id="deleteTjSurveyTempQuesByMid" parameterType="Long">
            delete
            from tj_survey_temp_ques where mid = #{mid}
        from tj_survey_temp_ques
        where mid = #{mid}
        </delete>
        <insert id="batchTjSurveyTempQues">
@@ -183,4 +260,6 @@
                })
            </foreach>
        </insert>
</mapper>
ltkj-system/src/main/java/com/ltkj/tduck/constant/CommonConstants.java
New file
@@ -0,0 +1,96 @@
package com.ltkj.tduck.constant;
/**
 * @description: 通用的常亮
 * @author: smalljop
 * @create: 2018-09-27 13:25
 **/
public interface CommonConstants {
    /**
     * 超级管理员id
     */
    Long SUPER_ADMIN_ID = 1L;
    String USER_KEY = "userId";
    /**
     * 用户正常状态
     * 1:正常 0 :禁用
     */
    Integer USER_NORMAL_STATUS = 1;
    /**
     * 文件下载content_type
     */
    String FILE_DOWNLOAD_CONTENT_TYPE = "application/octet-stream;charset=UTF-8";
    /**
     * 数字常量
     */
    interface ConstantNumber {
        /**
         * @Fields NEGATIVE : ( -1 )
         */
        Integer NEGATIVE = -1;
        /**
         * @Fields ZERO : ( 0 )
         */
        Integer ZERO = 0;
        /**
         * @Fields ONE : ( 1 )
         */
        Integer ONE = 1;
        /**
         * @Fields TOW : ( 2 )
         */
        Integer TOW = 2;
        /**
         * @Fields THREE : ( 3 )
         */
        Integer THREE = 3;
        /**
         * @Fields FOUR : ( 4 )
         */
        Integer FOUR = 4;
        /**
         * @Fields FIVE : ( 5 )
         */
        Integer FIVE = 5;
        /**
         * @Fields FIVE : ( 6 )
         */
        Integer SIX = 6;
        /**
         * @Fields FIVE : ( 7 )
         */
        Integer Seven = 7;
        /**
         * @Fields FIVE : ( 8 )
         */
        Integer Eight = 8;
        /**
         * @Fields FIVE : ( 9 )
         */
        Integer Nine = 9;
        /**
         * @Fields FIVE : ( 10 )
         */
        Integer Ten = 10;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/constant/FormConstants.java
New file
@@ -0,0 +1,35 @@
package com.ltkj.tduck.constant;
/**
 * @author : smalljop
 * @description :
 * @create : 2020-11-11 18:16
 **/
public interface FormConstants {
    /**
     * 选择性组件保存会创建两个字段 一个存放Id 一个存放选项名
     */
    String FIELD_SUFFIX_LABEL = "label";
    /**
     * 表单Item排序位置自增
     */
    String FORM_ITEM_POS_DELTA = "form:item:pos:{}";
    /**
     * 手机号验证码
     */
    String PHONE_NUMBER_CODE = "form:mobile:code:{}";
    /**
     * 查看表单数
     */
    String FORM_VIEW_COUNT = "form:view:count:{}";
    String FORM_RESULT_NUMBER = "form:view:result:{}";
}
ltkj-system/src/main/java/com/ltkj/tduck/constant/FormRedisKeyConstants.java
New file
@@ -0,0 +1,66 @@
package com.ltkj.tduck.constant;
/**
 * @description: redis key常量
 **/
public interface FormRedisKeyConstants {
    /**
     * 表单Item排序位置自增
     */
    String FORM_ITEM_POS_DELTA = "form:item:pos:{}";
    /**
     * 手机号验证码
     */
    String PHONE_NUMBER_CODE = "form:mobile:code:{}";
    /**
     * 表单Item排序位置自增
     */
    String FORM_RESULT_NUMBER = "form:result:number:{}";
    /**
     * 查看表单IP记录列表
     */
    String FORM_VIEW_IP_LIST = "form:view:ip:list:{}";
    /**
     * 表单查看次数
     */
    String FORM_VIEW_COUNT_KEY = "form:view:count:{}";
    /**
     * 表单预约人数
     */
    String FORM_RESERVE_COUNT = "form:reserve:count:{}:{}:{}";
    /**
     * 商品卖出数量
     */
    String FORM_GOODS_SELL_QUANTITY = "form:goods:sell:quantity:{}:{}";
    /**
     * 商品是否支付状态
     */
    String FORM_GOODS_PAY_STATUS = "form:goods:pay:status:{}";
    /**
     * 商品待提交表单数据
     */
    String FORM_GOODS_SUBMIT_DATA = "form:goods:submit:data:{}";
    /**
     * 商品支付金额
     */
    String FORM_GOODS_PAY_PRICE = "form:goods:pay:price:{}";
    /**
     * 表单投票数量 {formKey}:{formItemId}
     */
    String FORM_VOTE_COUNT = "form:vote:count:{}:{}";
    /**
     * 表单单选名额 {formKey}:{formItemId}
     */
    String FORM_OPTION_QUANTITY = "form:option:count:{}:{}";
}
ltkj-system/src/main/java/com/ltkj/tduck/constant/FormSettingConstants.java
New file
@@ -0,0 +1,21 @@
package com.ltkj.tduck.constant;
/**
 * @author : wangqing
 * @description : 表单设置项常量
 * @create :  2022/07/07 11:49
 **/
public interface FormSettingConstants {
    /**
     * 表单提交后显示类型字段名称
     */
    String SUBMIT_SHOW_TYPE_KEY = "submitShowType";
    /**
     * 自定义提示页面内容
     */
    String SUBMIT_SHOW_CUSTOM_PAGE_KEY = "submitShowCustomPage";
}
ltkj-system/src/main/java/com/ltkj/tduck/constant/ResponseCodeConstants.java
New file
@@ -0,0 +1,45 @@
package com.ltkj.tduck.constant;
/**
 * @description: 响应状态码
 * @author: smalljop
 * @create: 2020-02-10 15:46
 **/
public interface ResponseCodeConstants {
    /**
     * 接口成功
     */
    int SUCCESS = 200;
    /**
     * 接口失败 发生异常
     */
    int FAIL = 500;
    /**
     * 未登录
     */
    int UNAUTHORIZED = 401;
    /**
     * 需要验证的请求
     */
    int NEED_VERIFICATION = 416;
    /**
     * 找不到该请求
     */
    int NOT_FOUND = 404;
    /**
     * 非法签名
     */
    Integer SIGN_FAIL_CODE = 405;
    /**
     * 非法签名
     */
    String SIGN_FAIL_MSG = "非法访问,请检查请求信息";
    String VALIDATE_CODE_FAIL_MSG = "验证码验证失败";
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/FormTemplateCategoryEntity.java
New file
@@ -0,0 +1,26 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
 * 表单主题分类
 *
 * @author smalljop
 * @since 2021-01-06 10:50:51
 */
@Data
@TableName(value = "fm_form_template_category", autoResultMap = true)
public class FormTemplateCategoryEntity {
    /**
     * 主题名称
     */
    private String name;
    /**
     * 排序
     */
    private Integer sort;
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/FormThemeEntity.java
New file
@@ -0,0 +1,44 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
/**
 * 表单主题外观模板(FormTheme)表实体类
 *
 * @author smalljop
 * @since 2020-11-23 18:33:50
 */
@Data
@TableName(value = "fm_form_theme", autoResultMap = true)
@FieldNameConstants
public class FormThemeEntity {
    /**
     * 主题名称
     */
    private String name;
    /**
     * 主题风格
     */
    private Long style;
    /**
     * 头部图片
     */
    private String headImgUrl;
    /**
     * 背景图片
     */
    private String backgroundImg;
    /**
     * 主题颜色
     */
    private String themeColor;
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/PageRequest.java
New file
@@ -0,0 +1,21 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
/**
 * @author : smalljop
 * @description : 分页
 * @create : 2020-12-09 10:47
 **/
@Data
public class PageRequest {
    private long current = 1;
    private long size = 50;
    public Page toMybatisPage() {
        return new Page(current, size);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/SysBaseEntity.java
New file
@@ -0,0 +1,50 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
 * Entity基类
 *
 * @author smalljop
 */
@Data
@FieldNameConstants
public class SysBaseEntity extends TBaseEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 搜索值
     */
    @TableField(exist = false)
    private String searchValue;
    /**
     * 创建者
     */
    private String createBy;
    /**
     * 更新者
     */
    private String updateBy;
    /**
     * 请求参数
     */
    @TableField(exist = false)
    private Map<String, Object> params;
    public Map<String, Object> getParams() {
        if (params == null) {
            params = new HashMap<>();
        }
        return params;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/TBaseEntity.java
New file
@@ -0,0 +1,57 @@
package com.ltkj.tduck.domain;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.ltkj.tduck.utils.LongToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.FieldNameConstants;
import java.time.LocalDateTime;
import java.util.Date;
/**
 * @description: 实体类基类
 * @author: smalljop
 * @create: 2020-02-15 22:57
 **/
@Data
@FieldNameConstants
@EqualsAndHashCode(callSuper = false)
public class TBaseEntity<T> extends Model {
    private static final long serialVersionUID = 1L;
    /**
     * 主键 避免超出长度 前端丢失精度
     */
    @JsonSerialize(using= LongToStringSerializer.class)
    private Long id;
    /**
     * 创建时间
     **/
    @TableField(fill = FieldFill.INSERT)
//    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
//    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
    protected Date createTime;
    /**
     * 更新时间
     **/
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
//    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
//    @JsonSerialize(using = LocalDateTimeSerializer.class)
    protected Date updateTime;
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormDataEntity.java
New file
@@ -0,0 +1,112 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ltkj.common.annotation.Excel;
import com.ltkj.tduck.enums.FormTypeEnum;
import com.ltkj.tduck.handler.JacksonTypeHandler;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.experimental.FieldNameConstants;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotBlank;
import java.util.Date;
import java.util.Map;
/**
 * 表单数据(FormResult)表实体类
 *
 * @author smalljop
 * @since 2020-11-23 14:09:20
 */
@Data
@Accessors(chain = true)
@FieldNameConstants
@TableName(value = "fm_user_form_data", autoResultMap = true)
public class UserFormDataEntity extends SysBaseEntity {
    /**
     * 表单key
     */
    @NotBlank(message = "错误请求")
    private String formKey;
    /**
     * 提交序号
     */
    private Long serialNumber;
    /**
     * 填写结果原始数据
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> originalData;
    @TableField(exist = false)
    private FormTypeEnum formType;
    /**
     * 填写用户Ua
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> submitUa;
    /**
     * 提交系统
     */
    private String submitOs;
    /**
     * 提交浏览器
     */
    private String submitBrowser;
    /**
     * 提交ip
     */
    private String submitRequestIp;
    /**
     * 提交ip
     */
    private String submitAddress;
    /**
     * 完成时间
     */
    private Long completeTime;
    /**
     * 微信openID
     */
    private String wxOpenId;
    /**
     * 微信用户信息
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> wxUserInfo;
    /**
     * 扩展字段
     */
    private String extValue;
    /**
     * 体检号
     */
    private String tjNumber;
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormEntity.java
New file
@@ -0,0 +1,104 @@
package com.ltkj.tduck.domain;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ltkj.tduck.enums.FormSourceTypeEnum;
import com.ltkj.tduck.enums.FormStatusEnum;
import com.ltkj.tduck.utils.HtmlUtils;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import org.apache.ibatis.type.BooleanTypeHandler;
import javax.validation.constraints.NotBlank;
import java.util.Date;
/**
 * 用户表单表(Form)表实体类
 */
@Data
@FieldNameConstants
@TableName(value = "fm_user_form", autoResultMap = true)
public class UserFormEntity{
    /**
     * 主键 避免超出长度 前端丢失精度
     */
    private Long id;
    /**
     * 创建时间
     **/
    protected Date createTime;
    /**
     * 更新时间
     **/
    protected Date updateTime;
    /**
     * 表单code
     */
    @NotBlank(message = "错误请求")
    private String formKey;
    /**
     * 表单名称
     */
    @NotBlank(message = "表单名称不能为空")
    private String name;
    /**
     * 表单描述
     */
    private String description;
    /**
     * 表单来源
     */
    private Integer sourceType;
    /**
     * 来源ID
     */
    private String sourceId;
    /**
     * 用户ID
     */
    private Long userId;
    /***
     * 状态
     */
    private Integer status;
    /**
     * 表单类型
     */
    private String type;
    @TableField(value = "is_deleted", typeHandler = BooleanTypeHandler.class)
    private Boolean deleted;
    /**
     * 是否是文件夹
     */
    @TableField(value = "is_folder", typeHandler = BooleanTypeHandler.class)
    private Boolean folder;
    /**
     * 父级文件夹ID
     */
    private Long folderId;
    /**
     * 移除html标签
     * @return 文本
     */
    public String getTextName() {
        if (StrUtil.isBlank(name)) {
            return null;
        }
        // 标题是富文本 去除html 标签
        return HtmlUtils.cleanHtmlTag(name);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormItemEntity.java
New file
@@ -0,0 +1,145 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.ltkj.tduck.enums.FormItemTypeEnum;
import com.ltkj.tduck.utils.HtmlUtils;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.experimental.FieldNameConstants;
import org.apache.ibatis.type.BooleanTypeHandler;
import org.apache.ibatis.type.EnumTypeHandler;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * 表单表单项(FormItem)表实体类
 *
 * @author smalljop
 * @since 2020-11-19 10:49:16
 */
@Data
@Accessors(chain = true)
@FieldNameConstants
@JsonIgnoreProperties(ignoreUnknown = true)
@TableName(value = "fm_user_form_item", autoResultMap = true)
public class UserFormItemEntity {
    /**
     * 主键 避免超出长度 前端丢失精度
     */
    private Long id;
    /**
     * 创建时间
     **/
    protected Date createTime;
    /**
     * 更新时间
     **/
    protected Date updateTime;
    /**
     * 表单Id
     */
    @NotNull(message = "key请求异常")
    private String formKey;
    /**
     * 表单项Id 类型  + 时间戳
     */
    @NotNull(message = "Id请求错误")
    private String formItemId;
    /**
     * 表单项类型
     */
    @NotNull(message = "类型请求错误")
    @TableField(typeHandler = EnumTypeHandler.class)
    private FormItemTypeEnum type;
    /**
     * 表单项标题
     */
    @NotNull(message = "标题不能为空")
    private String label;
    /**
     * 展示类型组件 只在表单填写页查询到
     */
    @TableField(value = "is_display_type", typeHandler = BooleanTypeHandler.class)
    private Boolean displayType;
    /**
     * 隐藏类型组件 在表单填写页面无法查看到
     */
    @TableField(value = "is_hide_type", typeHandler = BooleanTypeHandler.class)
    private Boolean hideType;
    /**
     * 需要在入库前特殊处理的组件 比如随机编码等 验重
     */
    @TableField(value = "is_special_type", typeHandler = BooleanTypeHandler.class)
    private Boolean specialType;
    /**
     * 是否显示标签
     */
    @TableField(typeHandler = BooleanTypeHandler.class)
    private Boolean showLabel;
    /**
     * 表单项默认值
     */
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private String defaultValue;
    /**
     * 是否必填
     */
    @TableField(typeHandler = BooleanTypeHandler.class)
    private Boolean required;
    /**
     * 输入型提示文字
     */
    private String placeholder;
    /**
     * 排序
     */
    private Long sort;
    /**
     * 栅格宽度
     */
    private int span;
    /**
     * 扩展字段 表单项独有字段
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> scheme;
    /**
     * 正则表达式
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private List<Map<String, Object>> regList;
    /**
     * 去除html格式
     *
     * @return
     */
    public String getTextLabel() {
        return HtmlUtils.cleanHtmlTag(this.label);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormLogicEntity.java
New file
@@ -0,0 +1,88 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import java.util.List;
import java.util.Set;
/**
 * 表单逻辑(UserFormLogic)表实体类
 *
 * @author smalljop
 * @since 2020-05-01 13:36:27
 */
@Data
@Accessors(chain = true)
@TableName(value = "fm_user_form_logic", autoResultMap = true)
public class UserFormLogicEntity {
    /**
     * 表单key
     */
    @NotBlank(message = "formKey不能为空")
    private String formKey;
    @TableField(typeHandler = JacksonTypeHandler.class)
    private List<Definition> scheme;
    /**
     * 逻辑定义对象
     */
    @Data
    public static class Definition {
        /**
         * 触发内容
         */
        private Set<Trigger> triggerList;
        /**
         * 条件
         */
        private Set<Condition> conditionList;
    }
    @Data
    public static class Trigger {
        /**
         * 表单项Id
         */
        private String formItemId;
        /**
         * 类型
         */
        private String type = "show";
    }
    /**
     * 条件
     */
    @Data
    public static class Condition {
        /**
         * 表单项Id
         */
        private String formItemId;
        /**
         * 表达式
         */
        private String expression;
        /**
         * 选项
         */
        private Object optionValue;
        /**
         * AND OR
         */
        private String relation;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormSettingEntity.java
New file
@@ -0,0 +1,36 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ltkj.common.core.domain.BaseEntity;
import com.ltkj.tduck.handler.JacksonTypeHandler;
import lombok.Data;
import lombok.experimental.FieldNameConstants;
import javax.validation.constraints.NotBlank;
import java.util.Map;
/**
 * 表单设置对象
 *
 * @author tduck
 * @date 2021-08-12 16:19:57
 */
@Data
@FieldNameConstants
@TableName(value = "fm_user_form_setting", autoResultMap = true)
public class UserFormSettingEntity extends BaseEntity {
    @NotBlank
    private String formKey;
    /**
     * 设置具体内容
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private Map<String, Object> settings;
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormThemeEntity.java
New file
@@ -0,0 +1,86 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import org.apache.ibatis.type.BooleanTypeHandler;
import javax.validation.constraints.NotBlank;
/**
 * 表单表单项(UserFormTheme)表实体类
 *
 * @author smalljop
 * @since 2020-11-25 13:36:27
 */
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@TableName(value = "fm_user_form_theme", autoResultMap = true)
public class UserFormThemeEntity  {
    /**
     * 表单key
     */
    @NotBlank(message = "formKey不能为空")
    private String formKey;
    /**
     * logo图片
     */
    private String logoImg;
    /**
     * logo位置
     */
    private String logoPosition;
    /**
     * 头部图片
     */
    private String headImgUrl;
    /**
     * 主题颜色
     */
    private String themeColor;
    /**
     * 提交按钮文字
     */
    private String submitBtnText;
    /**
     * 背景
     */
    private String backgroundColor;
    /**
     * 背景
     */
    private String backgroundImg;
    /**
     * 是否显示标题
     */
    @TableField(typeHandler = BooleanTypeHandler.class)
    private Boolean showTitle;
    /**
     * 是否显示描述语
     */
    @TableField(typeHandler = BooleanTypeHandler.class)
    private Boolean showDescribe;
    /**
     * 显示序号
     */
    @TableField(typeHandler = BooleanTypeHandler.class)
    private Boolean showNumber;
    /**
     * 显示提交按钮
     */
    @TableField(typeHandler = BooleanTypeHandler.class)
    private Boolean showSubmitBtn;
}
ltkj-system/src/main/java/com/ltkj/tduck/domain/UserFormViewCountEntity.java
New file
@@ -0,0 +1,36 @@
package com.ltkj.tduck.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ltkj.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
 * 用户表单查看次数对象 fm_user_form_view_count
 *
 * @author tduck
 * @date 2023-04-04 21:29:39
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("fm_user_form_view_count")
public class UserFormViewCountEntity extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     *
     */
    @TableId(value = "id")
    private Long id;
    /**
     * 表单唯一标识
     */
    private String formKey;
    /**
     *
     */
    private Long count;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/EsTypeEnum.java
New file
@@ -0,0 +1,32 @@
package com.ltkj.tduck.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * ElasticSearch的字段类型
 */
@AllArgsConstructor
@Getter
public enum EsTypeEnum {
    STRING("string", "字符串类型"),
    TEXT("text", "字符串类型"),
    KEYWORD("keyword", "字符串类型"),
    INTEGER("integer", "整数类型"),
    LONG("long", "整数类型"),
    SHORT("short", "整数类型"),
    BYTE("byte", "整数类型"),
    DOUBLE("double", "浮点类型"),
    FLOAT("float", "浮点类型"),
    HALF_FLOAT("half_float", "浮点类型"),
    SCALED_FLOAT("scaled_float", "浮点类型"),
    BOOLEAN("boolean", "逻辑类型"),
    DATE("date", "日期类型");
    private String type;
    private String name;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormItemTypeEnum.java
New file
@@ -0,0 +1,60 @@
package com.ltkj.tduck.enums;
import com.baomidou.mybatisplus.annotation.IEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * @author : smalljop
 * @description : 表单项类型枚举
 * @create : 2020-11-19 10:51
 **/
@AllArgsConstructor
@Getter
public enum FormItemTypeEnum implements IEnum<String> {
    INPUT("单行文本"),
    NUMBER("数字"),
    TEXTAREA("多行文本"),
    SELECT("下拉框"),
    CASCADER("级联选择"),
    SORT("排序"),
    SLIDER("滑块"),
    RADIO("单选框"),
    CHECKBOX("多选框"),
    DATE("日期选择"),
    DATE_RANGE("日期范围"),
    RATE("评分"),
    IMAGE_UPLOAD("图片上传"),
    UPLOAD("文件上传组件"),
    IMAGE("图片展示"),
    IMAGE_SELECT("图片选择"),
    IMAGE_CAROUSEL("图片轮播"),
    DESC_TEXT("文字描述"),
    SIGN_PAD("手写签名"),
    PAGINATION("分页"),
    DIVIDER("分割线"),
    PROVINCE_CITY("省市联动"),
    PHONE_VERIFICATION("手机号验证"),
    SUB_FORM("子表单"),
    INPUT_MAP("地理位置"),
    MATRIX_INPUT("矩阵填空"),
    MATRIX_SCALE("矩阵量表"),
    HORIZONTAL_INPUT("横向填空"),
    MATRIX_SELECT("矩阵选择"),
    USER_SELECT("成员选择"),
    DEPT_SELECT("部门选择"),
    OCR("文字识别"),
    RANDOM_NUMBER("随机编号"),
    FUNCTION_CALC("函数计算"),
    GOODS_SELECT("商品选择"),
    RESERVE_DAY("预约日期"),
    RESERVE_TIME_RANGE("预约时段");
    private String desc;
    @Override
    public String getValue() {
        return this.toString();
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormLogicConditionExpressionEnum.java
New file
@@ -0,0 +1,28 @@
package com.ltkj.tduck.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * @author : smalljop
 * @description :逻辑条件
 * @create : 2020-12-04 13:35
 **/
@Getter
@AllArgsConstructor
public enum FormLogicConditionExpressionEnum {
    EQ("eq", "等于"),
    NE("ne", "不等于");
    @EnumValue
    @JsonValue
    private String value;
    private String desc;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormPermsBtnTypeEnum.java
New file
@@ -0,0 +1,25 @@
package com.ltkj.tduck.enums;
import lombok.AllArgsConstructor;
/**
 * 表单按钮权限类型
 */
@AllArgsConstructor
public enum FormPermsBtnTypeEnum {
    DETAIL("detail", "查看"),
    ADD("add", "新增"),
    IMPORT("import", "导入"),
    EXPORT("export", "导出"),
    QUERY("query", "结构查询"),
    BATCH_ACTION("batchAction", "批量操作"),
    CUSTOM_COLUMN("customColumn", "自定义列"),
    UPDATE("update", "编辑"),
    DELETE("delete", "删除");
    private final String code;
    private final String desc;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormSourceTypeEnum.java
New file
@@ -0,0 +1,30 @@
package com.ltkj.tduck.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.ltkj.tduck.utils.IDictEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * @author : smalljop
 * @description : 表单来源
 * @create : 2020-12-04 13:35
 **/
@Getter
@AllArgsConstructor
public enum FormSourceTypeEnum implements IDictEnum {
    BLANK(1, "空白创建"),
    TEMPLATE(2, "模板");
    @EnumValue
    @JsonValue
    private Integer value;
    private String desc;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormStatusEnum.java
New file
@@ -0,0 +1,31 @@
package com.ltkj.tduck.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.ltkj.tduck.utils.IDictEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
 * @author : smalljop
 * @description : 表单状态
 * @create : 2020-12-04 13:35
 **/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum FormStatusEnum implements IDictEnum<Integer> {
    CREATE(1, "未发布"),
    RELEASE(2, "收集中"),
    STOP(3, "停止发布");
    @EnumValue
    @JsonValue
    private Integer value;
    private String desc;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/FormTypeEnum.java
New file
@@ -0,0 +1,38 @@
package com.ltkj.tduck.enums;
import com.ltkj.tduck.utils.IDictEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
 * @author : smalljop
 * @description : 表单类型
 * @create : 2020-12-04 13:35
 **/
@Getter
@AllArgsConstructor
public enum FormTypeEnum implements IDictEnum {
    /**
     * 普通表单
     */
    ORDINARY(1, "普通表单"),
    /**
     * 流程表单
     */
    WORKFLOW(2, "流程表单"),
    /**
     * 文件夹
     */
    FOLDER(3, "文件夹"),
    /**
     * 考试
     */
    EXAM(4, "考试");
    private Integer value;
    private String desc;
}
ltkj-system/src/main/java/com/ltkj/tduck/enums/TimeRangeEnum.java
New file
@@ -0,0 +1,57 @@
package com.ltkj.tduck.enums;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
 * @author : tduck
 * @description : 时间范围枚举
 * @create :  2022/10/11 11:12
 **/
@NoArgsConstructor
@Getter
public enum TimeRangeEnum {
    /**
     * 今天
     */
    TODAY,
    /**
     * 昨天
     */
    YESTERDAY,
    /**
     * 近7天
     */
    WEEK,
    /**
     * 上周
     */
    LAST_WEEK,
    /**
     * 本月
     */
    MONTH,
    /**
     * 上月
     */
    LAST_MONTH,
    /**
     * 本季度
     */
    QUARTER,
    /**
     * 上季度
     */
    LAST_QUARTER,
    /**
     * 本年
     */
    YEAR,
    /**
     * 去年
     */
    LAST_YEAR;
}
ltkj-system/src/main/java/com/ltkj/tduck/handler/AutoFillMetaInfoHandler.java
New file
@@ -0,0 +1,30 @@
//package com.ltkj.tduck.handler;
//
//import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
//import com.ltkj.tduck.domain.TBaseEntity;
//import lombok.extern.slf4j.Slf4j;
//import org.apache.ibatis.reflection.MetaObject;
//import org.springframework.stereotype.Component;
//
//import java.time.LocalDateTime;
//
///**
// * @author smalljop
// * mybatis 自动填充插件
// * @link https://baomidou.com/guide/typehandler.html
// */
//@Slf4j
//@Component
//public class AutoFillMetaInfoHandler implements MetaObjectHandler {
//
//    @Override
//    public void insertFill(MetaObject metaObject) {
//        this.setFieldValByName(TBaseEntity.Fields.createTime, LocalDateTime.now(), metaObject);
//        this.setFieldValByName(TBaseEntity.Fields.updateTime, LocalDateTime.now(), metaObject);
//    }
//
//    @Override
//    public void updateFill(MetaObject metaObject) {
//        this.setFieldValByName(TBaseEntity.Fields.updateTime, LocalDateTime.now(), metaObject);
//    }
//}
ltkj-system/src/main/java/com/ltkj/tduck/handler/BooleanTypeHandler.java
New file
@@ -0,0 +1,47 @@
package com.ltkj.tduck.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
 * 处理布尔转换 mysql能自动转换
 * 有的数据库不支持自动转换 pgsql不行 干脆统一处理了
 *
 * @author tduck
 */
public class BooleanTypeHandler extends BaseTypeHandler<Boolean> {
    public BooleanTypeHandler() {
    }
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, parameter ? 1 : 0);
    }
    @Override
    public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException {
        boolean result = rs.getInt(columnName) != 0;
        return !result && rs.wasNull() ? null : result;
    }
    @Override
    public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        boolean result = rs.getInt(columnIndex) != 0;
        return !result && rs.wasNull() ? null : result;
    }
    @Override
    public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        boolean result = cs.getInt(columnIndex) != 0;
        return !result && cs.wasNull() ? null : result;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/handler/JacksonTypeHandler.java
New file
@@ -0,0 +1,64 @@
package com.ltkj.tduck.handler;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ltkj.tduck.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.io.IOException;
/**
 * Jackson 实现 JSON 字段类型处理器
 *
 * @author hubin
 * @since 2019-08-25
 */
@Slf4j
@MappedTypes({Object.class})
@MappedJdbcTypes(JdbcType.VARCHAR)
public class JacksonTypeHandler extends AbstractJsonTypeHandler<Object> {
    private static ObjectMapper objectMapper = new ObjectMapper();
    private Class<?> type;
    public JacksonTypeHandler(Class<?> type) {
        if (log.isTraceEnabled()) {
            log.trace("JacksonTypeHandler(" + type + ")");
        }
        Assert.notNull(type, "Type argument cannot be null");
        this.type = type;
    }
    public static void setObjectMapper(ObjectMapper objectMapper) {
        Assert.notNull(objectMapper, "ObjectMapper should not be null");
        JacksonTypeHandler.objectMapper = JsonUtils.getInstance();
    }
    @Override
    protected Object parse(String json) {
        try {
            if (StrUtil.isBlank(json)) {
                return null;
            }
            return objectMapper.readValue(json, type);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    protected String toJson(Object obj) {
        try {
            return JsonUtils.objToJsonIgnoreNull(obj);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/handler/LongToStringSerializer.java
New file
@@ -0,0 +1,34 @@
package com.ltkj.tduck.handler;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
 * @author : wangqing
 * @description : Long转string 避免返回前端丢失精度
 * @create :  2022/03/10 15:07
 **/
public class LongToStringSerializer extends JsonSerializer<Long> {
    /**
     * Method that can be called to ask implementation to serialize
     * values of type this serializer handles.
     *
     * @param value       Value to serialize; can <b>not</b> be null.
     * @param gen         Generator used to output resulting Json content
     * @param serializers Provider that can be used to get serializers for
     */
    @Override
    public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value != null && value.toString().length() > 16) {
            gen.writeString(value.toString());
        } else {
            gen.writeNumber(value);
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/FormTemplateCategoryMapper.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.FormTemplateCategoryEntity;
/**
 * 表单模板分类(FormTemplateType)表数据库访问层
 *
 * @author smalljop
 * @since 2021-01-06 10:51:05
 */
public interface FormTemplateCategoryMapper extends BaseMapper<FormTemplateCategoryEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/FormThemeMapper.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.FormThemeEntity;
/**
 * 表单主题外观模板(FormTheme)表数据库访问层
 *
 * @author smalljop
 * @since 2020-11-23 18:33:54
 */
public interface FormThemeMapper extends BaseMapper<FormThemeEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormDataMapper.java
New file
@@ -0,0 +1,54 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.ltkj.tduck.domain.UserFormDataEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
 * 表单表单数据(FormResult)表数据库访问层
 *
 * @author smalljop
 * @since 2020-11-23 14:09:21
 */
public interface UserFormDataMapper extends BaseMapper<UserFormDataEntity> {
    /**
     * 查询表单字段值是否存在
     * @param formKey 表单key
     * @param field 字段
     * @param value 值
     * @return 是否存在
     */
    @Select("SELECT COUNT(id) FROM fm_user_form_data WHERE form_key = #{formKey} AND JSON_EXTRACT(original_data, '$.\"${field}\"') = #{value}")
    Long selectOriginalDataValueCount(@Param("formKey") String formKey, @Param("field") String field, @Param("value") Object value);
    /**
     * 查询表单数据
     * @param sql sql
     * @return
     */
    @Results(id="queryRowsResultMap",
            value = {
                    @Result(property = "originalData", column = "original_data",typeHandler = JacksonTypeHandler.class),
                    @Result(property = "wxUserInfo", column = "wx_user_info",typeHandler = JacksonTypeHandler.class)})
    @Select("${sql}")
    List<UserFormDataEntity> selectRowsBySql(@Param("sql") String sql);
    /**
     * 查询表单数据条数
     * @param sql
     * @return
     */
    @Select("${sql}")
    Long selectCountBySql(@Param("sql") String sql);
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormItemMapper.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.UserFormItemEntity;
/**
 * 表单项(FormItem)表数据库访问层
 *
 * @author smalljop
 * @since 2020-11-19 10:49:17
 */
public interface UserFormItemMapper extends BaseMapper<UserFormItemEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormLogicMapper.java
New file
@@ -0,0 +1,15 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.UserFormLogicEntity;
/**
 * 用户表单逻辑表(UserFormLogic)表数据库访问层
 *
 * @author smalljop
 * @since 2020-11-18 18:16:17
 */
public interface UserFormLogicMapper extends BaseMapper<UserFormLogicEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormMapper.java
New file
@@ -0,0 +1,12 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.UserFormEntity;
/**
 * 表单表(Form)表数据库访问层
 */
public interface UserFormMapper extends BaseMapper<UserFormEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormSettingMapper.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.UserFormSettingEntity;
/**
 * 表单设置
 *
 * @author tduck
 * @date 2021-08-12 16:19:57
 */
public interface UserFormSettingMapper extends BaseMapper<UserFormSettingEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormThemeMapper.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.UserFormThemeEntity;
/**
 * 表单主题(UserFormTheme)表数据库访问层
 *
 * @author smalljop
 * @since 2020-11-25 13:36:31
 */
public interface UserFormThemeMapper extends BaseMapper<UserFormThemeEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/mapper/UserFormViewCountMapper.java
New file
@@ -0,0 +1,24 @@
package com.ltkj.tduck.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ltkj.tduck.domain.UserFormViewCountEntity;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
/**
 * 用户表单查看次数Mapper接口
 *
 * @author tduck
 * @date 2023-04-04 21:29:39
 */
public interface UserFormViewCountMapper extends BaseMapper<UserFormViewCountEntity> {
    /**
     * 查看次数自增
     *
     * @param formKey 表单key
     */
    @Update("update fm_user_form_view_count set count = count + 1 , update_time=now() where form_key = #{formKey}")
    void incrementCount(@Param("formKey") String formKey);
}
ltkj-system/src/main/java/com/ltkj/tduck/request/CheckWritePwdRequest.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class CheckWritePwdRequest {
    @NotBlank
    private String formKey;
    @NotBlank
    private String password;
}
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormItemRequest.java
New file
@@ -0,0 +1,25 @@
package com.ltkj.tduck.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
 * @author : smalljop
 * @description : 查询表单问题
 * @create :  2021/06/03 14:45
 **/
@Data
public class QueryFormItemRequest {
    /**
     * 表单key
     */
    @NotBlank
    private String key;
    /**
     * 是显示类型
     */
    private Boolean displayType;
}
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormRequest.java
New file
@@ -0,0 +1,53 @@
package com.ltkj.tduck.request;
import cn.hutool.core.date.DatePattern;
import com.ltkj.tduck.domain.PageRequest;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
/**
 * @author : smalljop
 * @description : 查询表单
 * @create : 2020-12-10 15:04
 **/
@Data
public class QueryFormRequest {
    @Data
    public static class List {
        private Integer status;
    }
    /**
     * 分页查询
     */
    @Data
    public static class Page extends PageRequest {
        private Long folderId;
        private Integer type;
        private Integer status;
        private String name;
        /**
         * 是否包含文件夹
         */
        private Boolean folder;
        @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
        private LocalDateTime beginDateTime;
        @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
        private LocalDateTime endDateTime;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormResultRequest.java
New file
@@ -0,0 +1,60 @@
package com.ltkj.tduck.request;
import cn.hutool.core.date.DatePattern;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldNameConstants;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.List;
/**
 * @author : smalljop
 * @description : 表单结果查询
 * @create : 2020-12-08 15:55
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
public class QueryFormResultRequest {
    /**
     * 当前页
     */
    private Integer current;
    /**
     * 大小
     */
    private Integer size;
    /**
     * 固定字段
     */
    @NotBlank
    private String formKey;
    @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
    private LocalDateTime beginDateTime;
    @DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
    private LocalDateTime endDateTime;
    /**
     * 被查询的字段
     */
    private String[] filterFields;
    /**
     * 数据id 集合
     */
    private List<String> dataIds;
    private Long inCode;
}
ltkj-system/src/main/java/com/ltkj/tduck/request/QueryFormTemplateTypeRequest.java
New file
@@ -0,0 +1,18 @@
package com.ltkj.tduck.request;
import lombok.Data;
/**
 * @author : smalljop
 * @description : 查询表单模板分页
 * @create : 2020-12-10 15:04
 **/
@Data
public class QueryFormTemplateTypeRequest {
    @Data
    public static class List {
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/request/SortFormItemRequest.java
New file
@@ -0,0 +1,28 @@
package com.ltkj.tduck.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
 * @author : smalljop
 * @description : 排序表单项
 * @create : 2020-11-20 10:14
 **/
@Data
public class SortFormItemRequest {
    /**
     * 表单Id
     */
    @NotNull(message = "key请求异常")
    private String formKey;
    private Long beforePosition;
    private Long afterPosition;
    @NotBlank(message = "formItemId请求异常")
    private String formItemId;
}
ltkj-system/src/main/java/com/ltkj/tduck/service/FormTemplateCategoryService.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.FormTemplateCategoryEntity;
/**
 * 表单模板分类(FormTemplateType)表服务接口
 *
 * @author smalljop
 * @since 2021-01-06 10:51:06
 */
public interface FormTemplateCategoryService extends IService<FormTemplateCategoryEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/service/FormThemeService.java
New file
@@ -0,0 +1,56 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.FormThemeEntity;
/**
 * 表单主题外观模板(FormTheme)表服务接口
 *
 * @author smalljop
 * @since 2020-11-23 18:33:55
 */
public interface FormThemeService extends IService<FormThemeEntity> {
//    /**
//     * 获取主题分类
//     *
//     * @return
//     */
//    List<FormThemeCategoryEntity> listThemeCategories();
//
//    /**
//     * 获取表单分类
//     *
//     * @param categoryId
//     * @return
//     */
//    FormThemeCategoryEntity getThemeCategory(Long categoryId);
//
//    /**
//     * 保存主题分类
//     *
//     * @param entity
//     * @return
//     */
//    Boolean saveThemeCategory(FormThemeCategoryEntity entity);
//
//    /**
//     * 修改主题分类
//     *
//     * @param entity
//     * @return
//     */
//    Boolean updateThemeCategory(FormThemeCategoryEntity entity);
//
//    /**
//     * 删除主题分类
//     *
//     * @param categoryId
//     * @return
//     */
//    Boolean deleteThemeCategory(List<Long> categoryIds);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormDataService.java
New file
@@ -0,0 +1,69 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormDataEntity;
import com.ltkj.tduck.request.QueryFormResultRequest;
import com.ltkj.tduck.utils.Result;
import com.ltkj.tduck.vo.FormDataTableVO;
import java.util.Map;
/**
 * 表单表单项(FormResult)表服务接口
 *
 * @author smalljop
 * @since 2020-11-23 14:09:22
 */
public interface UserFormDataService extends IService<UserFormDataEntity> {
    /**
     * 保存结果
     *
     * @param entity 表单数据
     * @return 结果
     */
    Map<String, Object> saveFormResult(UserFormDataEntity entity);
//    /**
//     * 下载表单结果中的附件
//     *
//     * @param request 请求
//     * @return
//     */
//    Result downloadFormResultFile(QueryFormResultRequest request);
    /**
     * 查询表单数据
     *
     * @param request
     * @return
     */
    FormDataTableVO listFormDataTable(QueryFormResultRequest request);
//    /**
//     * 根据Id删除
//     *
//     * @param dataIdList
//     * @param formKey
//     * @return
//     */
//    Boolean deleteByIds(List<String> dataIdList, String formKey);
//
//    /**
//     * 修改
//     *
//     * @param entity
//     * @return
//     */
//    Boolean updateFormResult(UserFormDataEntity entity);
//
    /**
     * 获取数据详情
     *
     * @param dataId
     * @return
     */
    Result getFormDataDetails(String dataId);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormItemService.java
New file
@@ -0,0 +1,60 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormItemEntity;
import com.ltkj.tduck.vo.FormFieldVO;
import java.util.List;
/**
 * 表单表单项(FormItem)表服务接口
 *
 * @author smalljop
 * @since 2020-11-19 10:49:17
 */
public interface UserFormItemService extends IService<UserFormItemEntity> {
//    /**
//     * 根据key查询
//     *
//     * @param key
//     * @return
//     */
//    List<UserFormItemEntity> listByFormKey(String key);
//
    /**
     * 查询自定义字段
     *
     * @param formKey 表单key
     * @return 自定义字段
     */
    List<FormFieldVO> listFormFields(String formKey);
    /**
     * 查询全部字段 包含默认字段
     *
     * @param formKey 表单key
     * @return 自定义字段
     */
    List<FormFieldVO> listAllFormFields(String formKey);
    /**
     * 查询最后一个字段的排序值
     *
     * @param formKey 表单key
     * @return 排序值
     */
    Long getLastItemSort(String formKey);
//
    /**
     * 检查字段是否是需要特殊处理字段 比如随机编号
     *
     * @param userFormItemEntity 字段
     * @return true 需要特殊处理
     */
    Boolean isSpecialTypeItem(UserFormItemEntity userFormItemEntity);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormLogicService.java
New file
@@ -0,0 +1,7 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormLogicEntity;
public interface UserFormLogicService extends IService<UserFormLogicEntity> {
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormService.java
New file
@@ -0,0 +1,24 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormEntity;
/**
 * 表单表(Form)表服务接口
 *
 * @author smalljop
 * @since 2020-11-18 18:16:18
 */
public interface UserFormService extends IService<UserFormEntity> {
    /**
     * 根据key获取
     *
     * @param key key
     * @return UserFormEntity
     */
    UserFormEntity getByKey(final String key);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormSettingService.java
New file
@@ -0,0 +1,61 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormSettingEntity;
import com.ltkj.tduck.struct.FormSettingSchemaStruct;
import com.ltkj.tduck.utils.Result;
import java.util.Map;
/**
 * 表单设置
 *
 * @author smalljop
 * @since 2020-11-30 14:00:52
 */
public interface UserFormSettingService extends IService<UserFormSettingEntity> {
    /**
     * 保存表单设置
     */
    Boolean saveFormSetting(Map<String, Object> params);
    /**
     * 表单设置
     *
     * @param formKey 表单key
     * @return 设置项
     */
    UserFormSettingEntity getFormSettingByKey(String formKey);
    /**
     * 设置具体定义设置项
     *
     * @param formKey 表单key
     * @return 设置项
     */
    FormSettingSchemaStruct getFormSettingSchema(String formKey);
    /**
     * 获取当前项目设置的状态
     * 是否可以填写等
     *
     * @param formKey   表单key
     * @param requestIp 请求ip
     * @param wxOpenId  微信openid
     * @param type      类型 1公开填写 2.指定填写
     * @return 是否可以填写
     */
    Result<Boolean> getUserFormWriteSettingStatus(String formKey, String requestIp, String wxOpenId, Integer type);
    /**
     * 删除表单所有设置
     *
     * @param key 表单key
     * @return 是否删除成功
     */
    Boolean deleteAllSetting(String key);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormThemeService.java
New file
@@ -0,0 +1,21 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormThemeEntity;
/**
 * 表单表单项(UserFormTheme)表服务接口
 *
 * @author smalljop
 * @since 2020-11-25 13:36:31
 */
public interface UserFormThemeService extends IService<UserFormThemeEntity> {
    /**
     * 获取表单主题详情
     *
     * @param key
     * @return
     */
    UserFormThemeEntity getByKey(String key);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/UserFormViewCountService.java
New file
@@ -0,0 +1,27 @@
package com.ltkj.tduck.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ltkj.tduck.domain.UserFormViewCountEntity;
/**
 * 用户表单查看次数Service接口
 *
 * @author tduck
 * @date 2023-04-04 21:29:39
 */
public interface UserFormViewCountService extends IService<UserFormViewCountEntity> {
    /**
     * 查看次数自增
     *
     * @param formKey 表单key
     */
    void increment(String formKey);
    /**
     * 查看次数
     *
     * @param formKey 表单key
     */
    Long count(String formKey);
}
ltkj-system/src/main/java/com/ltkj/tduck/service/data/FormDataBaseService.java
New file
@@ -0,0 +1,135 @@
package com.ltkj.tduck.service.data;
import com.ltkj.tduck.request.QueryFormResultRequest;
import com.ltkj.tduck.vo.FormDataTableVO;
/**
 * @author : tduck
 * @description : 表单数据基础服务
 * @create :  2022/07/04 13:50
 **/
public abstract class FormDataBaseService {
    /***
     * 表单字段值是否存在
     * @param formKey 表单key
     * @param formItemId 表单字段id
     * @param value 字段值
     * @return true 存在 false 不存在
     */
    public abstract Boolean valueExist(String formKey, String formItemId, Object value);
    /**
     * 同步表单数据
     *
     * @param result 表单数据
     * @return 是否同步成功
     */
//    public abstract Boolean syncSaveData(UserFormDataEntity result);
//
//    /**
//     * 同步更新数据
//     *
//     * @param result 表单数据
//     */
//    public abstract Boolean asyncUpdateData(UserFormDataEntity result);
//
//    /**
//     * 删除表单数据
//     *
//     * @param idList  表单数据id列表
//     * @param formKey 表单key
//     */
//    public abstract void asyncDeleteData(List<String> idList, String formKey);
//
    /**
     * 查询表单数据
     *
     * @param request 查询内容
     */
    public abstract FormDataTableVO search(QueryFormResultRequest request);
//
//
//    /**
//     * 查询全部数据
//     */
//    public abstract List<Map> searchAll(QueryFormResultRequest request);
//
//
//    /**
//     * 构造时间范围查询
//     *
//     * @param condition 条件
//     * @return 时间范围
//     */
//    protected Map<String, DateTime> getRangDateTime(FormDataFilterStruct.Condition condition) {
//        if (ObjectUtil.isNull(condition.getValue())) {
//            return null;
//        }
//        DateTime beginDate = null;
//        DateTime endDate = null;
//        TimeRangeEnum timeRangeEnum = TimeRangeEnum.valueOf(condition.getValue().toString());
//        switch (timeRangeEnum) {
//            case TODAY:
//                beginDate = DateUtil.beginOfDay(new Date());
//                endDate = DateUtil.endOfDay(new Date());
//                break;
//            case YESTERDAY:
//                beginDate = DateUtil.beginOfDay(DateUtil.yesterday());
//                endDate = DateUtil.endOfDay(DateUtil.yesterday());
//                break;
//            case WEEK:
//                beginDate = DateUtil.beginOfWeek(new Date());
//                endDate = DateUtil.endOfWeek(new Date());
//                break;
//            case LAST_WEEK:
//                beginDate = DateUtil.beginOfWeek(DateUtil.lastWeek());
//                endDate = DateUtil.endOfWeek(DateUtil.lastWeek());
//                break;
//            case MONTH:
//                beginDate = DateUtil.beginOfMonth(new Date());
//                endDate = DateUtil.endOfMonth(new Date());
//                break;
//            case LAST_MONTH:
//                beginDate = DateUtil.beginOfMonth(DateUtil.lastMonth());
//                endDate = DateUtil.endOfMonth(DateUtil.lastMonth());
//                break;
//            case YEAR:
//                beginDate = DateUtil.beginOfYear(new Date());
//                endDate = DateUtil.endOfYear(new Date());
//                break;
//            case LAST_YEAR:
//                Date lastYear = DateUtil.offset(new Date(), DateField.YEAR, -1);
//                beginDate = DateUtil.beginOfYear(lastYear);
//                endDate = DateUtil.endOfYear(lastYear);
//                break;
//            default:
//                beginDate = DateUtil.date();
//                endDate = DateUtil.date();
//                break;
//        }
//        Map<String, DateTime> result = MapUtil.newHashMap();
//        result.put("beginDate", beginDate);
//        result.put("endDate", endDate);
//        return result;
//    }
//
//
//    public static Map<String, Object> convertDocument(UserFormDataEntity result) {
//        Map<String, Object> processData = result.getOriginalData();
//        Map<String, Object> resultMap = BeanUtil.beanToMap(result);
//        //格式化时间
//
////        resultMap.put(BaseEntity.Fields.updateTime, LocalDateTimeUtil.formatNormal(result.getUpdateTime()));
////        resultMap.put(BaseEntity.Fields.createTime, LocalDateTimeUtil.formatNormal(result.getCreateTime()));
//        resultMap.remove(UserFormDataEntity.Fields.originalData);
//        processData.putAll(resultMap);
//        processData.remove(SysBaseEntity.Fields.searchValue);
//        processData.remove(SysBaseEntity.Fields.params);
//        return processData;
//    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/data/FormDataMysqlService.java
New file
@@ -0,0 +1,139 @@
package com.ltkj.tduck.service.data;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ltkj.system.service.ISysConfigService;
import com.ltkj.tduck.domain.UserFormDataEntity;
import com.ltkj.tduck.mapper.UserFormDataMapper;
import com.ltkj.tduck.request.QueryFormResultRequest;
import com.ltkj.tduck.vo.FormDataTableVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @author : wangqing
 * @description : 表单数据基础服务
 * @create :  2022/07/04 14:25
 **/
@Service
@Slf4j
public class FormDataMysqlService extends FormDataBaseService {
    @Autowired
    private UserFormDataMapper userFormDataMapper;
    @Autowired
    private ISysConfigService configService;
//    @Autowired(required = false)
//    private TduckMongoTemplate mongoTemplate;
//
//
    @Override
    public Boolean valueExist(String formKey, String formItemId, Object value) {
        return userFormDataMapper.selectOriginalDataValueCount(formKey, formItemId, value) > 0;
    }
//
//    @Override
//    public Boolean syncSaveData(UserFormDataEntity result) {
//        if (null == mongoTemplate) {
//            return true;
//        }
//        mongoTemplate.save(convertDocument(result), result.getFormKey());
//        return true;
//    }
//
//
//    @Override
//    public Boolean asyncUpdateData(UserFormDataEntity result) {
//        if (null == mongoTemplate) {
//            return true;
//        }
//        mongoTemplate.updateById(convertDocument(result), result.getId(), result.getFormKey());
//        return true;
//    }
//
//    @Override
//    public void asyncDeleteData(List<String> idList, String formKey) {
//        if (null == mongoTemplate) {
//            return;
//        }
//        mongoTemplate.deleteByIds(idList, formKey);
//    }
    @Override
    public FormDataTableVO search(QueryFormResultRequest request) {
        // 拼接sql
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder.append("select * from fm_user_form_data where form_key = '").append(request.getFormKey()).append("'");
        //1. 拼接条件 查询条件 用大括号包起来 里面的条件会拼接 OR 或者 AND 不能影响其他默认附带条件 比如form_key 否则会错误查询
        StringBuilder whereBuilder = new StringBuilder();
        // 查询指定id数据
        if (ObjectUtil.isNotNull(request.getDataIds()) && 0 != request.getDataIds().size()) {
            whereBuilder.append(" and id in (").append(CollUtil.join(request.getDataIds(), ",")).append(")");
        }
        // 先查询总数,查询总数后再进行拼接order by 及 limit 语句
        StringBuilder countBuilder = new StringBuilder("select count(1) from fm_user_form_data where form_key = '").append(request.getFormKey()).append("'");
        countBuilder.append(whereBuilder);
        Long total = userFormDataMapper.selectCountBySql(countBuilder.toString());
        whereBuilder.append(" ORDER BY id DESC");
        // 分页
        if (ObjectUtil.isNotNull(request.getCurrent()) && ObjectUtil.isNotNull(request.getSize())) {
            whereBuilder.append(" limit ").append(request.getCurrent() * request.getSize()).append(",").append(request.getSize());
        }
        sqlBuilder.append(whereBuilder);
        List<UserFormDataEntity> userFormDataEntities = userFormDataMapper.selectRowsBySql(sqlBuilder.toString());
        // 过滤指定字段
        List<Map> maps = expandData(userFormDataEntities, request.getFilterFields());
        return new FormDataTableVO(maps, total);
    }
//    @Override
//    public List<Map> searchAll(QueryFormResultRequest request) {
//        // 拼接sql
//        List<UserFormDataEntity> userFormDataEntities = userFormDataMapper.selectRowsBySql("select * from fm_user_form_data where form_key = '" + request.getFormKey() + "'");
//        return expandData(userFormDataEntities, null);
//    }
    /**
     * 展开数据为一级
     */
    public List<Map> expandData(List<UserFormDataEntity> userFormDataEntities, String[] filterFields) {
        return userFormDataEntities.stream().map(item -> {
            Map<String, Object> processData = item.getOriginalData();
            Map<String, Object> resultMap = BeanUtil.beanToMap(item);
            resultMap.remove(UserFormDataEntity.Fields.originalData);
//            resultMap.put(BaseEntity.Fields.createTime, LocalDateTimeUtil.formatNormal(item.getCreateTime()));
//            resultMap.put(BaseEntity.Fields.updateTime, LocalDateTimeUtil.formatNormal(item.getUpdateTime()));
            processData.putAll(resultMap);
            // 只过滤指定字段
            if (filterFields != null) {
                Map<String, Object> filterMap = MapUtil.newHashMap();
                for (String filterField : filterFields) {
                    filterMap.put(filterField, processData.get(filterField));
                }
                return filterMap;
            }
            return processData;
        }).collect(Collectors.toList());
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/FormTemplateCategoryServiceImpl.java
New file
@@ -0,0 +1,18 @@
package com.ltkj.tduck.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.FormTemplateCategoryEntity;
import com.ltkj.tduck.mapper.FormTemplateCategoryMapper;
import com.ltkj.tduck.service.FormTemplateCategoryService;
import org.springframework.stereotype.Service;
/**
 * 表单模板分类(FormTemplateType)表服务实现类
 *
 * @author smalljop
 * @since 2021-01-06 10:51:06
 */
@Service
public class FormTemplateCategoryServiceImpl extends ServiceImpl<FormTemplateCategoryMapper, FormTemplateCategoryEntity> implements FormTemplateCategoryService {
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/FormThemeServiceImpl.java
New file
@@ -0,0 +1,46 @@
package com.ltkj.tduck.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.FormThemeEntity;
import com.ltkj.tduck.mapper.FormThemeMapper;
import com.ltkj.tduck.service.FormThemeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
 * 表单主题外观模板(FormTheme)表服务实现类
 *
 * @author smalljop
 * @since 2020-11-23 18:33:56
 */
@Service
@RequiredArgsConstructor
public class FormThemeServiceImpl extends ServiceImpl<FormThemeMapper, FormThemeEntity> implements FormThemeService {
//    private final FormThemeCategoryMapper formThemeCategoryMapper;
//
//    @Override
//    public List<FormThemeCategoryEntity> listThemeCategories() {
//        return formThemeCategoryMapper.selectList(null);
//    }
//
//    @Override
//    public FormThemeCategoryEntity getThemeCategory(Long categoryId) {
//        return formThemeCategoryMapper.selectById(categoryId);
//    }
//
//    @Override
//    public Boolean saveThemeCategory(FormThemeCategoryEntity entity) {
//        return formThemeCategoryMapper.insert(entity) > 0;
//    }
//
//    @Override
//    public Boolean updateThemeCategory(FormThemeCategoryEntity entity) {
//        return formThemeCategoryMapper.updateById(entity) > 0;
//    }
//
//    @Override
//    public Boolean deleteThemeCategory(List<Long> categoryIds) {
//        return formThemeCategoryMapper.deleteBatchIds(categoryIds) > 0;
//    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormDataServiceImpl.java
New file
@@ -0,0 +1,159 @@
package com.ltkj.tduck.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.common.utils.ip.AddressUtils;
import com.ltkj.tduck.constant.CommonConstants;
import com.ltkj.tduck.domain.UserFormDataEntity;
import com.ltkj.tduck.mapper.UserFormDataMapper;
import com.ltkj.tduck.request.QueryFormResultRequest;
import com.ltkj.tduck.service.UserFormDataService;
import com.ltkj.tduck.service.UserFormItemService;
import com.ltkj.tduck.utils.CacheUtils;
import com.ltkj.tduck.utils.FormDataUtils;
import com.ltkj.tduck.utils.Result;
import com.ltkj.tduck.vo.FormDataTableVO;
import com.ltkj.tduck.vo.FormFieldVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.ltkj.tduck.constant.FormRedisKeyConstants.FORM_RESULT_NUMBER;
/**
 * 表单表单项(FormResult)表服务实现类
 *
 * @author smalljop
 * @since 2020-11-23 14:09:22
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserFormDataServiceImpl extends ServiceImpl<UserFormDataMapper, UserFormDataEntity> implements UserFormDataService {
    private final UserFormItemService userFormItemService;
    private final CacheUtils redisUtils;
    private final FormDataUtils formDataUtils;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> saveFormResult(UserFormDataEntity entity) {
        HashMap<String, Object> result = MapUtil.newHashMap();
        String formKey = entity.getFormKey();
        entity.setSubmitAddress(AddressUtils.getRealAddressByIP(entity.getSubmitRequestIp()));
        entity.setSerialNumber(redisUtils.incr(StrUtil.format(FORM_RESULT_NUMBER, formKey), CommonConstants.ConstantNumber.ONE));
        this.save(entity);
//        formDataUtils.syncSaveFormData(entity);
        result.put("id", entity.getId());
        return result;
    }
    /**
     * 下载表单结果中的附件
     *
     * @param request
     * @return
     */
//    @Override
//    public Result downloadFormResultFile(QueryFormResultRequest request) {
//        String uuid = IdUtil.simpleUUID();
//        List<UserFormItemEntity> userFormItemEntityList = userFormItemService.list(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, request.getFormKey()).in(UserFormItemEntity::getType, CollUtil.newArrayList(FormItemTypeEnum.UPLOAD.toString(), FormItemTypeEnum.IMAGE_UPLOAD.toString())));
//        //结果
//        List<Map> rows = null;
//        if (ObjectUtil.isNull(request.getCurrent()) && ObjectUtil.isNull(request.getSize())) {
//            rows = formDataUtils.searchAll(request);
//        } else {
//            FormDataTableVO formDataTableVO = this.listFormDataTable(request);
//            rows = formDataTableVO.getRows();
//        }
//        if (CollectionUtil.isEmpty(rows) || CollectionUtil.isEmpty(userFormItemEntityList)) {
//            return Result.failed("暂无收集附件,无法下载");
//        }
//        List<Map> finalRows = rows;
//        ThreadUtil.execAsync(() -> {
//            TimeInterval timer = DateUtil.timer();
//            List<String> paths = new ArrayList<>();
//            List<InputStream> ins = new ArrayList<>();
//            try {
//                finalRows.forEach(result -> {
//                    int index = 0;
//                    userFormItemEntityList.forEach(item -> {
//                        List<UploadResultStruct> uploadResults = JsonUtils.jsonToList(JsonUtils.objToJson(MapUtil.get(result, item.getFormItemId(), List.class)), UploadResultStruct.class);
//                        if (CollectionUtil.isNotEmpty(uploadResults)) {
//                            uploadResults.forEach(uFile -> {
//                                if (StrUtil.isNotBlank(uFile.getUrl())) {
//                                    paths.add(FileNameUtil.getName(uFile.getUrl()));
//                                    byte[] bytes = HttpUtil.downloadBytes(uFile.getUrl());
//                                    ins.add(IoUtil.toStream(bytes));
//                                }
//                            });
//                        }
//                    });
//                    AsyncProcessUtils.setProcess(uuid, ++index / finalRows.size());
//                });
//                // 压缩上传oss
//                ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
//                ZipUtil.zip(zipOutputStream, paths.toArray(new String[]{}), ins.toArray(new InputStream[]{}));
//                String downloadUrl = OssStorageFactory.getStorageService().upload(zipOutputStream.toByteArray(), StorageUtils.generateFileName("download", ".zip"));
//                AsyncProcessUtils.setProcess(uuid, downloadUrl);
//                log.info("export file cost time: {}", timer.interval());
//            } catch (Exception e) {
//                log.error("download file", e);
//            }
//        });
//        return Result.success(uuid);
//    }
//
//
    @Override
    public FormDataTableVO listFormDataTable(QueryFormResultRequest request) {
        return formDataUtils.search(request);
    }
//
//
//    @Override
//    public Boolean deleteByIds(List<String> dataIdList, String formKey) {
//        baseMapper.deleteBatchIds(dataIdList);
//        formDataUtils.asyncDeleteEsDocument(dataIdList, formKey);
//        return true;
//    }
//
//    @Override
//    public Boolean updateFormResult(UserFormDataEntity entity) {
//        UserFormDataEntity dataEntity = this.getById(entity.getId());
//        dataEntity.setOriginalData(entity.getOriginalData());
//        dataEntity.setUpdateBy(entity.getUpdateBy());
//        boolean update = this.updateById(dataEntity);
//        // 查询数据 同步到es 避免数据变空被覆盖
//        formDataUtils.asyncUpdateEsDocument(dataEntity);
//        return update;
//    }
    @Override
    public Result getFormDataDetails(String dataId) {
        Map<String, Object> result =new HashMap<>();
        UserFormDataEntity dataEntity = this.getById(dataId);
        List<FormFieldVO> formFields = userFormItemService.listFormFields(dataEntity.getFormKey());
        // 表单字段
        result.put("formFields", formFields);
        // 表单填写数据
        if (ObjectUtil.isNotNull(dataEntity)) {
            Map<String, Object> originalData = dataEntity.getOriginalData();
            dataEntity.setOriginalData(null);
            originalData.putAll(BeanUtil.beanToMap(dataEntity, false, true));
            result.put("formData", originalData);
        }
        return Result.success(result);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormItemServiceImpl.java
New file
@@ -0,0 +1,105 @@
package com.ltkj.tduck.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.UserFormEntity;
import com.ltkj.tduck.domain.UserFormItemEntity;
import com.ltkj.tduck.enums.FormItemTypeEnum;
import com.ltkj.tduck.mapper.UserFormItemMapper;
import com.ltkj.tduck.service.UserFormItemService;
import com.ltkj.tduck.service.UserFormService;
import com.ltkj.tduck.struct.CheckboxSchemaStruct;
import com.ltkj.tduck.struct.InputResultStruct;
import com.ltkj.tduck.utils.FormDataUtils;
import com.ltkj.tduck.vo.FormFieldVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
 * 表单表单项(FormItem)表服务实现类
 *
 * @author smalljop
 * @since 2020-11-19 10:49:18
 */
@Service
@RequiredArgsConstructor
public class UserFormItemServiceImpl extends ServiceImpl<UserFormItemMapper, UserFormItemEntity> implements UserFormItemService {
    private final UserFormService userFormService;
//    @Override
//    public List<UserFormItemEntity> listByFormKey(String key) {
//        List<UserFormItemEntity> list = this.list(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, key));
//        list.sort(Comparator.comparing(UserFormItemEntity::getSort));
//        return list;
//    }
//
    @Override
    public List<FormFieldVO> listFormFields(String formKey) {
        List<UserFormItemEntity> itemEntityList = this.list(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, formKey).eq(UserFormItemEntity::getDisplayType, 0));
        itemEntityList.sort(Comparator.comparing(UserFormItemEntity::getSort));
        // FormFieldVO 处理了部份组价默认显示label字段
        List<FormFieldVO> fields = itemEntityList.stream().map(FormFieldVO::new).collect(Collectors.toList());
        return fields;
    }
    @Override
    public List<FormFieldVO> listAllFormFields(String formKey) {
        // 查询表单类型
        UserFormEntity userFormEntity = userFormService.getByKey(formKey);
        List<FormFieldVO> fields = this.listFormFields(formKey);
        FormDataUtils.addFormDefaultDataField(userFormEntity, fields);
        return fields;
    }
    @Override
    public Long getLastItemSort(String formKey) {
        List<UserFormItemEntity> formItemEntityPage = baseMapper.selectList(
                Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, formKey)
                        .orderByDesc(UserFormItemEntity::getSort));
        // 去取第一个元素
        UserFormItemEntity first = CollUtil.getFirst(formItemEntityPage);
        return ObjectUtil.isNull(first) ? 0 : first.getSort();
    }
    @Override
    public Boolean isSpecialTypeItem(UserFormItemEntity userFormItemEntity) {
        // 随机编号
        if (userFormItemEntity.getType() == FormItemTypeEnum.RANDOM_NUMBER) {
            return true;
        }
        // 不允许重复
        if (userFormItemEntity.getType() == FormItemTypeEnum.INPUT) {
            InputResultStruct builder = InputResultStruct.builder(userFormItemEntity.getScheme());
            return builder.isNotRepeat();
        }
        // 商品
        if (userFormItemEntity.getType() == FormItemTypeEnum.GOODS_SELECT) {
            return true;
        }
        // 预约时间
        if (userFormItemEntity.getType() == FormItemTypeEnum.RESERVE_DAY || userFormItemEntity.getType() == FormItemTypeEnum.RESERVE_TIME_RANGE) {
            return true;
        }
        // 投票
        if (userFormItemEntity.getType() == FormItemTypeEnum.CHECKBOX || userFormItemEntity.getType() == FormItemTypeEnum.RADIO || userFormItemEntity.getType() == FormItemTypeEnum.IMAGE_SELECT) {
            CheckboxSchemaStruct builder = CheckboxSchemaStruct.builder(userFormItemEntity.getScheme());
            // 单选多选带名额
            if (builder.getConfig().getOptions().stream().anyMatch(item -> ObjectUtil.isNotNull(item.getQuotaSetting()))) {
                return true;
            }
            return builder.getConfig().isShowVoteResult();
        }
        return false;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormLogicServiceImpl.java
New file
@@ -0,0 +1,14 @@
package com.ltkj.tduck.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.UserFormLogicEntity;
import com.ltkj.tduck.mapper.UserFormLogicMapper;
import com.ltkj.tduck.service.UserFormLogicService;
import org.springframework.stereotype.Service;
/**
 * 表单逻辑
 */
@Service
public class UserFormLogicServiceImpl extends ServiceImpl<UserFormLogicMapper, UserFormLogicEntity> implements UserFormLogicService {
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormServiceImpl.java
New file
@@ -0,0 +1,29 @@
package com.ltkj.tduck.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.UserFormEntity;
import com.ltkj.tduck.mapper.UserFormMapper;
import com.ltkj.tduck.service.UserFormService;
import org.springframework.stereotype.Service;
/**
 * 表单主表(Form)表服务实现类
 *
 * @author smalljop
 * @since 2020-11-18 18:16:18
 */
@Service
public class UserFormServiceImpl extends ServiceImpl<UserFormMapper, UserFormEntity> implements UserFormService {
    @Override
    public UserFormEntity getByKey(final String key) {
        if (StrUtil.isBlank(key)) {
            return null;
        }
        return this.getOne(Wrappers.<UserFormEntity>lambdaQuery().eq(UserFormEntity::getFormKey, key));
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormSettingServiceImpl.java
New file
@@ -0,0 +1,194 @@
package com.ltkj.tduck.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.common.utils.SecurityUtils;
import com.ltkj.tduck.constant.CommonConstants;
import com.ltkj.tduck.domain.UserFormDataEntity;
import com.ltkj.tduck.domain.UserFormEntity;
import com.ltkj.tduck.domain.UserFormSettingEntity;
import com.ltkj.tduck.enums.FormStatusEnum;
import com.ltkj.tduck.mapper.UserFormSettingMapper;
import com.ltkj.tduck.service.UserFormDataService;
import com.ltkj.tduck.service.UserFormService;
import com.ltkj.tduck.service.UserFormSettingService;
import com.ltkj.tduck.struct.FormSettingSchemaStruct;
import com.ltkj.tduck.utils.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
 * 表单表单项(UserFormSetting)表服务实现类
 *
 * @author smalljop
 * @since 2020-11-30 14:00:53
 */
@Service
@RequiredArgsConstructor
public class UserFormSettingServiceImpl extends ServiceImpl<UserFormSettingMapper, UserFormSettingEntity> implements UserFormSettingService {
    private final UserFormService userFormService;
    private final UserFormDataService userFormDataService;
    @Override
    public Boolean saveFormSetting(Map<String, Object> params) {
        String formKey = params.get("formKey").toString();
        UserFormSettingEntity entity = this.getOne(Wrappers.<UserFormSettingEntity>lambdaQuery().eq(UserFormSettingEntity::getFormKey, formKey));
        if (ObjectUtil.isNull(entity)) {
            UserFormSettingEntity setting = new UserFormSettingEntity();
            setting.setFormKey(formKey);
            setting.setSettings(params);
            return this.save(setting);
        }
        Map<String, Object> settings = entity.getSettings();
        settings.putAll(params);
        entity.setSettings(settings);
        return this.updateById(entity);
    }
    @Override
    public UserFormSettingEntity getFormSettingByKey(String formKey) {
        return this.getOne(Wrappers.<UserFormSettingEntity>lambdaQuery().eq(UserFormSettingEntity::getFormKey, formKey));
    }
    @Override
    public FormSettingSchemaStruct getFormSettingSchema(String formKey) {
        UserFormSettingEntity settingEntity = getFormSettingByKey(formKey);
        if (ObjectUtil.isNull(settingEntity)) {
            return null;
        }
        return BeanUtil.toBean(settingEntity.getSettings(), FormSettingSchemaStruct.class);
    }
    @Override
    public Result<Boolean> getUserFormWriteSettingStatus(String formKey, String requestIp, String wxOpenId, Integer type) {
        UserFormEntity userFormEntity = userFormService.getByKey(formKey);
        boolean checkPublish = Objects.equals(type, CommonConstants.ConstantNumber.ONE) &&
                (ObjectUtil.isNull(userFormEntity) || userFormEntity.getStatus() != 2);
        // 非公开填写 不校验发布状态
        if (checkPublish) {
            return Result.success(null, "表单暂时无法填写");
        }
        UserFormSettingEntity settingEntity = getFormSettingByKey(formKey);
        if (ObjectUtil.isNull(settingEntity)) {
            return Result.success(true);
        }
        FormSettingSchemaStruct settingSchemaStruct = BeanUtil.toBean(settingEntity.getSettings(), FormSettingSchemaStruct.class);
        // 填写时间限制
        boolean writeInterviewTime = isWriteInterviewTime(settingSchemaStruct);
        if (!writeInterviewTime) {
            return Result.success(null, StrUtil.blankToDefault(settingSchemaStruct.getWriteInterviewTimeText(), "不在答题时间范围内,有问题请与表单发布者联系"));
        }
        // 每个微信答题次数限制
        if (settingSchemaStruct.isWxWriteCountLimitStatus()) {
            LambdaQueryWrapper<UserFormDataEntity> wrapper = Wrappers.<UserFormDataEntity>lambdaQuery().eq(UserFormDataEntity::getFormKey, formKey).eq(UserFormDataEntity::getWxOpenId, wxOpenId);
            String rangeTypeSql = FormSettingSchemaStruct.DateRangeType.getDateSql(settingSchemaStruct.getWxWriteCountLimitDateType());
            wrapper.apply(StrUtil.isNotBlank(rangeTypeSql), rangeTypeSql);
            long writeCount = userFormDataService.count(wrapper);
            if (writeCount >= settingSchemaStruct.getWxWriteCountLimit()) {
                return Result.success(null, StrUtil.blankToDefault(settingSchemaStruct.getWxWriteCountLimitText(), "该微信已经提交过数据,不可重复提交,有问题请与表单发布者联系"));
            }
        }
        // 每个IP答题次数限制
        if (settingSchemaStruct.isIpWriteCountLimitStatus()) {
            LambdaQueryWrapper<UserFormDataEntity> wrapper = Wrappers.<UserFormDataEntity>lambdaQuery().eq(UserFormDataEntity::getFormKey, formKey).eq(UserFormDataEntity::getSubmitRequestIp, requestIp);
            String rangeTypeSql = FormSettingSchemaStruct.DateRangeType.getDateSql(settingSchemaStruct.getIpWriteCountLimitDateType());
            wrapper.apply(StrUtil.isNotBlank(rangeTypeSql), rangeTypeSql);
            long writeCount = userFormDataService.count(wrapper);
            if (writeCount >= settingSchemaStruct.getIpWriteCountLimit()) {
                return Result.success(null, StrUtil.blankToDefault(settingSchemaStruct.getIpWriteCountLimitText(), "该IP已经提交过数据,不可重复提交,有问题请与表单发布者联系"));
            }
        }
        // 总答题次数限制
        if (settingSchemaStruct.isTotalWriteCountLimitStatus()) {
            LambdaQueryWrapper<UserFormDataEntity> wrapper = Wrappers.<UserFormDataEntity>lambdaQuery().eq(UserFormDataEntity::getFormKey, formKey);
            String rangeTypeSql = FormSettingSchemaStruct.DateRangeType.getDateSql(settingSchemaStruct.getTotalWriteCountLimitDateType());
            wrapper.apply(StrUtil.isNotBlank(rangeTypeSql), rangeTypeSql);
            long writeCount = userFormDataService.count(wrapper);
            if (writeCount >= settingSchemaStruct.getTotalWriteCountLimit()) {
                return Result.success(null, StrUtil.blankToDefault(settingSchemaStruct.getTotalWriteCountLimitText(), "该表单收集数据已经达到上限,有问题请与表单发布者联系"));
            }
        }
        // 每个账号答题次数限制
        if (settingSchemaStruct.isAccountWriteCountLimitStatus()) {
            LambdaQueryWrapper<UserFormDataEntity> wrapper = Wrappers.<UserFormDataEntity>lambdaQuery().eq(UserFormDataEntity::getFormKey, formKey)
                    .eq(UserFormDataEntity::getCreateBy, SecurityUtils.getUserId());
            String rangeTypeSql = FormSettingSchemaStruct.DateRangeType.getDateSql(settingSchemaStruct.getAccountWriteCountLimitDateType());
            wrapper.apply(StrUtil.isNotBlank(rangeTypeSql), rangeTypeSql);
            long writeCount = userFormDataService.count(wrapper);
            if (writeCount >= settingSchemaStruct.getAccountWriteCountLimit()) {
                return Result.success(null, StrUtil.blankToDefault(settingSchemaStruct.getAccountWriteCountLimitText(), "该账号已经提交过数据,不可重复提交,有问题请与表单发布者联系"));
            }
        }
        return Result.success(true);
    }
    /**
     * 是否在设置的答题时间内
     *
     * @return true 在答题时间内
     */
    private boolean isWriteInterviewTime(FormSettingSchemaStruct settingSchemaStruct) {
        // 答题时间限制
        if (settingSchemaStruct.isWriteInterviewTimeStatus()) {
            // 是否每天时间范围限制
            if (settingSchemaStruct.isWriteInterviewDayTimeStatus()) {
                // 是否在允许访问的天内
                List<String> writeInterviewDateRange = settingSchemaStruct.getWriteInterviewDateRange();
                if (CollUtil.isEmpty(writeInterviewDateRange) || DateUtil.isIn(DateUtil.date(), DateUtil.parse(writeInterviewDateRange.get(0)), DateUtil.parse(writeInterviewDateRange.get(1)))) {
                    // 是否在允许访问的小时内
                    List<String> writeInterviewTimeRange = settingSchemaStruct.getWriteInterviewTimeRange();
                    LocalTime now = LocalTime.now();
                    boolean isRange = CollUtil.isNotEmpty(writeInterviewDateRange) && now.isBefore(LocalTime.parse(writeInterviewTimeRange.get(0))) || now.isAfter(LocalTime.parse(writeInterviewTimeRange.get(1)));
                    if (isRange) {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                // 是否在允许访问的天内
                List<String> writeInterviewDateTimeRange = settingSchemaStruct.getWriteInterviewDateTimeRange();
                if (CollUtil.isNotEmpty(writeInterviewDateTimeRange) && !DateUtil.isIn(DateUtil.date(), DateUtil.parse(writeInterviewDateTimeRange.get(0)), DateUtil.parse(writeInterviewDateTimeRange.get(1)))) {
                    return false;
                }
            }
            // 是否是每周允许访问的周几
            List<String> writeInterviewTimeWhichDays = settingSchemaStruct.getWriteInterviewTimeWhichDays();
            if (CollUtil.isNotEmpty(writeInterviewTimeWhichDays)) {
                // 获取今天是每周的第几天
                int day = DateUtil.dayOfWeek(DateUtil.date());
                return writeInterviewTimeWhichDays.contains(String.valueOf(day));
            }
        }
        return true;
    }
    /**
     * 删除全部的表单数据
     *
     * @param formKey 表单key
     * @return 删除结果
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public Boolean deleteAllSetting(String formKey) {
        this.remove(Wrappers.<UserFormSettingEntity>lambdaQuery().eq(UserFormSettingEntity::getFormKey, formKey));
        return true;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormThemeServiceImpl.java
New file
@@ -0,0 +1,27 @@
package com.ltkj.tduck.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.UserFormThemeEntity;
import com.ltkj.tduck.mapper.UserFormThemeMapper;
import com.ltkj.tduck.service.UserFormThemeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
 * 项目表单项(UserFormTheme)表服务实现类
 *
 * @author smalljop
 * @since 2020-11-25 13:36:32
 */
@Service
@RequiredArgsConstructor
public class UserFormThemeServiceImpl extends ServiceImpl<UserFormThemeMapper, UserFormThemeEntity> implements UserFormThemeService {
    @Override
    public UserFormThemeEntity getByKey(String key) {
        UserFormThemeEntity userFormThemeEntity = this.getOne(Wrappers.<UserFormThemeEntity>lambdaQuery().eq(UserFormThemeEntity::getFormKey, key));
        return userFormThemeEntity;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/service/impl/UserFormViewCountServiceImpl.java
New file
@@ -0,0 +1,29 @@
package com.ltkj.tduck.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltkj.tduck.domain.UserFormViewCountEntity;
import com.ltkj.tduck.mapper.UserFormViewCountMapper;
import com.ltkj.tduck.service.UserFormViewCountService;
import org.springframework.stereotype.Service;
/**
 * 用户表单查看次数Service业务层处理
 *
 * @author tduck
 * @date 2023-04-04 21:29:39
 */
@Service
public class UserFormViewCountServiceImpl extends ServiceImpl<UserFormViewCountMapper, UserFormViewCountEntity> implements UserFormViewCountService {
    @Override
    public void increment(String formKey) {
        baseMapper.incrementCount(formKey);
    }
    @Override
    public Long count(String formKey) {
        UserFormViewCountEntity viewCount = baseMapper.selectOne(Wrappers.<UserFormViewCountEntity>lambdaQuery().eq(UserFormViewCountEntity::getFormKey, formKey));
        return viewCount == null ? 0 : viewCount.getCount();
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/struct/CheckboxSchemaStruct.java
New file
@@ -0,0 +1,37 @@
package com.ltkj.tduck.struct;
import com.ltkj.tduck.utils.JsonUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
 * @author : smalljop
 * @description : 选项结构
 * @create :  2021/06/07 16:37
 **/
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CheckboxSchemaStruct {
    private Config config;
    @Data
    public static class Config extends OptionQuotaListStruct{
        private boolean showVoteResult;
    }
    public static CheckboxSchemaStruct builder(Map<String, Object> params) {
        return JsonUtils.objToObj(params, CheckboxSchemaStruct.class);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/struct/FormDataFilterStruct.java
New file
@@ -0,0 +1,118 @@
package com.ltkj.tduck.struct;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * @author : wangqing
 * @description : 数据过滤对象结构
 * @create :  2021/10/13 14:49
 **/
@Data
public class FormDataFilterStruct {
    /**
     * or and 逻辑连接符号
     */
    RelEnum rel;
    /**
     * 过滤条件
     */
    List<Condition> conditionList;
    @Getter
    @AllArgsConstructor
    public enum QueryMethodEnum {
        /**
         * 等于
         */
        EQ,
        /**
         * 不等于
         */
        NE,
        /**
         * 包含
         */
        INCLUDE,
        /**
         * 不包含
         */
        NOT_INCLUDE,
        /**
         * 为空
         */
        IS_NULL,
        /**
         * 不为空
         */
        NOT_NULL,
        /**
         * ;
         * 大于
         */
        GT,
        /**
         * ;
         * 大于等于
         */
        GE,
        /**
         * 小于
         */
        LT,
        /**
         * 小于等于
         */
        LE,
        /**
         * 范围
         */
        RANGE,
        /**
         * 时间范围
         */
        TIME_RANGE;
    }
    /**
     * 默认值类型枚举
     */
    public enum DefaultValueTypeEnum {
        /**
         * 字符串
         */
        STRING,
        /***
         * 数组
         */
        ARRAY
    }
    /**
     * 默认值类型枚举
     */
    public enum RelEnum {
        AND,
        OR
    }
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    // 忽略前端传的未定义参数
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Condition {
        private String formItemId;
        private QueryMethodEnum method;
        private Object value;
        private DefaultValueTypeEnum defaultValueType;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/struct/FormSettingSchemaStruct.java
New file
@@ -0,0 +1,78 @@
package com.ltkj.tduck.struct;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @author : tduck
 * @description : 设置结构定义
 * @create :  2021/06/07 16:37
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FormSettingSchemaStruct extends WriteSettingSchemaStruct {
    /**
     * 自定义显示类型 1 系统默认 2 自定义页面 使用submitShowCustomPageContent内容
     */
    private int submitShowType;
    /**
     * 自定义显示内容
     */
    private String submitShowCustomPageContent;
    private boolean submitJump;
    private String submitJumpUrl;
    /**
     * 显示分享图片
     */
    private boolean shareWxImg;
    /**
     * 分享图片地址
     */
    private String shareWxImgUrl;
    /**
     * 显示分享标题
     */
    private boolean shareWxTitle;
    /**
     * 分享标题内容
     */
    private String shareWxTitleContent;
    /**
     * 开启分享描述
     */
    private boolean shareWxDesc;
    /**
     * 分享描述内容
     */
    private String shareWxDescContent;
    /**
     * 开启邮件通知
     */
    @JsonIgnore
    private boolean emailNotify;
    /**
     * 邮件通知账号
     */
    @JsonIgnore
    private String newWriteNotifyEmail;
    @JsonIgnore
    private boolean wxNotify;
    @JsonIgnore
    private String newWriteNotifyWx;
    /**
     * 公开回复
     */
    private boolean openReply;
}
ltkj-system/src/main/java/com/ltkj/tduck/struct/InputResultStruct.java
New file
@@ -0,0 +1,29 @@
package com.ltkj.tduck.struct;
import com.ltkj.tduck.utils.JsonUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
 * @author : smalljop
 * @description : 上传收集结果
 * @create :  2021/06/07 16:37
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class InputResultStruct {
    /**
     * 不允许重复
     */
    private boolean notRepeat;
    public static InputResultStruct builder(Map<String, Object> params) {
        return JsonUtils.objToObj(params, InputResultStruct.class);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/struct/OptionQuotaListStruct.java
New file
@@ -0,0 +1,52 @@
package com.ltkj.tduck.struct;
import lombok.Data;
import java.util.List;
/**
 * @author : tduck
 * @description :
 * @create :  2022/09/26 16:14
 **/
@Data
public class OptionQuotaListStruct {
    private List<Option> options;
    /**
     * 剩余名额为0时,显示文案
     */
    private String quotaBlankWarning;
    /**
     * 名额重置
     */
    private String quotaCycleRule;
    public enum QuotaCycleRule {
        /**
         * 不重置
         */
        FIXED,
        /**
         * 每天
         */
        PER_DAY,
        /**
         * 每周
         */
        PER_WEEK;
    }
    @Data
    public static class Option {
        private String label;
        private String value;
        private Integer quotaSetting;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/struct/WriteSettingSchemaStruct.java
New file
@@ -0,0 +1,239 @@
package com.ltkj.tduck.struct;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
/**
 * @author : tduck
 * @description : 设置结构定义  @JsonIgnore 不给前端返回的字段添加这个
 * @create :  2021/06/07 16:37
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WriteSettingSchemaStruct {
    /**
     * 仅在微信填写
     */
    private boolean onlyWxWrite;
    /**
     * 记录微信用户信息
     */
    private boolean recordWxUser;
    /**
     * 本地保存未提交数据
     */
    private boolean saveSubmitStatus;
    /**
     * 本地保存未提交数据
     */
    private boolean saveNotSubmitStatus;
    /**
     * 开启密码填写
     */
    private boolean passwordWriteStatus;
    /**
     * 填写密码
     */
    @JsonIgnore
    private String writePassword;
    /**
     * 开启每个微信答题次数限制
     */
    @JsonIgnore
    private boolean wxWriteCountLimitStatus;
    /**
     * 每个微信答题次数限制次数
     */
    @JsonIgnore
    private int wxWriteCountLimit = 1;
    /**
     * 开启每个微信答题时间限制类型 具体查看DateRangeTypeEnum
     */
    @JsonIgnore
    private int wxWriteCountLimitDateType = 1;
    /**
     * 开启每个微信答题时间限制显示文案
     */
    @JsonIgnore
    private String wxWriteCountLimitText;
    /**
     * 每个IP答题次数限制
     */
    @JsonIgnore
    private boolean ipWriteCountLimitStatus;
    /**
     * 每个IP答题次数限制次数
     */
    @JsonIgnore
    private int ipWriteCountLimit = 1;
    /**
     * 开启每个IP答题时间限制类型 具体查看DateRangeTypeEnum
     */
    @JsonIgnore
    private int ipWriteCountLimitDateType = 1;
    /**
     * 开启每个IP答题时间限制显示文案
     */
    @JsonIgnore
    private String ipWriteCountLimitText;
    /**
     * 每个账号答题限制
     */
    @JsonIgnore
    private boolean accountWriteCountLimitStatus;
    /**
     * 每个IP答题次数限制次数
     */
    @JsonIgnore
    private int accountWriteCountLimit = 1;
    /**
     * 开启每个账号答题时间限制类型 具体查看DateRangeTypeEnum
     */
    @JsonIgnore
    private int accountWriteCountLimitDateType = 1;
    /**
     * 开启每个账号答题时间限制显示文案
     */
    @JsonIgnore
    private String accountWriteCountLimitText;
    /**
     * 每个设备答题限制
     */
    private boolean deviceWriteCountLimitStatus;
    /**
     * 每个设备答题次数限制次数
     */
    private int deviceWriteCountLimit = 1;
    /**
     * 每个设备答题文案
     */
    private String deviceWriteCountLimitText;
    /**
     * 累计答题数量
     */
    @JsonIgnore
    private boolean totalWriteCountLimitStatus;
    /**
     * 次数
     */
    @JsonIgnore
    private int totalWriteCountLimit = 1;
    /**
     * 累计答题日期范围类型
     */
    @JsonIgnore
    private int totalWriteCountLimitDateType = 1;
    /**
     * 累计答题日期范围显示文案
     */
    @JsonIgnore
    private String totalWriteCountLimitText;
    /**
     * 开启答题时间限制
     */
    @JsonIgnore
    private boolean writeInterviewTimeStatus;
    /**
     * 访问时间是否是一天内的某些小时
     */
    @JsonIgnore
    private boolean writeInterviewDayTimeStatus;
    /**
     * 允许访问访问时间范围
     */
    @JsonIgnore
    private List<String> writeInterviewDateTimeRange;
    /**
     * 允许访问访问日期范围
     */
    @JsonIgnore
    private List<String> writeInterviewDateRange;
    /**
     * 允许访问访问时间范围
     */
    @JsonIgnore
    private List<String> writeInterviewTimeRange;
    /**
     * 允许访问访问时间范围显示文案
     */
    @JsonIgnore
    private List<String> writeInterviewTimeWhichDays;
    /**
     * 不允许访问访问时间范围显示文案
     */
    @JsonIgnore
    private String writeInterviewTimeText;
    @AllArgsConstructor
    public static enum DateRangeType {
        /**
         * 总共
         */
        SUM(1),
        /**
         * 每天
         */
        DAY(2),
        /**
         * 每周
         */
        WEEK(3),
        /**
         * 每月
         */
        MONTH(4);
        @Getter
        private final int value;
        /**
         * 获取对应的日期范围类型
         *
         * @param value 值
         * @return 日期范围类型sql
         */
        public static String getDateSql(int value) {
            Date now = new Date();
            String sql = " create_time>='{}' and create_time<='{}'";
            for (DateRangeType type : DateRangeType.values()) {
                if (type.getValue() == value) {
                    switch (type) {
                        case DAY:
                            return StrUtil.format(sql, DateUtil.beginOfDay(now), DateUtil.endOfDay(now));
                        case WEEK:
                            return StrUtil.format(sql, DateUtil.beginOfWeek(now), DateUtil.endOfWeek(now));
                        case MONTH:
                            return StrUtil.format(sql, DateUtil.beginOfMonth(now), DateUtil.endOfMonth(now));
                        default:
                            return "";
                    }
                }
            }
            throw new IllegalArgumentException("不支持的日期范围类型");
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/CacheUtils.java
New file
@@ -0,0 +1,133 @@
package com.ltkj.tduck.utils;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * @author : tduck
 * @description : 基于ehcache实现
 * @create :  2022/01/06 10:40
 **/
@Component
@Slf4j
@EnableCaching
public class CacheUtils {
    private final String ETERNAL_CACHE_NAME = "eternal_cache";
    private final String TEMP_CACHE_NAME = "temp_cache";
    @Autowired
    private EhCacheCacheManager cacheManager;
    /**
     * 保存到Cache
     */
    public void save(String key, String value) {
        cacheManager.getCache(ETERNAL_CACHE_NAME).put(key, value);
    }
    /**
     * 获取
     *
     * @param key
     */
    public String get(String key) {
        Cache.ValueWrapper valueWrapper = cacheManager.getCache(ETERNAL_CACHE_NAME).get(key);
        if (ObjectUtil.isNotNull(valueWrapper) && ObjectUtil.isNotNull(valueWrapper.get())) {
            return valueWrapper.get().toString();
        }
        return null;
    }
    /**
     * 自增
     *
     * @param key
     * @param number
     * @return
     */
    public Long incr(String key, Integer number) {
        String v = get(key);
        if (StrUtil.isBlank(v)) {
            v = "0";
        }
        long finalValue = Convert.toLong(v) + number;
        save(key, String.valueOf(finalValue));
        return finalValue;
    }
    /**
     * 添加到集合缓存
     *
     * @param key
     * @param value
     */
    public void addList(String key, Object value) {
        List coll = this.getList(key, Object.class);
        coll.add(value);
        cacheManager.getCache(TEMP_CACHE_NAME).put(key, JsonUtils.objToJson(coll));
    }
    /**
     * 从集合中移除
     *
     * @param key
     * @param value
     */
    public void removeList(String key, Object value) {
        List coll = this.getList(key, Object.class);
        coll.remove(value);
        cacheManager.getCache(TEMP_CACHE_NAME).put(key, JsonUtils.objToJson(coll));
    }
    /**
     * 获取集合
     *
     * @param key
     */
    public List getList(String key, Class classz) {
        String v = get(key);
        if (ObjectUtil.isNotNull(v)) {
            return JsonUtils.jsonToList(v, classz.getClass());
        }
        return Lists.newArrayList();
    }
    /**
     * 临时保存 默认5min
     */
    public void tempSave(String key, String value) {
        cacheManager.getCache(TEMP_CACHE_NAME).put(key, value);
    }
    /**
     * 获取临时存储变量
     *
     * @param key
     */
    public String getTemp(String key) {
        Cache.ValueWrapper valueWrapper = cacheManager.getCache(TEMP_CACHE_NAME).get(key);
        if (ObjectUtil.isNotNull(valueWrapper) && ObjectUtil.isNotNull(valueWrapper.get())) {
            return valueWrapper.get().toString();
        }
        return null;
    }
    public void removeTemp(String key) {
        cacheManager.getCache(TEMP_CACHE_NAME).evict(key);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/FormDataUtils.java
New file
@@ -0,0 +1,144 @@
package com.ltkj.tduck.utils;
import cn.hutool.core.collection.CollUtil;
import com.ltkj.tduck.domain.SysBaseEntity;
import com.ltkj.tduck.domain.TBaseEntity;
import com.ltkj.tduck.domain.UserFormDataEntity;
import com.ltkj.tduck.domain.UserFormEntity;
import com.ltkj.tduck.enums.FormItemTypeEnum;
import com.ltkj.tduck.request.QueryFormResultRequest;
import com.ltkj.tduck.service.data.FormDataBaseService;
import com.ltkj.tduck.vo.FormDataTableVO;
import com.ltkj.tduck.vo.FormFieldVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
 * @author : tduck
 * @description : 表单收集结果工具类
 * @create :  2021/08/18 18:17
 **/
@Slf4j
@Component
@RequiredArgsConstructor
public class FormDataUtils {
    /**
     * 特殊字段 会多出一个xxx label字段存放显示值 默认字段存放原始值
     */
    public static final List<FormItemTypeEnum> specialFields = CollUtil.newArrayList(FormItemTypeEnum.SELECT, FormItemTypeEnum.IMAGE_SELECT, FormItemTypeEnum.CHECKBOX, FormItemTypeEnum.RADIO, FormItemTypeEnum.CASCADER);
    private final static String FIELD_USER_TYPE = "USER";
    private final FormDataBaseService formDataBaseService;
    /**
     * 添加表单基础数据字段
     * 所有表单都包含的字段
     */
    public static void addFormBaseDataField(List<FormFieldVO> fields) {
        fields.add(new FormFieldVO(UserFormDataEntity.Fields.serialNumber, "提交序号", UserFormDataEntity.Fields.serialNumber));
        fields.add(new FormFieldVO(UserFormDataEntity.Fields.extValue, "扩展字段", FormItemTypeEnum.INPUT.toString()));
        fields.add(new FormFieldVO(SysBaseEntity.Fields.updateBy, "修改用户", FIELD_USER_TYPE));
        fields.add(new FormFieldVO(SysBaseEntity.Fields.createBy, "提交用户", FIELD_USER_TYPE));
        fields.add(new FormFieldVO(TBaseEntity.Fields.createTime, "提交时间", FormItemTypeEnum.DATE.toString()));
        fields.add(new FormFieldVO(TBaseEntity.Fields.updateTime, "修改时间", FormItemTypeEnum.DATE.toString()));
    }
    /**
     * 添加系统默认字段
     */
    public static void addFormDefaultDataField(UserFormEntity entity, List<FormFieldVO> fields) {
        addFormBaseDataField(fields);
    }
    /***
     * 表单字段值是否存在
     * @param formKey 表单key
     * @param formItemId 表单字段id
     * @param value 字段值
     */
//    public Boolean valueExist(String formKey, String formItemId, Object value) {
//        return formDataBaseService.valueExist(formKey, formItemId, value);
//    }
    /**
     * 特殊字段添加复合字段
     */
//    public List<String> concatSpecialField(List<String> fields) {
//        List<String> newFields = CollUtil.newArrayList("id");
//        if (CollUtil.isEmpty(fields)) {
//            return newFields;
//        }
//        fields.forEach(field -> {
//            newFields.add(field);
//            boolean isSpecialField = StrUtil.startWithAny(field, specialFields.stream().map(item -> item.toString().toLowerCase()).collect(Collectors.joining(",")));
//            if (isSpecialField) {
//                newFields.add(field + "label");
//            }
//        });
//        return newFields;
//    }
    /**
     * 保存数据到其他数据库 比如es MonggDB等 用来扩展查询 作报表等
     */
//    public Boolean syncSaveFormData(UserFormDataEntity result) {
//        return formDataBaseService.syncSaveData(result);
//    }
    /**
     * 更新文档
     *
     * @param result
     */
//    public void asyncUpdateEsDocument(UserFormDataEntity result) {
//        formDataBaseService.asyncUpdateData(result);
//    }
    /**
     * 删除索引文档
     *
     * @param idList  doc Id
     * @param formKey index
     */
//    public void asyncDeleteEsDocument(List<String> idList, String formKey) {
//        formDataBaseService.asyncDeleteData(idList, formKey);
//    }
    /**
     * 查询表单分页数据
     *
     * @param request 查询参数
     * @return 表单分页数据
     */
    public FormDataTableVO search(QueryFormResultRequest request) {
        return formDataBaseService.search(request);
    }
    /**
     * 全部数据
     *
     * @param request 请求
     * @return 表单数据
     */
//    public List<Map> searchAll(QueryFormResultRequest request) {
//        return formDataBaseService.searchAll(request);
//    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/HtmlUtils.java
New file
@@ -0,0 +1,20 @@
package com.ltkj.tduck.utils;
import cn.hutool.http.HtmlUtil;
import lombok.experimental.UtilityClass;
@UtilityClass
public class HtmlUtils extends HtmlUtil {
    /**
     * 清除标签 还原转义文本
     * @param content
     * @return
     */
    public static String cleanHtmlTag(String content) {
        // 清除HTML标签和空格 html编码解码
        return HtmlUtil.unescape(content).replaceAll("(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)", "").replaceAll(NBSP, "");
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/IDictEnum.java
New file
@@ -0,0 +1,43 @@
package com.ltkj.tduck.utils;
import com.baomidou.mybatisplus.annotation.IEnum;
import java.io.Serializable;
/**
 * @author : wangqing
 * @description : 字典枚举基础接口
 * 继承该接口会在jackson默认增强显示字段
 * @create :  2021/12/21 10:19
 **/
public interface IDictEnum<T extends Serializable> extends IEnum<T> {
    static <T extends IDictEnum> T getInstance(Class<T> clazz, String code) {
        T[] constants = clazz.getEnumConstants();
        for (T t : constants) {
            if (String.valueOf(t.getValue()).equals(code)) {
                return t;
            }
        }
        return null;
    }
    /**
     * 数据库中存储的值
     *
     * @return 数据库中存储的值
     */
    @Override
    T getValue();
    /**
     * 获取枚举描述
     *
     * @return 描述
     */
    String getDesc();
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/JsonUtils.java
New file
@@ -0,0 +1,276 @@
package com.ltkj.tduck.utils;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @author smalljop
 * @description: json工具类 使用jackson
 * @create: 2018-10-23 10:21
 **/
public class JsonUtils {
    private final static ObjectMapper objectMapper = new ObjectMapper();
    static {
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.registerModule(new JavaTimeModule());
    }
    private JsonUtils() {
    }
    /**
     * 获取objectMapper实例
     */
    public static ObjectMapper getInstance() {
        return objectMapper;
    }
    /**
     * javaBean、列表数组转换为json字符串
     */
    public static String objToJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * javaBean、列表数组转换为json字符串,忽略空值
     */
    public static String objToJsonIgnoreNull(Object obj) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        return mapper.writeValueAsString(obj);
    }
    /**
     * json 转对象
     */
    public static <T> T jsonToObj(String jsonString, Class<T> clazz) {
        if (StrUtil.isBlank(jsonString)) {
            return null;
        }
        //允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //接受只有一个元素的数组的反序列化
        objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        try {
            return objectMapper.readValue(jsonString, clazz);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }
    /**
     * json字符串转换为map
     */
    public static <T> Map<String, Object> jsonToMap(String jsonString) {
        if (StrUtil.isBlank(jsonString)) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        try {
            return mapper.readValue(jsonString, Map.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }
    public static <T> JsonNode jsonToJsonNode(String jsonString) {
        if (StrUtil.isBlank(jsonString)) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        try {
            return mapper.readValue(jsonString, JsonNode.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * json字符串转换为map
     */
    public static <T> Map<String, T> jsonToMap(String jsonString, Class<T> clazz) throws Exception {
        Map<String, Map<String, Object>> map = (Map<String, Map<String, Object>>) objectMapper.readValue(jsonString, new TypeReference<Map<String, T>>() {
        });
        Map<String, T> result = new HashMap<String, T>();
        for (Map.Entry<String, Map<String, Object>> entry : map.entrySet()) {
            result.put(entry.getKey(), mapToObj(entry.getValue(), clazz));
        }
        return result;
    }
    /**
     * 深度转换json成map
     *
     * @param json
     * @return
     */
    public static Map<String, Object> jsonToMapDeeply(String json) throws Exception {
        return jsonToMapRecursion(json, objectMapper);
    }
    /**
     * 把json解析成list,如果list内部的元素存在jsonString,继续解析
     *
     * @param json
     * @param mapper 解析工具
     * @return
     * @throws Exception
     */
    private static List<Object> jsonToListRecursion(String json, ObjectMapper mapper) throws Exception {
        if (json == null) {
            return null;
        }
        List<Object> list = mapper.readValue(json, List.class);
        for (Object obj : list) {
            if (obj != null && obj instanceof String) {
                String str = (String) obj;
                if (str.startsWith("[")) {
                    obj = jsonToListRecursion(str, mapper);
                } else if (obj.toString().startsWith("{")) {
                    obj = jsonToMapRecursion(str, mapper);
                }
            }
        }
        return list;
    }
    /**
     * 把json解析成map,如果map内部的value存在jsonString,继续解析
     *
     * @param json
     * @param mapper
     * @return
     * @throws Exception
     */
    private static Map<String, Object> jsonToMapRecursion(String json, ObjectMapper mapper) throws Exception {
        if (json == null) {
            return null;
        }
        Map<String, Object> map = mapper.readValue(json, Map.class);
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object obj = entry.getValue();
            if (obj != null && obj instanceof String) {
                String str = ((String) obj);
                if (str.startsWith("[")) {
                    List<?> list = jsonToListRecursion(str, mapper);
                    map.put(entry.getKey(), list);
                } else if (str.startsWith("{")) {
                    Map<String, Object> mapRecursion = jsonToMapRecursion(str, mapper);
                    map.put(entry.getKey(), mapRecursion);
                }
            }
        }
        return map;
    }
    /**
     * 与javaBean json数组字符串转换为列表
     */
    public static <T> List<T> jsonToList(String jsonArrayStr, Class<T> clazz) {
        JavaType javaType = getCollectionType(ArrayList.class, clazz);
        List<T> lst = null;
        try {
            lst = objectMapper.readValue(jsonArrayStr, javaType);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return lst;
    }
    /**
     * 获取泛型的Collection Type
     *
     * @param collectionClass 泛型的Collection
     * @param elementClasses  元素类
     * @return JavaType Java类型
     * @since 1.0
     */
    public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }
    /**
     * map  转JavaBean
     */
    public static <T> T mapToObj(Map map, Class<T> clazz) {
        return objectMapper.convertValue(map, clazz);
    }
    /**
     * map 转json
     *
     * @param map
     * @return
     */
    public static String mapToJson(Map map) {
        try {
            return objectMapper.writeValueAsString(map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
    /**
     * map  转JavaBean
     */
    public static <T> T objToObj(Object obj, Class<T> clazz) {
        return objectMapper.convertValue(obj, clazz);
    }
    /**
     * 是否是json格式
     */
    public static boolean isJson(String json) {
        try {
            if(StrUtil.isBlank(json)){
                return false;
            }
            objectMapper.readTree(json);
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/LongToStringSerializer.java
New file
@@ -0,0 +1,34 @@
package com.ltkj.tduck.utils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
 * @author : wangqing
 * @description : Long转string 避免返回前端丢失精度
 * @create :  2022/03/10 15:07
 **/
public class LongToStringSerializer extends JsonSerializer<Long> {
    /**
     * Method that can be called to ask implementation to serialize
     * values of type this serializer handles.
     *
     * @param value       Value to serialize; can <b>not</b> be null.
     * @param gen         Generator used to output resulting Json content
     * @param serializers Provider that can be used to get serializers for
     */
    @Override
    public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value != null && value.toString().length() > 16) {
            gen.writeString(value.toString());
        } else {
            gen.writeNumber(value);
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/Result.java
New file
@@ -0,0 +1,89 @@
package com.ltkj.tduck.utils;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ltkj.tduck.constant.ResponseCodeConstants;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
 * 响应信息主体
 *
 * @param <T>
 * @author smalljop
 */
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
//@Schema(description = "响应信息主体")
public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    @Getter
    @Setter
//    @Schema(description = "返回标记:成功标记=200,失败标记=500")
    private int code = ResponseCodeConstants.SUCCESS;
    @Getter
    @Setter
//    @Schema(description = "返回信息")
    private String msg;
    @Getter
    @Setter
//    @Schema(description = "数据")
    private T data;
    public static <T> Result<T> success() {
        return restResult(null, ResponseCodeConstants.SUCCESS, null);
    }
    public static <T> Result<T> success(T data) {
        return restResult(data, ResponseCodeConstants.SUCCESS, null);
    }
    public static <T> Result<T> success(T data, String msg) {
        return restResult(data, ResponseCodeConstants.SUCCESS, msg);
    }
    public static <T> Result<T> isSuccess(boolean flag) {
        return flag ? success() : failed();
    }
    public static <T> Result<T> failed() {
        return restResult(null, ResponseCodeConstants.FAIL, null);
    }
    public static <T> Result<T> failed(int code, String msg) {
        return restResult(null, code, msg);
    }
    public static <T> Result<T> failed(String msg) {
        return restResult(null, ResponseCodeConstants.FAIL, msg);
    }
    public static <T> Result<T> failed(String msg, T data) {
        return restResult(data, ResponseCodeConstants.FAIL, msg);
    }
    public static <T> Result<T> restResult(T data, int code, String msg) {
        Result<T> apiResult = new Result<>();
        apiResult.setCode(code);
        apiResult.setData(data);
        apiResult.setMsg(msg);
        return apiResult;
    }
    @JsonIgnore
    public Boolean isDataNull() {
        return ObjectUtil.isNull(data);
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/ShortIdUtils.java
New file
@@ -0,0 +1,41 @@
package com.ltkj.tduck.utils;
import cn.hutool.core.util.RandomUtil;
import lombok.experimental.UtilityClass;
import java.util.HashMap;
import java.util.Map;
/**
 * 短Id工具类
 */
@UtilityClass
public class ShortIdUtils {
    /**
     * 默认随机字母表,使用URL安全的Base64字符
     */
    private static final char[] DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    /**
     * 生成8位长度Id
     *
     * @return
     */
    public String genId() {
//        return NanoId.randomNanoId(null, DEFAULT_ALPHABET, 8);
        return RandomUtil.randomString(8);
    }
    public static void main(String[] args) {
        Map<Object, Object> of = new HashMap<>();
        for (int i = 0; i < 100000 ;i++) {
            String s = genId();
            Object put = of.put(s, "1");
            if (null != put) {
                System.out.println(s);
            }
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/SortUtils.java
New file
@@ -0,0 +1,109 @@
package com.ltkj.tduck.utils;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ltkj.tduck.constant.FormRedisKeyConstants;
import com.ltkj.tduck.domain.UserFormItemEntity;
import com.ltkj.tduck.service.UserFormItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.Comparator;
import java.util.List;
/**
 * 两个前提:位置的信息记录在任务的模型上(pos字段);一般两个任务的pos值相差很大(默认是65536);现在假设有任务 A, B, C.
 * 列举几个常见的场景:如果C要移到A的前面, 那么后端会把 C.pos 改为 A.pos/2;若果C要移到A和B之间,
 * 那么后端会把 C.pos 改为 (A.pos + B.pos)/2;如果B要移到C的后面, 那么后端会把 B.pos 改为 C.pos + 65536;
 * 当然这里会有个极端情况需要处理(假设pos是整数):如果 A.pos 是 1, B.pos 是 2, C想移到A和B之间, 其实是没有一个整数可以用的,
 * 针对这种情况, 后端会重新给整个列表的任务重新刷一遍pos值.
 * <p>
 * 拖动排序工具类
 * 算法参考 @link https://www.zhihu.com/question/55789722
 *
 * @author smalljop
 */
@RequiredArgsConstructor
@Component
public class SortUtils {
    private final CacheUtils cacheUtils;
    /**
     * 排序默认自增因子
     */
    private final Long SORT_DEFAULT_INCR_FACT = 65536L;
    private final UserFormItemService formItemService;
    /**
     * 获取排序数值
     *
     * @param formKey 表单key
     * @return 初始排序数值
     */
    public Long getInitialSortPosition(String formKey) {
        String redisKey = StrUtil.format(FormRedisKeyConstants.FORM_ITEM_POS_DELTA, formKey);
        // 模板创建时 初始排序数值
        if (StrUtil.isBlank(cacheUtils.get(redisKey))) {
            Long sort = formItemService.getLastItemSort(formKey);
            cacheUtils.save(redisKey, String.valueOf(sort == null ? 1 : sort));
        }
        return cacheUtils.incr(redisKey, SORT_DEFAULT_INCR_FACT.intValue());
    }
    /**
     * * 两个前提:位置的信息记录在任务的模型上(pos字段);一般两个任务的pos值相差很大(默认是65536);现在假设有任务 A, B, C.
     * * 列举几个常见的场景:如果C要移到A的前面, 那么后端会把 C.pos 改为 A.pos/2;若果C要移到A和B之间,
     * * 那么后端会把 C.pos 改为 (A.pos + B.pos)/2;如果B要移到C的后面, 那么后端会把 B.pos 改为 C.pos + 65536;
     * * 当然这里会有个极端情况需要处理(假设pos是整数):如果 A.pos 是 1, B.pos 是 2, C想移到A和B之间, 其实是没有一个整数可以用的,
     * * 针对这种情况, 后端会重新给整个列表的任务重新刷一遍pos值.
     * 排序之后重新计算
     *
     * @param beforePosition 之前的位置
     * @param afterPosition  之后的位置
     * @param formKey        表单key
     * @return 最终位置
     */
    public Long calcSortPosition(Long beforePosition, Long afterPosition, String formKey) {
        String redisKey = StrUtil.format(FormRedisKeyConstants.FORM_ITEM_POS_DELTA, formKey);
        boolean isCenter = (ObjectUtil.isNotNull(beforePosition) && 0L != beforePosition) && (ObjectUtil.isNotNull(afterPosition) && 0L != afterPosition);
        if (isCenter) { // 放到中间
            return (beforePosition + afterPosition) / 2;
        }
        if (ObjectUtil.isNull(beforePosition) || 0L == beforePosition) { // 放到最前面
            return afterPosition / 2;
        } else { // 放到最后面
            return cacheUtils.incr(redisKey, SORT_DEFAULT_INCR_FACT.intValue());
        }
    }
    /**
     * 极端情况刷新整个列表
     *
     * @param beforePosition 之前的位置
     * @param afterPosition  之后的位置
     * @param formKey        表单key
     * @param sort           排序数值
     */
    public Boolean sortAllList(Long beforePosition, Long afterPosition, String formKey, Long sort) {
        // 即将没有整数,刷新全部列表排序值
        if ((ObjectUtil.isNotNull(beforePosition) && 0L != beforePosition && ObjectUtil.equal(sort, beforePosition + 1))
                || (ObjectUtil.isNotNull(afterPosition) && 0L != afterPosition && ObjectUtil.equal(sort, 1L))) {
            List<UserFormItemEntity> itemEntityList = formItemService.list(Wrappers.<UserFormItemEntity>lambdaQuery().eq(UserFormItemEntity::getFormKey, formKey));
            itemEntityList.sort(Comparator.comparing(UserFormItemEntity::getSort));
            for (int i = 0; i < itemEntityList.size(); i++) {
                itemEntityList.get(i).setSort(SORT_DEFAULT_INCR_FACT * (i + 1));
            }
            formItemService.updateBatchById(itemEntityList);
            return true;
        }
        return false;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/utils/ValidatorUtils.java
New file
@@ -0,0 +1,57 @@
package com.ltkj.tduck.utils;
import com.ltkj.common.exception.base.BaseException;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
/**
 * @description: hibernate 校验工具类
 * 不通过注解使用 通过工具类返回自定义结果
 * @author: smalljop
 * @create: 2018-10-12 10:20
 **/
public class ValidatorUtils {
    private static Validator validator;
    static {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }
    /**
     * 校验对象
     *
     * @param object 待校验对象
     * @param groups 待校验的组
     * @throws BaseException 校验不通过,BaseException
     */
    public static void validateEntity(Object object, Class<?>... groups)
            throws BaseException {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
        if (!constraintViolations.isEmpty()) {
            StringBuilder msg = new StringBuilder();
            for (ConstraintViolation<Object> constraint : constraintViolations) {
                msg.append(constraint.getMessage());
            }
            throw new BaseException(msg.toString());
        }
    }
    public static void validateEntity(Object object)
            throws BaseException {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object);
        if (!constraintViolations.isEmpty()) {
            StringBuilder msg = new StringBuilder();
            for (ConstraintViolation<Object> constraint : constraintViolations) {
                msg.append(constraint.getMessage()).append("<br>");
            }
            throw new BaseException(msg.toString());
        }
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/vo/FormDataTableVO.java
New file
@@ -0,0 +1,26 @@
package com.ltkj.tduck.vo;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
 * 表单数据表格
 */
@Data
@NoArgsConstructor
public class FormDataTableVO {
    /**
     * 数据列表
     */
    private List<Map> rows;
    private Long total;
    public FormDataTableVO(List<Map> rows, Long total) {
        this.rows = rows;
        this.total = total;
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/vo/FormFieldVO.java
New file
@@ -0,0 +1,64 @@
package com.ltkj.tduck.vo;
import cn.hutool.core.collection.CollUtil;
import com.ltkj.tduck.domain.UserFormItemEntity;
import com.ltkj.tduck.utils.FormDataUtils;
import com.ltkj.tduck.utils.HtmlUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import static com.ltkj.tduck.constant.FormConstants.FIELD_SUFFIX_LABEL;
/**
 * 表单字段类
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FormFieldVO {
    /**
     * 字段Id
     */
    protected String value;
    /**
     * 字段名称
     */
    protected String label;
    /**
     * 字段类型
     */
    protected String type;
    /**
     * 配置
     */
    protected Object scheme;
    public FormFieldVO(String value, String label) {
        this.value = value;
        // 清除html里面的标签
        this.label = HtmlUtils.cleanHtmlTag(label);
    }
    public FormFieldVO(String value, String label, String type) {
        this.value = value;
        this.label = HtmlUtils.cleanHtmlTag(label);
        this.type = type;
    }
    public FormFieldVO(UserFormItemEntity entity) {
        this.label = HtmlUtils.cleanHtmlTag(entity.getLabel());
        this.type = entity.getType().toString();
        this.value = entity.getFormItemId();
        //  选择型组件特殊处理
        if (CollUtil.contains(FormDataUtils.specialFields, entity.getType())) {
            this.value = entity.getFormItemId() + FIELD_SUFFIX_LABEL;
        }
        //获取配置项
        this.scheme = entity.getScheme();
    }
}
ltkj-system/src/main/java/com/ltkj/tduck/vo/OperateFormItemVO.java
New file
@@ -0,0 +1,37 @@
package com.ltkj.tduck.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * 操作返回数据
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateFormItemVO {
    /**
     * 排序号
     */
    private Long sort;
    /**
     * 数据Id
     */
    private Long itemDataId;
    /**
     * 操作是否成功
     */
    private Boolean operateSuccess;
    /**
     * 刷新全部
     */
    private Boolean refreshAll;
}
ltkj-system/src/main/java/com/ltkj/tduck/vo/UserFormDetailVO.java
New file
@@ -0,0 +1,62 @@
package com.ltkj.tduck.vo;
import com.ltkj.tduck.domain.UserFormEntity;
import com.ltkj.tduck.domain.UserFormItemEntity;
import com.ltkj.tduck.domain.UserFormLogicEntity;
import com.ltkj.tduck.domain.UserFormThemeEntity;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
/**
 * @author smalljop
 */
@Data
@AllArgsConstructor
public class UserFormDetailVO {
    /**
     * 表单基础信息
     */
    private UserForm form;
    /**
     * 表单项
     */
    private List<UserFormItemEntity> formItems;
    /**
     * 主题
     */
    private UserFormThemeEntity userFormTheme;
    /**
     * 逻辑
     */
    private UserFormLogicEntity formLogic;
    @Data
    public static class UserForm {
        private String formKey;
        /**
         * 表单名称
         */
        private String name;
        /**
         * 表单描述
         */
        private String description;
        private String type;
        public UserForm(UserFormEntity entity) {
            this.formKey = entity.getFormKey();
            this.name = entity.getName();
            this.description = entity.getDescription();
            this.type = entity.getType();
        }
    }
}