├── WebApp ├── js │ ├── edit.js │ ├── management.js │ ├── login.js │ ├── forgot-password.js │ └── signin.js ├── README.md ├── vue-formtools │ ├── .browserslistrc │ ├── babel.config.js │ ├── postcss.config.js │ ├── .prettierrc │ ├── src │ │ ├── assets │ │ │ ├── logo.png │ │ │ ├── img │ │ │ │ ├── img.jpg │ │ │ │ ├── images │ │ │ │ │ ├── sc.jpg │ │ │ │ │ ├── logo.jpg │ │ │ │ │ ├── sb1.jpg │ │ │ │ │ ├── sb2.jpg │ │ │ │ │ ├── sc1.png │ │ │ │ │ ├── sc2.png │ │ │ │ │ ├── sc3.png │ │ │ │ │ ├── sh1.jpg │ │ │ │ │ ├── sh2.jpg │ │ │ │ │ ├── sh3.jpg │ │ │ │ │ ├── sh4.png │ │ │ │ │ └── codescene1585214317966.jpg │ │ │ │ └── login-bg.jpg │ │ │ └── css │ │ │ │ ├── icon.css │ │ │ │ ├── theme-green │ │ │ │ ├── fonts │ │ │ │ │ ├── element-icons.ttf │ │ │ │ │ └── element-icons.woff │ │ │ │ └── color-green.css │ │ │ │ ├── color-dark.css │ │ │ │ └── main.css │ │ ├── components │ │ │ ├── common │ │ │ │ ├── bus.js │ │ │ │ ├── HeaderUserInfo.vue │ │ │ │ └── directives.js │ │ │ └── page │ │ │ │ ├── edit │ │ │ │ ├── EditPreview.vue │ │ │ │ └── EditHeader.vue │ │ │ │ ├── 404.vue │ │ │ │ ├── EditForm.vue │ │ │ │ └── FormDetails.vue │ │ ├── api │ │ │ └── index.js │ │ ├── App.vue │ │ ├── utils │ │ │ └── request.js │ │ ├── main.js │ │ └── router │ │ │ └── index.js │ ├── .gitignore │ ├── public │ │ ├── index.html │ │ └── table.json │ ├── package.json │ ├── vue.config.js │ └── LICENSE ├── images │ ├── sb1.jpg │ ├── sb2.jpg │ ├── sc.jpg │ ├── sc1.png │ ├── sc2.png │ ├── sc3.png │ ├── sh1.jpg │ ├── sh2.jpg │ ├── sh3.webp │ ├── sh4.png │ ├── 1587714918(1).png │ └── codescene1585214317966.jpg ├── css │ ├── login.css │ ├── PERSONAL.css │ ├── management.css │ ├── Home Page.css │ └── edit.css ├── management.html ├── notice.html ├── signin.html ├── forgot-password.html ├── login.html ├── PERSONAL.html └── Home Page.html ├── ProjectImage └── 通用表单工具.jpg ├── README.md ├── Server ├── lib │ └── yb │ │ └── OpenApi │ │ └── 1.0 │ │ └── YBOpenApi.jar ├── src │ ├── main │ │ ├── resources │ │ │ ├── static │ │ │ │ ├── images │ │ │ │ │ └── weixin │ │ │ │ │ │ └── acode.jpg │ │ │ │ ├── error │ │ │ │ │ └── 404.html │ │ │ │ └── index.html │ │ │ ├── application.properties │ │ │ ├── mapper │ │ │ │ ├── FillQuestionnaireMapper.xml │ │ │ │ ├── BuiltFormMapper.xml │ │ │ │ ├── DraftFormMapper.xml │ │ │ │ ├── UserMapper.xml │ │ │ │ └── FillRegistryMapper.xml │ │ │ └── sql │ │ │ │ └── formtools.sql │ │ └── java │ │ │ └── com │ │ │ └── formtools │ │ │ ├── service │ │ │ ├── OtherUserService.java │ │ │ ├── FillQuestionnaireService.java │ │ │ ├── FillRegistryService.java │ │ │ ├── BuiltFormService.java │ │ │ ├── DraftFormService.java │ │ │ ├── UserService.java │ │ │ └── impl │ │ │ │ ├── OtherUserServiceImpl.java │ │ │ │ ├── FillQuestionnaireServiceImpl.java │ │ │ │ ├── BuiltFormServiceImpl.java │ │ │ │ ├── DraftFormServiceImpl.java │ │ │ │ ├── FillRegistryServiceImpl.java │ │ │ │ └── FileServiceImpl.java │ │ │ ├── Exception │ │ │ └── ParamException.java │ │ │ ├── utils │ │ │ ├── CodeUtil.java │ │ │ ├── RestTemplateConfig.java │ │ │ ├── IdBuilder.java │ │ │ ├── CookieUtil.java │ │ │ ├── Examiner.java │ │ │ ├── ValidationUtil.java │ │ │ ├── WeiXinCodeUtil.java │ │ │ ├── EmailUtil.java │ │ │ ├── WeiXinTokenUtil.java │ │ │ └── JSONObjectTypeHandler.java │ │ │ ├── FormtoolsApplication.java │ │ │ ├── ServletInitializer.java │ │ │ ├── GlobalCorsConfig.java │ │ │ ├── mapper │ │ │ ├── BuiltFormMapper.java │ │ │ ├── DraftFormMapper.java │ │ │ ├── FillQuestionnaireMapper.java │ │ │ ├── UserMapper.java │ │ │ └── FillRegistryMapper.java │ │ │ ├── enums │ │ │ └── ErrorMsg.java │ │ │ ├── OtherConfig.java │ │ │ ├── model │ │ │ ├── EmailVerify.java │ │ │ ├── DraftForm.java │ │ │ ├── UserInfo.java │ │ │ ├── FillQuestionnaire.java │ │ │ ├── UserVerify.java │ │ │ ├── UserModel.java │ │ │ ├── FillRegistry.java │ │ │ └── BuiltForm.java │ │ │ ├── RedisAutoConfiguration.java │ │ │ ├── vo │ │ │ ├── WXToken.java │ │ │ ├── WeiXinUser.java │ │ │ ├── ResultVo.java │ │ │ ├── FillRegistryReq.java │ │ │ └── BuildFormReq.java │ │ │ ├── controller │ │ │ ├── FillQuestionnaireController.java │ │ │ ├── WeiXinLoginController.java │ │ │ └── YiBanLoginController.java │ │ │ └── Handler │ │ │ └── GlobalExceptionHandler.java │ └── test │ │ └── java │ │ └── com │ │ └── formtools │ │ ├── SendEmailTest.java │ │ ├── RedisTest.java │ │ ├── FillQuestionnaireMapperTests.java │ │ ├── FillRegistryMapperTests.java │ │ ├── BuiltFormMapperTests.java │ │ ├── DraftFormMapperTests.java │ │ └── UserModelMapperTests.java ├── .gitignore └── pom.xml └── .gitignore /WebApp/js/edit.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /WebApp/README.md: -------------------------------------------------------------------------------- 1 | 前端项目,独立部署 2 | 暂时使用原始模式开发,不使用vue cli -------------------------------------------------------------------------------- /WebApp/vue-formtools/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /WebApp/images/sb1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sb1.jpg -------------------------------------------------------------------------------- /WebApp/images/sb2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sb2.jpg -------------------------------------------------------------------------------- /WebApp/images/sc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sc.jpg -------------------------------------------------------------------------------- /WebApp/images/sc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sc1.png -------------------------------------------------------------------------------- /WebApp/images/sc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sc2.png -------------------------------------------------------------------------------- /WebApp/images/sc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sc3.png -------------------------------------------------------------------------------- /WebApp/images/sh1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sh1.jpg -------------------------------------------------------------------------------- /WebApp/images/sh2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sh2.jpg -------------------------------------------------------------------------------- /WebApp/images/sh3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sh3.webp -------------------------------------------------------------------------------- /WebApp/images/sh4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/sh4.png -------------------------------------------------------------------------------- /ProjectImage/通用表单工具.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/ProjectImage/通用表单工具.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /WebApp/images/1587714918(1).png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/1587714918(1).png -------------------------------------------------------------------------------- /WebApp/vue-formtools/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FormTools 2 | 通用表单工具。 3 | ![项目介绍图](https://github.com/MYvLiang/FormTools/raw/master/ProjectImage/通用表单工具.jpg) 4 | -------------------------------------------------------------------------------- /Server/lib/yb/OpenApi/1.0/YBOpenApi.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/Server/lib/yb/OpenApi/1.0/YBOpenApi.jar -------------------------------------------------------------------------------- /WebApp/images/codescene1585214317966.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/images/codescene1585214317966.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 140 6 | } -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/logo.png -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/img.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sc.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/login-bg.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/common/bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // 使用 Event Bus 4 | const bus = new Vue(); 5 | 6 | export default bus; -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/css/icon.css: -------------------------------------------------------------------------------- 1 | 2 | [class*=" el-icon-lx"], [class^=el-icon-lx] { 3 | font-family: lx-iconfont!important; 4 | } -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/logo.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sb1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sb1.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sb2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sb2.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sc1.png -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sc2.png -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sc3.png -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sh1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sh1.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sh2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sh2.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sh3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sh3.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/sh4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/sh4.png -------------------------------------------------------------------------------- /Server/src/main/resources/static/images/weixin/acode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/Server/src/main/resources/static/images/weixin/acode.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/img/images/codescene1585214317966.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/img/images/codescene1585214317966.jpg -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/css/theme-green/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/css/theme-green/fonts/element-icons.ttf -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/css/theme-green/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MYvLiang/FormTools/HEAD/WebApp/vue-formtools/src/assets/css/theme-green/fonts/element-icons.woff -------------------------------------------------------------------------------- /Server/src/main/resources/static/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 404 6 | 7 | 8 |

404

9 | 10 | -------------------------------------------------------------------------------- /Server/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | hello 9 | 10 | 11 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/api/index.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request'; 2 | 3 | export const fetchData = query => { 4 | return request({ 5 | url: './table.json', 6 | method: 'get', 7 | params: query 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/OtherUserService.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service; 2 | 3 | /** 4 | * @author myl 5 | * @create 2020-02-23 23:24 6 | */ 7 | public interface OtherUserService { 8 | Long updateUser(String nickname,String profile, String openid,Character type); 9 | } 10 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/Exception/ParamException.java: -------------------------------------------------------------------------------- 1 | package com.formtools.Exception; 2 | 3 | import java.util.Map; 4 | 5 | public class ParamException extends RuntimeException{ 6 | private Map map; 7 | 8 | public ParamException(Map map) { 9 | this.map = map; 10 | } 11 | 12 | public Map getMap() { 13 | return map; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | example.html 5 | favicon.ico 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw* 23 | package-lock.json -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/FillQuestionnaireService.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service; 2 | 3 | import com.formtools.model.FillQuestionnaire; 4 | import com.formtools.model.FillRegistry; 5 | 6 | public interface FillQuestionnaireService { 7 | boolean insertFillQuestionnaire(String key, FillQuestionnaire fillQuestionnaire); 8 | FillRegistry getFillQuestionnaireFromCache(String key); 9 | } 10 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/CodeUtil.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | public class CodeUtil { 4 | 5 | /** 6 | * @author NaNrailgun 7 | * 随机验证码生成 8 | * @return 验证码 9 | */ 10 | public static String createCode(){ 11 | StringBuffer stringBuffer=new StringBuffer(String.valueOf(System.currentTimeMillis())); 12 | return stringBuffer.substring(stringBuffer.length()-4); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/page/edit/EditPreview.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/FillRegistryService.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service; 2 | 3 | import com.formtools.model.BuiltForm; 4 | import com.formtools.model.FillRegistry; 5 | 6 | public interface FillRegistryService { 7 | BuiltForm getFormInfo(Long formId); 8 | String currentSaveAnswer(String key, FillRegistry fillRegistry); 9 | FillRegistry getAnswer(Long userId, Long formId, String key); 10 | boolean insertRegistry(FillRegistry fillRegistry,String key); 11 | } 12 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/FormtoolsApplication.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.spring4all.swagger.EnableSwagger2Doc; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @EnableSwagger2Doc 8 | @SpringBootApplication 9 | public class FormtoolsApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(FormtoolsApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/ServletInitializer.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class ServletInitializer extends SpringBootServletInitializer { 7 | 8 | @Override 9 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 10 | return application.sources(FormtoolsApplication.class); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !**/src/main/** 4 | !**/src/test/** 5 | !lib/** 6 | ### STS ### 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | .sts4-cache 14 | 15 | ### IntelliJ IDEA ### 16 | .idea 17 | *.iws 18 | *.iml 19 | *.ipr 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ 27 | build/ 28 | 29 | ### VS Code ### 30 | .vscode/ 31 | 32 | 33 | /.mvn/ 34 | /mvnw 35 | /mvnw.cmd 36 | formDataFile 37 | zipFile -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/BuiltFormService.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service; 2 | 3 | import com.formtools.model.BuiltForm; 4 | import com.formtools.model.DraftForm; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author myl 10 | * @create 2020-02-06 14:21 11 | */ 12 | public interface BuiltFormService { 13 | 14 | List findAllBuiltForms(Long userId); 15 | 16 | boolean releaseForm(BuiltForm builtForm); 17 | 18 | BuiltForm copyBuiltForm(Long formId); 19 | 20 | boolean deleteBuiltForm(Long formId,Long userId); 21 | } 22 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/css/color-dark.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #242f42; 3 | } 4 | .login-wrap{ 5 | background: #324157; 6 | } 7 | .plugins-tips{ 8 | background: #eef1f6; 9 | } 10 | .plugins-tips a{ 11 | color: #20a0ff; 12 | } 13 | .el-upload--text em { 14 | color: #20a0ff; 15 | } 16 | .pure-button{ 17 | background: #20a0ff; 18 | } 19 | .tags-li.active { 20 | border: 1px solid #409EFF; 21 | background-color: #409EFF; 22 | } 23 | .message-title{ 24 | color: #20a0ff; 25 | } 26 | .collapse-btn:hover{ 27 | background: rgb(40,52,70); 28 | } -------------------------------------------------------------------------------- /WebApp/js/management.js: -------------------------------------------------------------------------------- 1 | 2 | /*打开侧栏,修改侧栏宽度,主体左跨度、背景透明度*/ 3 | function openNav() { 4 | 5 | document.getElementById("mySidenav").style.width = "250px"; 6 | 7 | document.getElementById("main").style.marginLeft = "250px"; 8 | 9 | document.body.style.backgroundColor = "rgba(0,0,0,0.4)"; 10 | 11 | } 12 | 13 | /*关闭侧栏,恢复原始侧栏宽度,主体左跨度、背景透明度*/ 14 | 15 | function closeNav() { 16 | 17 | document.getElementById("mySidenav").style.width = "0"; 18 | 19 | document.getElementById("main").style.marginLeft= "0"; 20 | 21 | document.body.style.backgroundColor = "white"; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/GlobalCorsConfig.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 6 | 7 | /** 8 | * @author myl 9 | * @create 2020-04-02 23:32 10 | */ 11 | @Configuration 12 | public class GlobalCorsConfig implements WebMvcConfigurer { 13 | @Override 14 | public void addCorsMappings(CorsRegistry registry) { 15 | registry.addMapping("/**") 16 | .allowCredentials(true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/DraftFormService.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service; 2 | 3 | import com.formtools.model.DraftForm; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author myl 9 | * @create 2020-04-16 23:15 10 | */ 11 | public interface DraftFormService { 12 | 13 | List findAllDraftForms(Long userId); 14 | 15 | boolean addDraftForm(DraftForm draftForm); 16 | 17 | DraftForm getDraftForm(Long userId,Long formId); 18 | 19 | void saveForm(DraftForm draftForm); 20 | 21 | void saveDraft(DraftForm draftForm); 22 | 23 | boolean deleteDraft(Long formId,Long userId); 24 | } 25 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/RestTemplateConfig.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import org.springframework.http.client.SimpleClientHttpRequestFactory; 4 | import org.springframework.web.client.RestTemplate; 5 | 6 | /** 7 | * @author myl 8 | * @create 2020-02-25 23:19 9 | */ 10 | public class RestTemplateConfig { 11 | 12 | public static RestTemplate getRestTemplate() { 13 | SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); 14 | factory.setConnectTimeout(3000); 15 | factory.setReadTimeout(3000); 16 | return new RestTemplate(factory); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/mapper/BuiltFormMapper.java: -------------------------------------------------------------------------------- 1 | package com.formtools.mapper; 2 | 3 | import com.formtools.model.BuiltForm; 4 | import org.apache.ibatis.annotations.*; 5 | import java.util.List; 6 | 7 | /** 8 | * 增删查改用户创建的表单 9 | * @author myl 10 | * @create 2020-02-05 14:24 11 | */ 12 | @Mapper 13 | public interface BuiltFormMapper { 14 | 15 | int addBuiltForm(BuiltForm builtForm); 16 | 17 | BuiltForm getBuiltForm(Long formId); 18 | 19 | List findAllBuiltForm(Long userId); 20 | 21 | int updateBuiltForm(BuiltForm builtForm); 22 | 23 | int deleteBuiltForm(@Param("formId") Long formId, @Param("userId") Long userId); 24 | } 25 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 通用表单数据收集系统 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /WebApp/css/login.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fff; 3 | } 4 | .login-box{ 5 | width:20%; 6 | height:auto; 7 | //border: 2px solid rgba(17, 8, 22, 0.46); 8 | border-radius:30px; 9 | margin: 0 auto; 10 | margin-top: 15%; 11 | text-align: center; 12 | background: #fff; 13 | padding: 20px 50px; 14 | box-shadow: 0px 0px 5px 5px rgba(12, 43, 63, 0.43), 10px 10px 10px 10px rgba(255,255,255,0.5) 15 | } 16 | .login-box .form .item{ 17 | margin-top: 15px; 18 | } 19 | .login-box .form .item input{ 20 | border:2px solid #00000010; 21 | border-radius:5px; 22 | padding: 5px 10px; 23 | background: #ffffff00; 24 | color: #000000; 25 | } 26 | .login-box button{ 27 | width: 300px; 28 | } 29 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/mapper/DraftFormMapper.java: -------------------------------------------------------------------------------- 1 | package com.formtools.mapper; 2 | 3 | import com.formtools.model.DraftForm; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author myl 11 | * @create 2020-04-13 12:01 12 | */ 13 | @Mapper 14 | public interface DraftFormMapper { 15 | int addDraftForm(DraftForm draftForm); 16 | 17 | DraftForm getDraftForm(@Param("formId") Long formId, @Param("userId") Long userId); 18 | 19 | List findAllDraftForm(Long userId); 20 | 21 | int updateDraftForm(DraftForm draftForm); 22 | 23 | int deleteDraftForm(@Param("formId") Long formId, @Param("userId") Long userId); 24 | } 25 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-formtools", 3 | "version": "4.2.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "npm run serve", 7 | "serve": "vue-cli-service serve", 8 | "build": "vue-cli-service build" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.21.1", 12 | "babel-polyfill": "^6.26.0", 13 | "element-ui": "^2.11.0", 14 | "vue": "^2.6.10", 15 | "vue-cropperjs": "^3.0.0", 16 | "vue-quill-editor": "^3.0.6", 17 | "vue-router": "^3.0.3", 18 | "vue-schart": "^2.0.0", 19 | "vuedraggable": "^2.17.0", 20 | "jquery": "^3.4.1" 21 | }, 22 | "devDependencies": { 23 | "@vue/cli-plugin-babel": "^3.9.0", 24 | "@vue/cli-service": "^3.9.0", 25 | "vue-template-compiler": "^2.6.10" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/vue.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | 3 | module.exports = { 4 | publicPath: './', 5 | assetsDir: 'static', 6 | productionSourceMap: false, 7 | configureWebpack: { 8 | plugins: [ 9 | new webpack.ProvidePlugin({ 10 | $: "jquery", 11 | jQuery: "jquery", 12 | "windows.jQuery": "jquery" 13 | }) 14 | ] 15 | }, 16 | // devServer: { 17 | // proxy: { 18 | // '/api':{ 19 | // target:'http://jsonplaceholder.typicode.com', 20 | // changeOrigin:true, 21 | // pathRewrite:{ 22 | // '/api':'' 23 | // } 24 | // } 25 | // } 26 | // } 27 | }; -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/mapper/FillQuestionnaireMapper.java: -------------------------------------------------------------------------------- 1 | package com.formtools.mapper; 2 | 3 | import com.formtools.model.FillQuestionnaire; 4 | import org.apache.ibatis.annotations.Mapper; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author myl 10 | * @create 2020-04-04 10:51 11 | */ 12 | @Mapper 13 | public interface FillQuestionnaireMapper { 14 | 15 | int addQuestionnaire(FillQuestionnaire fillQuestionnaire); 16 | 17 | List findFilledQuestionnaire(Long formId); 18 | 19 | int deleteFilledQuestionnaire(Integer id); 20 | 21 | /** 22 | * 当 当前时间晚于开始时间 早于截止时间 人数符合 则插入 23 | * @param fillQuestionnaire 问卷答案 24 | * @return 插入信息条数(1||0 25 | */ 26 | int insertFilledQuestionnaire(FillQuestionnaire fillQuestionnaire); 27 | } 28 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/IdBuilder.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | /** 4 | * @author myl 5 | * @create 2020-04-14 16:29 6 | */ 7 | public class IdBuilder { 8 | 9 | private static int formid=1; 10 | 11 | private static int userid=1; 12 | 13 | private static int sceneid=1; 14 | 15 | public static synchronized long getFormId(){ 16 | formid=(formid+1)%1000; 17 | return System.currentTimeMillis()*1000+formid; 18 | } 19 | 20 | public static synchronized long getUserId(){ 21 | userid=(userid+1)%1000; 22 | return System.currentTimeMillis()*1000+userid; 23 | } 24 | 25 | public static synchronized long getSceneId(){ 26 | sceneid=(sceneid+1)%1000; 27 | return System.currentTimeMillis()*1000+sceneid; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/css/theme-green/color-green.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #07c4a8; 3 | } 4 | .login-wrap{ 5 | background: rgba(56, 157, 170, 0.82);; 6 | } 7 | .plugins-tips{ 8 | background: #f2f2f2; 9 | } 10 | .plugins-tips a{ 11 | color: #00d1b2; 12 | } 13 | .el-upload--text em { 14 | color: #00d1b2; 15 | } 16 | .pure-button{ 17 | background: #00d1b2; 18 | } 19 | .pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus { 20 | background-color: #00d1b2 !important; 21 | border-color: #00d1b2 !important; 22 | } 23 | .tags-li.active { 24 | border: 1px solid #00d1b2; 25 | background-color: #00d1b2; 26 | } 27 | .collapse-btn:hover{ 28 | background: #00d1b2; 29 | } -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/utils/request.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | const service = axios.create({ 4 | // process.env.NODE_ENV === 'development' 来判断是否开发环境 5 | // easy-mock服务挂了,暂时不使用了 6 | // baseURL: 'https://www.easy-mock.com/mock/592501a391470c0ac1fab128', 7 | timeout: 5000 8 | }); 9 | 10 | service.interceptors.request.use( 11 | config => { 12 | return config; 13 | }, 14 | error => { 15 | console.log(error); 16 | return Promise.reject(); 17 | } 18 | ); 19 | 20 | service.interceptors.response.use( 21 | response => { 22 | if (response.status === 200) { 23 | return response.data; 24 | } else { 25 | Promise.reject(); 26 | } 27 | }, 28 | error => { 29 | console.log(error); 30 | return Promise.reject(); 31 | } 32 | ); 33 | 34 | export default service; 35 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/CookieUtil.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import javax.servlet.http.Cookie; 4 | import javax.servlet.http.HttpServletRequest; 5 | 6 | public class CookieUtil { 7 | /** 8 | * 从FormId Cookie 中获取缓存的key 9 | * @param request req 10 | * @param formId 表id 11 | * @return 缓存key 12 | */ 13 | public static String getKeyFromFormIdCookie(HttpServletRequest request,String formId){ 14 | String key = null; 15 | //遍历cookie 获取名为formId的cookie 内含缓存的key 16 | Cookie[] cookies = request.getCookies(); 17 | if (cookies==null || cookies.length==0) return null; 18 | for (Cookie cookie : cookies) { 19 | if (cookie.getName().equals(formId)) { 20 | key = cookie.getValue(); 21 | break; 22 | } 23 | } 24 | return key; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WebApp/management.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 无标题文档 6 | 7 | 8 | 9 |
10 | 11 |
12 | {{name}} 13 |
14 |
15 |
16 |

导航

17 |
    18 |
  • 活动报名

  • 19 | 20 | 21 |
  • 信息登记

  • 22 | 23 | 24 |
  • 调查问卷

  • 25 | 26 | 27 |
  • 回收站

  • 28 | 29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/mapper/UserMapper.java: -------------------------------------------------------------------------------- 1 | package com.formtools.mapper; 2 | 3 | import com.formtools.model.EmailVerify; 4 | import com.formtools.model.UserInfo; 5 | import com.formtools.model.UserVerify; 6 | import org.apache.ibatis.annotations.Mapper; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * CRUD用户信息 12 | * @author myl 13 | * @create 2020-02-05 22:06 14 | */ 15 | @Mapper 16 | public interface UserMapper { 17 | 18 | int addUserInfo(UserInfo userInfo); 19 | 20 | UserInfo getUserInfo(Long userId); 21 | 22 | int updateUserInfo(UserInfo userInfo); 23 | 24 | int addUserVerify(UserVerify userVerify); 25 | 26 | int updateUserVerify(UserVerify userVerify); 27 | 28 | UserVerify getUserVerify(String openid); 29 | 30 | EmailVerify getEmailVerify(String email); 31 | 32 | int addEmailVerify(EmailVerify emailVerify); 33 | 34 | int updateEmailVerify(EmailVerify emailVerify); 35 | 36 | Map getUserVerifyType(Long userId); 37 | } 38 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/SendEmailTest.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.formtools.service.UserService; 4 | import com.formtools.utils.CodeUtil; 5 | import com.formtools.utils.EmailUtil; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | 10 | /** 11 | * @author myl 12 | * @create 2020-02-19 15:39 13 | */ 14 | @SpringBootTest 15 | public class SendEmailTest { 16 | 17 | @Autowired 18 | private UserService userService; 19 | 20 | @Test 21 | void testSendEmail(){ 22 | try{ 23 | System.out.println(EmailUtil.SendEmail("1739845021@qq.com","123456")); 24 | }catch (Exception e){ 25 | System.out.println(e.getMessage()); 26 | } 27 | } 28 | @Test 29 | void CodeTest(){ 30 | System.out.println(CodeUtil.createCode()); 31 | } 32 | 33 | @Test 34 | void CodeTest2(){ 35 | System.out.println(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/RedisTest.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.formtools.model.UserModel; 4 | import org.junit.jupiter.api.Test; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | 8 | import javax.annotation.Resource; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | @SpringBootTest 13 | class RedisTest { 14 | 15 | @Resource 16 | private RedisTemplate redisTemplate; 17 | 18 | @Test 19 | void test1(){ 20 | UserModel userModel=new UserModel(); 21 | userModel.setUserId(12L); 22 | redisTemplate.opsForValue().set("test",userModel); 23 | } 24 | 25 | @Test 26 | void test2(){ 27 | System.out.println(redisTemplate.opsForValue().get("key")); 28 | } 29 | 30 | @Test 31 | void test3(){ 32 | List list=new ArrayList<>(); 33 | list.add(1); 34 | list.add(2); 35 | list.add("haha"); 36 | redisTemplate.opsForValue().set("key",list); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/enums/ErrorMsg.java: -------------------------------------------------------------------------------- 1 | package com.formtools.enums; 2 | 3 | 4 | /** 5 | * @author NaNRailgun 6 | * 错误信息枚举类 7 | */ 8 | public enum ErrorMsg { 9 | 10 | ACCOUNT_EXIT("用户已存在"), 11 | ACCOUNT_NOT_EXIT("用户不存在"), 12 | PASSWORD_IS_NOT_SAME("密码不一致"), 13 | PASSWORD_RESET_ERROR("修改密码失败"), 14 | EMAIL_SEND_ERROR("邮件发送失败 请重试"), 15 | PARAM_ERROR("参数错误"), 16 | SYSTEM_ERROR("系统错误"), 17 | REGISTER_ERROR("注册失败"), 18 | FILE_TYPE_ERROR("文件类型错误 请选择.jpg或.png"), 19 | FILE_UPLOAD_ERROR("文件上传失败"), 20 | FILE_NOT_EXIT("文件不存在"), 21 | FILE_DOWNLOAD_ERROR("文件下载异常"), 22 | FILE_SIZE_ERROR("文件过大"), 23 | OPERAT_FREQUENCY("操作频繁 稍后重试"), 24 | MISSING_PARAMETER("缺少参数"), 25 | COOKIE_ERROR("请重新登录"), 26 | EMAIL_LOGIN_ERROR("登录失败 账号密码错误"), 27 | JSON_READ_ERROR("json参数解析错误"), 28 | FORM_NUMBER_ERROR("表单id错误"), 29 | REPEAT_COMMIT_ERROR("请勿重复提交"), 30 | COMMIT_FAIL_ERROR("提交失败"); 31 | 32 | private String msg; 33 | 34 | ErrorMsg(String msg) { 35 | this.msg = msg; 36 | } 37 | 38 | public String getMsg() { 39 | return msg; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/mapper/FillRegistryMapper.java: -------------------------------------------------------------------------------- 1 | package com.formtools.mapper; 2 | 3 | import com.formtools.model.FillRegistry; 4 | import org.apache.ibatis.annotations.Mapper; 5 | import org.apache.ibatis.annotations.Param; 6 | 7 | import java.sql.Timestamp; 8 | import java.util.List; 9 | 10 | /** 11 | * @author myl 12 | * @create 2020-04-04 14:01 13 | */ 14 | @Mapper 15 | public interface FillRegistryMapper { 16 | 17 | int addRegistry(FillRegistry fillRegistry); 18 | 19 | FillRegistry getFilledRegistry(@Param("userId") Long userId, @Param("formId") Long formId); 20 | 21 | List findAllFilled(Long formId); 22 | 23 | int updateFilledRegistry(FillRegistry fillRegistry); 24 | 25 | int cancelFilledRegistry(@Param("userId") Long userId, @Param("formId") Long formId, @Param("now")Timestamp now); 26 | 27 | int deleteFilledRegistry(@Param("userId") Long userId, @Param("formId") Long formId); 28 | 29 | /** 30 | * 若 此刻时间 晚于开始时间 早于截止时间 总填表人数小于最大填表人数 插入数据 31 | * @param fillRegistry 数据 32 | * @return 插入数据条数 33 | */ 34 | int insertFilledRegistry(FillRegistry fillRegistry); 35 | } 36 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2019 vue-formtools 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/Examiner.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import java.time.Duration; 4 | import java.time.LocalDateTime; 5 | 6 | /** 7 | * @author NaNRailgun 8 | * 验证码剩余时间检测 9 | */ 10 | public class Examiner { 11 | 12 | private String code; 13 | private LocalDateTime time; 14 | 15 | 16 | /** 17 | * 返回剩余时间 剩余时间为0则返回空字符串 18 | * @param now 当前时间 19 | * @return 剩余时间 1-59s||”“ 20 | */ 21 | public String timeComputer(LocalDateTime now){ 22 | Duration duration=Duration.between(time,now); 23 | if (duration.toMillis()<60*1000) 24 | return String.valueOf((60-(duration.toMillis()/1000))); 25 | return ""; 26 | } 27 | 28 | 29 | public Examiner(String code, LocalDateTime time) { 30 | this.code = code; 31 | this.time = time; 32 | } 33 | 34 | public String getCode() { 35 | return code; 36 | } 37 | 38 | public void setCode(String code) { 39 | this.code = code; 40 | } 41 | 42 | public LocalDateTime getTime() { 43 | return time; 44 | } 45 | 46 | public void setTime(LocalDateTime time) { 47 | this.time = time; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/common/HeaderUserInfo.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 22 | 23 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service; 2 | 3 | 4 | import com.formtools.model.EmailVerify; 5 | import com.formtools.model.UserInfo; 6 | import com.formtools.model.UserModel; 7 | import com.formtools.vo.ResultVo; 8 | import org.springframework.web.multipart.MultipartFile; 9 | 10 | import javax.mail.MessagingException; 11 | import java.io.IOException; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author myl 16 | * @create 2020-02-05 22:57 17 | */ 18 | 19 | public interface UserService { 20 | 21 | UserInfo getUserInfo(Long userId); 22 | ResultVo sendEmailCode(String email,String type) throws MessagingException; 23 | void addUser(UserModel userModel); 24 | boolean isTrueCode(UserModel userModel,String code,String type); 25 | boolean register(UserModel userModel,String code); 26 | String keepImage(MultipartFile multipartFile, String id) throws IOException; 27 | Long emailLogin(String email,String password); 28 | boolean resetPassword(UserModel userModel,String code); 29 | void updateEmailVerify(EmailVerify emailVerify); 30 | boolean updateUserInfo(UserModel userModel); 31 | Map getUserVerifyType(Long userId); 32 | } 33 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/public/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "list": [{ 3 | "id": 1, 4 | "name": "张三", 5 | "money": 123, 6 | "address": "广东省东莞市长安镇", 7 | "state": "成功", 8 | "date": "2019-11-1", 9 | "thumb": "https://lin-xin.gitee.io/images/post/wms.png" 10 | }, 11 | { 12 | "id": 2, 13 | "name": "李四", 14 | "money": 456, 15 | "address": "广东省广州市白云区", 16 | "state": "成功", 17 | "date": "2019-10-11", 18 | "thumb": "https://lin-xin.gitee.io/images/post/node3.png" 19 | }, 20 | { 21 | "id": 3, 22 | "name": "王五", 23 | "money": 789, 24 | "address": "湖南省长沙市", 25 | "state": "失败", 26 | "date": "2019-11-11", 27 | "thumb": "https://lin-xin.gitee.io/images/post/parcel.png" 28 | }, 29 | { 30 | "id": 4, 31 | "name": "赵六", 32 | "money": 1011, 33 | "address": "福建省厦门市鼓浪屿", 34 | "state": "成功", 35 | "date": "2019-10-20", 36 | "thumb": "https://lin-xin.gitee.io/images/post/notice.png" 37 | } 38 | ], 39 | "pageTotal": 4 40 | } -------------------------------------------------------------------------------- /WebApp/css/PERSONAL.css: -------------------------------------------------------------------------------- 1 | .logo{ 2 | position: absolute; 3 | top: 80px; 4 | left: 175px; 5 | } 6 | .sh3{ 7 | position: absolute; 8 | top: 160px; 9 | left: 850px; 10 | } 11 | li{display: inline;} 12 | a{text-decoration: none} 13 | .head{ 14 | font-size: 20px; 15 | color: white; 16 | position: absolute; 17 | top: 320px; 18 | left: 770px; 19 | } 20 | .nav{ 21 | background-color: white; 22 | width:360px; 23 | height: 30px; 24 | font-size: 20px; 25 | position: absolute; 26 | top: 80px; 27 | left: 1300px; 28 | } 29 | #\=field1{ 30 | position: absolute; 31 | top: 620px; 32 | left: 570px; 33 | } 34 | #button1{ 35 | font-size: 25px; 36 | position: absolute; 37 | top: 820px; 38 | left: 1100px; 39 | } 40 | #\=field2{ 41 | position: absolute; 42 | top: 920px; 43 | left: 570px; 44 | } 45 | 46 | #button2{ 47 | font-size: 25px; 48 | position: absolute; 49 | top: 1020px; 50 | left:1105px; 51 | } 52 | #\=field3{ 53 | position: absolute; 54 | top: 1120px; 55 | left: 570px; 56 | } 57 | 58 | #button3{ 59 | font-size: 25px; 60 | position: absolute; 61 | top:1180px; 62 | left:1105px; 63 | } 64 | .biaoti{ 65 | color: gray; 66 | font-size: 30px; 67 | position: absolute; 68 | top:650px; 69 | left:180px; 70 | } -------------------------------------------------------------------------------- /WebApp/js/login.js: -------------------------------------------------------------------------------- 1 | // axios全局配置withCredentials也可以获取cookie 2 | // axios.defaults.withCredentials = true; 3 | var app = new Vue({ 4 | el: '#app', 5 | data: { 6 | email: "", 7 | password: "", 8 | wxLogin:false 9 | }, 10 | methods: { 11 | toOtherLogin:function(){ 12 | this.wxLogin=false; 13 | }, 14 | toWXLogin:function(){ 15 | this.wxLogin=true; 16 | }, 17 | login: function () { 18 | axios.get("http://localhost:8080/login?" + "email=" + this.email 19 | + "&password=" + this.password, 20 | { 21 | "withCredentials": true/*单个axios设置withCredentials*/ 22 | } 23 | ).then(function (response) { 24 | if (response.data.status_code === 0) { 25 | alert(response.data.msg); 26 | } else { 27 | window.location.href="index.html"; 28 | } 29 | }).catch(function (error) { 30 | console.log(error); 31 | }) 32 | }, 33 | toSignin:function () { 34 | window.location.href="signin.html"; 35 | }, 36 | toForgotPassword:function () { 37 | window.location.href="forgot-password.html"; 38 | }, 39 | toYBLogin:function () { 40 | alert("yiban"); 41 | } 42 | } 43 | }) -------------------------------------------------------------------------------- /WebApp/js/forgot-password.js: -------------------------------------------------------------------------------- 1 | var forgot = new Vue({ 2 | el: '#app', 3 | data: { 4 | form:{ 5 | email:"", 6 | code:"", 7 | password:"", 8 | password_again:"" 9 | } 10 | }, 11 | methods: { 12 | getEmailCode: function () { 13 | axios.get("http://localhost:8080//email-code/reset-password?"+"email="+this.form.email,{ 14 | "withCredentials": true 15 | }).then(function (response) { 16 | if (response.data.status_code === 0) { 17 | alert(response.data.msg); 18 | } else { 19 | alert("已发送验证码"); 20 | } 21 | }).catch(function (error) { 22 | console.log(error); 23 | }) 24 | }, 25 | resetPassword: function () { 26 | axios.post("http://localhost:8080/reset-password",this.form,{ 27 | "withCredentials": true/*单个axios设置withCredentials*/ 28 | }).then(function (response) { 29 | if (response.data.status_code === 0) { 30 | alert(response.data.msg); 31 | } else { 32 | alert("密码修改成功"); 33 | window.location.href="login.html"; 34 | } 35 | }).catch(function (error) { 36 | console.log(error); 37 | }) 38 | } 39 | } 40 | }) -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/impl/OtherUserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service.impl; 2 | 3 | import com.formtools.mapper.UserMapper; 4 | import com.formtools.model.UserInfo; 5 | import com.formtools.model.UserVerify; 6 | import com.formtools.service.OtherUserService; 7 | import com.formtools.utils.IdBuilder; 8 | import org.springframework.stereotype.Service; 9 | 10 | import javax.annotation.Resource; 11 | 12 | /** 13 | * @author myl 14 | * @create 2020-02-23 23:34 15 | */ 16 | @Service 17 | public class OtherUserServiceImpl implements OtherUserService { 18 | @Resource 19 | private UserMapper userMapper; 20 | 21 | public Long updateUser(String nickname,String profile,String openid,Character type){ 22 | UserVerify userVerify=userMapper.getUserVerify(openid); 23 | // System.out.println(userVerify); 24 | Long userId; 25 | int n; 26 | if(userVerify!=null){ 27 | userId=userVerify.getUserId(); 28 | n=userMapper.updateUserInfo(new UserInfo(userId,nickname,profile)); 29 | }else { 30 | userId= IdBuilder.getUserId(); 31 | n=userMapper.addUserVerify(new UserVerify(null,userId,openid,type)); 32 | if(n==1){ 33 | n=userMapper.addUserInfo(new UserInfo(userId,nickname,profile)); 34 | }else return null; 35 | } 36 | if(n==1)return userId; 37 | return null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import ElementUI from 'element-ui'; 5 | import $ from 'jquery' 6 | import 'element-ui/lib/theme-chalk/index.css'; // 默认主题 7 | // import './assets/css/theme-green/index.css'; // 浅绿色主题 8 | import './assets/css/icon.css'; 9 | import './components/common/directives'; 10 | import 'babel-polyfill'; 11 | 12 | Vue.config.productionTip = false; 13 | 14 | Vue.use(ElementUI, { 15 | // size: 'small' 16 | }); 17 | 18 | 19 | // //使用钩子函数对路由进行权限跳转 20 | router.beforeEach((to, from, next) => { 21 | document.title = `${to.meta.title}`; 22 | next(); 23 | // const role = localStorage.getItem('ms_username'); 24 | // if (!role && to.path !== '/login') { 25 | // next('/login'); 26 | // } else if (to.meta.permission) { 27 | // // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已 28 | // role === 'admin' ? next() : next('/403'); 29 | // } else { 30 | // // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容 31 | // if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') { 32 | // Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', { 33 | // confirmButtonText: '确定' 34 | // }); 35 | // } else { 36 | // next(); 37 | // } 38 | // } 39 | }); 40 | 41 | new Vue({ 42 | router, 43 | render: h => h(App) 44 | }).$mount('#app'); 45 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import EditForm from '../components/page/EditForm' 4 | import Home from '../components/page/Home' 5 | import ManagePage from '../components/page/ManagePage' 6 | import FillForm from '../components/page/FillForm' 7 | import FormDetails from '../components/page/FormDetails' 8 | 9 | Vue.use(Router); 10 | 11 | export default new Router({ 12 | routes: [ 13 | { 14 | path: '/', 15 | redirect: '/home' 16 | }, 17 | { 18 | path: '/home', 19 | component: Home, 20 | meta: { title: '通用表单数据收集系统' } 21 | }, 22 | { 23 | path: '/editForm', 24 | component: EditForm, 25 | meta: { title: '编辑表单' } 26 | }, 27 | { 28 | path: '/managePage', 29 | component: ManagePage, 30 | meta: { title: '通用表单数据收集系统' } 31 | }, 32 | { 33 | path: '/fillForm', 34 | component: FillForm, 35 | meta: { title: '通用表单数据收集系统' } 36 | }, 37 | { 38 | path: '/formDetails', 39 | component: FormDetails, 40 | meta: { title: '通用表单数据收集系统' } 41 | }, 42 | { 43 | path: '*', 44 | component: () => import('../components/page/404.vue'), 45 | meta: { title: '404' } 46 | } 47 | ] 48 | }); 49 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/page/404.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | 24 | 25 | 57 | -------------------------------------------------------------------------------- /WebApp/js/signin.js: -------------------------------------------------------------------------------- 1 | var signin = new Vue({ 2 | el: '#app', 3 | data: { 4 | email: "", 5 | password: "", 6 | nickname: "", 7 | code: "" 8 | }, 9 | methods: { 10 | getEmailCode : function () { 11 | axios.get("http://localhost:8080/email-code?"+"email="+this.email,{ 12 | "withCredentials": true 13 | }).then(function (response) { 14 | if (response.data.status_code === 0) { 15 | alert(response.data.msg); 16 | } else { 17 | alert("已发送验证码"); 18 | } 19 | }).catch(function (error) { 20 | console.log(error); 21 | }) 22 | }, 23 | registerUser : function () { 24 | axios.post("http://localhost:8080/user",{ 25 | email:this.email, 26 | password:this.password, 27 | nickname:this.nickname, 28 | code:this.code 29 | },{ 30 | "withCredentials": true 31 | }).then(function (response) { 32 | if (response.data.status_code === 0) { 33 | alert(response.data.msg); 34 | } else { 35 | alert('注册成功!'); 36 | location.href='login.html'; 37 | } 38 | }).catch(function (error) { 39 | console.log(error); 40 | }) 41 | } 42 | } 43 | }) -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/ValidationUtil.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import com.formtools.Exception.ParamException; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.validation.ConstraintViolation; 8 | import javax.validation.Validator; 9 | import javax.validation.groups.Default; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | @Component 15 | public class ValidationUtil { 16 | 17 | //SpringBoot能将Validator直接注入 18 | @Autowired 19 | private Validator validator; 20 | 21 | /** 22 | * 参数校验器 23 | * @param object 待校验对象 24 | * @param classes 分组 25 | */ 26 | public void validateParam(Object object,Class[] classes){ 27 | 28 | if (classes==null||classes.length==0) classes=new Class[]{Default.class}; 29 | 30 | Set> set = validator.validate(object, classes); 31 | //set.size大于0则表明参数出错 32 | if (set.size()>0){ 33 | Map map=new HashMap<>(); 34 | for (ConstraintViolation cv : set){ 35 | String[] param=cv.getPropertyPath().toString().split("\\."); 36 | String message=cv.getMessage(); 37 | map.put(param[param.length-1],message); 38 | } 39 | //抛出参数异常,并且需要根据业务异常再写一个异常拦截器,此处不再赘述 40 | throw new ParamException(map); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/OtherConfig.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | /** 4 | * @author myl 5 | * @create 2020-02-27 15:48 6 | */ 7 | public class OtherConfig { 8 | //易班配置 9 | // public static final String APP_ID = "abb9a6549cddf5fc"; 10 | // public static final String APP_SEC = "1c89782f669e34bf1fbdccca2a33be1a"; 11 | // public static final String BACK_URL = "http://api.shinytengxvnyun.cn/YBAPI/auth"; 12 | // public static final String DEFAULTREDIRECTURL = "http://shinytengxvnyun.cn"; 13 | //易班开发测试环境的配置 14 | public static final String APP_ID = "985f6bf0a2b04632"; 15 | public static final String APP_SEC = "413ee0b76cb3d8e00e84ab5c2c24f100"; 16 | public static final String BACK_URL = "http://localhost:8080/YBAPI/auth"; 17 | public static final String DEFAULTREDIRECTURL = "http://shinytengxvnyun.cn"; 18 | 19 | //微信小程序配置 20 | public static final String GRANT_TYPE = "client_credential"; 21 | public static final String APPID = "wx80e741529e832e6b"; 22 | public static final String SECRET = "4e1e6771f9c2ca3cee6edcee2306921f"; 23 | public static final String LOGIN_PAGE="pages/webLogin/webLogin"; 24 | public static final String TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type="; 25 | public static final String CODE_URL="https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="; 26 | 27 | //部署域名 28 | public static final String APPURL="http://api.shinytengxvnyun.cn"; 29 | 30 | public static int cookieMaxAge=60*60*24*365; 31 | } 32 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/WeiXinCodeUtil.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import com.formtools.OtherConfig; 4 | import org.springframework.http.HttpEntity; 5 | import org.springframework.http.HttpHeaders; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.util.LinkedMultiValueMap; 9 | import org.springframework.util.MultiValueMap; 10 | import org.springframework.util.ResourceUtils; 11 | import org.springframework.web.client.RestTemplate; 12 | 13 | import java.io.*; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | /** 18 | * @author myl 19 | * @create 2020-02-23 22:02 20 | */ 21 | public class WeiXinCodeUtil { 22 | 23 | private static RestTemplate restTemplate = RestTemplateConfig.getRestTemplate(); 24 | 25 | public static byte[] getCode(String scene) { 26 | String token=WeiXinTokenUtil.getToken(); 27 | // System.out.println("token="+token); 28 | String url = OtherConfig.CODE_URL + token; 29 | Map paramMap = new HashMap<>(); 30 | paramMap.put("scene", scene); 31 | // paramMap.put("page",OtherConfig.LOGIN_PAGE); 32 | HttpHeaders headers = new HttpHeaders(); 33 | headers.setContentType(MediaType.APPLICATION_JSON); 34 | HttpEntity> entity = new HttpEntity(paramMap, headers); 35 | ResponseEntity response = restTemplate.postForEntity(url, entity, byte[].class); 36 | return response.getBody(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /WebApp/notice.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 通知页 6 | 7 | 8 | 30 | 31 | 32 |
33 | 消息中心 34 |
35 |
36 |

37 | {{ parentMessage }} - {{ index }} - {{ item.message }} 38 |

39 | 40 |
41 | 42 | 54 | -------------------------------------------------------------------------------- /WebApp/signin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 通用表单数据收集系统 8 | 9 | 10 | 11 | 12 | 13 |
14 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/FillQuestionnaireMapperTests.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.formtools.mapper.FillQuestionnaireMapper; 5 | import com.formtools.model.FillQuestionnaire; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | import javax.annotation.Resource; 10 | import java.sql.Timestamp; 11 | import java.util.List; 12 | 13 | /** 14 | * @author myl 15 | * @create 2020-04-04 11:13 16 | */ 17 | @SpringBootTest 18 | class FillQuestionnaireMapperTests { 19 | 20 | @Resource 21 | FillQuestionnaireMapper fillQuestionnaireMapper; 22 | 23 | @Test 24 | void testAdd(){ 25 | FillQuestionnaire fillQuestionnaire=new FillQuestionnaire(1111L, 26 | JSON.parseObject("{}"),new Timestamp(System.currentTimeMillis())); 27 | int n= fillQuestionnaireMapper.addQuestionnaire(fillQuestionnaire); 28 | System.out.println(n); 29 | } 30 | 31 | @Test 32 | void testFindAllFilled(){ 33 | List fillQuestionnaireList=fillQuestionnaireMapper.findFilledQuestionnaire(1111L); 34 | for(FillQuestionnaire data:fillQuestionnaireList) 35 | System.out.println(data); 36 | } 37 | 38 | @Test 39 | void testDelete(){ 40 | int n=fillQuestionnaireMapper.deleteFilledQuestionnaire(3); 41 | System.out.println(n); 42 | } 43 | 44 | @Test 45 | void testInsert(){ 46 | FillQuestionnaire fillQuestionnaire=new FillQuestionnaire(1L, 47 | JSON.parseObject("{}"),new Timestamp(System.currentTimeMillis())); 48 | System.out.println(fillQuestionnaireMapper.insertFilledQuestionnaire(fillQuestionnaire)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /WebApp/forgot-password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 通用表单数据收集系统 8 | 9 | 10 | 11 | 12 | 13 |
14 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/impl/FillQuestionnaireServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service.impl; 2 | 3 | import com.formtools.mapper.FillQuestionnaireMapper; 4 | import com.formtools.model.FillQuestionnaire; 5 | import com.formtools.model.FillRegistry; 6 | import com.formtools.service.FillQuestionnaireService; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import javax.annotation.Resource; 12 | 13 | @Service 14 | public class FillQuestionnaireServiceImpl implements FillQuestionnaireService { 15 | 16 | @Resource 17 | private FillQuestionnaireMapper fillQuestionnaireMapper; 18 | 19 | @Resource 20 | private RedisTemplate redisTemplate; 21 | 22 | /** 23 | * 问卷类 插入答案 24 | * @param key 缓存key 25 | * @param fillQuestionnaire 答案 26 | * @return 是否成功 27 | */ 28 | @Transactional 29 | public boolean insertFillQuestionnaire(String key, FillQuestionnaire fillQuestionnaire){ 30 | if (fillQuestionnaireMapper.insertFilledQuestionnaire(fillQuestionnaire)>0){ 31 | redisTemplate.delete(key); 32 | return true; 33 | } 34 | return false; 35 | } 36 | 37 | /** 38 | * 从缓存取出问卷类缓存的答案 39 | * @param key 缓存key 40 | * @return 答案(key找不到即返回空 41 | */ 42 | public FillRegistry getFillQuestionnaireFromCache(String key){ 43 | FillRegistry fillQuestionnaire; 44 | try { 45 | fillQuestionnaire=(FillRegistry) redisTemplate.opsForValue().get(key); 46 | } catch (Exception e) { 47 | fillQuestionnaire=null; 48 | } 49 | return fillQuestionnaire; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /WebApp/css/management.css: -------------------------------------------------------------------------------- 1 | *{ 2 | background-color:f4f4f4; 3 | padding:0; 4 | margin:0; 5 | } 6 | .body 7 | { 8 | margin:0px; 9 | padding: 0px; 10 | } 11 | #top { 12 | margin:0px; 13 | position: absolute; 14 | background-color: #F4F4F4; 15 | position: static; 16 | clear:both; 17 | height:80px; 18 | box-shadow: 3px 3px 5px #888888; 19 | } 20 | #top #logo { 21 | position: fixed; 22 | margin-left: 140px; 23 | margin-top:10px; 24 | width:97px; 25 | float:left; 26 | background-color:#FF9F9F; 27 | top: -1px; 28 | height: 56px; 29 | left: 8px; 30 | } 31 | #top #_name { 32 | position: static; 33 | margin:20px 200px 20px 0; 34 | width:auto; 35 | padding:10px 30px; 36 | float:right; 37 | background-color:#A2A2FF; 38 | } 39 | .2_top { 40 | position: relative; 41 | height:30px; 42 | margin:5px 0; 43 | box-shadow: 3px 2px 2px #888888; 44 | left: -1px; 45 | } 46 | .2_top ._creat { 47 | float:left; 48 | margin:0 60px; 49 | position:absolute; 50 | left: 71px; 51 | top: 87px; 52 | width: 112px; 53 | height: 31px; 54 | } 55 | 56 | #main{ 57 | position:relative; 58 | margin:20%; 59 | background-color:#C4C4C4; 60 | } 61 | #LeftMenu1_divChildMenu{ 62 | position: relative; 63 | float: left; 64 | width:186px; 65 | margin:10px 0 0 5px; 66 | top: 40px; 67 | left: 200px; 68 | height: 397px; 69 | } 70 | ul li{ 71 | list-style: none; 72 | 73 | } 74 | #LeftMenu1_divChildMenu .Nsb_l_list_top { 75 | padding:10px 15px; 76 | font-size:16px 77 | } 78 | #LeftMenu1_divChildMenu ul li .exam_user_exam { 79 | padding: 20px; 80 | margin:0 5px 81 | } 82 | #_right{ 83 | float:right; 84 | position: absolute; 85 | height:50%; 86 | width:30%; 87 | background-color:#BEBEBE 88 | } 89 | .2_top ._type { 90 | position:relative; 91 | float:left; 92 | margin:5px 0 0 300px; 93 | } 94 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/EmailVerify.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | 5 | import javax.validation.constraints.NotEmpty; 6 | import javax.validation.constraints.NotNull; 7 | import javax.validation.constraints.Null; 8 | 9 | /** 10 | * @author myl 11 | * @create 2020-03-27 11:41 12 | */ 13 | @ApiModel("邮箱登录验证") 14 | public class EmailVerify { 15 | @Null 16 | private Integer id; 17 | 18 | @NotNull 19 | @NotEmpty 20 | private String email; 21 | 22 | @NotNull 23 | @NotEmpty 24 | private String password; 25 | 26 | public EmailVerify() { 27 | } 28 | 29 | public EmailVerify(@Null Integer id, @NotNull @NotEmpty String email, @NotNull @NotEmpty String password) { 30 | this.id = id; 31 | this.email = email; 32 | this.password = password; 33 | } 34 | 35 | public Integer getId() { 36 | return id; 37 | } 38 | 39 | public void setId(Integer id) { 40 | this.id = id; 41 | } 42 | 43 | public String getEmail() { 44 | return email; 45 | } 46 | 47 | public void setEmail(String email) { 48 | this.email = email; 49 | } 50 | 51 | public String getPassword() { 52 | return password; 53 | } 54 | 55 | public void setPassword(String password) { 56 | this.password = password; 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | final StringBuilder sb = new StringBuilder("{"); 62 | sb.append("\"id\":") 63 | .append(id); 64 | sb.append(",\"email\":\"") 65 | .append(email).append('\"'); 66 | sb.append(",\"password\":\"") 67 | .append(password).append('\"'); 68 | sb.append('}'); 69 | return sb.toString(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /WebApp/css/Home Page.css: -------------------------------------------------------------------------------- 1 | .logo{ 2 | position: absolute; 3 | top: 80px; 4 | left: 175px; 5 | } 6 | .sh3{ 7 | position: absolute; 8 | top: 160px; 9 | left: 850px; 10 | } 11 | li{display: inline;} 12 | a{text-decoration: none} 13 | .head{ 14 | font-size: 20px; 15 | color: white; 16 | position: absolute; 17 | top: 320px; 18 | left: 770px; 19 | } 20 | .sc{ 21 | position: absolute; 22 | top: 1905px; 23 | left: 380px; 24 | } 25 | .nav{ 26 | background-color: white; 27 | width:360px; 28 | height: 30px; 29 | font-size: 20px; 30 | position: absolute; 31 | top: 80px; 32 | left: 1300px; 33 | } 34 | .activity1{ 35 | position: absolute; 36 | top: 1000px; 37 | left: 475px; 38 | } 39 | .text1{ 40 | border:1px solid white; 41 | position: absolute; 42 | top: 1250px; 43 | left: 520px; 44 | } 45 | .activity2{ 46 | position: absolute; 47 | top: 1000px; 48 | left: 875px; 49 | } 50 | .text2{ 51 | border:1px solid white; 52 | position: absolute; 53 | top: 1250px; 54 | left: 925px; 55 | } 56 | .activity3{ 57 | position: absolute; 58 | top: 1000px; 59 | left: 1275px; 60 | } 61 | .text3{ 62 | border:1px solid white; 63 | position: absolute; 64 | top: 1250px; 65 | left: 1325px; 66 | } 67 | .text4{ 68 | color: aliceblue; 69 | font-size: 20px; 70 | position: absolute; 71 | top: 1870px; 72 | left: 1020px; 73 | } 74 | .sc1{ 75 | position: absolute; 76 | top: 2470px; 77 | left: 1020px; 78 | } 79 | .text5{ 80 | color: aliceblue; 81 | font-size: 24px; 82 | position: absolute; 83 | top: 3970px; 84 | left: 1080px; 85 | } 86 | .text6{ 87 | background-color: white; 88 | color: blue; 89 | font-size: 24px; 90 | position: absolute; 91 | top: 4400px; 92 | left: 1140px; 93 | } -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/EmailUtil.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import javax.mail.Message; 4 | import javax.mail.MessagingException; 5 | import javax.mail.Session; 6 | import javax.mail.Transport; 7 | import javax.mail.internet.InternetAddress; 8 | import javax.mail.internet.MimeMessage; 9 | import java.util.Properties; 10 | 11 | public class EmailUtil { 12 | 13 | //发件人邮箱,授权码(可以在邮箱设置中获取到授权码的信息) 14 | private static final String myEmail="nanrailgun@163.com"; 15 | 16 | private static final String myPassword="lzn422780767666"; 17 | 18 | /** 19 | * 发送邮件 20 | * @param email 收件人邮箱 21 | * @param code 待发送验证码 22 | * @return 成功返回true 23 | * @throws MessagingException 失败抛出异常 24 | */ 25 | public static boolean SendEmail(String email,String code) throws MessagingException { 26 | 27 | Properties props = new Properties(); 28 | props.setProperty("mail.smtp.auth", "true"); 29 | props.setProperty("mail.transport.protocol", "smtp"); 30 | props.put("mail.smtp.host","smtp.163.com");// smtp服务器地址 31 | 32 | Session session = Session.getInstance(props); 33 | //debug模式 34 | session.setDebug(false); 35 | 36 | Message msg = new MimeMessage(session); 37 | //标题 38 | msg.setSubject("表单工具邮箱验证"+code); 39 | //正文 40 | msg.setContent("验证码:"+code, "text/html;charset=UTF-8"); 41 | msg.setFrom(new InternetAddress(myEmail));//发件人邮箱(我的163邮箱) 42 | msg.setRecipient(Message.RecipientType.TO, 43 | new InternetAddress(email)); //收件人邮箱 44 | msg.saveChanges(); 45 | 46 | Transport transport = session.getTransport(); 47 | transport.connect(myEmail,myPassword);//发件人邮箱,授权码(可以在邮箱设置中获取到授权码的信息) 48 | 49 | transport.sendMessage(msg, msg.getAllRecipients()); 50 | 51 | transport.close(); 52 | 53 | return true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/RedisAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.redis.connection.RedisConnectionFactory; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | import org.springframework.data.redis.serializer.RedisSerializer; 9 | import org.springframework.data.redis.serializer.StringRedisSerializer; 10 | 11 | @Configuration 12 | //@ConditionalOnClass(RedisOperations.class) 13 | //@EnableConfigurationProperties(RedisProperties.class) 14 | //@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) 15 | public class RedisAutoConfiguration { 16 | @Bean 17 | @ConditionalOnMissingBean(name = "redisTemplate") 18 | public RedisTemplate redisTemplate( 19 | RedisConnectionFactory redisConnectionFactory) { 20 | RedisTemplate redisTemplate = new RedisTemplate<>(); 21 | RedisSerializer stringSerializer = new StringRedisSerializer(); 22 | redisTemplate.setKeySerializer(stringSerializer); 23 | //redisTemplate.setValueSerializer(stringSerializer); 24 | redisTemplate.setHashKeySerializer(stringSerializer); 25 | redisTemplate.setHashValueSerializer(stringSerializer); 26 | redisTemplate.setConnectionFactory(redisConnectionFactory); 27 | return redisTemplate; 28 | } 29 | // 30 | // @Bean 31 | // @ConditionalOnMissingBean(StringRedisTemplate.class) 32 | // public StringRedisTemplate stringRedisTemplate( 33 | // RedisConnectionFactory redisConnectionFactory) { 34 | // StringRedisTemplate template = new StringRedisTemplate(); 35 | // template.setConnectionFactory(redisConnectionFactory); 36 | // return template; 37 | // } 38 | } 39 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/DraftForm.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import io.swagger.annotations.ApiModel; 6 | import io.swagger.annotations.ApiModelProperty; 7 | 8 | import java.sql.Timestamp; 9 | 10 | /** 11 | * @author myl 12 | * @create 2020-04-13 11:56 13 | */ 14 | @ApiModel("草稿表单") 15 | @JsonInclude(value = JsonInclude.Include.NON_NULL) 16 | public class DraftForm extends BuiltForm{ 17 | 18 | //redis的数据是否持久化到该表 19 | @ApiModelProperty("数据是否持久化") 20 | private Boolean state; 21 | 22 | public DraftForm(){ 23 | super(); 24 | } 25 | 26 | public DraftForm(Long formId, Long userId, String formTitle, JSONObject formInfo, Timestamp builtTime, 27 | Timestamp beginTime, Timestamp endTime, Integer maxCount, String formType, Boolean state) { 28 | super(formId,userId,formTitle,formInfo,builtTime,beginTime,endTime,maxCount,formType); 29 | this.state = state; 30 | } 31 | public DraftForm(BuiltForm builtForm, Boolean state) { 32 | super(builtForm.getFormId(),builtForm.getUserId(),builtForm.getFormTitle(), 33 | builtForm.getFormInfo(),builtForm.getBuiltTime(),builtForm.getBeginTime(), 34 | builtForm.getEndTime(),builtForm.getMaxCount(),builtForm.getFormType()); 35 | this.state = state; 36 | } 37 | 38 | public Boolean getState() { 39 | return state; 40 | } 41 | 42 | public void setState(Boolean state) { 43 | this.state = state; 44 | } 45 | 46 | 47 | @Override 48 | public String toString() { 49 | final StringBuilder sb = new StringBuilder("{"); 50 | sb.append("\"buildForm\":") 51 | .append(super.toString()); 52 | sb.append(",\"state\":") 53 | .append(state); 54 | sb.append('}'); 55 | return sb.toString(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/vo/WXToken.java: -------------------------------------------------------------------------------- 1 | package com.formtools.vo; 2 | 3 | /** 4 | * @author myl 5 | * @create 2020-02-25 23:44 6 | */ 7 | public class WXToken { 8 | private String access_token; 9 | private Integer expires_in; 10 | private Integer errcode; 11 | private String errmsg; 12 | 13 | public WXToken() { 14 | } 15 | 16 | public WXToken(String access_token, Integer expires_in, Integer errcode, String errmsg) { 17 | this.access_token = access_token; 18 | this.expires_in = expires_in; 19 | this.errcode = errcode; 20 | this.errmsg = errmsg; 21 | } 22 | 23 | public String getAccess_token() { 24 | return access_token; 25 | } 26 | 27 | public void setAccess_token(String access_token) { 28 | this.access_token = access_token; 29 | } 30 | 31 | public Integer getExpires_in() { 32 | return expires_in; 33 | } 34 | 35 | public void setExpires_in(Integer expires_in) { 36 | this.expires_in = expires_in; 37 | } 38 | 39 | public Integer getErrcode() { 40 | return errcode; 41 | } 42 | 43 | public void setErrcode(Integer errcode) { 44 | this.errcode = errcode; 45 | } 46 | 47 | public String getErrmsg() { 48 | return errmsg; 49 | } 50 | 51 | public void setErrmsg(String errmsg) { 52 | this.errmsg = errmsg; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | final StringBuilder sb = new StringBuilder("{"); 58 | sb.append("\"access_token\":\"") 59 | .append(access_token).append('\"'); 60 | sb.append(",\"expires_in\":\"") 61 | .append(expires_in).append('\"'); 62 | sb.append(",\"errcode\":\"") 63 | .append(errcode).append('\"'); 64 | sb.append(",\"errmsg\":\"") 65 | .append(errmsg).append('\"'); 66 | sb.append('}'); 67 | return sb.toString(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/WeiXinTokenUtil.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import com.formtools.OtherConfig; 4 | import com.formtools.vo.WXToken; 5 | import org.springframework.web.client.RestTemplate; 6 | 7 | import java.time.Duration; 8 | import java.time.LocalDateTime; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author myl 14 | * @create 2020-02-26 17:23 15 | */ 16 | public class WeiXinTokenUtil { 17 | 18 | private static RestTemplate restTemplate=RestTemplateConfig.getRestTemplate(); 19 | private static String token=""; 20 | private static int expires_in=-1; 21 | private static LocalDateTime time=LocalDateTime.now(); 22 | 23 | private static final String GRANT_TYPE= OtherConfig.GRANT_TYPE; 24 | private static final String APPID=OtherConfig.APPID; 25 | private static final String SECRET=OtherConfig.SECRET; 26 | 27 | public static String getToken() { 28 | Duration duration=Duration.between(time,LocalDateTime.now()); 29 | // System.out.println("duration="+duration.toMillis()); 30 | if (duration.toMillis() params = new HashMap<>(); 36 | params.put("grant_type", GRANT_TYPE); 37 | params.put("appid", APPID); 38 | params.put("secret", SECRET); 39 | WXToken wxToken = restTemplate.getForObject(url, WXToken.class, params); 40 | // System.out.println("wxToken="+wxToken); 41 | if(wxToken.getErrcode()==null||wxToken.getErrcode()==0){ 42 | expires_in=wxToken.getExpires_in()-200; 43 | token=wxToken.getAccess_token(); 44 | time=LocalDateTime.now(); 45 | }else { 46 | expires_in=-1; 47 | token=""; 48 | } 49 | return token; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | mybatis.typeAliasesPackage=com.formtools.model 2 | mybatis.mapperLocations=classpath:mapper/*.xml 3 | 4 | spring.datasource.url=jdbc:mysql://localhost:3306/formtools?serverTimezone=GMT%2B8 5 | spring.datasource.username=root 6 | spring.datasource.password=123456 7 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 8 | 9 | # multipart\u4E0A\u4F20\u6587\u4EF6 10 | spring.servlet.multipart.enabled=true 11 | #\u5355\u4E2A\u6587\u4EF6\u4E0A\u4F20\u6700\u5927\u503C 12 | spring.servlet.multipart.max-file-size=200MB 13 | #\u5355\u6B21\u4E0A\u4F20\u6700\u5927\u503C 14 | spring.servlet.multipart.max-request-size=200MB 15 | 16 | # Redis\u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 17 | spring.redis.database=0 18 | # Redis\u670D\u52A1\u5668\u5730\u5740 19 | spring.redis.host=localhost 20 | # Redis\u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 21 | spring.redis.port=6379 22 | # Redis\u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09 23 | spring.redis.password= 24 | # \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 25 | spring.redis.jedis.pool.max-active=-1 26 | # \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 27 | spring.redis.jedis.pool.max-wait=60 28 | # \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 29 | spring.redis.jedis.pool.max-idle=8 30 | # \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 31 | spring.redis.jedis.pool.min-idle=0 32 | # \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09 33 | spring.redis.timeout=6000 34 | 35 | #\u4E0A\u4F20\u6587\u4EF6\u4F4D\u7F6E 36 | formDataFileDir=formDataFile/ 37 | #zip\u6587\u4EF6\u4F4D\u7F6E 38 | zipDir=zipFile/ 39 | 40 | swagger.title=FormTools\u9879\u76EE\u540E\u7AEF\u63A5\u53E3\u6587\u6863 41 | swagger.version=1.0.RELEASE 42 | swagger.base-package=com.formtools 43 | swagger.base-path=/** -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/page/edit/EditHeader.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 31 | 32 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/utils/JSONObjectTypeHandler.java: -------------------------------------------------------------------------------- 1 | package com.formtools.utils; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import org.apache.ibatis.type.BaseTypeHandler; 5 | import org.apache.ibatis.type.JdbcType; 6 | import org.apache.ibatis.type.MappedJdbcTypes; 7 | import org.apache.ibatis.type.MappedTypes; 8 | 9 | import java.sql.CallableStatement; 10 | import java.sql.PreparedStatement; 11 | import java.sql.ResultSet; 12 | import java.sql.SQLException; 13 | 14 | /** 15 | * @author myl 16 | * @create 2020-04-14 11:24 17 | */ 18 | @MappedJdbcTypes(JdbcType.VARCHAR) 19 | @MappedTypes({JSONObject.class}) 20 | public class JSONObjectTypeHandler extends BaseTypeHandler { 21 | 22 | /** 23 | * 将JSONObject存入数据库 24 | */ 25 | @Override 26 | public void setNonNullParameter(PreparedStatement ps, int i, JSONObject parameter, JdbcType jdbcType) throws SQLException { 27 | ps.setString(i, parameter.toJSONString()); 28 | } 29 | 30 | /** 31 | * 把字符串取出转换为JSONObject 32 | */ 33 | @Override 34 | public JSONObject getNullableResult(ResultSet rs, String columnName) throws SQLException { 35 | String json = rs.getString(columnName); 36 | if (null != json) { 37 | return JSONObject.parseObject(json); 38 | } 39 | return null; 40 | } 41 | 42 | /** 43 | * 把字符串取出转换为JSONObject 44 | */ 45 | @Override 46 | public JSONObject getNullableResult(ResultSet rs, int columnIndex) throws SQLException { 47 | String json = rs.getString(columnIndex); 48 | if (null != json) { 49 | return JSONObject.parseObject(json); 50 | } 51 | return null; 52 | } 53 | 54 | /** 55 | * 把字符串取出转换为JSONObject 56 | */ 57 | @Override 58 | public JSONObject getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { 59 | String json = cs.getString(columnIndex); 60 | if (null != json) { 61 | return JSONObject.parseObject(json); 62 | } 63 | return null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/vo/WeiXinUser.java: -------------------------------------------------------------------------------- 1 | package com.formtools.vo; 2 | 3 | import javax.validation.constraints.NotNull; 4 | 5 | /** 6 | * @author myl 7 | * @create 2020-02-23 21:36 8 | */ 9 | public class WeiXinUser { 10 | //微信小程序用户的openid 11 | @NotNull 12 | private String openid; 13 | //小程序码的参数 14 | @NotNull 15 | private String scene; 16 | //微信昵称 17 | @NotNull 18 | private String nickName; 19 | //微信头像 20 | @NotNull 21 | private String avatarUrl; 22 | 23 | public WeiXinUser() { 24 | } 25 | 26 | public WeiXinUser(String openid, String scene, String nickName, String avatarUrl) { 27 | this.openid = openid; 28 | this.scene = scene; 29 | this.nickName = nickName; 30 | this.avatarUrl = avatarUrl; 31 | } 32 | 33 | public String getOpenid() { 34 | return openid; 35 | } 36 | 37 | public void setOpenid(String openid) { 38 | this.openid = openid; 39 | } 40 | 41 | public String getScene() { 42 | return scene; 43 | } 44 | 45 | public void setScene(String scene) { 46 | this.scene = scene; 47 | } 48 | 49 | public String getNickName() { 50 | return nickName; 51 | } 52 | 53 | public void setNickName(String nickName) { 54 | this.nickName = nickName; 55 | } 56 | 57 | public String getAvatarUrl() { 58 | return avatarUrl; 59 | } 60 | 61 | public void setAvatarUrl(String avatarUrl) { 62 | this.avatarUrl = avatarUrl; 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | final StringBuilder sb = new StringBuilder("{"); 68 | sb.append("\"openid\":\"") 69 | .append(openid).append('\"'); 70 | sb.append(",\"scene\":\"") 71 | .append(scene).append('\"'); 72 | sb.append(",\"nickName\":\"") 73 | .append(nickName).append('\"'); 74 | sb.append(",\"avatarUrl\":\"") 75 | .append(avatarUrl).append('\"'); 76 | sb.append('}'); 77 | return sb.toString(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import javax.validation.constraints.NotEmpty; 8 | import javax.validation.constraints.NotNull; 9 | import javax.validation.groups.Default; 10 | 11 | /** 12 | * @author myl 13 | * @create 2020-03-27 11:18 14 | */ 15 | @ApiModel("用户基本信息") 16 | @JsonInclude(value = JsonInclude.Include.NON_NULL) 17 | public class UserInfo { 18 | public interface register extends Default {} 19 | 20 | //用户id 21 | private Long userId; 22 | 23 | @NotNull(groups = UserInfo.register.class) 24 | @NotEmpty(groups = UserInfo.register.class) 25 | //昵称 26 | @ApiModelProperty("用户昵称") 27 | private String nickname; 28 | 29 | //头像 30 | @ApiModelProperty("用户头像的url") 31 | private String profile; 32 | 33 | public UserInfo() { 34 | } 35 | 36 | public UserInfo(Long userId, String nickname, String profile) { 37 | this.userId = userId; 38 | this.nickname = nickname; 39 | this.profile = profile; 40 | } 41 | 42 | public Long getUserId() { 43 | return userId; 44 | } 45 | 46 | public void setUserId(Long userId) { 47 | this.userId = userId; 48 | } 49 | 50 | public String getNickname() { 51 | return nickname; 52 | } 53 | 54 | public void setNickname(String nickname) { 55 | this.nickname = nickname; 56 | } 57 | 58 | public String getProfile() { 59 | return profile; 60 | } 61 | 62 | public void setProfile(String profile) { 63 | this.profile = profile; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | final StringBuilder sb = new StringBuilder("{"); 69 | sb.append("\"userId\":\"") 70 | .append(userId).append('\"'); 71 | sb.append(",\"nickname\":\"") 72 | .append(nickname).append('\"'); 73 | sb.append(",\"profile\":\"") 74 | .append(profile).append('\"'); 75 | sb.append('}'); 76 | return sb.toString(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/page/EditForm.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 43 | 56 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/vo/ResultVo.java: -------------------------------------------------------------------------------- 1 | package com.formtools.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.formtools.enums.ErrorMsg; 5 | 6 | /** 7 | * @author NaNRailgun 8 | * @param 代返回数据 的 数据类型 9 | */ 10 | @JsonInclude(value = JsonInclude.Include.NON_NULL) 11 | public class ResultVo { 12 | 13 | private Integer status_code; 14 | private String msg; 15 | private T data; 16 | 17 | //直接返回成功状态码 18 | public static ResultVo success(){ 19 | ResultVo resultVo=new ResultVo(); 20 | resultVo.setStatus_code(1); 21 | return resultVo; 22 | } 23 | 24 | //返回成功状态码的同时返回对象 25 | public static ResultVo success(T data){ 26 | ResultVo resultVo=new ResultVo<>(); 27 | resultVo.setStatus_code(1); 28 | resultVo.setData(data); 29 | return resultVo; 30 | } 31 | 32 | //直接返回错误状态码和错误信息 33 | public static ResultVo fail(ErrorMsg errorMsg){ 34 | ResultVo resultVo=new ResultVo(); 35 | resultVo.setStatus_code(0); 36 | resultVo.setMsg(errorMsg.getMsg()); 37 | return resultVo; 38 | } 39 | 40 | //返回错误状态码和错误信息的同时返回错误对象 41 | public static ResultVo fail(ErrorMsg errorMsg,T data){ 42 | ResultVo resultVo=new ResultVo<>(); 43 | resultVo.setStatus_code(0); 44 | resultVo.setMsg(errorMsg.getMsg()); 45 | resultVo.setData(data); 46 | return resultVo; 47 | } 48 | 49 | 50 | public Integer getStatus_code() { 51 | return status_code; 52 | } 53 | 54 | public void setStatus_code(Integer status_code) { 55 | this.status_code = status_code; 56 | } 57 | 58 | public String getMsg() { 59 | return msg; 60 | } 61 | 62 | public void setMsg(String msg) { 63 | this.msg = msg; 64 | } 65 | 66 | public T getData() { 67 | return data; 68 | } 69 | 70 | public void setData(T data) { 71 | this.data = data; 72 | } 73 | 74 | public ResultVo(Integer status_code, String msg, T data) { 75 | this.status_code = status_code; 76 | this.msg = msg; 77 | this.data = data; 78 | } 79 | 80 | public ResultVo() { 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Server/src/main/resources/mapper/FillQuestionnaireMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | insert into fill_questionnaire 17 | (id,form_id,fill_content,fill_time) 18 | value (null,#{formId},#{fillContent,typeHandler=com.formtools.utils.JSONObjectTypeHandler},#{fillTime}) 19 | 20 | 21 | 24 | 25 | 26 | delete from fill_questionnaire where id=#{id} 27 | 28 | 29 | 30 | insert into fill_questionnaire (id,form_id,fill_content,fill_time) 31 | select null,#{formId},#{fillContent,typeHandler=com.formtools.utils.JSONObjectTypeHandler},now() 32 | where 33 | timestampdiff(second,(select begin_time from all_built_form where form_id=#{formId}),now()) > 0 34 | and 35 | timestampdiff(second,now(),(select end_time from all_built_form where form_id=#{formId})) > 0 36 | and 37 | (select max_count from all_built_form where form_id=#{formId}) > 38 | (select count(*) from fill_questionnaire where form_id=#{formId}) 39 | and 40 | (select form_type from all_built_form where form_id=#{formId}) = 'W' 41 | 42 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/FillQuestionnaire.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import javax.validation.constraints.NotNull; 8 | import java.sql.Timestamp; 9 | 10 | /** 11 | * @author myl 12 | * @create 2020-04-04 10:45 13 | */ 14 | @ApiModel("问卷类表单收集的信息") 15 | public class FillQuestionnaire { 16 | //自增id 17 | private Integer id; 18 | //表单id 19 | @NotNull 20 | private Long formId; 21 | //表单收集的数据 22 | @ApiModelProperty("用户填写的信息") 23 | private JSONObject fillContent; 24 | //填表时间 25 | @ApiModelProperty("用户填写完成的时间") 26 | private Timestamp fillTime; 27 | 28 | public FillQuestionnaire() { 29 | } 30 | 31 | public FillQuestionnaire(Long formId, JSONObject fillContent, Timestamp fillTime) { 32 | this.formId = formId; 33 | this.fillContent = fillContent; 34 | this.fillTime = fillTime; 35 | } 36 | 37 | public Integer getId() { 38 | return id; 39 | } 40 | 41 | public void setId(Integer id) { 42 | this.id = id; 43 | } 44 | 45 | public Long getFormId() { 46 | return formId; 47 | } 48 | 49 | public void setFormId(Long formId) { 50 | this.formId = formId; 51 | } 52 | 53 | public JSONObject getFillContent() { 54 | return fillContent; 55 | } 56 | 57 | public void setFillContent(JSONObject fillContent) { 58 | this.fillContent = fillContent; 59 | } 60 | 61 | public Timestamp getFillTime() { 62 | return fillTime; 63 | } 64 | 65 | public void setFillTime(Timestamp fillTime) { 66 | this.fillTime = fillTime; 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | final StringBuilder sb = new StringBuilder("{"); 72 | sb.append("\"id\":") 73 | .append(id); 74 | sb.append(",\"formId\":\"") 75 | .append(formId).append('\"'); 76 | sb.append(",\"fillContent\":\"") 77 | .append(fillContent).append('\"'); 78 | sb.append(",\"fillTime\":\"") 79 | .append(fillTime).append('\"'); 80 | sb.append('}'); 81 | return sb.toString(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/UserVerify.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import javax.validation.constraints.NotEmpty; 8 | import javax.validation.constraints.NotNull; 9 | import javax.validation.constraints.Null; 10 | 11 | /** 12 | * @author myl 13 | * @create 2020-03-27 11:27 14 | */ 15 | @ApiModel("用户的第三方账号信息") 16 | @JsonInclude(value = JsonInclude.Include.NON_NULL) 17 | public class UserVerify { 18 | @Null 19 | private Integer id; 20 | 21 | private Long userId; 22 | 23 | @NotNull 24 | @NotEmpty 25 | @ApiModelProperty("第三方账号id") 26 | private String openid; 27 | 28 | @ApiModelProperty("第三方账号类型") 29 | private Character type; 30 | 31 | public UserVerify() { 32 | } 33 | 34 | public UserVerify(@Null Integer id, Long userId, @NotNull @NotEmpty String openid, Character type) { 35 | this.id = id; 36 | this.userId = userId; 37 | this.openid = openid; 38 | this.type = type; 39 | } 40 | 41 | public Integer getId() { 42 | return id; 43 | } 44 | 45 | public void setId(Integer id) { 46 | this.id = id; 47 | } 48 | 49 | public Long getUserId() { 50 | return userId; 51 | } 52 | 53 | public void setUserId(Long userId) { 54 | this.userId = userId; 55 | } 56 | 57 | public String getOpenid() { 58 | return openid; 59 | } 60 | 61 | public void setOpenid(String openid) { 62 | this.openid = openid; 63 | } 64 | 65 | public Character getType() { 66 | return type; 67 | } 68 | 69 | public void setType(Character type) { 70 | this.type = type; 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | final StringBuilder sb = new StringBuilder("{"); 76 | sb.append("\"id\":") 77 | .append(id); 78 | sb.append(",\"userId\":") 79 | .append(userId); 80 | sb.append(",\"openid\":\"") 81 | .append(openid).append('\"'); 82 | sb.append(",\"type\":") 83 | .append(type); 84 | sb.append('}'); 85 | return sb.toString(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/vo/FillRegistryReq.java: -------------------------------------------------------------------------------- 1 | package com.formtools.vo; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import java.sql.Timestamp; 7 | 8 | public class FillRegistryReq { 9 | @NotNull 10 | private Long userId; 11 | @NotNull 12 | private Long formId; 13 | private JSONObject fillContent; 14 | private Timestamp fillTime; 15 | private Timestamp alterTime; 16 | private String fileList; 17 | private String checkState; 18 | 19 | 20 | public Long getUserId() { 21 | return userId; 22 | } 23 | 24 | public void setUserId(Long userId) { 25 | this.userId = userId; 26 | } 27 | 28 | public Long getFormId() { 29 | return formId; 30 | } 31 | 32 | public void setFormId(Long formId) { 33 | this.formId = formId; 34 | } 35 | 36 | public JSONObject getFillContent() { 37 | return fillContent; 38 | } 39 | 40 | public void setFillContent(JSONObject fillContent) { 41 | this.fillContent = fillContent; 42 | } 43 | 44 | public Timestamp getFillTime() { 45 | return fillTime; 46 | } 47 | 48 | public void setFillTime(Timestamp fillTime) { 49 | this.fillTime = fillTime; 50 | } 51 | 52 | public Timestamp getAlterTime() { 53 | return alterTime; 54 | } 55 | 56 | public void setAlterTime(Timestamp alterTime) { 57 | this.alterTime = alterTime; 58 | } 59 | 60 | public String getFileList() { 61 | return fileList; 62 | } 63 | 64 | public void setFileList(String fileList) { 65 | this.fileList = fileList; 66 | } 67 | 68 | public String getCheckState() { 69 | return checkState; 70 | } 71 | 72 | public void setCheckState(String checkState) { 73 | this.checkState = checkState; 74 | } 75 | 76 | public FillRegistryReq() { 77 | } 78 | 79 | public FillRegistryReq(Long userId, Long formId, JSONObject fillContent, Timestamp fillTime, Timestamp alterTime, String fileList, String checkState) { 80 | this.userId = userId; 81 | this.formId = formId; 82 | this.fillContent = fillContent; 83 | this.fillTime = fillTime; 84 | this.alterTime = alterTime; 85 | this.fileList = fileList; 86 | this.checkState = checkState; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/impl/BuiltFormServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service.impl; 2 | 3 | import com.formtools.mapper.BuiltFormMapper; 4 | import com.formtools.mapper.DraftFormMapper; 5 | import com.formtools.model.BuiltForm; 6 | import com.formtools.model.DraftForm; 7 | import com.formtools.service.BuiltFormService; 8 | import com.formtools.utils.IdBuilder; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.annotation.Transactional; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.List; 15 | 16 | /** 17 | * @author myl 18 | * @create 2020-04-13 16:13 19 | */ 20 | @Service 21 | public class BuiltFormServiceImpl implements BuiltFormService { 22 | 23 | @Resource 24 | BuiltFormMapper builtFormMapper; 25 | 26 | @Resource 27 | DraftFormMapper draftFormMapper; 28 | 29 | @Resource 30 | private RedisTemplate redisTemplate; 31 | 32 | /** 33 | * 查询所有已创建发布的表单的简略信息 34 | * @param userId 35 | * @return 36 | */ 37 | public List findAllBuiltForms(Long userId){ 38 | List builtForms=builtFormMapper.findAllBuiltForm(userId); 39 | return builtForms; 40 | } 41 | 42 | /** 43 | * 复制表单 44 | * @param formId 45 | * @return 46 | */ 47 | @Transactional 48 | public BuiltForm copyBuiltForm(Long formId){ 49 | BuiltForm builtForm=builtFormMapper.getBuiltForm(formId); 50 | builtForm.setFormId(IdBuilder.getFormId()); 51 | DraftForm draftForm=new DraftForm(builtForm,false); 52 | return draftFormMapper.addDraftForm(draftForm)==1?builtForm:null; 53 | } 54 | /** 55 | * 发布表单,并删除草稿 56 | * @param builtForm 57 | * @return 58 | */ 59 | @Transactional 60 | public boolean releaseForm(BuiltForm builtForm){ 61 | int bn=builtFormMapper.addBuiltForm(builtForm); 62 | draftFormMapper.deleteDraftForm(builtForm.getFormId(),builtForm.getUserId()); 63 | redisTemplate.delete(builtForm.getFormId().toString()+builtForm.getUserId().toString()); 64 | return bn==1; 65 | } 66 | 67 | public boolean deleteBuiltForm(Long formId,Long userId){ 68 | redisTemplate.delete(formId.toString()); 69 | return builtFormMapper.deleteBuiltForm(formId,userId)==1; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /WebApp/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 通用表单数据收集系统 8 | 9 | 10 | 11 | 20 | 21 | 22 |
23 |
24 | 30 |
31 |
32 | 52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/FillRegistryMapperTests.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.formtools.mapper.FillRegistryMapper; 6 | import com.formtools.model.FillRegistry; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | 10 | import javax.annotation.Resource; 11 | import java.sql.Timestamp; 12 | import java.util.List; 13 | 14 | /** 15 | * @author myl 16 | * @create 2020-04-04 11:13 17 | */ 18 | @SpringBootTest 19 | class FillRegistryMapperTests { 20 | 21 | @Resource 22 | FillRegistryMapper fillRegistryMapper; 23 | 24 | @Test 25 | void testAdd(){ 26 | JSONArray fileArray=new JSONArray(); 27 | fileArray.add("www/a/file1.zip"); 28 | fileArray.add("www/a/file2.zip"); 29 | fileArray.add("www/a/file3.zip"); 30 | FillRegistry fillRegistry=new FillRegistry(1114L,1234L, JSON.parseObject("{}"), 31 | new Timestamp(System.currentTimeMillis()), 32 | new Timestamp(System.currentTimeMillis()),fileArray.toString(),'T'); 33 | int n= fillRegistryMapper.addRegistry(fillRegistry); 34 | System.out.println(n); 35 | } 36 | 37 | @Test 38 | void getFilledRegistry(){ 39 | FillRegistry fillRegistry=fillRegistryMapper.getFilledRegistry(1111L,123L); 40 | System.out.println(fillRegistry); 41 | } 42 | 43 | @Test 44 | void testFindAllFilled(){ 45 | List allFilled=fillRegistryMapper.findAllFilled(1234L); 46 | for(FillRegistry data:allFilled) 47 | System.out.println(data); 48 | } 49 | 50 | @Test 51 | void testupdateFilledRegistry(){ 52 | JSONArray fileArray=new JSONArray(); 53 | fileArray.add("www/a/file1.zip"); 54 | fileArray.add("www/a/file2.zip"); 55 | FillRegistry fillRegistry=new FillRegistry(1114L,1234L,JSON.parseObject("{}"), 56 | new Timestamp(System.currentTimeMillis()), 57 | new Timestamp(System.currentTimeMillis()),fileArray.toString(),'F'); 58 | int n= fillRegistryMapper.updateFilledRegistry(fillRegistry); 59 | System.out.println(n); 60 | fillRegistry=fillRegistryMapper.getFilledRegistry(1114L,1234L); 61 | System.out.println(fillRegistry); 62 | } 63 | 64 | @Test 65 | void testcancelFilledRegistry(){ 66 | int n=fillRegistryMapper.cancelFilledRegistry(1114L,1234L,new Timestamp(System.currentTimeMillis())); 67 | System.out.println(n); 68 | } 69 | 70 | @Test 71 | void testdeleteFilledRegistry(){ 72 | int n=fillRegistryMapper.deleteFilledRegistry(1113L,1234L); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Server/src/main/resources/mapper/BuiltFormMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | insert into all_built_form 32 | (id,form_id,user_id,form_title,form_info,built_time, 33 | begin_time,end_time,max_count,form_type) 34 | value (null,#{formId},#{userId},#{formTitle},#{formInfo,typeHandler=com.formtools.utils.JSONObjectTypeHandler},#{builtTime}, 35 | #{beginTime},#{endTime},#{maxCount},#{formType}) 36 | 37 | 38 | 41 | 42 | 45 | 46 | 47 | update all_built_form 48 | 49 | 50 | form_info=#{formInfo,typeHandler=com.formtools.utils.JSONObjectTypeHandler}, 51 | 52 | 53 | form_title=#{formTitle}, 54 | 55 | 56 | begin_time=#{beginTime}, 57 | 58 | 59 | end_time=#{endTime}, 60 | 61 | 62 | max_count=#{maxCount}, 63 | 64 | 65 | where form_id=#{formId} 66 | 67 | 68 | 69 | delete from all_built_form where form_id= #{formId} and user_id=#{userId} 70 | 71 | 72 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/BuiltFormMapperTests.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.formtools.mapper.BuiltFormMapper; 5 | import com.formtools.model.BuiltForm; 6 | import org.junit.jupiter.api.AfterEach; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | import javax.annotation.Resource; 12 | import java.sql.Timestamp; 13 | import java.util.List; 14 | 15 | @SpringBootTest 16 | class BuiltFormMapperTests { 17 | 18 | @Resource 19 | BuiltFormMapper builtFormMapper; 20 | 21 | @BeforeEach 22 | void init() { 23 | System.out.println("开始测试-----------------"); 24 | } 25 | 26 | @AfterEach 27 | void after() { 28 | System.out.println("测试结束-----------------"); 29 | } 30 | 31 | @Test 32 | void testAddBuiltForm() { 33 | JSONObject jsonObject=new JSONObject(); 34 | jsonObject.put("aa","aaa"); 35 | BuiltForm builtForm=new BuiltForm(); 36 | builtForm.setFormId(22222L); 37 | builtForm.setUserId(111112L); 38 | builtForm.setFormTitle("标题"); 39 | builtForm.setFormInfo(jsonObject); 40 | builtForm.setBuiltTime(new Timestamp(System.currentTimeMillis())); 41 | builtForm.setBeginTime(new Timestamp(System.currentTimeMillis())); 42 | builtForm.setEndTime(new Timestamp(System.currentTimeMillis()+1000*60*60*24*10)); 43 | builtForm.setMaxCount(100); 44 | builtForm.setFormType("B"); 45 | int n=builtFormMapper.addBuiltForm(builtForm); 46 | System.out.println("插入"+n+"行"); 47 | } 48 | @Test 49 | void testGetBuiltForm(){ 50 | BuiltForm builtForm=builtFormMapper.getBuiltForm(33333L); 51 | System.out.println(builtForm); 52 | } 53 | @Test 54 | void testFindAllBuiltForm(){ 55 | List builtForms=builtFormMapper.findAllBuiltForm(111111L); 56 | for (BuiltForm builtForm:builtForms) 57 | System.out.println(builtForm); 58 | } 59 | 60 | @Test 61 | void testUpdateBuiltForm(){ 62 | JSONObject jsonObject=new JSONObject(); 63 | jsonObject.put("aa","aaa"); 64 | BuiltForm builtForm=new BuiltForm(); 65 | builtForm.setFormId(1111L); 66 | builtForm.setFormTitle("标题2"); 67 | builtForm.setFormInfo(jsonObject); 68 | builtForm.setBuiltTime(new Timestamp(System.currentTimeMillis())); 69 | builtForm.setBeginTime(new Timestamp(System.currentTimeMillis())); 70 | builtForm.setEndTime(new Timestamp(System.currentTimeMillis())); 71 | System.out.println(new Timestamp(System.currentTimeMillis())); 72 | builtForm.setMaxCount(500); 73 | int n=builtFormMapper.updateBuiltForm(builtForm); 74 | System.out.println("更改:"+n); 75 | } 76 | @Test 77 | void testDeleteBuiltForm(){ 78 | int n=builtFormMapper.deleteBuiltForm(2222L,111L); 79 | System.out.println(n); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Server/src/main/resources/mapper/DraftFormMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | insert into all_draft_form 31 | (id,form_id,user_id,form_title,form_info,built_time, 32 | begin_time,end_time,max_count,form_type,state) 33 | value (null,#{formId},#{userId},#{formTitle},#{formInfo,typeHandler=com.formtools.utils.JSONObjectTypeHandler},#{builtTime}, 34 | #{beginTime},#{endTime},#{maxCount},#{formType},#{state}) 35 | 36 | 37 | 40 | 41 | 44 | 45 | 46 | update all_draft_form 47 | 48 | 49 | form_info=#{formInfo,typeHandler=com.formtools.utils.JSONObjectTypeHandler}, 50 | 51 | 52 | form_title=#{formTitle}, 53 | 54 | 55 | built_time=#{builtTime}, 56 | 57 | 58 | begin_time=#{beginTime}, 59 | 60 | 61 | end_time=#{endTime}, 62 | 63 | 64 | max_count=#{maxCount}, 65 | 66 | 67 | state=#{state}, 68 | 69 | 70 | where form_id=#{formId} 71 | 72 | 73 | 74 | delete from all_draft_form where form_id= #{formId} and user_id=#{userId} 75 | 76 | 77 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/impl/DraftFormServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service.impl; 2 | 3 | import com.formtools.mapper.DraftFormMapper; 4 | import com.formtools.model.DraftForm; 5 | import com.formtools.service.DraftFormService; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.transaction.annotation.Transactional; 9 | 10 | import javax.annotation.Resource; 11 | import java.util.List; 12 | 13 | /** 14 | * @author myl 15 | * @create 2020-04-16 23:16 16 | */ 17 | @Service 18 | public class DraftFormServiceImpl implements DraftFormService { 19 | 20 | @Resource 21 | DraftFormMapper draftFormMapper; 22 | 23 | @Resource 24 | private RedisTemplate redisTemplate; 25 | 26 | /** 27 | * 查询所有草稿表单的简略信息 28 | * @param userId 29 | * @return 30 | */ 31 | public List findAllDraftForms(Long userId){ 32 | List draftForms=draftFormMapper.findAllDraftForm(userId); 33 | return draftForms; 34 | } 35 | 36 | /** 37 | * 创建一个草稿 38 | * @param draftForm 39 | * @return 40 | */ 41 | @Transactional 42 | public boolean addDraftForm(DraftForm draftForm){ 43 | return draftFormMapper.addDraftForm(draftForm)==1; 44 | } 45 | 46 | /** 47 | * 获取草稿 48 | * @param userId 49 | * @param formId 50 | * @return 51 | */ 52 | public DraftForm getDraftForm(Long userId,Long formId){ 53 | DraftForm draftForm=draftFormMapper.getDraftForm(formId,userId); 54 | if(null==draftForm)return null; 55 | if(draftForm.getState()){ 56 | DraftForm updataState=new DraftForm(); 57 | updataState.setState(false); 58 | updataState.setFormId(draftForm.getFormId()); 59 | draftFormMapper.updateDraftForm(updataState); 60 | redisTemplate.opsForValue().set(formId.toString()+userId.toString(),draftForm); 61 | return draftForm; 62 | } else { 63 | DraftForm draftForm1=(DraftForm) redisTemplate.opsForValue().get(formId.toString()+userId.toString()); 64 | return null==draftForm1?draftForm:draftForm1; 65 | } 66 | } 67 | 68 | /** 69 | * 实时保存表单信息 70 | * @param draftForm 71 | */ 72 | public void saveForm(DraftForm draftForm){ 73 | redisTemplate.opsForValue().set(draftForm.getFormId().toString()+draftForm.getUserId().toString(),draftForm); 74 | } 75 | 76 | /** 77 | * 保存草稿到MYSQL 78 | * @param draftForm 79 | * @return 80 | */ 81 | @Transactional 82 | public void saveDraft(DraftForm draftForm){ 83 | if(draftFormMapper.updateDraftForm(draftForm)==0){ 84 | draftFormMapper.addDraftForm(draftForm); 85 | redisTemplate.delete(draftForm.getFormId().toString()+draftForm.getUserId().toString()); 86 | } 87 | } 88 | 89 | public boolean deleteDraft(Long formId,Long userId){ 90 | redisTemplate.delete(formId.toString()+userId.toString()); 91 | return draftFormMapper.deleteDraftForm(formId,userId)==1; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /WebApp/PERSONAL.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 个人中心 6 | 7 | 8 | 9 | 10 | 12 |
13 |
14 | 23 |
24 |

一个在线审核表单

25 |
26 |
27 |

28 |
29 |

30 |
31 |

32 |
33 |

34 |
35 |
36 |
37 | 个人信息 38 | 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 | 47 | 48 |
49 |
50 | 51 | 52 |
53 |
54 | 55 | 56 |
57 |
58 | 59 |
60 |
61 | 修改 62 |
63 | 64 | 65 |
66 |
67 | 68 | 69 |
70 |
71 | 72 | 73 |
74 |
75 |
76 | 77 |
78 |
79 | 绑定(注意:绑定后不可修改) 80 | 81 | 82 |
83 |
84 | 85 | 86 |
87 |
88 | 89 |
90 |
91 | 92 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/DraftFormMapperTests.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.formtools.mapper.DraftFormMapper; 5 | import com.formtools.model.DraftForm; 6 | import org.junit.jupiter.api.AfterEach; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | import javax.annotation.Resource; 12 | import java.sql.Timestamp; 13 | import java.util.List; 14 | 15 | @SpringBootTest 16 | class DraftFormMapperTests { 17 | 18 | @Resource 19 | DraftFormMapper draftFormMapper; 20 | 21 | @BeforeEach 22 | void init() { 23 | System.out.println("开始测试-----------------"); 24 | } 25 | 26 | @AfterEach 27 | void after() { 28 | System.out.println("测试结束-----------------"); 29 | } 30 | 31 | @Test 32 | void testAddDraftForm() { 33 | JSONObject jsonObject=new JSONObject(); 34 | jsonObject.put("aa","aaa"); 35 | DraftForm draftForm = new DraftForm(); 36 | draftForm.setFormId(154688L); 37 | draftForm.setUserId(111112L); 38 | draftForm.setFormTitle("标题"); 39 | draftForm.setFormInfo(jsonObject); 40 | draftForm.setBuiltTime(new Timestamp(System.currentTimeMillis())); 41 | draftForm.setBeginTime(new Timestamp(System.currentTimeMillis())); 42 | draftForm.setEndTime(new Timestamp(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 10)); 43 | draftForm.setMaxCount(100); 44 | draftForm.setFormType("B"); 45 | draftForm.setState(false); 46 | int n = draftFormMapper.addDraftForm(draftForm); 47 | System.out.println("插入" + n + "行"); 48 | } 49 | 50 | @Test 51 | void testGetDraftForm() { 52 | DraftForm draftForm = draftFormMapper.getDraftForm(666666L,1111L); 53 | System.out.println(draftForm); 54 | } 55 | 56 | @Test 57 | void testFindAllDraftForm() { 58 | List draftForms = draftFormMapper.findAllDraftForm(111112L); 59 | for (DraftForm draftForm : draftForms) 60 | System.out.println(draftForm); 61 | } 62 | 63 | @Test 64 | void testUpdateDraftForm() { 65 | JSONObject jsonObject=new JSONObject(); 66 | jsonObject.put("aa","aaa"); 67 | DraftForm draftForm = new DraftForm(); 68 | draftForm.setFormId(666666L); 69 | draftForm.setUserId(111112L); 70 | draftForm.setFormTitle("标题"); 71 | draftForm.setFormInfo(jsonObject); 72 | draftForm.setBuiltTime(new Timestamp(System.currentTimeMillis())); 73 | draftForm.setBeginTime(new Timestamp(System.currentTimeMillis())); 74 | draftForm.setEndTime(new Timestamp(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 10)); 75 | draftForm.setMaxCount(100); 76 | draftForm.setFormType("B"); 77 | draftForm.setState(true); 78 | int n = draftFormMapper.updateDraftForm(draftForm); 79 | System.out.println("更改:" + n); 80 | } 81 | 82 | @Test 83 | void testDeleteBuiltForm() { 84 | int n = draftFormMapper.deleteDraftForm(22222L,11L); 85 | System.out.println(n); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/common/directives.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // v-dialogDrag: 弹窗拖拽属性 4 | Vue.directive('dialogDrag', { 5 | bind(el, binding, vnode, oldVnode) { 6 | const dialogHeaderEl = el.querySelector('.el-dialog__header'); 7 | const dragDom = el.querySelector('.el-dialog'); 8 | 9 | dialogHeaderEl.style.cssText += ';cursor:move;' 10 | dragDom.style.cssText += ';top:0px;' 11 | 12 | // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); 13 | const sty = (() => { 14 | if (window.document.currentStyle) { 15 | return (dom, attr) => dom.currentStyle[attr]; 16 | } else { 17 | return (dom, attr) => getComputedStyle(dom, false)[attr]; 18 | } 19 | })() 20 | 21 | dialogHeaderEl.onmousedown = (e) => { 22 | // 鼠标按下,计算当前元素距离可视区的距离 23 | const disX = e.clientX - dialogHeaderEl.offsetLeft; 24 | const disY = e.clientY - dialogHeaderEl.offsetTop; 25 | 26 | const screenWidth = document.body.clientWidth; // body当前宽度 27 | const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取) 28 | 29 | const dragDomWidth = dragDom.offsetWidth; // 对话框宽度 30 | const dragDomheight = dragDom.offsetHeight; // 对话框高度 31 | 32 | const minDragDomLeft = dragDom.offsetLeft; 33 | const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth; 34 | 35 | const minDragDomTop = dragDom.offsetTop; 36 | const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight; 37 | 38 | 39 | // 获取到的值带px 正则匹配替换 40 | let styL = sty(dragDom, 'left'); 41 | let styT = sty(dragDom, 'top'); 42 | 43 | // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px 44 | if (styL.includes('%')) { 45 | styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100); 46 | styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100); 47 | } else { 48 | styL = +styL.replace(/\px/g, ''); 49 | styT = +styT.replace(/\px/g, ''); 50 | }; 51 | 52 | document.onmousemove = function (e) { 53 | // 通过事件委托,计算移动的距离 54 | let left = e.clientX - disX; 55 | let top = e.clientY - disY; 56 | 57 | // 边界处理 58 | if (-(left) > minDragDomLeft) { 59 | left = -(minDragDomLeft); 60 | } else if (left > maxDragDomLeft) { 61 | left = maxDragDomLeft; 62 | } 63 | 64 | if (-(top) > minDragDomTop) { 65 | top = -(minDragDomTop); 66 | } else if (top > maxDragDomTop) { 67 | top = maxDragDomTop; 68 | } 69 | 70 | // 移动当前元素 71 | dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`; 72 | }; 73 | 74 | document.onmouseup = function (e) { 75 | document.onmousemove = null; 76 | document.onmouseup = null; 77 | }; 78 | } 79 | } 80 | }) 81 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/controller/FillQuestionnaireController.java: -------------------------------------------------------------------------------- 1 | package com.formtools.controller; 2 | 3 | import com.formtools.enums.ErrorMsg; 4 | import com.formtools.model.FillQuestionnaire; 5 | import com.formtools.model.FillRegistry; 6 | import com.formtools.service.FillQuestionnaireService; 7 | import com.formtools.utils.CookieUtil; 8 | import com.formtools.utils.ValidationUtil; 9 | import com.formtools.vo.ResultVo; 10 | import io.swagger.annotations.Api; 11 | import io.swagger.annotations.ApiOperation; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.annotation.Resource; 15 | import javax.servlet.http.Cookie; 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpServletResponse; 18 | import javax.validation.groups.Default; 19 | 20 | @Api(tags = "调查问卷") 21 | @RestController 22 | public class FillQuestionnaireController { 23 | 24 | @Resource 25 | private FillQuestionnaireService fillQuestionnaireService; 26 | 27 | @Resource 28 | private ValidationUtil validationUtil; 29 | 30 | /** 31 | * 提交问卷表答案 32 | * @param fillQuestionnaire 答案 33 | * @param request request 34 | * @param response response 35 | * @return 成功 36 | */ 37 | @ApiOperation("提交问卷答案") 38 | @PostMapping("/fill-questionnaire") 39 | public ResultVo InsertFillQuestionnaire(@RequestBody FillQuestionnaire fillQuestionnaire, HttpServletRequest request, HttpServletResponse response){ 40 | //参数验证 41 | validationUtil.validateParam(fillQuestionnaire,new Class[]{Default.class}); 42 | //表单id 43 | String formId=fillQuestionnaire.getFormId().toString(); 44 | //获取缓存key 45 | String key= CookieUtil.getKeyFromFormIdCookie(request,fillQuestionnaire.getFormId().toString()); 46 | //若key不存在 1.已提交过一次 2.没实时保存就提交 47 | if (key==null){ 48 | //返回重复提交失败 49 | return ResultVo.fail(ErrorMsg.REPEAT_COMMIT_ERROR); 50 | } 51 | 52 | boolean isSucceed; 53 | try { 54 | isSucceed=fillQuestionnaireService.insertFillQuestionnaire(key,fillQuestionnaire); 55 | } catch (Exception e) { 56 | //返回系统错误 57 | return ResultVo.fail(ErrorMsg.SYSTEM_ERROR); 58 | } 59 | if (isSucceed){ 60 | Cookie cookie=new Cookie(formId,null); 61 | cookie.setMaxAge(0); 62 | response.addCookie(cookie); 63 | return ResultVo.success(); 64 | } 65 | //返回提交失败 66 | return ResultVo.fail(ErrorMsg.COMMIT_FAIL_ERROR); 67 | } 68 | 69 | /** 70 | * 获取问卷答案缓存 71 | * @param fid 表id 72 | * @param request request 73 | * @return 问卷表 答案缓存 74 | */ 75 | @ApiOperation("获取问卷答案缓存") 76 | @GetMapping("/fill-questionnaire") 77 | public ResultVo getFillQuestionnaire(@RequestParam("formId") String fid,HttpServletRequest request){ 78 | //获取缓存key 79 | String key=CookieUtil.getKeyFromFormIdCookie(request,fid); 80 | if (key!=null){ 81 | FillRegistry fillQuestionnaire=fillQuestionnaireService.getFillQuestionnaireFromCache(key); 82 | return ResultVo.success(fillQuestionnaire); 83 | } 84 | //key为空 返回成功 空 85 | return ResultVo.success(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Server/src/test/java/com/formtools/UserModelMapperTests.java: -------------------------------------------------------------------------------- 1 | package com.formtools; 2 | 3 | import com.formtools.mapper.UserMapper; 4 | import com.formtools.model.EmailVerify; 5 | import com.formtools.model.UserInfo; 6 | import com.formtools.model.UserModel; 7 | import com.formtools.model.UserVerify; 8 | import com.formtools.service.impl.UserServiceImpl; 9 | import org.junit.jupiter.api.Test; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | 12 | import javax.annotation.Resource; 13 | 14 | /** 15 | * @author myl 16 | * @create 2020-02-05 22:33 17 | */ 18 | @SpringBootTest 19 | public class UserModelMapperTests { 20 | 21 | @Resource 22 | UserMapper userMapper; 23 | 24 | @Resource 25 | UserServiceImpl userService; 26 | 27 | @Test 28 | void testaddUserInfo(){ 29 | UserInfo userInfo=new UserInfo(111111111L,"***","***"); 30 | int i=userMapper.addUserInfo(userInfo); 31 | System.out.println(i); 32 | } 33 | 34 | @Test 35 | void testgetUserInfo(){ 36 | UserInfo userInfo=userMapper.getUserInfo(111111111L); 37 | System.out.println(userInfo); 38 | } 39 | 40 | @Test 41 | void testupdateUserInfo(){ 42 | UserInfo userInfo=new UserInfo(111111111L,"222","***"); 43 | int i=userMapper.updateUserInfo(userInfo); 44 | System.out.println(i); 45 | } 46 | 47 | @Test 48 | void testaddUserVerify(){ 49 | UserVerify userVerify=new UserVerify(null,111111111L,"1111",'w'); 50 | int i=userMapper.addUserVerify(userVerify); 51 | System.out.println(i); 52 | } 53 | 54 | @Test 55 | void testupdateUserVerify(){ 56 | UserVerify userVerify=new UserVerify(null,111111111L,"11112",'w'); 57 | int i=userMapper.updateUserVerify(userVerify); 58 | } 59 | 60 | @Test 61 | void testgetUserVerify(){ 62 | UserVerify userVerify=userMapper.getUserVerify("11112"); 63 | System.out.println(userVerify); 64 | } 65 | 66 | @Test 67 | void testaddEmailVerify(){ 68 | EmailVerify emailVerify=new EmailVerify(null,"123","123"); 69 | System.out.println(userMapper.addEmailVerify(emailVerify)); 70 | } 71 | 72 | @Test 73 | void testgetEmailVerify(){ 74 | EmailVerify emailVerify=userMapper.getEmailVerify("123"); 75 | System.out.println(emailVerify); 76 | } 77 | @Test 78 | void testupdateEmailVerify(){ 79 | EmailVerify emailVerify=userMapper.getEmailVerify("123"); 80 | emailVerify.setEmail("1234"); 81 | System.out.println(userMapper.updateEmailVerify(emailVerify)); 82 | emailVerify=userMapper.getEmailVerify("1234"); 83 | System.out.println(emailVerify); 84 | } 85 | @Test 86 | void updateUserInfoTest(){ 87 | UserModel userModel=new UserModel(); 88 | userModel.setProfile("111"); 89 | userModel.setNickname("haha"); 90 | userModel.setUserId(1585912422638L); 91 | 92 | System.out.println(userService.updateUserInfo(userModel)); 93 | System.out.println(); 94 | } 95 | @Test 96 | void getUserVerifyTypeTest(){ 97 | System.out.println(userMapper.getUserVerifyType(1L)); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /WebApp/Home Page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 首页 6 | 7 | 8 | 9 | 10 | 11 | 13 |
14 |
15 | 24 |
25 |

一个在线审核表单

26 |
27 |
28 |

创建活动报名

29 |
    30 |
  • 活动报名
  • 31 |
    32 |
    33 |
  • 会议报名
  • 34 |
    35 |
    36 |
  • 在线申请
  • 37 |
38 |
39 |
40 | 41 |
42 |
43 |

创建信息登记

44 |
    45 |
  • 学生信息
  • 46 |
    47 |
    48 |
  • 员工信息
  • 49 |
    50 |
    51 |
  • 客户信息
  • 52 |
53 |
54 |
55 | 56 |
57 |
58 |

创建问卷调查

59 |
    60 |
  • 市场调查
  • 61 |
    62 |
    63 |
  • 产品调查
  • 64 |
    65 |
    66 |
  • 学生调查
  • 67 |
68 |
69 |
70 | 71 |
72 |
73 |
74 |
75 |

ABOUT TOOLS

76 |

支持登陆和无登陆使用,填写问卷类无需登陆,为公示信息

77 |

审核提供私密的环境

78 |

独特的在线审核功能,在规定时间内可重复修改提交,后台

79 |

自动更新信息,大大降低了信息收集与整理的工作量,也大

80 |

大降低了信息的错误率。

81 |

支持临时通讯功能,管理者可随时发出信息错误的提醒,表

82 |

单创建者与填写者交流更方便,具有灵活的可操作性。

83 |
84 |
85 | 86 |
87 |
88 |

专属自定义表单

89 |
90 |

该表单工具应用于调查问卷,生活、工作

91 |

或学习的事物信息登记,各种活动的通知

92 |

发布和报名信息收集,各平台数据互通和

93 |

统一,且该工具使用完全免费。

94 |
95 |
96 | 97 |
98 | 99 |

首页 我的管理 我的参与 关于我们

100 |

工作时间

101 |

地址

102 | 103 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/impl/FillRegistryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service.impl; 2 | 3 | import com.formtools.mapper.BuiltFormMapper; 4 | import com.formtools.mapper.FillRegistryMapper; 5 | import com.formtools.model.BuiltForm; 6 | import com.formtools.model.FillRegistry; 7 | import com.formtools.service.FillRegistryService; 8 | import org.springframework.data.redis.core.RedisTemplate; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import javax.annotation.Resource; 13 | import java.util.UUID; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | @Service 17 | public class FillRegistryServiceImpl implements FillRegistryService { 18 | 19 | @Resource 20 | private BuiltFormMapper builtFormMapper; 21 | 22 | @Resource 23 | private FillRegistryMapper fillRegistryMapper; 24 | 25 | @Resource 26 | private RedisTemplate redisTemplate; 27 | 28 | /** 29 | * 获取表单基本信息、题目... 30 | * 31 | * @param formId 表单id 32 | * @return 表单基本信息(标题,题目,建表人... 33 | */ 34 | @Override 35 | public BuiltForm getFormInfo(Long formId) { 36 | 37 | String FormInfoKey = formId.toString(); 38 | 39 | //从缓存获取表单 题目信息 40 | BuiltForm builtForm = (BuiltForm) redisTemplate.opsForValue().get(FormInfoKey); 41 | //若缓存中不存在该表单 题目信息 42 | if (builtForm == null) { 43 | synchronized (this) { 44 | builtForm = builtFormMapper.getBuiltForm(formId); 45 | //若数据库查无此表 返回空 46 | if (builtForm == null) return null; 47 | redisTemplate.opsForValue().set(FormInfoKey, builtForm); 48 | } 49 | } 50 | return builtForm; 51 | } 52 | 53 | /** 54 | * 实时保存答案 55 | * 56 | * @param key 缓存的key 可为空 57 | * @param fillRegistry 答案 填表人信息 58 | * @return 缓存的key 59 | */ 60 | public String currentSaveAnswer(String key, FillRegistry fillRegistry) { 61 | //作为缓存的key 62 | String uuid = key; 63 | if (uuid == null) { 64 | uuid = UUID.randomUUID().toString(); 65 | } 66 | //设置过期时间为7天 67 | redisTemplate.opsForValue().set(uuid, fillRegistry, 7, TimeUnit.DAYS); 68 | return uuid; 69 | } 70 | 71 | /** 72 | * 获取答案 73 | * 74 | * @param userId 用户id 75 | * @param formId 表单id 76 | * @param key 缓存的key 可为空 77 | * @return 答案 78 | */ 79 | public FillRegistry getAnswer(Long userId, Long formId, String key) { 80 | //若缓存不存在 即为改表或填表 直接获取数据库 81 | if (key == null || "".equals(key)) { 82 | return fillRegistryMapper.getFilledRegistry(userId, formId); 83 | } else { 84 | return (FillRegistry) redisTemplate.opsForValue().get(key); 85 | } 86 | } 87 | 88 | /** 89 | * 插入答案(非问卷类 90 | * @param fillRegistry 答案 91 | * @param key 缓存key 92 | * @return 是否成功 93 | */ 94 | @Transactional 95 | public boolean insertRegistry(FillRegistry fillRegistry, String key) { 96 | if (fillRegistryMapper.insertFilledRegistry(fillRegistry) > 0) { 97 | redisTemplate.delete(key); 98 | return true; 99 | } 100 | return false; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/controller/WeiXinLoginController.java: -------------------------------------------------------------------------------- 1 | package com.formtools.controller; 2 | 3 | import com.formtools.OtherConfig; 4 | import com.formtools.enums.ErrorMsg; 5 | import com.formtools.model.UserModel; 6 | import com.formtools.service.OtherUserService; 7 | import com.formtools.utils.IdBuilder; 8 | import com.formtools.utils.WeiXinCodeUtil; 9 | import com.formtools.vo.ResultVo; 10 | import com.formtools.vo.WeiXinUser; 11 | import io.swagger.annotations.Api; 12 | import io.swagger.annotations.ApiOperation; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.http.MediaType; 15 | import org.springframework.validation.annotation.Validated; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import javax.servlet.http.Cookie; 19 | import javax.servlet.http.HttpServletResponse; 20 | import javax.validation.Valid; 21 | import java.util.concurrent.ConcurrentHashMap; 22 | 23 | /** 24 | * @author myl 25 | * @create 2020-02-23 21:39 26 | */ 27 | @Api(tags = "微信登录") 28 | @RestController 29 | @RequestMapping("/weixin") 30 | @Validated 31 | public class WeiXinLoginController { 32 | @Autowired 33 | private OtherUserService otherUserService; 34 | 35 | private static ConcurrentHashMap wxSceneMap = new ConcurrentHashMap(); 36 | /** 37 | * 返回小程序二维码和scene,二维码使用参数scene生成 38 | * 39 | * @return 40 | */ 41 | @ApiOperation("获取登录二维码和scene") 42 | @GetMapping(value = "/code", produces = MediaType.IMAGE_JPEG_VALUE) 43 | public byte[] getwxCode(HttpServletResponse response) { 44 | String scene = "scene" + IdBuilder.getSceneId(); 45 | byte[] code = WeiXinCodeUtil.getCode(scene); 46 | wxSceneMap.put(scene, "no"); 47 | response.setHeader("scene", scene); 48 | return code; 49 | } 50 | 51 | /** 52 | * 检验小程序中是否授权登录 53 | * 返回no即小程序端未授权登录 54 | * 返回yes即小程序端已授权登录 55 | * 56 | * @param scene 57 | * @return 58 | */ 59 | @ApiOperation("判断是否登录成功") 60 | @GetMapping("/isLogin") 61 | public ResultVo isLogin(@RequestParam String scene,HttpServletResponse response) { 62 | String sceneState = wxSceneMap.get(scene.trim()); 63 | if(sceneState==null){ 64 | return ResultVo.fail(ErrorMsg.PARAM_ERROR,"该scene不存在"); 65 | }else if (!sceneState.equals("no")) { 66 | Cookie uesrIdCookie=new Cookie("userId",sceneState); 67 | uesrIdCookie.setMaxAge(OtherConfig.cookieMaxAge); 68 | uesrIdCookie.setPath("/"); 69 | uesrIdCookie.setHttpOnly(true); 70 | response.addCookie(uesrIdCookie); 71 | wxSceneMap.remove(scene); 72 | return ResultVo.success("success"); 73 | } 74 | return ResultVo.success("no"); 75 | } 76 | 77 | /** 78 | * 小程序中调用该接口进行登录 79 | * @param wxUser 80 | * @return 81 | */ 82 | @ApiOperation("微信端调用进行登录") 83 | @PostMapping("/login") 84 | public ResultVo wxLogin(@RequestBody @Valid WeiXinUser wxUser) { 85 | Long userId=otherUserService.updateUser(wxUser.getNickName(),wxUser.getAvatarUrl(),wxUser.getOpenid(),'W'); 86 | if(userId!=null){ 87 | wxSceneMap.put(wxUser.getScene().trim(),String.valueOf(userId)); 88 | return ResultVo.success("success"); 89 | } 90 | return ResultVo.fail(ErrorMsg.SYSTEM_ERROR,"更新或添加用户信息时出错"); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/assets/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | html, 7 | body, 8 | #app, 9 | .wrapper { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | } 14 | 15 | body { 16 | font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif; 17 | } 18 | 19 | a { 20 | text-decoration: none 21 | } 22 | 23 | 24 | .content-box { 25 | position: absolute; 26 | left: 250px; 27 | right: 0; 28 | top: 70px; 29 | bottom: 0; 30 | padding-bottom: 30px; 31 | -webkit-transition: left .3s ease-in-out; 32 | transition: left .3s ease-in-out; 33 | background: #f0f0f0; 34 | } 35 | 36 | .content { 37 | width: auto; 38 | height: 100%; 39 | padding: 10px; 40 | overflow-y: scroll; 41 | box-sizing: border-box; 42 | } 43 | 44 | .content-collapse { 45 | left: 65px; 46 | } 47 | 48 | .container { 49 | padding: 30px; 50 | background: #fff; 51 | border: 1px solid #ddd; 52 | border-radius: 5px; 53 | } 54 | 55 | .crumbs { 56 | margin: 10px 0; 57 | } 58 | 59 | .el-table th { 60 | background-color: #f5f7fa !important; 61 | } 62 | 63 | .pagination { 64 | margin: 20px 0; 65 | text-align: right; 66 | } 67 | 68 | .plugins-tips { 69 | padding: 20px 10px; 70 | margin-bottom: 20px; 71 | } 72 | 73 | .el-button+.el-tooltip { 74 | margin-left: 10px; 75 | } 76 | 77 | .el-table tr:hover { 78 | background: #f6faff; 79 | } 80 | 81 | .mgb20 { 82 | margin-bottom: 20px; 83 | } 84 | 85 | .move-enter-active, 86 | .move-leave-active { 87 | transition: opacity .5s; 88 | } 89 | 90 | .move-enter, 91 | .move-leave { 92 | opacity: 0; 93 | } 94 | 95 | /*BaseForm*/ 96 | 97 | .form-box { 98 | width: 600px; 99 | } 100 | 101 | .form-box .line { 102 | text-align: center; 103 | } 104 | 105 | .el-time-panel__content::after, 106 | .el-time-panel__content::before { 107 | margin-top: -7px; 108 | } 109 | 110 | .el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) { 111 | padding-bottom: 0; 112 | } 113 | 114 | /*Upload*/ 115 | 116 | .pure-button { 117 | width: 150px; 118 | height: 40px; 119 | line-height: 40px; 120 | text-align: center; 121 | color: #fff; 122 | border-radius: 3px; 123 | } 124 | 125 | .g-core-image-corp-container .info-aside { 126 | height: 45px; 127 | } 128 | 129 | .el-upload--text { 130 | background-color: #fff; 131 | border: 1px dashed #d9d9d9; 132 | border-radius: 6px; 133 | box-sizing: border-box; 134 | width: 360px; 135 | height: 180px; 136 | text-align: center; 137 | cursor: pointer; 138 | position: relative; 139 | overflow: hidden; 140 | } 141 | 142 | .el-upload--text .el-icon-upload { 143 | font-size: 67px; 144 | color: #97a8be; 145 | margin: 40px 0 16px; 146 | line-height: 50px; 147 | } 148 | 149 | .el-upload--text { 150 | color: #97a8be; 151 | font-size: 14px; 152 | text-align: center; 153 | } 154 | 155 | .el-upload--text em { 156 | font-style: normal; 157 | } 158 | 159 | /*VueEditor*/ 160 | 161 | .ql-container { 162 | min-height: 400px; 163 | } 164 | 165 | .ql-snow .ql-tooltip { 166 | transform: translateX(117.5px) translateY(10px) !important; 167 | } 168 | 169 | .editor-btn { 170 | margin-top: 20px; 171 | } 172 | 173 | /*markdown*/ 174 | 175 | .v-note-wrapper .v-note-panel { 176 | min-height: 500px; 177 | } -------------------------------------------------------------------------------- /Server/src/main/resources/mapper/UserMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | insert into user_info values(#{userId},#{nickname},#{profile}) 26 | 27 | 28 | 31 | 32 | 33 | update user_info 34 | 35 | 36 | user_nickname=#{nickname}, 37 | 38 | 39 | user_profile=#{profile}, 40 | 41 | 42 | where user_id=#{userId} 43 | 44 | 45 | 46 | insert into user_verify values(null,#{userId},#{openid},#{type}) 47 | 48 | 49 | 50 | update user_verify 51 | 52 | 53 | openid=#{openid}, 54 | 55 | 56 | verify_type=#{type}, 57 | 58 | 59 | where user_id=#{userId} 60 | 61 | 62 | 65 | 66 | 69 | 70 | 71 | insert into email_verify values(null,#{email},#{password}) 72 | 73 | 74 | 75 | update email_verify 76 | 77 | 78 | user_password=#{password}, 79 | 80 | 81 | where user_email=#{email} 82 | 83 | 84 | 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | /FormTools.iml 4 | ### JetBrains template 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff 9 | .idea/**/workspace.xml 10 | .idea/**/tasks.xml 11 | .idea/**/usage.statistics.xml 12 | .idea/**/dictionaries 13 | .idea/**/shelf 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/modules.xml 36 | # .idea/*.iml 37 | # .idea/modules 38 | # *.iml 39 | # *.ipr 40 | 41 | # CMake 42 | cmake-build-*/ 43 | 44 | # Mongo Explorer plugin 45 | .idea/**/mongoSettings.xml 46 | 47 | # File-based project format 48 | *.iws 49 | 50 | # IntelliJ 51 | out/ 52 | 53 | # mpeltonen/sbt-idea plugin 54 | .idea_modules/ 55 | 56 | # JIRA plugin 57 | atlassian-ide-plugin.xml 58 | 59 | # Cursive Clojure plugin 60 | .idea/replstate.xml 61 | 62 | # Crashlytics plugin (for Android Studio and IntelliJ) 63 | com_crashlytics_export_strings.xml 64 | crashlytics.properties 65 | crashlytics-build.properties 66 | fabric.properties 67 | 68 | # Editor-based Rest Client 69 | .idea/httpRequests 70 | 71 | # Android studio 3.1+ serialized cache file 72 | .idea/caches/build_file_checksums.ser 73 | 74 | ### Eclipse template 75 | .metadata 76 | bin/ 77 | tmp/ 78 | *.tmp 79 | *.bak 80 | *.swp 81 | *~.nib 82 | local.properties 83 | .settings/ 84 | .loadpath 85 | .recommenders 86 | 87 | # External tool builders 88 | .externalToolBuilders/ 89 | 90 | # Locally stored "Eclipse launch configurations" 91 | *.launch 92 | 93 | # PyDev specific (Python IDE for Eclipse) 94 | *.pydevproject 95 | 96 | # CDT-specific (C/C++ Development Tooling) 97 | .cproject 98 | 99 | # CDT- autotools 100 | .autotools 101 | 102 | # Java annotation processor (APT) 103 | .factorypath 104 | 105 | # PDT-specific (PHP Development Tools) 106 | .buildpath 107 | 108 | # sbteclipse plugin 109 | .target 110 | 111 | # Tern plugin 112 | .tern-project 113 | 114 | # TeXlipse plugin 115 | .texlipse 116 | 117 | # STS (Spring Tool Suite) 118 | .springBeans 119 | 120 | # Code Recommenders 121 | .recommenders/ 122 | 123 | # Annotation Processing 124 | .apt_generated/ 125 | 126 | # Scala IDE specific (Scala & Java development for Eclipse) 127 | .cache-main 128 | .scala_dependencies 129 | .worksheet 130 | 131 | 132 | # IntelliJ project files 133 | 134 | out 135 | gen 136 | ### Java template 137 | # Compiled class file 138 | *.class 139 | 140 | # Log file 141 | *.log 142 | 143 | # BlueJ files 144 | *.ctxt 145 | 146 | # Mobile Tools for Java (J2ME) 147 | .mtj.tmp/ 148 | 149 | # Package Files # 150 | *.jar 151 | *.war 152 | *.nar 153 | *.ear 154 | *.zip 155 | *.tar.gz 156 | *.rar 157 | 158 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 159 | hs_err_pid* 160 | 161 | ### Maven template 162 | target/ 163 | pom.xml.tag 164 | pom.xml.releaseBackup 165 | pom.xml.versionsBackup 166 | pom.xml.next 167 | release.properties 168 | dependency-reduced-pom.xml 169 | buildNumber.properties 170 | .mvn/timing.properties 171 | .mvn/wrapper/maven-wrapper.jar 172 | 173 | formDataFile 174 | zipFile -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/controller/YiBanLoginController.java: -------------------------------------------------------------------------------- 1 | package com.formtools.controller; 2 | 3 | import cn.yiban.open.Authorize; 4 | import cn.yiban.open.common.User; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.formtools.OtherConfig; 7 | import com.formtools.service.OtherUserService; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiOperation; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | import springfox.documentation.annotations.ApiIgnore; 16 | 17 | import javax.servlet.http.Cookie; 18 | import javax.servlet.http.HttpServletResponse; 19 | 20 | /** 21 | * @author myl 22 | * @create 2020-02-23 23:02 23 | */ 24 | @Api(tags = "易班登录") 25 | @Controller 26 | @RequestMapping("/YBAPI") 27 | public class YiBanLoginController { 28 | @Autowired 29 | private OtherUserService otherUserService; 30 | 31 | private final String APP_ID= OtherConfig.APP_ID; 32 | private final String APP_SEC=OtherConfig.APP_SEC; 33 | private final String BACK_URL=OtherConfig.BACK_URL; 34 | private final String DEFAULTREDIRECTURL=OtherConfig.DEFAULTREDIRECTURL; 35 | 36 | @ApiOperation("登录") 37 | @GetMapping("/login") 38 | public String yblogin(@RequestParam(value = "state", 39 | defaultValue = DEFAULTREDIRECTURL)String state){ 40 | Authorize authorize=new Authorize(APP_ID,APP_SEC); 41 | String url = authorize.forwardurl(BACK_URL,state, Authorize.DISPLAY_TAG_T.WEB); 42 | return "redirect:"+url; 43 | } 44 | 45 | @ApiIgnore 46 | @RequestMapping("/auth") 47 | public String ybauth(@RequestParam(value = "code",required = false)String code, 48 | @RequestParam(value = "state", 49 | defaultValue = DEFAULTREDIRECTURL)String redirectURL, 50 | HttpServletResponse response){ 51 | if(code!=null){ 52 | Authorize authorize = new Authorize(APP_ID,APP_SEC ); 53 | String text = authorize.querytoken(code, BACK_URL); 54 | JSONObject textjson = JSONObject.parseObject(text); 55 | if(!textjson.containsKey("access_token")){ 56 | return "redirect:"+DEFAULTREDIRECTURL; 57 | } 58 | String token=textjson.getString("access_token"); 59 | User user=new User(token); 60 | String metext = user.me(); 61 | if(metext==null){ 62 | return "redirect:"+DEFAULTREDIRECTURL; 63 | } 64 | JSONObject me=JSONObject.parseObject(metext); 65 | if(!me.containsKey("status")||!me.getString("status").equals("success")){ 66 | return "redirect:"+DEFAULTREDIRECTURL; 67 | } 68 | JSONObject info=me.getJSONObject("info"); 69 | String openid=info.getString("yb_userid"); 70 | String nickname=info.getString("yb_username"); 71 | String profile=info.getString("yb_userhead"); 72 | Long userId=otherUserService.updateUser(nickname,profile,openid,'Y'); 73 | if(userId==null) return "redirect:"+DEFAULTREDIRECTURL; 74 | // System.out.println(userId); 75 | Cookie uesrIdCookie=new Cookie("userId",String.valueOf(userId)); 76 | uesrIdCookie.setMaxAge(OtherConfig.cookieMaxAge); 77 | uesrIdCookie.setPath("/"); 78 | uesrIdCookie.setHttpOnly(true); 79 | response.addCookie(uesrIdCookie); 80 | return "redirect:"+redirectURL; 81 | } 82 | return "redirect:"+DEFAULTREDIRECTURL; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/UserModel.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import javax.validation.constraints.Email; 8 | import javax.validation.constraints.NotEmpty; 9 | import javax.validation.constraints.NotNull; 10 | import javax.validation.groups.Default; 11 | import java.io.Serializable; 12 | 13 | /** 14 | * @author myl 15 | * @create 2020-02-05 21:59 16 | */ 17 | @ApiModel("用户所有信息") 18 | @JsonInclude(value = JsonInclude.Include.NON_NULL) 19 | public class UserModel implements Serializable { 20 | 21 | public interface register extends Default {} 22 | 23 | public interface resetPassword extends Default{} 24 | 25 | public interface updateUserInfo extends Default{} 26 | 27 | //用户id 28 | private Long userId; 29 | 30 | @NotNull(groups = {register.class,resetPassword.class}) 31 | @NotEmpty(groups = {register.class,resetPassword.class}) 32 | @Email(groups = {register.class,resetPassword.class}) 33 | //邮箱 34 | private String email; 35 | 36 | @NotNull(groups = {register.class,resetPassword.class}) 37 | @NotEmpty(groups = {register.class,resetPassword.class}) 38 | private String password; 39 | 40 | //昵称 41 | @NotNull(groups = {register.class,updateUserInfo.class}) 42 | @NotEmpty(groups = {register.class,updateUserInfo.class}) 43 | @ApiModelProperty("用户昵称") 44 | private String nickname; 45 | 46 | //头像 47 | @ApiModelProperty("用户头像的url") 48 | private String profile; 49 | 50 | public UserModel() { 51 | } 52 | 53 | public UserModel(Long userId, String nickname, String profile) { 54 | this.userId = userId; 55 | this.nickname = nickname; 56 | this.profile = profile; 57 | } 58 | 59 | public UserModel(Long userId, String email, String password, String nickname, String profile) { 60 | this.userId = userId; 61 | this.email = email; 62 | this.password = password; 63 | this.nickname = nickname; 64 | this.profile = profile; 65 | } 66 | 67 | public Long getUserId() { 68 | return userId; 69 | } 70 | 71 | public void setUserId(Long userId) { 72 | this.userId = userId; 73 | } 74 | 75 | public String getEmail() { 76 | return email; 77 | } 78 | 79 | public void setEmail(String email) { 80 | this.email = email; 81 | } 82 | 83 | public String getPassword() { 84 | return password; 85 | } 86 | 87 | public void setPassword(String password) { 88 | this.password = password; 89 | } 90 | 91 | public String getNickname() { 92 | return nickname; 93 | } 94 | 95 | public void setNickname(String nickname) { 96 | this.nickname = nickname; 97 | } 98 | 99 | public String getProfile() { 100 | return profile; 101 | } 102 | 103 | public void setProfile(String profile) { 104 | this.profile = profile; 105 | } 106 | 107 | @Override 108 | public String toString() { 109 | final StringBuilder sb = new StringBuilder("{"); 110 | sb.append("\"userId\":\"") 111 | .append(userId).append('\"'); 112 | sb.append(",\"email\":\"") 113 | .append(email).append('\"'); 114 | sb.append(",\"password\":\"") 115 | .append(password).append('\"'); 116 | sb.append(",\"nickname\":\"") 117 | .append(nickname).append('\"'); 118 | sb.append(",\"profile\":\"") 119 | .append(profile).append('\"'); 120 | sb.append('}'); 121 | return sb.toString(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Server/src/main/resources/mapper/FillRegistryMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | insert into fill_registry_form 21 | (id, user_id, form_id, fill_content, fill_time, alter_time, file_list, check_state) 22 | value (null, #{userId}, #{formId}, #{fillContent,typeHandler=com.formtools.utils.JSONObjectTypeHandler}, #{fillTime}, #{alterTime}, #{fileList}, #{checkState}) 23 | 24 | 25 | 31 | 32 | 37 | 38 | 39 | update fill_registry_form 40 | 41 | 42 | fill_content=#{fillContent,typeHandler=com.formtools.utils.JSONObjectTypeHandler}, 43 | 44 | 45 | alter_time=#{alterTime}, 46 | 47 | 48 | file_list=#{fileList}, 49 | 50 | 51 | check_state=#{checkState}, 52 | 53 | 54 | where user_id = #{userId} and form_id = #{formId} 55 | 56 | 57 | 58 | delete 59 | from fill_registry_form 60 | where user_id = #{userId} 61 | and form_id = #{formId} 62 | and (select end_time from all_built_form where form_id = #{formId}) >= #{now} 63 | 64 | 65 | 66 | update fill_registry_form 67 | set user_id=id 68 | where user_id = #{userId} 69 | and form_id = #{formId} 70 | 71 | 72 | 73 | insert into fill_registry_form (id,user_id,form_id,fill_content,fill_time,alter_time,file_list,check_state) 74 | select 75 | null,#{userId},#{formId},#{fillContent,typeHandler=com.formtools.utils.JSONObjectTypeHandler},now(),now(),#{fileList},#{checkState} 76 | where 77 | timestampdiff(second,(select begin_time from all_built_form where form_id=#{formId}),now()) > 0 78 | and 79 | timestampdiff(second,now(),(select end_time from all_built_form where form_id=#{formId})) > 0 80 | and 81 | (select max_count from all_built_form where form_id=#{formId}) > 82 | (select count(*) from fill_registry_form where form_id=#{formId}) 83 | and 84 | (select form_type from all_built_form where form_id=#{formId}) <> 'W' 85 | 86 | 87 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/FillRegistry.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | 7 | import javax.validation.constraints.NotNull; 8 | import java.io.Serializable; 9 | import java.sql.Timestamp; 10 | 11 | /** 12 | * @author myl 13 | * @create 2020-04-04 13:53 14 | */ 15 | @ApiModel("非问卷类表单收集的信息") 16 | public class FillRegistry implements Serializable { 17 | 18 | private Integer id; 19 | @NotNull 20 | private Long userId; 21 | @NotNull 22 | private Long formId; 23 | @ApiModelProperty("用户填写的信息") 24 | private JSONObject fillContent; 25 | @ApiModelProperty("用户填写完成的时间") 26 | private Timestamp fillTime; 27 | @ApiModelProperty("用户最后一次修改的时间") 28 | private Timestamp alterTime; 29 | @ApiModelProperty("附件列表,每个附件的url") 30 | private String fileList; 31 | @ApiModelProperty("审核类表单的状态") 32 | private Character checkState; 33 | 34 | public FillRegistry() { 35 | } 36 | 37 | public FillRegistry(Long userId, Long formId, JSONObject fillContent, Timestamp fillTime, Timestamp alterTime, String fileList, Character checkState) { 38 | this.userId = userId; 39 | this.formId = formId; 40 | this.fillContent = fillContent; 41 | this.fillTime = fillTime; 42 | this.alterTime = alterTime; 43 | this.fileList = fileList; 44 | this.checkState = checkState; 45 | } 46 | 47 | public Integer getId() { 48 | return id; 49 | } 50 | 51 | public void setId(Integer id) { 52 | this.id = id; 53 | } 54 | 55 | public Long getUserId() { 56 | return userId; 57 | } 58 | 59 | public void setUserId(Long userId) { 60 | this.userId = userId; 61 | } 62 | 63 | public Long getFormId() { 64 | return formId; 65 | } 66 | 67 | public void setFormId(Long formId) { 68 | this.formId = formId; 69 | } 70 | 71 | public JSONObject getFillContent() { 72 | return fillContent; 73 | } 74 | 75 | public void setFillContent(JSONObject fillContent) { 76 | this.fillContent = fillContent; 77 | } 78 | 79 | public Timestamp getFillTime() { 80 | return fillTime; 81 | } 82 | 83 | public void setFillTime(Timestamp fillTime) { 84 | this.fillTime = fillTime; 85 | } 86 | 87 | public Timestamp getAlterTime() { 88 | return alterTime; 89 | } 90 | 91 | public void setAlterTime(Timestamp alterTime) { 92 | this.alterTime = alterTime; 93 | } 94 | 95 | public String getFileList() { 96 | return fileList; 97 | } 98 | 99 | public void setFileList(String fileList) { 100 | this.fileList = fileList; 101 | } 102 | 103 | public Character getCheckState() { 104 | return checkState; 105 | } 106 | 107 | public void setCheckState(Character checkState) { 108 | this.checkState = checkState; 109 | } 110 | 111 | @Override 112 | public String toString() { 113 | final StringBuilder sb = new StringBuilder("{"); 114 | sb.append("\"id\":") 115 | .append(id); 116 | sb.append(",\"userId\":") 117 | .append(userId); 118 | sb.append(",\"formId\":") 119 | .append(formId); 120 | sb.append(",\"fillContent\":\"") 121 | .append(fillContent).append('\"'); 122 | sb.append(",\"fillTime\":\"") 123 | .append(fillTime).append('\"'); 124 | sb.append(",\"alterTime\":\"") 125 | .append(alterTime).append('\"'); 126 | sb.append(",\"fileList\":") 127 | .append(fileList); 128 | sb.append(",\"checkState\":") 129 | .append(checkState); 130 | sb.append('}'); 131 | return sb.toString(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/vo/BuildFormReq.java: -------------------------------------------------------------------------------- 1 | package com.formtools.vo; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import java.sql.Timestamp; 7 | 8 | /** 9 | * @author myl 10 | * @create 2020-04-04 21:24 11 | */ 12 | public class BuildFormReq { 13 | 14 | private Long formId; 15 | @NotNull 16 | private String formTitle; 17 | @NotNull 18 | private JSONObject formInfo; 19 | 20 | private Timestamp builtTime; 21 | 22 | private Timestamp beginTime; 23 | 24 | private Timestamp endTime; 25 | 26 | private Integer maxCount; 27 | @NotNull 28 | private String formType; 29 | 30 | private Short state; 31 | 32 | public BuildFormReq() { 33 | } 34 | 35 | public BuildFormReq(Long formId, String formTitle, JSONObject formInfo, Timestamp builtTime, Timestamp beginTime, Timestamp endTime, Integer maxCount, String formType, Short state) { 36 | this.formId = formId; 37 | this.formTitle = formTitle; 38 | this.formInfo = formInfo; 39 | this.builtTime = builtTime; 40 | this.beginTime = beginTime; 41 | this.endTime = endTime; 42 | this.maxCount = maxCount; 43 | this.formType = formType; 44 | this.state = state; 45 | } 46 | 47 | public String getFormTitle() { 48 | return formTitle; 49 | } 50 | 51 | public void setFormTitle(String formTitle) { 52 | this.formTitle = formTitle; 53 | } 54 | 55 | public JSONObject getFormInfo() { 56 | return formInfo; 57 | } 58 | 59 | public void setFormInfo(JSONObject formInfo) { 60 | this.formInfo = formInfo; 61 | } 62 | 63 | public Timestamp getBeginTime() { 64 | return beginTime; 65 | } 66 | 67 | public void setBeginTime(Timestamp beginTime) { 68 | this.beginTime = beginTime; 69 | } 70 | 71 | public Timestamp getEndTime() { 72 | return endTime; 73 | } 74 | 75 | public void setEndTime(Timestamp endTime) { 76 | this.endTime = endTime; 77 | } 78 | 79 | public Integer getMaxCount() { 80 | return maxCount; 81 | } 82 | 83 | public void setMaxCount(Integer maxCount) { 84 | this.maxCount = maxCount; 85 | } 86 | 87 | public String getFormType() { 88 | return formType; 89 | } 90 | 91 | public void setFormType(String formType) { 92 | this.formType = formType; 93 | } 94 | 95 | public Long getFormId() { 96 | return formId; 97 | } 98 | 99 | public void setFormId(Long formId) { 100 | this.formId = formId; 101 | } 102 | 103 | public Timestamp getBuiltTime() { 104 | return builtTime; 105 | } 106 | 107 | public void setBuiltTime(Timestamp builtTime) { 108 | this.builtTime = builtTime; 109 | } 110 | 111 | public Short getState() { 112 | return state; 113 | } 114 | 115 | public void setState(Short state) { 116 | this.state = state; 117 | } 118 | 119 | @Override 120 | public String toString() { 121 | final StringBuilder sb = new StringBuilder("{"); 122 | sb.append("\"formId\":") 123 | .append(formId); 124 | sb.append(",\"formTitle\":\"") 125 | .append(formTitle).append('\"'); 126 | sb.append(",\"formInfo\":") 127 | .append(formInfo); 128 | sb.append(",\"builtTime\":\"") 129 | .append(builtTime).append('\"'); 130 | sb.append(",\"beginTime\":\"") 131 | .append(beginTime).append('\"'); 132 | sb.append(",\"endTime\":\"") 133 | .append(endTime).append('\"'); 134 | sb.append(",\"maxCount\":") 135 | .append(maxCount); 136 | sb.append(",\"formType\":") 137 | .append(formType); 138 | sb.append(",\"state\":") 139 | .append(state); 140 | sb.append('}'); 141 | return sb.toString(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /WebApp/vue-formtools/src/components/page/FormDetails.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 103 | 104 | -------------------------------------------------------------------------------- /WebApp/css/edit.css: -------------------------------------------------------------------------------- 1 | @import url("//unpkg.com/element-ui@2.13.2/lib/theme-chalk/index.css"); 2 | body{ 3 | margin: 0; 4 | padding: 0; 5 | background-color: #f0f1f8; 6 | } 7 | a{ 8 | text-decoration:none; 9 | color: #000000; 10 | } 11 | .header{ 12 | padding-left: 140px; 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | background-color: #ffffff; 17 | box-shadow: 0px 1px 5px 1px #f5f5f5; 18 | position: fixed; 19 | top: 0; 20 | left: 0; 21 | right: 0; 22 | height: 50px; 23 | z-index: 1000; 24 | } 25 | .header-item{ 26 | padding: 0px 10px; 27 | margin: 10px 0px; 28 | font-size: 16px; 29 | } 30 | .header-item:not(:last-child) { 31 | border-right: 2px solid #eeeeee; 32 | } 33 | .header-item-select{ 34 | color: #1593ff; 35 | } 36 | .design-page-body{ 37 | margin-top: 50px; 38 | display: flex; 39 | } 40 | .menu-body{ 41 | padding: 10px; 42 | background-color: #ffffff; 43 | position: fixed; 44 | top: 50px; 45 | left: 0; 46 | bottom: 0; 47 | } 48 | .question_type{ 49 | padding: 10px; 50 | margin: 10px; 51 | border: 1px solid #dddddd; 52 | border-radius: 2px; 53 | } 54 | 55 | .form-design{ 56 | min-height: 1000px; 57 | width: 100%; 58 | margin-left: 150px; 59 | display: flex; 60 | justify-content: center; 61 | } 62 | .form-design-container{ 63 | margin-top: 20px; 64 | width: 700px; 65 | background-color: #ffffff; 66 | } 67 | 68 | .form-design-title input{ 69 | border: 0px; 70 | font-size: 22px; 71 | text-align: center; 72 | width: 100%; 73 | padding: 10px 0; 74 | margin-bottom: 2px; 75 | margin-top: 20px; 76 | } 77 | .form-design-title textarea{ 78 | text-align: center; 79 | border: none; 80 | resize:none; 81 | font-size: 18px; 82 | width: 100%; 83 | line-height:1.5; 84 | background-color: #ffffff; 85 | color: #676767; 86 | margin-bottom: 10px; 87 | } 88 | .form-design-container{ 89 | padding: 0 50px; 90 | } 91 | .form-design-question{ 92 | border: 1px solid #eeeeee; 93 | border-radius: 10px; 94 | margin-bottom: 20px; 95 | box-shadow: 0px 0px 5px 5px #eeeeee; 96 | } 97 | .form-design-question-index{ 98 | padding-left: 20px; 99 | padding-top: 10px; 100 | font-size: 20px; 101 | } 102 | .question-title{ 103 | display: flex; 104 | margin: 10px 20px; 105 | align-items: center; 106 | } 107 | .question-title-text{ 108 | font-size: 16px; 109 | min-width: 50px; 110 | height: 30px; 111 | line-height: 30px; 112 | } 113 | .question-tip{ 114 | display: flex; 115 | margin: 10px 20px; 116 | align-items: center; 117 | } 118 | .question-tip-text{ 119 | font-size: 14px; 120 | width: 40px; 121 | height: 30px; 122 | line-height: 30px; 123 | color: #777777; 124 | padding-left: 12px; 125 | } 126 | .question-tip-input{ 127 | width: 100%; 128 | } 129 | .question-set{ 130 | margin: 0px 20px 20px 60px; 131 | display: flex; 132 | align-items: center; 133 | justify-content: space-between; 134 | padding-bottom: 10px; 135 | } 136 | .question-select-container{ 137 | margin: 0px 20px 10px 65px; 138 | } 139 | .question-select-item{ 140 | display: flex; 141 | align-items: center; 142 | height: 55px; 143 | } 144 | .question-select-item-index{ 145 | width: 20px; 146 | } 147 | .question-select-add{ 148 | margin-left: 20px; 149 | } 150 | .form-question{ 151 | margin-bottom: 10px; 152 | } 153 | .question-item{ 154 | padding: 5px 20px; 155 | } 156 | .question-item-tip-text{ 157 | font-size: 14px; 158 | color: #777777; 159 | padding-top: 5px; 160 | padding-bottom: 10px; 161 | } 162 | .question-item-input{ 163 | width: 100%; 164 | height: 15px; 165 | border: 1px solid #999999; 166 | margin-bottom: 10px; 167 | border-radius: 4px; 168 | padding: 5px; 169 | font-size: 12px; 170 | color: #999999; 171 | } 172 | .question-item-radio{ 173 | display: flex; 174 | flex-direction: column; 175 | padding-bottom: 10px; 176 | } 177 | .question-item-radio label{ 178 | margin: 5px 0; 179 | } 180 | .question-item-checkbox{ 181 | width: 10px; 182 | margin-bottom: 10px; 183 | } 184 | .question-item-checkbox label{ 185 | margin: 5px 0; 186 | } 187 | .question-item-areatext{ 188 | width: 100%; 189 | height: 50px; 190 | border: 1px solid #999999; 191 | margin-bottom: 10px; 192 | border-radius: 4px; 193 | padding: 5px; 194 | font-size: 12px; 195 | color: #999999; 196 | } 197 | .question-select-item-input{ 198 | width: 100%; 199 | height: 20px; 200 | padding: 5px; 201 | } -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/model/BuiltForm.java: -------------------------------------------------------------------------------- 1 | package com.formtools.model; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import io.swagger.annotations.ApiModel; 6 | import io.swagger.annotations.ApiModelProperty; 7 | 8 | import java.io.Serializable; 9 | import java.sql.Timestamp; 10 | 11 | /** 12 | * 用户创建的表单, 13 | * 包含表单id、建表者id、储存表结构信息的JSON串 14 | * @author myl 15 | * @create 2020-02-05 14:13 16 | */ 17 | @ApiModel("表单信息") 18 | @JsonInclude(value = JsonInclude.Include.NON_NULL) 19 | public class BuiltForm implements Serializable { 20 | //自增id 21 | private Integer id; 22 | //表单id 23 | private Long formId; 24 | //建表者id 25 | private Long userId; 26 | //表单标题 27 | private String formTitle; 28 | //表单结构,是一个json串 29 | @ApiModelProperty("所有题目(一个JSON对象)") 30 | private JSONObject formInfo; 31 | //建表时间 32 | private Timestamp builtTime; 33 | //开始填表时间(默认为建表时间) 34 | private Timestamp beginTime; 35 | //截止时间(可无) 36 | private Timestamp endTime; 37 | //最多可填表的人数(可无) 38 | private Integer maxCount; 39 | //表单类型 40 | private String formType; 41 | 42 | public BuiltForm() { 43 | } 44 | 45 | public BuiltForm(Long formId, Long userId, String formTitle, JSONObject formInfo, Timestamp builtTime, Timestamp beginTime, Timestamp endTime, Integer maxCount, String formType) { 46 | this.formId = formId; 47 | this.userId = userId; 48 | this.formTitle = formTitle; 49 | this.formInfo = formInfo; 50 | this.builtTime = builtTime; 51 | this.beginTime = beginTime; 52 | this.endTime = endTime; 53 | this.maxCount = maxCount; 54 | this.formType = formType; 55 | } 56 | 57 | public Integer getId() { 58 | return id; 59 | } 60 | 61 | public void setId(Integer id) { 62 | this.id = id; 63 | } 64 | 65 | public Long getFormId() { 66 | return formId; 67 | } 68 | 69 | public void setFormId(Long formId) { 70 | this.formId = formId; 71 | } 72 | 73 | public Long getUserId() { 74 | return userId; 75 | } 76 | 77 | public void setUserId(Long userId) { 78 | this.userId = userId; 79 | } 80 | 81 | public String getFormTitle() { 82 | return formTitle; 83 | } 84 | 85 | public void setFormTitle(String formTitle) { 86 | this.formTitle = formTitle; 87 | } 88 | 89 | public JSONObject getFormInfo() { 90 | return formInfo; 91 | } 92 | 93 | public void setFormInfo(JSONObject formInfo) { 94 | this.formInfo = formInfo; 95 | } 96 | 97 | public Timestamp getBuiltTime() { 98 | return builtTime; 99 | } 100 | 101 | public void setBuiltTime(Timestamp builtTime) { 102 | this.builtTime = builtTime; 103 | } 104 | 105 | public Timestamp getBeginTime() { 106 | return beginTime; 107 | } 108 | 109 | public void setBeginTime(Timestamp beginTime) { 110 | this.beginTime = beginTime; 111 | } 112 | 113 | public Timestamp getEndTime() { 114 | return endTime; 115 | } 116 | 117 | public void setEndTime(Timestamp endTime) { 118 | this.endTime = endTime; 119 | } 120 | 121 | public Integer getMaxCount() { 122 | return maxCount; 123 | } 124 | 125 | public void setMaxCount(Integer maxCount) { 126 | this.maxCount = maxCount; 127 | } 128 | 129 | public String getFormType() { 130 | return formType; 131 | } 132 | 133 | public void setFormType(String formType) { 134 | this.formType = formType; 135 | } 136 | 137 | @Override 138 | public String toString() { 139 | final StringBuilder sb = new StringBuilder("{"); 140 | sb.append("\"id\":") 141 | .append(id); 142 | sb.append(",\"formId\":\"") 143 | .append(formId).append('\"'); 144 | sb.append(",\"userId\":\"") 145 | .append(userId).append('\"'); 146 | sb.append(",\"formTitle\":\"") 147 | .append(formTitle).append('\"'); 148 | sb.append(",\"formInfo\":\"") 149 | .append(formInfo).append('\"'); 150 | sb.append(",\"builtTime\":\"") 151 | .append(builtTime).append('\"'); 152 | sb.append(",\"beginTime\":\"") 153 | .append(beginTime).append('\"'); 154 | sb.append(",\"endTime\":\"") 155 | .append(endTime).append('\"'); 156 | sb.append(",\"maxCount\":") 157 | .append(maxCount); 158 | sb.append(",\"formType\":") 159 | .append(formType); 160 | sb.append('}'); 161 | return sb.toString(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/Handler/GlobalExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.formtools.Handler; 2 | 3 | import com.formtools.Exception.ParamException; 4 | import com.formtools.enums.ErrorMsg; 5 | import com.formtools.vo.ResultVo; 6 | import org.springframework.http.converter.HttpMessageNotReadableException; 7 | import org.springframework.validation.FieldError; 8 | import org.springframework.web.bind.MethodArgumentNotValidException; 9 | import org.springframework.web.bind.MissingRequestCookieException; 10 | import org.springframework.web.bind.MissingServletRequestParameterException; 11 | import org.springframework.web.bind.annotation.ControllerAdvice; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | import org.springframework.web.multipart.MultipartException; 15 | 16 | import javax.validation.ConstraintViolation; 17 | import javax.validation.ConstraintViolationException; 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | import java.util.Set; 21 | import java.util.stream.Collectors; 22 | 23 | @ControllerAdvice 24 | @ResponseBody 25 | public class GlobalExceptionHandler { 26 | 27 | /** 28 | * controller的方法参数错误 29 | * @param e 30 | * @return 31 | */ 32 | @ExceptionHandler(MethodArgumentNotValidException.class) 33 | public ResultVo MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { 34 | Map collect = e.getBindingResult().getFieldErrors().stream() 35 | .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage)); 36 | return ResultVo.fail(ErrorMsg.PARAM_ERROR,collect); 37 | } 38 | 39 | /** 40 | * 缺少request body错误 41 | * @return 42 | */ 43 | @ExceptionHandler(HttpMessageNotReadableException.class) 44 | public ResultVo HttpMessageNotReadableExceptionHandler() { 45 | return ResultVo.fail(ErrorMsg.MISSING_PARAMETER, "requestBody错误!"); 46 | } 47 | 48 | /** 49 | * url中缺少Query Params 50 | * @param e e.getMessage()返回首个缺少的参数名 51 | * @return 52 | */ 53 | @ExceptionHandler(MissingServletRequestParameterException.class) 54 | public ResultVo MissingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) { 55 | return ResultVo.fail(ErrorMsg.MISSING_PARAMETER, "缺少参数"+e.getParameterName()); 56 | } 57 | 58 | @ExceptionHandler(ConstraintViolationException.class) 59 | public ResultVo ConstraintViolationExceptionHandler(ConstraintViolationException e) { 60 | 61 | Set> set = e.getConstraintViolations(); 62 | Map map = new HashMap<>(); 63 | if (set.size() > 0) { 64 | for (ConstraintViolation cv : set) { 65 | String[] param = cv.getPropertyPath().toString().split("\\."); 66 | String message = cv.getMessage(); 67 | map.put(param[param.length - 1], message); 68 | } 69 | } 70 | 71 | return ResultVo.fail(ErrorMsg.PARAM_ERROR, map); 72 | } 73 | 74 | @ExceptionHandler(ParamException.class) 75 | public ResultVo ParamExceptionHandler(ParamException e) { 76 | return ResultVo.fail(ErrorMsg.PARAM_ERROR, e.getMap()); 77 | } 78 | 79 | /*@ExceptionHandler(Exception.class) 80 | public Object CommonExceptionHandler(Exception e){ 81 | return "服务器错误"; 82 | }*/ 83 | 84 | /** 85 | * 拦截文件过大异常 86 | * @param e 87 | * @return 88 | */ 89 | @ExceptionHandler(MultipartException.class) 90 | public ResultVo SizeLimitExceededExceptionHandler(Exception e){ 91 | return new ResultVo(0,e.getLocalizedMessage(),null); 92 | } 93 | 94 | /** 95 | * 拦截cookie缺失异常 96 | * @return 97 | */ 98 | @ExceptionHandler(MissingRequestCookieException.class) 99 | public ResultVo MissingRequestCookieExceptionHandler(){ 100 | return ResultVo.fail(ErrorMsg.COOKIE_ERROR); 101 | } 102 | } 103 | /** 104 | * DefaultHandlerExceptionResolver 105 | * 106 | * HttpRequestMethodNotSupportedException 107 | * 405 (SC_METHOD_NOT_ALLOWED) 108 | * HttpMediaTypeNotSupportedException 109 | * 415 (SC_UNSUPPORTED_MEDIA_TYPE) 110 | * HttpMediaTypeNotAcceptableException 111 | * 406 (SC_NOT_ACCEPTABLE) 112 | * MissingPathVariableException 113 | * 500 (SC_INTERNAL_SERVER_ERROR) 114 | * MissingServletRequestParameterException 115 | * 400 (SC_BAD_REQUEST) 116 | * ServletRequestBindingException 117 | * 400 (SC_BAD_REQUEST) 118 | * ConversionNotSupportedException 119 | * 500 (SC_INTERNAL_SERVER_ERROR) 120 | * TypeMismatchException 121 | * 400 (SC_BAD_REQUEST) 122 | * HttpMessageNotReadableException 123 | * 400 (SC_BAD_REQUEST) 124 | * HttpMessageNotWritableException 125 | * 500 (SC_INTERNAL_SERVER_ERROR) 126 | * MethodArgumentNotValidException 127 | * 400 (SC_BAD_REQUEST) 128 | * MissingServletRequestPartException 129 | * 400 (SC_BAD_REQUEST) 130 | * BindException 131 | * 400 (SC_BAD_REQUEST) 132 | * NoHandlerFoundException 133 | * 404 (SC_NOT_FOUND) 134 | * AsyncRequestTimeoutException 135 | * 503 (SC_SERVICE_UNAVAILABLE) 136 | */ -------------------------------------------------------------------------------- /Server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.4.RELEASE 9 | 10 | 11 | com 12 | formtools 13 | 0.0.1-SNAPSHOT 14 | war 15 | formtools 16 | 通用表单工具 17 | 18 | 19 | 1.8 20 | true 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.mybatis.spring.boot 30 | mybatis-spring-boot-starter 31 | 2.1.1 32 | 33 | 34 | 35 | javax.mail 36 | mail 37 | 1.4.7 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-devtools 44 | runtime 45 | true 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-tomcat 50 | provided 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | test 56 | 57 | 58 | org.junit.vintage 59 | junit-vintage-engine 60 | 61 | 62 | 63 | 64 | 65 | mysql 66 | mysql-connector-java 67 | 8.0.18 68 | 69 | 70 | com.alibaba 71 | fastjson 72 | 1.2.61 73 | 74 | 75 | org.apache.httpcomponents 76 | httpclient 77 | 4.5.9 78 | 79 | 80 | yb 81 | OpenApi 82 | 1.0 83 | system 84 | ${pom.basedir}/lib/yb/OpenApi/1.0/YBOpenApi.jar 85 | 86 | 87 | 88 | org.springframework.boot 89 | spring-boot-starter-data-redis 90 | 91 | 92 | 93 | com.spring4all 94 | swagger-spring-boot-starter 95 | 1.9.1.RELEASE 96 | 97 | 98 | 99 | 100 | 101 | org.springframework.boot 102 | spring-boot-maven-plugin 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | org.apache.maven.plugins 114 | maven-war-plugin 115 | 116 |   117 |           118 | ${pom.basedir}/lib/yb/OpenApi/1.0 119 | WEB-INF/lib/ 120 |   121 | **/*.jar           122 |     123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /Server/src/main/resources/sql/formtools.sql: -------------------------------------------------------------------------------- 1 | /* 2 | SQLyog Ultimate v11.33 (64 bit) 3 | MySQL - 8.0.18 : Database - formtools 4 | ********************************************************************* 5 | */ 6 | 7 | 8 | /*!40101 SET NAMES utf8mb4 */; 9 | 10 | /*!40101 SET SQL_MODE=''*/; 11 | 12 | 13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 17 | CREATE DATABASE /*!32312 IF NOT EXISTS*/`formtools` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; 18 | 19 | USE `formtools`; 20 | 21 | DROP TABLE IF EXISTS `all_draft_form`; 22 | 23 | CREATE TABLE `all_draft_form` 24 | ( 25 | `id` INT NOT NULL AUTO_INCREMENT, 26 | `form_id` BIGINT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单的id', 27 | `user_id` BIGINT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单创建者的userId', 28 | `form_title` VARCHAR(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单标题', 29 | `form_info` TEXT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单的信息', 30 | `built_time` DATETIME NOT NULL COMMENT '建表时间', 31 | `begin_time` DATETIME NOT NULL COMMENT '开始填表时间(默认为建表时间)', 32 | `end_time` DATETIME DEFAULT NULL COMMENT '截止时间(可无)', 33 | `max_count` INT DEFAULT NULL COMMENT '最多可填表的人数(可无)', 34 | `form_type` CHAR(1) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单类型 (问卷:W;登记:D,报名:B)', 35 | `state` BIT NOT NULL COMMENT '草稿是否持久化', 36 | UNIQUE (`form_id`), 37 | PRIMARY KEY (`id`) 38 | ) ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci; 39 | 40 | /*Table structure for table `all_built_form` */ 41 | 42 | DROP TABLE IF EXISTS `all_built_form`; 43 | 44 | CREATE TABLE `all_built_form` ( 45 | `id` INT NOT NULL AUTO_INCREMENT, 46 | `form_id` BIGINT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单的id', 47 | `user_id` BIGINT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单创建者的userId', 48 | `form_title` VARCHAR(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单标题', 49 | `form_info` TEXT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单的信息', 50 | `built_time` DATETIME NOT NULL COMMENT '建表时间', 51 | `begin_time` DATETIME NOT NULL COMMENT '开始填表时间(默认为建表时间)', 52 | `end_time` DATETIME DEFAULT NULL COMMENT '截止时间(可无)', 53 | `max_count` INT DEFAULT NULL COMMENT '最多可填表的人数(可无)', 54 | `form_type` CHAR(1) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '表单类型 (问卷:W;登记:D,报名:B)', 55 | UNIQUE (`form_id`), 56 | PRIMARY KEY (`id`) 57 | ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 58 | 59 | /*Data for the table `all_built_form` */ 60 | 61 | /*Table structure for table `email_verify` */ 62 | 63 | DROP TABLE IF EXISTS `email_verify`; 64 | 65 | CREATE TABLE `email_verify` ( 66 | `id` INT NOT NULL AUTO_INCREMENT, 67 | `user_email` VARCHAR(30) COLLATE utf8mb4_unicode_ci NOT NULL, 68 | `user_password` VARCHAR(30) COLLATE utf8mb4_unicode_ci NOT NULL, 69 | UNIQUE (`user_email`), 70 | PRIMARY KEY (`id`) 71 | ) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 72 | 73 | /*Data for the table `email_verify` */ 74 | 75 | 76 | /*Table structure for table `fill_questionnaire` */ 77 | 78 | DROP TABLE IF EXISTS `fill_questionnaire`; 79 | 80 | CREATE TABLE `fill_questionnaire` ( 81 | `id` INT NOT NULL AUTO_INCREMENT, 82 | `form_id` BIGINT NOT NULL COMMENT '表单id', 83 | `fill_content` TEXT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '填写的内容', 84 | `fill_time` DATETIME NOT NULL COMMENT '填表时间', 85 | PRIMARY KEY (`id`) 86 | ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 87 | 88 | /*Data for the table `fill_questionnaire` */ 89 | 90 | /*Table structure for table `fill_registry_form` */ 91 | 92 | DROP TABLE IF EXISTS `fill_registry_form`; 93 | 94 | CREATE TABLE `fill_registry_form` ( 95 | `id` INT NOT NULL AUTO_INCREMENT, 96 | `user_id` BIGINT NOT NULL COMMENT '填表用户id', 97 | `form_id` BIGINT NOT NULL COMMENT '表单id', 98 | `fill_content` TEXT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '填写的内容', 99 | `fill_time` DATETIME NOT NULL COMMENT '填表时间', 100 | `alter_time` DATETIME NOT NULL COMMENT '修改时间', 101 | `file_list` TEXT COLLATE utf8mb4_unicode_ci COMMENT '所有附件的路径集合', 102 | `check_state` CHAR(1) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核情况', 103 | CONSTRAINT DATA_ID UNIQUE (`user_id`,`form_id`), 104 | PRIMARY KEY (`id`) 105 | ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 106 | 107 | /*Data for the table `fill_registry_form` */ 108 | 109 | /*Table structure for table `user_info` */ 110 | 111 | DROP TABLE IF EXISTS `user_info`; 112 | 113 | CREATE TABLE `user_info` ( 114 | `user_id` BIGINT NOT NULL COMMENT '用户唯一id', 115 | `user_nickname` VARCHAR(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户昵称', 116 | `user_profile` TEXT COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户头像的url', 117 | PRIMARY KEY (`user_id`) 118 | ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 119 | 120 | /*Table structure for table `user_verify` */ 121 | 122 | DROP TABLE IF EXISTS `user_verify`; 123 | 124 | CREATE TABLE `user_verify` ( 125 | `id` INT NOT NULL AUTO_INCREMENT, 126 | `user_id` BIGINT NOT NULL, 127 | `openid` VARCHAR(30) COLLATE utf8mb4_unicode_ci NOT NULL, 128 | `verify_type` CHAR(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, 129 | UNIQUE (`openid`), 130 | PRIMARY KEY (`id`) 131 | ) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; 132 | 133 | 134 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 135 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 136 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 137 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 138 | -------------------------------------------------------------------------------- /Server/src/main/java/com/formtools/service/impl/FileServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.formtools.service.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Service; 5 | import org.springframework.transaction.annotation.Transactional; 6 | import org.springframework.web.multipart.MultipartFile; 7 | 8 | import java.io.*; 9 | import java.util.zip.ZipEntry; 10 | import java.util.zip.ZipOutputStream; 11 | 12 | @Service 13 | public class FileServiceImpl { 14 | 15 | @Value("${formDataFileDir}") 16 | private String formDataFileDir; 17 | 18 | /** 19 | * 储存路径为 "(上线需更改配置文件)formDataFileDir/表单id/用户id+用户名” 20 | * 判断文件夹是否存在,判断文件是否存在 21 | * 文件夹不存在则创建 文件存在则覆盖 22 | * 返回保存成功或失败 23 | * @param userId 24 | * @param userName 25 | * @param formId 26 | * @param multipartFile 27 | * @return 28 | * @throws IOException 29 | */ 30 | @Transactional(rollbackFor = Exception.class) 31 | public boolean uploadFile(String userId, String userName, String formId, MultipartFile multipartFile) throws IOException { 32 | File fileDir = new File(formDataFileDir + formId + "\\" + userId + userName);//该用户于该表中文件储存位置 33 | if (!fileDir.exists()) { 34 | //创建文件夹 35 | if (!fileDir.mkdirs()) { 36 | return false; 37 | } 38 | } 39 | File file = new File(fileDir.getAbsolutePath() + "\\" + multipartFile.getOriginalFilename());//需保存的文件 40 | if (file.exists()) { 41 | if (!file.delete()) { 42 | return false; 43 | } 44 | } 45 | if (file.createNewFile()) { 46 | multipartFile.transferTo(file); 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | /** 53 | * 将 “(上线需更改配置文件)formDataFileDir/表单id”路径下的文件打包 54 | * 将zip包放置于zipDir(上线需更改配置文件)下 55 | * 重复请求会重新打包,把原有zip覆盖。 56 | * ps 这段具体实现不要问我,我忘光了。 57 | * @param sourceFilePath 待压缩文件(夹)路径 58 | * @param targetPath 压缩文件所在目录 59 | * @param zipFileName 压缩后的文件名称{.zip结尾} 60 | * @return 61 | * @Description: 创建zip文件 62 | */ 63 | public boolean createZipFile(String sourceFilePath, String targetPath, String zipFileName) throws FileNotFoundException { 64 | 65 | boolean flag = false; 66 | FileOutputStream fos = null; 67 | ZipOutputStream zos = null; 68 | 69 | // 要压缩的文件资源 70 | File sourceFile = new File(sourceFilePath); 71 | // zip文件存放路径 72 | String zipPath = ""; 73 | 74 | if (null != targetPath && !"".equals(targetPath)) { 75 | zipPath = targetPath + File.separator + zipFileName; 76 | } else { 77 | zipPath = new File(sourceFilePath).getParent() + File.separator + zipFileName; 78 | } 79 | 80 | if (!sourceFile.exists()) { 81 | System.out.println("待压缩的文件目录:" + sourceFilePath + "不存在."); 82 | return flag; 83 | } 84 | 85 | try { 86 | File zipFile = new File(zipPath); 87 | if (zipFile.exists()) { 88 | zipFile.delete(); 89 | } 90 | File[] sourceFiles = sourceFile.listFiles(); 91 | 92 | fos = new FileOutputStream(zipPath); 93 | zos = new ZipOutputStream(new BufferedOutputStream(fos)); 94 | // 生成压缩文件 95 | writeZip(sourceFile, "", zos); 96 | flag = true; 97 | 98 | 99 | } catch (FileNotFoundException e) { 100 | e.printStackTrace(); 101 | } finally { 102 | //关闭流 103 | try { 104 | if (null != zos) { 105 | zos.close(); 106 | } 107 | if (null != fos) { 108 | fos.close(); 109 | } 110 | } catch (IOException e) { 111 | e.printStackTrace(); 112 | } 113 | } 114 | return flag; 115 | } 116 | 117 | /** 118 | * @param file 119 | * @param parentPath 120 | * @param zos 121 | * @Description: 122 | */ 123 | private void writeZip(File file, String parentPath, ZipOutputStream zos) { 124 | if (file.exists()) { 125 | // 处理文件夹 126 | if (file.isDirectory()) { 127 | parentPath += file.getName() + File.separator; 128 | File[] files = file.listFiles(); 129 | if (files != null && files.length != 0) { 130 | for (File f : files) { 131 | // 递归调用 132 | writeZip(f, parentPath, zos); 133 | } 134 | } else { 135 | // 空目录则创建当前目录的ZipEntry 136 | try { 137 | zos.putNextEntry(new ZipEntry(parentPath)); 138 | } catch (IOException e) { 139 | e.printStackTrace(); 140 | } 141 | } 142 | } else { 143 | FileInputStream fis = null; 144 | try { 145 | fis = new FileInputStream(file); 146 | ZipEntry ze = new ZipEntry(parentPath + file.getName()); 147 | zos.putNextEntry(ze); 148 | byte[] content = new byte[1024]; 149 | int len; 150 | while ((len = fis.read(content)) != -1) { 151 | zos.write(content, 0, len); 152 | zos.flush(); 153 | } 154 | } catch (IOException e) { 155 | System.out.println(("创建ZIP文件失败")); 156 | } finally { 157 | try { 158 | if (fis != null) { 159 | fis.close(); 160 | } 161 | } catch (IOException e) { 162 | System.out.println(("创建ZIP文件失败")); 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | --------------------------------------------------------------------------------