diff --git a/orange-demo-service/zz-orange-demo.sql b/orange-demo-service/zz-orange-demo.sql index 34057e46..9e113342 100644 --- a/orange-demo-service/zz-orange-demo.sql +++ b/orange-demo-service/zz-orange-demo.sql @@ -266,7 +266,7 @@ CREATE TABLE `zz_student` ( `birthday` date NOT NULL COMMENT '生日', `experience_level` tinyint(4) NOT NULL COMMENT '经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)', `total_coin` int(11) NOT NULL DEFAULT '0' COMMENT '总共充值学币数量', - `left_coin` int(11) NOT NULL COMMENT '可用学币数量', + `left_coin` int(11) NOT NULL DEFAULT '0' COMMENT '可用学币数量', `grade_id` int(11) NOT NULL COMMENT '年级Id', `school_id` bigint(20) NOT NULL COMMENT '校区Id', `register_time` datetime NOT NULL COMMENT '注册时间', @@ -648,10 +648,6 @@ INSERT INTO `zz_sys_menu` VALUES (1093809448598376533, 1093376634916704256, '新 INSERT INTO `zz_sys_menu` VALUES (1093809448598376534, 1093376634916704256, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); INSERT INTO `zz_sys_menu` VALUES (1093809448598376535, 1093376634916704256, '删除', 3, NULL, 4, NULL, CURDATE(), 1); INSERT INTO `zz_sys_menu` VALUES (1093809448598376536, 1093376634916704256, '重置密码', 3, NULL, 5, NULL, CURDATE(), 1); -INSERT INTO `zz_sys_menu` VALUES (1093809448598376544, 1093376634916704257, '显示', 3, NULL, 1, NULL, CURDATE(), 1); -INSERT INTO `zz_sys_menu` VALUES (1093809448598376545, 1093376634916704257, '新增', 3, NULL, 2, NULL, CURDATE(), 1); -INSERT INTO `zz_sys_menu` VALUES (1093809448598376546, 1093376634916704257, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); -INSERT INTO `zz_sys_menu` VALUES (1093809448598376547, 1093376634916704257, '删除', 3, NULL, 4, NULL, CURDATE(), 1); INSERT INTO `zz_sys_menu` VALUES (1093809448598376554, 1093376634916704258, '角色管理', 2, NULL, 1, NULL, CURDATE(), 1); INSERT INTO `zz_sys_menu` VALUES (1093809448598376555, 1093376634916704258, '用户授权', 2, NULL, 2, NULL, CURDATE(), 1); INSERT INTO `zz_sys_menu` VALUES (1093809448598376556, 1093809448598376554, '显示', 3, NULL, 1, NULL, CURDATE(), 1); @@ -822,10 +818,6 @@ INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376533, 109380944859837 INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376534, 1093809448598376540); INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376535, 1093809448598376541); INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376536, 1093809448598376542); -INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376544, 1093809448598376549); -INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376545, 1093809448598376550); -INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376546, 1093809448598376551); -INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376547, 1093809448598376552); INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376556, 1093809448598376564); INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376560, 1093809448598376565); INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376557, 1093809448598376566); diff --git a/orange-demo-single-service/.DS_Store b/orange-demo-single-service/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/orange-demo-single-service/.DS_Store differ diff --git a/orange-demo-single-service/.gitignore b/orange-demo-single-service/.gitignore new file mode 100644 index 00000000..ac242580 --- /dev/null +++ b/orange-demo-single-service/.gitignore @@ -0,0 +1,26 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar +/.mvn/* + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/orange-demo-single-service/README.md b/orange-demo-single-service/README.md new file mode 100644 index 00000000..dcbb79ce --- /dev/null +++ b/orange-demo-single-service/README.md @@ -0,0 +1,3 @@ +### 服务启动环境依赖 +--- + diff --git a/orange-demo-single-service/application-common/pom.xml b/orange-demo-single-service/application-common/pom.xml new file mode 100644 index 00000000..0af5d4c2 --- /dev/null +++ b/orange-demo-single-service/application-common/pom.xml @@ -0,0 +1,24 @@ + + + + com.orange.demo + OrangeSingleDemo + 1.0.0 + + 4.0.0 + + application-common + 1.0.0 + application-common + jar + + + + com.orange.demo + common-core + 1.0.0 + + + \ No newline at end of file diff --git a/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java new file mode 100644 index 00000000..afdada25 --- /dev/null +++ b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/DeviceType.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 设备类型常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class DeviceType { + + /** + * iOS。 + */ + public static final int IOS = 0; + /** + * Android。 + */ + public static final int ANDROID = 1; + /** + * PC。 + */ + public static final int PC = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(IOS, "iOS"); + DICT_MAP.put(ANDROID, "Android"); + DICT_MAP.put(PC, "PC"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DeviceType() { + } +} diff --git a/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java new file mode 100644 index 00000000..a9bb8d8e --- /dev/null +++ b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/ExpLevel.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 经验等级常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class ExpLevel { + + /** + * 初级学员。 + */ + public static final int LOWER = 0; + /** + * 中级学员。 + */ + public static final int MIDDLE = 1; + /** + * 高级学员。 + */ + public static final int HIGH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(LOWER, "初级学员"); + DICT_MAP.put(MIDDLE, "中级学员"); + DICT_MAP.put(HIGH, "高级学员"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ExpLevel() { + } +} diff --git a/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java new file mode 100644 index 00000000..30a33f9f --- /dev/null +++ b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/Gender.java @@ -0,0 +1,44 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 性别常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class Gender { + + /** + * 男。 + */ + public static final int MALE = 1; + /** + * 女。 + */ + public static final int FEMALE = 0; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(MALE, "男"); + DICT_MAP.put(FEMALE, "女"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private Gender() { + } +} diff --git a/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java new file mode 100644 index 00000000..3cf8ea83 --- /dev/null +++ b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/StudentActionType.java @@ -0,0 +1,89 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 学生行为常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class StudentActionType { + + /** + * 充值。 + */ + public static final int RECHARGE = 0; + /** + * 购课。 + */ + public static final int BUY_COURSE = 1; + /** + * 上课签到。 + */ + public static final int SIGNIN_COURSE = 2; + /** + * 上课签退。 + */ + public static final int SIGNOUT_COURSE = 3; + /** + * 看视频课。 + */ + public static final int WATCH_VIDEO = 4; + /** + * 做作业。 + */ + public static final int DO_PAPER = 5; + /** + * 刷题。 + */ + public static final int REFRESH_EXERCISE = 6; + /** + * 献花。 + */ + public static final int PRESENT_FLOWER = 7; + /** + * 购买视频。 + */ + public static final int BUY_VIDEO_COURSE = 8; + /** + * 购买鲜花。 + */ + public static final int BUY_FLOWER = 9; + /** + * 购买作业。 + */ + public static final int BUY_PAPER = 10; + + private static final Map DICT_MAP = new HashMap<>(11); + static { + DICT_MAP.put(RECHARGE, "充值"); + DICT_MAP.put(BUY_COURSE, "购课"); + DICT_MAP.put(SIGNIN_COURSE, "上课签到"); + DICT_MAP.put(SIGNOUT_COURSE, "上课签退"); + DICT_MAP.put(WATCH_VIDEO, "看视频课"); + DICT_MAP.put(DO_PAPER, "做作业"); + DICT_MAP.put(REFRESH_EXERCISE, "刷题"); + DICT_MAP.put(PRESENT_FLOWER, "献花"); + DICT_MAP.put(BUY_VIDEO_COURSE, "购买视频"); + DICT_MAP.put(BUY_FLOWER, "购买鲜花"); + DICT_MAP.put(BUY_PAPER, "购买作业"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private StudentActionType() { + } +} diff --git a/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java new file mode 100644 index 00000000..fb05587b --- /dev/null +++ b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/StudentStatus.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 学生状态常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class StudentStatus { + + /** + * 正常。 + */ + public static final int NORMAL = 0; + /** + * 锁定。 + */ + public static final int LOCKED = 1; + /** + * 注销。 + */ + public static final int DELETED = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(NORMAL, "正常"); + DICT_MAP.put(LOCKED, "锁定"); + DICT_MAP.put(DELETED, "注销"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private StudentStatus() { + } +} diff --git a/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java new file mode 100644 index 00000000..1408cb93 --- /dev/null +++ b/orange-demo-single-service/application-common/src/main/java/com/orange/demo/application/common/constant/Subject.java @@ -0,0 +1,49 @@ +package com.orange.demo.application.common.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 学科常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class Subject { + + /** + * 语文。 + */ + public static final int CHINESE = 0; + /** + * 数学。 + */ + public static final int MATCH = 1; + /** + * 英语。 + */ + public static final int ENGLISH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(CHINESE, "语文"); + DICT_MAP.put(MATCH, "数学"); + DICT_MAP.put(ENGLISH, "英语"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private Subject() { + } +} diff --git a/orange-demo-single-service/application/pom.xml b/orange-demo-single-service/application/pom.xml new file mode 100644 index 00000000..3c561be6 --- /dev/null +++ b/orange-demo-single-service/application/pom.xml @@ -0,0 +1,67 @@ + + + + com.orange.demo + OrangeSingleDemo + 1.0.0 + + 4.0.0 + + application + 1.0.0 + application + jar + + + + + com.orange.demo + common-core + 1.0.0 + + + com.orange.demo + application-common + 1.0.0 + + + com.orange.demo + common-sequence + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/MyApplication.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/MyApplication.java new file mode 100644 index 00000000..a3f6a435 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/MyApplication.java @@ -0,0 +1,18 @@ +package com.orange.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 应用服务启动类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@SpringBootApplication +public class MyApplication { + + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java new file mode 100644 index 00000000..c492fb5a --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/AreaCodeController.java @@ -0,0 +1,56 @@ +package com.orange.demo.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.orange.demo.app.model.AreaCode; +import com.orange.demo.app.service.AreaCodeService; +import com.orange.demo.common.core.object.ResponseResult; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 行政区划数据访问接口类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@RestController +@RequestMapping("/admin/app/areaCode") +public class AreaCodeController { + + @Autowired + private AreaCodeService areaCodeService; + + /** + * 按照字典的形式返回行政区划列表。 + * + * @return 字典形式的行政区划列表。 + */ + @GetMapping("/listDictAreaCode") + public ResponseResult>> listDictAreaCode() { + List resultList = areaCodeService.getAllList(); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } + + /** + * 根据上级行政区划Id获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 按照字典的形式返回下级行政区划列表。 + */ + @GetMapping("/listDictAreaCodeByParentId") + public ResponseResult>> listDictAreaCodeByParentId(@RequestParam(required = false) Long parentId) { + Collection resultList = areaCodeService.getListByParentId(parentId); + if (CollectionUtils.isEmpty(resultList)) { + return ResponseResult.success(new LinkedList<>()); + } + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/CourseController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/CourseController.java new file mode 100644 index 00000000..38e0b385 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/CourseController.java @@ -0,0 +1,253 @@ +package com.orange.demo.app.controller; + +import cn.hutool.core.util.ReflectUtil; +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.cache.SessionCacheHelper; +import com.orange.demo.config.ApplicationConfig; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import javax.validation.groups.Default; + +/** + * 课程数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/course") +public class CourseController { + + @Autowired + private CourseService courseService; + @Autowired + private ApplicationConfig appConfig; + @Autowired + private SessionCacheHelper cacheHelper; + + /** + * 新增课程数据数据。 + * + * @param course 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Course course) { + String errorMessage = MyCommonUtil.getModelValidationError(course); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = courseService.verifyRelatedData(course, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + course = courseService.saveNew(course); + JSONObject responseData = new JSONObject(); + responseData.put("courseId", course.getCourseId()); + return ResponseResult.success(responseData); + } + + /** + * 更新课程数据数据。 + * + * @param course 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Course course) { + String errorMessage = MyCommonUtil.getModelValidationError(course, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + Course originalCourse = courseService.getById(course.getCourseId()); + if (originalCourse == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = courseService.verifyRelatedData(course, originalCourse); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!courseService.update(course, originalCourse)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除课程数据数据。 + * + * @param courseId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long courseId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + Course originalCourse = courseService.getById(courseId); + if (originalCourse == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!courseService.remove(courseId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的课程数据列表。 + * + * @param courseFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody Course courseFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class); + List resultList = courseService.getCourseListWithRelation(courseFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定课程数据对象详情。 + * + * @param courseId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long courseId) { + if (MyCommonUtil.existBlankArgument(courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Course course = courseService.getByIdWithRelation(courseId, MyRelationParam.full()); + if (course == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(course); + } + + /** + * 附件文件下载。 + * 这里将图片和其他类型的附件文件放到不同的父目录下,主要为了便于今后图片文件的迁移。 + * + * @param courseId 附件所在记录的主键Id。 + * @param fieldName 附件所属的字段名。 + * @param filename 文件名。如果没有提供该参数,就从当前记录的指定字段中读取。 + * @param asImage 下载文件是否为图片。 + * @param response Http 应答对象。 + */ + @GetMapping("/download") + public void download( + @RequestParam(required = false) Long courseId, + @RequestParam String fieldName, + @RequestParam String filename, + @RequestParam Boolean asImage, + HttpServletResponse response) { + if (MyCommonUtil.existBlankArgument(fieldName, filename, asImage)) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + // 使用try来捕获异常,是为了保证一旦出现异常可以返回500的错误状态,便于调试。 + // 否则有可能给前端返回的是200的错误码。 + try { + // 如果请求参数中没有包含主键Id,就判断该文件是否为当前session上传的。 + if (courseId == null) { + if (!cacheHelper.existSessionUploadFile(filename)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + return; + } + } else { + Course course = courseService.getById(courseId); + if (course == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + String fieldJsonData = (String) ReflectUtil.getFieldValue(course, fieldName); + if (fieldJsonData == null) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + if (!UpDownloadUtil.containFile(fieldJsonData, filename)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + UpDownloadUtil.doDownload(appConfig.getUploadFileBaseDir(), + Course.class.getSimpleName(), fieldName, filename, asImage, response); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + log.error(e.getMessage(), e); + } + } + + /** + * 文件上传操作。 + * + * @param fieldName 上传文件名。 + * @param asImage 是否作为图片上传。如果是图片,今后下载的时候无需权限验证。否则就是附件上传,下载时需要权限验证。 + * @param uploadFile 上传文件对象。 + * @param response Http 应答对象。 + * @throws IOException 文件读写错误。 + */ + @PostMapping("/upload") + public void upload( + @RequestParam String fieldName, + @RequestParam Boolean asImage, + @RequestParam("uploadFile") MultipartFile uploadFile, + HttpServletResponse response) throws IOException { + String filename = UpDownloadUtil.doUpload(appConfig.getUploadFileBaseDir(), + Course.class.getSimpleName(), fieldName, asImage, uploadFile, response); + if (filename != null) { + cacheHelper.putSessionUploadFile(filename); + } + } + + /** + * 以字典形式返回全部课程数据数据集合。字典的键值为[courseId, courseName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictCourse") + public ResponseResult>> listDictCourse(Course filter) { + List resultList = courseService.getListByFilter(filter, null); + return ResponseResult.success(BeanQuery.select( + "courseId as id", "courseName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java new file mode 100644 index 00000000..4e6d7ce3 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/CourseTransStatsController.java @@ -0,0 +1,99 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 课程统计操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/courseTransStats") +public class CourseTransStatsController { + + @Autowired + private CourseTransStatsService courseTransStatsService; + + /** + * 列出符合过滤条件的课程统计列表。 + * + * @param courseTransStatsFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody CourseTransStats courseTransStatsFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, CourseTransStats.class); + List resultList = courseTransStatsService.getCourseTransStatsListWithRelation(courseTransStatsFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 分组列出符合过滤条件的课程统计列表。 + * + * @param courseTransStatsFilter 过滤对象。 + * @param groupParam 分组参数。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/listWithGroup") + public ResponseResult listWithGroup( + @MyRequestBody CourseTransStats courseTransStatsFilter, + @MyRequestBody MyGroupParam groupParam, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String orderBy = MyOrderParam.buildOrderBy(orderParam, CourseTransStats.class); + groupParam = MyGroupParam.buildGroupBy(groupParam, CourseTransStats.class); + if (groupParam == null) { + return ResponseResult.error( + ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!"); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + MyGroupCriteria criteria = groupParam.getGroupCriteria(); + List resultList = courseTransStatsService.getGroupedCourseTransStatsListWithRelation( + courseTransStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定课程统计对象详情。 + * + * @param statsId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long statsId) { + if (MyCommonUtil.existBlankArgument(statsId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + CourseTransStats courseTransStats = courseTransStatsService.getByIdWithRelation(statsId, MyRelationParam.full()); + if (courseTransStats == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(courseTransStats); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/GradeController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/GradeController.java new file mode 100644 index 00000000..ab66a6fb --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/GradeController.java @@ -0,0 +1,114 @@ +package com.orange.demo.app.controller; + +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import cn.jimmyshi.beanquery.BeanQuery; + +import javax.validation.groups.Default; +import java.util.*; + +/** + * 年级操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/grade") +public class GradeController { + + @Autowired + private GradeService gradeService; + + /** + * 新增年级数据。 + * + * @param grade 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Grade grade) { + String errorMessage = MyCommonUtil.getModelValidationError(grade); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + grade = gradeService.saveNew(grade); + JSONObject responseData = new JSONObject(); + responseData.put("gradeId", grade.getGradeId()); + return ResponseResult.success(responseData); + } + + /** + * 更新年级数据。 + * + * @param grade 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Grade grade) { + String errorMessage = MyCommonUtil.getModelValidationError(grade, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + Grade originalGrade = gradeService.getById(grade.getGradeId()); + if (originalGrade == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + if (!gradeService.update(grade, originalGrade)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除年级数据。 + * + * @param gradeId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Integer gradeId) { + if (MyCommonUtil.existBlankArgument(gradeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!gradeService.remove(gradeId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 以字典形式返回全部年级数据集合。 + * 白名单接口,登录用户均可访问。 + * + * @return 应答结果对象,包含字典形式的数据集合。 + */ + @GetMapping("/listDictGrade") + public ResponseResult>> listDictGrade() { + List resultList = gradeService.getAllList(); + return ResponseResult.success(BeanQuery.select( + "gradeId as id", "gradeName as name").executeFrom(resultList)); + } + + /** + * 将当前字典表的数据重新加载到缓存中。 + * 由于缓存的数据更新,在add/update/delete等接口均有同步处理。因此该接口仅当同步过程中出现问题时, + * 可手工调用,或者每天晚上定时同步一次。 + */ + @GetMapping("/reloadCachedData") + public ResponseResult reloadCachedData() { + gradeService.reloadCachedData(true); + return ResponseResult.success(true); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java new file mode 100644 index 00000000..ac59f081 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/SchoolInfoController.java @@ -0,0 +1,167 @@ +package com.orange.demo.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 校区数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/schoolInfo") +public class SchoolInfoController { + + @Autowired + private SchoolInfoService schoolInfoService; + + /** + * 新增校区数据数据。 + * + * @param schoolInfo 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SchoolInfo schoolInfo) { + String errorMessage = MyCommonUtil.getModelValidationError(schoolInfo); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = schoolInfoService.verifyRelatedData(schoolInfo, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + schoolInfo = schoolInfoService.saveNew(schoolInfo); + JSONObject responseData = new JSONObject(); + responseData.put("schoolId", schoolInfo.getSchoolId()); + return ResponseResult.success(responseData); + } + + /** + * 更新校区数据数据。 + * + * @param schoolInfo 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SchoolInfo schoolInfo) { + String errorMessage = MyCommonUtil.getModelValidationError(schoolInfo, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + SchoolInfo originalSchoolInfo = schoolInfoService.getById(schoolInfo.getSchoolId()); + if (originalSchoolInfo == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = schoolInfoService.verifyRelatedData(schoolInfo, originalSchoolInfo); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!schoolInfoService.update(schoolInfo, originalSchoolInfo)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除校区数据数据。 + * + * @param schoolId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long schoolId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(schoolId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SchoolInfo originalSchoolInfo = schoolInfoService.getById(schoolId); + if (originalSchoolInfo == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!schoolInfoService.remove(schoolId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的校区数据列表。 + * + * @param schoolInfoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SchoolInfo schoolInfoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SchoolInfo.class); + List resultList = schoolInfoService.getSchoolInfoListWithRelation(schoolInfoFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定校区数据对象详情。 + * + * @param schoolId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long schoolId) { + if (MyCommonUtil.existBlankArgument(schoolId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SchoolInfo schoolInfo = schoolInfoService.getByIdWithRelation(schoolId, MyRelationParam.full()); + if (schoolInfo == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(schoolInfo); + } + + /** + * 以字典形式返回全部校区数据数据集合。字典的键值为[schoolId, schoolName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictSchoolInfo") + public ResponseResult>> listDictSchoolInfo(SchoolInfo filter) { + List resultList = schoolInfoService.getListByFilter(filter, null); + return ResponseResult.success(BeanQuery.select( + "schoolId as id", "schoolName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java new file mode 100644 index 00000000..487a7aa2 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentActionStatsController.java @@ -0,0 +1,99 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 学生行为统计操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/studentActionStats") +public class StudentActionStatsController { + + @Autowired + private StudentActionStatsService studentActionStatsService; + + /** + * 列出符合过滤条件的学生行为统计列表。 + * + * @param studentActionStatsFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody StudentActionStats studentActionStatsFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionStats.class); + List resultList = studentActionStatsService.getStudentActionStatsListWithRelation(studentActionStatsFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 分组列出符合过滤条件的学生行为统计列表。 + * + * @param studentActionStatsFilter 过滤对象。 + * @param groupParam 分组参数。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/listWithGroup") + public ResponseResult listWithGroup( + @MyRequestBody StudentActionStats studentActionStatsFilter, + @MyRequestBody MyGroupParam groupParam, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionStats.class); + groupParam = MyGroupParam.buildGroupBy(groupParam, StudentActionStats.class); + if (groupParam == null) { + return ResponseResult.error( + ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!"); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + MyGroupCriteria criteria = groupParam.getGroupCriteria(); + List resultList = studentActionStatsService.getGroupedStudentActionStatsListWithRelation( + studentActionStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定学生行为统计对象详情。 + * + * @param statsId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long statsId) { + if (MyCommonUtil.existBlankArgument(statsId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + StudentActionStats studentActionStats = studentActionStatsService.getByIdWithRelation(statsId, MyRelationParam.full()); + if (studentActionStats == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(studentActionStats); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java new file mode 100644 index 00000000..957156f8 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentActionTransController.java @@ -0,0 +1,152 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 学生行为流水操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/studentActionTrans") +public class StudentActionTransController { + + @Autowired + private StudentActionTransService studentActionTransService; + + /** + * 新增学生行为流水数据。 + * + * @param studentActionTrans 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody StudentActionTrans studentActionTrans) { + String errorMessage = MyCommonUtil.getModelValidationError(studentActionTrans); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentActionTransService.verifyRelatedData(studentActionTrans, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + studentActionTrans = studentActionTransService.saveNew(studentActionTrans); + JSONObject responseData = new JSONObject(); + responseData.put("transId", studentActionTrans.getTransId()); + return ResponseResult.success(responseData); + } + + /** + * 更新学生行为流水数据。 + * + * @param studentActionTrans 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody StudentActionTrans studentActionTrans) { + String errorMessage = MyCommonUtil.getModelValidationError(studentActionTrans, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + StudentActionTrans originalStudentActionTrans = studentActionTransService.getById(studentActionTrans.getTransId()); + if (originalStudentActionTrans == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentActionTransService.verifyRelatedData(studentActionTrans, originalStudentActionTrans); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentActionTransService.update(studentActionTrans, originalStudentActionTrans)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除学生行为流水数据。 + * + * @param transId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long transId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(transId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + StudentActionTrans originalStudentActionTrans = studentActionTransService.getById(transId); + if (originalStudentActionTrans == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!studentActionTransService.remove(transId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的学生行为流水列表。 + * + * @param studentActionTransFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody StudentActionTrans studentActionTransFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionTrans.class); + List resultList = studentActionTransService.getStudentActionTransListWithRelation(studentActionTransFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定学生行为流水对象详情。 + * + * @param transId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long transId) { + if (MyCommonUtil.existBlankArgument(transId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + StudentActionTrans studentActionTrans = studentActionTransService.getByIdWithRelation(transId, MyRelationParam.full()); + if (studentActionTrans == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(studentActionTrans); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java new file mode 100644 index 00000000..c8440825 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentClassController.java @@ -0,0 +1,429 @@ +package com.orange.demo.app.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; +import java.util.stream.Collectors; + +/** + * 班级数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/studentClass") +public class StudentClassController { + + @Autowired + private StudentClassService studentClassService; + @Autowired + private CourseService courseService; + @Autowired + private StudentService studentService; + + /** + * 新增班级数据数据。 + * + * @param studentClass 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody StudentClass studentClass) { + String errorMessage = MyCommonUtil.getModelValidationError(studentClass); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentClassService.verifyRelatedData(studentClass, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + studentClass = studentClassService.saveNew(studentClass); + JSONObject responseData = new JSONObject(); + responseData.put("classId", studentClass.getClassId()); + return ResponseResult.success(responseData); + } + + /** + * 更新班级数据数据。 + * + * @param studentClass 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody StudentClass studentClass) { + String errorMessage = MyCommonUtil.getModelValidationError(studentClass, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + StudentClass originalStudentClass = studentClassService.getById(studentClass.getClassId()); + if (originalStudentClass == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentClassService.verifyRelatedData(studentClass, originalStudentClass); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentClassService.update(studentClass, originalStudentClass)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除班级数据数据。 + * + * @param classId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long classId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + StudentClass originalStudentClass = studentClassService.getById(classId); + if (originalStudentClass == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!studentClassService.remove(classId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的班级数据列表。 + * + * @param studentClassFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody StudentClass studentClassFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentClass.class); + List resultList = studentClassService.getStudentClassListWithRelation(studentClassFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定班级数据对象详情。 + * + * @param classId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long classId) { + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + StudentClass studentClass = studentClassService.getByIdWithRelation(classId, MyRelationParam.full()); + if (studentClass == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(studentClass); + } + + /** + * 列出不与指定班级数据存在多对多关系的 [课程数据] 列表数据。通常用于查看添加新 [课程数据] 对象的候选列表。 + * + * @param classId 主表关联字段。 + * @param courseFilter [课程数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInClassCourse") + public ResponseResult listNotInClassCourse( + @MyRequestBody Long classId, + @MyRequestBody Course courseFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassCourseVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class); + List resultList = + courseService.getNotInCourseListByClassId(classId, courseFilter, orderBy); + JSONObject responseData = MyPageUtil.makeResponseData(resultList); + return ResponseResult.success(responseData); + } + + /** + * 列出与指定班级数据存在多对多关系的 [课程数据] 列表数据。 + * + * @param classId 主表关联字段。 + * @param courseFilter [课程数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listClassCourse") + public ResponseResult listClassCourse( + @MyRequestBody Long classId, + @MyRequestBody Course courseFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassCourseVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class); + List resultList = + courseService.getCourseListByClassId(classId, courseFilter, orderBy); + JSONObject responseData = MyPageUtil.makeResponseData(resultList); + return ResponseResult.success(responseData); + } + + private ResponseResult doClassCourseVerify(Long classId) { + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.existId(classId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 批量添加班级数据和 [课程数据] 对象的多对多关联关系数据。 + * + * @param classId 主表主键Id。 + * @param classCourseList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addClassCourse") + public ResponseResult addClassCourse( + @MyRequestBody Long classId, + @MyRequestBody(elementType = ClassCourse.class) List classCourseList) { + if (MyCommonUtil.existBlankArgument(classId, classCourseList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (ClassCourse classCourse : classCourseList) { + String errorMessage = MyCommonUtil.getModelValidationError(classCourse); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + } + Set courseIdSet = + classCourseList.stream().map(ClassCourse::getCourseId).collect(Collectors.toSet()); + if (!studentClassService.existId(classId) + || !courseService.existUniqueKeyList("courseId", courseIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + studentClassService.addClassCourseList(classCourseList, classId); + return ResponseResult.success(); + } + + /** + * 更新指定班级数据和指定 [课程数据] 的多对多关联数据。 + * + * @param classCourse 对多对中间表对象。 + * @return 应答结果对象。 + */ + @PostMapping("/updateClassCourse") + public ResponseResult updateClassCourse(@MyRequestBody ClassCourse classCourse) { + String errorMessage = MyCommonUtil.getModelValidationError(classCourse); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentClassService.updateClassCourse(classCourse)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 显示班级数据和指定 [课程数据] 的多对多关联详情数据。 + * + * @param classId 主表主键Id。 + * @param courseId 从表主键Id。 + * @return 应答结果对象,包括中间表详情。 + */ + @GetMapping("/viewClassCourse") + public ResponseResult viewClassCourse( + @RequestParam Long classId, @RequestParam Long courseId) { + if (MyCommonUtil.existBlankArgument(classId, courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + ClassCourse classCourse = studentClassService.getClassCourse(classId, courseId); + if (classCourse == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(classCourse); + } + + /** + * 移除指定班级数据和指定 [课程数据] 的多对多关联关系。 + * + * @param classId 主表主键Id。 + * @param courseId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteClassCourse") + public ResponseResult deleteClassCourse( + @MyRequestBody Long classId, @MyRequestBody Long courseId) { + if (MyCommonUtil.existBlankArgument(classId, courseId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.removeClassCourse(classId, courseId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 列出不与指定班级数据存在多对多关系的 [学生数据] 列表数据。通常用于查看添加新 [学生数据] 对象的候选列表。 + * + * @param classId 主表关联字段。 + * @param studentFilter [学生数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInClassStudent") + public ResponseResult listNotInClassStudent( + @MyRequestBody Long classId, + @MyRequestBody Student studentFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassStudentVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class); + List resultList = + studentService.getNotInStudentListByClassId(classId, studentFilter, orderBy); + JSONObject responseData = MyPageUtil.makeResponseData(resultList); + return ResponseResult.success(responseData); + } + + /** + * 列出与指定班级数据存在多对多关系的 [学生数据] 列表数据。 + * + * @param classId 主表关联字段。 + * @param studentFilter [学生数据] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listClassStudent") + public ResponseResult listClassStudent( + @MyRequestBody Long classId, + @MyRequestBody Student studentFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doClassStudentVerify(classId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class); + List resultList = + studentService.getStudentListByClassId(classId, studentFilter, orderBy); + JSONObject responseData = MyPageUtil.makeResponseData(resultList); + return ResponseResult.success(responseData); + } + + private ResponseResult doClassStudentVerify(Long classId) { + if (MyCommonUtil.existBlankArgument(classId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.existId(classId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 批量添加班级数据和 [学生数据] 对象的多对多关联关系数据。 + * + * @param classId 主表主键Id。 + * @param classStudentList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addClassStudent") + public ResponseResult addClassStudent( + @MyRequestBody Long classId, + @MyRequestBody(elementType = ClassStudent.class) List classStudentList) { + if (MyCommonUtil.existBlankArgument(classId, classStudentList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (ClassStudent classStudent : classStudentList) { + String errorMessage = MyCommonUtil.getModelValidationError(classStudent); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + } + Set studentIdSet = + classStudentList.stream().map(ClassStudent::getStudentId).collect(Collectors.toSet()); + if (!studentClassService.existId(classId) + || !studentService.existUniqueKeyList("studentId", studentIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + studentClassService.addClassStudentList(classStudentList, classId); + return ResponseResult.success(); + } + + /** + * 移除指定班级数据和指定 [学生数据] 的多对多关联关系。 + * + * @param classId 主表主键Id。 + * @param studentId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteClassStudent") + public ResponseResult deleteClassStudent( + @MyRequestBody Long classId, @MyRequestBody Long studentId) { + if (MyCommonUtil.existBlankArgument(classId, studentId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!studentClassService.removeClassStudent(classId, studentId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentController.java new file mode 100644 index 00000000..37133747 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/controller/StudentController.java @@ -0,0 +1,167 @@ +package com.orange.demo.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.app.model.*; +import com.orange.demo.app.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 学生数据操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/student") +public class StudentController { + + @Autowired + private StudentService studentService; + + /** + * 新增学生数据数据。 + * + * @param student 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Student student) { + String errorMessage = MyCommonUtil.getModelValidationError(student); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentService.verifyRelatedData(student, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + student = studentService.saveNew(student); + JSONObject responseData = new JSONObject(); + responseData.put("studentId", student.getStudentId()); + return ResponseResult.success(responseData); + } + + /** + * 更新学生数据数据。 + * + * @param student 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Student student) { + String errorMessage = MyCommonUtil.getModelValidationError(student, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + Student originalStudent = studentService.getById(student.getStudentId()); + if (originalStudent == null) { + //NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = studentService.verifyRelatedData(student, originalStudent); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (!studentService.update(student, originalStudent)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除学生数据数据。 + * + * @param studentId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long studentId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(studentId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + Student originalStudent = studentService.getById(studentId); + if (originalStudent == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!studentService.remove(studentId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的学生数据列表。 + * + * @param studentFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody Student studentFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class); + List resultList = studentService.getStudentListWithRelation(studentFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定学生数据对象详情。 + * + * @param studentId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long studentId) { + if (MyCommonUtil.existBlankArgument(studentId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Student student = studentService.getByIdWithRelation(studentId, MyRelationParam.full()); + if (student == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(student); + } + + /** + * 以字典形式返回全部学生数据数据集合。字典的键值为[studentId, studentName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictStudent") + public ResponseResult>> listDictStudent(Student filter) { + List resultList = studentService.getListByFilter(filter, null); + return ResponseResult.success(BeanQuery.select( + "studentId as id", "studentName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java new file mode 100644 index 00000000..61ffbdbb --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/AreaCodeMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.AreaCode; + +/** + * 行政区划数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface AreaCodeMapper extends BaseDaoMapper { +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java new file mode 100644 index 00000000..b4917a20 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/ClassCourseMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.ClassCourse; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface ClassCourseMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java new file mode 100644 index 00000000..0ee06698 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/ClassStudentMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.ClassStudent; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface ClassStudentMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java new file mode 100644 index 00000000..9a88b9a9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/CourseMapper.java @@ -0,0 +1,52 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.Course; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 课程数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface CourseMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param courseFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getCourseList( + @Param("courseFilter") Course courseFilter, @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表数据列表。 + * + * @param classId 关联主表Id。 + * @param courseFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 从表数据列表。 + */ + List getCourseListByClassId( + @Param("classId") Long classId, + @Param("courseFilter") Course courseFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param classId 关联主表Id。 + * @param courseFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInCourseListByClassId( + @Param("classId") Long classId, + @Param("courseFilter") Course courseFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java new file mode 100644 index 00000000..f249b8a6 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/CourseTransStatsMapper.java @@ -0,0 +1,41 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.CourseTransStats; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 课程统计数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface CourseTransStatsMapper extends BaseDaoMapper { + + /** + * 获取分组计算后的数据对象列表。 + * + * @param courseTransStatsFilter 主表过滤对象。 + * @param groupSelect 分组显示字段列表字符串,SELECT从句的参数。 + * @param groupBy 分组字段列表字符串,GROUP BY从句的参数。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 对象列表。 + */ + List getGroupedCourseTransStatsList( + @Param("courseTransStatsFilter") CourseTransStats courseTransStatsFilter, + @Param("groupSelect") String groupSelect, + @Param("groupBy") String groupBy, + @Param("orderBy") String orderBy); + + /** + * 获取过滤后的对象列表。 + * + * @param courseTransStatsFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getCourseTransStatsList( + @Param("courseTransStatsFilter") CourseTransStats courseTransStatsFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java new file mode 100644 index 00000000..657dcdbf --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/GradeMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.Grade; + +/** + * 年级数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface GradeMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java new file mode 100644 index 00000000..7d4f6106 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/MaterialEditionMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.MaterialEdition; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface MaterialEditionMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java new file mode 100644 index 00000000..fa57e4c5 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/SchoolInfoMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.SchoolInfo; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 校区数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SchoolInfoMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param schoolInfoFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSchoolInfoList( + @Param("schoolInfoFilter") SchoolInfo schoolInfoFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java new file mode 100644 index 00000000..792286b8 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentActionStatsMapper.java @@ -0,0 +1,41 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.StudentActionStats; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 学生行为统计数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface StudentActionStatsMapper extends BaseDaoMapper { + + /** + * 获取分组计算后的数据对象列表。 + * + * @param studentActionStatsFilter 主表过滤对象。 + * @param groupSelect 分组显示字段列表字符串,SELECT从句的参数。 + * @param groupBy 分组字段列表字符串,GROUP BY从句的参数。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 对象列表。 + */ + List getGroupedStudentActionStatsList( + @Param("studentActionStatsFilter") StudentActionStats studentActionStatsFilter, + @Param("groupSelect") String groupSelect, + @Param("groupBy") String groupBy, + @Param("orderBy") String orderBy); + + /** + * 获取过滤后的对象列表。 + * + * @param studentActionStatsFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentActionStatsList( + @Param("studentActionStatsFilter") StudentActionStats studentActionStatsFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java new file mode 100644 index 00000000..a131f60f --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentActionTransMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.StudentActionTrans; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 学生行为流水数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface StudentActionTransMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param studentActionTransFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentActionTransList( + @Param("studentActionTransFilter") StudentActionTrans studentActionTransFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java new file mode 100644 index 00000000..29aaf450 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentClassMapper.java @@ -0,0 +1,26 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.StudentClass; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 班级数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface StudentClassMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param studentClassFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentClassList( + @Param("studentClassFilter") StudentClass studentClassFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java new file mode 100644 index 00000000..e8ba5dc9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/StudentMapper.java @@ -0,0 +1,52 @@ +package com.orange.demo.app.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.app.model.Student; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 学生数据数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface StudentMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param studentFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getStudentList( + @Param("studentFilter") Student studentFilter, @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表数据列表。 + * + * @param classId 关联主表Id。 + * @param studentFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 从表数据列表。 + */ + List getStudentListByClassId( + @Param("classId") Long classId, + @Param("studentFilter") Student studentFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param classId 关联主表Id。 + * @param studentFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInStudentListByClassId( + @Param("classId") Long classId, + @Param("studentFilter") Student studentFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml new file mode 100644 index 00000000..a65ab49a --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/AreaCodeMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml new file mode 100644 index 00000000..7fd02629 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/ClassCourseMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml new file mode 100644 index 00000000..7e0a0952 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/ClassStudentMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml new file mode 100644 index 00000000..41f2ae23 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/CourseMapper.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + AND zz_course.course_name LIKE #{safeCourseName} + + + AND zz_course.price >= #{courseFilter.priceStart} + + + AND zz_course.price <= #{courseFilter.priceEnd} + + + AND zz_course.difficulty = #{courseFilter.difficulty} + + + AND zz_course.grade_id = #{courseFilter.gradeId} + + + AND zz_course.subject_id = #{courseFilter.subjectId} + + + AND zz_course.class_hour >= #{courseFilter.classHourStart} + + + AND zz_course.class_hour <= #{courseFilter.classHourEnd} + + + AND zz_course.create_time >= #{courseFilter.createTimeStart} + + + AND zz_course.create_time <= #{courseFilter.createTimeEnd} + + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml new file mode 100644 index 00000000..cc20e41f --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/CourseTransStatsMapper.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + AND zz_course_trans_stats.stats_date >= #{courseTransStatsFilter.statsDateStart} + + + AND zz_course_trans_stats.stats_date <= #{courseTransStatsFilter.statsDateEnd} + + + AND zz_course_trans_stats.subject_id = #{courseTransStatsFilter.subjectId} + + + AND zz_course_trans_stats.grade_id = #{courseTransStatsFilter.gradeId} + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml new file mode 100644 index 00000000..0ed23888 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/GradeMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml new file mode 100644 index 00000000..75c26ef4 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/MaterialEditionMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml new file mode 100644 index 00000000..a7db22d2 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/SchoolInfoMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + AND zz_school_info.school_name LIKE #{safeSchoolName} + + + AND zz_school_info.province_id = #{schoolInfoFilter.provinceId} + + + AND zz_school_info.city_id = #{schoolInfoFilter.cityId} + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml new file mode 100644 index 00000000..fdd1e8e9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionStatsMapper.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_student_action_stats.stats_date >= #{studentActionStatsFilter.statsDateStart} + + + AND zz_student_action_stats.stats_date <= #{studentActionStatsFilter.statsDateEnd} + + + AND zz_student_action_stats.grade_id = #{studentActionStatsFilter.gradeId} + + + AND zz_student_action_stats.province_id = #{studentActionStatsFilter.provinceId} + + + AND zz_student_action_stats.city_id = #{studentActionStatsFilter.cityId} + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml new file mode 100644 index 00000000..4375e6d3 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentActionTransMapper.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_student_action_trans.student_id = #{studentActionTransFilter.studentId} + + + AND zz_student_action_trans.school_id = #{studentActionTransFilter.schoolId} + + + AND zz_student_action_trans.grade_id = #{studentActionTransFilter.gradeId} + + + AND zz_student_action_trans.action_type = #{studentActionTransFilter.actionType} + + + AND zz_student_action_trans.device_type = #{studentActionTransFilter.deviceType} + + + AND zz_student_action_trans.create_time >= #{studentActionTransFilter.createTimeStart} + + + AND zz_student_action_trans.create_time <= #{studentActionTransFilter.createTimeEnd} + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml new file mode 100644 index 00000000..a32e79b0 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentClassMapper.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + AND zz_class.class_name = #{studentClassFilter.className} + + + AND zz_class.school_id = #{studentClassFilter.schoolId} + + + AND zz_class.class_level = #{studentClassFilter.classLevel} + + + AND zz_class.status = ${@com.orange.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml new file mode 100644 index 00000000..81ee2f42 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/dao/mapper/StudentMapper.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_student.province_id = #{studentFilter.provinceId} + + + AND zz_student.city_id = #{studentFilter.cityId} + + + AND zz_student.district_id = #{studentFilter.districtId} + + + AND zz_student.birthday >= #{studentFilter.birthdayStart} + + + AND zz_student.birthday <= #{studentFilter.birthdayEnd} + + + AND zz_student.grade_id = #{studentFilter.gradeId} + + + AND zz_student.school_id = #{studentFilter.schoolId} + + + AND zz_student.register_time >= #{studentFilter.registerTimeStart} + + + AND zz_student.register_time <= #{studentFilter.registerTimeEnd} + + + AND zz_student.status = #{studentFilter.status} + + + + AND CONCAT(IFNULL(zz_student.login_mobile,''), IFNULL(zz_student.student_name,'')) LIKE #{safeSearchString} + + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/AreaCode.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/AreaCode.java new file mode 100644 index 00000000..5f9450ab --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/AreaCode.java @@ -0,0 +1,41 @@ +package com.orange.demo.app.model; + +import lombok.Data; + +import javax.persistence.*; + +/** + * 行政区划实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_area_code") +public class AreaCode { + + /** + * 行政区划主键Id + */ + @Id + @Column(name = "area_id") + private Long areaId; + + /** + * 行政区划名称 + */ + @Column(name = "area_name") + private String areaName; + + /** + * 行政区划级别 (1: 省级别 2: 市级别 3: 区级别) + */ + @Column(name = "area_level") + private Integer areaLevel; + + /** + * 父级行政区划Id + */ + @Column(name = "parent_id") + private Long parentId; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/ClassCourse.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/ClassCourse.java new file mode 100644 index 00000000..0b45e248 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/ClassCourse.java @@ -0,0 +1,40 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * ClassCourse实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_class_course") +public class ClassCourse { + + /** + * 班级Id。 + */ + @NotNull(message = "数据验证失败,班级Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "class_id") + private Long classId; + + /** + * 课程Id。 + */ + @NotNull(message = "数据验证失败,课程Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "course_id") + private Long courseId; + + /** + * 课程顺序(数值越小越靠前)。 + */ + @NotNull(message = "数据验证失败,课程顺序(数值越小越靠前)不能为空!", groups = {UpdateGroup.class}) + @Column(name = "course_order") + private Integer courseOrder; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/ClassStudent.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/ClassStudent.java new file mode 100644 index 00000000..f08ea947 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/ClassStudent.java @@ -0,0 +1,33 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * ClassStudent实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_class_student") +public class ClassStudent { + + /** + * 班级Id。 + */ + @NotNull(message = "数据验证失败,班级Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "class_id") + private Long classId; + + /** + * 学生Id。 + */ + @NotNull(message = "数据验证失败,学生Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "student_id") + private Long studentId; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Course.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Course.java new file mode 100644 index 00000000..d70160f1 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Course.java @@ -0,0 +1,163 @@ +package com.orange.demo.app.model; + +import com.orange.demo.app.model.constant.CourseDifficult; +import com.orange.demo.application.common.constant.Subject; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.Map; + +/** + * Course实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_course") +public class Course { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "course_id") + private Long courseId; + + /** + * 课程名称。 + */ + @NotBlank(message = "数据验证失败,课程名称不能为空!") + @Column(name = "course_name") + private String courseName; + + /** + * 课程价格。 + */ + @NotNull(message = "数据验证失败,课程价格不能为空!") + private BigDecimal price; + + /** + * 课程描述。 + */ + private String description; + + /** + * 课程难度(0: 容易 1: 普通 2: 很难)。 + */ + @NotNull(message = "数据验证失败,课程难度不能为空!") + @ConstDictRef(constDictClass = CourseDifficult.class, message = "数据验证失败,课程难度为无效值!") + private Integer difficulty; + + /** + * 年级Id。 + */ + @NotNull(message = "数据验证失败,所属年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 学科Id。 + */ + @NotNull(message = "数据验证失败,所属学科不能为空!") + @ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所属学科为无效值!") + @Column(name = "subject_id") + private Integer subjectId; + + /** + * 课时数量。 + */ + @NotNull(message = "数据验证失败,课时数量不能为空!") + @Column(name = "class_hour") + private Integer classHour; + + /** + * 多张课程图片地址。 + */ + @NotBlank(message = "数据验证失败,课程图片不能为空!") + @Column(name = "picture_url") + private String pictureUrl; + + /** + * 创建用户Id。 + */ + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 最后修改时间。 + */ + @Column(name = "update_time") + private Date updateTime; + + /** + * price 范围过滤起始值(>=)。 + */ + @Transient + private BigDecimal priceStart; + + /** + * price 范围过滤结束值(<=)。 + */ + @Transient + private BigDecimal priceEnd; + + /** + * classHour 范围过滤起始值(>=)。 + */ + @Transient + private Integer classHourStart; + + /** + * classHour 范围过滤结束值(<=)。 + */ + @Transient + private Integer classHourEnd; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @Transient + private String createTimeEnd; + + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @RelationConstDict( + masterIdField = "difficulty", + constantDictClass = CourseDifficult.class) + @Transient + private Map difficultyDictMap; + + @RelationConstDict( + masterIdField = "subjectId", + constantDictClass = Subject.class) + @Transient + private Map subjectIdDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java new file mode 100644 index 00000000..63839cd3 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/CourseTransStats.java @@ -0,0 +1,122 @@ +package com.orange.demo.app.model; + +import com.orange.demo.application.common.constant.Subject; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * CourseTransStats实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_course_trans_stats") +public class CourseTransStats { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "stats_id") + private Long statsId; + + /** + * 统计日期。 + */ + @NotNull(message = "数据验证失败,统计日期不能为空!") + @Column(name = "stats_date") + private Date statsDate; + + /** + * 科目Id。 + */ + @NotNull(message = "数据验证失败,所属科目不能为空!") + @ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所属科目为无效值!") + @Column(name = "subject_id") + private Integer subjectId; + + /** + * 年级Id。 + */ + @NotNull(message = "数据验证失败,所属年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 年级名称。 + */ + @Column(name = "grade_name") + private String gradeName; + + /** + * 课程Id。 + */ + @NotNull(message = "数据验证失败,课程Id不能为空!") + @Column(name = "course_id") + private Long courseId; + + /** + * 课程名称。 + */ + @Column(name = "course_name") + private String courseName; + + /** + * 学生上课次数。 + */ + @NotNull(message = "数据验证失败,上课次数不能为空!") + @Column(name = "student_attend_count") + private Integer studentAttendCount; + + /** + * 学生献花数量。 + */ + @NotNull(message = "数据验证失败,献花数量不能为空!") + @Column(name = "student_flower_amount") + private Integer studentFlowerAmount; + + /** + * 学生献花次数。 + */ + @NotNull(message = "数据验证失败,献花次数不能为空!") + @Column(name = "student_flower_count") + private Integer studentFlowerCount; + + /** + * statsDate 范围过滤起始值(>=)。 + */ + @Transient + private String statsDateStart; + + /** + * statsDate 范围过滤结束值(<=)。 + */ + @Transient + private String statsDateEnd; + + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @RelationConstDict( + masterIdField = "subjectId", + constantDictClass = Subject.class) + @Transient + private Map subjectIdDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Grade.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Grade.java new file mode 100644 index 00000000..af1849cb --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Grade.java @@ -0,0 +1,42 @@ +package com.orange.demo.app.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * Grade实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_grade") +public class Grade { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 年级名称。 + */ + @NotBlank(message = "数据验证失败,年级名称不能为空!") + @Column(name = "grade_name") + private String gradeName; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + private Integer status; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java new file mode 100644 index 00000000..681e9d54 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/MaterialEdition.java @@ -0,0 +1,39 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +/** + * MaterialEdition实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_material_edition") +public class MaterialEdition { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "edition_id") + private Integer editionId; + + /** + * 教材版本名称。 + */ + @NotBlank(message = "数据验证失败,教材版本名称不能为空!") + @Column(name = "edition_name") + private String editionName; + + /** + * 是否正在使用(0:不是,1:是)。 + */ + @NotNull(message = "数据验证失败,是否正在使用(0:不是,1:是)不能为空!") + private Integer status; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java new file mode 100644 index 00000000..dc7096e2 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/SchoolInfo.java @@ -0,0 +1,67 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Map; + +/** + * SchoolInfo实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_school_info") +public class SchoolInfo { + + /** + * 学校Id。 + */ + @NotNull(message = "数据验证失败,学校Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "school_id") + private Long schoolId; + + /** + * 学校名称。 + */ + @NotBlank(message = "数据验证失败,学校名称不能为空!") + @Column(name = "school_name") + private String schoolName; + + /** + * 所在省Id。 + */ + @NotNull(message = "数据验证失败,所在省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 所在城市Id。 + */ + @NotNull(message = "数据验证失败,所在城市不能为空!") + @Column(name = "city_id") + private Long cityId; + + @RelationDict( + masterIdField = "provinceId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map provinceIdDictMap; + + @RelationDict( + masterIdField = "cityId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map cityIdDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Student.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Student.java new file mode 100644 index 00000000..ea66a23e --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/Student.java @@ -0,0 +1,224 @@ +package com.orange.demo.app.model; + +import com.orange.demo.application.common.constant.Gender; +import com.orange.demo.application.common.constant.ExpLevel; +import com.orange.demo.application.common.constant.StudentStatus; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * Student实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_student") +public class Student { + + /** + * 学生Id。 + */ + @NotNull(message = "数据验证失败,学生Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "student_id") + private Long studentId; + + /** + * 登录手机。 + */ + @NotBlank(message = "数据验证失败,手机号码不能为空!") + @Column(name = "login_mobile") + private String loginMobile; + + /** + * 学生姓名。 + */ + @NotBlank(message = "数据验证失败,学生姓名不能为空!") + @Column(name = "student_name") + private String studentName; + + /** + * 所在省份Id。 + */ + @NotNull(message = "数据验证失败,所在省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 所在城市Id。 + */ + @NotNull(message = "数据验证失败,所在城市不能为空!") + @Column(name = "city_id") + private Long cityId; + + /** + * 区县Id。 + */ + @NotNull(message = "数据验证失败,所在区县不能为空!") + @Column(name = "district_id") + private Long districtId; + + /** + * 学生性别 (0: 女生 1: 男生)。 + */ + @NotNull(message = "数据验证失败,学生性别不能为空!") + @ConstDictRef(constDictClass = Gender.class, message = "数据验证失败,学生性别为无效值!") + private Integer gender; + + /** + * 生日。 + */ + @NotNull(message = "数据验证失败,出生日期不能为空!") + private Date birthday; + + /** + * 经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)。 + */ + @NotNull(message = "数据验证失败,经验等级不能为空!") + @ConstDictRef(constDictClass = ExpLevel.class, message = "数据验证失败,经验等级为无效值!") + @Column(name = "experience_level") + private Integer experienceLevel; + + /** + * 总共充值学币数量。 + */ + @NotNull(message = "数据验证失败,充值学币不能为空!", groups = {UpdateGroup.class}) + @Column(name = "total_coin") + private Integer totalCoin; + + /** + * 可用学币数量。 + */ + @NotNull(message = "数据验证失败,剩余学币不能为空!") + @Column(name = "left_coin") + private Integer leftCoin; + + /** + * 年级Id。 + */ + @NotNull(message = "数据验证失败,年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 校区Id。 + */ + @NotNull(message = "数据验证失败,所属校区不能为空!") + @Column(name = "school_id") + private Long schoolId; + + /** + * 注册时间。 + */ + @Column(name = "register_time") + private Date registerTime; + + /** + * 学生状态 (0: 正常 1: 锁定 2: 注销)。 + */ + @NotNull(message = "数据验证失败,学生状态不能为空!", groups = {UpdateGroup.class}) + @ConstDictRef(constDictClass = StudentStatus.class, message = "数据验证失败,学生状态为无效值!") + private Integer status; + + /** + * birthday 范围过滤起始值(>=)。 + */ + @Transient + private String birthdayStart; + + /** + * birthday 范围过滤结束值(<=)。 + */ + @Transient + private String birthdayEnd; + + /** + * registerTime 范围过滤起始值(>=)。 + */ + @Transient + private String registerTimeStart; + + /** + * registerTime 范围过滤结束值(<=)。 + */ + @Transient + private String registerTimeEnd; + + /** + * login_mobile / student_name LIKE搜索字符串。 + */ + @Transient + private String searchString; + + @RelationDict( + masterIdField = "provinceId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map provinceIdDictMap; + + @RelationDict( + masterIdField = "cityId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map cityIdDictMap; + + @RelationDict( + masterIdField = "districtId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map districtIdDictMap; + + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "schoolInfoService", + slaveModelClass = SchoolInfo.class, + slaveIdField = "schoolId", + slaveNameField = "schoolName") + @Transient + private Map schoolIdDictMap; + + @RelationConstDict( + masterIdField = "gender", + constantDictClass = Gender.class) + @Transient + private Map genderDictMap; + + @RelationConstDict( + masterIdField = "experienceLevel", + constantDictClass = ExpLevel.class) + @Transient + private Map experienceLevelDictMap; + + @RelationConstDict( + masterIdField = "status", + constantDictClass = StudentStatus.class) + @Transient + private Map statusDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java new file mode 100644 index 00000000..d027a297 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentActionStats.java @@ -0,0 +1,207 @@ +package com.orange.demo.app.model; + +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * StudentActionStats实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_student_action_stats") +public class StudentActionStats { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "stats_id") + private Long statsId; + + /** + * 统计日期。 + */ + @NotNull(message = "数据验证失败,统计日期不能为空!") + @Column(name = "stats_date") + private Date statsDate; + + /** + * 统计小时。 + */ + @Column(name = "stats_month") + private Date statsMonth; + + /** + * 年级Id。 + */ + @NotNull(message = "数据验证失败,所属年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 学生所在省Id。 + */ + @NotNull(message = "数据验证失败,所在省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 学生所在城市Id。 + */ + @NotNull(message = "数据验证失败,所在城市不能为空!", groups = {UpdateGroup.class}) + @Column(name = "city_id") + private Long cityId; + + /** + * 购课学币数量。 + */ + @NotNull(message = "数据验证失败,购课学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_course_amount") + private Integer buyCourseAmount; + + /** + * 购买课程次数。 + */ + @NotNull(message = "数据验证失败,购买课程次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_course_count") + private Integer buyCourseCount; + + /** + * 购买视频学币数量。 + */ + @NotNull(message = "数据验证失败,购买视频学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_video_amount") + private Integer buyVideoAmount; + + /** + * 购买视频次数。 + */ + @NotNull(message = "数据验证失败,购买视频次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_video_count") + private Integer buyVideoCount; + + /** + * 购买作业学币数量。 + */ + @NotNull(message = "数据验证失败,购买作业学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_paper_amount") + private Integer buyPaperAmount; + + /** + * 购买作业次数。 + */ + @NotNull(message = "数据验证失败,购买作业次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_paper_count") + private Integer buyPaperCount; + + /** + * 购买献花数量。 + */ + @NotNull(message = "数据验证失败,购买献花数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_flower_amount") + private Integer buyFlowerAmount; + + /** + * 购买献花次数。 + */ + @NotNull(message = "数据验证失败,购买献花次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "buy_flower_count") + private Integer buyFlowerCount; + + /** + * 充值学币数量。 + */ + @NotNull(message = "数据验证失败,充值学币数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "recharge_coin_amount") + private Integer rechargeCoinAmount; + + /** + * 充值学币次数。 + */ + @NotNull(message = "数据验证失败,充值学币次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "recharge_coin_count") + private Integer rechargeCoinCount; + + /** + * 线下课程上课次数。 + */ + @NotNull(message = "数据验证失败,线下课程上课次数不能为空!") + @Column(name = "do_course_count") + private Integer doCourseCount; + + /** + * 观看视频次数。 + */ + @NotNull(message = "数据验证失败,观看视频次数不能为空!", groups = {UpdateGroup.class}) + @Column(name = "watch_video_count") + private Integer watchVideoCount; + + /** + * 购买献花消费学币数量。 + */ + @NotNull(message = "数据验证失败,购买献花消费学币数量不能为空!") + @Column(name = "watch_video_total_second") + private Integer watchVideoTotalSecond; + + /** + * 做题数量。 + */ + @NotNull(message = "数据验证失败,做题数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "do_exercise_count") + private Integer doExerciseCount; + + /** + * 做题正确的数量。 + */ + @NotNull(message = "数据验证失败,做题正确的数量不能为空!", groups = {UpdateGroup.class}) + @Column(name = "do_exercise_correct_count") + private Integer doExerciseCorrectCount; + + /** + * statsDate 范围过滤起始值(>=)。 + */ + @Transient + private String statsDateStart; + + /** + * statsDate 范围过滤结束值(<=)。 + */ + @Transient + private String statsDateEnd; + + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @RelationDict( + masterIdField = "provinceId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map provinceIdDictMap; + + @RelationDict( + masterIdField = "cityId", + slaveServiceName = "areaCodeService", + slaveModelClass = AreaCode.class, + slaveIdField = "areaId", + slaveNameField = "areaName") + @Transient + private Map cityIdDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java new file mode 100644 index 00000000..b2e36071 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentActionTrans.java @@ -0,0 +1,168 @@ +package com.orange.demo.app.model; + +import com.orange.demo.application.common.constant.StudentActionType; +import com.orange.demo.application.common.constant.DeviceType; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * StudentActionTrans实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_student_action_trans") +public class StudentActionTrans { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "trans_id") + private Long transId; + + /** + * 学生Id。 + */ + @NotNull(message = "数据验证失败,学生Id不能为空!") + @Column(name = "student_id") + private Long studentId; + + /** + * 学生名称。 + */ + @NotBlank(message = "数据验证失败,学生名称不能为空!") + @Column(name = "student_name") + private String studentName; + + /** + * 学生校区。 + */ + @NotNull(message = "数据验证失败,学生校区不能为空!") + @Column(name = "school_id") + private Long schoolId; + + /** + * 年级Id。 + */ + @NotNull(message = "数据验证失败,学生年级不能为空!") + @Column(name = "grade_id") + private Integer gradeId; + + /** + * 行为类型(0: 充值 1: 购课 2: 上课签到 3: 上课签退 4: 看视频课 5: 做作业 6: 刷题 7: 献花)。 + */ + @NotNull(message = "数据验证失败,行为类型不能为空!") + @ConstDictRef(constDictClass = StudentActionType.class, message = "数据验证失败,行为类型为无效值!") + @Column(name = "action_type") + private Integer actionType; + + /** + * 设备类型(0: iOS 1: Android 2: PC)。 + */ + @NotNull(message = "数据验证失败,设备类型不能为空!") + @ConstDictRef(constDictClass = DeviceType.class, message = "数据验证失败,设备类型为无效值!") + @Column(name = "device_type") + private Integer deviceType; + + /** + * 看视频秒数。 + */ + @Column(name = "watch_video_seconds") + private Integer watchVideoSeconds; + + /** + * 购买献花数量。 + */ + @Column(name = "flower_count") + private Integer flowerCount; + + /** + * 购买作业数量。 + */ + @Column(name = "paper_count") + private Integer paperCount; + + /** + * 购买视频数量。 + */ + @Column(name = "video_count") + private Integer videoCount; + + /** + * 购买课程数量。 + */ + @Column(name = "course_count") + private Integer courseCount; + + /** + * 充值学币数量。 + */ + @Column(name = "coin_count") + private Integer coinCount; + + /** + * 做题是否正确标记。 + */ + @Column(name = "exercise_correct_flag") + private Integer exerciseCorrectFlag; + + /** + * 发生时间。 + */ + @NotNull(message = "数据验证失败,发生时间不能为空!") + @Column(name = "create_time") + private Date createTime; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @Transient + private String createTimeEnd; + + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "schoolInfoService", + slaveModelClass = SchoolInfo.class, + slaveIdField = "schoolId", + slaveNameField = "schoolName") + @Transient + private Map schoolIdDictMap; + + @RelationDict( + masterIdField = "gradeId", + slaveServiceName = "gradeService", + slaveModelClass = Grade.class, + slaveIdField = "gradeId", + slaveNameField = "gradeName") + @Transient + private Map gradeIdDictMap; + + @RelationConstDict( + masterIdField = "actionType", + constantDictClass = StudentActionType.class) + @Transient + private Map actionTypeDictMap; + + @RelationConstDict( + masterIdField = "deviceType", + constantDictClass = DeviceType.class) + @Transient + private Map deviceTypeDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentClass.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentClass.java new file mode 100644 index 00000000..7bcec6fc --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/StudentClass.java @@ -0,0 +1,113 @@ +package com.orange.demo.app.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.app.model.constant.ClassLevel; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +/** + * StudentClass实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_class") +public class StudentClass { + + /** + * 班级Id。 + */ + @NotNull(message = "数据验证失败,班级Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "class_id") + private Long classId; + + /** + * 班级名称。 + */ + @NotBlank(message = "数据验证失败,班级名称不能为空!") + @Column(name = "class_name") + private String className; + + /** + * 学校Id。 + */ + @NotNull(message = "数据验证失败,所属校区不能为空!") + @Column(name = "school_id") + private Long schoolId; + + /** + * 学生班长Id。 + */ + @NotNull(message = "数据验证失败,学生班长不能为空!") + @Column(name = "leader_id") + private Long leaderId; + + /** + * 已完成课时数量。 + */ + @NotNull(message = "数据验证失败,已完成课时不能为空!", groups = {UpdateGroup.class}) + @Column(name = "finish_class_hour") + private Integer finishClassHour; + + /** + * 班级级别(0: 初级班 1: 培优班 2: 冲刺提分班 3: 竞赛班)。 + */ + @NotNull(message = "数据验证失败,班级级别不能为空!") + @ConstDictRef(constDictClass = ClassLevel.class, message = "数据验证失败,班级级别为无效值!") + @Column(name = "class_level") + private Integer classLevel; + + /** + * 创建用户。 + */ + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 班级创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + private Integer status; + + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "schoolInfoService", + slaveModelClass = SchoolInfo.class, + slaveIdField = "schoolId", + slaveNameField = "schoolName") + @Transient + private Map schoolIdDictMap; + + @RelationDict( + masterIdField = "leaderId", + slaveServiceName = "studentService", + slaveModelClass = Student.class, + slaveIdField = "studentId", + slaveNameField = "studentName") + @Transient + private Map leaderIdDictMap; + + @RelationConstDict( + masterIdField = "classLevel", + constantDictClass = ClassLevel.class) + @Transient + private Map classLevelDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java new file mode 100644 index 00000000..aa2f694b --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/ClassLevel.java @@ -0,0 +1,49 @@ +package com.orange.demo.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 班级级别常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class ClassLevel { + + /** + * 初级班。 + */ + public static final int NORMAL = 0; + /** + * 中级班。 + */ + public static final int MIDDLE = 1; + /** + * 高级班。 + */ + public static final int HIGH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(NORMAL, "初级班"); + DICT_MAP.put(MIDDLE, "中级班"); + DICT_MAP.put(HIGH, "高级班"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ClassLevel() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java new file mode 100644 index 00000000..754c4d8c --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/ClassStatus.java @@ -0,0 +1,44 @@ +package com.orange.demo.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 班级状态常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class ClassStatus { + + /** + * 正常。 + */ + public static final int NORAML = 1; + /** + * 解散。 + */ + public static final int DELETED = -1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(NORAML, "正常"); + DICT_MAP.put(DELETED, "解散"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ClassStatus() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java new file mode 100644 index 00000000..8ffbeacf --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/model/constant/CourseDifficult.java @@ -0,0 +1,49 @@ +package com.orange.demo.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 课程难度常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class CourseDifficult { + + /** + * 容易。 + */ + public static final int NORMAL = 0; + /** + * 普通。 + */ + public static final int MIDDLE = 1; + /** + * 困难。 + */ + public static final int HIGH = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(NORMAL, "容易"); + DICT_MAP.put(MIDDLE, "普通"); + DICT_MAP.put(HIGH, "困难"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private CourseDifficult() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java new file mode 100644 index 00000000..45975e85 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/AreaCodeService.java @@ -0,0 +1,57 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.AreaCodeMapper; +import com.orange.demo.app.model.AreaCode; +import com.orange.demo.common.core.cache.MapTreeDictionaryCache; +import com.orange.demo.common.core.base.service.BaseDictService; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import java.util.Collection; +import java.util.List; + +/** + * 行政区划的Service类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class AreaCodeService extends BaseDictService { + + @Autowired + private AreaCodeMapper areaCodeMapper; + + public AreaCodeService() { + super(); + this.dictionaryCache = MapTreeDictionaryCache.create(AreaCode::getAreaId, AreaCode::getParentId); + } + + @Override + protected BaseDaoMapper mapper() { + return areaCodeMapper; + } + + /** + * 加载数据库数据到内存缓存。 + */ + @Override + public void loadCachedData() { + Example e = new Example(AreaCode.class); + e.orderBy("areaLevel"); + List areaCodeList = areaCodeMapper.selectByExample(e); + dictionaryCache.putAll(areaCodeList); + } + + /** + * 根据上级行政区划Id,获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 下级行政区划列表。 + */ + public Collection getListByParentId(Long parentId) { + return ((MapTreeDictionaryCache) dictionaryCache).getListByParentId(parentId); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/CourseService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/CourseService.java new file mode 100644 index 00000000..e438c5ed --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/CourseService.java @@ -0,0 +1,175 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 课程数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class CourseService extends BaseService { + + @Autowired + private CourseMapper courseMapper; + @Autowired + private ClassCourseMapper classCourseMapper; + @Autowired + private GradeService gradeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return courseMapper; + } + + /** + * 保存新增对象。 + * + * @param course 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public Course saveNew(Course course) { + course.setCourseId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + course.setCreateUserId(tokenData.getUserId()); + Date now = new Date(); + course.setCreateTime(now); + course.setUpdateTime(now); + courseMapper.insert(course); + return course; + } + + /** + * 更新数据对象。 + * + * @param course 更新的对象。 + * @param originalCourse 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(Course course, Course originalCourse) { + course.setCreateUserId(originalCourse.getCreateUserId()); + course.setCreateTime(originalCourse.getCreateTime()); + course.setUpdateTime(new Date()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return courseMapper.updateByPrimaryKey(course) == 1; + } + + /** + * 删除指定数据。 + * + * @param courseId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long courseId) { + // 这里先删除主数据 + if (courseMapper.deleteByPrimaryKey(courseId) == 0) { + return false; + } + // 这里可继续删除关联数据。 + // 开始删除多对多父表的关联 + ClassCourse classCourse = new ClassCourse(); + classCourse.setCourseId(courseId); + classCourseMapper.delete(classCourse); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getCourseListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseList(Course filter, String orderBy) { + return courseMapper.getCourseList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getCourseList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseListWithRelation(Course filter, String orderBy) { + List resultList = courseMapper.getCourseList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getNotInCourseListByClassId( + Long classId, Course filter, String orderBy) { + List resultList = + courseMapper.getNotInCourseListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseListByClassId( + Long classId, Course filter, String orderBy) { + List resultList = + courseMapper.getCourseListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param course 最新数据对象。 + * @param originalCourse 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(Course course, Course originalCourse) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(course, originalCourse, Course::getGradeId) + && !gradeService.existId(course.getGradeId())) { + return CallResult.error(String.format(errorMessageFormat, "所属年级")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java new file mode 100644 index 00000000..aa24fb43 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/CourseTransStatsService.java @@ -0,0 +1,83 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.base.service.BaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 课程统计数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class CourseTransStatsService extends BaseService { + + @Autowired + private CourseTransStatsMapper courseTransStatsMapper; + @Autowired + private GradeService gradeService; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return courseTransStatsMapper; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getCourseTransStatsListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseTransStatsList(CourseTransStats filter, String orderBy) { + return courseTransStatsMapper.getCourseTransStatsList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getCourseTransStatsList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getCourseTransStatsListWithRelation(CourseTransStats filter, String orderBy) { + List resultList = courseTransStatsMapper.getCourseTransStatsList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param filter 过滤对象。 + * @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。 + * @param groupBy 分组参数。位于SQL语句的GROUP BY后面。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 分组过滤结果集。 + */ + public List getGroupedCourseTransStatsListWithRelation( + CourseTransStats filter, String groupSelect, String groupBy, String orderBy) { + List resultList = + courseTransStatsMapper.getGroupedCourseTransStatsList(filter, groupSelect, groupBy, orderBy); + // NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。 + // 主要原因是,由于聚合字段通常被视为普通字段使用,不会在group by的从句中出现,语义上也不会在此关联。 + this.buildRelationForDataList(resultList, MyRelationParam.normal(), null); + return resultList; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/GradeService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/GradeService.java new file mode 100644 index 00000000..f5de3fd5 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/GradeService.java @@ -0,0 +1,88 @@ +package com.orange.demo.app.service; + +import com.orange.demo.common.core.base.service.BaseDictService; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.cache.MapDictionaryCache; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.app.dao.GradeMapper; +import com.orange.demo.app.model.Grade; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 年级数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class GradeService extends BaseDictService { + + @Autowired + private GradeMapper gradeMapper; + + public GradeService() { + super(); + this.dictionaryCache = MapDictionaryCache.create(Grade::getGradeId); + } + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return gradeMapper; + } + + /** + * 保存新增对象。 + * + * @param grade 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public Grade saveNew(Grade grade) { + grade.setStatus(GlobalDeletedFlag.NORMAL); + gradeMapper.insert(grade); + dictionaryCache.put(grade.getGradeId(), grade); + return grade; + } + + /** + * 更新数据对象。 + * + * @param grade 更新的对象。 + * @param originalGrade 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(Grade grade, Grade originalGrade) { + grade.setStatus(GlobalDeletedFlag.NORMAL); + if (gradeMapper.updateByPrimaryKey(grade) != 1) { + return false; + } + dictionaryCache.put(grade.getGradeId(), grade); + return true; + } + + /** + * 删除指定数据。 + * + * @param gradeId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Integer gradeId) { + Grade deletedObject = new Grade(); + deletedObject.setGradeId(gradeId); + deletedObject.setStatus(GlobalDeletedFlag.DELETED); + if (gradeMapper.updateByPrimaryKeySelective(deletedObject) != 1) { + return false; + } + dictionaryCache.invalidate(gradeId); + return true; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java new file mode 100644 index 00000000..d588b113 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/SchoolInfoService.java @@ -0,0 +1,129 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 校区数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SchoolInfoService extends BaseService { + + @Autowired + private SchoolInfoMapper schoolInfoMapper; + @Autowired + private AreaCodeService areaCodeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return schoolInfoMapper; + } + + /** + * 保存新增对象。 + * + * @param schoolInfo 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SchoolInfo saveNew(SchoolInfo schoolInfo) { + schoolInfo.setSchoolId(idGenerator.nextLongId()); + schoolInfoMapper.insert(schoolInfo); + return schoolInfo; + } + + /** + * 更新数据对象。 + * + * @param schoolInfo 更新的对象。 + * @param originalSchoolInfo 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SchoolInfo schoolInfo, SchoolInfo originalSchoolInfo) { + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return schoolInfoMapper.updateByPrimaryKey(schoolInfo) == 1; + } + + /** + * 删除指定数据。 + * + * @param schoolId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long schoolId) { + return schoolInfoMapper.deleteByPrimaryKey(schoolId) != 0; + // 这里可继续删除关联数据。 + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSchoolInfoListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSchoolInfoList(SchoolInfo filter, String orderBy) { + return schoolInfoMapper.getSchoolInfoList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getSchoolInfoList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSchoolInfoListWithRelation(SchoolInfo filter, String orderBy) { + List resultList = schoolInfoMapper.getSchoolInfoList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param schoolInfo 最新数据对象。 + * @param originalSchoolInfo 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(SchoolInfo schoolInfo, SchoolInfo originalSchoolInfo) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(schoolInfo, originalSchoolInfo, SchoolInfo::getProvinceId) + && !areaCodeService.existId(schoolInfo.getProvinceId())) { + return CallResult.error(String.format(errorMessageFormat, "所在省份")); + } + //这里是基于字典的验证。 + if (this.needToVerify(schoolInfo, originalSchoolInfo, SchoolInfo::getCityId) + && !areaCodeService.existId(schoolInfo.getCityId())) { + return CallResult.error(String.format(errorMessageFormat, "所在城市")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java new file mode 100644 index 00000000..36daf831 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentActionStatsService.java @@ -0,0 +1,85 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.base.service.BaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 学生行为统计数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class StudentActionStatsService extends BaseService { + + @Autowired + private StudentActionStatsMapper studentActionStatsMapper; + @Autowired + private GradeService gradeService; + @Autowired + private AreaCodeService areaCodeService; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentActionStatsMapper; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentActionStatsListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionStatsList(StudentActionStats filter, String orderBy) { + return studentActionStatsMapper.getStudentActionStatsList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentActionStatsList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionStatsListWithRelation(StudentActionStats filter, String orderBy) { + List resultList = studentActionStatsMapper.getStudentActionStatsList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param filter 过滤对象。 + * @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。 + * @param groupBy 分组参数。位于SQL语句的GROUP BY后面。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 分组过滤结果集。 + */ + public List getGroupedStudentActionStatsListWithRelation( + StudentActionStats filter, String groupSelect, String groupBy, String orderBy) { + List resultList = + studentActionStatsMapper.getGroupedStudentActionStatsList(filter, groupSelect, groupBy, orderBy); + // NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。 + // 主要原因是,由于聚合字段通常被视为普通字段使用,不会在group by的从句中出现,语义上也不会在此关联。 + this.buildRelationForDataList(resultList, MyRelationParam.normal(), null); + return resultList; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java new file mode 100644 index 00000000..4e1ea4eb --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentActionTransService.java @@ -0,0 +1,131 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 学生行为流水数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class StudentActionTransService extends BaseService { + + @Autowired + private StudentActionTransMapper studentActionTransMapper; + @Autowired + private SchoolInfoService schoolInfoService; + @Autowired + private GradeService gradeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentActionTransMapper; + } + + /** + * 保存新增对象。 + * + * @param studentActionTrans 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public StudentActionTrans saveNew(StudentActionTrans studentActionTrans) { + studentActionTrans.setTransId(idGenerator.nextLongId()); + studentActionTransMapper.insert(studentActionTrans); + return studentActionTrans; + } + + /** + * 更新数据对象。 + * + * @param studentActionTrans 更新的对象。 + * @param originalStudentActionTrans 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(StudentActionTrans studentActionTrans, StudentActionTrans originalStudentActionTrans) { + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return studentActionTransMapper.updateByPrimaryKey(studentActionTrans) == 1; + } + + /** + * 删除指定数据。 + * + * @param transId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long transId) { + return studentActionTransMapper.deleteByPrimaryKey(transId) != 0; + // 这里可继续删除关联数据。 + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentActionTransListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionTransList(StudentActionTrans filter, String orderBy) { + return studentActionTransMapper.getStudentActionTransList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentActionTransList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentActionTransListWithRelation(StudentActionTrans filter, String orderBy) { + List resultList = studentActionTransMapper.getStudentActionTransList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param studentActionTrans 最新数据对象。 + * @param originalStudentActionTrans 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(StudentActionTrans studentActionTrans, StudentActionTrans originalStudentActionTrans) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(studentActionTrans, originalStudentActionTrans, StudentActionTrans::getSchoolId) + && !schoolInfoService.existId(studentActionTrans.getSchoolId())) { + return CallResult.error(String.format(errorMessageFormat, "学生校区")); + } + //这里是基于字典的验证。 + if (this.needToVerify(studentActionTrans, originalStudentActionTrans, StudentActionTrans::getGradeId) + && !gradeService.existId(studentActionTrans.getGradeId())) { + return CallResult.error(String.format(errorMessageFormat, "学生年级")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentClassService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentClassService.java new file mode 100644 index 00000000..91ce2cd4 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentClassService.java @@ -0,0 +1,259 @@ +package com.orange.demo.app.service; + +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import java.util.*; + +/** + * 班级数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class StudentClassService extends BaseService { + + @Autowired + private StudentClassMapper studentClassMapper; + @Autowired + private ClassCourseMapper classCourseMapper; + @Autowired + private ClassStudentMapper classStudentMapper; + @Autowired + private SchoolInfoService schoolInfoService; + @Autowired + private StudentService studentService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentClassMapper; + } + + /** + * 保存新增对象。 + * + * @param studentClass 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public StudentClass saveNew(StudentClass studentClass) { + studentClass.setClassId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + studentClass.setCreateUserId(tokenData.getUserId()); + studentClass.setCreateTime(new Date()); + studentClass.setStatus(GlobalDeletedFlag.NORMAL); + if (studentClass.getFinishClassHour() == null) { + studentClass.setFinishClassHour(0); + } + if (studentClass.getStatus() == null) { + studentClass.setStatus(0); + } + studentClassMapper.insert(studentClass); + return studentClass; + } + + /** + * 更新数据对象。 + * + * @param studentClass 更新的对象。 + * @param originalStudentClass 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(StudentClass studentClass, StudentClass originalStudentClass) { + studentClass.setCreateUserId(originalStudentClass.getCreateUserId()); + studentClass.setCreateTime(originalStudentClass.getCreateTime()); + studentClass.setStatus(GlobalDeletedFlag.NORMAL); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return studentClassMapper.updateByPrimaryKey(studentClass) == 1; + } + + /** + * 删除指定数据。 + * + * @param classId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long classId) { + Example studentClassExample = new Example(StudentClass.class); + Example.Criteria c = studentClassExample.createCriteria(); + c.andEqualTo(super.idFieldName, classId); + c.andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + // 这里先删除主数据 + StudentClass deletedObject = new StudentClass(); + deletedObject.setStatus(GlobalDeletedFlag.DELETED); + if (studentClassMapper.updateByExampleSelective(deletedObject, studentClassExample) == 0) { + return false; + } + // 这里可继续删除关联数据。 + // 开始删除多对多子表的关联 + ClassCourse classCourse = new ClassCourse(); + classCourse.setClassId(classId); + classCourseMapper.delete(classCourse); + ClassStudent classStudent = new ClassStudent(); + classStudent.setClassId(classId); + classStudentMapper.delete(classStudent); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentClassListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentClassList(StudentClass filter, String orderBy) { + return studentClassMapper.getStudentClassList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentClassList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentClassListWithRelation(StudentClass filter, String orderBy) { + List resultList = studentClassMapper.getStudentClassList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 批量添加多对多关联关系。 + * + * @param classCourseList 多对多关联表对象集合。 + * @param classId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + public void addClassCourseList(List classCourseList, Long classId) { + for (ClassCourse classCourse : classCourseList) { + classCourse.setClassId(classId); + if (classCourse.getCourseOrder() == null) { + classCourse.setCourseOrder(0); + } + } + classCourseMapper.insertList(classCourseList); + } + + /** + * 更新中间表数据。 + * + * @param classCourse 中间表对象。 + * @return 更新成功与否。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean updateClassCourse(ClassCourse classCourse) { + Example e = new Example(ClassCourse.class); + e.createCriteria() + .andEqualTo("classId", classCourse.getClassId()) + .andEqualTo("courseId", classCourse.getCourseId()); + return classCourseMapper.updateByExample(classCourse, e) > 0; + } + + /** + * 获取中间表数据。 + * + * @param classId 主表Id。 + * @param courseId 从表Id。 + * @return 中间表对象。 + */ + public ClassCourse getClassCourse(Long classId, Long courseId) { + Example e = new Example(ClassCourse.class); + e.createCriteria() + .andEqualTo("classId", classId) + .andEqualTo("courseId", courseId); + return classCourseMapper.selectOneByExample(e); + } + + /** + * 移除单条多对多关系。 + * + * @param classId 主表Id。 + * @param courseId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean removeClassCourse(Long classId, Long courseId) { + ClassCourse classCourse = new ClassCourse(); + classCourse.setClassId(classId); + classCourse.setCourseId(courseId); + return classCourseMapper.delete(classCourse) > 0; + } + + /** + * 批量添加多对多关联关系。 + * + * @param classStudentList 多对多关联表对象集合。 + * @param classId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + public void addClassStudentList(List classStudentList, Long classId) { + for (ClassStudent classStudent : classStudentList) { + classStudent.setClassId(classId); + } + classStudentMapper.insertList(classStudentList); + } + + /** + * 移除单条多对多关系。 + * + * @param classId 主表Id。 + * @param studentId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean removeClassStudent(Long classId, Long studentId) { + ClassStudent classStudent = new ClassStudent(); + classStudent.setClassId(classId); + classStudent.setStudentId(studentId); + return classStudentMapper.delete(classStudent) > 0; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param studentClass 最新数据对象。 + * @param originalStudentClass 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(StudentClass studentClass, StudentClass originalStudentClass) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(studentClass, originalStudentClass, StudentClass::getSchoolId) + && !schoolInfoService.existId(studentClass.getSchoolId())) { + return CallResult.error(String.format(errorMessageFormat, "所属校区")); + } + //这里是基于字典的验证。 + if (this.needToVerify(studentClass, originalStudentClass, StudentClass::getLeaderId) + && !studentService.existId(studentClass.getLeaderId())) { + return CallResult.error(String.format(errorMessageFormat, "学生班长")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentService.java new file mode 100644 index 00000000..435a0c9d --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/app/service/StudentService.java @@ -0,0 +1,202 @@ +package com.orange.demo.app.service; + +import com.orange.demo.application.common.constant.StudentStatus; +import com.orange.demo.app.dao.*; +import com.orange.demo.app.model.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 学生数据数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class StudentService extends BaseService { + + @Autowired + private StudentMapper studentMapper; + @Autowired + private ClassStudentMapper classStudentMapper; + @Autowired + private AreaCodeService areaCodeService; + @Autowired + private GradeService gradeService; + @Autowired + private SchoolInfoService schoolInfoService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return studentMapper; + } + + /** + * 保存新增对象。 + * + * @param student 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + public Student saveNew(Student student) { + student.setStudentId(idGenerator.nextLongId()); + student.setRegisterTime(new Date()); + if (student.getTotalCoin() == null) { + student.setTotalCoin(0); + } + if (student.getLeftCoin() == null) { + student.setLeftCoin(0); + } + if (student.getStatus() == null) { + student.setStatus(StudentStatus.NORMAL); + } + studentMapper.insert(student); + return student; + } + + /** + * 更新数据对象。 + * + * @param student 更新的对象。 + * @param originalStudent 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(Student student, Student originalStudent) { + student.setRegisterTime(originalStudent.getRegisterTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + return studentMapper.updateByPrimaryKey(student) == 1; + } + + /** + * 删除指定数据。 + * + * @param studentId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long studentId) { + // 这里先删除主数据 + if (studentMapper.deleteByPrimaryKey(studentId) == 0) { + return false; + } + // 这里可继续删除关联数据。 + // 开始删除多对多父表的关联 + ClassStudent classStudent = new ClassStudent(); + classStudent.setStudentId(studentId); + classStudentMapper.delete(classStudent); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getStudentListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentList(Student filter, String orderBy) { + return studentMapper.getStudentList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getStudentList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentListWithRelation(Student filter, String orderBy) { + List resultList = studentMapper.getStudentList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getNotInStudentListByClassId( + Long classId, Student filter, String orderBy) { + List resultList = + studentMapper.getNotInStudentListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param classId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getStudentListByClassId( + Long classId, Student filter, String orderBy) { + List resultList = + studentMapper.getStudentListByClassId(classId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param student 最新数据对象。 + * @param originalStudent 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public CallResult verifyRelatedData(Student student, Student originalStudent) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getProvinceId) + && !areaCodeService.existId(student.getProvinceId())) { + return CallResult.error(String.format(errorMessageFormat, "所在省份")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getCityId) + && !areaCodeService.existId(student.getCityId())) { + return CallResult.error(String.format(errorMessageFormat, "所在城市")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getDistrictId) + && !areaCodeService.existId(student.getDistrictId())) { + return CallResult.error(String.format(errorMessageFormat, "所在区县")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getGradeId) + && !gradeService.existId(student.getGradeId())) { + return CallResult.error(String.format(errorMessageFormat, "年级")); + } + //这里是基于字典的验证。 + if (this.needToVerify(student, originalStudent, Student::getSchoolId) + && !schoolInfoService.existId(student.getSchoolId())) { + return CallResult.error(String.format(errorMessageFormat, "所属校区")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/config/ApplicationConfig.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/ApplicationConfig.java new file mode 100644 index 00000000..86f8e4da --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/ApplicationConfig.java @@ -0,0 +1,46 @@ +package com.orange.demo.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 应用程序自定义的程序属性配置文件。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "application") +public class ApplicationConfig { + + /** + * token的Http Request Header的key + */ + private String tokenHeaderKey; + /** + * token在过期之前,但是已经需要被刷新时,response返回的header信息的key。 + */ + private String refreshedTokenHeaderKey; + /** + * token 加密用的密钥 + */ + private String tokenSigningKey; + /** + * 令牌的过期时间,单位毫秒 + */ + private Long expiration; + /** + * 用户密码被重置之后的缺省密码 + */ + private String defaultUserPassword; + /** + * 上传文件的基础目录 + */ + private String uploadFileBaseDir; + /** + * 授信ip列表,没有填写表示全部信任。多个ip之间逗号分隔,如: http://10.10.10.1:8080,http://10.10.10.2:8080 + */ + private String credentialIpList; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/config/DataSourceConfig.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/DataSourceConfig.java new file mode 100644 index 00000000..38b69b93 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/DataSourceConfig.java @@ -0,0 +1,30 @@ +package com.orange.demo.config; + +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import tk.mybatis.spring.annotation.MapperScan; + +import javax.sql.DataSource; + +/** + * 数据源配置Bean对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +@EnableTransactionManagement +@MapperScan(value = {"com.orange.demo.*.dao"}) +public class DataSourceConfig { + + @Bean(initMethod = "init", destroyMethod = "close") + @Primary + @ConfigurationProperties(prefix = "spring.datasource.druid") + public DataSource druidDataSource() { + return DruidDataSourceBuilder.create().build(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/config/FilterConfig.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/FilterConfig.java new file mode 100644 index 00000000..b42db88c --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/FilterConfig.java @@ -0,0 +1,57 @@ +package com.orange.demo.config; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.Filter; +import java.nio.charset.StandardCharsets; + +/** + * 这里主要配置Web的各种过滤器和监听器等Servlet容器组件。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +public class FilterConfig { + + /** + * 配置Ajax跨域过滤器。 + */ + @Bean + public CorsFilter corsFilterRegistration(ApplicationConfig applicationConfig) { + UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + if (StringUtils.isNotBlank(applicationConfig.getCredentialIpList())) { + String[] credentialIpList = StringUtils.split(applicationConfig.getCredentialIpList(), ","); + if (credentialIpList.length > 0) { + for (String ip : credentialIpList) { + corsConfiguration.addAllowedOrigin(ip); + } + } + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedMethod("*"); + corsConfiguration.addExposedHeader(applicationConfig.getRefreshedTokenHeaderKey()); + corsConfiguration.setAllowCredentials(true); + configSource.registerCorsConfiguration("/**", corsConfiguration); + } + return new CorsFilter(configSource); + } + + @Bean + public FilterRegistrationBean characterEncodingFilterRegistration() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>( + new org.springframework.web.filter.CharacterEncodingFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.addInitParameter("encoding", StandardCharsets.UTF_8.name()); + // forceEncoding强制response也被编码,另外即使request中已经设置encoding,forceEncoding也会重新设置 + filterRegistrationBean.addInitParameter("forceEncoding", "true"); + filterRegistrationBean.setAsyncSupported(true); + return filterRegistrationBean; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/config/InterceptorConfig.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/InterceptorConfig.java new file mode 100644 index 00000000..7ac7d8b0 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/config/InterceptorConfig.java @@ -0,0 +1,21 @@ +package com.orange.demo.config; + +import com.orange.demo.interceptor.AuthenticationInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 所有的项目拦截器都在这里集中配置 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/**"); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java new file mode 100644 index 00000000..2ecfc15b --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/interceptor/AuthenticationInterceptor.java @@ -0,0 +1,134 @@ +package com.orange.demo.interceptor; + +import com.orange.demo.config.ApplicationConfig; +import com.orange.demo.upms.model.SysPermWhitelist; +import com.orange.demo.upms.service.SysPermWhitelistService; +import com.orange.demo.upms.service.SysPermService; +import com.orange.demo.common.core.annotation.NoAuthInterface; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.util.ApplicationContextHolder; +import com.orange.demo.common.core.util.JwtUtil; +import com.orange.demo.common.core.cache.SessionCacheHelper; +import com.alibaba.fastjson.JSONObject; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Set; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 登录用户Token验证、生成和权限验证的拦截器。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class AuthenticationInterceptor implements HandlerInterceptor { + + private ApplicationConfig appConfig = + ApplicationContextHolder.getBean("applicationConfig"); + + private SessionCacheHelper cacheHelper = + ApplicationContextHolder.getBean("sessionCacheHelper"); + + private SysPermService sysPermService = + ApplicationContextHolder.getBean("sysPermService"); + + private static SysPermWhitelistService sysPermWhilelistService = + ApplicationContextHolder.getBean("sysPermWhitelistService"); + + private static Set whitelistPermSet; + + static { + List sysPermWhitelistList = sysPermWhilelistService.getAllList(); + whitelistPermSet = sysPermWhitelistList.stream() + .map(SysPermWhitelist::getPermUrl).collect(Collectors.toSet()); + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + String url = request.getRequestURI(); + // 如果接口方法标记NoAuthInterface注解,可以直接跳过Token鉴权验证,这里主要为了测试接口方便 + if (handler instanceof HandlerMethod) { + HandlerMethod hm = (HandlerMethod) handler; + if (hm.getBeanType().getAnnotation(NoAuthInterface.class) != null + || hm.getMethodAnnotation(NoAuthInterface.class) != null) { + return true; + } + } + String token = request.getHeader(appConfig.getTokenHeaderKey()); + if (StringUtils.isBlank(token)) { + token = request.getParameter(appConfig.getTokenHeaderKey()); + } + Claims c = JwtUtil.parseToken(token, appConfig.getTokenSigningKey()); + if (JwtUtil.isNullOrExpired(c)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已过期,请重新登录!")); + return false; + } + String sessionId = (String) c.get("sessionId"); + TokenData tokenData = cacheHelper.getTokenData(sessionId); + if (tokenData == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已失效,请重新登录!")); + return false; + } + TokenData.addToRequest(tokenData); + // 如果url在权限资源白名单中,则不需要进行鉴权操作 + if (!tokenData.getIsAdmin() && !whitelistPermSet.contains(url)) { + Set urlSet = sysPermService.getCacheableSysPermSetByUserId( + tokenData.getSessionId(), tokenData.getUserId()); + if (!urlSet.contains(url)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION)); + return false; + } + } + if (JwtUtil.needToRefresh(c)) { + String refreshedToken = JwtUtil.generateToken(c, appConfig.getExpiration(), appConfig.getTokenSigningKey()); + response.addHeader(appConfig.getRefreshedTokenHeaderKey(), refreshedToken); + } + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + // 这里需要空注解,否则sonar会不happy。 + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + // 这里需要空注解,否则sonar会不happy。 + } + + private void outputResponseMessage(HttpServletResponse response, ResponseResult respObj) { + PrintWriter out; + try { + out = response.getWriter(); + } catch (IOException e) { + log.error("Failed to call OutputResponseMessage.", e); + return; + } + response.setContentType("application/json; charset=utf-8"); + out.print(JSONObject.toJSONString(respObj)); + out.flush(); + out.close(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/LoginController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/LoginController.java new file mode 100644 index 00000000..408d19b9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/LoginController.java @@ -0,0 +1,151 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.config.ApplicationConfig; +import com.orange.demo.upms.service.*; +import com.orange.demo.upms.model.SysMenu; +import com.orange.demo.upms.model.SysUser; +import com.orange.demo.upms.model.constant.SysUserStatus; +import com.orange.demo.upms.model.constant.SysUserType; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.annotation.NoAuthInterface; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.cache.SessionCacheHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 登录接口控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/login") +public class LoginController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private SysMenuService sysMenuService; + @Autowired + private SysPermCodeService sysPermCodeService; + @Autowired + private SysPermService sysPermService; + @Autowired + private ApplicationConfig appConfig; + @Autowired + private SessionCacheHelper cacheHelper; + @Autowired + private PasswordEncoder passwordEncoder; + + /** + * 登录接口。 + * + * @param loginName 登录名。 + * @param password 密码。 + * @return 应答结果对象,其中包括JWT的Token数据,以及菜单列表。 + */ + @NoAuthInterface + @GetMapping("/doLogin") + public ResponseResult doLogin( + @RequestParam String loginName, @RequestParam String password) throws Exception { + if (MyCommonUtil.existBlankArgument(loginName, password)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysUser user = sysUserService.getSysUserByLoginName(loginName); + password = URLDecoder.decode(password, StandardCharsets.UTF_8.name()); + //NOTE: 第一次使用时,请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。 + //执行RsaUtil工具类中的main函数,可以生成新的公钥和私钥。 + password = RsaUtil.decrypt(password, ApplicationConstant.PRIVATE_KEY); + if (user == null || !passwordEncoder.matches(password, user.getPassword())) { + return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD); + } + String errorMessage; + if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) { + errorMessage = "登录失败,用户账号被锁定!"; + return ResponseResult.error(ErrorCodeEnum.INVALID_USER_STATUS, errorMessage); + } + boolean isAdmin = user.getUserType() == SysUserType.TYPE_ADMIN; + Map claims = new HashMap<>(3); + String sessionId = MyCommonUtil.generateUuid(); + claims.put("sessionId", sessionId); + String token = JwtUtil.generateToken(claims, appConfig.getExpiration(), appConfig.getTokenSigningKey()); + JSONObject jsonData = new JSONObject(); + jsonData.put(TokenData.REQUEST_ATTRIBUTE_NAME, token); + jsonData.put("showName", user.getShowName()); + jsonData.put("isAdmin", isAdmin); + TokenData tokenData = new TokenData(); + tokenData.setSessionId(sessionId); + tokenData.setUserId(user.getUserId()); + tokenData.setShowName(user.getShowName()); + tokenData.setIsAdmin(isAdmin); + cacheHelper.putTokenData(sessionId, tokenData); + List menuList; + if (isAdmin) { + menuList = sysMenuService.getAllMenuList(); + } else { + menuList = sysMenuService.getMenuListByUserId(user.getUserId()); + List permCodeList = sysPermCodeService.getPermCodeListByUserId(user.getUserId()); + jsonData.put("permCodeList", permCodeList); + } + jsonData.put("menuList", menuList); + if (user.getUserType() != SysUserType.TYPE_ADMIN) { + // 缓存用户的权限资源 + sysPermService.putUserSysPermCache(sessionId, user.getUserId(), isAdmin); + } + return ResponseResult.success(jsonData); + } + + /** + * 登出操作。同时将Session相关的信息从缓存中删除。 + * + * @return 应答结果对象。 + */ + @PostMapping("/doLogout") + public ResponseResult doLogout() { + cacheHelper.removeAllSessionCache(); + return ResponseResult.success(); + } + + /** + * 用户修改自己的密码。 + * + * @param oldPass 原有密码。 + * @param newPass 新密码。 + * @return 应答结果对象。 + */ + @PostMapping("/changePassword") + public ResponseResult changePassword( + @MyRequestBody String oldPass, @MyRequestBody String newPass) throws Exception { + if (MyCommonUtil.existBlankArgument(oldPass, oldPass)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + TokenData tokenData = TokenData.takeFromRequest(); + SysUser user = sysUserService.getById(tokenData.getUserId()); + oldPass = URLDecoder.decode(oldPass, StandardCharsets.UTF_8.name()); + //NOTE: 第一次使用时,请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。 + //执行RsaUtil工具类中的main函数,可以生成新的公钥和私钥。 + oldPass = RsaUtil.decrypt(oldPass, ApplicationConstant.PRIVATE_KEY); + if (user == null || !passwordEncoder.matches(oldPass, user.getPassword())) { + return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD); + } + newPass = URLDecoder.decode(newPass, StandardCharsets.UTF_8.name()); + newPass = RsaUtil.decrypt(newPass, ApplicationConstant.PRIVATE_KEY); + if (!sysUserService.changePassword(tokenData.getUserId(), newPass)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysMenuController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysMenuController.java new file mode 100644 index 00000000..8ac13a44 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysMenuController.java @@ -0,0 +1,160 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.upms.model.SysMenu; +import com.orange.demo.upms.service.SysMenuService; +import com.orange.demo.upms.service.SysPermCodeService; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; + +/** + * 菜单管理接口控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysMenu") +public class SysMenuController { + + @Autowired + private SysMenuService sysMenuService; + @Autowired + private SysPermCodeService sysPermCodeService; + + /** + * 添加新菜单操作。 + * + * @param sysMenu 新菜单对象。 + * @param permCodeIdListString 与当前菜单Id绑定的权限Id列表,多个权限之间逗号分隔。 + * @return 应答结果对象,包含新增菜单的主键Id。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysMenu sysMenu, @MyRequestBody String permCodeIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysMenu); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + CallResult result = sysMenuService.verifyRelatedData(sysMenu, null, permCodeIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set permCodeIdSet = null; + if (result.getData() != null) { + permCodeIdSet = (Set) result.getData().get("permCodeIdSet"); + } + sysMenuService.saveNew(sysMenu, permCodeIdSet); + JSONObject responseData = new JSONObject(); + responseData.put("sysMenuId", sysMenu.getMenuId()); + return ResponseResult.success(responseData); + } + + /** + * 更新菜单数据操作。 + * + * @param sysMenu 更新菜单对象。 + * @param permCodeIdListString 与当前菜单Id绑定的权限Id列表,多个权限之间逗号分隔。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysMenu sysMenu, @MyRequestBody String permCodeIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysMenu, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysMenu originalSysMenu = sysMenuService.getById(sysMenu.getMenuId()); + if (originalSysMenu == null) { + errorMessage = "数据验证失败,当前菜单并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + CallResult result = sysMenuService.verifyRelatedData(sysMenu, originalSysMenu, permCodeIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set permCodeIdSet = null; + if (result.getData() != null) { + permCodeIdSet = (Set) result.getData().get("permCodeIdSet"); + } + if (!sysMenuService.update(sysMenu, originalSysMenu, permCodeIdSet)) { + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定菜单操作。 + * + * @param menuId 指定菜单主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long menuId) { + if (MyCommonUtil.existBlankArgument(menuId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + String errorMessage; + if (sysMenuService.hasChildren(menuId)) { + errorMessage = "数据验证失败,当前菜单存在下级菜单!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysMenuService.remove(menuId)) { + errorMessage = "数据操作失败,菜单不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 获取全部菜单列表。 + * + * @return 应答结果对象,包含全部菜单数据列表。 + */ + @GetMapping("/list") + public ResponseResult> list() { + return ResponseResult.success(sysMenuService.getAllListByOrder("showOrder")); + } + + /** + * 查看指定菜单数据详情。 + * + * @param menuId 指定菜单主键Id。 + * @return 应答结果对象,包含菜单详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long menuId) { + if (MyCommonUtil.existBlankArgument(menuId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysMenu sysMenu = sysMenuService.getByIdWithRelation(menuId, MyRelationParam.full()); + if (sysMenu == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(sysMenu); + } + + /** + * 列出与指定菜单关联的权限字和权限资源,便于管理员排查配置中的错误。 + * + * @param menuId 菜单Id。 + * @return 与菜单关联的权限字和权限资源列表。 + */ + @GetMapping("/listMenuPerm") + public ResponseResult>> listMenuPerm(@RequestParam Long menuId) { + return ResponseResult.success(sysPermCodeService.getPermCodeListByMenuId(menuId)); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermCodeController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermCodeController.java new file mode 100644 index 00000000..14339f8c --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermCodeController.java @@ -0,0 +1,180 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.upms.model.SysPermCode; +import com.orange.demo.upms.service.SysPermCodeService; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.object.MyPageParam; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.util.MyPageUtil; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; + +/** + * 权限字管理接口控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPermCode") +public class SysPermCodeController { + + @Autowired + private SysPermCodeService sysPermCodeService; + + /** + * 新增权限字操作。 + * + * @param sysPermCode 新增权限字对象。 + * @param permIdListString 与当前权限Id绑定的权限资源Id列表,多个权限资源之间逗号分隔。 + * @return 应答结果对象,包含新增权限字的主键Id。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysPermCode sysPermCode, @MyRequestBody String permIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermCode); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED); + } + CallResult result = sysPermCodeService.verifyRelatedData(sysPermCode, null, permIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set permIdSet = null; + if (result.getData() != null) { + permIdSet = (Set) result.getData().get("permIdSet"); + } + sysPermCode = sysPermCodeService.saveNew(sysPermCode, permIdSet); + JSONObject responseData = new JSONObject(); + responseData.put("sysPermCodeId", sysPermCode.getPermCodeId()); + return ResponseResult.success(responseData); + } + + /** + * 更新权限字操作。 + * + * @param sysPermCode 更新权限字对象。 + * @param permIdListString 与当前权限Id绑定的权限资源Id列表,多个权限资源之间逗号分隔。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPermCode sysPermCode, @MyRequestBody String permIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermCode, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysPermCode originalSysPermCode = sysPermCodeService.getById(sysPermCode.getPermCodeId()); + if (originalSysPermCode == null) { + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + CallResult result = sysPermCodeService.verifyRelatedData(sysPermCode, originalSysPermCode, permIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set permIdSet = null; + if (result.getData() != null) { + permIdSet = (Set) result.getData().get("permIdSet"); + } + try { + if (!sysPermCodeService.update(sysPermCode, originalSysPermCode, permIdSet)) { + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + } catch (DuplicateKeyException e) { + errorMessage = "数据操作失败,权限字编码已经存在!"; + return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定权限字操作。 + * + * @param permCodeId 指定的权限字主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long permCodeId) { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + String errorMessage; + if (sysPermCodeService.hasChildren(permCodeId)) { + errorMessage = "数据验证失败,当前权限字存在下级权限字!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysPermCodeService.remove(permCodeId)) { + errorMessage = "数据操作失败,权限字不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看权限字列表。 + * + * @return 应答结果对象,包含权限字列表。 + */ + @PostMapping("/list") + public ResponseResult> list() { + return ResponseResult.success(sysPermCodeService.getAllListByOrder("permCodeType", "showOrder")); + } + + /** + * 查看权限字对象详情。 + * + * @param permCodeId 指定权限字主键Id。 + * @return 应答结果对象,包含权限字对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long permCodeId) { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysPermCode sysPermCode = sysPermCodeService.getByIdWithRelation(permCodeId, MyRelationParam.full()); + if (sysPermCode == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(sysPermCode); + } + + /** + * 查看用户关联的权限字列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param permCode 模糊匹配的权限字名,LIKE %permCode%。 + * @param pageParam 分页对象。 + * @return 应答结果对象,包含该用户的全部权限资源列表。 + */ + @PostMapping("/listAllPermCodesByUserFilter") + public ResponseResult listAllPermCodesByUserFilter( + @MyRequestBody String loginName, + @MyRequestBody String permCode, + @MyRequestBody MyPageParam pageParam) { + if (MyCommonUtil.existBlankArgument(loginName)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List permCodeList = + sysPermCodeService.getUserPermCodeListByFilter(loginName, permCode); + JSONObject responseData = MyPageUtil.makeResponseData(permCodeList); + return ResponseResult.success(responseData); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermController.java new file mode 100644 index 00000000..4a83e032 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermController.java @@ -0,0 +1,197 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.upms.model.SysPerm; +import com.orange.demo.upms.model.SysPermModule; +import com.orange.demo.upms.service.SysPermService; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.object.MyPageParam; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.util.MyPageUtil; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; +import java.util.Map; + +/** + * 权限资源管理接口控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPerm") +public class SysPermController { + + @Autowired + private SysPermService sysPermService; + + /** + * 新增权限资源操作。 + * + * @param sysPerm 新增权限资源对象。 + * @return 应答结果对象,包含新增权限资源的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysPerm sysPerm) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPerm); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + CallResult result = sysPermService.verifyRelatedData(sysPerm, null); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + sysPerm = sysPermService.saveNew(sysPerm); + JSONObject responseData = new JSONObject(); + responseData.put("permId", sysPerm.getPermId()); + return ResponseResult.success(responseData); + } + + /** + * 更新权限资源操作。 + * + * @param sysPerm 更新权限资源对象。 + * @return 应答结果对象,包含更新权限资源的主键Id。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPerm sysPerm) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPerm, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysPerm originalPerm = sysPermService.getById(sysPerm.getPermId()); + if (originalPerm == null) { + errorMessage = "数据验证失败,当前权限资源并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + CallResult result = sysPermService.verifyRelatedData(sysPerm, originalPerm); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + if (result.getData() != null) { + SysPermModule permModule = (SysPermModule) result.getData().get("permModule"); + sysPerm.setModuleId(permModule.getModuleId()); + } + sysPermService.update(sysPerm, originalPerm); + return ResponseResult.success(); + } + + /** + * 删除指定权限资源操作。 + * + * @param permId 指定的权限资源主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long permId) { + if (MyCommonUtil.existBlankArgument(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysPermService.remove(permId)) { + String errorMessage = "数据操作失败,权限不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看权限资源对象详情。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含权限资源对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long permId) { + if (MyCommonUtil.existBlankArgument(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysPerm perm = sysPermService.getById(permId); + if (perm == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(perm); + } + + /** + * 查看权限资源列表。 + * + * @param sysPermFilter 过滤对象。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含权限资源列表。 + */ + @PostMapping("/list") + public ResponseResult list(@MyRequestBody SysPerm sysPermFilter, @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List resultList = sysPermService.getPermListWithRelation(sysPermFilter); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看用户关联的权限资源列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param moduleId 精确匹配权限模块Id。 + * @param url 模糊匹配的url过滤条件。 + * @param pageParam 分页对象。 + * @return 应答结果对象,包含该用户的全部权限资源列表。 + */ + @PostMapping("/listAllPermsByUserFilter") + public ResponseResult listAllPermsByUserFilter( + @MyRequestBody String loginName, + @MyRequestBody Long moduleId, + @MyRequestBody String url, + @MyRequestBody MyPageParam pageParam) { + if (MyCommonUtil.existBlankArgument(loginName)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List> userPermMapList = + sysPermService.getUserPermListByFilter(loginName, moduleId, url); + JSONObject responseData = MyPageUtil.makeResponseData(userPermMapList); + return ResponseResult.success(responseData); + } + + /** + * 查看拥有指定权限资源的所有用户数据列表。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含用户数据列表。 + */ + @PostMapping("/listAllUsers") + public ResponseResult>> listAllUsers(@MyRequestBody Long permId) { + if (MyCommonUtil.existBlankArgument(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + List> permUserMapList = sysPermService.getPermUserListById(permId); + return ResponseResult.success(permUserMapList); + } + + /** + * 查看拥有指定权限资源的所有角色数据列表。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含角色数据列表。 + */ + @PostMapping("/listAllRoles") + public ResponseResult>> listAllRoles(@MyRequestBody Long permId) { + if (MyCommonUtil.existBlankArgument(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + List> permRoleMapList = sysPermService.getPermRoleListById(permId); + return ResponseResult.success(permRoleMapList); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermModuleController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermModuleController.java new file mode 100644 index 00000000..373ecb24 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysPermModuleController.java @@ -0,0 +1,157 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.upms.model.SysPerm; +import com.orange.demo.upms.model.SysPermModule; +import com.orange.demo.upms.service.SysPermModuleService; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.annotation.MyRequestBody; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * 权限资源模块管理接口控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPermModule") +public class SysPermModuleController { + + @Autowired + private SysPermModuleService sysPermModuleService; + + /** + * 新增权限资源模块操作。 + * + * @param sysPermModule 新增权限资源模块对象。 + * @return 应答结果对象,包含新增权限资源模块的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysPermModule sysPermModule) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermModule); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + if (sysPermModule.getParentId() != null + && sysPermModuleService.getById(sysPermModule.getParentId()) == null) { + errorMessage = "数据验证失败,关联的上级权限模块并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage); + } + sysPermModuleService.saveNew(sysPermModule); + JSONObject responseData = new JSONObject(); + responseData.put("permModuleId", sysPermModule.getModuleId()); + return ResponseResult.success(responseData); + } + + /** + * 更新权限资源模块操作。 + * + * @param sysPermModule 更新权限资源模块对象。 + * @return 应答结果对象,包含新增权限资源模块的主键Id。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPermModule sysPermModule) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermModule, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysPermModule originalPermModule = sysPermModuleService.getById(sysPermModule.getModuleId()); + if (originalPermModule == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + if (sysPermModule.getParentId() != null + && !sysPermModule.getParentId().equals(originalPermModule.getParentId())) { + if (sysPermModuleService.getById(sysPermModule.getParentId()) == null) { + errorMessage = "数据验证失败,关联的上级权限模块并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage); + } + } + if (!sysPermModuleService.update(sysPermModule, originalPermModule)) { + errorMessage = "数据验证失败,当前模块并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定权限资源模块操作。 + * + * @param moduleId 指定的权限资源模块主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long moduleId) { + if (MyCommonUtil.existBlankArgument(moduleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + String errorMessage; + if (sysPermModuleService.hasChildren(moduleId) + || sysPermModuleService.hasModulePerms(moduleId)) { + errorMessage = "数据验证失败,当前权限模块存在子模块或权限资源,请先删除关联数据!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysPermModuleService.remove(moduleId)) { + errorMessage = "数据操作失败,权限模块不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看全部权限资源模块列表。 + * + * @return 应答结果对象,包含权限资源模块列表。 + */ + @GetMapping("/list") + public ResponseResult> list() { + return ResponseResult.success(sysPermModuleService.getAllListByOrder("showOrder")); + } + + /** + * 列出全部权限资源模块及其下级关联的权限资源列表。 + * + * @return 应答结果对象,包含树状列表,结构为权限资源模块和权限资源之间的树状关系。 + */ + @GetMapping("/listAll") + public ResponseResult>> listAll() { + List sysPermModuleList = sysPermModuleService.getPermModuleAndPermList(); + List> resultList = new LinkedList<>(); + for (SysPermModule sysPermModule : sysPermModuleList) { + Map permModuleMap = new HashMap<>(5); + permModuleMap.put("id", sysPermModule.getModuleId()); + permModuleMap.put("name", sysPermModule.getModuleName()); + permModuleMap.put("type", sysPermModule.getModuleType()); + permModuleMap.put("isPerm", false); + if (MyCommonUtil.isNotBlankOrNull(sysPermModule.getParentId())) { + permModuleMap.put("parentId", sysPermModule.getParentId()); + } + resultList.add(permModuleMap); + if (CollectionUtils.isNotEmpty(sysPermModule.getSysPermList())) { + for (SysPerm sysPerm : sysPermModule.getSysPermList()) { + Map permMap = new HashMap<>(4); + permMap.put("id", sysPerm.getPermId()); + permMap.put("name", sysPerm.getPermName()); + permMap.put("isPerm", true); + permMap.put("url", sysPerm.getUrl()); + permMap.put("parentId", sysPermModule.getModuleId()); + resultList.add(permMap); + } + } + } + return ResponseResult.success(resultList); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysRoleController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysRoleController.java new file mode 100644 index 00000000..396e1af3 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysRoleController.java @@ -0,0 +1,323 @@ +package com.orange.demo.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import com.orange.demo.upms.model.SysRole; +import com.orange.demo.upms.model.SysUser; +import com.orange.demo.upms.model.SysUserRole; +import com.orange.demo.upms.service.SysRoleService; +import com.orange.demo.upms.service.SysUserService; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.util.MyCommonUtil; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.MyOrderParam; +import com.orange.demo.common.core.object.MyPageParam; +import com.orange.demo.common.core.object.ResponseResult; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.util.MyPageUtil; +import com.orange.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 角色管理接口控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysRole") +public class SysRoleController { + + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysUserService sysUserService; + + /** + * 新增角色操作。 + * + * @param sysRole 新增角色对象。 + * @param menuIdListString 与当前角色Id绑定的menuId列表,多个menuId之间逗号分隔。 + * @return 应答结果对象,包含新增角色的主键Id。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysRole sysRole, @MyRequestBody String menuIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysRole); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + CallResult result = sysRoleService.verifyRelatedData(sysRole, null, menuIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set menuIdSet = null; + if (result.getData() != null) { + menuIdSet = (Set) result.getData().get("menuIdSet"); + } + sysRoleService.saveNew(sysRole, menuIdSet); + JSONObject responseData = new JSONObject(); + responseData.put("roleId", sysRole.getRoleId()); + return ResponseResult.success(responseData); + } + + /** + * 更新角色操作。 + * + * @param sysRole 更新角色对象。 + * @param menuIdListString 与当前角色Id绑定的menuId列表,多个menuId之间逗号分隔。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysRole sysRole, @MyRequestBody String menuIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysRole, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysRole originalSysRole = sysRoleService.getById(sysRole.getRoleId()); + if (originalSysRole == null) { + errorMessage = "数据验证失败,当前角色并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + CallResult result = sysRoleService.verifyRelatedData(sysRole, originalSysRole, menuIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set menuIdSet = null; + if (result.getData() != null) { + menuIdSet = (Set) result.getData().get("menuIdSet"); + } + if (!sysRoleService.update(sysRole, originalSysRole, menuIdSet)) { + errorMessage = "更新失败,数据不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定角色操作。 + * + * @param roleId 指定角色主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long roleId) { + if (MyCommonUtil.existBlankArgument(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysRoleService.remove(roleId)) { + String errorMessage = "数据操作失败,角色不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看角色列表。 + * + * @param sysRoleFilter 角色过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含角色列表。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SysRole sysRoleFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List roleList = sysRoleService.getSysRoleList( + sysRoleFilter, MyOrderParam.buildOrderBy(orderParam, SysRole.class)); + return ResponseResult.success(MyPageUtil.makeResponseData(roleList)); + } + + /** + * 查看角色详情。 + * + * @param roleId 指定角色主键Id。 + * @return 应答结果对象,包含角色详情对象。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long roleId) { + if (MyCommonUtil.existBlankArgument(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysRole sysRole = sysRoleService.getByIdWithRelation(roleId, MyRelationParam.full()); + if (sysRole == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(sysRole); + } + + /** + * 获取不包含指定角色Id的用户列表。 + * 用户和角色是多对多关系,当前接口将返回没有赋值指定RoleId的用户列表。可用于给角色添加新用户。 + * + * @param roleId 角色主键Id。 + * @param sysUserFilter 用户过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listNotInUserRole") + public ResponseResult listNotInUserRole( + @MyRequestBody Long roleId, + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doRoleUserVerify(roleId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = + sysUserService.getNotInSysUserListByRoleId(roleId, sysUserFilter, orderBy); + JSONObject responseData = MyPageUtil.makeResponseData(resultList); + return ResponseResult.success(responseData); + } + + /** + * 拥有指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param sysUserFilter 用户过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listUserRole") + public ResponseResult listUserRole( + @MyRequestBody Long roleId, + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doRoleUserVerify(roleId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = sysUserService.getSysUserListByRoleId(roleId, sysUserFilter, orderBy); + JSONObject responseData = MyPageUtil.makeResponseData(resultList); + return ResponseResult.success(responseData); + } + + private ResponseResult doRoleUserVerify(Long roleId) { + if (MyCommonUtil.existBlankArgument(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysRoleService.existId(roleId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 为指定角色添加用户列表。该操作可同时给一批用户赋值角色,并在同一事务内完成。 + * + * @param roleId 角色主键Id。 + * @param userIdListString 逗号分隔的用户Id列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addUserRole") + public ResponseResult addUserRole( + @MyRequestBody Long roleId, @MyRequestBody String userIdListString) { + if (MyCommonUtil.existBlankArgument(roleId, userIdListString)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Set userIdSet = Arrays.stream( + userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysRoleService.existId(roleId) + || !sysUserService.existUniqueKeyList("userId", userIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + List userRoleList = new LinkedList<>(); + for (Long userId : userIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + userRoleList.add(userRole); + } + sysRoleService.addUserRoleList(userRoleList); + return ResponseResult.success(); + } + + /** + * 为指定用户移除指定角色。 + * + * @param roleId 指定角色主键Id。 + * @param userId 指定用户主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/deleteUserRole") + public ResponseResult deleteUserRole( + @MyRequestBody Long roleId, @MyRequestBody Long userId) { + if (MyCommonUtil.existBlankArgument(roleId, userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysRoleService.removeUserRole(roleId, userId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 通过权限字Id获取拥有改权限的所有角色。 + * 开发人员调试用接口。 + * + * @param permCodeId 查询的权限字Id。 + * @param pageParam 分页对象。 + * @return 符合条件的角色列表。 + */ + @PostMapping("/listAllRolesByPermCode") + public ResponseResult listAllRolesByPermCode( + @MyRequestBody Long permCodeId, @MyRequestBody MyPageParam pageParam) { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List roleList = sysRoleService.getSysRoleListByPermCodeId(permCodeId); + JSONObject responseData = MyPageUtil.makeResponseData(roleList); + return ResponseResult.success(responseData); + } + + /** + * 通过权限资源url,模糊搜索拥有改权限的所有角色。 + * 开发人员调试用接口。 + * + * @param url 用于模糊搜索的url。 + * @param pageParam 分页对象。 + * @return 符合条件的角色列表。 + */ + @PostMapping("/listAllRolesByPerm") + public ResponseResult listAllRolesByPerm( + @MyRequestBody String url, @MyRequestBody MyPageParam pageParam) { + if (MyCommonUtil.existBlankArgument(url)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List roleList = sysRoleService.getSysRoleListByPerm(url); + JSONObject responseData = MyPageUtil.makeResponseData(roleList); + return ResponseResult.success(responseData); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java new file mode 100644 index 00000000..0546a8d4 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/controller/SysUserController.java @@ -0,0 +1,176 @@ +package com.orange.demo.upms.controller; + +import com.github.pagehelper.page.PageMethod; +import com.orange.demo.upms.model.*; +import com.orange.demo.upms.service.*; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.*; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.annotation.MyRequestBody; +import com.orange.demo.common.core.validator.AddGroup; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.config.ApplicationConfig; +import lombok.extern.slf4j.Slf4j; +import com.alibaba.fastjson.JSONObject; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 用户管理操作控制器类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysUser") +public class SysUserController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private PasswordEncoder passwordEncoder; + @Autowired + private ApplicationConfig appConfig; + + /** + * 新增用户操作。 + * + * @param sysUser 新增用户对象。 + * @param roleIdListString 逗号分隔的角色Id列表。 + * @return 应答结果对象,包含新增用户的主键Id。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysUser sysUser, @MyRequestBody String roleIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, AddGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + CallResult result = sysUserService.verifyRelatedData(sysUser, null, roleIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set roleIdSet = (Set) result.getData().get("roleIdSet"); + sysUserService.saveNew(sysUser, roleIdSet); + JSONObject responseData = new JSONObject(); + responseData.put("userId", sysUser.getUserId()); + return ResponseResult.success(responseData); + } + + /** + * 更新用户操作。 + * + * @param sysUser 更新用户对象。 + * @param roleIdListString 逗号分隔的角色Id列表。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysUser sysUser, @MyRequestBody String roleIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage); + } + SysUser originalUser = sysUserService.getById(sysUser.getUserId()); + if (originalUser == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + CallResult result = sysUserService.verifyRelatedData(sysUser, originalUser, roleIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + Set roleIdSet = (Set) result.getData().get("roleIdSet"); + if (!sysUserService.update(sysUser, originalUser, roleIdSet)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 重置密码操作。 + * + * @param userId 指定用户主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/resetPassword") + public ResponseResult resetPassword(@MyRequestBody Long userId) { + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysUserService.changePassword(userId, appConfig.getDefaultUserPassword())) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除用户管理数据。 + * + * @param userId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long userId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SysUser originalSysUser = sysUserService.getById(userId); + if (originalSysUser == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!sysUserService.remove(userId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的用户管理列表。 + * + * @param sysUserFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = sysUserService.getSysUserListWithRelation(sysUserFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定用户管理对象详情。 + * + * @param userId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long userId) { + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 这里查看用户数据时候,需要把用户多对多关联的角色和数据权限Id一并查出。 + SysUser sysUser = sysUserService.getByIdWithRelation(userId, MyRelationParam.full()); + if (sysUser == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(sysUser); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysMenuMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysMenuMapper.java new file mode 100644 index 00000000..59f04e31 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysMenuMapper.java @@ -0,0 +1,23 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysMenu; + +import java.util.List; + +/** + * 菜单数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysMenuMapper extends BaseDaoMapper { + + /** + * 获取登录用户的菜单列表。 + * + * @param userId 登录用户。 + * @return 菜单列表。 + */ + List getMenuListByUserId(Long userId); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysMenuPermCodeMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysMenuPermCodeMapper.java new file mode 100644 index 00000000..c4837b37 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysMenuPermCodeMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysMenuPermCode; + +/** + * 菜单与权限字关系数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysMenuPermCodeMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermCodeMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermCodeMapper.java new file mode 100644 index 00000000..96ce0f3c --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermCodeMapper.java @@ -0,0 +1,43 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysPermCode; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 权限字数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysPermCodeMapper extends BaseDaoMapper { + + /** + * 获取用户的所有权限字列表。 + * + * @param userId 用户Id。 + * @return 该用户的权限字列表。 + */ + List getPermCodeListByUserId(Long userId); + + /** + * 获取该菜单的权限字和关联的权限资源列表。 + * + * @param menuId 菜单Id。 + * @return 权限字和关联的权限资源列表。 + */ + List> getPermCodeListByMenuId(Long menuId); + + /** + * 获取指定用户的权限字列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param permCode 模糊匹配的权限字名,LIKE %permCode%。 + * @return 权限字列表。 + */ + List getUserPermCodeListByFilter( + @Param("loginName") String loginName, @Param("permCode") String permCode); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermCodePermMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermCodePermMapper.java new file mode 100644 index 00000000..cd55d331 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermCodePermMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysPermCodePerm; + +/** + * 权限字与权限资源关系数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysPermCodePermMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermMapper.java new file mode 100644 index 00000000..57de97e1 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermMapper.java @@ -0,0 +1,61 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysPerm; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 权限资源数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysPermMapper extends BaseDaoMapper { + + /** + * 获取用户的权限列表。 + * + * @param userId 用户Id。 + * @return 该用户的权限标识列表。 + */ + List getPermListByUserId(@Param("userId") Long userId); + + /** + * 获取指定用户Id的权限列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param moduleId 精确匹配权限模块Id。 + * @param url 权限的url过滤条件,LIKE %url%。 + * @return 权限列表。 + */ + List> getUserPermListByFilter( + @Param("loginName") String loginName, @Param("moduleId") Long moduleId, @Param("url") String url); + + /** + * 根据关联权限字主键Id,获取权限资源数据列表。 + * + * @param permCodeId 关联权限字主键Id。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 从表数据列表。 + */ + List getPermListByPermCodeId(@Param("permCodeId") Long permCodeId, @Param("orderBy") String orderBy); + + /** + * 获取指定权限的用户列表。 + * + * @param permId 指定权限。 + * @return 用户列表。 + */ + List> getPermUserListById(@Param("permId") Long permId); + + /** + * 获取指定权限的角色列表。 + * + * @param permId 指定权限。 + * @return 角色列表。 + */ + List> getPermRoleListById(@Param("permId") Long permId); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermModuleMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermModuleMapper.java new file mode 100644 index 00000000..80a4d90e --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermModuleMapper.java @@ -0,0 +1,22 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysPermModule; + +import java.util.List; + +/** + * 权限资源模块数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysPermModuleMapper extends BaseDaoMapper { + + /** + * 获取整个权限模块和权限关联后的全部数据。 + * + * @return 关联的权限模块和权限资源列表。 + */ + List getPermModuleAndPermList(); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermWhitelistMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermWhitelistMapper.java new file mode 100644 index 00000000..e2d3b618 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysPermWhitelistMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysPermWhitelist; + +/** + * 权限资源白名单数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysPermWhitelistMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysRoleMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysRoleMapper.java new file mode 100644 index 00000000..c15ee2fb --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysRoleMapper.java @@ -0,0 +1,41 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysRole; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysRoleMapper extends BaseDaoMapper { + + /** + * 获取对象列表,过滤条件中包含like和between条件。 + * + * @param sysRoleFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysRoleList(@Param("sysRoleFilter") SysRole sysRoleFilter, @Param("orderBy") String orderBy); + + /** + * 根据权限字Id获取关联的角色列表。 + * + * @param permCodeId 权限字Id。 + * @return 关联的角色列表。 + */ + List getSysRoleListByPermCodeId(@Param("permCodeId") Long permCodeId); + + /** + * 根据url模糊查询关联的角色列表。 + * + * @param url url片段。 + * @return 关联的角色列表。 + */ + List getSysRoleListByPerm(@Param("url") String url); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysRoleMenuMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysRoleMenuMapper.java new file mode 100644 index 00000000..891bc0c8 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysRoleMenuMapper.java @@ -0,0 +1,13 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysRoleMenu; + +/** + * 角色与菜单操作关联关系数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysRoleMenuMapper extends BaseDaoMapper { +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java new file mode 100644 index 00000000..b08bc925 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysUserMapper.java @@ -0,0 +1,52 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysUser; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 用户管理数据操作访问接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysUserMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param sysUserFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysUserList( + @Param("sysUserFilter") SysUser sysUserFilter, @Param("orderBy") String orderBy); + + /** + * 根据角色Id,获取关联的用户Id列表。 + * + * @param roleId 关联的角色Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和RoleId关联的用户列表。 + */ + List getSysUserListByRoleId( + @Param("roleId") Long roleId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); + + /** + * 根据角色Id,获取和当前角色Id没有建立多对多关联关系的用户Id列表。 + * + * @param roleId 关联的角色Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和RoleId没有建立关联关系的用户列表。 + */ + List getNotInSysUserListByRoleId( + @Param("roleId") Long roleId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysUserRoleMapper.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysUserRoleMapper.java new file mode 100644 index 00000000..320a6bf9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/SysUserRoleMapper.java @@ -0,0 +1,22 @@ +package com.orange.demo.upms.dao; + +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.model.SysUserRole; + +import java.util.List; + +/** + * 用户与角色关联关系数据访问操作接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface SysUserRoleMapper extends BaseDaoMapper { + + /** + * 批量插入用户角色信息,如果用户角色已经存在,则不会重复插入。 + * + * @param userRoleList 待插入的角色用户列表。 + */ + void addUserRoleList(List userRoleList); +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysMenuMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysMenuMapper.xml new file mode 100644 index 00000000..60db0f8c --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysMenuMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysMenuPermCodeMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysMenuPermCodeMapper.xml new file mode 100644 index 00000000..23965546 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysMenuPermCodeMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermCodeMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermCodeMapper.xml new file mode 100644 index 00000000..989a2bcf --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermCodeMapper.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermCodePermMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermCodePermMapper.xml new file mode 100644 index 00000000..e93dc650 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermCodePermMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermMapper.xml new file mode 100644 index 00000000..f1987410 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermMapper.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermModuleMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermModuleMapper.xml new file mode 100644 index 00000000..265dba8c --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermModuleMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermWhitelistMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermWhitelistMapper.xml new file mode 100644 index 00000000..e5bd6be9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysPermWhitelistMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysRoleMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysRoleMapper.xml new file mode 100644 index 00000000..495e41ad --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysRoleMapper.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysRoleMenuMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysRoleMenuMapper.xml new file mode 100644 index 00000000..62b6cc83 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysRoleMenuMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml new file mode 100644 index 00000000..0ded7457 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserMapper.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_user.login_name LIKE #{safeLoginName} + + + + AND zz_sys_user.show_name LIKE #{safeShowName} + + + AND zz_sys_user.user_status = #{sysUserFilter.userStatus} + + + AND zz_sys_user.create_time >= #{sysUserFilter.createTimeStart} + + + AND zz_sys_user.create_time <= #{sysUserFilter.createTimeEnd} + + + AND zz_sys_user.deleted_flag = ${@com.orange.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserRoleMapper.xml b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserRoleMapper.xml new file mode 100644 index 00000000..b8e5f287 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/dao/mapper/SysUserRoleMapper.xml @@ -0,0 +1,15 @@ + + + + + + + + + + REPLACE INTO zz_sys_user_role(user_id, role_id) VALUES + + (#{item.userId}, #{item.roleId}) + + + diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysMenu.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysMenu.java new file mode 100644 index 00000000..a622f775 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysMenu.java @@ -0,0 +1,93 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.annotation.RelationManyToMany; +import com.orange.demo.common.core.validator.ConstDictRef; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.upms.model.constant.SysMenuType; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +/** + * 菜单实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_menu") +public class SysMenu { + + /** + * 主键Id。 + */ + @NotNull(message = "菜单Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "menu_id") + private Long menuId; + + /** + * 父菜单Id,目录菜单的父菜单为null。 + */ + @Column(name = "parent_id") + private Long parentId; + + /** + * 菜单显示名称。 + */ + @NotBlank(message = "菜单显示名称不能为空!") + @Column(name = "menu_name") + private String menuName; + + /** + * 菜单类型(0: 目录 1: 菜单 2: 按钮 3: UI片段)。 + */ + @NotNull(message = "菜单类型不能为空!") + @ConstDictRef(constDictClass = SysMenuType.class, message = "数据验证失败,菜单类型为无效值!") + @Column(name = "menu_type") + private Integer menuType; + + /** + * 前端表单路由名称,仅用于menu_type为1的菜单类型。 + */ + @Column(name = "form_router_name") + private String formRouterName; + + /** + * 菜单显示顺序 (值越小,排序越靠前)。 + */ + @NotNull(message = "菜单显示顺序不能为空!") + @Column(name = "show_order") + private Integer showOrder; + + /** + * 菜单图标。 + */ + private String icon; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @RelationManyToMany( + relationMapperName = "sysMenuPermCodeMapper", + relationMasterIdField = "menuId", + relationModelClass = SysMenuPermCode.class) + @Transient + private List sysMenuPermCodeList; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysMenuPermCode.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysMenuPermCode.java new file mode 100644 index 00000000..27460ab5 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysMenuPermCode.java @@ -0,0 +1,30 @@ +package com.orange.demo.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +/** + * 菜单与权限字关联实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_menu_perm_code") +public class SysMenuPermCode { + + /** + * 关联菜单Id。 + */ + @Id + @Column(name = "menu_id") + private Long menuId; + + /** + * 关联权限字Id。 + */ + @Id + @Column(name = "perm_code_id") + private Long permCodeId; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPerm.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPerm.java new file mode 100644 index 00000000..3e9e7401 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPerm.java @@ -0,0 +1,81 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.Map; + +/** + * 权限资源实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_perm") +public class SysPerm { + + /** + * 权限Id。 + */ + @NotNull(message = "权限Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "perm_id") + private Long permId; + + /** + * 权限所在的权限模块Id。 + */ + @NotNull(message = "权限模块Id不能为空!") + @Column(name = "module_id") + private Long moduleId; + + /** + * 权限名称。 + */ + @NotBlank(message = "权限名称不能为空!") + @Column(name = "perm_name") + private String permName; + + /** + * 关联的URL。 + */ + @NotBlank(message = "权限关联的url不能为空!") + private String url; + + /** + * 权限在当前模块下的顺序,由小到大。 + */ + @NotNull(message = "权限显示顺序不能为空!") + @Column(name = "show_order") + private Integer showOrder; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @RelationDict( + masterIdField = "moduleId", + slaveServiceName = "SysPermModuleService", + slaveModelClass = SysPermModule.class, + slaveIdField = "moduleId", + slaveNameField = "moduleName") + @Transient + private Map moduleIdDictMap; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermCode.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermCode.java new file mode 100644 index 00000000..25fb48bc --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermCode.java @@ -0,0 +1,89 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.annotation.RelationManyToMany; +import com.orange.demo.common.core.validator.ConstDictRef; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.upms.model.constant.SysPermCodeType; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +/** + * 权限字实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_perm_code") +public class SysPermCode { + + /** + * 主键Id。 + */ + @NotNull(message = "权限字Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "perm_code_id") + private Long permCodeId; + + /** + * 上级权限字Id。 + */ + @Column(name = "parent_id") + private Long parentId; + + /** + * 权限字标识(一般为有含义的英文字符串)。 + */ + @NotBlank(message = "权限字编码不能为空!") + @Column(name = "perm_code") + private String permCode; + + /** + * 权限类型(0: 表单 1: UI片段 2: 操作)。 + */ + @NotNull(message = "权限字类型不能为空!") + @ConstDictRef(constDictClass = SysPermCodeType.class, message = "数据验证失败,权限类型为无效值!") + @Column(name = "perm_code_type") + private Integer permCodeType; + + /** + * 显示名称。 + */ + @NotBlank(message = "权限字显示名称不能为空!") + @Column(name = "show_name") + private String showName; + + /** + * 显示顺序(数值越小,越靠前)。 + */ + @NotNull(message = "权限字显示顺序不能为空!") + @Column(name = "show_order") + private Integer showOrder; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @RelationManyToMany( + relationMapperName = "sysPermCodePermMapper", + relationMasterIdField = "permCodeId", + relationModelClass = SysPermCodePerm.class) + @Transient + private List sysPermCodePermList; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermCodePerm.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermCodePerm.java new file mode 100644 index 00000000..befa7caf --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermCodePerm.java @@ -0,0 +1,30 @@ +package com.orange.demo.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +/** + * 权限字与权限资源关联实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_perm_code_perm") +public class SysPermCodePerm { + + /** + * 权限字Id。 + */ + @Id + @Column(name = "perm_code_id") + private Long permCodeId; + + /** + * 权限Id。 + */ + @Id + @Column(name = "perm_id") + private Long permId; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermModule.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermModule.java new file mode 100644 index 00000000..9ad50c2e --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermModule.java @@ -0,0 +1,77 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.ConstDictRef; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.upms.model.constant.SysPermModuleType; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +/** + * 权限模块实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_perm_module") +public class SysPermModule { + + /** + * 权限模块Id。 + */ + @NotNull(message = "权限模块Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "module_id") + private Long moduleId; + + /** + * 上级权限模块Id。 + */ + @Column(name = "parent_id") + private Long parentId; + + /** + * 权限模块名称。 + */ + @NotBlank(message = "权限模块名称不能为空!") + @Column(name = "module_name") + private String moduleName; + + /** + * 权限模块类型(0: 普通模块 1: Controller模块)。 + */ + @NotNull(message = "模块类型不能为空!") + @ConstDictRef(constDictClass = SysPermModuleType.class, message = "数据验证失败,权限模块类型为无效值!") + @Column(name = "module_type") + private Integer moduleType; + + /** + * 权限模块在当前层级下的顺序,由小到大。 + */ + @NotNull(message = "权限模块显示顺序不能为空!") + @Column(name = "show_order") + private Integer showOrder; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @Transient + private List sysPermList; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermWhitelist.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermWhitelist.java new file mode 100644 index 00000000..d60ac331 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysPermWhitelist.java @@ -0,0 +1,35 @@ +package com.orange.demo.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +/** + * 白名单实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_perm_whitelist") +public class SysPermWhitelist { + + /** + * 权限资源的URL。 + */ + @Id + @Column(name = "perm_url") + private String permUrl; + + /** + * 权限资源所属模块名字(通常是Controller的名字)。 + */ + @Column(name = "module_name") + private String moduleName; + + /** + * 权限的名称。 + */ + @Column(name = "perm_name") + private String permName; +} \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysRole.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysRole.java new file mode 100644 index 00000000..77195cf4 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysRole.java @@ -0,0 +1,83 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.annotation.RelationManyToMany; +import com.orange.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +/** + * 角色实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_role") +public class SysRole { + + /** + * 主键Id。 + */ + @NotNull(message = "角色Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "role_id") + private Long roleId; + + /** + * 角色名称。 + */ + @NotBlank(message = "角色名称不能为空!") + @Column(name = "role_name") + private String roleName; + + /** + * 创建者。 + */ + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 创建者显示名称。 + */ + @Column(name = "create_username") + private String createUsername; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 更新时间。 + */ + @Column(name = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @RelationManyToMany( + relationMapperName = "sysRoleMenuMapper", + relationMasterIdField = "roleId", + relationModelClass = SysRoleMenu.class) + @Transient + private List sysRoleMenuList; + + @Transient + private String createTimeStart; + + @Transient + private String createTimeEnd; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysRoleMenu.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysRoleMenu.java new file mode 100644 index 00000000..e5a4e1d8 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysRoleMenu.java @@ -0,0 +1,30 @@ +package com.orange.demo.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +/** + * 角色菜单实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_role_menu") +public class SysRoleMenu { + + /** + * 角色Id。 + */ + @Id + @Column(name = "role_id") + private Long roleId; + + /** + * 菜单Id。 + */ + @Id + @Column(name = "menu_id") + private Long menuId; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysUser.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysUser.java new file mode 100644 index 00000000..1b62008b --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysUser.java @@ -0,0 +1,145 @@ +package com.orange.demo.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.upms.model.constant.SysUserType; +import com.orange.demo.upms.model.constant.SysUserStatus; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.annotation.RelationManyToMany; +import com.orange.demo.common.core.annotation.DeletedFlagColumn; +import com.orange.demo.common.core.validator.AddGroup; +import com.orange.demo.common.core.validator.UpdateGroup; +import com.orange.demo.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; +import java.util.List; + +/** + * SysUser实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_user") +public class SysUser { + + /** + * 用户Id。 + */ + @NotNull(message = "数据验证失败,用户Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "user_id") + private Long userId; + + /** + * 登录用户名。 + */ + @NotBlank(message = "数据验证失败,登录用户名不能为空!") + @Column(name = "login_name") + private String loginName; + + /** + * 用户密码。 + */ + @NotBlank(message = "数据验证失败,用户密码不能为空!", groups = {AddGroup.class}) + private String password; + + /** + * 用户显示名称。 + */ + @NotBlank(message = "数据验证失败,用户显示名称不能为空!") + @Column(name = "show_name") + private String showName; + + /** + * 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。 + */ + @NotNull(message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)不能为空!") + @ConstDictRef(constDictClass = SysUserType.class, message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)为无效值!") + @Column(name = "user_type") + private Integer userType; + + /** + * 用户头像的Url。 + */ + @Column(name = "head_image_url") + private String headImageUrl; + + /** + * 用户状态(0: 正常 1: 锁定)。 + */ + @NotNull(message = "数据验证失败,用户状态(0: 正常 1: 锁定)不能为空!") + @ConstDictRef(constDictClass = SysUserStatus.class, message = "数据验证失败,用户状态(0: 正常 1: 锁定)为无效值!") + @Column(name = "user_status") + private Integer userStatus; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + /** + * 创建用户Id。 + */ + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 创建用户名。 + */ + @Column(name = "create_username") + private String createUsername; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 更新时间。 + */ + @Column(name = "update_time") + private Date updateTime; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @Transient + private String createTimeEnd; + + /** + * 多对多用户角色数据集合。 + */ + @RelationManyToMany( + relationMapperName = "sysUserRoleMapper", + relationMasterIdField = "userId", + relationModelClass = SysUserRole.class) + @Transient + private List sysUserRoleList; + + @RelationConstDict( + masterIdField = "userType", + constantDictClass = SysUserType.class) + @Transient + private Map userTypeDictMap; + + @RelationConstDict( + masterIdField = "userStatus", + constantDictClass = SysUserStatus.class) + @Transient + private Map userStatusDictMap; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysUserRole.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysUserRole.java new file mode 100644 index 00000000..e1ecb088 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/SysUserRole.java @@ -0,0 +1,30 @@ +package com.orange.demo.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +/** + * 用户角色实体对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Table(name = "zz_sys_user_role") +public class SysUserRole { + + /** + * 用户Id。 + */ + @Id + @Column(name = "user_id") + private Long userId; + + /** + * 角色Id。 + */ + @Id + @Column(name = "role_id") + private Long roleId; +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysMenuType.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysMenuType.java new file mode 100644 index 00000000..9aa83c68 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysMenuType.java @@ -0,0 +1,54 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 菜单类型常量对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class SysMenuType { + + /** + * 目录菜单。 + */ + public static final int TYPE_DIRECTORY = 0; + /** + * 普通菜单。 + */ + public static final int TYPE_MENU = 1; + /** + * 表单片段类型。 + */ + public static final int TYPE_UI_FRAGMENT = 2; + /** + * 按钮类型。 + */ + public static final int TYPE_BUTTON = 3; + + private static final Map DICT_MAP = new HashMap<>(4); + static { + DICT_MAP.put(0, "目录菜单"); + DICT_MAP.put(1, "普通菜单"); + DICT_MAP.put(2, "表单片段类型"); + DICT_MAP.put(3, "按钮类型"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysMenuType() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysPermCodeType.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysPermCodeType.java new file mode 100644 index 00000000..2906a0d4 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysPermCodeType.java @@ -0,0 +1,49 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 权限字类型常量对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class SysPermCodeType { + + /** + * 表单权限字。 + */ + public static final int TYPE_FORM = 0; + /** + * 表单片段布局权限字。 + */ + public static final int TYPE_FRAGMENT = 1; + /** + * 操作权限字。 + */ + public static final int TYPE_OPERATION = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(0, "表单权限字"); + DICT_MAP.put(1, "表单片段布局权限字"); + DICT_MAP.put(2, "操作权限字"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysPermCodeType() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysPermModuleType.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysPermModuleType.java new file mode 100644 index 00000000..0a92d0cd --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysPermModuleType.java @@ -0,0 +1,44 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 权限资源模块类型常量对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class SysPermModuleType { + + /** + * 普通模块。 + */ + public static final int TYPE_NORMAL = 0; + /** + * controller接口模块。 + */ + public static final int TYPE_CONTROLLER = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(0, "普通模块"); + DICT_MAP.put(1, "controller接口模块"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysPermModuleType() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java new file mode 100644 index 00000000..7e30b773 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysUserStatus.java @@ -0,0 +1,44 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用户状态常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class SysUserStatus { + + /** + * 正常状态。 + */ + public static final int STATUS_NORMAL = 0; + /** + * 锁定状态。 + */ + public static final int STATUS_LOCKED = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(STATUS_NORMAL, "正常状态"); + DICT_MAP.put(STATUS_LOCKED, "锁定状态"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserStatus() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java new file mode 100644 index 00000000..28444e4a --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/model/constant/SysUserType.java @@ -0,0 +1,49 @@ +package com.orange.demo.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用户类型常量字典对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class SysUserType { + + /** + * 管理员。 + */ + public static final int TYPE_ADMIN = 0; + /** + * 系统操作员。 + */ + public static final int TYPE_SYSTEM = 1; + /** + * 普通操作员。 + */ + public static final int TYPE_OPERATOR = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(TYPE_ADMIN, "管理员"); + DICT_MAP.put(TYPE_SYSTEM, "系统操作员"); + DICT_MAP.put(TYPE_OPERATOR, "普通操作员"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserType() { + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysMenuService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysMenuService.java new file mode 100644 index 00000000..a19fa91f --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysMenuService.java @@ -0,0 +1,234 @@ +package com.orange.demo.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.upms.dao.SysMenuMapper; +import com.orange.demo.upms.dao.SysMenuPermCodeMapper; +import com.orange.demo.upms.dao.SysRoleMenuMapper; +import com.orange.demo.upms.model.SysMenu; +import com.orange.demo.upms.model.SysMenuPermCode; +import com.orange.demo.upms.model.SysRoleMenu; +import com.orange.demo.upms.model.constant.SysMenuType; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.entity.Example; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 菜单数据服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysMenuService extends BaseService { + + @Autowired + private SysMenuMapper sysMenuMapper; + @Autowired + private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysMenuPermCodeMapper sysMenuPermCodeMapper; + @Autowired + private SysPermCodeService sysPermCodeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysMenuMapper; + } + + /** + * 保存新增的菜单对象。 + * + * @param sysMenu 新增的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 新增后的菜单对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysMenu saveNew(SysMenu sysMenu, Set permCodeIdSet) { + sysMenu.setMenuId(idGenerator.nextLongId()); + sysMenu.setCreateTime(new Date()); + sysMenu.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysMenuMapper.insert(sysMenu); + if (permCodeIdSet != null) { + List sysMenuPermCodeList = new LinkedList<>(); + for (Long permCodeId : permCodeIdSet) { + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setMenuId(sysMenu.getMenuId()); + menuPermCode.setPermCodeId(permCodeId); + sysMenuPermCodeList.add(menuPermCode); + } + sysMenuPermCodeMapper.insertList(sysMenuPermCodeList); + } + return sysMenu; + } + + /** + * 更新菜单对象。 + * + * @param sysMenu 更新的菜单对象。 + * @param originalSysMenu 原有的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysMenu sysMenu, SysMenu originalSysMenu, Set permCodeIdSet) { + sysMenu.setCreateTime(originalSysMenu.getCreateTime()); + sysMenu.setMenuType(originalSysMenu.getMenuType()); + sysMenu.setDeletedFlag(GlobalDeletedFlag.NORMAL); + if (sysMenuMapper.updateByPrimaryKey(sysMenu) != 1) { + return false; + } + SysMenuPermCode deletedMenuPermCode = new SysMenuPermCode(); + deletedMenuPermCode.setMenuId(sysMenu.getMenuId()); + sysMenuPermCodeMapper.delete(deletedMenuPermCode); + if (permCodeIdSet != null) { + List sysMenuPermCodeList = new LinkedList<>(); + for (Long permCodeId : permCodeIdSet) { + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setMenuId(sysMenu.getMenuId()); + menuPermCode.setPermCodeId(permCodeId); + sysMenuPermCodeList.add(menuPermCode); + } + sysMenuPermCodeMapper.insertList(sysMenuPermCodeList); + } + return true; + } + + /** + * 删除指定的菜单。 + * + * @param menuId 菜单主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long menuId) { + SysMenu menu = new SysMenu(); + menu.setMenuId(menuId); + menu.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysMenuMapper.updateByPrimaryKeySelective(menu) != 1) { + return false; + } + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setMenuId(menuId); + sysRoleMenuMapper.delete(roleMenu); + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setMenuId(menuId); + sysMenuPermCodeMapper.delete(menuPermCode); + return true; + } + + /** + * 获取全部菜单列表。 + * + * @return 全部菜单列表。 + */ + public List getAllMenuList() { + Example e = new Example(SysMenu.class); + e.orderBy("showOrder"); + Example.Criteria c = e.createCriteria(); + c.andIn("menuType", Arrays.asList(SysMenuType.TYPE_MENU, SysMenuType.TYPE_DIRECTORY)); + c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + return sysMenuMapper.selectByExample(e); + } + + /** + * 获取指定用户Id的菜单列表。 + * + * @param userId 用户主键Id。 + * @return 用户关联的菜单列表。 + */ + public List getMenuListByUserId(Long userId) { + return sysMenuMapper.getMenuListByUserId(userId); + } + + /** + * 判断当前菜单是否存在子菜单。 + * + * @param menuId 菜单主键Id。 + * @return 存在返回true,否则false。 + */ + public boolean hasChildren(Long menuId) { + SysMenu menu = new SysMenu(); + menu.setParentId(menuId); + return this.getCountByFilter(menu) > 0; + } + + /** + * 验证菜单对象关联的数据是否都合法。 + * + * @param sysMenu 当前操作的对象。 + * @param originalSysMenu 原有对象。 + * @param permCodeIdListString 逗号分隔的权限Id列表。 + * @return 验证结果。 + */ + public CallResult verifyRelatedData(SysMenu sysMenu, SysMenu originalSysMenu, String permCodeIdListString) { + JSONObject jsonObject = null; + if (this.needToVerify(sysMenu, originalSysMenu, SysMenu::getParentId)) { + // menu、ui fragment和button类型的menu不能没有parentId + if (sysMenu.getParentId() == null) { + if (sysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) { + return CallResult.error("数据验证失败,当前类型菜单项的上级菜单不能为空!"); + } + } else { + String errorMessage = checkErrorOfNonDirectoryMenu(sysMenu); + if (errorMessage != null) { + return CallResult.error(errorMessage); + } + } + } + if (StringUtils.isNotBlank(permCodeIdListString)) { + Set permCodeIdSet = Arrays.stream( + permCodeIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPermCodeService.existAllPrimaryKeys(permCodeIdSet)) { + return CallResult.error("数据验证失败,存在不合法的权限字,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("permCodeIdSet", permCodeIdSet); + } + return CallResult.ok(jsonObject); + } + + private String checkErrorOfNonDirectoryMenu(SysMenu sysMenu) { + // 判断父节点是否存在 + SysMenu parentSysMenu = getById(sysMenu.getParentId()); + if (parentSysMenu == null) { + return "数据验证失败,关联的上级菜单并不存在,请刷新后重试!"; + } + // 逐个判断每种类型的菜单,他的父菜单的合法性,先从目录类型和菜单类型开始 + if (sysMenu.getMenuType() == SysMenuType.TYPE_DIRECTORY + || sysMenu.getMenuType() == SysMenuType.TYPE_MENU) { + // 他们的上级只能是目录 + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) { + return "数据验证失败,当前类型菜单项的上级菜单只能是目录类型!"; + } + } else if (sysMenu.getMenuType() == SysMenuType.TYPE_UI_FRAGMENT) { + // ui fragment的上级只能是menu类型 + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU) { + return "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和按钮类型!"; + } + } else if (sysMenu.getMenuType() == SysMenuType.TYPE_BUTTON) { + // button的上级只能是menu和ui fragment + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU + && parentSysMenu.getMenuType() != SysMenuType.TYPE_UI_FRAGMENT) { + return "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和UI片段类型!"; + } + } + return null; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermCodeService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermCodeService.java new file mode 100644 index 00000000..44a0644b --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermCodeService.java @@ -0,0 +1,204 @@ +package com.orange.demo.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.upms.dao.SysMenuPermCodeMapper; +import com.orange.demo.upms.dao.SysPermCodeMapper; +import com.orange.demo.upms.dao.SysPermCodePermMapper; +import com.orange.demo.upms.model.SysMenuPermCode; +import com.orange.demo.upms.model.SysPermCode; +import com.orange.demo.upms.model.SysPermCodePerm; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 权限字数据服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysPermCodeService extends BaseService { + + @Autowired + private SysPermCodeMapper sysPermCodeMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private SysMenuPermCodeMapper sysMenuPermCodeMapper; + @Autowired + private SysPermService sysPermService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermCodeMapper; + } + + /** + * 获取指定用户的权限字列表。 + * + * @param userId 用户主键Id。 + * @return 用户关联的权限字列表。 + */ + public List getPermCodeListByUserId(Long userId) { + return sysPermCodeMapper.getPermCodeListByUserId(userId); + } + + /** + * 保存新增的权限字对象。 + * + * @param sysPermCode 新增的权限字对象。 + * @param permIdSet 权限资源Id列表。 + * @return 新增后的权限字对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysPermCode saveNew(SysPermCode sysPermCode, Set permIdSet) { + sysPermCode.setPermCodeId(idGenerator.nextLongId()); + sysPermCode.setCreateTime(new Date()); + sysPermCode.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysPermCodeMapper.insert(sysPermCode); + if (permIdSet != null) { + List sysPermCodePermList = new LinkedList<>(); + for (Long permId : permIdSet) { + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(sysPermCode.getPermCodeId()); + permCodePerm.setPermId(permId); + sysPermCodePermList.add(permCodePerm); + } + sysPermCodePermMapper.insertList(sysPermCodePermList); + } + return sysPermCode; + } + + /** + * 更新权限字对象。 + * + * @param sysPermCode 更新的权限字对象。 + * @param originalSysPermCode 原有的权限字对象。 + * @param permIdSet 权限资源Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysPermCode sysPermCode, SysPermCode originalSysPermCode, Set permIdSet) { + sysPermCode.setCreateTime(originalSysPermCode.getCreateTime()); + sysPermCode.setParentId(originalSysPermCode.getParentId()); + sysPermCode.setDeletedFlag(GlobalDeletedFlag.NORMAL); + if (sysPermCodeMapper.updateByPrimaryKey(sysPermCode) != 1) { + return false; + } + SysPermCodePerm deletedPermCodePerm = new SysPermCodePerm(); + deletedPermCodePerm.setPermCodeId(sysPermCode.getPermCodeId()); + sysPermCodePermMapper.delete(deletedPermCodePerm); + if (permIdSet != null) { + List sysPermCodePermList = new LinkedList<>(); + for (Long permId : permIdSet) { + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(sysPermCode.getPermCodeId()); + permCodePerm.setPermId(permId); + sysPermCodePermList.add(permCodePerm); + } + sysPermCodePermMapper.insertList(sysPermCodePermList); + } + return true; + } + + /** + * 删除指定的权限字。 + * + * @param permCodeId 权限字主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long permCodeId) { + SysPermCode permCode = new SysPermCode(); + permCode.setPermCodeId(permCodeId); + permCode.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysPermCodeMapper.updateByPrimaryKeySelective(permCode) != 1) { + return false; + } + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setPermCodeId(permCodeId); + sysMenuPermCodeMapper.delete(menuPermCode); + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(permCodeId); + sysPermCodePermMapper.delete(permCodePerm); + return true; + } + + /** + * 获取指定用户的权限字列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param permCode 模糊匹配的权限字名,LIKE %permCode%。 + * @return 权限字列表。 + */ + public List getUserPermCodeListByFilter(String loginName, String permCode) { + return sysPermCodeMapper.getUserPermCodeListByFilter(loginName, permCode); + } + + /** + * 获取该菜单的权限字,及其权限字关联的权限资源列表。 + * + * @param menuId 菜单Id。 + * @return 关联了权限资源的权限字列表。 + */ + public List> getPermCodeListByMenuId(Long menuId) { + return sysPermCodeMapper.getPermCodeListByMenuId(menuId); + } + + /** + * 判断当前权限字是否存在下级权限字对象。 + * + * @param permCodeId 权限字主键Id。 + * @return 存在返回true,否则false。 + */ + public boolean hasChildren(Long permCodeId) { + SysPermCode permCode = new SysPermCode(); + permCode.setParentId(permCodeId); + return this.getCountByFilter(permCode) > 0; + } + + /** + * 验证权限字对象关联的数据是否都合法。 + * + * @param sysPermCode 当前操作的对象。 + * @param originalSysPermCode 原有对象。 + * @param permIdListString 逗号分隔的权限资源Id列表。 + * @return 验证结果。 + */ + public CallResult verifyRelatedData( + SysPermCode sysPermCode, SysPermCode originalSysPermCode, String permIdListString) { + if (this.needToVerify(sysPermCode, originalSysPermCode, SysPermCode::getParentId)) { + if (getById(sysPermCode.getParentId()) == null) { + return CallResult.error("数据验证失败,关联的上级权限字并不存在,请刷新后重试!"); + } + } + JSONObject jsonObject = null; + if (StringUtils.isNotBlank(permIdListString)) { + Set permIdSet = Arrays.stream( + permIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPermService.existAllPrimaryKeys(permIdSet)) { + return CallResult.error("数据验证失败,存在不合法的权限资源,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("permIdSet", permIdSet); + } + return CallResult.ok(jsonObject); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermModuleService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermModuleService.java new file mode 100644 index 00000000..bb33e45f --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermModuleService.java @@ -0,0 +1,118 @@ +package com.orange.demo.upms.service; + +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.upms.dao.SysPermModuleMapper; +import com.orange.demo.upms.model.SysPerm; +import com.orange.demo.upms.model.SysPermModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +/** + * 权限资源模块数据服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysPermModuleService extends BaseService { + + @Autowired + private SysPermModuleMapper sysPermModuleMapper; + @Autowired + private SysPermService sysPermService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermModuleMapper; + } + + /** + * 保存新增的权限资源模块对象。 + * + * @param sysPermModule 新增的权限资源模块对象。 + * @return 新增后的权限资源模块对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysPermModule saveNew(SysPermModule sysPermModule) { + sysPermModule.setModuleId(idGenerator.nextLongId()); + sysPermModule.setCreateTime(new Date()); + sysPermModule.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysPermModuleMapper.insert(sysPermModule); + return sysPermModule; + } + + /** + * 更新权限资源模块对象。 + * + * @param sysPermModule 更新的权限资源模块对象。 + * @param originalSysPermModule 原有的权限资源模块对象。 + * @return 更新成功返回true,否则false + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysPermModule sysPermModule, SysPermModule originalSysPermModule) { + sysPermModule.setCreateTime(originalSysPermModule.getCreateTime()); + sysPermModule.setDeletedFlag(GlobalDeletedFlag.NORMAL); + return sysPermModuleMapper.updateByPrimaryKey(sysPermModule) != 0; + } + + /** + * 删除指定的权限资源模块。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long moduleId) { + SysPermModule permModule = new SysPermModule(); + permModule.setModuleId(moduleId); + permModule.setDeletedFlag(GlobalDeletedFlag.DELETED); + return sysPermModuleMapper.updateByPrimaryKeySelective(permModule) != 0; + } + + /** + * 获取权限模块资源及其关联的权限资源列表。 + * + * @return 权限资源模块及其关联的权限资源列表。 + */ + public List getPermModuleAndPermList() { + return sysPermModuleMapper.getPermModuleAndPermList(); + } + + /** + * 判断是否存在下级权限资源模块。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 存在返回true,否则false。 + */ + public boolean hasChildren(Long moduleId) { + SysPermModule permModule = new SysPermModule(); + permModule.setParentId(moduleId); + return this.getCountByFilter(permModule) > 0; + } + + /** + * 判断是否存在权限数据。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 存在返回true,否则false。 + */ + public boolean hasModulePerms(Long moduleId) { + SysPerm filter = new SysPerm(); + filter.setModuleId(moduleId); + return sysPermService.getCountByFilter(filter) > 0; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermService.java new file mode 100644 index 00000000..7f0917a0 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermService.java @@ -0,0 +1,257 @@ +package com.orange.demo.upms.service; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.upms.dao.SysPermCodePermMapper; +import com.orange.demo.upms.dao.SysPermMapper; +import com.orange.demo.upms.model.SysPerm; +import com.orange.demo.upms.model.SysPermCodePerm; +import com.orange.demo.upms.model.SysPermModule; +import com.orange.demo.upms.model.SysUser; +import com.orange.demo.upms.model.constant.SysUserType; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tk.mybatis.mapper.entity.Example; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 权限资源数据服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysPermService extends BaseService { + + @Autowired + private SysPermMapper sysPermMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private SysPermModuleService sysPermModuleService; + @Autowired + private SysUserService sysUserService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermMapper; + } + + /** + * 保存新增的权限资源对象。 + * + * @param perm 新增的权限资源对象。 + * @return 新增后的权限资源对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysPerm saveNew(SysPerm perm) { + perm.setPermId(idGenerator.nextLongId()); + perm.setCreateTime(new Date()); + perm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysPermMapper.insert(perm); + return perm; + } + + /** + * 更新权限资源对象。 + * + * @param perm 更新的权限资源对象。 + * @param originalPerm 原有的权限资源对象。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysPerm perm, SysPerm originalPerm) { + perm.setCreateTime(originalPerm.getCreateTime()); + perm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + return sysPermMapper.updateByPrimaryKeySelective(perm) != 0; + } + + /** + * 删除权限资源。 + * + * @param permId 权限资源主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long permId) { + SysPerm perm = new SysPerm(); + perm.setPermId(permId); + perm.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysPermMapper.updateByPrimaryKeySelective(perm) != 1) { + return false; + } + Example e = new Example(SysPermCodePerm.class); + e.createCriteria().andEqualTo("permId", permId); + sysPermCodePermMapper.deleteByExample(e); + return true; + } + + /** + * 获取权限数据列表。 + * + * @param sysPermFilter 过滤对象。 + * @return 权限列表。 + */ + public List getPermListWithRelation(SysPerm sysPermFilter) { + Example e = new Example(SysPerm.class); + e.orderBy("showOrder"); + Example.Criteria c = e.createCriteria(); + if (ObjectUtil.isNotNull(sysPermFilter.getModuleId())) { + c.andEqualTo("moduleId", sysPermFilter.getModuleId()); + } + if (ObjectUtil.isNotNull(sysPermFilter.getUrl())) { + c.andLike("url", "%" + sysPermFilter.getUrl() + "%"); + } + c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + List permList = sysPermMapper.selectByExample(e); + // 这里因为权限只有字典数据,所以仅仅做字典关联。 + this.buildRelationForDataList(permList, MyRelationParam.dictOnly(), null); + return permList; + } + + /** + * 获取指定用户的权限资源集合,并存储于缓存,从而提升后续读取效率。 + * + * @param sessionId 用户会话Id。 + * @param userId 用户主键Id。 + * @return 当前用户权限集合。 + */ + @Cacheable(value = "USER_PERMISSION_CACHE", key = "#sessionId", unless = "#result == null") + public Set getCacheableSysPermSetByUserId(String sessionId, Long userId) { + // 这里可以防止非法的userId直接访问权限受限的url + SysUser user = sysUserService.getById(userId); + if (user == null) { + return new HashSet<>(1); + } + // 管理员账户返回空对象,便于缓存的统一处理。 + return user.getUserType() == SysUserType.TYPE_ADMIN + ? new HashSet<>(1) : this.getSysPermSetByUserId(userId); + } + + /** + * 将指定用户的指定会话的权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @param isAdmin 是否是管理员。 + * @return 查询并缓存后的权限集合。 + */ + @CachePut(value = "USER_PERMISSION_CACHE", key = "#sessionId") + public Set putUserSysPermCache(String sessionId, Long userId, boolean isAdmin) { + // 管理员账户返回空对象,便于缓存的统一处理。 + return isAdmin ? new HashSet<>(1) : this.getSysPermSetByUserId(userId); + } + + /** + * 将指定会话的权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + @CacheEvict(value = "USER_PERMISSION_CACHE", key = "#sessionId") + public void removeUserSysPermCache(String sessionId) { + // 空实现即可,只是通过注解将当前sessionId从cache中删除。 + } + + /** + * 获取指定用户的权限集合,这里之所以为公有方法,因为spring cache的技术要求,私有方法数据不能缓存。 + * + * @param userId 用户主键Id。 + * @return 用户权限集合。 + */ + public Set getSysPermSetByUserId(Long userId) { + List permList = this.getPermListByUserId(userId); + return permList.stream().map(SysPerm::getUrl).collect(Collectors.toSet()); + } + + /** + * 获取与指定权限字关联的权限资源列表。 + * + * @param permCodeId 关联的权限字主键Id。 + * @param orderBy 排序参数。 + * @return 与指定权限字Id关联的权限资源列表。 + */ + public List getPermListByPermCodeId(Long permCodeId, String orderBy) { + return sysPermMapper.getPermListByPermCodeId(permCodeId, orderBy); + } + + /** + * 获取与指定用户关联的权限资源列表。 + * + * @param userId 关联的用户主键Id。 + * @return 与指定用户Id关联的权限资源列表。 + */ + public List getPermListByUserId(Long userId) { + return sysPermMapper.getPermListByUserId(userId); + } + + /** + * 获取指定用户的用户权限关联列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param moduleId 精确匹配权限模块Id。 + * @param url 模糊匹配的url过滤条件。 + * @return 用户权限关联列表。 + */ + public List> getUserPermListByFilter(String loginName, Long moduleId, String url) { + return sysPermMapper.getUserPermListByFilter(loginName, moduleId, url); + } + + /** + * 获取指定权限资源的权限用户关联数据列表。 + * + * @param permId 权限资源主键Id。 + * @return 用户和权限资源关联列表。 + */ + public List> getPermUserListById(Long permId) { + return sysPermMapper.getPermUserListById(permId); + } + + /** + * 获取指定权限资源的权限角色关联数据列表。 + * + * @param permId 权限资源主键Id。 + * @return 角色和权限资源关联列表。 + */ + public List> getPermRoleListById(Long permId) { + return sysPermMapper.getPermRoleListById(permId); + } + + /** + * 验证权限资源对象关联的数据是否都合法。 + * + * @param sysPerm 当前操作的对象。 + * @param originalSysPerm 原有对象。 + * @return 验证结果。 + */ + public CallResult verifyRelatedData(SysPerm sysPerm, SysPerm originalSysPerm) { + JSONObject jsonObject = null; + if (this.needToVerify(sysPerm, originalSysPerm, SysPerm::getModuleId)) { + SysPermModule permModule = sysPermModuleService.getById(sysPerm.getModuleId()); + if (permModule == null) { + return CallResult.error("数据验证失败,关联的权限模块Id并不存在,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("permModule", permModule); + } + return CallResult.ok(jsonObject); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermWhitelistService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermWhitelistService.java new file mode 100644 index 00000000..6e268f5b --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysPermWhitelistService.java @@ -0,0 +1,32 @@ +package com.orange.demo.upms.service; + +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.upms.dao.SysPermWhitelistMapper; +import com.orange.demo.upms.model.SysPermWhitelist; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 权限资源白名单数据服务类。 + * 白名单中的权限资源,可以不受权限控制,任何用户皆可访问,一般用于常用的字典数据列表接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysPermWhitelistService extends BaseService { + + @Autowired + private SysPermWhitelistMapper sysPermWhitelistMapper; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermWhitelistMapper; + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysRoleService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysRoleService.java new file mode 100644 index 00000000..310873f9 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysRoleService.java @@ -0,0 +1,221 @@ +package com.orange.demo.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.upms.dao.SysRoleMapper; +import com.orange.demo.upms.dao.SysRoleMenuMapper; +import com.orange.demo.upms.dao.SysUserRoleMapper; +import com.orange.demo.upms.model.SysRole; +import com.orange.demo.upms.model.SysRoleMenu; +import com.orange.demo.upms.model.SysUserRole; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 角色数据服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysRoleService extends BaseService { + + @Autowired + private SysRoleMapper sysRoleMapper; + @Autowired + private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + @Autowired + private SysMenuService sysMenuService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysRoleMapper; + } + + /** + * 保存新增的角色对象。 + * + * @param role 新增的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 新增后的角色对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysRole saveNew(SysRole role, Set menuIdSet) { + role.setRoleId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + role.setCreateUserId(tokenData.getUserId()); + role.setCreateUsername(tokenData.getShowName()); + Date now = new Date(); + role.setCreateTime(now); + role.setUpdateTime(now); + role.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysRoleMapper.insert(role); + if (menuIdSet != null) { + List roleMenuList = new LinkedList<>(); + for (Long menuId : menuIdSet) { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(role.getRoleId()); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + sysRoleMenuMapper.insertList(roleMenuList); + } + return role; + } + + /** + * 更新角色对象。 + * + * @param role 更新的角色对象。 + * @param originalRole 原有的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysRole role, SysRole originalRole, Set menuIdSet) { + SysRole updateRole = new SysRole(); + BeanUtils.copyProperties(role, updateRole, "createUserId", "createUsername", "createTime"); + updateRole.setUpdateTime(new Date()); + updateRole.setDeletedFlag(GlobalDeletedFlag.NORMAL); + if (sysRoleMapper.updateByPrimaryKeySelective(updateRole) != 1) { + return false; + } + SysRoleMenu deletedRoleMenu = new SysRoleMenu(); + deletedRoleMenu.setRoleId(role.getRoleId()); + sysRoleMenuMapper.delete(deletedRoleMenu); + if (menuIdSet != null) { + List roleMenuList = new LinkedList<>(); + for (Long menuId : menuIdSet) { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(role.getRoleId()); + roleMenu.setMenuId(menuId); + roleMenuList.add(roleMenu); + } + sysRoleMenuMapper.insertList(roleMenuList); + } + return true; + } + + /** + * 删除指定角色。 + * + * @param roleId 角色主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long roleId) { + SysRole role = new SysRole(); + role.setRoleId(roleId); + role.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysRoleMapper.updateByPrimaryKeySelective(role) != 1) { + return false; + } + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(roleId); + sysRoleMenuMapper.delete(roleMenu); + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + sysUserRoleMapper.delete(userRole); + return true; + } + + /** + * 获取角色列表。 + * + * @param filter 角色过滤对象。 + * @param orderBy 排序参数。 + * @return 角色列表。 + */ + public List getSysRoleList(SysRole filter, String orderBy) { + return sysRoleMapper.getSysRoleList(filter, orderBy); + } + + /** + * 通过权限字Id获取拥有改权限的所有角色。 + * 开发人员调试用接口。 + * + * @param permCodeId 查询的权限字Id。 + * @return 符合条件的角色列表。 + */ + public List getSysRoleListByPermCodeId(Long permCodeId) { + return sysRoleMapper.getSysRoleListByPermCodeId(permCodeId); + } + + /** + * 通过权限资源url,模糊搜索拥有改权限的所有角色。 + * 开发人员调试用接口。 + * + * @param url 用于模糊搜索的url。 + * @return 符合条件的角色列表。 + */ + public List getSysRoleListByPerm(String url) { + return sysRoleMapper.getSysRoleListByPerm(url); + } + + /** + * 批量新增用户角色关联。 + * + * @param userRoleList 用户角色关系数据列表。 + */ + @Transactional(rollbackFor = Exception.class) + public void addUserRoleList(List userRoleList) { + sysUserRoleMapper.addUserRoleList(userRoleList); + } + + /** + * 移除指定用户和指定角色的关联关系。 + * + * @param roleId 角色主键Id。 + * @param userId 用户主键Id。 + * @return 移除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean removeUserRole(Long roleId, Long userId) { + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + return sysUserRoleMapper.delete(userRole) == 1; + } + + /** + * 验证角色对象关联的数据是否都合法。 + * + * @param sysRole 当前操作的对象。 + * @param originalSysRole 原有对象。 + * @param menuIdListString 逗号分隔的menuId列表。 + * @return 验证结果。 + */ + public CallResult verifyRelatedData(SysRole sysRole, SysRole originalSysRole, String menuIdListString) { + JSONObject jsonObject = null; + if (StringUtils.isNotBlank(menuIdListString)) { + Set menuIdSet = Arrays.stream( + menuIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysMenuService.existAllPrimaryKeys(menuIdSet)) { + return CallResult.error("数据验证失败,存在不合法的菜单权限,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("menuIdSet", menuIdSet); + } + return CallResult.ok(jsonObject); + } +} diff --git a/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysUserService.java b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysUserService.java new file mode 100644 index 00000000..ad77b598 --- /dev/null +++ b/orange-demo-single-service/application/src/main/java/com/orange/demo/upms/service/SysUserService.java @@ -0,0 +1,252 @@ +package com.orange.demo.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.upms.dao.*; +import com.orange.demo.upms.model.*; +import com.orange.demo.upms.model.constant.SysUserStatus; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.object.TokenData; +import com.orange.demo.common.core.object.MyWhereCriteria; +import com.orange.demo.common.core.object.MyRelationParam; +import com.orange.demo.common.core.object.CallResult; +import com.orange.demo.common.core.base.service.BaseService; +import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import tk.mybatis.mapper.entity.Example; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 用户管理数据操作服务类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Service +public class SysUserService extends BaseService { + + @Autowired + private SysUserMapper sysUserMapper; + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + @Autowired + private SysRoleService sysRoleService; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private PasswordEncoder passwordEncoder; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysUserMapper; + } + + /** + * 获取指定登录名的用户对象。 + * + * @param loginName 指定登录用户名。 + * @return 用户对象。 + */ + public SysUser getSysUserByLoginName(String loginName) { + Example e = new Example(SysUser.class); + Example.Criteria c = e.createCriteria(); + c.andEqualTo("loginName", loginName); + c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + return sysUserMapper.selectOneByExample(e); + } + + /** + * 保存新增的用户对象。 + * + * @param user 新增的用户对象。 + * @param roleIdSet 用户角色Id集合。 + * @return 新增后的用户对象。 + */ + @Transactional(rollbackFor = Exception.class) + public SysUser saveNew(SysUser user, Set roleIdSet) { + user.setUserId(idGenerator.nextLongId()); + user.setPassword(passwordEncoder.encode(user.getPassword())); + user.setUserStatus(SysUserStatus.STATUS_NORMAL); + user.setDeletedFlag(GlobalDeletedFlag.NORMAL); + TokenData tokenData = TokenData.takeFromRequest(); + user.setCreateUserId(tokenData.getUserId()); + user.setCreateUsername(tokenData.getShowName()); + Date now = new Date(); + user.setCreateTime(now); + user.setUpdateTime(now); + sysUserMapper.insert(user); + if (CollectionUtils.isNotEmpty(roleIdSet)) { + List userRoleList = new LinkedList<>(); + for (Long roleId : roleIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(user.getUserId()); + userRole.setRoleId(roleId); + userRoleList.add(userRole); + } + sysUserRoleMapper.insertList(userRoleList); + } + return user; + } + + /** + * 更新用户对象。 + * + * @param user 更新的用户对象。 + * @param originalUser 原有的用户对象。 + * @param roleIdSet 用户角色Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean update(SysUser user, SysUser originalUser, Set roleIdSet) { + user.setLoginName(originalUser.getLoginName()); + user.setPassword(originalUser.getPassword()); + user.setCreateUserId(originalUser.getCreateUserId()); + user.setCreateUsername(originalUser.getCreateUsername()); + user.setCreateTime(originalUser.getCreateTime()); + user.setUpdateTime(new Date()); + if (sysUserMapper.updateByPrimaryKeySelective(user) != 1) { + return false; + } + // 先删除原有的User-Role关联关系,再重新插入新的关联关系 + SysUserRole deletedUserRole = new SysUserRole(); + deletedUserRole.setUserId(user.getUserId()); + sysUserRoleMapper.delete(deletedUserRole); + if (CollectionUtils.isNotEmpty(roleIdSet)) { + List userRoleList = new LinkedList<>(); + for (Long roleId : roleIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(user.getUserId()); + userRole.setRoleId(roleId); + userRoleList.add(userRole); + } + sysUserRoleMapper.insertList(userRoleList); + } + return true; + } + + /** + * 修改用户密码。 + * @param userId 用户主键Id。 + * @param newPass 新密码。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean changePassword(Long userId, String newPass) { + Example e = new Example(SysUser.class); + e.createCriteria().andEqualTo(super.idFieldName, userId); + e.createCriteria().andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + SysUser updatedUser = new SysUser(); + updatedUser.setPassword(passwordEncoder.encode(newPass)); + return sysUserMapper.updateByExampleSelective(updatedUser, e) == 1; + } + + /** + * 删除指定数据。 + * + * @param userId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + public boolean remove(Long userId) { + Example sysUserExample = new Example(SysUser.class); + Example.Criteria c = sysUserExample.createCriteria(); + c.andEqualTo(super.idFieldName, userId); + c.andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + // 这里先删除主数据 + SysUser deletedObject = new SysUser(); + deletedObject.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysUserMapper.updateByExampleSelective(deletedObject, sysUserExample) == 0) { + return false; + } + // 这里可继续删除关联数据。 + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(userId); + sysUserRoleMapper.delete(userRole); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysUserListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSysUserList(SysUser filter, String orderBy) { + return sysUserMapper.getSysUserList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getSysUserList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSysUserListWithRelation(SysUser filter, String orderBy) { + List resultList = sysUserMapper.getSysUserList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap); + return resultList; + } + + /** + * 获取指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + public List getSysUserListByRoleId(Long roleId, SysUser filter, String orderBy) { + return sysUserMapper.getSysUserListByRoleId(roleId, filter, orderBy); + } + + /** + * 获取不属于指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + public List getNotInSysUserListByRoleId(Long roleId, SysUser filter, String orderBy) { + return sysUserMapper.getNotInSysUserListByRoleId(roleId, filter, orderBy); + } + + /** + * 验证用户对象关联的数据是否都合法。 + * + * @param sysUser 当前操作的对象。 + * @param originalSysUser 原有对象。 + * @param roleIdListString 逗号分隔的角色Id列表字符串。 + * @return 验证结果。 + */ + public CallResult verifyRelatedData(SysUser sysUser, SysUser originalSysUser, String roleIdListString) { + JSONObject jsonObject = new JSONObject(); + if (StringUtils.isBlank(roleIdListString)) { + return CallResult.error("数据验证失败,用户的角色数据不能为空!"); + } + Set roleIdSet = Arrays.stream( + roleIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysRoleService.existAllPrimaryKeys(roleIdSet)) { + return CallResult.error("数据验证失败,存在不合法的用户角色,请刷新后重试!"); + } + jsonObject.put("roleIdSet", roleIdSet); + return CallResult.ok(jsonObject); + } +} diff --git a/orange-demo-single-service/application/src/main/resources/application.yml b/orange-demo-single-service/application/src/main/resources/application.yml new file mode 100644 index 00000000..10a3ec07 --- /dev/null +++ b/orange-demo-single-service/application/src/main/resources/application.yml @@ -0,0 +1,193 @@ +logging: + level: + # 这里设置的日志级别优先于log4j2.xml文件Loggers中的日志级别。 + com.orange.demo: info + +server: + tomcat: + uri-encoding: UTF-8 + max-threads: 100 + min-spare-threads: 10 + port: 8082 + +# spring相关配置 +spring: + application: + name: application + profiles: + active: dev + servlet: + multipart: + max-file-size: 50MB + max-request-size: 50MB + http: + converters: + preferred-json-mapper: fastjson + encoding: + force: true + charset: UTF-8 + enabled: true + freemarker: + template-loader-path: classpath:/template/ + cache: false + charset: UTF-8 + check-template-location: true + content-type: text/html + expose-request-attributes: false + expose-session-attributes: false + request-context-attribute: request + suffix: .ftl + +# mybatis的基本配置 +mybatis: + mapperLocations: classpath:com/orange/demo/*/dao/mapper/*Mapper.xml + typeAliasesPackage: com.orange.demo.*.model + +# mybatis的通用mapper的配置 +mapper: + mappers: tk.mybatis.mapper.common.Mapper,tk.mybatis.mapper.additional.insert.InsertListMapper + not-empty: false + identity: MYSQL + +# 自动分页的配置 +pagehelper: + helperDialect: mysql + reasonable: true + supportMethodsArguments: false + params: count=countSql + +# 暴露监控端点 +management: + endpoints: + web: + exposure: + include: '*' + jmx: + exposure: + include: '*' + endpoint: + # 与中间件相关的健康详情也会被展示 + health: + show-details: always + configprops: + # 在/actuator/configprops中,所有包含password的配置,将用 * 隐藏。 + # 如果不想隐藏任何配置项的值,可以直接使用如下被注释的空值。 + # keys-to-sanitize: + keys-to-sanitize: password + server: + servlet: + context-path: "/" + +# 开发数据库相关配置 +--- +spring: + profiles: dev + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + url: jdbc:mysql://localhost:3306/zzdemo-single?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + name: application + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # Jwt令牌加密的签名值。 + tokenSigningKey: OrangeSingleDemo + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/app + # 跨域的IP白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + +sequence: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 + +# 发布数据库相关配置 +--- +spring: + profiles: product + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + url: jdbc:mysql://localhost:3306/zzdemo-single?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + name: application + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # Jwt令牌加密的签名值。 + tokenSigningKey: OrangeSingleDemo + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/app + # 跨域的IP白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + +sequence: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 \ No newline at end of file diff --git a/orange-demo-single-service/application/src/main/resources/log4j2.xml b/orange-demo-single-service/application/src/main/resources/log4j2.xml new file mode 100644 index 00000000..1a4ca1f3 --- /dev/null +++ b/orange-demo-single-service/application/src/main/resources/log4j2.xml @@ -0,0 +1,70 @@ + + + + + + + + + + ./zzlogs + + ./zzlogs/backup + + info + + + + + + + + [%-5p] [%d{YYYY-MM-dd HH:mm:ss}] [%t] ==> %msg%n + + + [%-5p] [%d{YYYY-MM-dd HH:mm:ss}] 请求Id[%X{traceId}] [%t] ==> %msg%n + + + 31 + + 20M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-single-service/application/src/main/resources/template/views/print_error.ftl b/orange-demo-single-service/application/src/main/resources/template/views/print_error.ftl new file mode 100644 index 00000000..af8b36a7 --- /dev/null +++ b/orange-demo-single-service/application/src/main/resources/template/views/print_error.ftl @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
天津公安警官职业学院2017—2018学年度第一学期课程表
班 级星期一星期二星期三星期四星期五
第1节第2节第3节第1节第2节第3节第1节第2节第3节第1节第2节第3节第1节第2节
16 级 刑 事 技 术 班 课程刑法自习刑事图像民 法(选修)派出所工作刑事图像法医学派出所工作法医学国内安全保卫体能自习刑事技术总论刑法
自习自习自习
教师曾岚陈磊邵刚杨丽伟陈磊于辉杨丽伟于辉朱学强张付海王 伟(刑技)曾岚
   
教室206206206206206206206206206操场206206
   
16 级 刑 事 侦 查 课程自习侦查措施经济案件侦查公安信息化公安信息化刑法体能自习痕迹检验刑法国内安全保卫经济案件侦查痕迹检验民 法(选修)
侦查措施
教师徐宏涛张静赵晓松赵晓松王骏强张付海郭海川王骏强朱学强张静郭海川邵刚
徐宏涛
教室2022023号机房3号机房202操场202202202202202202
16 级 治 安 管 理 班 课程刑事技术体能刑事技术治安秩序管理刑事侦查概论刑法群众工作与纠纷调解群众工作与纠纷调解公共关系(选修)刑事侦查概论刑法自习自习自习
q
教师郭海川 韩易浦张付海郭海川 韩易浦翟政亮邵妍薛强刘晓鹏刘晓鹏尚欣邵妍薛强
翟政亮
教室218操场218218218218218218218218218
16 网 络 安 全 监 察 1 班课程应用写作数据库系统应用周二中午:计算机安全管理及实用技术刑事诉讼法周一中午:数据库系统应用民法体育VB语言程序设计选修VB语言程序设计刑事诉讼法选修应用写作犯罪心理
民法犯罪心理
教师关利杨斌赵晓松王伟杨斌李静程军赵伟赵伟王伟关利张学林
李静张学林
教室东阶梯2号机房主楼2011012号机房101操场3号机房3号机房101东阶梯主楼201
主楼201
注:1、课程一栏中有两科次的,上面的课程单周上课,下面的课程双周上课。2、每天上课时间:上午第1节8:30至9:55;第2节10:15至11:40;中午上课时间12:30至13:55;下午第3节14:00至15:25。
+ + diff --git a/orange-demo-single-service/common/common-core/pom.xml b/orange-demo-single-service/common/common-core/pom.xml new file mode 100644 index 00000000..a2dd2491 --- /dev/null +++ b/orange-demo-single-service/common/common-core/pom.xml @@ -0,0 +1,110 @@ + + + + com.orange.demo + common + 1.0.0 + + 4.0.0 + + common-core + 1.0.0 + common-core + jar + + + + + com.google.guava + guava + + + org.apache.commons + commons-lang3 + + + commons-codec + commons-codec + + + commons-io + commons-io + + + commons-fileupload + commons-fileupload + + + org.apache.httpcomponents + httpclient + + + joda-time + joda-time + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + org.apache.commons + commons-csv + ${common-csv.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + cn.jimmyshi + bean-query + ${bean.query.version} + + + + org.apache.poi + poi-ooxml + ${poi-ooxml.version} + + + + + mysql + mysql-connector-java + runtime + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + tk.mybatis + mapper-spring-boot-starter + ${mybatis-mapper.version} + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.version} + + + diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java new file mode 100644 index 00000000..7a4196d0 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyControllerAdvice.java @@ -0,0 +1,30 @@ +package com.orange.demo.common.core.advice; + +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.InitBinder; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Controller的环绕拦截类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@ControllerAdvice +public class MyControllerAdvice { + + /** + * 转换前端传入的日期变量参数为指定格式。 + * + * @param binder 数据绑定参数。 + */ + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(Date.class, + new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), false)); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java new file mode 100644 index 00000000..5d91dc2e --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/advice/MyExceptionHandler.java @@ -0,0 +1,128 @@ +package com.orange.demo.common.core.advice; + +import com.orange.demo.common.core.exception.InvalidClassFieldException; +import com.orange.demo.common.core.exception.InvalidDataFieldException; +import com.orange.demo.common.core.exception.InvalidDataModelException; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.exception.RedisCacheAccessException; +import com.orange.demo.common.core.object.ResponseResult; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.exceptions.PersistenceException; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.dao.PermissionDeniedDataAccessException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; +import java.util.concurrent.TimeoutException; + +/** + * 业务层的异常处理类,这里只是给出最通用的Exception的捕捉,今后可以根据业务需要, + * 用不同的函数,处理不同类型的异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@RestControllerAdvice("com.orange.demo") +public class MyExceptionHandler { + + /** + * 通用异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = Exception.class) + public ResponseResult exceptionHandle(Exception ex, HttpServletRequest request) { + log.error("Unhandled exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.UNHANDLED_EXCEPTION); + } + + /** + * 无效的实体对象异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidDataModelException.class) + public ResponseResult invalidDataModelExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidDataModelException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_MODEL); + } + + /** + * 无效的实体对象字段异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidDataFieldException.class) + public ResponseResult invalidDataFieldExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidDataFieldException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_FIELD); + } + + /** + * 无效类字段异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidClassFieldException.class) + public ResponseResult invalidClassFieldExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidClassFieldException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_CLASS_FIELD); + } + + /** + * 重复键异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = DuplicateKeyException.class) + public ResponseResult duplicateKeyExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("DuplicateKeyException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY); + } + + /** + * 数据访问失败异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = DataAccessException.class) + public ResponseResult dataAccessExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("DataAccessException exception from URL [" + request.getRequestURI() + "]", ex); + if (ex.getCause() instanceof PersistenceException + && ex.getCause().getCause() instanceof PermissionDeniedDataAccessException) { + return ResponseResult.error(ErrorCodeEnum.DATA_PERM_ACCESS_FAILED); + } + return ResponseResult.error(ErrorCodeEnum.DATA_ACCESS_FAILED); + } + + /** + * Redis缓存访问异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = RedisCacheAccessException.class) + public ResponseResult redisCacheAccessExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("RedisCacheAccessException exception from URL [" + request.getRequestURI() + "]", ex); + if (ex.getCause() instanceof TimeoutException) { + return ResponseResult.error(ErrorCodeEnum.REDIS_CACHE_ACCESS_TIMEOUT); + } + return ResponseResult.error(ErrorCodeEnum.REDIS_CACHE_ACCESS_STATE_ERROR); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java new file mode 100644 index 00000000..bdf7249d --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/DeletedFlagColumn.java @@ -0,0 +1,16 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记逻辑删除字段。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeletedFlagColumn { + +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java new file mode 100644 index 00000000..84da0a01 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/JobUpdateTimeColumn.java @@ -0,0 +1,16 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记更新字段。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface JobUpdateTimeColumn { + +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java new file mode 100644 index 00000000..2c898d48 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyDataSource.java @@ -0,0 +1,21 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记Service所依赖的数据源类型。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MyDataSource { + + /** + * 标注的数据源类型 + * @return 当前标注的数据源类型。 + */ + int value(); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java new file mode 100644 index 00000000..612e73e7 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/MyRequestBody.java @@ -0,0 +1,31 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标记Controller中的方法参数,参数解析器会根据该注解将请求中的JSON数据,映射到参数中的绑定字段。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface MyRequestBody { + + /** + * 是否必须出现的参数。 + */ + boolean required() default false; + /** + * 解析时用到的JSON的key。 + */ + String value() default ""; + /** + * 集合元素的ClassType。只有在接口参数为List的时候,需要把E的class传入。 + * 缺省值Class.class表示没有设置。 + */ + Class elementType() default Class.class; +} \ No newline at end of file diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java new file mode 100644 index 00000000..de33462a --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/NoAuthInterface.java @@ -0,0 +1,15 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记无需Token验证的接口 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface NoAuthInterface { +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java new file mode 100644 index 00000000..4615255d --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationConstDict.java @@ -0,0 +1,29 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model和常量字典之间的关联关系。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationConstDict { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的常量字典的Class对象。 + * + * @return 关联的常量字典的Class对象。 + */ + Class constantDictClass(); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java new file mode 100644 index 00000000..97722f81 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationDict.java @@ -0,0 +1,60 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model之间的字典关联关系。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationDict { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联Model对象的关联Name字段名称。 + * + * @return 被关联Model对象的关联Name字段名称。 + */ + String slaveNameField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 在同一个实体对象中,如果有一对一关联和字典关联,都是基于相同的主表字段,并关联到 + * 相同关联表的同一关联字段时,可以在字典关联的注解中引用被一对一注解标准的对象属性。 + * 从而在数据整合时,当前字典的数据可以直接取自"equalOneToOneRelationField"指定 + * 的字段,从而避免一次没必要的数据库查询操作,提升了加载显示的效率。 + * + * @return 与该字典字段引用关系完全相同的一对一关联属性名称。 + */ + String equalOneToOneRelationField() default ""; +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java new file mode 100644 index 00000000..c5cbed13 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToMany.java @@ -0,0 +1,36 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标注多对多的Model关系。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationManyToMany { + + /** + * 多对多中间表的Mapper对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String relationMapperName(); + + /** + * 多对多关联表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class relationModelClass(); + + /** + * 多对多关联表Model对象中与主表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationMasterIdField(); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java new file mode 100644 index 00000000..86ed12e4 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationManyToManyAggregation.java @@ -0,0 +1,85 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于多对多的Model关系。标注通过从表关联字段或者关联表关联字段计算主表聚合计算字段的规则。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationManyToManyAggregation { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 多对多从表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 多对多从表Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 多对多关联表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class relationModelClass(); + + /** + * 多对多关联表Model对象中与主表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationMasterIdField(); + + /** + * 多对多关联表Model对象中与从表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationSlaveIdField(); + + /** + * 聚合计算所在的Model。 + * + * @return 聚合计算所在Model的Class。 + */ + Class aggregationModelClass(); + + /** + * 聚合类型。具体数值参考AggregationType对象。 + * + * @return 聚合类型。 + */ + int aggregationType(); + + /** + * 聚合计算所在Model的字段名称。 + * + * @return 聚合计算所在Model的字段名称。 + */ + String aggregationField(); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java new file mode 100644 index 00000000..4e5db643 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToManyAggregation.java @@ -0,0 +1,57 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于一对多的Model关系。标注通过从表关联字段计算主表聚合计算字段的规则。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToManyAggregation { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联Model对象中参与计算的聚合类型。具体数值参考AggregationType对象。 + * + * @return 被关联Model对象中参与计算的聚合类型。 + */ + int aggregationType(); + + /** + * 被关联Model对象中参与聚合计算的字段名称。 + * + * @return 被关联Model对象中参与计算字段的名称。 + */ + String aggregationField(); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java new file mode 100644 index 00000000..a1c8957a --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/annotation/RelationOneToOne.java @@ -0,0 +1,50 @@ +package com.orange.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model之间的一对一关联关系。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToOne { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联的本地Service对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName(); + + /** + * 在一对一关联时,是否加载从表的字典关联。 + * + * @return 是否加载从表的字典关联。true关联,false则只返回从表自身数据。 + */ + boolean loadSlaveDict() default true; +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java new file mode 100644 index 00000000..8203b845 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/aop/AccessLogAspect.java @@ -0,0 +1,84 @@ +package com.orange.demo.common.core.aop; + +import com.alibaba.fastjson.JSON; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.util.MyCommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.MDC; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 记录接口的链路traceId、请求参数、应答数据、错误信息和调用时长。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class AccessLogAspect { + + /** + * 所有controller方法。 + */ + @Pointcut("execution(public * com.orange.demo..controller..*(..))") + public void controllerPointCut() { + // 空注释,避免sonar警告 + } + + @Around("controllerPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + HttpServletRequest request = + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + // 请求流水号 + String traceId = MyCommonUtil.generateUuid(); + HttpServletResponse response = + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse(); + response.setHeader(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + MDC.put(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + long start = System.currentTimeMillis(); + // 获取方法参数 + List httpReqArgs = new ArrayList<>(); + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Object[] args = joinPoint.getArgs(); + for (Object object : args) { + if (!(object instanceof HttpServletRequest) + && !(object instanceof HttpServletResponse) + && !(object instanceof MultipartFile)) { + httpReqArgs.add(object); + } + } + String url = request.getRequestURI(); + String params = JSON.toJSONString(httpReqArgs); + log.info("开始请求,traceId={}, url={}, reqData={}", traceId, url, params); + Object result = null; + try { + // 调用原来的方法 + result = joinPoint.proceed(); + } catch (Exception e) { + log.error("请求报错,traceId={}, url={}, reqData={}, error={}", traceId, url, params, e.getMessage()); + throw e; + } finally { + // 获取应答报文及接口处理耗时 + String respData = result == null ? null : JSON.toJSONString(result); + log.info("请求完成, traceId={}, url={},elapse={}ms, respData={}", + traceId, url, (System.currentTimeMillis() - start), respData); + } + return result; + } +} \ No newline at end of file diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java new file mode 100644 index 00000000..c91934c3 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/dao/BaseDaoMapper.java @@ -0,0 +1,90 @@ +package com.orange.demo.common.core.base.dao; + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import tk.mybatis.mapper.additional.insert.InsertListMapper; +import tk.mybatis.mapper.annotation.RegisterMapper; +import tk.mybatis.mapper.common.Mapper; + +import java.util.List; +import java.util.Map; + +/** + * 数据访问对象的基类。 + * + * @param 主Model实体对象。 + * @author Jerry + * @date 2020-09-25 + */ +@RegisterMapper +public interface BaseDaoMapper extends Mapper, InsertListMapper { + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和分组字段,返回聚合计算后的查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 返回字段列表,逗号分隔。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy 分组字段列表,逗号分隔。 + * @return 对象可选字段Map列表。 + */ + @Select("") + List> getGroupedListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("groupBy") String groupBy); + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和排序字符串,返回查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 选择的字段列表。 + * @param whereClause 过滤字符串。 + * @param orderBy 排序字符串。 + * @return 查询结果。 + */ + @Select("") + List> getListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("orderBy") String orderBy); + + /** + * 用指定过滤条件,计算记录数量。 + * + * @param selectTable 表名称。 + * @param whereClause 过滤字符串。 + * @return 返回过滤后的数据数量。 + */ + @Select("") + int getCountByCondition(@Param("selectTable") String selectTable, @Param("whereClause") String whereClause); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java new file mode 100644 index 00000000..1cbbe602 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/BaseModelMapper.java @@ -0,0 +1,124 @@ +package com.orange.demo.common.core.base.mapper; + +import cn.hutool.core.bean.BeanUtil; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Model对象到Domain类型对象的相互转换。实现类通常声明在Model实体类中。 + * + * @param Domain域对象类型。 + * @param Model实体对象类型。 + * @author Jerry + * @date 2020-09-25 + */ +public interface BaseModelMapper { + + /** + * 转换Model实体对象到Domain域对象。 + * + * @param model Model实体对象。 + * @return Domain域对象。 + */ + D fromModel(M model); + + /** + * 转换Model实体对象列表到Domain域对象列表。 + * + * @param modelList Model实体对象列表。 + * @return Domain域对象列表。 + */ + List fromModelList(List modelList); + + /** + * 转换Domain域对象到Model实体对象。 + * + * @param domain Domain域对象。 + * @return Model实体对象。 + */ + M toModel(D domain); + + /** + * 转换Domain域对象列表到Model实体对象列表。 + * + * @param domainList Domain域对象列表。 + * @return Model实体对象列表。 + */ + List toModelList(List domainList); + + /** + * 转换bean到map + * + * @param bean bean对象。 + * @param ignoreNullValue 值为null的字段是否转换到Map。 + * @param bean类型。 + * @return 转换后的map对象。 + */ + default Map beanToMap(T bean, boolean ignoreNullValue) { + return BeanUtil.beanToMap(bean, false, ignoreNullValue); + } + + /** + * 转换bean集合到map集合 + * + * @param dataList bean对象集合。 + * @param ignoreNullValue 值为null的字段是否转换到Map。 + * @param bean类型。 + * @return 转换后的map对象集合。 + */ + default List> beanToMap(List dataList, boolean ignoreNullValue) { + if (CollectionUtils.isEmpty(dataList)) { + return new LinkedList<>(); + } + return dataList.stream() + .map(o -> BeanUtil.beanToMap(o, false, ignoreNullValue)) + .collect(Collectors.toList()); + } + + /** + * 转换map到bean。 + * + * @param map map对象。 + * @param beanClazz bean的Class对象。 + * @param bean类型。 + * @return 转换后的bean对象。 + */ + default T mapToBean(Map map, Class beanClazz) { + return BeanUtil.mapToBean(map, beanClazz, true); + } + + /** + * 转换map集合到bean集合。 + * + * @param mapList map对象集合。 + * @param beanClazz bean的Class对象。 + * @param bean类型。 + * @return 转换后的bean对象集合。 + */ + default List mapToBean(List> mapList, Class beanClazz) { + if (CollectionUtils.isEmpty(mapList)) { + return new LinkedList<>(); + } + return mapList.stream() + .map(m -> BeanUtil.mapToBean(m, beanClazz, true)) + .collect(Collectors.toList()); + } + + /** + * 对于Map字段到Map字段的映射场景,MapStruct会根据方法签名自动选择该函数 + * 作为对象copy的函数。由于该函数是直接返回的,因此没有对象copy,效率更高。 + * 如果没有该函数,MapStruct会生成如下代码: + * Map map = courseDto.getTeacherIdDictMap(); + * if ( map != null ) { + * course.setTeacherIdDictMap( new HashMap( map ) ); + * } + * + * @param map map对象。 + * @return 直接返回的map。 + */ + default Map mapToMap(Map map) { + return map; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/DummyModelMapper.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/DummyModelMapper.java new file mode 100644 index 00000000..7228f446 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/mapper/DummyModelMapper.java @@ -0,0 +1,58 @@ +package com.orange.demo.common.core.base.mapper; + +import java.util.List; + +/** + * 哑元占位对象。Model实体对象和Domain域对象相同的场景下使用。 + * 由于没有实际的数据转换,因此同时保证了代码统一和执行效率。 + * + * @param 数据类型。 + * @author Jerry + * @date 2020-09-25 + */ +public class DummyModelMapper implements BaseModelMapper { + + /** + * 不转换直接返回。 + * + * @param model Model实体对象。 + * @return Domain域对象。 + */ + @Override + public M fromModel(M model) { + return model; + } + + /** + * 不转换直接返回。 + * + * @param modelList Model实体对象列表。 + * @return Domain域对象列表。 + */ + @Override + public List fromModelList(List modelList) { + return modelList; + } + + /** + * 不转换直接返回。 + * + * @param domain Domain域对象。 + * @return Model实体对象。 + */ + @Override + public M toModel(M domain) { + return domain; + } + + /** + * 不转换直接返回。 + * + * @param domainList Domain域对象列表。 + * @return Model实体对象列表。 + */ + @Override + public List toModelList(List domainList) { + return domainList; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseDictService.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseDictService.java new file mode 100644 index 00000000..f611dde0 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseDictService.java @@ -0,0 +1,149 @@ +package com.orange.demo.common.core.base.service; + +import com.orange.demo.common.core.cache.DictionaryCache; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import tk.mybatis.mapper.entity.Example; + +import java.util.Set; +import java.util.List; + +/** + * 带有缓存功能的字典Service基类,需要留意的是,由于缓存基于Key/Value方式存储, + * 目前仅支持基于主键字段的缓存查找,其他条件的查找仍然从数据源获取。 + * + * @param Model实体对象的类型。 + * @param Model对象主键的类型。 + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public abstract class BaseDictService extends BaseService { + + /** + * 缓存池对象。 + */ + protected DictionaryCache dictionaryCache; + + /** + * 构造函数使用缺省缓存池对象。 + */ + public BaseDictService() { + super(); + } + + /** + * 是否在服务启动的时候加载。子类可以重载该方法,并在需要的时候手工调用loadCachedData加载数据。 + * + * @return true表示启动即可加载数据,false需要手动调用loadCachedData进行加载。 + */ + public boolean loadOnStartup() { + return true; + } + + /** + * 在系统启动时,加载全部数据到内存,缓存的key只能为映射表的主键。 + */ + public void loadCachedData() { + if (loadOnStartup()) { + reloadCachedData(false); + } + } + + /** + * 重新加载数据库中所有当前表数据到系统内存。 + * + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + public void reloadCachedData(boolean force) { + // 在非强制刷新情况下。 + // 先行判断缓存中是否存在数据,如果有就不加载了。 + if (!force && dictionaryCache.getCount() > 0) { + return; + } + List allList = super.getAllList(); + dictionaryCache.reload(allList, force); + } + + /** + * 直接从缓存池中获取主键Id关联的数据。 + * + * @param id 主键Id。 + * @return 主键关联的数据,不存在返回null。 + */ + @Override + public M getById(K id) { + return dictionaryCache.get(id); + } + + /** + * 直接从缓存池中获取所有数据。 + * + * @return 返回所有数据。 + */ + @Override + public List getAllList() { + return dictionaryCache.getAll(); + } + + /** + * 直接从缓存池中返回符合主键 in (idValues) 条件的所有数据。 + * + * @param idValues 主键值列表。 + * @return 检索后的数据列表。 + */ + @Override + public List getInList(Set idValues) { + return dictionaryCache.getInList(idValues); + } + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。蜀国property是主键,则从缓存中读取。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @return 检索后的数据列表。 + */ + @Override + @SuppressWarnings("unchecked") + public List getInList(String inFilterField, Set inFilterValues) { + if (inFilterField.equals(this.idFieldName)) { + return this.getInList((Set) inFilterValues); + } + return this.getInList(inFilterField, inFilterValues, (String) null); + } + + /** + * 判断参数值列表中的所有数据,是否全部存在。另外,keyName字段在数据表中必须是唯一键值,否则返回结果会出现误判。 + * + * @param inFilterField 待校验的数据字段,这里使用Java对象中的属性,如courseId,而不是数据字段名course_id。 + * @param inFilterValues 数据值集合。 + * @return 全部存在返回true,否则false。 + */ + @Override + @SuppressWarnings("unchecked") + public boolean existUniqueKeyList(String inFilterField, Set inFilterValues) { + if (CollectionUtils.isEmpty(inFilterValues)) { + return false; + } + if (inFilterField.equals(this.idFieldName)) { + List dataList = dictionaryCache.getInList((Set) inFilterValues); + return dataList.size() == inFilterValues.size(); + } + Example e = this.makeDefaultInListExample(inFilterField, inFilterValues, null); + if (deletedFlagFieldName != null) { + e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + } + return mapper().selectCountByExample(e) == inFilterValues.size(); + } + + /** + * 获取缓存中的数据数量。 + * + * @return 缓存中的数据总量。 + */ + public int getCachedCount() { + return dictionaryCache.getCount(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseService.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseService.java new file mode 100644 index 00000000..c404c069 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/base/service/BaseService.java @@ -0,0 +1,1380 @@ +package com.orange.demo.common.core.base.service; + +import com.orange.demo.common.core.annotation.*; +import com.orange.demo.common.core.base.dao.BaseDaoMapper; +import com.orange.demo.common.core.constant.AggregationType; +import com.orange.demo.common.core.constant.GlobalDeletedFlag; +import com.orange.demo.common.core.exception.MyRuntimeException; +import com.orange.demo.common.core.object.*; +import com.orange.demo.common.core.util.AopTargetUtil; +import com.orange.demo.common.core.util.ApplicationContextHolder; +import com.orange.demo.common.core.util.MyModelUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import tk.mybatis.mapper.entity.Example; +import cn.hutool.core.util.ReflectUtil; + +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.*; +import java.util.function.Function; + +import static java.util.stream.Collectors.*; + +/** + * 所有Service的基类。 + * + * @param Model对象的类型。 + * @param Model对象主键的类型。 + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public abstract class BaseService { + + /** + * 当前Service关联的主Model实体对象的Class。 + */ + protected Class modelClass; + /** + * 当前Service关联的主Model实体对象的实际表名称。 + */ + protected String tableName; + /** + * 当前Service关联的主Model对象主键字段名称。 + */ + protected String idFieldName; + /** + * 当前Service关联的主数据表中数据字段名称。 + */ + protected String idColumnName; + /** + * 当前Service关联的主Model对象逻辑删除字段名称。 + */ + protected String deletedFlagFieldName; + /** + * 当前Service关联的主数据表中逻辑删除字段名称。 + */ + protected String deletedFlagColumnName; + /** + * 当前Job服务源主表Model对象最后更新时间字段名称。 + */ + protected String updateTimeFieldName; + /** + * 当前Job服务源主表Model对象最后更新时间列名称。 + */ + protected String updateTimeColumnName; + /** + * 当前Service关联的主Model对象主键字段反射对象。 + */ + protected Field idField; + /** + * 当前Service关联的主Model对象逻辑删除字段反射对象。 + */ + protected Field deletedFlagField; + /** + * 当前Service关联的主Model对象逻辑字段赋值方法的反射对象。 + */ + private Method setDeletedFlagMethod; + /** + * 当前Service关联的主Model对象的所有字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationDictStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有常量字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationConstDictStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有一对一关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationOneToOneStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有多对多关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationManyToManyStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有一对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationOneToManyAggrStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有多对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationManyToManyAggrStructList = new LinkedList<>(); + + private static final String GROUPED_KEY = "groupedKey"; + private static final String AGGREGATED_VALUE = "aggregatedValue"; + private static final String AND_OP = " AND "; + + /** + * 构造函数,在实例化的时候,一次性完成所有有关主Model对象信息的加载。 + */ + @SuppressWarnings("unchecked") + public BaseService() { + modelClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + this.tableName = modelClass.getAnnotation(Table.class).name(); + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field field : fields) { + initializeField(field); + } + } + + private void initializeField(Field field) { + if (idFieldName == null && null != field.getAnnotation(Id.class)) { + idFieldName = field.getName(); + idField = field; + Column c = field.getAnnotation(Column.class); + idColumnName = c == null ? idFieldName : c.name(); + } + if (updateTimeFieldName == null && null != field.getAnnotation(JobUpdateTimeColumn.class)) { + updateTimeFieldName = field.getName(); + Column c = field.getAnnotation(Column.class); + updateTimeColumnName = c == null ? updateTimeFieldName : c.name(); + } + if (deletedFlagFieldName == null && null != field.getAnnotation(DeletedFlagColumn.class)) { + deletedFlagFieldName = field.getName(); + Column c = field.getAnnotation(Column.class); + deletedFlagColumnName = c == null ? deletedFlagFieldName : c.name(); + deletedFlagField = field; + setDeletedFlagMethod = ReflectUtil.getMethod( + modelClass, "set" + StringUtils.capitalize(deletedFlagFieldName), Integer.class); + } + } + + /** + * 获取子类中注入的Mapper类。 + * + * @return 子类中注入的Mapper类。 + */ + protected abstract BaseDaoMapper mapper(); + + /** + * 判断指定字段的数据是否存在,且仅仅存在一条记录。 + * 如果是基于主键的过滤,会直接调用existId过滤函数,提升性能。在有缓存的场景下,也可以利用缓存。 + * + * @param fieldName 待过滤的字段名(Java 字段)。 + * @param fieldValue 字段值。 + * @return 存在且仅存在一条返回true,否则false。 + */ + @SuppressWarnings("unchecked") + public boolean existOne(String fieldName, Object fieldValue) { + if (fieldName.equals(this.idFieldName)) { + return this.existId((K) fieldValue); + } + Example e = new Example(modelClass); + e.createCriteria().andEqualTo(fieldName, fieldValue); + return mapper().selectByExample(e).size() == 1; + } + + /** + * 判断主键Id关联的数据是否存在。 + * + * @param id 主键Id。 + * @return 存在返回true,否则false。 + */ + public boolean existId(K id) { + return getById(id) != null; + } + + /** + * 获取主键Id关联的数据。 + * + * @param id 主键Id。 + * @return 主键关联的数据,不存在返回null。 + */ + public M getById(K id) { + if (deletedFlagFieldName == null) { + return mapper().selectByPrimaryKey(id); + } + Example e = new Example(modelClass); + e.createCriteria() + .andEqualTo(this.idFieldName, id) + .andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + return mapper().selectOneByExample(e); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param id 主表主键Id。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @return 查询结果对象。 + */ + public M getByIdWithRelation(K id, MyRelationParam relationParam) { + M dataObject = this.getById(id); + this.buildRelationForData(dataObject, relationParam, buildAggregationAdditionalWhereCriteria()); + return dataObject; + } + + /** + * 获取所有数据。 + * + * @return 返回所有数据。 + */ + public List getAllList() { + if (deletedFlagFieldName == null) { + return mapper().selectAll(); + } + Example e = new Example(modelClass); + e.createCriteria().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + return mapper().selectByExample(e); + } + + /** + * 获取所有主数据,及其关联数据。 + * + * @param relationParam 实体对象数据组装的参数构建器。 + * @return 返回所有主数据,及其关联数据。 + */ + public List getAllListWithRelation(MyRelationParam relationParam) { + List resultList = getAllList(); + this.buildRelationForDataList(resultList, relationParam, null); + return resultList; + } + + /** + * 获取排序后所有数据。 + * + * @param orderByProperties 需要排序的字段属性,这里使用Java对象中的属性名,而不是数据库字段名。 + * @return 返回排序后所有数据。 + */ + public List getAllListByOrder(String... orderByProperties) { + Example e = new Example(modelClass); + for (String orderByProperty : orderByProperties) { + e.orderBy(orderByProperty); + } + if (deletedFlagFieldName != null) { + e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + } + return mapper().selectByExample(e); + } + + /** + * 判断参数值主键集合中的所有数据,是否全部存在 + * + * @param idSet 待校验的主键集合。 + * @return 全部存在返回true,否则false。 + */ + public boolean existAllPrimaryKeys(Set idSet) { + if (CollectionUtils.isEmpty(idSet)) { + return false; + } + return this.existUniqueKeyList(idFieldName, idSet); + } + + /** + * 判断参数值列表中的所有数据,是否全部存在。另外,keyName字段在数据表中必须是唯一键值,否则返回结果会出现误判。 + * + * @param inFilterField 待校验的数据字段,这里使用Java对象中的属性,如courseId,而不是数据字段名course_id + * @param inFilterValues 数据值列表。 + * @return 全部存在返回true,否则false。 + */ + public boolean existUniqueKeyList(String inFilterField, Set inFilterValues) { + if (CollectionUtils.isEmpty(inFilterValues)) { + return false; + } + Example e = this.makeDefaultInListExample(inFilterField, inFilterValues, null); + if (deletedFlagFieldName != null) { + e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + } + return mapper().selectCountByExample(e) == inFilterValues.size(); + } + + /** + * 获取所有数据的指定字段的数据列表。 + * + * @param getterFunc 指定字段的getter方法。 + * @param 指定字段的类型。 + * @return 指定字段的列表。 + */ + public List getAllListWithField(Function getterFunc) { + List allList = this.getAllList(); + // 即使没有符合filter条件的item存在,也会返回空列表对象,而不是null。 + return allList.stream().filter(x -> getterFunc.apply(x) != null).map(getterFunc).collect(toList()); + } + + /** + * 返回符合主键 in (idValues) 条件的所有数据。 + * + * @param idValues 主键值集合。 + * @return 检索后的数据列表。 + */ + public List getInList(Set idValues) { + return this.getInList(idFieldName, idValues, (String) null); + } + + /** + * 通过getIdFunc函数,获取主对象列表masterList中的主键列表。在基于该Id列表作为主键查询的in list条件,获取数据。 + * + * @param masterList 主对象列表,通过应用getIdFunc函数,获取查询条件中的主键in list条件。 + * @param getIdFunc 获取主对象中符合查询条件主键的id值。 + * @return 检索后的数据列表。 + */ + public List getInList(List masterList, Function getIdFunc) { + // 即使没有符合filter条件的item存在,也会返回空列表对象,而不是null。 + return this.getInList(masterList.stream() + .filter(x -> getIdFunc.apply(x) != null).map(getIdFunc).collect(toSet())); + } + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @return 检索后的数据列表。 + */ + public List getInList(String inFilterField, Set inFilterValues) { + return this.getInList(inFilterField, inFilterValues, (String) null); + } + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据,并根据orderBy字段排序。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @param orderBy 排序字段。 + * @return 检索后的数据列表。 + */ + public List getInList(String inFilterField, Set inFilterValues, String orderBy) { + if (CollectionUtils.isEmpty(inFilterValues)) { + return new LinkedList<>(); + } + Example e = this.makeDefaultInListExample(inFilterField, inFilterValues, orderBy); + if (deletedFlagFieldName != null) { + e.and().andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + } + return mapper().selectByExample(e); + } + + /** + * 基于对象集合(masterList),并通过masterIdFunction函数对象获取property字段的数据列表, + * inFilterField in (inFilterValues)的所有数据。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param masterList 主对象数据集合。 + * @param masterIdFunction 获取主对象中,property字段数值的函数对象。 + * @param 主对象类型。 + * @return 检索后的数据列表。 + */ + public List getInList(String inFilterField, Collection masterList, Function masterIdFunction) { + // 即使没有符合filter条件的item存在,也会返回空列表对象,而不是null。 + return this.getInList(inFilterField, masterList.stream() + .filter(x -> masterIdFunction.apply(x) != null).map(masterIdFunction).collect(toSet())); + } + + /** + * 用参数对象作为过滤条件,获取数据数量。 + * + * @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。 + * @return 返回过滤后的数据数量。 + */ + public int getCountByFilter(M filter) { + if (deletedFlagFieldName == null) { + return mapper().selectCount(filter); + } + try { + setDeletedFlagMethod.invoke(filter, GlobalDeletedFlag.NORMAL); + return mapper().selectCount(filter); + } catch (Exception e) { + log.error("Failed to call reflection code of BaseService.getCountByFilter.", e); + throw new MyRuntimeException(e); + } + } + + /** + * 用参数对象作为过滤条件,判断是否存在过滤数据。 + * + * @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。 + * @return 存在返回true,否则false。 + */ + public boolean existByFilter(M filter) { + return this.getCountByFilter(filter) > 0; + } + + /** + * 用参数对象作为过滤条件,获取查询结果。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @return 返回过滤后的数据。 + */ + private List getListByFilter(M filter) { + if (filter == null) { + return this.getAllList(); + } + if (deletedFlagFieldName == null) { + return mapper().select(filter); + } + try { + setDeletedFlagMethod.invoke(filter, GlobalDeletedFlag.NORMAL); + return mapper().select(filter); + } catch (Exception ex) { + log.error("Failed to call reflection code of BaseService.getListByFilter.", ex); + throw new MyRuntimeException(ex); + } + } + + /** + * 用参数对象作为过滤条件,获取查询结果。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @param orderBy SQL中ORDER BY从句。 + * @return 返回过滤后的数据。 + */ + public List getListByFilter(M filter, String orderBy) { + if (StringUtils.isBlank(orderBy)) { + return this.getListByFilter(filter); + } + Example e = new Example(modelClass); + if (StringUtils.isNotBlank(orderBy)) { + e.setOrderByClause(orderBy); + } + if (filter != null) { + Example.Criteria c = e.createCriteria(); + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field field : fields) { + if (field.getAnnotation(Transient.class) == null) { + assembleCriteriaByFilter(filter, field, c); + } + } + } + return mapper().selectByExample(e); + } + + private void assembleCriteriaByFilter(M filter, Field field, Example.Criteria c) { + int modifiers = field.getModifiers(); + // transient类型的字段不能作为查询条件 + int transientMask = 128; + if ((modifiers & transientMask) == 0) { + if (field.getName().equals(deletedFlagFieldName)) { + c.andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + } else { + ReflectUtil.setAccessible(field); + try { + Object o = field.get(filter); + if (o != null) { + c.andEqualTo(field.getName(), field.get(filter)); + } + } catch (IllegalAccessException ex) { + log.error("Failed to call reflection code of BaseService.getListByFilter.", ex); + throw new MyRuntimeException(ex); + } + } + } + } + + /** + * 用参数对象作为过滤条件,获取查询结果。同时组装实体对象中基于RelationXXXX注解关联的数据。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @param orderBy SQL中ORDER BY从句。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @return 返回过滤后的数据。 + */ + public List getListWithRelationByFilter(M filter, String orderBy, MyRelationParam relationParam) { + List resultList = this.getListByFilter(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildRelationForDataList(resultList, relationParam, criteriaMap); + return resultList; + } + + /** + * 获取父主键Id下的所有子数据列表。 + * + * @param parentIdFieldName 父主键字段名字,如"courseId"。 + * @param parentId 父主键的值。 + * @return 父主键Id下的所有子数据列表。 + */ + public List getListByParentId(String parentIdFieldName, K parentId) { + Example e = new Example(modelClass); + if (parentId != null) { + e.createCriteria().andEqualTo(parentIdFieldName, parentId); + } else { + e.createCriteria().andIsNull(parentIdFieldName); + } + return mapper().selectByExample(e); + } + + /** + * 根据指定的显示字段列表、过滤条件字符串和分组字符串,返回聚合计算后的查询结果。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param selectFields 选择的字段列表,多个字段逗号分隔。 + * NOTE: 如果数据表字段和Java对象字段名字不同,Java对象字段应该以别名的形式出现。 + * 如: table_column_name modelFieldName。否则无法被反射回Bean对象。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy SQL常量形式分组字段列表,逗号分隔。 + * @return 聚合计算后的数据结果集。 + */ + public List> getGroupedListByCondition( + String selectFields, String whereClause, String groupBy) { + return mapper().getGroupedListByCondition(tableName, selectFields, whereClause, groupBy); + } + + /** + * 根据指定的显示字段列表、过滤条件字符串和排序字符串,返回查询结果。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param selectList 选择的Java字段列表。如果为空表示返回全部字段。 + * @param whereClause SQL常量形式的条件从句。 + * @param orderBy SQL常量形式排序字段列表,逗号分隔。 + * @return 查询结果。 + */ + public List getListByCondition(List selectList, String whereClause, String orderBy) { + Example e = new Example(modelClass); + if (CollectionUtils.isNotEmpty(selectList)) { + String[] selectFields = new String[selectList.size()]; + selectList.toArray(selectFields); + e.selectProperties(selectFields); + } + if (StringUtils.isNotBlank(orderBy)) { + e.setOrderByClause(orderBy); + } + if (StringUtils.isNotBlank(whereClause)) { + e.createCriteria().andCondition(whereClause); + } + return mapper().selectByExample(e); + } + + /** + * 用指定过滤条件,计算记录数量。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param whereClause SQL常量形式的条件从句。 + * @return 返回过滤后的数据数量。 + */ + public Integer getCountByCondition(String whereClause) { + return mapper().getCountByCondition(this.tableName, whereClause); + } + + /** + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param criteriaListMap 仅仅用于一对多和多对多聚合计算的附加过滤条件。如果没有可以为NULL。 + */ + public void buildRelationForDataList( + List resultList, MyRelationParam relationParam, Map> criteriaListMap) { + if (relationParam == null || CollectionUtils.isEmpty(resultList)) { + return; + } + // 集成本地一对一和字段级别的数据关联。 + boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict(); + // 这里集成一对一关联。 + if (buildOneToOne) { + this.buildOneToOneForDataList(resultList, relationParam.isBuildOneToOneWithDict()); + } + // 这里集成字典关联 + if (relationParam.isBuildDict()) { + // 构建常量字典关联关系 + this.buildConstDictForDataList(resultList); + this.buildDictForDataList(resultList, buildOneToOne); + } + // 组装本地聚合计算关联数据 + if (relationParam.isBuildRelationAggregation()) { + // 处理多对多场景下,根据主表的结果,进行从表聚合数据的计算。 + this.buildManyToManyAggregationForDataList(resultList, criteriaListMap); + // 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。 + this.buildOneToManyAggregationForDataList(resultList, criteriaListMap); + } + } + + /** + * 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * + * @param dataObject 主表实体对象。数据集成将直接作用于该对象。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param criteriaListMap 仅仅用于一对多和多对多聚合计算的附加过滤条件。如果没有可以为NULL。 + * @param 实体对象类型。 + */ + public void buildRelationForData( + T dataObject, MyRelationParam relationParam, Map> criteriaListMap) { + if (dataObject == null || relationParam == null) { + return; + } + // 集成本地一对一和字段级别的数据关联。 + boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict(); + if (buildOneToOne) { + this.buildOneToOneForData(dataObject, relationParam.isBuildOneToOneWithDict()); + } + if (relationParam.isBuildDict()) { + // 构建常量字典关联关系 + this.buildConstDictForData(dataObject); + // 构建本地数据字典关联关系。 + this.buildDictForData(dataObject, buildOneToOne); + } + // 组装本地聚合计算关联数据 + if (relationParam.isBuildRelationAggregation()) { + // 开始处理多对多场景。 + buildManyToManyAggregationForData(dataObject, criteriaListMap); + // 构建一对多场景 + buildOneToManyAggregationForData(dataObject, criteriaListMap); + } + if (relationParam.isBuildRelationManyToMany()) { + this.buildManyToManyRelation(dataObject); + } + } + + /** + * 集成主表和多对多中间表之间的关联关系。 + * + * @param dataObject 关联后的主表数据对象。 + */ + private void buildManyToManyRelation(T dataObject) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationManyToManyStructList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + Example e = new Example(relationStruct.relationManyToMany.relationModelClass()); + e.createCriteria().andEqualTo(relationStruct.masterIdField.getName(), masterIdValue); + List manyToManyList = relationStruct.manyToManyMapper.selectByExample(e); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, manyToManyList); + } + } + + /** + * 为实体对象参数列表数据集成本地静态字典关联数据。 + * + * @param resultList 主表数据列表。 + */ + private void buildConstDictForDataList(List resultList) { + if (CollectionUtils.isEmpty(this.relationConstDictStructList) + || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationConstDictStructList) { + for (M dataObject : resultList) { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + String name = relationStruct.dictMap.get(id); + if (name != null) { + Map dictMap = new HashMap<>(2); + dictMap.put("id", id); + dictMap.put("name", name); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, dictMap); + } + } + } + } + } + + /** + * 为参数实体对象数据集成本地静态字典关联数据。 + * + * @param dataObject 实体对象。 + */ + private void buildConstDictForData(T dataObject) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationConstDictStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationConstDictStructList) { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + String name = relationStruct.dictMap.get(id); + if (name != null) { + Map dictMap = new HashMap<>(2); + dictMap.put("id", id); + dictMap.put("name", name); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, dictMap); + } + } + } + } + + /** + * 为实体对象参数列表数据集成本地字典关联数据。 + * + * @param resultList 实体对象数据列表。 + * @param hasBuiltOneToOne 性能优化参数。如果该值为true,同时注解参数RelationDict.equalOneToOneRelationField + * 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。 + */ + private void buildDictForDataList(List resultList, boolean hasBuiltOneToOne) { + if (CollectionUtils.isEmpty(this.relationDictStructList) + || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationDictStructList) { + List relationList = null; + if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) { + relationList = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.equalOneToOneRelationField)) + .filter(Objects::nonNull) + .collect(toList()); + } else { + String slaveId = relationStruct.relationDict.slaveIdField(); + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isNotEmpty(masterIdSet)) { + relationList = relationStruct.service.getInList(slaveId, masterIdSet); + } + } + MyModelUtil.makeDictRelation( + modelClass, resultList, relationList, relationStruct.relationField.getName()); + } + } + + /** + * 为实体对象数据集成本地数据字典关联数据。 + * + * @param dataObject 实体对象。 + * @param hasBuiltOneToOne 性能优化参数。如果该值为true,同时注解参数RelationDict.equalOneToOneRelationField + * 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。 + */ + private void buildDictForData(T dataObject, boolean hasBuiltOneToOne) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationDictStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationDictStructList) { + Object relationObject = null; + if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) { + relationObject = ReflectUtil.getFieldValue(dataObject, relationStruct.equalOneToOneRelationField); + } else { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + relationObject = relationStruct.service.getById(id); + } + } + MyModelUtil.makeDictRelation( + modelClass, dataObject, relationObject, relationStruct.relationField.getName()); + } + } + + /** + * 为实体对象参数列表数据集成本地一对一关联数据。 + * + * @param resultList 实体对象数据列表。 + * @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。。 + */ + private void buildOneToOneForDataList(List resultList, boolean withDict) { + if (CollectionUtils.isEmpty(this.relationOneToOneStructList) + || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationOneToOneStructList) { + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + // 从主表集合中,抽取主表关联字段的集合,再以in list形式去从表中查询。 + if (CollectionUtils.isNotEmpty(masterIdSet)) { + BaseService relationService = relationStruct.service; + List relationList = + relationService.getInList(relationStruct.relationOneToOne.slaveIdField(), masterIdSet); + MyModelUtil.makeOneToOneRelation( + modelClass, resultList, relationList, relationStruct.relationField.getName()); + // 仅仅当需要加载从表字典关联时,才去加载。 + if (withDict && relationStruct.relationOneToOne.loadSlaveDict() + && CollectionUtils.isNotEmpty(relationList)) { + @SuppressWarnings("unchecked") + BaseService proxyTarget = + (BaseService) AopTargetUtil.getTarget(relationService); + // 关联本地字典。 + proxyTarget.buildDictForDataList(relationList, false); + // 关联常量字典 + proxyTarget.buildConstDictForDataList(relationList); + } + } + } + } + + /** + * 为实体对象数据集成本地一对一关联数据。 + * + * @param dataObject 实体对象。 + * @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。。 + */ + private void buildOneToOneForData(M dataObject, boolean withDict) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToOneStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationOneToOneStructList) { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + BaseService relationService = relationStruct.service; + Object relationObject = relationService.getById(id); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject); + // 仅仅当需要加载从表字典关联时,才去加载。 + if (withDict && relationStruct.relationOneToOne.loadSlaveDict() && relationObject != null) { + @SuppressWarnings("unchecked") + BaseService proxyTarget = + (BaseService) AopTargetUtil.getTarget(relationService); + // 关联本地字典 + proxyTarget.buildDictForData(relationObject, false); + // 关联常量字典 + proxyTarget.buildConstDictForData(relationObject); + } + } + } + } + + /** + * 根据实体对象参数列表和过滤条件,集成本地多对多关联聚合计算数据。 + * + * @param resultList 实体对象数据列表。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + */ + private void buildManyToManyAggregationForDataList( + List resultList, Map> criteriaListMap) { + if (CollectionUtils.isEmpty(this.relationManyToManyAggrStructList) + || CollectionUtils.isEmpty(resultList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(this.relationManyToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) { + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isEmpty(masterIdSet)) { + continue; + } + RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation; + // 提取关联中用到的各种字段和表数据。 + BasicAggregationRelationInfo basicRelationInfo = + this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap); + // 构建多表关联的where语句 + StringBuilder whereClause = new StringBuilder(256); + // 如果需要从表聚合计算或参与过滤,则需要把中间表和从表之间的关联条件加上。 + if (!basicRelationInfo.onlySelectRelationTable) { + whereClause.append(basicRelationInfo.relationTable) + .append(".") + .append(basicRelationInfo.relationSlaveColumn) + .append(" = ") + .append(basicRelationInfo.slaveTable) + .append(".") + .append(basicRelationInfo.slaveColumn); + } else { + whereClause.append("1 = 1"); + } + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + MyWhereCriteria inlistFilter = new MyWhereCriteria(); + inlistFilter.setCriteria(relation.relationModelClass(), + relation.relationMasterIdField(), MyWhereCriteria.OPERATOR_IN, masterIdSet); + criteriaList.add(inlistFilter); + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + whereClause.append(AND_OP).append(criteriaString); + StringBuilder tableNames = new StringBuilder(64); + tableNames.append(basicRelationInfo.relationTable); + if (!basicRelationInfo.onlySelectRelationTable) { + tableNames.append(", ").append(basicRelationInfo.slaveTable); + } + List> aggregationMapList = + mapper().getGroupedListByCondition(tableNames.toString(), + basicRelationInfo.selectList, whereClause.toString(), basicRelationInfo.groupBy); + doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct); + } + } + + /** + * 根据实体对象和过滤条件,集成本地多对多关联聚合计算数据。 + * + * @param dataObject 实体对象。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + */ + private void buildManyToManyAggregationForData( + T dataObject, Map> criteriaListMap) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyAggrStructList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationManyToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue == null) { + continue; + } + BasicAggregationRelationInfo basicRelationInfo = + this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap); + // 组装过滤条件 + String whereClause = this.makeManyToManyWhereClause( + relationStruct, masterIdValue, basicRelationInfo, criteriaListMap); + StringBuilder tableNames = new StringBuilder(64); + tableNames.append(basicRelationInfo.relationTable); + if (!basicRelationInfo.onlySelectRelationTable) { + tableNames.append(", ").append(basicRelationInfo.slaveTable); + } + List> aggregationMapList = + mapper().getGroupedListByCondition(tableNames.toString(), + basicRelationInfo.selectList, whereClause, basicRelationInfo.groupBy); + // 将查询后的结果回填到主表数据中。 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + + /** + * 根据实体对象参数列表和过滤条件,集成本地一对多关联聚合计算数据。 + * + * @param resultList 实体对象数据列表。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + */ + private void buildOneToManyAggregationForDataList( + List resultList, Map> criteriaListMap) { + // 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。 + if (CollectionUtils.isEmpty(this.relationOneToManyAggrStructList) + || CollectionUtils.isEmpty(resultList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) { + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isEmpty(masterIdSet)) { + continue; + } + RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation; + // 开始获取后面所需的各种关联数据。此部分今后可以移植到缓存中,无需每次计算。 + String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + String slaveColumnName = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + slaveTable, slaveColumnName, relation.slaveModelClass(), + slaveTable, relation.aggregationField(), relation.aggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + MyWhereCriteria inlistFilter = new MyWhereCriteria(); + inlistFilter.setCriteria(relation.slaveModelClass(), + relation.slaveIdField(), MyWhereCriteria.OPERATOR_IN, masterIdSet); + criteriaList.add(inlistFilter); + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + List> aggregationMapList = + mapper().getGroupedListByCondition(slaveTable, selectList, criteriaString, groupBy); + doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct); + } + } + + /** + * 根据实体对象和过滤条件,集成本地一对多关联聚合计算数据。 + * + * @param dataObject 实体对象。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + */ + private void buildOneToManyAggregationForData( + T dataObject, Map> criteriaListMap) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyAggrStructList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue == null) { + continue; + } + RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation; + String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + String slaveColumnName = + MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + slaveTable, slaveColumnName, relation.slaveModelClass(), + slaveTable, relation.aggregationField(), relation.aggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + String whereClause = this.makeOneToManyWhereClause( + relationStruct, masterIdValue, slaveColumnName, criteriaListMap); + // 获取分组聚合计算结果 + List> aggregationMapList = + mapper().getGroupedListByCondition(slaveTable, selectList, whereClause, groupBy); + // 将计算结果回填到主表关联字段 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + + /** + * 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。 + */ + public void loadRelationStruct() { + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field f : fields) { + initializeRelationDictStruct(f); + initializeRelationStruct(f); + initializeRelationAggregationStruct(f); + } + } + + /** + * 缺省实现返回null,在进行一对多和多对多聚合计算时,没有额外的自定义过滤条件。如有需要,需子类自行实现。 + * + * @return 自定义过滤条件列表。 + */ + protected Map> buildAggregationAdditionalWhereCriteria() { + return null; + } + + /** + * 判断当前对象的关联字段数据是否需要被验证,如果原有对象为null,表示新对象第一次插入,则必须验证。 + * + * @param object 新对象。 + * @param originalObject 原有对象。 + * @param fieldGetter 获取需要验证字段的函数对象。 + * @param 需要验证字段的类型。 + * @return 需要关联验证返回true,否则false。 + */ + protected boolean needToVerify(M object, M originalObject, Function fieldGetter) { + T data = fieldGetter.apply(object); + if (data == null) { + return false; + } + if (data instanceof String) { + String stringData = (String) data; + if (stringData.length() == 0) { + return false; + } + } + if (originalObject == null) { + return true; + } + T originalData = fieldGetter.apply(originalObject); + return !data.equals(originalData); + } + + /** + * 通过(In-list)条件和orderBy条件,构建Example对象,以供后续的查询操作使用。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @param orderBy 排序字段。 + * @param in 属性字段的类型。 + * @return 构建后的Example对象。 + */ + protected Example makeDefaultInListExample(String inFilterField, Collection inFilterValues, String orderBy) { + Set inFilterValueSet; + Example e = new Example(modelClass); + if (StringUtils.isNotBlank(orderBy)) { + e.setOrderByClause(orderBy); + } + if (inFilterValues instanceof Set) { + inFilterValueSet = (Set) inFilterValues; + } else { + inFilterValueSet = new HashSet<>(inFilterValues.size()); + inFilterValueSet.addAll(inFilterValues); + } + e.createCriteria().andIn(inFilterField, inFilterValueSet); + return e; + } + + private void initializeRelationStruct(Field f) { + RelationOneToOne relationOneToOne = f.getAnnotation(RelationOneToOne.class); + if (relationOneToOne != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToOne.masterIdField()); + relationStruct.relationOneToOne = relationOneToOne; + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationOneToOne.slaveServiceName())); + relationOneToOneStructList.add(relationStruct); + return; + } + RelationManyToMany relationManyToMany = f.getAnnotation(RelationManyToMany.class); + if (relationManyToMany != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToMany.relationMasterIdField()); + relationStruct.relationManyToMany = relationManyToMany; + relationStruct.manyToManyMapper = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationManyToMany.relationMapperName())); + relationManyToManyStructList.add(relationStruct); + } + } + + private void initializeRelationAggregationStruct(Field f) { + RelationOneToManyAggregation relationOneToManyAggregation = f.getAnnotation(RelationOneToManyAggregation.class); + if (relationOneToManyAggregation != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToManyAggregation.masterIdField()); + relationStruct.relationOneToManyAggregation = relationOneToManyAggregation; + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationOneToManyAggregation.slaveServiceName())); + relationOneToManyAggrStructList.add(relationStruct); + return; + } + RelationManyToManyAggregation relationManyToManyAggregation = f.getAnnotation(RelationManyToManyAggregation.class); + if (relationManyToManyAggregation != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToManyAggregation.masterIdField()); + relationStruct.relationManyToManyAggregation = relationManyToManyAggregation; + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationManyToManyAggregation.slaveServiceName())); + relationManyToManyAggrStructList.add(relationStruct); + } + } + + @SuppressWarnings("unchecked") + private void initializeRelationDictStruct(Field f) { + RelationConstDict relationConstDict = f.getAnnotation(RelationConstDict.class); + if (relationConstDict != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationConstDict.masterIdField()); + Field dictMapField = ReflectUtil.getField(relationConstDict.constantDictClass(), "DICT_MAP"); + relationStruct.dictMap = (Map) ReflectUtil.getFieldValue(modelClass, dictMapField); + relationConstDictStructList.add(relationStruct); + return; + } + RelationDict relationDict = f.getAnnotation(RelationDict.class); + if (relationDict != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationDict.masterIdField()); + relationStruct.relationDict = relationDict; + if (StringUtils.isNotBlank(relationDict.equalOneToOneRelationField())) { + relationStruct.equalOneToOneRelationField = + ReflectUtil.getField(modelClass, relationDict.equalOneToOneRelationField()); + } + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationDict.slaveServiceName())); + relationDictStructList.add(relationStruct); + } + } + + private BasicAggregationRelationInfo parseBasicAggregationRelationInfo( + RelationStruct relationStruct, Map> criteriaListMap) { + RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation; + BasicAggregationRelationInfo relationInfo = new BasicAggregationRelationInfo(); + // 提取关联中用到的各种字段和表数据。 + relationInfo.slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + relationInfo.relationTable = MyModelUtil.mapToTableName(relation.relationModelClass()); + relationInfo.relationMasterColumn = + MyModelUtil.mapToColumnName(relation.relationMasterIdField(), relation.relationModelClass()); + relationInfo.relationSlaveColumn = + MyModelUtil.mapToColumnName(relation.relationSlaveIdField(), relation.relationModelClass()); + relationInfo.slaveColumn = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + // 判断是否只需要关联中间表即可,从而提升查询统计的效率。 + // 1. 统计字段为中间表字段。2. 自定义过滤条件中没有基于从表字段的过滤条件。 + relationInfo.onlySelectRelationTable = + relation.aggregationModelClass().equals(relation.relationModelClass()); + if (relationInfo.onlySelectRelationTable && MapUtils.isNotEmpty(criteriaListMap)) { + List criteriaList = + criteriaListMap.get(relationStruct.relationField.getName()); + if (CollectionUtils.isNotEmpty(criteriaList)) { + for (MyWhereCriteria whereCriteria : criteriaList) { + if (whereCriteria.getModelClazz().equals(relation.slaveModelClass())) { + relationInfo.onlySelectRelationTable = false; + break; + } + } + } + } + String aggregationTable = relation.aggregationModelClass().equals(relation.relationModelClass()) + ? relationInfo.relationTable : relationInfo.slaveTable; + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + relationInfo.relationTable, relationInfo.relationMasterColumn, relation.aggregationModelClass(), + aggregationTable, relation.aggregationField(), relation.aggregationType()); + relationInfo.selectList = selectAndGroupByTuple.getFirst(); + relationInfo.groupBy = selectAndGroupByTuple.getSecond(); + return relationInfo; + } + + private String makeManyToManyWhereClause( + RelationStruct relationStruct, + Object masterIdValue, + BasicAggregationRelationInfo basicRelationInfo, + Map> criteriaListMap) { + StringBuilder whereClause = new StringBuilder(256); + whereClause.append(basicRelationInfo.relationTable) + .append(".").append(basicRelationInfo.relationMasterColumn); + if (masterIdValue instanceof Number) { + whereClause.append(" = ").append(masterIdValue); + } else { + whereClause.append(" = '").append(masterIdValue).append("'"); + } + // 如果需要从表聚合计算或参与过滤,则需要把中间表和从表之间的关联条件加上。 + if (!basicRelationInfo.onlySelectRelationTable) { + whereClause.append(AND_OP) + .append(basicRelationInfo.relationTable) + .append(".") + .append(basicRelationInfo.relationSlaveColumn) + .append(" = ") + .append(basicRelationInfo.slaveTable) + .append(".") + .append(basicRelationInfo.slaveColumn); + } + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relationStruct.relationManyToManyAggregation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (CollectionUtils.isNotEmpty(criteriaList)) { + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + whereClause.append(AND_OP).append(criteriaString); + } + return whereClause.toString(); + } + + private String makeOneToManyWhereClause( + RelationStruct relationStruct, + Object masterIdValue, + String slaveColumnName, + Map> criteriaListMap) { + StringBuilder whereClause = new StringBuilder(64); + if (masterIdValue instanceof Number) { + whereClause.append(slaveColumnName).append(" = ").append(masterIdValue); + } else { + whereClause.append(slaveColumnName).append(" = '").append(masterIdValue).append("'"); + } + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relationStruct.relationOneToManyAggregation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (CollectionUtils.isNotEmpty(criteriaList)) { + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + whereClause.append(AND_OP).append(criteriaString); + } + return whereClause.toString(); + } + + private static class BasicAggregationRelationInfo { + private String slaveTable; + private String slaveColumn; + private String relationTable; + private String relationMasterColumn; + private String relationSlaveColumn; + private String selectList; + private String groupBy; + private boolean onlySelectRelationTable; + } + + private void doMakeLocalAggregationData( + List> aggregationMapList, List resultList, RelationStruct relationStruct) { + if (CollectionUtils.isEmpty(resultList)) { + return; + } + // 根据获取的分组聚合结果集,绑定到主表总的关联字段。 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Map relatedMap = new HashMap<>(aggregationMapList.size()); + for (Map map : aggregationMapList) { + relatedMap.put(map.get(GROUPED_KEY), map.get(AGGREGATED_VALUE)); + } + for (M dataObject : resultList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue != null) { + Object value = relatedMap.get(masterIdValue); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + } + + private Tuple2 makeSelectListAndGroupByClause( + String groupTableName, + String groupColumnName, + Class aggregationModel, + String aggregationTableName, + String aggregationField, + Integer aggregationType) { + if (!AggregationType.isValid(aggregationType)) { + throw new IllegalArgumentException("Invalid AggregationType Value [" + + aggregationType + "] in Model [" + aggregationModel.getName() + "]."); + } + String aggregationFunc = AggregationType.getAggregationFunction(aggregationType); + String aggregationColumn = MyModelUtil.mapToColumnName(aggregationField, aggregationModel); + if (StringUtils.isBlank(aggregationColumn)) { + throw new IllegalArgumentException("Invalid AggregationField [" + + aggregationField + "] in Model [" + aggregationModel.getName() + "]."); + } + // 构建Select List + // 如:r_table.master_id groupedKey, SUM(r_table.aggr_column) aggregated_value + StringBuilder groupedSelectList = new StringBuilder(128); + groupedSelectList.append(groupTableName) + .append(".") + .append(groupColumnName) + .append(" ") + .append(GROUPED_KEY) + .append(", ") + .append(aggregationFunc) + .append("(") + .append(aggregationTableName) + .append(".") + .append(aggregationColumn) + .append(") ") + .append(AGGREGATED_VALUE) + .append(" "); + StringBuilder groupBy = new StringBuilder(64); + groupBy.append(groupTableName).append(".").append(groupColumnName); + return new Tuple2<>(groupedSelectList.toString(), groupBy.toString()); + } + + static class RelationStruct { + private Field relationField; + private Field masterIdField; + private Field equalOneToOneRelationField; + private BaseService service; + private BaseDaoMapper manyToManyMapper; + private Map dictMap; + private RelationDict relationDict; + private RelationOneToOne relationOneToOne; + private RelationManyToMany relationManyToMany; + private RelationOneToManyAggregation relationOneToManyAggregation; + private RelationManyToManyAggregation relationManyToManyAggregation; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/CacheConfig.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/CacheConfig.java new file mode 100644 index 00000000..a1522ace --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/CacheConfig.java @@ -0,0 +1,90 @@ +package com.orange.demo.common.core.cache; + +import com.github.benmanes.caffeine.cache.Caffeine; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.caffeine.CaffeineCache; +import org.springframework.cache.support.SimpleCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +/** + * 使用Caffeine作为本地缓存库 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +@EnableCaching +public class CacheConfig { + + private static final int DEFAULT_MAXSIZE = 10000; + private static final int DEFAULT_TTL = 3600; + + /** + * 定义cache名称、超时时长秒、最大个数 + * 每个cache缺省3600秒过期,最大个数1000 + */ + public enum CacheEnum { + /** + * 专门存储用户权限的缓存。 + */ + USER_PERMISSION_CACHE(1800, 10000), + /** + * session下上传文件名的缓存(时间是24小时)。 + */ + UPLOAD_FILENAME_CACHE(86400, 20000), + /** + * 缺省全局缓存(时间是24小时)。 + */ + GLOBAL_CACHE(86400, 20000); + + CacheEnum() { + } + + CacheEnum(int ttl, int maxSize) { + this.ttl = ttl; + this.maxSize = maxSize; + } + + /** + * 缓存的最大数量。 + */ + private int maxSize = DEFAULT_MAXSIZE; + /** + * 缓存的时长(单位:秒) + */ + private int ttl = DEFAULT_TTL; + + public int getMaxSize() { + return maxSize; + } + + public int getTtl() { + return ttl; + } + } + + /** + * 初始化缓存配置。 + */ + @Bean + public CacheManager cacheManager() { + SimpleCacheManager manager = new SimpleCacheManager(); + //把各个cache注册到cacheManager中,CaffeineCache实现了org.springframework.cache.Cache接口 + ArrayList caches = new ArrayList<>(); + for (CacheEnum c : CacheEnum.values()) { + caches.add(new CaffeineCache(c.name(), + Caffeine.newBuilder().recordStats() + .expireAfterAccess(c.getTtl(), TimeUnit.SECONDS) + .maximumSize(c.getMaxSize()) + .build()) + ); + } + manager.setCaches(caches); + return manager; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/DictionaryCache.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/DictionaryCache.java new file mode 100644 index 00000000..31fef714 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/DictionaryCache.java @@ -0,0 +1,88 @@ +package com.orange.demo.common.core.cache; + +import java.util.List; +import java.util.Set; + +/** + * 主要用于完整缓存字典表数据的接口对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2020-09-25 + */ +public interface DictionaryCache { + + /** + * 按照数据插入的顺序返回全部字典对象的列表。 + * + * @return 全部字段数据列表。 + */ + List getAll(); + + /** + * 获取缓存中与键列表对应的对象列表。 + * + * @param keys 主键集合。 + * @return 对象列表。 + */ + List getInList(Set keys); + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + void putAll(List dataList); + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + void reload(List dataList, boolean force); + + /** + * 从缓存中获取指定的数据。 + * + * @param key 数据的key。 + * @return 获取到的数据,如果没有返回null。 + */ + V get(K key); + + /** + * 将数据存入缓存。 + * + * @param key 通常为字典数据的主键。 + * @param object 字典数据对象。 + */ + void put(K key, V object); + + /** + * 获取缓存中数据条目的数量。 + * + * @return 返回缓存的数据数量。 + */ + int getCount(); + + /** + * 删除缓存中指定的键。 + * + * @param key 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + V invalidate(K key); + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + void invalidateSet(Set keys); + + /** + * 清空缓存。 + */ + void invalidateAll(); +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapDictionaryCache.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapDictionaryCache.java new file mode 100644 index 00000000..431772d9 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapDictionaryCache.java @@ -0,0 +1,176 @@ +package com.orange.demo.common.core.cache; + +import java.util.*; +import java.util.function.Function; + +/** + * 字典数据内存缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2020-09-25 + */ +public class MapDictionaryCache implements DictionaryCache { + + /** + * 存储字典数据的Map。 + */ + protected LinkedHashMap dataMap = new LinkedHashMap<>(); + /** + * 获取字典主键数据的函数对象。 + */ + protected Function idGetter; + + /** + * 当前对象的构造器函数。 + * + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param 字典主键类型。 + * @param 字典对象类型 + * @return 实例化后的字典内存缓存对象。 + */ + public static MapDictionaryCache create(Function idGetter) { + if (idGetter == null) { + throw new IllegalArgumentException("IdGetter can't be NULL."); + } + return new MapDictionaryCache<>(idGetter); + } + + /** + * 构造函数。 + * + * @param idGetter 主键Id的获取函数对象。 + */ + public MapDictionaryCache(Function idGetter) { + this.idGetter = idGetter; + } + + /** + * 按照数据插入的顺序返回全部字典对象的列表。 + * + * @return 全部字段数据列表。 + */ + @Override + public synchronized List getAll() { + List resultList = new LinkedList<>(); + for (Map.Entry entry : dataMap.entrySet()) { + resultList.add(entry.getValue()); + } + return resultList; + } + + /** + * 获取缓存中与键列表对应的对象列表。 + * + * @param keys 主键集合。 + * @return 对象列表。 + */ + @Override + public synchronized List getInList(Set keys) { + List resultList = new LinkedList<>(); + keys.forEach(key -> { + V object = dataMap.get(key); + if (object != null) { + resultList.add(object); + } + }); + return resultList; + } + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + @Override + public synchronized void putAll(List dataList) { + if (dataList == null) { + return; + } + dataList.forEach(dataObj -> { + K id = idGetter.apply(dataObj); + dataMap.put(id, dataObj); + }); + } + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + @Override + public synchronized void reload(List dataList, boolean force) { + if (!force && this.getCount() > 0) { + return; + } + this.invalidateAll(); + this.putAll(dataList); + } + + /** + * 从缓存中获取指定的数据。 + * + * @param id 数据的key。 + * @return 获取到的数据,如果没有返回null。 + */ + @Override + public synchronized V get(K id) { + return id == null ? null : dataMap.get(id); + } + + /** + * 将数据存入缓存。 + * + * @param id 通常为字典数据的主键。 + * @param object 字典数据对象。 + */ + @Override + public synchronized void put(K id, V object) { + dataMap.put(id, object); + } + + /** + * 获取缓存中数据条目的数量。 + * + * @return 返回缓存的数据数量。 + */ + @Override + public synchronized int getCount() { + return dataMap.size(); + } + + /** + * 删除缓存中指定的键。 + * + * @param id 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + @Override + public synchronized V invalidate(K id) { + return id == null ? null : dataMap.remove(id); + } + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + @Override + public synchronized void invalidateSet(Set keys) { + keys.forEach(id -> { + if (id != null) { + dataMap.remove(id); + } + }); + } + + /** + * 清空缓存。 + */ + @Override + public synchronized void invalidateAll() { + dataMap.clear(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapTreeDictionaryCache.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapTreeDictionaryCache.java new file mode 100644 index 00000000..d16d86c3 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/MapTreeDictionaryCache.java @@ -0,0 +1,142 @@ +package com.orange.demo.common.core.cache; + +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; + +import java.util.*; +import java.util.function.Function; + +/** + * 树形字典数据内存缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2020-09-25 + */ +public class MapTreeDictionaryCache extends MapDictionaryCache { + + /** + * 树形数据存储对象。 + */ + private final Multimap allTreeMap = LinkedHashMultimap.create(); + /** + * 获取字典父主键数据的函数对象。 + */ + protected Function parentIdGetter; + + /** + * 当前对象的构造器函数。 + * + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param parentIdGetter 获取当前类父主键字段值的函数对象。 + * @param 字典主键类型。 + * @param 字典对象类型 + * @return 实例化后的树形字典内存缓存对象。 + */ + public static MapTreeDictionaryCache create(Function idGetter, Function parentIdGetter) { + if (idGetter == null) { + throw new IllegalArgumentException("IdGetter can't be NULL."); + } + if (parentIdGetter == null) { + throw new IllegalArgumentException("ParentIdGetter can't be NULL."); + } + return new MapTreeDictionaryCache<>(idGetter, parentIdGetter); + } + + /** + * 构造函数。 + * + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param parentIdGetter 获取当前类父主键字段值的函数对象。 + */ + public MapTreeDictionaryCache(Function idGetter, Function parentIdGetter) { + super(idGetter); + this.parentIdGetter = parentIdGetter; + } + + /** + * 获取该父主键的子数据列表。 + * + * @param parentId 父主键Id。 + * @return 子数据列表。 + */ + public synchronized List getListByParentId(K parentId) { + return new LinkedList<>(allTreeMap.get(parentId)); + } + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + @Override + public synchronized void putAll(List dataList) { + if (dataList == null) { + return; + } + super.putAll(dataList); + dataList.forEach(data -> { + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, data); + allTreeMap.put(parentId, data); + }); + } + + /** + * 将数据存入缓存。 + * + * @param id 通常为字典数据的主键。 + * @param data 字典数据对象。 + */ + @Override + public synchronized void put(K id, V data) { + super.put(id, data); + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, data); + allTreeMap.put(parentId, data); + } + + /** + * 删除缓存中指定的键。 + * + * @param id 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + @Override + public synchronized V invalidate(K id) { + V v = super.invalidate(id); + if (v != null) { + K parentId = parentIdGetter.apply(v); + allTreeMap.remove(parentId, v); + } + return v; + } + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + @Override + public synchronized void invalidateSet(Set keys) { + keys.forEach(id -> { + if (id != null) { + V data = dataMap.remove(id); + if (data != null) { + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, data); + } + } + }); + } + + /** + * 清空缓存。 + */ + @Override + public synchronized void invalidateAll() { + super.invalidateAll(); + allTreeMap.clear(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/SessionCacheHelper.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/SessionCacheHelper.java new file mode 100644 index 00000000..a68212c6 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/cache/SessionCacheHelper.java @@ -0,0 +1,97 @@ +package com.orange.demo.common.core.cache; + +import com.orange.demo.common.core.object.TokenData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.Set; + +/** + * Session数据缓存辅助类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@SuppressWarnings("unchecked") +@Component +public class SessionCacheHelper { + + @Autowired + private CacheManager cacheManager; + + /** + * 缓存当前session内,上传过的文件名。 + * + * @param filename 通常是本地存储的文件名,而不是上传时的原始文件名。 + */ + public void putSessionUploadFile(String filename) { + if (filename != null) { + Set sessionUploadFileSet = null; + Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.UPLOAD_FILENAME_CACHE.name()); + Cache.ValueWrapper valueWrapper = cache.get(TokenData.takeFromRequest().getSessionId()); + if (valueWrapper != null) { + sessionUploadFileSet = (Set) valueWrapper.get(); + } + if (sessionUploadFileSet == null) { + sessionUploadFileSet = new HashSet<>(); + } + sessionUploadFileSet.add(filename); + cache.put(TokenData.takeFromRequest().getSessionId(), sessionUploadFileSet); + } + } + + /** + * 判断参数中的文件名,是否有当前session上传。 + * + * @param filename 通常是本地存储的文件名,而不是上传时的原始文件名。 + * @return true表示该文件是由当前session上传并存储在本地的,否则false。 + */ + public boolean existSessionUploadFile(String filename) { + if (filename == null) { + return false; + } + Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.UPLOAD_FILENAME_CACHE.name()); + Cache.ValueWrapper valueWrapper = cache.get(TokenData.takeFromRequest().getSessionId()); + if (valueWrapper == null) { + return false; + } + return ((Set) valueWrapper.get()).contains(filename); + } + + /** + * 存放session的Token数据。 + * + * @param sessionId 当前会话的SessionId。 + * @param tokenData 当前会话的JWT Token对象。 + */ + public void putTokenData(String sessionId, TokenData tokenData) { + if (sessionId == null || tokenData == null) { + return; + } + Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.GLOBAL_CACHE.name()); + cache.put(sessionId, tokenData); + } + + /** + * 获取session的JWT Token对象。 + * + * @param sessionId 当前会话的SessionId。 + * @return 当前会话的JWT Token对象。 + */ + public TokenData getTokenData(String sessionId) { + Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.GLOBAL_CACHE.name()); + return cache.get(sessionId, TokenData.class); + } + + /** + * 清除当前session的所有缓存数据。 + */ + public void removeAllSessionCache() { + for (CacheConfig.CacheEnum c : CacheConfig.CacheEnum.values()) { + cacheManager.getCache(c.name()).clear(); + } + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/CommonWebMvcConfig.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/CommonWebMvcConfig.java new file mode 100644 index 00000000..1dcec660 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/CommonWebMvcConfig.java @@ -0,0 +1,67 @@ +package com.orange.demo.common.core.config; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import com.orange.demo.common.core.interceptor.MyRequestArgumentResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * 所有的项目拦截器、参数解析器、消息对象转换器都在这里集中配置。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +public class CommonWebMvcConfig implements WebMvcConfigurer { + + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + // 添加MyRequestBody参数解析器 + argumentResolvers.add(new MyRequestArgumentResolver()); + } + + @Bean + public HttpMessageConverter responseBodyConverter() { + return new StringHttpMessageConverter(StandardCharsets.UTF_8); + } + + @Bean + public FastJsonHttpMessageConverter fastJsonHttpMessageConverters() { + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + List supportedMediaTypes = new ArrayList<>(); + supportedMediaTypes.add(MediaType.APPLICATION_JSON); + supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); + fastConverter.setSupportedMediaTypes(supportedMediaTypes); + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures( + SerializerFeature.PrettyFormat, + SerializerFeature.DisableCircularReferenceDetect, + SerializerFeature.IgnoreNonFieldGetter); + fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); + fastConverter.setFastJsonConfig(fastJsonConfig); + return fastConverter; + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(responseBodyConverter()); + converters.add(fastJsonHttpMessageConverters()); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/EncryptConfig.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/EncryptConfig.java new file mode 100644 index 00000000..783bb595 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/EncryptConfig.java @@ -0,0 +1,20 @@ +package com.orange.demo.common.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * 目前用于用户密码加密,UAA接入应用客户端的client_secret加密。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +public class EncryptConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/RestTemplateConfig.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/RestTemplateConfig.java new file mode 100644 index 00000000..8d99aa0c --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/RestTemplateConfig.java @@ -0,0 +1,64 @@ +package com.orange.demo.common.core.config; + +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * RestTemplate连接池配置对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +public class RestTemplateConfig { + private static final int MAX_TOTAL_CONNECTION = 50; + private static final int MAX_CONNECTION_PER_ROUTE = 20; + private static final int CONNECTION_TIMEOUT = 20000; + private static final int READ_TIMEOUT = 30000; + + @Bean + @ConditionalOnMissingBean({RestOperations.class, RestTemplate.class}) + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(createFactory()); + List> messageConverters = restTemplate.getMessageConverters(); + messageConverters.removeIf( + c -> c instanceof StringHttpMessageConverter || c instanceof MappingJackson2HttpMessageConverter); + messageConverters.add(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); + messageConverters.add(new FastJsonHttpMessageConverter()); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + // 防止400+和500等错误被直接抛出异常,这里避开了缺省处理方式,所有的错误均交给业务代码处理。 + } + }); + return restTemplate; + } + + private ClientHttpRequestFactory createFactory() { + HttpClient httpClient = HttpClientBuilder.create() + .setMaxConnTotal(MAX_TOTAL_CONNECTION) + .setMaxConnPerRoute(MAX_CONNECTION_PER_ROUTE) + .build(); + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + factory.setReadTimeout(READ_TIMEOUT); + factory.setConnectTimeout(CONNECTION_TIMEOUT); + return factory; + } +} \ No newline at end of file diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/TomcatConfig.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/TomcatConfig.java new file mode 100644 index 00000000..1171309f --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/config/TomcatConfig.java @@ -0,0 +1,39 @@ +package com.orange.demo.common.core.config; + +import org.apache.tomcat.util.descriptor.web.SecurityCollection; +import org.apache.tomcat.util.descriptor.web.SecurityConstraint; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * tomcat配置对象。当前配置禁用了PUT和DELETE方法,防止渗透攻击。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Configuration +public class TomcatConfig { + + @Bean + public TomcatServletWebServerFactory servletContainer() { + TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); + factory.addContextCustomizers(context -> { + SecurityConstraint securityConstraint = new SecurityConstraint(); + securityConstraint.setUserConstraint("CONFIDENTIAL"); + SecurityCollection collection = new SecurityCollection(); + collection.addPattern("/*"); + collection.addMethod("HEAD"); + collection.addMethod("PUT"); + collection.addMethod("PATCH"); + collection.addMethod("DELETE"); + collection.addMethod("TRACE"); + collection.addMethod("COPY"); + collection.addMethod("SEARCH"); + collection.addMethod("PROPFIND"); + securityConstraint.addCollection(collection); + context.addConstraint(securityConstraint); + }); + return factory; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/AggregationType.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/AggregationType.java new file mode 100644 index 00000000..f95c04c6 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/AggregationType.java @@ -0,0 +1,81 @@ +package com.orange.demo.common.core.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 聚合计算的常量类型对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class AggregationType { + + /** + * sum 计数 + */ + public static final int SUM = 0; + /** + * count 汇总 + */ + public static final int COUNT = 1; + /** + * average 平均值 + */ + public static final int AVG = 2; + /** + * min 最小值 + */ + public static final int MIN = 3; + /** + * max 最大值 + */ + public static final int MAX = 4; + + private static final Map DICT_MAP = new HashMap<>(5); + static { + DICT_MAP.put(0, "累计总和"); + DICT_MAP.put(1, "数量总和"); + DICT_MAP.put(2, "平均值"); + DICT_MAP.put(3, "最小值"); + DICT_MAP.put(4, "最大值"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 获取与SQL对应的聚合函数字符串名称。 + * + * @return 聚合函数名称。 + */ + public static String getAggregationFunction(Integer aggregationType) { + switch (aggregationType) { + case COUNT: + return "COUNT"; + case AVG: + return "AVG"; + case SUM: + return "SUM"; + case MAX: + return "MAX"; + case MIN: + return "MIN"; + default: + throw new IllegalArgumentException("无效的聚合类型!"); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private AggregationType() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/ApplicationConstant.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/ApplicationConstant.java new file mode 100644 index 00000000..7efe88d6 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/ApplicationConstant.java @@ -0,0 +1,55 @@ +package com.orange.demo.common.core.constant; + +/** + * 应用程序的常量声明对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class ApplicationConstant { + + /** + * 图片文件上传的父目录。 + */ + public static final String UPLOAD_IMAGE_PARENT_PATH = "image"; + /** + * 附件文件上传的父目录。 + */ + public static final String UPLOAD_ATTACHMENT_PARENT_PATH = "attachment"; + /** + * CSV文件扩展名。 + */ + public static final String CSV_EXT = "csv"; + /** + * XLSX文件扩展名。 + */ + public static final String XLSX_EXT = "xlsx"; + /** + * 统计分类计算时,按天聚合计算的常量值。(前端在MyOrderParam和MyGroupParam中传给后台) + */ + public static final String DAY_AGGREGATION = "day"; + /** + * 统计分类计算时,按月聚合计算的常量值。(前端在MyOrderParam和MyGroupParam中传给后台) + */ + public static final String MONTH_AGGREGATION = "month"; + /** + * 统计分类计算时,按年聚合计算的常量值。(前端在MyOrderParam和MyGroupParam中传给后台) + */ + public static final String YEAR_AGGREGATION = "year"; + /** + * 请求头跟踪id名。 + */ + public static final String HTTP_HEADER_TRACE_ID = "traceId"; + /** + * 重要说明:该值为项目生成后的缺省密钥,仅为使用户可以快速上手并跑通流程。 + * 在实际的应用中,一定要为不同的项目或服务,自行生成公钥和私钥,并将 PRIVATE_KEY 的引用改为服务的配置项。 + * 密钥的生成方式,可通过执行common.core.util.RsaUtil类的main函数动态生成。 + */ + public static final String PRIVATE_KEY = + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKkLhAydtOtA4WuIkkIIUVaGWu4ElOEAQF9GTulHHWOwCHI1UvcKolvS1G+mdsKcmGtEAQ92AUde/kDRGu8Wn7kLDtCgUfo72soHz7Qfv5pVB4ohMxQd/9cxeKjKbDoirhB9Z3xGF20zUozp4ZPLxpTtI7azr0xzUtd5+D/HfLDrAgMBAAECgYEApESZhDz4YyeAJiPnpJ06lS8oS2VOWzsIUs0av5uoloeoHXtt7Lx7u2kroHeNrl3Hy2yg7ypH4dgQkGHin3VHrVAgjG3TxhgBXIqqntzzk2AGJKBeIIkRX86uTvtKZyp3flUgcwcGmpepAHS1V1DPY3aVYvbcqAmoL6DX6VYN0NECQQDQUitMdC76lEtAr5/ywS0nrZJDo6U7eQ7ywx/eiJ+YmrSye8oorlAj1VBWG+Cl6jdHOHtTQyYv/tu71fjzQiJTAkEAz7wb47/vcSUpNWQxItFpXz0o6rbJh71xmShn1AKP7XptOVZGlW9QRYEzHabV9m/DHqI00cMGhHrWZAhCiTkUCQJAFsJjaJ7o4weAkTieyO7B+CvGZw1h5/V55Jvcx3s1tH5yb22G0Jr6tm9/r2isSnQkReutzZLwgR3e886UvD7lcQJAAUcD2OOuQkDbPwPNtYwaHMbQgJj9JkOI9kskUE5vuiMdltOr/XFAyhygRtdmy2wmhAK1VnDfkmL6/IR8fEGImQJABOB0KCalb0M8CPnqqHzozrD8gPObnIIr4aVvLIPATN2g7MM2N6F7JbI4RZFiKa92LV6bhQCY8OvHi5K2cgFpbw=="; + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ApplicationConstant() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/ErrorCodeEnum.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/ErrorCodeEnum.java new file mode 100644 index 00000000..5e928b58 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/ErrorCodeEnum.java @@ -0,0 +1,78 @@ +package com.orange.demo.common.core.constant; + +/** + * 返回应答中的错误代码和错误信息。 + * + * @author Jerry + * @date 2020-09-25 + */ +public enum ErrorCodeEnum { + + /** + * 没有错误 + */ + NO_ERROR("没有错误"), + /** + * 未处理的异常! + */ + UNHANDLED_EXCEPTION("未处理的异常!"), + + ARGUMENT_NULL_EXIST("数据验证失败,接口调用参数存在空值,请核对!"), + ARGUMENT_PK_ID_NULL("数据验证失败,接口调用主键Id参数为空,请核对!"), + INVALID_ARGUMENT_FORMAT("数据验证失败,不合法的参数格式,请核对!"), + INVALID_STATUS_ARGUMENT("数据验证失败,无效的状态参数值,请核对!"), + INVALID_UPLOAD_FILE_ARGUMENT("数据验证失败,上传文件参数错误,请核对!"), + INVALID_UPLOAD_FILE_IOERROR("上传文件写入失败,请联系管理员!"), + UNAUTHORIZED_LOGIN("当前用户尚未登录或登录已超时,请重新登录!"), + UNAUTHORIZED_USER_PERMISSION("权限验证失败,当前用户不能访问该接口,请核对!"), + NO_ACCESS_PERMISSION("当前用户没有访问权限,请核对!"), + NO_OPERATION_PERMISSION("当前用户没有操作权限,请核对!"), + + PASSWORD_ERR("密码错误,请重试!"), + INVALID_USERNAME_PASSWORD("用户名或密码错误,请重试!"), + INVALID_ACCESS_TOKEN("无效的用户访问令牌!"), + INVALID_USER_STATUS("用户状态错误,请刷新后重试!"), + + HAS_CHILDREN_DATA("数据验证失败,子数据存在,请刷新后重试!"), + DATA_VALIDATAED_FAILED("数据验证失败,请核对!"), + UPLOAD_FILE_FAILED("文件上传失败,请联系管理员!"), + DATA_SAVE_FAILED("数据保存失败,请联系管理员!"), + DATA_ACCESS_FAILED("数据访问失败,请联系管理员!"), + DATA_PERM_ACCESS_FAILED("数据访问失败,您没有该页面的数据访问权限!"), + DUPLICATED_UNIQUE_KEY("数据保存失败,存在重复数据,请核对!"), + DATA_NOT_EXIST("数据不存在,请刷新后重试!"), + DATA_PARENT_LEVEL_ID_NOT_EXIST("数据验证失败,父级别关联Id不存在,请刷新后重试!"), + DATA_PARENT_ID_NOT_EXIST("数据验证失败,ParentId不存在,请核对!"), + INVALID_RELATED_RECORD_ID("数据验证失败,关联数据并不存在,请刷新后重试!"), + INVALID_DATA_MODEL("数据验证失败,无效的数据实体对象!"), + INVALID_DATA_FIELD("数据验证失败,无效的数据实体对象字段!"), + INVALID_CLASS_FIELD("数据验证失败,无效的类对象字段!"), + SERVER_INTERNAL_ERROR("服务器内部错误,请联系管理员!"), + REDIS_CACHE_ACCESS_TIMEOUT("Redis缓存数据访问超时,请刷新后重试!"), + REDIS_CACHE_ACCESS_STATE_ERROR("Redis缓存数据访问状态错误,请刷新后重试!"); + + // 下面的枚举值为特定枚举值,即开发者可以根据自己的项目需求定义更多的非通用枚举值 + + /** + * 构造函数。 + * + * @param errorMessage 错误消息。 + */ + ErrorCodeEnum(String errorMessage) { + this.errorMessage = errorMessage; + } + + /** + * 错误信息。 + */ + private String errorMessage; + + /** + * 获取错误信息。 + * + * @return 错误信息。 + */ + public String getErrorMessage() { + return errorMessage; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/GlobalDeletedFlag.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/GlobalDeletedFlag.java new file mode 100644 index 00000000..cac588a4 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/constant/GlobalDeletedFlag.java @@ -0,0 +1,25 @@ +package com.orange.demo.common.core.constant; + +/** + * 数据记录逻辑删除标记常量。 + * + * @author Jerry + * @date 2020-09-25 + */ +public final class GlobalDeletedFlag { + + /** + * 表示数据表记录已经删除 + */ + public static final int DELETED = -1; + /** + * 数据记录正常 + */ + public static final int NORMAL = 1; + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private GlobalDeletedFlag() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/DataValidationException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/DataValidationException.java new file mode 100644 index 00000000..c7fb997c --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/DataValidationException.java @@ -0,0 +1,26 @@ +package com.orange.demo.common.core.exception; + +/** + * 数据验证失败的自定义异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class DataValidationException extends RuntimeException { + + /** + * 构造函数。 + */ + public DataValidationException() { + + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public DataValidationException(String msg) { + super(msg); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidClassFieldException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidClassFieldException.java new file mode 100644 index 00000000..97a9a7b6 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidClassFieldException.java @@ -0,0 +1,30 @@ +package com.orange.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的类对象字段的自定义异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidClassFieldException extends RuntimeException { + + private final String className; + private final String fieldName; + + /** + * 构造函数。 + * + * @param className 对象名。 + * @param fieldName 字段名。 + */ + public InvalidClassFieldException(String className, String fieldName) { + super("Invalid FieldName [" + fieldName + "] in Class [" + className + "]."); + this.className = className; + this.fieldName = fieldName; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataFieldException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataFieldException.java new file mode 100644 index 00000000..0f7df706 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataFieldException.java @@ -0,0 +1,30 @@ +package com.orange.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的实体对象字段的自定义异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidDataFieldException extends RuntimeException { + + private final String modelName; + private final String fieldName; + + /** + * 构造函数。 + * + * @param modelName 实体对象名。 + * @param fieldName 字段名。 + */ + public InvalidDataFieldException(String modelName, String fieldName) { + super("Invalid FieldName [" + fieldName + "] in Model Class [" + modelName + "]."); + this.modelName = modelName; + this.fieldName = fieldName; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataModelException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataModelException.java new file mode 100644 index 00000000..71de86e9 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/InvalidDataModelException.java @@ -0,0 +1,27 @@ +package com.orange.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的实体对象的自定义异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidDataModelException extends RuntimeException { + + private final String modelName; + + /** + * 构造函数。 + * + * @param modelName 实体对象名。 + */ + public InvalidDataModelException(String modelName) { + super("Invalid Model Class [" + modelName + "]."); + this.modelName = modelName; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/MyRuntimeException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/MyRuntimeException.java new file mode 100644 index 00000000..46c15640 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/MyRuntimeException.java @@ -0,0 +1,36 @@ +package com.orange.demo.common.core.exception; + +/** + * 自定义的运行时异常,在需要抛出运行时异常时,可使用该异常。 + * NOTE:主要是为了避免SonarQube进行代码质量扫描时,给出警告。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class MyRuntimeException extends RuntimeException { + + /** + * 构造函数。 + */ + public MyRuntimeException() { + + } + + /** + * 构造函数。 + * + * @param throwable 引发异常对象。 + */ + public MyRuntimeException(Throwable throwable) { + super(throwable); + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public MyRuntimeException(String msg) { + super(msg); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataAffectException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataAffectException.java new file mode 100644 index 00000000..37364f7f --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataAffectException.java @@ -0,0 +1,26 @@ +package com.orange.demo.common.core.exception; + +/** + * 没有数据被修改的自定义异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class NoDataAffectException extends RuntimeException { + + /** + * 构造函数。 + */ + public NoDataAffectException() { + + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public NoDataAffectException(String msg) { + super(msg); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataPermException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataPermException.java new file mode 100644 index 00000000..8f0a3c8b --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/NoDataPermException.java @@ -0,0 +1,26 @@ +package com.orange.demo.common.core.exception; + +/** + * 没有数据访问权限的自定义异常。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class NoDataPermException extends RuntimeException { + + /** + * 构造函数。 + */ + public NoDataPermException() { + + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public NoDataPermException(String msg) { + super(msg); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/RedisCacheAccessException.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/RedisCacheAccessException.java new file mode 100644 index 00000000..793c524f --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/exception/RedisCacheAccessException.java @@ -0,0 +1,20 @@ +package com.orange.demo.common.core.exception; + +/** + * Redis缓存访问失败。比如:获取分布式数据锁超时、等待线程中断等。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class RedisCacheAccessException extends RuntimeException { + + /** + * 构造函数。 + * + * @param msg 错误信息。 + * @param cause 原始异常。 + */ + public RedisCacheAccessException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/interceptor/MyRequestArgumentResolver.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/interceptor/MyRequestArgumentResolver.java new file mode 100644 index 00000000..406111c0 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/interceptor/MyRequestArgumentResolver.java @@ -0,0 +1,226 @@ +package com.orange.demo.common.core.interceptor; + +import cn.hutool.core.convert.Convert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.orange.demo.common.core.annotation.MyRequestBody; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.util.*; + +/** + * MyRequestBody解析器 + * 解决的问题: + * 1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收; + * 2、多个对象需要封装到一个对象里才可以用@RequestBody接收。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class MyRequestArgumentResolver implements HandlerMethodArgumentResolver { + + private static final String JSONBODY_ATTRIBUTE = "MY_REQUEST_BODY_ATTRIBUTE_XX"; + + private static Set> classSet = new HashSet<>(); + + static { + classSet.add(Integer.class); + classSet.add(Long.class); + classSet.add(Short.class); + classSet.add(Float.class); + classSet.add(Double.class); + classSet.add(Boolean.class); + classSet.add(Byte.class); + classSet.add(Character.class); + } + + /** + * 设置支持的方法参数类型。 + * + * @param parameter 方法参数。 + * @return 支持的类型。 + */ + @Override + public boolean supportsParameter(@NonNull MethodParameter parameter) { + return parameter.hasParameterAnnotation(MyRequestBody.class); + } + + /** + * 参数解析,利用fastjson。 + * 注意:非基本类型返回null会报空指针异常,要通过反射或者JSON工具类创建一个空对象。 + */ + @Override + public Object resolveArgument( + @NonNull MethodParameter parameter, + ModelAndViewContainer mavContainer, + @NonNull NativeWebRequest webRequest, + WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + String contentType = servletRequest.getContentType(); + if (!HttpMethod.POST.name().equals(servletRequest.getMethod())) { + throw new IllegalArgumentException("Only POST method can be applied @MyRequestBody annotation!"); + } + if (!StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { + throw new IllegalArgumentException( + "Only application/json Content-Type can be applied @MyRequestBody annotation!"); + } + // 根据@MyRequestBody注解value作为json解析的key + MyRequestBody parameterAnnotation = parameter.getParameterAnnotation(MyRequestBody.class); + JSONObject jsonObject = getRequestBody(webRequest); + if (jsonObject == null) { + if (parameterAnnotation.required()) { + throw new IllegalArgumentException("Request Body is EMPTY!"); + } + return null; + } + String key = parameterAnnotation.value(); + if (StringUtils.isBlank(key)) { + key = parameter.getParameterName(); + } + Object value = jsonObject.get(key); + if (value == null) { + if (parameterAnnotation.required()) { + throw new IllegalArgumentException(String.format("Required parameter %s is not present!", key)); + } + return null; + } + // 获取参数类型。 + Class parameterType = parameter.getParameterType(); + //基本类型 + if (parameterType.isPrimitive()) { + return parsePrimitive(parameterType.getName(), value); + } + // 基本类型包装类 + if (isBasicDataTypes(parameterType)) { + return parseBasicTypeWrapper(parameterType, value); + } else if (parameterType == String.class) { + // 字符串类型 + return value.toString(); + } + // 数组类型 + if (value instanceof JSONArray) { + return parseArray(parameterType, parameterAnnotation.elementType(), key, value); + } + // 其他复杂对象 + return JSON.toJavaObject((JSONObject) value, parameterType); + } + + @SuppressWarnings("unchecked") + private Object parseArray(Class parameterType, Class elementType, String key, Object value) + throws IllegalAccessException, InstantiationException { + Object o; + if (!parameterType.equals(List.class)) { + o = parameterType.newInstance(); + parameterType = (Class) ((ParameterizedType) + parameterType.getGenericSuperclass()).getActualTypeArguments()[0]; + } else { + parameterType = elementType; + if (parameterType.equals(Class.class)) { + throw new IllegalArgumentException( + String.format("List Type parameter %s MUST have elementType!", key)); + } + o = new LinkedList<>(); + } + if (!(o instanceof List)) { + throw new IllegalArgumentException(String.format("Required parameter %s is List!", key)); + } + ((List) o).addAll(((JSONArray) value).toJavaList(parameterType)); + return o; + } + + private Object parsePrimitive(String parameterTypeName, Object value) { + final String booleanTypeName = "boolean"; + if (booleanTypeName.equals(parameterTypeName)) { + return Boolean.valueOf(value.toString()); + } + final String intTypeName = "int"; + if (intTypeName.equals(parameterTypeName)) { + return Integer.valueOf(value.toString()); + } + final String charTypeName = "char"; + if (charTypeName.equals(parameterTypeName)) { + return value.toString().charAt(0); + } + final String shortTypeName = "short"; + if (shortTypeName.equals(parameterTypeName)) { + return Short.valueOf(value.toString()); + } + final String longTypeName = "long"; + if (longTypeName.equals(parameterTypeName)) { + return Long.valueOf(value.toString()); + } + final String floatTypeName = "float"; + if (floatTypeName.equals(parameterTypeName)) { + return Float.valueOf(value.toString()); + } + final String doubleTypeName = "double"; + if (doubleTypeName.equals(parameterTypeName)) { + return Double.valueOf(value.toString()); + } + final String byteTypeName = "byte"; + if (byteTypeName.equals(parameterTypeName)) { + return Byte.valueOf(value.toString()); + } + return null; + } + + private Object parseBasicTypeWrapper(Class parameterType, Object value) { + if (Number.class.isAssignableFrom(parameterType)) { + if (value instanceof String) { + return Convert.convert(parameterType, value); + } + Number number = (Number) value; + if (parameterType == Integer.class) { + return number.intValue(); + } else if (parameterType == Short.class) { + return number.shortValue(); + } else if (parameterType == Long.class) { + return number.longValue(); + } else if (parameterType == Float.class) { + return number.floatValue(); + } else if (parameterType == Double.class) { + return number.doubleValue(); + } else if (parameterType == Byte.class) { + return number.byteValue(); + } + } else if (parameterType == Boolean.class) { + return value.toString(); + } else if (parameterType == Character.class) { + return value.toString().charAt(0); + } + return null; + } + + private boolean isBasicDataTypes(Class clazz) { + return classSet.contains(clazz); + } + + private JSONObject getRequestBody(NativeWebRequest webRequest) throws IOException { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + // 有就直接获取 + JSONObject jsonObject = (JSONObject) webRequest.getAttribute(JSONBODY_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); + // 没有就从请求中读取 + if (jsonObject == null) { + String jsonBody = IOUtils.toString(servletRequest.getReader()); + jsonObject = JSON.parseObject(jsonBody); + if (jsonObject != null) { + webRequest.setAttribute(JSONBODY_ATTRIBUTE, jsonObject, RequestAttributes.SCOPE_REQUEST); + } + } + return jsonObject; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadCachedDataListener.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadCachedDataListener.java new file mode 100644 index 00000000..ca9611bf --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadCachedDataListener.java @@ -0,0 +1,28 @@ +package com.orange.demo.common.core.listener; + +import com.orange.demo.common.core.base.service.BaseDictService; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 应用程序启动后的事件监听对象。主要负责加载Model之间的字典关联和一对一关联所对应的Service结构关系。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Component +public class LoadCachedDataListener implements ApplicationListener { + + @SuppressWarnings("all") + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + Map serviceMap = + applicationReadyEvent.getApplicationContext().getBeansOfType(BaseDictService.class); + for (Map.Entry e : serviceMap.entrySet()) { + e.getValue().loadCachedData(); + } + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadServiceRelationListener.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadServiceRelationListener.java new file mode 100644 index 00000000..3be64d6b --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/listener/LoadServiceRelationListener.java @@ -0,0 +1,28 @@ +package com.orange.demo.common.core.listener; + +import com.orange.demo.common.core.base.service.BaseService; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 应用程序启动后的事件监听对象。主要负责加载Model之间的字典关联和一对一关联所对应的Service结构关系。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Component +public class LoadServiceRelationListener implements ApplicationListener { + + @SuppressWarnings("all") + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + Map serviceMap = + applicationReadyEvent.getApplicationContext().getBeansOfType(BaseService.class); + for (Map.Entry e : serviceMap.entrySet()) { + e.getValue().loadRelationStruct(); + } + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/CallResult.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/CallResult.java new file mode 100644 index 00000000..37fbbb2b --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/CallResult.java @@ -0,0 +1,87 @@ +package com.orange.demo.common.core.object; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +/** + * 接口数据验证结果对象。主要是Service类使用。 + * 同时为了提升效率,减少查询次数,可以根据具体的需求,将部分验证关联对象存入data字段,以供Controller使用。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +public class CallResult { + + /** + * 为了优化性能,所有没有携带数据的正确结果,均可用该对象表示。 + */ + private static final CallResult OK = new CallResult(); + /** + * 是否成功标记。 + */ + private boolean success = true; + /** + * 错误信息描述。 + */ + private String errorMessage = null; + /** + * 在验证同时,仍然需要附加的关联数据对象。 + */ + private JSONObject data; + + /** + * 创建验证结果对象。 + * + * @param errorMessage 错误描述信息。 + * @return 如果参数为空,表示成功,否则返回代码错误信息的错误对象实例。 + */ + public static CallResult create(String errorMessage) { + return errorMessage == null ? ok() : error(errorMessage); + } + + /** + * 创建验证结果对象。 + * + * @param errorMessage 错误描述信息。 + * @param data 附带的数据对象。 + * @return 如果参数为空,表示成功,否则返回代码错误信息的错误对象实例。 + */ + public static CallResult create(String errorMessage, JSONObject data) { + return errorMessage == null ? ok(data) : error(errorMessage); + } + + /** + * 创建表示验证成功的对象实例。 + * + * @return 验证成功对象实例。 + */ + public static CallResult ok() { + return OK; + } + + /** + * 创建表示验证成功的对象实例。 + * + * @param data 附带的数据对象。 + * @return 验证成功对象实例。 + */ + public static CallResult ok(JSONObject data) { + CallResult result = new CallResult(); + result.data = data; + return result; + } + + /** + * 创建表示验证失败的对象实例。 + * + * @param errorMessage 错误描述。 + * @return 验证失败对象实例。 + */ + public static CallResult error(String errorMessage) { + CallResult result = new CallResult(); + result.success = false; + result.errorMessage = errorMessage; + return result; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupCriteria.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupCriteria.java new file mode 100644 index 00000000..ff71ebe3 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupCriteria.java @@ -0,0 +1,24 @@ +package com.orange.demo.common.core.object; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Mybatis Mapper.xml中所需的分组条件对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@AllArgsConstructor +public class MyGroupCriteria { + + /** + * GROUP BY 从句后面的参数。 + */ + private String groupBy; + /** + * SELECT 从句后面的分组显示字段。 + */ + private String groupSelect; +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupParam.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupParam.java new file mode 100644 index 00000000..33465285 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyGroupParam.java @@ -0,0 +1,168 @@ +package com.orange.demo.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.exception.InvalidClassFieldException; +import com.orange.demo.common.core.exception.InvalidDataFieldException; +import com.orange.demo.common.core.exception.InvalidDataModelException; +import com.orange.demo.common.core.util.MyModelUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 查询分组参数请求对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Data +public class MyGroupParam extends ArrayList { + + /** + * SQL语句的SELECT LIST中,分组字段的返回字段名称列表。 + */ + private List selectGroupFieldList; + + /** + * 分组参数解析后构建的SQL语句中所需的分组数据,如GROUP BY的字段列表和SELECT LIST中的分组字段显示列表。 + */ + private MyGroupCriteria groupCriteria; + /** + * 基于分组参数对象中的数据,构建SQL中select list和group by从句可以直接使用的分组对象。 + * + * @param groupParam 分组参数对象。 + * @param modelClazz 查询表对应的主对象的Class。 + * @return SQL中所需的GROUP对象。详见MyGroupCriteria类定义。 + */ + public static MyGroupParam buildGroupBy(MyGroupParam groupParam, Class modelClazz) { + if (groupParam == null) { + return null; + } + if (modelClazz == null) { + throw new IllegalArgumentException("modelClazz Argument can't be NULL"); + } + groupParam.selectGroupFieldList = new LinkedList<>(); + StringBuilder groupByBuilder = new StringBuilder(128); + StringBuilder groupSelectBuilder = new StringBuilder(128); + int i = 0; + for (GroupInfo groupInfo : groupParam) { + GroupBaseData groupBaseData = parseGroupBaseData(groupInfo, modelClazz); + if (StringUtils.isBlank(groupBaseData.tableName)) { + throw new InvalidDataModelException(groupBaseData.modelName); + } + if (StringUtils.isBlank(groupBaseData.columnName)) { + throw new InvalidDataFieldException(groupBaseData.modelName, groupBaseData.fieldName); + } + processGroupInfo(groupInfo, groupBaseData, groupByBuilder, groupSelectBuilder); + String aliasName = StringUtils.isBlank(groupInfo.aliasName) ? groupInfo.fieldName : groupInfo.aliasName; + // selectGroupFieldList中的元素,目前只是被export操作使用。会根据集合中的元素名称匹配导出表头。 + groupParam.selectGroupFieldList.add(aliasName); + if (++i < groupParam.size()) { + groupByBuilder.append(", "); + groupSelectBuilder.append(", "); + } + } + groupParam.groupCriteria = new MyGroupCriteria(groupByBuilder.toString(), groupSelectBuilder.toString()); + return groupParam; + } + + private static GroupBaseData parseGroupBaseData(GroupInfo groupInfo, Class modelClazz) { + GroupBaseData baseData = new GroupBaseData(); + String[] stringArray = StringUtils.split(groupInfo.fieldName,'.'); + if (stringArray.length == 1) { + baseData.modelName = modelClazz.getSimpleName(); + baseData.fieldName = groupInfo.fieldName; + baseData.tableName = MyModelUtil.mapToTableName(modelClazz); + baseData.columnName = MyModelUtil.mapToColumnName(groupInfo.fieldName, modelClazz); + } else { + Field field = ReflectUtil.getField(modelClazz, stringArray[0]); + if (field == null) { + throw new InvalidClassFieldException(modelClazz.getSimpleName(), stringArray[0]); + } + Class fieldClazz = field.getType(); + baseData.modelName = fieldClazz.getSimpleName(); + baseData.fieldName = stringArray[1]; + baseData.tableName = MyModelUtil.mapToTableName(fieldClazz); + baseData.columnName = MyModelUtil.mapToColumnName(baseData.fieldName, fieldClazz); + } + return baseData; + } + + private static void processGroupInfo( + GroupInfo groupInfo, + GroupBaseData baseData, + StringBuilder groupByBuilder, + StringBuilder groupSelectBuilder) { + String tableName = baseData.tableName; + String columnName = baseData.columnName; + if (StringUtils.isNotBlank(groupInfo.dateAggregateBy)) { + groupByBuilder.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + groupSelectBuilder.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + if (ApplicationConstant.DAY_AGGREGATION.equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-%m-%d')"); + groupSelectBuilder.append(", '%Y-%m-%d')"); + } else if (ApplicationConstant.MONTH_AGGREGATION.equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-%m-01')"); + groupSelectBuilder.append(", '%Y-%m-01')"); + } else if (ApplicationConstant.YEAR_AGGREGATION.equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-01-01')"); + groupSelectBuilder.append(", '%Y-01-01')"); + } else { + throw new IllegalArgumentException("Illegal DATE_FORMAT for GROUP ID list."); + } + if (StringUtils.isNotBlank(groupInfo.aliasName)) { + groupSelectBuilder.append(" ").append(groupInfo.aliasName); + } else { + groupSelectBuilder.append(" ").append(columnName); + } + } else { + groupByBuilder.append(tableName).append(".").append(columnName); + groupSelectBuilder.append(tableName).append(".").append(columnName); + if (StringUtils.isNotBlank(groupInfo.aliasName)) { + groupSelectBuilder.append(" ").append(groupInfo.aliasName); + } + } + } + + /** + * 分组信息对象。 + */ + @Data + public static class GroupInfo { + /** + * Java对象的字段名。目前主要包含三种格式: + * 1. 简单的属性名称,如userId,将会直接映射到与其关联的数据库字段。表名为当前ModelClazz所对应的表名。 + * 映射结果或为 my_main_table.user_id + * 2. 一对一关联表属性,如user.userId,这里将先获取user属性的对象类型并映射到对应的表名,后面的userId为 + * user所在实体的属性。映射结果或为:my_sys_user.user_id + */ + private String fieldName; + /** + * SQL语句的Select List中,分组字段的别名。如果别名为NULL,直接取fieldName。 + */ + private String aliasName; + /** + * 如果该值不为NULL,则会对分组字段进行DATE_FORMAT函数的计算,并根据具体的值,将日期数据截取到指定的位。 + * day: 表示按照天聚合,将会截取到天。DATE_FORMAT(columnName, '%Y-%m-%d') + * month: 表示按照月聚合,将会截取到月。DATE_FORMAT(columnName, '%Y-%m-01') + * year: 表示按照年聚合,将会截取到年。DATE_FORMAT(columnName, '%Y-01-01') + */ + private String dateAggregateBy; + } + + private static class GroupBaseData { + private String modelName; + private String fieldName; + private String tableName; + private String columnName; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyOrderParam.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyOrderParam.java new file mode 100644 index 00000000..e8bcc8c5 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyOrderParam.java @@ -0,0 +1,258 @@ +package com.orange.demo.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.exception.InvalidClassFieldException; +import com.orange.demo.common.core.exception.InvalidDataFieldException; +import com.orange.demo.common.core.exception.InvalidDataModelException; +import com.orange.demo.common.core.util.MyModelUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * Controller参数中的排序请求对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Data +public class MyOrderParam extends ArrayList { + + private static final String DICT_MAP = "DictMap."; + /** + * 基于排序对象中的JSON数据,构建SQL中order by从句可以直接使用的排序字符串。 + * + * @param orderParam 排序参数对象。 + * @param modelClazz 查询主表对应的主对象的Class。 + * @return SQL中order by从句可以直接使用的排序字符串。 + */ + public static String buildOrderBy(MyOrderParam orderParam, Class modelClazz) { + if (orderParam == null) { + return null; + } + if (modelClazz == null) { + throw new IllegalArgumentException( + "modelClazz Argument in MyOrderParam.buildOrderBy can't be NULL"); + } + int i = 0; + StringBuilder orderBy = new StringBuilder(128); + for (OrderInfo orderInfo : orderParam) { + OrderBaseData orderBaseData = parseOrderBaseData(orderInfo, modelClazz); + if (StringUtils.isBlank(orderBaseData.tableName)) { + throw new InvalidDataModelException(orderBaseData.modelName); + } + if (StringUtils.isBlank(orderBaseData.columnName)) { + throw new InvalidDataFieldException(orderBaseData.modelName, orderBaseData.fieldName); + } + processOrderInfo(orderInfo, orderBaseData, orderBy); + if (++i < orderParam.size()) { + orderBy.append(", "); + } + } + return orderBy.toString(); + } + + private static void processOrderInfo( + OrderInfo orderInfo, OrderBaseData orderBaseData, StringBuilder orderByBuilder) { + if (StringUtils.isNotBlank(orderInfo.dateAggregateBy)) { + orderByBuilder.append("DATE_FORMAT(") + .append(orderBaseData.tableName).append(".").append(orderBaseData.columnName); + if (ApplicationConstant.DAY_AGGREGATION.equals(orderInfo.dateAggregateBy)) { + orderByBuilder.append(", '%Y-%m-%d')"); + } else if (ApplicationConstant.MONTH_AGGREGATION.equals(orderInfo.dateAggregateBy)) { + orderByBuilder.append(", '%Y-%m-01')"); + } else if (ApplicationConstant.YEAR_AGGREGATION.equals(orderInfo.dateAggregateBy)) { + orderByBuilder.append(", '%Y-01-01')"); + } else { + throw new IllegalArgumentException("Illegal DATE_FORMAT for GROUP ID list."); + } + } else { + orderByBuilder.append(orderBaseData.tableName).append(".").append(orderBaseData.columnName); + } + if (orderInfo.asc != null && !orderInfo.asc) { + orderByBuilder.append(" DESC"); + } + } + + private static OrderBaseData parseOrderBaseData(OrderInfo orderInfo, Class modelClazz) { + OrderBaseData orderBaseData = new OrderBaseData(); + orderBaseData.fieldName = StringUtils.substringBefore(orderInfo.fieldName, DICT_MAP); + String[] stringArray = StringUtils.split(orderBaseData.fieldName, '.'); + if (stringArray.length == 1) { + orderBaseData.modelName = modelClazz.getSimpleName(); + orderBaseData.tableName = MyModelUtil.mapToTableName(modelClazz); + orderBaseData.columnName = MyModelUtil.mapToColumnName(orderBaseData.fieldName, modelClazz); + } else { + Field field = ReflectUtil.getField(modelClazz, stringArray[0]); + if (field == null) { + throw new InvalidClassFieldException(modelClazz.getSimpleName(), stringArray[0]); + } + Class fieldClazz = field.getType(); + orderBaseData.modelName = fieldClazz.getSimpleName(); + orderBaseData.fieldName = stringArray[1]; + orderBaseData.tableName = MyModelUtil.mapToTableName(fieldClazz); + orderBaseData.columnName = MyModelUtil.mapToColumnName(orderBaseData.fieldName, fieldClazz); + } + return orderBaseData; + } + + /** + * 在排序列表中,可能存在基于指定表字段的排序,该函数将获取指定表的所有排序字段。 + * 返回的字符串,可直接用于SQL中的ORDER BY从句。 + * + * @param orderParam 排序参数对象。 + * @param modelClazz 查询主表对应的主对象的Class。 + * @param relationModelName 与关联表对应的Model的名称,如my_course_paper表应对的Java对象CoursePaper。 + * 如果该值为null或空字符串,则获取所有主表的排序字段。 + * @return 返回的是表字段,而非Java对象的属性,多个字段之间逗号分隔。 + */ + public static String getOrderClauseByModelName( + MyOrderParam orderParam, Class modelClazz, String relationModelName) { + if (orderParam == null) { + return null; + } + if (modelClazz == null) { + throw new IllegalArgumentException( + "modelClazz Argument in MyOrderParam.getOrderClauseByModelName can't be NULL"); + } + List fieldNameList = new LinkedList<>(); + String prefix = null; + if (StringUtils.isNotBlank(relationModelName)) { + prefix = relationModelName + "."; + } + for (OrderInfo orderInfo : orderParam) { + OrderBaseData baseData = parseOrderBaseData(orderInfo, modelClazz, prefix, relationModelName); + if (baseData != null) { + fieldNameList.add(makeOrderBy(baseData, orderInfo.asc)); + } + } + return StringUtils.join(fieldNameList, ", "); + } + + private static OrderBaseData parseOrderBaseData( + OrderInfo orderInfo, Class modelClazz, String prefix, String relationModelName) { + OrderBaseData baseData = null; + String fieldName = StringUtils.substringBefore(orderInfo.fieldName, DICT_MAP); + if (prefix != null) { + if (fieldName.startsWith(prefix)) { + baseData = new OrderBaseData(); + Field field = ReflectUtil.getField(modelClazz, relationModelName); + if (field == null) { + throw new InvalidClassFieldException(modelClazz.getSimpleName(), relationModelName); + } + Class fieldClazz = field.getType(); + baseData.modelName = fieldClazz.getSimpleName(); + baseData.fieldName = StringUtils.removeStart(fieldName, prefix); + baseData.tableName = MyModelUtil.mapToTableName(fieldClazz); + baseData.columnName = MyModelUtil.mapToColumnName(fieldName, fieldClazz); + } + } else { + String dotLimitor = "."; + if (!fieldName.contains(dotLimitor)) { + baseData = new OrderBaseData(); + baseData.modelName = modelClazz.getSimpleName(); + baseData.tableName = MyModelUtil.mapToTableName(modelClazz); + baseData.columnName = MyModelUtil.mapToColumnName(fieldName, modelClazz); + } + } + return baseData; + } + + private static String makeOrderBy(OrderBaseData baseData, Boolean asc) { + if (StringUtils.isBlank(baseData.tableName)) { + throw new InvalidDataModelException(baseData.modelName); + } + if (StringUtils.isBlank(baseData.columnName)) { + throw new InvalidDataFieldException(baseData.modelName, baseData.fieldName); + } + StringBuilder orderBy = new StringBuilder(128); + orderBy.append(baseData.tableName).append(".").append(baseData.columnName); + if (asc != null && !asc) { + orderBy.append(" DESC"); + } + return orderBy.toString(); + } + + /** + * 在排序列表中,可能存在基于指定表字段的排序,该函数将删除指定表的所有排序字段。 + * + * @param orderParam 排序参数对象。 + * @param modelClazz 查询主表对应的主对象的Class。 + * @param relationModelName 与关联表对应的Model的名称,如my_course_paper表应对的Java对象CoursePaper。 + * 如果该值为null或空字符串,则获取所有主表的排序字段。 + */ + public static void removeOrderClauseByModelName( + MyOrderParam orderParam, Class modelClazz, String relationModelName) { + if (orderParam == null) { + return; + } + if (modelClazz == null) { + throw new IllegalArgumentException( + "modelClazz Argument in MyOrderParam.removeOrderClauseByModelName can't be NULL"); + } + List fieldIndexList = new LinkedList<>(); + String prefix = null; + if (StringUtils.isNotBlank(relationModelName)) { + prefix = relationModelName + "."; + } + int i = 0; + for (OrderInfo orderInfo : orderParam) { + String fieldName = StringUtils.substringBefore(orderInfo.fieldName, DICT_MAP); + if (prefix != null) { + if (fieldName.startsWith(prefix)) { + fieldIndexList.add(i); + } + } else { + if (!fieldName.contains(".")) { + fieldIndexList.add(i); + } + } + ++i; + } + for (int index : fieldIndexList) { + orderParam.remove(index); + } + } + + /** + * 排序信息对象。 + */ + @Data + public static class OrderInfo { + /** + * Java对象的字段名。目前主要包含三种格式: + * 1. 简单的属性名称,如userId,将会直接映射到与其关联的数据库字段。表名为当前ModelClazz所对应的表名。 + * 映射结果或为 my_main_table.user_id + * 2. 字典属性名称,如userIdDictMap.id,由于仅仅支持字典中Id数据的排序,所以直接截取DictMap之前的字符串userId作为排序属性。 + * 表名为当前ModelClazz所对应的表名。映射结果或为 my_main_table.user_id + * 3. 一对一关联表属性,如user.userId,这里将先获取user属性的对象类型并映射到对应的表名,后面的userId为 + * user所在实体的属性。映射结果或为:my_sys_user.user_id + */ + private String fieldName; + /** + * 排序方向。true为升序,否则降序。 + */ + private Boolean asc = true; + /** + * 如果该值不为NULL,则会对日期型排序字段进行DATE_FORMAT函数的计算,并根据具体的值,将日期数据截取到指定的位。 + * day: 表示按照天聚合,将会截取到天。DATE_FORMAT(columnName, '%Y-%m-%d') + * month: 表示按照月聚合,将会截取到月。DATE_FORMAT(columnName, '%Y-%m-01') + * year: 表示按照年聚合,将会截取到年。DATE_FORMAT(columnName, '%Y-01-01') + */ + private String dateAggregateBy; + } + + private static class OrderBaseData { + private String modelName; + private String fieldName; + private String tableName; + private String columnName; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyPageParam.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyPageParam.java new file mode 100644 index 00000000..0e97be67 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyPageParam.java @@ -0,0 +1,58 @@ +package com.orange.demo.common.core.object; + +import lombok.Getter; + +/** + * Controller参数中的分页请求对象 + * + * @author Jerry + * @date 2020-09-25 + */ +@Getter +public class MyPageParam { + + public static final int DEFAULT_PAGE_NUM = 1; + public static final int DEFAULT_PAGE_SIZE = 10; + public static final int DEFAULT_MAX_SIZE = 100; + + /** + * 分页号码,从1开始计数。 + */ + private Integer pageNum; + + /** + * 每页大小。 + */ + private Integer pageSize; + + /** + * 设置当前分页页号。 + * + * @param pageNum 页号,如果传入非法值,则使用缺省值。 + */ + public void setPageNum(Integer pageNum) { + if (pageNum == null) { + return; + } + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + this.pageNum = pageNum; + } + + /** + * 设置分页的大小。 + * + * @param pageSize 分页大小,如果传入非法值,则使用缺省值。 + */ + public void setPageSize(Integer pageSize) { + if (pageSize == null) { + return; + } + if (pageSize <= 0 || pageSize > DEFAULT_MAX_SIZE) { + pageSize = DEFAULT_PAGE_SIZE; + } + this.pageSize = pageSize; + } + +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyRelationParam.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyRelationParam.java new file mode 100644 index 00000000..f8a1e562 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyRelationParam.java @@ -0,0 +1,84 @@ +package com.orange.demo.common.core.object; + +import lombok.Builder; +import lombok.Data; + +/** + * 实体对象数据组装参数构建器。 + * BaseService中的实体对象数据组装函数,会根据该参数对象进行数据组装。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@Builder +public class MyRelationParam { + + /** + * 是否组装字典关联的标记。 + * 组装RelationDict和RelationConstDict注解标记的字段。 + */ + private boolean buildDict; + + /** + * 是否组装一对一关联的标记。 + * 组装RelationOneToOne注解标记的字段。 + */ + private boolean buildOneToOne; + + /** + * 在组装一对一关联的同时,是否继续关联从表中的字典。 + * 从表中RelationDict和RelationConstDict注解标记的字段。 + * 该字段为true时,无需设置buildOneToOne了。 + */ + private boolean buildOneToOneWithDict; + + /** + * 是否组装主表对多对多中间表关联的标记。 + * 组装RelationManyToMany注解标记的字段。 + */ + private boolean buildRelationManyToMany; + + /** + * 是否组装聚合计算关联的标记。 + * 组装RelationOneToManyAggregation和RelationManyToManyAggregation注解标记的字段。 + */ + private boolean buildRelationAggregation; + + /** + * 便捷方法,返回仅做字典关联的参数对象。 + * + * @return 返回仅做字典关联的参数对象。 + */ + public static MyRelationParam dictOnly() { + return MyRelationParam.builder().buildDict(true).build(); + } + + /** + * 便捷方法,返回仅做字典关联、一对一从表及其字典和聚合计算的参数对象。 + * NOTE: 对于一对多和多对多,这种从表数据是列表结果的关联,均不返回。 + * + * @return 返回仅做字典关联、一对一从表及其字典和聚合计算的参数对象。 + */ + public static MyRelationParam normal() { + return MyRelationParam.builder() + .buildDict(true) + .buildOneToOneWithDict(true) + .buildRelationAggregation(true) + .build(); + } + + /** + * 便捷方法,返回全部关联的参数对象。 + * + * @return 返回全部关联的参数对象。 + */ + public static MyRelationParam full() { + return MyRelationParam.builder() + .buildDict(true) + .buildOneToOneWithDict(true) + .buildRelationAggregation(true) + .buildRelationManyToMany(true) + .build(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyWhereCriteria.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyWhereCriteria.java new file mode 100644 index 00000000..8211efbe --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/MyWhereCriteria.java @@ -0,0 +1,308 @@ +package com.orange.demo.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.demo.common.core.exception.InvalidDataFieldException; +import com.orange.demo.common.core.exception.InvalidDataModelException; +import com.orange.demo.common.core.util.MyModelUtil; +import lombok.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Collection; +import java.util.List; + +/** + * Where中的条件语句。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MyWhereCriteria { + + /** + * 等于 + */ + public static final int OPERATOR_EQUAL = 0; + + /** + * 不等于 + */ + public static final int OPERATOR_NOT_EQUAL = 1; + + /** + * 大于等于 + */ + public static final int OPERATOR_GE = 2; + + /** + * 大于 + */ + public static final int OPERATOR_GT = 3; + + /** + * 小于等于 + */ + public static final int OPERATOR_LE = 4; + + /** + * 小于 + */ + public static final int OPERATOR_LT = 5; + + /** + * LIKE + */ + public static final int OPERATOR_LIKE = 6; + + /** + * NOT NULL + */ + public static final int OPERATOR_NOT_NULL = 7; + + /** + * IS NULL + */ + public static final int OPERATOR_IS_NULL = 8; + + /** + * IN + */ + public static final int OPERATOR_IN = 9; + + /** + * 参与过滤的实体对象的Class。 + */ + @JSONField(serialize = false) + private Class modelClazz; + + /** + * Java属性名称。 + */ + private String fieldName; + + /** + * 操作符类型,取值范围见上面的常量值。 + */ + private Integer operatorType; + + /** + * 条件数据值。 + */ + private Object value; + + /** + * 设置条件值。 + * + * @param fieldName 条件所属的实体对象的字段名。 + * @param operatorType 条件操作符。具体值可参考当前对象的静态变量。 + * @param value 条件过滤值。 + * @return 验证结果对象,如果有错误将会返回具体的错误信息。 + */ + public CallResult setCriteria(String fieldName, Integer operatorType, Object value) { + this.operatorType = operatorType; + this.fieldName = fieldName; + this.value = value; + return doVerify(); + } + + /** + * 设置条件值。 + * + * @param modelClazz 数据表对应实体对象的Class. + * @param fieldName 条件所属的实体对象的字段名。 + * @param operatorType 条件操作符。具体值可参考当前对象的静态变量。 + * @param value 条件过滤值。 + * @return 验证结果对象,如果有错误将会返回具体的错误信息。 + */ + public CallResult setCriteria(Class modelClazz, String fieldName, Integer operatorType, Object value) { + this.modelClazz = modelClazz; + this.operatorType = operatorType; + this.fieldName = fieldName; + this.value = value; + return doVerify(); + } + + /** + * 在执行该函数之前,该对象的所有数据均已经赋值完毕。 + * 该函数主要验证操作符字段和条件值字段对应关系的合法性。 + * + * @return 验证结果对象,如果有错误将会返回具体的错误信息。 + */ + public CallResult doVerify() { + if (fieldName == null) { + return CallResult.error("过滤字段名称 [fieldName] 不能为空!"); + } + if (modelClazz != null && ReflectUtil.getField(modelClazz, fieldName) == null) { + return CallResult.error( + "过滤字段 [" + fieldName + "] 在实体对象 [" + modelClazz.getSimpleName() + "] 中并不存在!"); + } + if (!checkOperatorType()) { + return CallResult.error("无效的操作符类型 [" + operatorType + "]!"); + } + // 其他操作符必须包含value值 + if (operatorType != OPERATOR_IS_NULL && operatorType != OPERATOR_NOT_NULL && value == null) { + String operatorString = this.getOperatorString(); + return CallResult.error("操作符 [" + operatorString + "] 的条件值不能为空!"); + } + if (this.operatorType == OPERATOR_IN) { + if (!(value instanceof Collection)) { + return CallResult.error("操作符 [IN] 的条件值必须为集合对象!"); + } + if (CollectionUtils.isEmpty((Collection) value)) { + return CallResult.error("操作符 [IN] 的条件值不能为空!"); + } + } + return CallResult.ok(); + } + + /** + * 判断操作符类型是否合法。 + * + * @return 合法返回true,否则false。 + */ + public boolean checkOperatorType() { + return operatorType != null + && (operatorType >= OPERATOR_EQUAL && operatorType <= OPERATOR_IN); + } + + /** + * 获取操作符的字符串形式。 + * + * @return 操作符的字符串。 + */ + public String getOperatorString() { + switch (operatorType) { + case OPERATOR_EQUAL: + return " = "; + case OPERATOR_NOT_EQUAL: + return " != "; + case OPERATOR_GE: + return " >= "; + case OPERATOR_GT: + return " > "; + case OPERATOR_LE: + return " <= "; + case OPERATOR_LT: + return " < "; + case OPERATOR_LIKE: + return " LIKE "; + case OPERATOR_NOT_NULL: + return " IS NOT NULL "; + case OPERATOR_IS_NULL: + return " IS NULL "; + case OPERATOR_IN: + return " IN "; + default: + return null; + } + } + + /** + * 获取组装后的SQL Where从句,如 table_name.column_name = 'value'。 + * 与查询数据表对应的实体对象Class为当前对象的modelClazz字段。 + * + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public String makeCriteriaString() { + return makeCriteriaString(this.modelClazz); + } + + /** + * 获取组装后的SQL Where从句,如 table_name.column_name = 'value'。 + * + * @param modelClazz 与查询数据表对应的实体对象的Class。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @exception InvalidDataModelException 参数modelClazz没有对应的table,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public String makeCriteriaString(Class modelClazz) { + if (modelClazz == null) { + throw new IllegalArgumentException("ModelClazz argument can't be NULL."); + } + Tuple2 fieldInfo = MyModelUtil.mapToColumnInfo(fieldName, modelClazz); + if (fieldInfo == null) { + throw new InvalidDataFieldException(modelClazz.getSimpleName(), fieldName); + } + String tableName = MyModelUtil.mapToTableName(modelClazz); + if (tableName == null) { + throw new InvalidDataModelException(modelClazz.getSimpleName()); + } + return this.buildClauseString(tableName, fieldInfo.getFirst(), fieldInfo.getSecond()); + } + + /** + * 获取组装后的SQL Where从句。如 table_name.column_name = 'value'。 + * + * @param criteriaList 条件列表,所有条件直接目前仅支持 AND 的关系。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public static String makeCriteriaString(List criteriaList) { + return makeCriteriaString(criteriaList, null); + } + + /** + * 获取组装后的SQL Where从句。如 table_name.column_name = 'value'。 + * + * @param criteriaList 条件列表,所有条件直接目前仅支持 AND 的关系。 + * @param modelClazz 与数据表对应的实体对象的Class。 + * 如果不为NULL实体对象Class使用该值,否则使用每个MyWhereCriteria自身的modelClazz。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public static String makeCriteriaString(List criteriaList, Class modelClazz) { + if (CollectionUtils.isEmpty(criteriaList)) { + return null; + } + StringBuilder sb = new StringBuilder(256); + int i = 0; + for (MyWhereCriteria whereCriteria : criteriaList) { + Class clazz = modelClazz; + if (clazz == null) { + clazz = whereCriteria.modelClazz; + } + if (i++ != 0) { + sb.append(" AND "); + } + String criteriaString = whereCriteria.makeCriteriaString(clazz); + sb.append(criteriaString); + } + return sb.length() == 0 ? null : sb.toString(); + } + + private String buildClauseString(String tableName, String columnName, Integer columnType) { + StringBuilder sb = new StringBuilder(64); + sb.append(tableName).append(".").append(columnName).append(getOperatorString()); + if (operatorType == OPERATOR_IN) { + Collection filterValues = (Collection) value; + sb.append("("); + int i = 0; + for (Object filterValue : filterValues) { + if (columnType.equals(MyModelUtil.NUMERIC_FIELD_TYPE)) { + sb.append(filterValue); + } else { + sb.append("'").append(filterValue).append("'"); + } + if (i++ != filterValues.size() - 1) { + sb.append(", "); + } + } + sb.append(")"); + return sb.toString(); + } + if (value != null) { + if (columnType.equals(MyModelUtil.NUMERIC_FIELD_TYPE)) { + sb.append(value); + } else { + sb.append("'").append(value).append("'"); + } + } + return sb.toString(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/ResponseResult.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/ResponseResult.java new file mode 100644 index 00000000..718bb8d8 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/ResponseResult.java @@ -0,0 +1,157 @@ +package com.orange.demo.common.core.object; + +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import lombok.Data; + +/** + * 接口返回对象 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +public class ResponseResult { + + /** + * 为了优化性能,所有没有携带数据的正确结果,均可用该对象表示。 + */ + private static final ResponseResult OK = new ResponseResult<>(); + /** + * 是否成功标记。 + */ + private boolean success = true; + /** + * 错误码。 + */ + private String errorCode = "NO-ERROR"; + /** + * 错误信息描述。 + */ + private String errorMessage = "NO-MESSAGE"; + /** + * 实际数据。 + */ + private T data = null; + + /** + * 根据参数errorCodeEnum的枚举值,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和 getErrorMessage()。 + * + * @param errorCodeEnum 错误码枚举 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(ErrorCodeEnum errorCodeEnum) { + return create(errorCodeEnum, errorCodeEnum.getErrorMessage()); + } + + /** + * 根据参数errorCodeEnum的枚举值,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和参数 errorMessage。 + * + * @param errorCodeEnum 错误码枚举。 + * @param errorMessage 如果该参数为null,错误信息取自errorCodeEnum参数内置的errorMessage,否则使用当前参数。 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(ErrorCodeEnum errorCodeEnum, String errorMessage) { + errorMessage = errorMessage != null ? errorMessage : errorCodeEnum.getErrorMessage(); + return errorCodeEnum == ErrorCodeEnum.NO_ERROR ? success() : error(errorCodeEnum.name(), errorMessage); + } + + /** + * 根据参数errorCode是否为空,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCode 和参数 errorMessage。 + * + * @param errorCode 自定义的错误码 + * @param errorMessage 自定义的错误信息 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(String errorCode, String errorMessage) { + return errorCode == null ? success() : error(errorCode, errorMessage); + } + + /** + * 创建成功对象。 + * 如果需要绑定返回数据,可以在实例化后调用setDataObject方法。 + * + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult success() { + return OK; + } + + /** + * 创建带有返回数据的成功对象。 + * + * @param data 返回的数据对象 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult success(T data) { + ResponseResult resp = new ResponseResult<>(); + resp.data = data; + return resp; + } + + /** + * 创建错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和 getErrorMessage()。 + * + * @param errorCodeEnum 错误码枚举 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult error(ErrorCodeEnum errorCodeEnum) { + return error(errorCodeEnum.name(), errorCodeEnum.getErrorMessage()); + } + + /** + * 创建错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和参数 errorMessage。 + * + * @param errorCodeEnum 错误码枚举 + * @param errorMessage 自定义的错误信息 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult error(ErrorCodeEnum errorCodeEnum, String errorMessage) { + return error(errorCodeEnum.name(), errorMessage); + } + + /** + * 创建错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCode 和参数 errorMessage。 + * + * @param errorCode 自定义的错误码 + * @param errorMessage 自定义的错误信息 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult error(String errorCode, String errorMessage) { + return new ResponseResult<>(false, errorCode, errorMessage); + } + + /** + * 根据参数的errorCode和errorMessage创建新的错误应答对象。 + * + * @param errorCause 导致错误原因的应答对象。 + * @return 返回创建的ResponseResult实例对象。 + */ + public static ResponseResult errorFrom(ResponseResult errorCause) { + return error(errorCause.errorCode, errorCause.getErrorMessage()); + } + + /** + * 是否成功。 + * + * @return true成功,否则false。 + */ + public boolean isSuccess() { + return success; + } + + private ResponseResult() { + + } + + private ResponseResult(boolean success, String errorCode, String errorMessage) { + this.success = success; + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/TokenData.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/TokenData.java new file mode 100644 index 00000000..b1d74f58 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/TokenData.java @@ -0,0 +1,59 @@ +package com.orange.demo.common.core.object; + +import com.orange.demo.common.core.util.ContextUtil; +import lombok.Data; +import lombok.ToString; + +import javax.servlet.http.HttpServletRequest; + +/** + * 基于Jwt,用于前后端传递的令牌对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@ToString +public class TokenData { + + /** + * 在HTTP Request对象中的属性键。 + */ + public static final String REQUEST_ATTRIBUTE_NAME = "tokenData"; + /** + * 用户Id。 + */ + private Long userId; + /** + * 是否为超级管理员。 + */ + private Boolean isAdmin; + /** + * 用户显示名称。 + */ + private String showName; + /** + * 标识不同登录的会话Id。 + */ + private String sessionId; + + /** + * 将令牌对象添加到Http请求对象。 + * + * @param tokenData 令牌对象。 + */ + public static void addToRequest(TokenData tokenData) { + HttpServletRequest request = ContextUtil.getHttpRequest(); + request.setAttribute(TokenData.REQUEST_ATTRIBUTE_NAME, tokenData); + } + + /** + * 从Http Request对象中获取令牌对象。 + * + * @return 令牌对象。 + */ + public static TokenData takeFromRequest() { + HttpServletRequest request = ContextUtil.getHttpRequest(); + return (TokenData) request.getAttribute(REQUEST_ATTRIBUTE_NAME); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/Tuple2.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/Tuple2.java new file mode 100644 index 00000000..b908d019 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/object/Tuple2.java @@ -0,0 +1,50 @@ +package com.orange.demo.common.core.object; + +/** + * 二元组对象。主要用于可以一次返回多个结果的场景,同时还能避免强制转换。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class Tuple2 { + + /** + * 第一个变量。 + */ + private final T1 first; + /** + * 第二个变量。 + */ + private final T2 second; + + /** + * 构造函数。 + * + * @param first 第一个变量。 + * @param second 第二个变量。 + */ + public Tuple2(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + /** + * 获取第一个变量。 + * + * @return 返回第一个变量。 + */ + public T1 getFirst() { + return first; + } + + /** + * 获取第二个变量。 + * + * @return 返回第二个变量。 + */ + public T2 getSecond() { + return second; + } + +} + diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/AopTargetUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/AopTargetUtil.java new file mode 100644 index 00000000..77002bad --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/AopTargetUtil.java @@ -0,0 +1,58 @@ +package com.orange.demo.common.core.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.framework.AdvisedSupport; +import org.springframework.aop.framework.AopProxy; +import org.springframework.aop.support.AopUtils; + +import java.lang.reflect.Field; + +/** + * 获取JDK动态代理/CGLIB代理对象代理的目标对象的工具类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class AopTargetUtil { + + /** + * 获取参数对象代理的目标对象。 + * + * @param proxy 代理对象 + * @return 代理的目标对象。 + */ + public static Object getTarget(Object proxy) { + if (!AopUtils.isAopProxy(proxy)) { + return proxy; + } + try { + if (AopUtils.isJdkDynamicProxy(proxy)) { + return getJdkDynamicProxyTargetObject(proxy); + } else { + return getCglibProxyTargetObject(proxy); + } + } catch (Exception e) { + log.error("Failed to call getJdkDynamicProxyTargetObject or getCglibProxyTargetObject", e); + return null; + } + } + + private static Object getCglibProxyTargetObject(Object proxy) throws Exception { + Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); + h.setAccessible(true); + Object dynamicAdvisedInterceptor = h.get(proxy); + Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + return ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); + } + + private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { + Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); + h.setAccessible(true); + AopProxy aopProxy = (AopProxy) h.get(proxy); + Field advised = aopProxy.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + return ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget(); + } +} \ No newline at end of file diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ApplicationContextHolder.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ApplicationContextHolder.java new file mode 100644 index 00000000..8341de18 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ApplicationContextHolder.java @@ -0,0 +1,74 @@ +package com.orange.demo.common.core.util; + +import com.orange.demo.common.core.exception.MyRuntimeException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; + +/** + * Spring 系统启动应用感知对象,主要用于获取Spring Bean的上下文对象,后续的代码中可以直接查找系统中加载的Bean对象。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Component +public class ApplicationContextHolder implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + /** + * Spring 启动的过程中会自动调用,并将应用上下文对象赋值进来。 + * + * @param applicationContext 应用上下文对象,可通过该对象查找Spring中已经加载的Bean。 + */ + @Override + public void setApplicationContext(@NonNull ApplicationContext applicationContext) { + doSetApplicationContext(applicationContext); + } + + /** + * 获取应用上下文对象。 + * + * @return 应用上下文。 + */ + public static ApplicationContext getApplicationContext() { + assertApplicationContext(); + return applicationContext; + } + + /** + * 根据BeanName,获取Bean对象。 + * + * @param beanName Bean名称。 + * @param 返回的Bean类型。 + * @return Bean对象。 + */ + @SuppressWarnings("unchecked") + public static T getBean(String beanName) { + assertApplicationContext(); + return (T) applicationContext.getBean(beanName); + } + + /** + * 根据Bean的ClassType,获取Bean对象。 + * + * @param beanType Bean的Class类型。。 + * @param 返回的Bean类型。 + * @return Bean对象。 + */ + public static T getBean(Class beanType) { + assertApplicationContext(); + return applicationContext.getBean(beanType); + } + + private static void assertApplicationContext() { + if (ApplicationContextHolder.applicationContext == null) { + throw new MyRuntimeException("applicaitonContext属性为null,请检查是否注入了ApplicationContextHolder!"); + } + } + + private static void doSetApplicationContext(ApplicationContext applicationContext) { + ApplicationContextHolder.applicationContext = applicationContext; + } +} \ No newline at end of file diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ContextUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ContextUtil.java new file mode 100644 index 00000000..83332f7a --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ContextUtil.java @@ -0,0 +1,49 @@ +package com.orange.demo.common.core.util; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 获取Servlet HttpRequest和HttpResponse的工具类。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class ContextUtil { + + /** + * 判断当前是否处于HttpServletRequest上下文环境。 + * + * @return 是返回true,否则false。 + */ + public static boolean hasRequestContext() { + return RequestContextHolder.getRequestAttributes() != null; + } + + /** + * 获取Servlet请求上下文的HttpRequest对象。 + * + * @return 请求上下文中的HttpRequest对象。 + */ + public static HttpServletRequest getHttpRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + /** + * 获取Servlet请求上下文的HttpResponse对象。 + * + * @return 请求上下文中的HttpResponse对象。 + */ + public static HttpServletResponse getHttpResponse() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ContextUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ExportUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ExportUtil.java new file mode 100644 index 00000000..37562b06 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ExportUtil.java @@ -0,0 +1,95 @@ +package com.orange.demo.common.core.util; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.ExcelWriter; +import cn.jimmyshi.beanquery.BeanQuery; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.exception.MyRuntimeException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.io.FilenameUtils; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 导出工具类,目前支持xlsx和csv两种类型。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class ExportUtil { + + /** + * 数据导出。目前仅支持xlsx和csv。 + * + * @param dataList 导出数据列表。 + * @param selectFieldMap 导出的数据字段,key为对象字段名称,value为中文标题名称。 + * @param filename 导出文件名。 + * @param 数据对象类型。 + * @throws IOException 文件操作失败。 + */ + public static void doExport( + Collection dataList, Map selectFieldMap, String filename) throws IOException { + if (CollectionUtils.isEmpty(dataList)) { + return; + } + StringBuilder sb = new StringBuilder(128); + for (Map.Entry e : selectFieldMap.entrySet()) { + sb.append(e.getKey()).append(" as ").append(e.getValue()).append(", "); + } + // 去掉末尾的逗号 + String selectFieldString = sb.substring(0, sb.length() - 2); + // 写出数据到xcel格式的输出流 + List> resultList = BeanQuery.select(selectFieldString).executeFrom(dataList); + // 构建HTTP输出流参数 + HttpServletResponse response = ContextUtil.getHttpResponse(); + response.setHeader("content-type", "application/octet-stream"); + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + filename); + if (ApplicationConstant.XLSX_EXT.equals(FilenameUtils.getExtension(filename))) { + ServletOutputStream out = response.getOutputStream(); + ExcelWriter writer = ExcelUtil.getWriter(true); + writer.setRowHeight(-1, 30); + writer.setColumnWidth(-1, 30); + writer.setColumnWidth(1, 20); + writer.write(resultList); + writer.flush(out); + writer.close(); + IoUtil.close(out); + } else if (ApplicationConstant.CSV_EXT.equals(FilenameUtils.getExtension(filename))) { + Collection headerList = selectFieldMap.values(); + String[] headerArray = new String[headerList.size()]; + headerList.toArray(headerArray); + CSVFormat format = CSVFormat.DEFAULT.withHeader(headerArray); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + try (Writer out = response.getWriter(); CSVPrinter printer = new CSVPrinter(out, format)) { + for (Map o : resultList) { + for (Map.Entry entry : o.entrySet()) { + printer.print(entry.getValue()); + } + printer.println(); + } + printer.flush(); + } catch (Exception e) { + log.error("Failed to call ExportUtil.doExport", e); + } + } else { + throw new MyRuntimeException("不支持的导出文件类型!"); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ExportUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ImportUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ImportUtil.java new file mode 100644 index 00000000..32eaf9b9 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/ImportUtil.java @@ -0,0 +1,214 @@ +package com.orange.demo.common.core.util; + +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.poi.excel.ExcelReader; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.sax.Excel07SaxReader; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.exception.MyRuntimeException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.*; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 导入工具类,目前支持xlsx和csv两种类型。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class ImportUtil { + + private static final String IMPORT_EXCEPTION_ERROR = "Failed to call ImportUtil.doImport"; + private static final String UNSUPPORT_FILE_EXT_ERROR = "不支持的导入文件类型!"; + /** + * 同步导入方式。 + * + * @param filename 导入文件名。 + * @return 导入数据列表。 + */ + public static List> doImport(String filename) { + if (ApplicationConstant.XLSX_EXT.equals(FilenameUtils.getExtension(filename))) { + try (ExcelReader reader = ExcelUtil.getReader(filename)) { + return reader.readAll(); + } + } else if (ApplicationConstant.CSV_EXT.equals(FilenameUtils.getExtension(filename))) { + List> resultList = new LinkedList<>(); + try (FileReader reader = new FileReader(filename)) { + CSVParser parser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader); + Map headerMap = parser.getHeaderMap(); + for (CSVRecord record : parser) { + Map rowMap = new LinkedHashMap<>(); + for (final Map.Entry header : headerMap.entrySet()) { + int col = header.getValue(); + if (col < record.size()) { + rowMap.put(header.getKey(), record.get(col)); + } + } + resultList.add(rowMap); + } + } catch (Exception e) { + log.error(IMPORT_EXCEPTION_ERROR, e); + } + return resultList; + } + throw new MyRuntimeException(UNSUPPORT_FILE_EXT_ERROR); + } + + /** + * 异步导入方式,即SAX导入方式。 + * + * @param filename 导入文件名。 + * @param importer 异步导入处理接口。 + * @throws IOException 文件处理异常。 + */ + public static void doImport(String filename, BaseImporter importer) throws IOException { + if (ApplicationConstant.XLSX_EXT.equals(FilenameUtils.getExtension(filename))) { + Excel07SaxReader reader = new MyExcel07SaxReader<>(importer); + try (InputStream in = new FileInputStream(filename)) { + reader.read(in, 0); + } + } else if (ApplicationConstant.CSV_EXT.equals(FilenameUtils.getExtension(filename))) { + try (BufferedReader reader = new BufferedReader(new FileReader(filename))) { + int rowIndex = 0; + do { + String rowData = reader.readLine(); + if (StringUtils.isBlank(rowData)) { + importer.doImport(-1, null); + break; + } + String[] dataArray = StringUtils.split(rowData, ","); + importer.doImport(rowIndex++, Arrays.asList(dataArray)); + } while (!importer.doInterrupt()); + } catch (Exception e) { + log.error(IMPORT_EXCEPTION_ERROR, e); + } + } + throw new MyRuntimeException(UNSUPPORT_FILE_EXT_ERROR); + } + + /** + * 异步导入抽象类。 + * + * @param 导入数据对象类型。 + */ + public abstract static class BaseImporter { + private Class beanType; + private List batchRowList = new LinkedList<>(); + private int batchSize; + private Field[] fieldArray = null; + private Map headerColumnMap; + + public BaseImporter(int batchSize, Class beanType, Map headerColumnMap) { + if (batchSize <= 0) { + batchSize = 100; + } + this.batchSize = batchSize; + this.beanType = beanType; + this.headerColumnMap = headerColumnMap; + } + + /** + * 导入操作执行函数。 + * + * @param rowIndex 当前行号。 + * @param row 当前行数据列表对象。 + */ + public void doImport(int rowIndex, List row) { + if (row == null) { + doProcess(batchRowList); + doFinish(); + batchRowList.clear(); + return; + } + if (rowIndex <= 0) { + fieldArray = new Field[row.size()]; + List headerList = row.stream().map(Object::toString).collect(Collectors.toList()); + List columnList = new ArrayList<>(row.size()); + for (String headerName : headerList) { + String columnName = headerColumnMap.get(headerName); + if (columnName != null) { + columnList.add(columnName); + } + } + columnList.stream() + .map(columnName -> ReflectUtil.getField(beanType, columnName)) + .collect(Collectors.toList()) + .toArray(fieldArray); + return; + } + T data; + try { + data = beanType.newInstance(); + for (int i = 0; i < row.size(); i++) { + Object value = row.get(i); + Field field = fieldArray[i]; + if (field != null) { + ReflectUtil.setFieldValue(data, field, value); + } + } + batchRowList.add(data); + } catch (Exception e) { + log.error(IMPORT_EXCEPTION_ERROR, e); + } + if (rowIndex % batchSize == 0) { + doProcess(batchRowList); + batchRowList.clear(); + } + } + + /** + * 数据处理进行中回调模板函数。 + * + * @param batchRowList 一批数据行。 + */ + public abstract void doProcess(List batchRowList); + + /** + * 数据处理完毕回调模板函数。 + */ + public abstract void doFinish(); + + /** + * 数据处理终端标记模板函数。 + * @return 是否中断。true则中断后面的处理。 + */ + public abstract boolean doInterrupt(); + } + + static class MyExcel07SaxReader extends Excel07SaxReader { + private BaseImporter importer; + + MyExcel07SaxReader(BaseImporter importer) { + super((sheetIndex, rowIndex, rowList) -> importer.doImport(rowIndex, rowList)); + this.importer = importer; + } + + @Override + public void endElement(String uri, String localName, String qName) { + super.endElement(uri, localName, qName); + if (importer.doInterrupt()) { + throw new MyRuntimeException(); + } + } + + @Override + public void endDocument() { + importer.doImport(-1, null); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ImportUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/IpUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/IpUtil.java new file mode 100644 index 00000000..a0ead06c --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/IpUtil.java @@ -0,0 +1,101 @@ +package com.orange.demo.common.core.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * Ip工具类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class IpUtil { + + private static final String UNKNOWN = "unknown"; + + /** + * 通过Servlet的HttpRequest对象获取Ip地址。 + * + * @param request HttpRequest对象。 + * @return 本次请求的Ip地址。 + */ + public static String getRemoteIpAddress(HttpServletRequest request) { + String ip = null; + //X-Forwarded-For:Squid 服务代理 + String ipAddresses = request.getHeader("X-Forwarded-For"); + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + //Proxy-Client-IP:apache 服务代理 + ipAddresses = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + //WL-Proxy-Client-IP:weblogic 服务代理 + ipAddresses = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + //HTTP_CLIENT_IP:有些代理服务器 + ipAddresses = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + //X-Real-IP:nginx服务代理 + ipAddresses = request.getHeader("X-Real-IP"); + } + //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP + if (StringUtils.isNotBlank(ipAddresses)) { + ip = ipAddresses.split(",")[0]; + } + //还是不能获取到,最后再通过request.getRemoteAddr();获取 + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + ip = request.getRemoteAddr(); + } + return ip; + } + + public static String getFirstLocalIpAddress() { + String ip; + try { + List ipList = getHostAddress(); + // default the first + ip = (!ipList.isEmpty()) ? ipList.get(0) : ""; + } catch (Exception ex) { + ip = ""; + log.error("Failed to call ", ex); + } + return ip; + } + + private static List getHostAddress() throws SocketException { + List ipList = new ArrayList<>(5); + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface ni = interfaces.nextElement(); + Enumeration allAddress = ni.getInetAddresses(); + while (allAddress.hasMoreElements()) { + InetAddress address = allAddress.nextElement(); + // skip the IPv6 addr + // skip the IPv6 addr + if (address.isLoopbackAddress() || address instanceof Inet6Address) { + continue; + } + String hostAddress = address.getHostAddress(); + ipList.add(hostAddress); + } + } + return ipList; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private IpUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/JwtUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/JwtUtil.java new file mode 100644 index 00000000..9c2726dd --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/JwtUtil.java @@ -0,0 +1,110 @@ +package com.orange.demo.common.core.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.Map; + +/** + * 基于JWT的Token生成工具类 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class JwtUtil { + + private static final String TOKEN_PREFIX = "Bearer:"; + private static final String CLAIM_KEY_CREATEDTIME = "CreatedTime"; + + /** + * Token缺省过期时间是30分钟 + */ + private static final Long TOKEN_EXPIRATION = 1800000L; + /** + * 缺省情况下,Token会每5分钟被刷新一次 + */ + private static final Long REFRESH_TOKEN_INTERVAL = 300000L; + + /** + * 生成加密后的JWT令牌,生成的结果中包含令牌前缀,如"Bearer " + * + * @param claims 令牌中携带的数据 + * @param expirationMillisecond 过期的毫秒数 + * @return 生成后的令牌信息 + */ + public static String generateToken(Map claims, long expirationMillisecond, String signingKey) { + // 自动添加token的创建时间 + long createTime = System.currentTimeMillis(); + claims.put(CLAIM_KEY_CREATEDTIME, createTime); + String token = Jwts.builder() + .setClaims(claims) + .setExpiration(new Date(createTime + expirationMillisecond)) + .signWith(SignatureAlgorithm.HS512, signingKey) + .compact(); + return TOKEN_PREFIX + token; + } + + /** + * 生成加密后的JWT令牌,生成的结果中包含令牌前缀,如"Bearer " + * + * @param claims 令牌中携带的数据 + * @return 生成后的令牌信息 + */ + public static String generateToken(Map claims, String signingKey) { + return generateToken(claims, TOKEN_EXPIRATION, signingKey); + } + + /** + * 获取token中的数据对象 + * + * @param token 令牌信息(需要包含令牌前缀,如"Bearer:") + * @return 令牌中的数据对象,解析视频返回null。 + */ + public static Claims parseToken(String token, String signingKey) { + if (token == null || !token.startsWith(TOKEN_PREFIX)) { + return null; + } + String tokenKey = token.substring(TOKEN_PREFIX.length()); + Claims claims = null; + try { + claims = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(tokenKey).getBody(); + } catch (Exception e) { + log.error("Token Expired", e); + } + return claims; + } + + /** + * 判断令牌是否过期 + * + * @param claims 令牌解密后的Map对象。 + * @return true 过期,否则false。 + */ + public static boolean isNullOrExpired(Claims claims) { + return claims == null || claims.getExpiration().before(new Date()); + } + + /** + * 判断解密后的Token payload是否需要被强制刷新,如果需要,则调用generateToken方法重新生成Token。 + * + * @param claims Token解密后payload数据 + * @return true 需要刷新,否则false + */ + public static boolean needToRefresh(Claims claims) { + if (claims == null) { + return false; + } + Long createTime = (Long) claims.get(CLAIM_KEY_CREATEDTIME); + return createTime == null || System.currentTimeMillis() - createTime > REFRESH_TOKEN_INTERVAL; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private JwtUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/LogMessageUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/LogMessageUtil.java new file mode 100644 index 00000000..7c8f069d --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/LogMessageUtil.java @@ -0,0 +1,33 @@ +package com.orange.demo.common.core.util; + +/** + * 拼接日志消息的工具类。 + * 主要目标是,尽量保证日志输出的统一性,同时也可以有效减少与日志信息相关的常量字符串, + * 提高代码的规范度和可维护性。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class LogMessageUtil { + + /** + * RPC调用错误格式。 + */ + private static final String RPC_ERROR_MSG_FORMAT = "RPC Failed with Error message [%s]"; + + /** + * 组装RPC调用的错误信息。 + * + * @param errorMsg 具体的错误信息。 + * @return 格式化后的错误信息。 + */ + public static String makeRpcError(String errorMsg) { + return String.format(RPC_ERROR_MSG_FORMAT, errorMsg); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private LogMessageUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyCommonUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyCommonUtil.java new file mode 100644 index 00000000..40d7d226 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyCommonUtil.java @@ -0,0 +1,144 @@ +package com.orange.demo.common.core.util; + +import cn.hutool.crypto.digest.DigestUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + +/** + * 脚手架中常用的基本工具方法集合,一般而言工程内部使用的方法。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class MyCommonUtil { + + private static Validator validator; + + static { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + + /** + * 创建uuid。 + * + * @return 返回uuid。 + */ + public static String generateUuid() { + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 对用户密码进行加盐后加密。 + * + * @param password 明文密码。 + * @param passwordSalt 盐值。 + * @return 加密后的密码。 + */ + public static String encrptedPassword(String password, String passwordSalt) { + return DigestUtil.md5Hex(password + passwordSalt); + } + + /** + * 这个方法一般用于Controller对于入口参数的基本验证。 + * 对于字符串,如果为空字符串,也将视为Blank,同时返回true。 + * + * @param objs 一组参数。 + * @return 返回是否存在null或空字符串的参数。 + */ + public static boolean existBlankArgument(Object...objs) { + for (Object obj : objs) { + if (MyCommonUtil.isBlankOrNull(obj)) { + return true; + } + } + return false; + } + + /** + * 结果和 existBlankArgument 相反。 + * + * @param objs 一组参数。 + * @return 返回是否存在null或空字符串的参数。 + */ + public static boolean existNotBlankArgument(Object...objs) { + for (Object obj : objs) { + if (!MyCommonUtil.isBlankOrNull(obj)) { + return true; + } + } + return false; + } + + /** + * 验证参数是否为空。 + * + * @param obj 待判断的参数。 + * @return 空或者null返回true,否则false。 + */ + public static boolean isBlankOrNull(Object obj) { + if (obj instanceof Collection) { + return CollectionUtils.isEmpty((Collection) obj); + } + return obj == null || (obj instanceof CharSequence && StringUtils.isBlank((CharSequence) obj)); + } + + /** + * 验证参数是否为非空。 + * + * @param obj 待判断的参数。 + * @return 空或者null返回false,否则true。 + */ + public static boolean isNotBlankOrNull(Object obj) { + return !isBlankOrNull(obj); + } + + /** + * 判断模型对象是否通过校验,没有通过返回具体的校验错误信息。 + * + * @param model 带校验的model。 + * @param groups Validate绑定的校验组。 + * @return 没有错误返回null,否则返回具体的错误信息。 + */ + public static String getModelValidationError(T model, Class...groups) { + Set> constraintViolations = validator.validate(model, groups); + if (!constraintViolations.isEmpty()) { + Iterator> it = constraintViolations.iterator(); + ConstraintViolation constraint = it.next(); + return constraint.getMessage(); + } + return null; + } + + /** + * 拼接参数中的字符串列表,用指定分隔符进行分割,同时每个字符串对象用单引号括起来。 + * + * @param dataList 字符串集合。 + * @param separator 分隔符。 + * @return 拼接后的字符串。 + */ + public static String joinString(Collection dataList, final char separator) { + int index = 0; + StringBuilder sb = new StringBuilder(128); + for (String data : dataList) { + sb.append("'").append(data).append("'"); + if (index++ != dataList.size() - 1) { + sb.append(separator); + } + } + return sb.toString(); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyCommonUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyDateUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyDateUtil.java new file mode 100644 index 00000000..9ee747d5 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyDateUtil.java @@ -0,0 +1,181 @@ +package com.orange.demo.common.core.util; + +import com.orange.demo.common.core.object.Tuple2; +import org.apache.commons.lang3.time.DateUtils; +import org.joda.time.DateTime; +import org.joda.time.Period; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.util.Calendar; +import java.util.Date; + +import static org.joda.time.PeriodType.days; + +/** + * 日期工具类,主要封装了部分joda-time中的方法,让很多代码一行完成,同时统一了日期到字符串的pattern格式。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class MyDateUtil { + + /** + * 统一的日期pattern,今后可以根据自己的需求去修改。 + */ + public static final String COMMON_DATE_FORMAT = "yyyy-MM-dd"; + /** + * 统一的日期时间pattern,今后可以根据自己的需求去修改。 + */ + public static final String COMMON_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + /** + * 缺省日期格式化器,提前获取提升运行时效率。 + */ + private static final DateTimeFormatter DATE_PARSE_FORMATTER = + DateTimeFormat.forPattern(MyDateUtil.COMMON_DATE_FORMAT); + /** + * 缺省日期时间格式化器,提前获取提升运行时效率。 + */ + private static final DateTimeFormatter DATETIME_PARSE_FORMATTER = + DateTimeFormat.forPattern(MyDateUtil.COMMON_DATETIME_FORMAT); + + /** + * 获取一天的开始时间的字符串格式,如2019-08-03 00:00:00.000。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 格式化后的字符串。 + */ + public static String getBeginTimeOfDay(DateTime dateTime) { + return dateTime.withTimeAtStartOfDay().toString(COMMON_DATETIME_FORMAT); + } + + /** + * 获取一天的结束时间的字符串格式,如2019-08-03 23:59:59.999。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 格式化后的字符串。 + */ + public static String getEndTimeOfDay(DateTime dateTime) { + return dateTime.withTime(23, 59, 59, 999).toString(COMMON_DATETIME_FORMAT); + } + + /** + * 获取一天中的开始时间和结束时间的字符串格式,如2019-08-03 00:00:00.000 和 2019-08-03 23:59:59.999。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 包含格式后字符串的二元组对象。 + */ + public static Tuple2 getDateTimeRangeOfDay(DateTime dateTime) { + return new Tuple2<>(getBeginTimeOfDay(dateTime), getEndTimeOfDay(dateTime)); + } + + /** + * 获取本月第一天的日期格式。如2019-08-01。 + * + * @param dateTime 待格式化的日期对象。 + * @return 格式化后的字符串。 + */ + public static String getBeginDateOfMonth(DateTime dateTime) { + return dateTime.withDayOfMonth(1).toString(COMMON_DATE_FORMAT); + } + + /** + * 获取本月第一天的日期格式。如2019-08-01。 + * + * @param dateString 待格式化的日期字符串对象。 + * @return 格式化后的字符串。 + */ + public static String getBeginDateOfMonth(String dateString) { + DateTime dateTime = toDate(dateString); + return dateTime.withDayOfMonth(1).toString(COMMON_DATE_FORMAT); + } + + /** + * 计算指定日期距离今天相差的天数。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 相差天数。 + */ + public static int getDayDiffToNow(DateTime dateTime) { + return new Period(dateTime, new DateTime(), days()).getDays(); + } + + /** + * 将日期对象格式化为缺省的字符串格式。 + * + * @param dateTime 待格式化的日期对象。 + * @return 格式化后的字符串。 + */ + public static String toDateString(DateTime dateTime) { + return dateTime.toString(COMMON_DATE_FORMAT); + } + + /** + * 将日期时间对象格式化为缺省的字符串格式。 + * + * @param dateTime 待格式化的日期对象。 + * @return 格式化后的字符串。 + */ + public static String toDateTimeString(DateTime dateTime) { + return dateTime.toString(COMMON_DATETIME_FORMAT); + } + + /** + * 将缺省格式的日期字符串解析为日期对象。 + * + * @param dateString 待解析的字符串。 + * @return 解析后的日期对象。 + */ + public static DateTime toDate(String dateString) { + return DATE_PARSE_FORMATTER.parseDateTime(dateString); + } + + /** + * 将缺省格式的日期字符串解析为日期对象。 + * + * @param dateTimeString 待解析的字符串。 + * @return 解析后的日期对象。 + */ + public static DateTime toDateTime(String dateTimeString) { + return DATETIME_PARSE_FORMATTER.parseDateTime(dateTimeString); + } + + /** + * 截取时间到天。如2019-10-03 01:20:30 转换为 2019-10-03 00:00:00。 + * 由于没有字符串的中间转换,因此效率更高。 + * + * @param date 待截取日期对象。 + * @return 转换后日期对象。 + */ + public static Date truncateToDay(Date date) { + return DateUtils.truncate(date, Calendar.DAY_OF_MONTH); + } + + /** + * 截取时间到月。如2019-10-03 01:20:30 转换为 2019-10-01 00:00:00。 + * 由于没有字符串的中间转换,因此效率更高。 + * + * @param date 待截取日期对象。 + * @return 转换后日期对象。 + */ + public static Date truncateToMonth(Date date) { + return DateUtils.truncate(date, Calendar.MONTH); + } + + /** + * 截取时间到年。如2019-10-03 01:20:30 转换为 2019-01-01 00:00:00。 + * 由于没有字符串的中间转换,因此效率更高。 + * + * @param date 待截取日期对象。 + * @return 转换后日期对象。 + */ + public static Date truncateToYear(Date date) { + return DateUtils.truncate(date, Calendar.YEAR); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyDateUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyModelUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyModelUtil.java new file mode 100644 index 00000000..419f02a1 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyModelUtil.java @@ -0,0 +1,437 @@ +package com.orange.demo.common.core.util; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ReflectUtil; +import com.orange.demo.common.core.annotation.RelationConstDict; +import com.orange.demo.common.core.annotation.RelationDict; +import com.orange.demo.common.core.annotation.RelationOneToOne; +import com.orange.demo.common.core.exception.MyRuntimeException; +import com.orange.demo.common.core.object.Tuple2; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import tk.mybatis.mapper.entity.Example; + +import javax.persistence.Column; +import javax.persistence.Table; +import javax.persistence.Transient; +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 负责Model数据操作、类型转换和关系关联等行为的工具类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class MyModelUtil { + + /** + * 数值型字段。 + */ + public static final Integer NUMERIC_FIELD_TYPE = 0; + /** + * 字符型字段。 + */ + public static final Integer STRING_FIELD_TYPE = 1; + /** + * 日期型字段。 + */ + public static final Integer DATE_FIELD_TYPE = 2; + /** + * mapToColumnName和mapToColumnInfo使用的缓存。 + */ + private static Map> cachedColumnInfoMap = new ConcurrentHashMap<>(); + + /** + * 映射Model对象的字段反射对象,获取与该字段对应的数据库列名称。 + * + * @param field 字段反射对象。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称。 + */ + public static String mapToColumnName(Field field, Class modelClazz) { + return mapToColumnName(field.getName(), modelClazz); + } + + /** + * 映射Model对象的字段名称,获取与该字段对应的数据库列名称。 + * + * @param fieldName 字段名称。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称。 + */ + public static String mapToColumnName(String fieldName, Class modelClazz) { + Tuple2 columnInfo = mapToColumnInfo(fieldName, modelClazz); + return columnInfo == null ? null : columnInfo.getFirst(); + } + + /** + * 映射Model对象的字段名称,获取与该字段对应的数据库列名称和字段类型。 + * + * @param fieldName 字段名称。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称和Java字段类型。 + */ + public static Tuple2 mapToColumnInfo(String fieldName, Class modelClazz) { + if (StringUtils.isBlank(fieldName)) { + return null; + } + StringBuilder sb = new StringBuilder(128); + sb.append(modelClazz.getName()).append("-#-").append(fieldName); + Tuple2 columnInfo = cachedColumnInfoMap.get(sb.toString()); + if (columnInfo == null) { + Field field = ReflectUtil.getField(modelClazz, fieldName); + if (field == null) { + return null; + } + Column c = field.getAnnotation(Column.class); + String typeName = field.getType().getSimpleName(); + String columnName = c == null ? fieldName : c.name(); + // 这里缺省情况下都是按照整型去处理,因为他覆盖太多的类型了。 + // 如Integer/Long/Double/BigDecimal,可根据实际情况完善和扩充。 + Integer type = NUMERIC_FIELD_TYPE; + if (String.class.getSimpleName().equals(typeName)) { + type = STRING_FIELD_TYPE; + } else if (Date.class.getSimpleName().equals(typeName)) { + type = DATE_FIELD_TYPE; + } + columnInfo = new Tuple2<>(columnName, type); + cachedColumnInfoMap.put(sb.toString(), columnInfo); + } + return columnInfo; + } + + /** + * 映射Model主对象的Class名称,到Model所对应的表名称。 + * + * @param modelClazz Model主对象的Class。 + * @return Model对象对应的数据表名称。 + */ + public static String mapToTableName(Class modelClazz) { + Table t = modelClazz.getAnnotation(Table.class); + return t == null ? null : t.name(); + } + + /** + * 主Model类型中,遍历所有包含RelationConstDict注解的字段,并将关联的静态字典中的数据, + * 填充到thisModel对象的被注解字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModel 主对象。 + * @param 主表对象类型。 + */ + @SuppressWarnings("unchecked") + public static void makeConstDictRelation(Class thisClazz, T thisModel) { + if (thisModel == null) { + return; + } + Field[] fields = ReflectUtil.getFields(thisClazz); + for (Field field : fields) { + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, field.getName()); + RelationConstDict r = thisTargetField.getAnnotation(RelationConstDict.class); + if (r == null) { + continue; + } + Field dictMapField = ReflectUtil.getField(r.constantDictClass(), "DICT_MAP"); + Map dictMap = (Map) ReflectUtil.getFieldValue(thisClazz, dictMapField); + Object id = ReflectUtil.getFieldValue(thisModel, r.masterIdField()); + if (id != null) { + String name = dictMap.get(id); + if (name != null) { + Map m = new HashMap<>(2); + m.put("id", id); + m.put("name", name); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + } + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象thatModel中的数据, + * 关联到thisModel对象的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModel 主对象。 + * @param thatModel 字典关联对象。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeDictRelation( + Class thisClazz, T thisModel, R thatModel, String thisRelationField) { + if (thatModel == null || thisModel == null) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationDict r = thisTargetField.getAnnotation(RelationDict.class); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Field slaveNameField = ReflectUtil.getField(thatClass, r.slaveNameField()); + Map m = new HashMap<>(2); + m.put("id", ReflectUtil.getFieldValue(thatModel, slaveIdField)); + m.put("name", ReflectUtil.getFieldValue(thatModel, slaveNameField)); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象集合thatModelList中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatModelList 字典关联对象列表集合。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeDictRelation( + Class thisClazz, List thisModelList, List thatModelList, String thisRelationField) { + if (CollectionUtils.isEmpty(thatModelList) + || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationDict r = thisTargetField.getAnnotation(RelationDict.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Field slaveNameField = ReflectUtil.getField(thatClass, r.slaveNameField()); + Map thatMap = new HashMap<>(20); + thatModelList.forEach(thatModel -> { + Object id = ReflectUtil.getFieldValue(thatModel, slaveIdField); + thatMap.put(id, thatModel); + }); + thisModelList.forEach(thisModel -> { + if (thisModel != null) { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMap.get(id); + if (thatModel != null) { + Map m = new HashMap<>(4); + m.put("id", id); + m.put("name", ReflectUtil.getFieldValue(thatModel, slaveNameField)); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + }); + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象集合thatModelMap中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * 该函数之所以使用Map,主要出于性能优化考虑,在连续使用thatModelMap进行关联时,有效的避免了从多次从List转换到Map的过程。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatMadelMap 字典关联对象映射集合。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeDictRelation( + Class thisClazz, List thisModelList, Map thatMadelMap, String thisRelationField) { + if (MapUtils.isEmpty(thatMadelMap) + || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationDict r = thisTargetField.getAnnotation(RelationDict.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveNameField = ReflectUtil.getField(thatClass, r.slaveNameField()); + thisModelList.forEach(thisModel -> { + if (thisModel != null) { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMadelMap.get(id); + if (thatModel != null) { + Map m = new HashMap<>(4); + m.put("id", id); + m.put("name", ReflectUtil.getFieldValue(thatModel, slaveNameField)); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + }); + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationOneToOne注解参数,将被关联对象列表thatModelList中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatModelList 一对一关联对象列表。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToOneRelation( + Class thisClazz, List thisModelList, List thatModelList, String thisRelationField) { + if (CollectionUtils.isEmpty(thatModelList) + || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationOneToOne r = thisTargetField.getAnnotation(RelationOneToOne.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Map thatMap = new HashMap<>(20); + thatModelList.forEach(thatModel -> { + Object id = ReflectUtil.getFieldValue(thatModel, slaveIdField); + thatMap.put(id, thatModel); + }); + // 判断放在循环的外部,提升一点儿效率。 + if (thisTargetField.getType().equals(Map.class)) { + thisModelList.forEach(thisModel -> { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMap.get(id); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, BeanUtil.beanToMap(thatModel)); + } + }); + } else { + thisModelList.forEach(thisModel -> { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMap.get(id); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, thatModel); + } + }); + } + } + + /** + * 根据主对象和关联对象各自的关联Id函数,将主对象列表和关联对象列表中的数据关联到一起,并将关联对象 + * 设置到主对象的指定关联字段中。 + * NOTE: 用于主对象关联字段中,没有包含RelationOneToOne注解的场景。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thisIdGetterFunc 主对象Id的Getter函数。 + * @param thatModelList 关联对象列表。 + * @param thatIdGetterFunc 关联对象Id的Getter函数。 + * @param thisRelationField 主对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToOneRelation( + Class thisClazz, + List thisModelList, + Function thisIdGetterFunc, + List thatModelList, + Function thatIdGetterFunc, + String thisRelationField) { + makeOneToOneRelation(thisClazz, thisModelList, + thisIdGetterFunc, thatModelList, thatIdGetterFunc, thisRelationField, false); + } + + /** + * 根据主对象和关联对象各自的关联Id函数,将主对象列表和关联对象列表中的数据关联到一起,并将关联对象 + * 设置到主对象的指定关联字段中。 + * NOTE: 用于主对象关联字段中,没有包含RelationOneToOne注解的场景。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thisIdGetterFunc 主对象Id的Getter函数。 + * @param thatModelList 关联对象列表。 + * @param thatIdGetterFunc 关联对象Id的Getter函数。 + * @param thisRelationField 主对象中保存被关联对象的字段名称。 + * @param orderByThatList 如果为true,则按照ThatModelList的顺序输出。同时thisModelList被排序后的新列表替换。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToOneRelation( + Class thisClazz, + List thisModelList, + Function thisIdGetterFunc, + List thatModelList, + Function thatIdGetterFunc, + String thisRelationField, + boolean orderByThatList) { + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + boolean isMap = thisTargetField.getType().equals(Map.class); + if (orderByThatList) { + List newThisModelList = new LinkedList<>(); + Map thisModelMap = + thisModelList.stream().collect(Collectors.toMap(thisIdGetterFunc, c -> c)); + thatModelList.forEach(thatModel -> { + Object thatId = thatIdGetterFunc.apply(thatModel); + T thisModel = thisModelMap.get(thatId); + if (thisModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, normalize(isMap, thatModel)); + newThisModelList.add(thisModel); + } + }); + thisModelList.clear(); + thisModelList.addAll(newThisModelList); + } else { + Map thatMadelMap = + thatModelList.stream().collect(Collectors.toMap(thatIdGetterFunc, c -> c)); + thisModelList.forEach(thisModel -> { + Object thisId = thisIdGetterFunc.apply(thisModel); + R thatModel = thatMadelMap.get(thisId); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, normalize(isMap, thatModel)); + } + }); + } + } + + private static Object normalize(boolean isMap, M model) { + return isMap ? BeanUtil.beanToMap(model) : model; + } + + /** + * 转换过滤对象到与其等效的Example对象。 + * + * @param filterModel 过滤对象。 + * @param modelClass 过滤对象的Class对象。 + * @param 过滤对象类型。 + * @return 转换后的Example对象。 + */ + public static Example convertFilterModelToExample(T filterModel, Class modelClass) { + if (filterModel == null) { + return null; + } + Example e = new Example(modelClass); + Example.Criteria c = e.createCriteria(); + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field field : fields) { + if (field.getAnnotation(Transient.class) != null) { + continue; + } + int modifiers = field.getModifiers(); + // transient类型的字段不能作为查询条件 + if ((modifiers & 128) == 0) { + ReflectUtil.setAccessible(field); + try { + Object o = field.get(filterModel); + if (o != null) { + c.andEqualTo(field.getName(), field.get(filterModel)); + } + } catch (IllegalAccessException ex) { + log.error("Failed to call reflection code.", ex); + throw new MyRuntimeException(ex); + } + } + } + return e; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyModelUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyPageUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyPageUtil.java new file mode 100644 index 00000000..76e70d0c --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/MyPageUtil.java @@ -0,0 +1,72 @@ +package com.orange.demo.common.core.util; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.Page; + +import java.util.List; + +/** + * 生成带有分页信息的数据列表 + * + * @author Jerry + * @date 2020-09-25 + */ +public class MyPageUtil { + + private static final String DATA_LIST_LITERAL = "dataList"; + private static final String TOTAL_COUNT_LITERAL = "totalCount"; + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageMethod.startPage之后,立即执行mybatis查询操作的结果集。 + * @param includeFields 结果集中需要返回到前端的字段,多个字段之间逗号分隔。 + * @return 返回只是包含includeFields字段的数据列表,以及结果集TotalCount。 + */ + public static JSONObject makeResponseData(List dataList, String includeFields) { + JSONObject pageData = new JSONObject(); + pageData.put(DATA_LIST_LITERAL, BeanQuery.select(includeFields).from(dataList).execute()); + if (dataList instanceof Page) { + pageData.put(TOTAL_COUNT_LITERAL, ((Page)dataList).getTotal()); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageMethod.startPage之后,立即执行mybatis查询操作的结果集。 + * @return 返回结果集和TotalCount。 + */ + public static JSONObject makeResponseData(List dataList) { + JSONObject pageData = new JSONObject(); + pageData.put(DATA_LIST_LITERAL, dataList); + if (dataList instanceof Page) { + pageData.put(TOTAL_COUNT_LITERAL, ((Page)dataList).getTotal()); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageMethod.startPage之后,立即执行mybatis查询操作的结果集。 + * @param totalCount 总数量。 + * @return 返回结果集和TotalCount。 + */ + public static JSONObject makeResponseData(List dataList, Long totalCount) { + JSONObject pageData = new JSONObject(); + pageData.put(DATA_LIST_LITERAL, dataList); + if (totalCount != null) { + pageData.put(TOTAL_COUNT_LITERAL, totalCount); + } + return pageData; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyPageUtil() { + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/RsaUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/RsaUtil.java new file mode 100644 index 00000000..a8e345c4 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/RsaUtil.java @@ -0,0 +1,114 @@ +package com.orange.demo.common.core.util; + +import javax.crypto.Cipher; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * Java RSA 加密工具类。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class RsaUtil { + + /** + * 密钥长度 于原文长度对应 以及越长速度越慢 + */ + private static final int KEY_SIZE = 1024; + /** + * 用于封装随机产生的公钥与私钥 + */ + private static Map keyMap = new HashMap<>(); + + /** + * 随机生成密钥对。 + */ + public static void genKeyPair() throws NoSuchAlgorithmException { + // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); + // 初始化密钥对生成器 + keyPairGen.initialize(KEY_SIZE, new SecureRandom()); + // 生成一个密钥对,保存在keyPair中 + KeyPair keyPair = keyPairGen.generateKeyPair(); + // 得到私钥 + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + // 得到公钥 + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded()); + // 得到私钥字符串 + String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded()); + // 将公钥和私钥保存到Map + //0表示公钥 + keyMap.put(0, publicKeyString); + //1表示私钥 + keyMap.put(1, privateKeyString); + } + + /** + * RSA公钥加密。 + * + * @param str 加密字符串 + * @param publicKey 公钥 + * @return 密文 + * @throws Exception 加密过程中的异常信息 + */ + public static String encrypt(String str, String publicKey) throws Exception { + //base64编码的公钥 + byte[] decoded = Base64.getDecoder().decode(publicKey); + RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); + //RSA加密 + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, pubKey); + return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8))); + } + + /** + * RSA私钥解密。 + * + * @param str 加密字符串 + * @param privateKey 私钥 + * @return 明文 + * @throws Exception 解密过程中的异常信息 + */ + public static String decrypt(String str, String privateKey) throws Exception { + //64位解码加密后的字符串 + byte[] inputByte = Base64.getDecoder().decode(str); + //base64编码的私钥 + byte[] decoded = Base64.getDecoder().decode(privateKey); + RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); + //RSA解密 + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, priKey); + return new String(cipher.doFinal(inputByte)); + } + + public static void main(String[] args) throws Exception { + long temp = System.currentTimeMillis(); + //生成公钥和私钥 + genKeyPair(); + //加密字符串 + System.out.println("公钥:" + keyMap.get(0)); + System.out.println("私钥:" + keyMap.get(1)); + System.out.println("生成密钥消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒"); + System.out.println("生成后的公钥前端使用!"); + System.out.println("生成后的私钥后台使用!"); + String message = "RSA测试ABCD~!@#$"; + System.out.println("原文:" + message); + temp = System.currentTimeMillis(); + String messageEn = encrypt(message, keyMap.get(0)); + System.out.println("密文:" + messageEn); + System.out.println("加密消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒"); + temp = System.currentTimeMillis(); + String messageDe = decrypt(messageEn, keyMap.get(1)); + System.out.println("解密:" + messageDe); + System.out.println("解密消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒"); + } +} \ No newline at end of file diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/TreeNode.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/TreeNode.java new file mode 100644 index 00000000..715fe5df --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/TreeNode.java @@ -0,0 +1,93 @@ +package com.orange.demo.common.core.util; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * 将列表结构组建为树结构的工具类。 + * + * @param 对象类型。 + * @param 节点之间关联键的类型。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +public class TreeNode { + + private K id; + private K parentId; + private T data; + private List> childList = new ArrayList<>(); + + /** + * 将列表结构组建为树结构的工具方法。 + * + * @param dataList 数据列表结构。 + * @param idFunc 获取关联id的函数对象。 + * @param parentIdFunc 获取关联ParentId的函数对象。 + * @param root 根节点。 + * @param 数据对象类型。 + * @param 节点之间关联键的类型。 + * @return 源数据对象的树结构存储。 + */ + public static List> build( + List dataList, Function idFunc, Function parentIdFunc, K root) { + List> treeNodeList = new ArrayList<>(); + for (T data : dataList) { + if (parentIdFunc.apply(data).equals(idFunc.apply(data))) { + continue; + } + TreeNode dataNode = new TreeNode<>(); + dataNode.setId(idFunc.apply(data)); + dataNode.setParentId(parentIdFunc.apply(data)); + dataNode.setData(data); + treeNodeList.add(dataNode); + } + return root == null ? toBuildTreeWithoutRoot(treeNodeList) : toBuildTree(treeNodeList, root); + } + + private static List> toBuildTreeWithoutRoot(List> treeNodes) { + Map> treeNodeMap = new HashMap<>(treeNodes.size()); + for (TreeNode treeNode : treeNodes) { + treeNodeMap.put(treeNode.id, treeNode); + } + List> treeNodeList = new ArrayList<>(); + for (TreeNode treeNode : treeNodes) { + TreeNode parentNode = treeNodeMap.get(treeNode.getParentId()); + if (parentNode == null) { + treeNodeList.add(treeNode); + } else { + parentNode.add(treeNode); + } + } + return treeNodeList; + } + + private static List> toBuildTree(List> treeNodes, K root) { + List> treeNodeList = new ArrayList<>(); + for (TreeNode treeNode : treeNodes) { + if (root.equals(treeNode.getParentId())) { + treeNodeList.add(treeNode); + } + for (TreeNode it : treeNodes) { + if (it.getParentId() == treeNode.getId()) { + if (treeNode.getChildList() == null) { + treeNode.setChildList(new ArrayList<>()); + } + treeNode.add(it); + } + } + } + return treeNodeList; + } + + private void add(TreeNode node) { + childList.add(node); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/UpDownloadUtil.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/UpDownloadUtil.java new file mode 100644 index 00000000..fedb42d5 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/util/UpDownloadUtil.java @@ -0,0 +1,180 @@ +package com.orange.demo.common.core.util; + +import com.alibaba.fastjson.JSON; +import com.orange.demo.common.core.constant.ApplicationConstant; +import com.orange.demo.common.core.constant.ErrorCodeEnum; +import com.orange.demo.common.core.object.ResponseResult; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; + +/** + * 上传或下载附件文件的工具类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Slf4j +public class UpDownloadUtil { + + /** + * 执行下载操作,并将读取的文件数据直接写入到HttpServletResponse应答对象。 + * + * @param rootBaseDir 文件下载的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param fileName 文件名。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @param response Http 应答对象。 + */ + public static void doDownload( + String rootBaseDir, + String modelName, + String fieldName, + String fileName, + Boolean asImage, + HttpServletResponse response) { + StringBuilder uploadPathBuilder = new StringBuilder(128); + uploadPathBuilder.append(rootBaseDir).append("/"); + if (Boolean.TRUE.equals(asImage)) { + uploadPathBuilder.append(ApplicationConstant.UPLOAD_IMAGE_PARENT_PATH); + } else { + uploadPathBuilder.append(ApplicationConstant.UPLOAD_ATTACHMENT_PARENT_PATH); + } + uploadPathBuilder.append("/").append(modelName).append("/").append(fieldName).append("/").append(fileName); + File file = new File(uploadPathBuilder.toString()); + if (!file.exists()) { + log.warn("Download file [" + uploadPathBuilder.toString() + "] failed, no file found!"); + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + response.setHeader("content-type", "application/octet-stream"); + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName); + byte[] buff = new byte[2048]; + try (OutputStream os = response.getOutputStream(); + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) { + int i = bis.read(buff); + while (i != -1) { + os.write(buff, 0, buff.length); + os.flush(); + i = bis.read(buff); + } + } catch (IOException e) { + log.error("Failed to call UpDownloadUtil.doDownload", e); + } + } + + /** + * 执行文件上传操作,并将与该文件下载对应的Url直接写入到HttpServletResponse应答对象,返回给前端。 + * + * @param rootBaseDir 存放上传文件的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param uploadFile Http请求中上传的文件对象。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @param response Http 应答对象。 + * @return 存储在本地上传文件名。 + * @throws IOException 文件操作错误。 + */ + public static String doUpload( + String rootBaseDir, + String modelName, + String fieldName, + Boolean asImage, + MultipartFile uploadFile, + HttpServletResponse response) throws IOException { + PrintWriter out = response.getWriter(); + response.setContentType("application/json; charset=utf-8"); + if (Objects.isNull(uploadFile) || uploadFile.isEmpty() || MyCommonUtil.isBlankOrNull(fieldName)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + out.print(JSON.toJSONString(ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FILE_ARGUMENT))); + return null; + } + StringBuilder uploadPathBuilder = new StringBuilder(128); + uploadPathBuilder.append(rootBaseDir).append("/"); + if (Boolean.TRUE.equals(asImage)) { + uploadPathBuilder.append(ApplicationConstant.UPLOAD_IMAGE_PARENT_PATH); + } else { + uploadPathBuilder.append(ApplicationConstant.UPLOAD_ATTACHMENT_PARENT_PATH); + } + uploadPathBuilder.append("/").append(modelName).append("/").append(fieldName).append("/"); + // 根据请求上传的uri构建下载uri,只是将末尾的/upload改为/download即可。 + HttpServletRequest request = ContextUtil.getHttpRequest(); + String uri = request.getRequestURI(); + uri = StringUtils.removeEnd(uri, "/"); + uri = StringUtils.removeEnd(uri, "/upload"); + String downloadUri = uri + "/download"; + StringBuilder filenameBuilder = new StringBuilder(64); + filenameBuilder.append(MyCommonUtil.generateUuid()) + .append(".").append(FilenameUtils.getExtension(uploadFile.getOriginalFilename())); + UploadFileInfo fileInfo = new UploadFileInfo(); + fileInfo.downloadUri = downloadUri; + fileInfo.filename = filenameBuilder.toString(); + try { + byte[] bytes = uploadFile.getBytes(); + Path path = Paths.get(uploadPathBuilder.toString() + filenameBuilder.toString()); + //如果没有files文件夹,则创建 + if (!Files.isWritable(path)) { + Files.createDirectories(Paths.get(uploadPathBuilder.toString())); + } + //文件写入指定路径 + Files.write(path, bytes); + } catch (IOException e) { + log.error("Failed to write uploaded file [" + uploadFile.getOriginalFilename() + " ].", e); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + out.print(JSON.toJSONString(ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FILE_IOERROR))); + return null; + } + out.print(JSON.toJSONString(ResponseResult.success(fileInfo))); + out.flush(); + out.close(); + return fileInfo.filename; + } + + /** + * 判断filename参数指定的文件名,是否被包含在fileInfoJson参数中。 + * + * @param fileInfoJson 内部类UploadFileInfo的JSONArray数组。 + * @param filename 被包含的文件名。 + * @return 存在返回true,否则false。 + */ + public static boolean containFile(String fileInfoJson, String filename) { + if (StringUtils.isAnyBlank(fileInfoJson, filename)) { + return false; + } + List fileInfoList = JSON.parseArray(fileInfoJson, UploadFileInfo.class); + if (CollectionUtils.isNotEmpty(fileInfoList)) { + for (UploadFileInfo fileInfo : fileInfoList) { + if (StringUtils.equals(filename, fileInfo.filename)) { + return true; + } + } + } + return false; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private UpDownloadUtil() { + } + + @Data + static class UploadFileInfo { + private String downloadUri; + private String filename; + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/AddGroup.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/AddGroup.java new file mode 100644 index 00000000..a0412961 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/AddGroup.java @@ -0,0 +1,10 @@ +package com.orange.demo.common.core.validator; + +/** + * 数据增加的验证分组。通常用于数据新增场景。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface AddGroup { +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictRef.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictRef.java new file mode 100644 index 00000000..eb897142 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictRef.java @@ -0,0 +1,48 @@ +package com.orange.demo.common.core.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 定义在Model对象中,标注字段值引用自指定的常量字典,和ConstDictRefValidator对象配合完成数据验证。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ConstDictValidator.class) +public @interface ConstDictRef { + + /** + * 引用的常量字典对象,该对象必须包含isValid的静态方法。 + * + * @return 最大长度。 + */ + Class constDictClass(); + + /** + * 超过边界后的错误消息提示。 + * + * @return 错误提示。 + */ + String message() default "无效的字典引用值!"; + + /** + * 验证分组。 + * + * @return 验证分组。 + */ + Class[] groups() default {}; + + /** + * 载荷对象类型。 + * + * @return 载荷对象。 + */ + Class[] payload() default {}; +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictValidator.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictValidator.java new file mode 100644 index 00000000..dd8dce31 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/ConstDictValidator.java @@ -0,0 +1,33 @@ +package com.orange.demo.common.core.validator; + +import cn.hutool.core.util.ReflectUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.lang.reflect.Method; + +/** + * 数据字段自定义验证,用于验证Model中字符串字段的最大长度和最小长度。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class ConstDictValidator implements ConstraintValidator { + + private ConstDictRef constDictRef; + + @Override + public void initialize(ConstDictRef constDictRef) { + this.constDictRef = constDictRef; + } + + @Override + public boolean isValid(Object s, ConstraintValidatorContext constraintValidatorContext) { + if (s == null) { + return true; + } + Method method = + ReflectUtil.getMethodByName(constDictRef.constDictClass(), "isValid"); + return ReflectUtil.invokeStatic(method, s); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLength.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLength.java new file mode 100644 index 00000000..31f669a1 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLength.java @@ -0,0 +1,55 @@ +package com.orange.demo.common.core.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 定义在Model或Dto对象中,UTF-8编码的字符串字段长度的上限和下限,和TextLengthValidator对象配合完成数据验证。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = TextLengthValidator.class) +public @interface TextLength { + + /** + * 字符串字段的最小长度。 + * + * @return 最小长度。 + */ + int min() default 0; + + /** + * 字符串字段的最大长度。 + * + * @return 最大长度。 + */ + int max() default Integer.MAX_VALUE; + + /** + * 超过边界后的错误消息提示。 + * + * @return 错误提示。 + */ + String message() default "字段长度超过最大字节数!"; + + /** + * 验证分组。 + * + * @return 验证分组。 + */ + Class[] groups() default { }; + + /** + * 载荷对象类型。 + * + * @return 载荷对象。 + */ + Class[] payload() default { }; +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLengthValidator.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLengthValidator.java new file mode 100644 index 00000000..cf643f25 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/TextLengthValidator.java @@ -0,0 +1,39 @@ +package com.orange.demo.common.core.validator; + +import org.apache.commons.lang3.CharUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * 数据字段自定义验证,用于验证Model中UTF-8编码的字符串字段的最大长度和最小长度。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class TextLengthValidator implements ConstraintValidator { + + private TextLength textLength; + + @Override + public void initialize(TextLength textLength) { + this.textLength = textLength; + } + + @Override + public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { + if (s == null) { + return true; + } + int length = 0; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (CharUtils.isAscii(c)) { + ++length; + } else { + length += 2; + } + } + return length >= textLength.min() && length <= textLength.max(); + } +} diff --git a/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/UpdateGroup.java b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/UpdateGroup.java new file mode 100644 index 00000000..f8d34107 --- /dev/null +++ b/orange-demo-single-service/common/common-core/src/main/java/com/orange/demo/common/core/validator/UpdateGroup.java @@ -0,0 +1,11 @@ +package com.orange.demo.common.core.validator; + +/** + * 数据修改的验证分组。通常用于数据更新的场景。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface UpdateGroup { + +} diff --git a/orange-demo-single-service/common/common-sequence/pom.xml b/orange-demo-single-service/common/common-sequence/pom.xml new file mode 100644 index 00000000..6c801e67 --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/pom.xml @@ -0,0 +1,24 @@ + + + + common + com.orange.demo + 1.0.0 + + 4.0.0 + + common-sequence + 1.0.0 + common-sequence + jar + + + + com.orange.demo + common-core + 1.0.0 + + + \ No newline at end of file diff --git a/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorAutoConfigure.java b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorAutoConfigure.java new file mode 100644 index 00000000..b335355e --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorAutoConfigure.java @@ -0,0 +1,14 @@ +package com.orange.demo.common.sequence.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-sequence模块的自动配置引导类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@EnableConfigurationProperties({IdGeneratorProperties.class}) +public class IdGeneratorAutoConfigure { + +} diff --git a/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorProperties.java b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorProperties.java new file mode 100644 index 00000000..b6ad2baa --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/config/IdGeneratorProperties.java @@ -0,0 +1,20 @@ +package com.orange.demo.common.sequence.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * common-sequence模块的配置类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Data +@ConfigurationProperties(prefix = "sequence") +public class IdGeneratorProperties { + + /** + * 基础版生成器所需的WorkNode参数值。仅当advanceIdGenerator为false时生效。 + */ + private Integer snowflakeWorkNode = 1; +} diff --git a/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/BasicIdGenerator.java b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/BasicIdGenerator.java new file mode 100644 index 00000000..729acb17 --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/BasicIdGenerator.java @@ -0,0 +1,48 @@ +package com.orange.demo.common.sequence.generator; + +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.IdUtil; + +/** + * 基础版snowflake计算工具类。 + * 和SnowflakeIdGenerator相比,相同点是均为基于Snowflake算法的生成器。不同点在于当前类的 + * WorkNodeId是通过配置文件静态指定的。而SnowflakeIdGenerator的WorkNodeId是由zk生成的。 + * + * @author Jerry + * @date 2020-09-25 + */ +public class BasicIdGenerator implements MyIdGenerator { + + private Snowflake snowflake; + + /** + * 构造函数。 + * + * @param workNode 工作节点。 + */ + public BasicIdGenerator(Integer workNode) { + snowflake = IdUtil.createSnowflake(workNode, 0); + } + + /** + * 获取基于Snowflake算法的数值型Id。 + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + @Override + public long nextLongId() { + return this.snowflake.nextId(); + } + + /** + * 获取基于Snowflake算法的字符串Id。 + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + @Override + public String nextStringId() { + return this.snowflake.nextIdStr(); + } +} diff --git a/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/MyIdGenerator.java b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/MyIdGenerator.java new file mode 100644 index 00000000..a1d67f08 --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/generator/MyIdGenerator.java @@ -0,0 +1,24 @@ +package com.orange.demo.common.sequence.generator; + +/** + * 分布式Id生成器的统一接口。 + * + * @author Jerry + * @date 2020-09-25 + */ +public interface MyIdGenerator { + + /** + * 获取数值型分布式Id。 + * + * @return 生成后的Id。 + */ + long nextLongId(); + + /** + * 获取字符型分布式Id。 + * + * @return 生成后的Id。 + */ + String nextStringId(); +} diff --git a/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/wrapper/IdGeneratorWrapper.java b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/wrapper/IdGeneratorWrapper.java new file mode 100644 index 00000000..21d2c568 --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/src/main/java/com/orange/demo/common/sequence/wrapper/IdGeneratorWrapper.java @@ -0,0 +1,52 @@ +package com.orange.demo.common.sequence.wrapper; + +import com.orange.demo.common.sequence.config.IdGeneratorProperties; +import com.orange.demo.common.sequence.generator.BasicIdGenerator; +import com.orange.demo.common.sequence.generator.MyIdGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * 分布式Id生成器的封装类。该对象可根据配置选择不同的生成器实现类。 + * + * @author Jerry + * @date 2020-09-25 + */ +@Component +public class IdGeneratorWrapper { + + @Autowired + private IdGeneratorProperties properties; + /** + * Id生成器接口对象。 + */ + private MyIdGenerator idGenerator; + + /** + * 今后如果支持更多Id生成器时,可以在该函数内实现不同生成器的动态选择。 + */ + @PostConstruct + public void init() { + idGenerator = new BasicIdGenerator(properties.getSnowflakeWorkNode()); + } + + /** + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + public long nextLongId() { + return idGenerator.nextLongId(); + } + + /** + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + public String nextStringId() { + return idGenerator.nextStringId(); + } +} diff --git a/orange-demo-single-service/common/common-sequence/src/main/resources/META-INF/spring.factories b/orange-demo-single-service/common/common-sequence/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..b2628200 --- /dev/null +++ b/orange-demo-single-service/common/common-sequence/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.orange.demo.common.sequence.config.IdGeneratorAutoConfigure \ No newline at end of file diff --git a/orange-demo-single-service/common/pom.xml b/orange-demo-single-service/common/pom.xml new file mode 100644 index 00000000..6dc41ee7 --- /dev/null +++ b/orange-demo-single-service/common/pom.xml @@ -0,0 +1,18 @@ + + + + com.orange.demo + OrangeSingleDemo + 1.0.0 + + 4.0.0 + + common + pom + + + common-core + common-sequence + + diff --git a/orange-demo-single-service/pom.xml b/orange-demo-single-service/pom.xml new file mode 100644 index 00000000..8cd555bc --- /dev/null +++ b/orange-demo-single-service/pom.xml @@ -0,0 +1,149 @@ + + + 4.0.0 + + com.orange.demo + OrangeSingleDemo + 1.0.0 + OrangeSingleDemo + pom + + + 2.2.5.RELEASE + Cairo-SR8 + 2.2.2 + UTF-8 + 1.8 + 1.8 + 1.8 + OrangeSingleDemo + + + 4.4 + 1.8 + 4.1.2 + 5.1.5 + 0.9.1 + 1.2.70 + 1.1.5 + 2.8.1 + 1.3.1.Final + + + 1.1.22 + 2.1.5 + 1.3.7 + 1.2.13 + + + + application + application-common + common + + + + + + org.springframework.boot + spring-boot-starter-web + + + spring-boot-starter-logging + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + javax.servlet + javax.servlet-api + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-cache + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.security + spring-security-crypto + + + + org.springframework.boot + spring-boot-starter-actuator + + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided + + + + org.projectlombok + lombok + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + io.spring.platform + platform-bom + ${spring-platform.version} + pom + import + + + + diff --git a/orange-demo-single-service/zz-orange-demo.sql b/orange-demo-single-service/zz-orange-demo.sql new file mode 100644 index 00000000..875d9dfc --- /dev/null +++ b/orange-demo-single-service/zz-orange-demo.sql @@ -0,0 +1,5043 @@ +CREATE DATABASE `zzdemo-single` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; +USE `zzdemo-single`; + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for zz_class +-- ---------------------------- +DROP TABLE IF EXISTS `zz_class`; +CREATE TABLE `zz_class` ( + `class_id` bigint(20) NOT NULL COMMENT '班级Id', + `class_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '班级名称', + `school_id` bigint(20) NOT NULL COMMENT '学校Id', + `leader_id` bigint(20) NOT NULL COMMENT '学生班长Id', + `finish_class_hour` int(11) NOT NULL DEFAULT '0' COMMENT '已完成课时数量', + `class_level` tinyint(4) NOT NULL COMMENT '班级级别(0: 初级班 1: 培优班 2: 冲刺提分班 3: 竞赛班)', + `create_user_id` bigint(20) NOT NULL COMMENT '创建用户', + `create_time` datetime NOT NULL COMMENT '班级创建时间', + `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '班级状态(0: 正常 1: 解散)', + PRIMARY KEY (`class_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_class +-- ---------------------------- +BEGIN; +INSERT INTO `zz_class` VALUES (1016971499387228160, '小学一年级随堂班', 1015817732197453824, 1015842628948463616, 15, 0, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016971692685922304, '小学二年级随堂班', 1015818056597508096, 1018000939508568064, 20, 0, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016971755373989888, '小学三年级随堂班', 1015817732197453824, 1015842628948463616, 100, 0, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016971816040402944, '小学四年级随堂班', 1015817732197453824, 1015852853839532032, 0, 0, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016971872105664512, '小学五年级随堂班', 1015818056597508096, 1018001219050541056, 0, 0, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016971931153076224, '小学六年级随堂班', 1015817732197453824, 1015852480873631744, 0, 0, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972016347779072, '小学一年级提高班', 1015817732197453824, 1015842628948463616, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972071955861504, '小学二年级提高班', 1015817732197453824, 1015852480873631744, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972128667045888, '小学三年级提高班', 1015818056597508096, 1018001219050541056, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972187949338624, '小学四年级提高班', 1015817732197453824, 1015852480873631744, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972236452270080, '小学五年级提高班', 1015817732197453824, 1015852480873631744, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972308355223552, '小学六年级提高班', 1015818056597508096, 1018000939508568064, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972406023786496, '小学奥林匹克竞赛班', 1015818056597508096, 1018001219050541056, 0, 1, 1093809448606765057, CURDATE(), 1); +INSERT INTO `zz_class` VALUES (1016972484746678272, '小学毕业提分班', 1015818056597508096, 1018000939508568064, 0, 2, 1093809448606765057, CURDATE(), 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_class_course +-- ---------------------------- +DROP TABLE IF EXISTS `zz_class_course`; +CREATE TABLE `zz_class_course` ( + `class_id` bigint(20) NOT NULL COMMENT '班级Id', + `course_id` bigint(20) NOT NULL COMMENT '课程Id', + `course_order` tinyint(4) NOT NULL DEFAULT '0' COMMENT '课程顺序(数值越小越靠前)', + PRIMARY KEY (`class_id`,`course_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_class_course +-- ---------------------------- +BEGIN; +INSERT INTO `zz_class_course` VALUES (1016971499387228160, 1016699195411402752, 0); +INSERT INTO `zz_class_course` VALUES (1016971499387228160, 1016917385529790464, 0); +INSERT INTO `zz_class_course` VALUES (1016971499387228160, 1016920878164480000, 0); +INSERT INTO `zz_class_course` VALUES (1016971499387228160, 1016923276064854016, 0); +INSERT INTO `zz_class_course` VALUES (1016971692685922304, 1016917385529790464, 0); +INSERT INTO `zz_class_course` VALUES (1016971755373989888, 1016917732260319232, 0); +INSERT INTO `zz_class_course` VALUES (1016971755373989888, 1016917900699373568, 0); +INSERT INTO `zz_class_course` VALUES (1016971755373989888, 1016918360520921088, 0); +INSERT INTO `zz_class_course` VALUES (1016971755373989888, 1016918605715738624, 0); +INSERT INTO `zz_class_course` VALUES (1016971755373989888, 1016918836729614336, 0); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_class_student +-- ---------------------------- +DROP TABLE IF EXISTS `zz_class_student`; +CREATE TABLE `zz_class_student` ( + `class_id` bigint(20) NOT NULL COMMENT '班级Id', + `student_id` bigint(20) NOT NULL COMMENT '学生Id', + PRIMARY KEY (`class_id`,`student_id`) USING BTREE, + KEY `idx_student_id` (`student_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_class_student +-- ---------------------------- +BEGIN; +INSERT INTO `zz_class_student` VALUES (1016971499387228160, 1015842628948463616); +INSERT INTO `zz_class_student` VALUES (1016971692685922304, 1015842628948463616); +INSERT INTO `zz_class_student` VALUES (1016971499387228160, 1015852480873631744); +INSERT INTO `zz_class_student` VALUES (1016971692685922304, 1015852853839532032); +INSERT INTO `zz_class_student` VALUES (1016972016347779072, 1018000939508568064); +INSERT INTO `zz_class_student` VALUES (1016972016347779072, 1018001219050541056); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_course +-- ---------------------------- +DROP TABLE IF EXISTS `zz_course`; +CREATE TABLE `zz_course` ( + `course_id` bigint(20) NOT NULL COMMENT '主键Id', + `course_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '课程名称', + `price` decimal(10,2) NOT NULL COMMENT '课程价格', + `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '课程描述', + `difficulty` int(11) NOT NULL COMMENT '课程难度(0: 容易 1: 普通 2: 很难)', + `grade_id` tinyint(4) NOT NULL COMMENT '年级Id', + `subject_id` tinyint(4) NOT NULL COMMENT '学科Id', + `class_hour` int(11) NOT NULL COMMENT '课时数量', + `picture_url` varchar(1024) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '多张课程图片地址', + `create_user_id` bigint(20) NOT NULL COMMENT '创建用户Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '最后修改时间', + PRIMARY KEY (`course_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_course +-- ---------------------------- +BEGIN; +INSERT INTO `zz_course` VALUES (1016699195411402752, '小学一年级拼音基础练习', 299.00, '小学一年级拼音基础练习', 0, 1, 0, 10, '[{\"name\":\"IMG_0003.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"b09ef09478d8452d908600ff98b6f1ce.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016917385529790464, '小学二年级语文课程', 980.00, '小学二年级课程', 1, 2, 0, 25, '[{\"name\":\"IMG_0455.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"79651a658e88408888f847366fbf98d0.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016917732260319232, '小学三年级语文课程', 1080.00, '小学三年级语文课程', 1, 3, 0, 30, '[{\"name\":\"IMG_0001.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"0d11548eb91142d49a9253c0060d3f94.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016917900699373568, '小学四年级语文课程', 888.00, '小学四年级语文课程', 1, 4, 0, 27, '[{\"name\":\"IMG_0002.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"7358b520e31e4ee0b2b8c4f9c31614d9.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016918360520921088, '小学五年级语文课程', 1199.00, '小学五年级语文课程', 2, 5, 0, 30, '[{\"name\":\"IMG_0004.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"cf804a5e14fb498fa8bf3745cad39bca.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016918605715738624, '小学六年级语文课程', 1288.00, '小学六年级语文课程', 2, 6, 0, 32, '[{\"name\":\"IMG_0006.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"a0d0476fac9c46f08b7ebef597b8765a.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016918836729614336, '天津小学一年级语文课程', 300.00, '天津小学一年级语文课程', 0, 1, 0, 20, '[{\"name\":\"IMG_0003.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"7f64971a69944b0082f21a6036c31efd.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016920152549888000, '天津小学二年级语文课程', 699.00, '天津小学二年级语文课程', 1, 2, 0, 20, '[{\"name\":\"IMG_0007.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"4baf08c1da8741bb808caf09475e49a9.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016920339255136256, '天津小学三年级语文课程', 998.00, '天津小学三年级语文课程', 1, 3, 0, 25, '[{\"name\":\"IMG_0009.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"6bc1eaab831d49708e4b1e0a5d657d61.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016920878164480000, '小学数学一年级课程', 388.00, '小学数学一年级课程', 0, 1, 1, 15, '[{\"name\":\"IMG_0010.JPG\",\"downloadUri\":\"/admin/coursepaper/course/download\",\"filename\":\"7e9583aba9594a98b1e0268837d2a5d0.JPG\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016921053566078976, '小学数学二年级课程', 700.00, '小学数学二年级课程', 0, 2, 1, 20, '[{\"name\":\"shuxue2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"7a1fdc70976f4820aa019f91514de272.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016921250996162560, '小学数学三年级课程', 700.00, '小学数学三年级课程', 1, 3, 1, 20, '[{\"name\":\"shuxue.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"f14c0f101146453c80607230e842f1c9.jpg\"},{\"name\":\"shuxue2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"b8451e95fa314facaa8a3cd720888574.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016921446102601728, '小学数学四年级课程', 800.00, '小学数学四年级课程', 1, 4, 1, 21, '[{\"name\":\"shuxue2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"78e1cac8c4284c8a82c7ea4bef5162a4.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016921667582824448, '小学数学五年级课程', 900.00, '小学数学五年级课程', 2, 5, 1, 25, '[{\"name\":\"shuxue.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"167967c0c025406483861eed038111a0.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016922210208321536, '小学数学六年级课程', 1099.00, '小学数学六年级课程', 2, 6, 1, 20, '[{\"name\":\"shuxue2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"7f79d414e4b14ce19d75f038306088a9.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016922414236045312, '天津数学一年级课程', 499.00, '天津数学一年级课程', 0, 1, 1, 20, '[{\"name\":\"shuxue.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"59d6f1cea3584a1ab637ab6a69ebacd6.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016922587657932800, '天津数学二年级课程', 500.00, '天津数学二年级课程', 1, 2, 1, 25, '[{\"name\":\"shuxue2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"830a0f67737e4b79a605ecbbd20f9418.jpg\"},{\"name\":\"shuxue.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"5f9be80c275c48bda8a67562276aa04e.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016922752997396480, '天津数学三年级课程', 799.00, '天津数学三年级课程', 2, 3, 1, 24, '[{\"name\":\"shuxue2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"0fb454a0d56843e6b77bfc874f8a4a0f.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016923276064854016, '小学英语一年级课程', 399.00, '小学英语一年级课程', 0, 1, 2, 15, '[{\"name\":\"english.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"44177c3674f543fda24222b8297ef203.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016923512082534400, '小学英语二年级课程', 428.00, '小学英语二年级课程', 0, 2, 2, 15, '[{\"name\":\"english2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"1a775271ccf9436c8b4e92a841556d79.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016924065042796544, '小学英语三年级课程', 666.00, '小学英语三年级课程', 1, 3, 2, 25, '[{\"name\":\"english2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"d9eded33a06d4931ae326cac3871948f.jpg\"},{\"name\":\"english.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"f179474ce95e4210b4e2a04d480c6535.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016924308048187392, '小学英语四年级课程', 700.00, '小学英语四年级课程', 1, 4, 2, 25, '[{\"name\":\"english.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"c71da8ce21b44dd8bb761fa93b09a341.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016924664354312192, '小学英语五年级课程', 805.00, '小学英语五年级课程', 2, 5, 2, 28, '[{\"name\":\"english2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"0d81493585d94962acbcdc81c074224a.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016924985629609984, '小学英语六年级课程', 998.00, '小学英语六年级课程', 2, 6, 2, 30, '[{\"name\":\"english.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"17b2b4380fc746659666f9c51bfa7618.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016925257013661696, '天津英语一年级课程', 499.00, '天津英语一年级课程', 0, 1, 2, 20, '[{\"name\":\"english2.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"dd15b00b79154c398a3daa9fb8cff9f9.jpg\"},{\"name\":\"english.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"2a0b1f0d262649a294a9f647421f5a7e.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1016925420855758848, '天津英语二年级课程', 528.00, '天津英语二年级课程', 1, 2, 2, 23, '[{\"name\":\"english.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"7dc07373076f452eac02d9405ac83479.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +INSERT INTO `zz_course` VALUES (1018007994936070144, '小学一年级语文课程B', 1111.00, '1112222', 0, 1, 1, 23, '[{\"name\":\"微信图片_20190406094309.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"b11699acb7094c11a1c1efa71d53ee19.jpg\"},{\"name\":\"微信图片_20190406094305.jpg\",\"downloadUri\":\"/admin/app/course/download\",\"filename\":\"e248874a47e849e29dd7b699b2685d30.jpg\"}]', 1093809448606765057, CURDATE(), CURDATE()); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_course_trans_stats +-- ---------------------------- +DROP TABLE IF EXISTS `zz_course_trans_stats`; +CREATE TABLE `zz_course_trans_stats` ( + `stats_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键Id', + `stats_date` date NOT NULL COMMENT '统计日期', + `subject_id` tinyint(4) NOT NULL COMMENT '科目Id', + `grade_id` tinyint(4) NOT NULL COMMENT '年级Id', + `grade_name` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '年级名称', + `course_id` bigint(20) NOT NULL COMMENT '课程Id', + `course_name` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '课程名称', + `student_attend_count` int(11) NOT NULL COMMENT '学生上课次数', + `student_flower_amount` int(11) NOT NULL COMMENT '学生献花数量', + `student_flower_count` int(11) NOT NULL COMMENT '学生献花次数', + PRIMARY KEY (`stats_id`) USING BTREE, + UNIQUE KEY `uk_stats_date_subject_id_grade_course_id` (`stats_date`,`grade_id`,`course_id`) USING BTREE, + KEY `idx_grade_id` (`grade_id`) USING BTREE, + KEY `idx_course_id` (`course_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_course_trans_stats +-- ---------------------------- +BEGIN; +INSERT INTO `zz_course_trans_stats` VALUES (1, '2020-01-10', 0, 1, NULL, 1016699195411402752, '小学一年级拼音基础练习', 1, 0, 0); +INSERT INTO `zz_course_trans_stats` VALUES (2, '2020-01-10', 0, 2, NULL, 1016917385529790464, '小学二年级语文课程', 2, 55, 1); +INSERT INTO `zz_course_trans_stats` VALUES (3, '2020-01-10', 0, 3, NULL, 1016917732260319232, '小学三年级语文课程', 2, 118, 2); +INSERT INTO `zz_course_trans_stats` VALUES (4, '2020-01-10', 0, 4, NULL, 1016917900699373568, '小学四年级语文课程', 0, 40, 1); +INSERT INTO `zz_course_trans_stats` VALUES (5, '2020-01-11', 0, 1, NULL, 1016699195411402752, '小学一年级拼音基础练习', 3, 119, 2); +INSERT INTO `zz_course_trans_stats` VALUES (6, '2020-01-11', 0, 2, NULL, 1016917385529790464, '小学二年级语文课程', 1, 36, 1); +INSERT INTO `zz_course_trans_stats` VALUES (7, '2020-01-11', 0, 3, NULL, 1016917732260319232, '小学三年级语文课程', 1, 147, 2); +INSERT INTO `zz_course_trans_stats` VALUES (8, '2020-01-11', 0, 4, NULL, 1016917900699373568, '小学四年级语文课程', 0, 76, 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_grade +-- ---------------------------- +DROP TABLE IF EXISTS `zz_grade`; +CREATE TABLE `zz_grade` ( + `grade_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id', + `grade_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '年级名称', + `status` int(11) NOT NULL COMMENT '是否正在使用(0:不是,1:是)', + PRIMARY KEY (`grade_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_grade +-- ---------------------------- +BEGIN; +INSERT INTO `zz_grade` VALUES (1, '一年级', 1); +INSERT INTO `zz_grade` VALUES (2, '二年级', 1); +INSERT INTO `zz_grade` VALUES (3, '三年级', 1); +INSERT INTO `zz_grade` VALUES (4, '四年级', 1); +INSERT INTO `zz_grade` VALUES (5, '五年级', 1); +INSERT INTO `zz_grade` VALUES (6, '六年级', 1); +INSERT INTO `zz_grade` VALUES (7, '初一', 1); +INSERT INTO `zz_grade` VALUES (8, '初二', 1); +INSERT INTO `zz_grade` VALUES (9, '初三', 1); +INSERT INTO `zz_grade` VALUES (10, '高一', 1); +INSERT INTO `zz_grade` VALUES (11, '高二', 1); +INSERT INTO `zz_grade` VALUES (12, '高三', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_material_edition +-- ---------------------------- +DROP TABLE IF EXISTS `zz_material_edition`; +CREATE TABLE `zz_material_edition` ( + `edition_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id', + `edition_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '教材版本名称', + `status` int(11) NOT NULL COMMENT '是否正在使用(0:不是,1:是)', + PRIMARY KEY (`edition_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_material_edition +-- ---------------------------- +BEGIN; +INSERT INTO `zz_material_edition` VALUES (1, '苏教版', 1); +INSERT INTO `zz_material_edition` VALUES (2, '人教版', 1); +INSERT INTO `zz_material_edition` VALUES (3, '湘教版', 1); +INSERT INTO `zz_material_edition` VALUES (4, '沪教版', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_school_info +-- ---------------------------- +DROP TABLE IF EXISTS `zz_school_info`; +CREATE TABLE `zz_school_info` ( + `school_id` bigint(20) NOT NULL COMMENT '学校Id', + `school_name` varchar(128) COLLATE utf8mb4_bin NOT NULL COMMENT '学校名称', + `province_id` bigint(20) NOT NULL COMMENT '所在省Id', + `city_id` bigint(20) NOT NULL COMMENT '所在城市Id', + PRIMARY KEY (`school_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_school_info +-- ---------------------------- +BEGIN; +INSERT INTO `zz_school_info` VALUES (1014065909648330752, '公司总部', 110000000000, 110100000000); +INSERT INTO `zz_school_info` VALUES (1015817732197453824, '北京校区', 110000000000, 110100000000); +INSERT INTO `zz_school_info` VALUES (1015818056597508096, '天津校区', 120000000000, 120100000000); +INSERT INTO `zz_school_info` VALUES (1015818992220901376, '浙江校区', 330000000000, 330100000000); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_student +-- ---------------------------- +DROP TABLE IF EXISTS `zz_student`; +CREATE TABLE `zz_student` ( + `student_id` bigint(20) NOT NULL COMMENT '学生Id', + `login_mobile` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '登录手机', + `student_name` varchar(20) COLLATE utf8mb4_bin NOT NULL COMMENT '学生姓名', + `province_id` bigint(20) NOT NULL COMMENT '所在省份Id', + `city_id` bigint(20) NOT NULL COMMENT '所在城市Id', + `district_id` bigint(20) NOT NULL COMMENT '区县Id', + `gender` int(11) NOT NULL COMMENT '学生性别 (0: 女生 1: 男生)', + `birthday` date NOT NULL COMMENT '生日', + `experience_level` tinyint(4) NOT NULL COMMENT '经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)', + `total_coin` int(11) NOT NULL DEFAULT '0' COMMENT '总共充值学币数量', + `left_coin` int(11) NOT NULL DEFAULT '0' COMMENT '可用学币数量', + `grade_id` int(11) NOT NULL COMMENT '年级Id', + `school_id` bigint(20) NOT NULL COMMENT '校区Id', + `register_time` datetime NOT NULL COMMENT '注册时间', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '学生状态 (0: 正常 1: 锁定 2: 注销)', + PRIMARY KEY (`student_id`) USING BTREE, + KEY `idx_login_mobile` (`login_mobile`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_student +-- ---------------------------- +BEGIN; +INSERT INTO `zz_student` VALUES (1015842628948463616, '13834561230', '张三', 110000000000, 110100000000, 110105000000, 1, '2010-08-19', 1, 3412, 1077, 4, 1015817732197453824, CURDATE(), 0); +INSERT INTO `zz_student` VALUES (1015852480873631744, '13945651267', '李军', 110000000000, 110100000000, 110107000000, 1, '2011-11-18', 1, 3178, 3024, 3, 1015817732197453824, CURDATE(), 0); +INSERT INTO `zz_student` VALUES (1015852853839532032, '13709481736', '王石', 110000000000, 110100000000, 110108000000, 1, '2015-01-15', 0, 3187, 2199, 1, 1015817732197453824, CURDATE(), 0); +INSERT INTO `zz_student` VALUES (1018000939508568064, '13700023451', '天津二哥', 120000000000, 120100000000, 120103000000, 1, '2010-06-10', 0, 1287, 634, 3, 1015818056597508096, CURDATE(), 0); +INSERT INTO `zz_student` VALUES (1018001219050541056, '13903122987', '南开学霸', 120000000000, 120100000000, 120104000000, 0, '2009-07-17', 2, 8721, 7023, 4, 1015818056597508096, CURDATE(), 0); +INSERT INTO `zz_student` VALUES (1023072888777609216, '13920134567', 'aaa', 120000000000, 120100000000, 120103000000, 1, '2020-01-08', 1, 0, 0, 1, 1015818992220901376, CURDATE(), 0); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_student_action_stats +-- ---------------------------- +DROP TABLE IF EXISTS `zz_student_action_stats`; +CREATE TABLE `zz_student_action_stats` ( + `stats_id` bigint(20) NOT NULL COMMENT '主键Id', + `stats_date` date NOT NULL COMMENT '统计日期', + `stats_month` date DEFAULT NULL COMMENT '统计小时', + `grade_id` int(11) NOT NULL COMMENT '年级Id', + `province_id` bigint(20) NOT NULL COMMENT '学生所在省Id', + `city_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '学生所在城市Id', + `buy_course_amount` int(11) NOT NULL DEFAULT '0' COMMENT '购课学币数量', + `buy_course_count` int(11) NOT NULL DEFAULT '0' COMMENT '购买课程次数', + `buy_video_amount` int(11) NOT NULL DEFAULT '0' COMMENT '购买视频学币数量', + `buy_video_count` int(11) NOT NULL DEFAULT '0' COMMENT '购买视频次数', + `buy_paper_amount` int(11) NOT NULL DEFAULT '0' COMMENT '购买作业学币数量', + `buy_paper_count` int(11) NOT NULL DEFAULT '0' COMMENT '购买作业次数', + `buy_flower_amount` int(11) NOT NULL DEFAULT '0' COMMENT '购买献花数量', + `buy_flower_count` int(11) NOT NULL DEFAULT '0' COMMENT '购买献花次数', + `recharge_coin_amount` int(11) NOT NULL DEFAULT '0' COMMENT '充值学币数量', + `recharge_coin_count` int(11) NOT NULL DEFAULT '0' COMMENT '充值学币次数', + `do_course_count` int(11) NOT NULL COMMENT '线下课程上课次数', + `watch_video_count` int(11) NOT NULL DEFAULT '0' COMMENT '观看视频次数', + `watch_video_total_second` int(11) NOT NULL COMMENT '购买献花消费学币数量', + `do_exercise_count` int(11) NOT NULL DEFAULT '0' COMMENT '做题数量', + `do_exercise_correct_count` int(11) NOT NULL DEFAULT '0' COMMENT '做题正确的数量', + PRIMARY KEY (`stats_id`) USING BTREE, + UNIQUE KEY `uk_stats_date_grade_id_region_id` (`stats_date`,`grade_id`,`province_id`,`city_id`) USING BTREE, + KEY `idx_province_id` (`province_id`) USING BTREE, + KEY `idx_city_id` (`city_id`) USING BTREE, + KEY `idx_grade_id` (`grade_id`) USING BTREE, + KEY `idx_stats_month` (`stats_month`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_student_action_stats +-- ---------------------------- +BEGIN; +INSERT INTO `zz_student_action_stats` VALUES (1293010719117148160, '2020-01-10', NULL, 1, 110000000000, 110100000000, 16, 5, 0, 0, 14, 2, 123, 3, 2694, 5, 3, 3, 707, 3, 0); +INSERT INTO `zz_student_action_stats` VALUES (1293010719121342468, '2020-01-10', NULL, 2, 110000000000, 110100000000, 8, 3, 0, 0, 6, 1, 133, 2, 1717, 3, 3, 0, 0, 4, 0); +INSERT INTO `zz_student_action_stats` VALUES (1293010719121342475, '2020-01-10', NULL, 4, 110000000000, 110100000000, 0, 0, 0, 0, 16, 2, 55, 2, 1881, 4, 2, 6, 2987, 2, 0); +INSERT INTO `zz_student_action_stats` VALUES (1293010719121342482, '2020-01-10', NULL, 2, 120000000000, 120100000000, 12, 4, 0, 0, 0, 0, 134, 2, 292, 2, 3, 1, 434, 1, 1); +INSERT INTO `zz_student_action_stats` VALUES (1293010719121342489, '2020-01-10', NULL, 3, 120000000000, 120100000000, 5, 2, 0, 0, 18, 3, 79, 2, 1343, 2, 2, 4, 2266, 5, 5); +INSERT INTO `zz_student_action_stats` VALUES (1293010719121342497, '2020-01-10', NULL, 4, 120000000000, 120100000000, 10, 3, 0, 0, 33, 4, 212, 4, 766, 2, 3, 2, 1480, 4, 4); +INSERT INTO `zz_student_action_stats` VALUES (1293010719297503232, '2020-01-11', NULL, 1, 110000000000, 110100000000, 12, 3, 0, 0, 13, 2, 216, 3, 1119, 2, 3, 2, 511, 2, 2); +INSERT INTO `zz_student_action_stats` VALUES (1293010719297503240, '2020-01-11', NULL, 2, 110000000000, 110100000000, 7, 4, 0, 0, 20, 3, 142, 2, 509, 2, 3, 3, 1699, 3, 3); +INSERT INTO `zz_student_action_stats` VALUES (1293010719297503248, '2020-01-11', NULL, 3, 110000000000, 110100000000, 2, 1, 0, 0, 11, 2, 158, 3, 1571, 2, 3, 0, 0, 3, 3); +INSERT INTO `zz_student_action_stats` VALUES (1293010719297503255, '2020-01-11', NULL, 2, 120000000000, 120100000000, 0, 0, 0, 0, 15, 2, 0, 0, 1741, 3, 2, 3, 1280, 3, 3); +INSERT INTO `zz_student_action_stats` VALUES (1293010719301697539, '2020-01-11', NULL, 3, 120000000000, 120100000000, 3, 2, 0, 0, 0, 0, 176, 3, 1702, 2, 2, 2, 1306, 2, 2); +INSERT INTO `zz_student_action_stats` VALUES (1293010719301697545, '2020-01-11', NULL, 4, 120000000000, 120100000000, 7, 2, 0, 0, 9, 2, 122, 2, 1257, 3, 0, 3, 1210, 2, 2); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_student_action_trans +-- ---------------------------- +DROP TABLE IF EXISTS `zz_student_action_trans`; +CREATE TABLE `zz_student_action_trans` ( + `trans_id` bigint(20) NOT NULL COMMENT '主键Id', + `student_id` bigint(20) NOT NULL COMMENT '学生Id', + `student_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '学生名称', + `school_id` bigint(20) NOT NULL COMMENT '学生校区', + `grade_id` int(11) NOT NULL COMMENT '年级Id', + `action_type` tinyint(4) NOT NULL COMMENT '行为类型(0: 充值 1: 购课 2: 上课签到 3: 上课签退 4: 看视频课 5: 做作业 6: 刷题 7: 献花)', + `device_type` tinyint(4) NOT NULL COMMENT '设备类型(0: iOS 1: Android 2: PC)', + `watch_video_seconds` int(11) DEFAULT NULL COMMENT '看视频秒数', + `flower_count` int(11) DEFAULT NULL COMMENT '购买献花数量', + `paper_count` int(11) DEFAULT NULL COMMENT '购买作业数量', + `video_count` int(11) DEFAULT NULL COMMENT '购买视频数量', + `course_count` int(11) DEFAULT NULL COMMENT '购买课程数量', + `coin_count` int(11) DEFAULT NULL COMMENT '充值学币数量', + `exercise_correct_flag` tinyint(4) DEFAULT NULL COMMENT '做题是否正确标记', + `create_time` datetime NOT NULL COMMENT '发生时间', + PRIMARY KEY (`trans_id`) USING BTREE, + KEY `idx_student_id` (`student_id`) USING BTREE, + KEY `idx_grade_id` (`grade_id`) USING BTREE, + KEY `idx_action_type` (`action_type`) USING BTREE, + KEY `idx_create_time` (`create_time`) USING BTREE, + KEY `idx_device_type` (`action_type`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_student_action_trans +-- ---------------------------- +BEGIN; +INSERT INTO `zz_student_action_trans` VALUES (1018423001834328064, 1015841864515588096, '张大', 1015817732197453824, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, 617, NULL, '2020-01-10 11:13:23'); +INSERT INTO `zz_student_action_trans` VALUES (1018803416562667520, 1015841864515588096, '张大', 1015817732197453824, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, 468, NULL, '2020-01-10 11:13:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018803445553696768, 1015841864515588096, '张大', 1015817732197453824, 1, 0, 1, NULL, NULL, NULL, NULL, NULL, 548, NULL, '2020-01-10 11:13:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018803590760501248, 1015841864515588096, '张大', 1015817732197453824, 1, 0, 2, NULL, NULL, NULL, NULL, NULL, 250, NULL, '2020-01-10 11:13:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018803838299934720, 1015841864515588096, '张大', 1015817732197453824, 1, 0, 2, NULL, NULL, NULL, NULL, NULL, 811, NULL, '2020-01-10 11:13:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018803855614021632, 1015841864515588096, '张大', 1015817732197453824, 1, 1, 2, NULL, NULL, NULL, NULL, 5, NULL, NULL, '2020-01-10 11:13:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018803873183961088, 1015841864515588096, '张大', 1015817732197453824, 1, 1, 1, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-10 11:13:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018803890552573952, 1015841864515588096, '张大', 1015817732197453824, 1, 1, 0, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-10 11:13:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018803897053745152, 1015841864515588096, '张大', 1015817732197453824, 1, 1, 0, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-10 11:14:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018803910555209728, 1015841864515588096, '张大', 1015817732197453824, 1, 1, 0, NULL, NULL, NULL, NULL, 1, NULL, NULL, '2020-01-10 11:14:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018803926451621888, 1015841864515588096, '张大', 1015817732197453824, 1, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018803940418654208, 1015841864515588096, '张大', 1015817732197453824, 1, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018803955727863808, 1015841864515588096, '张大', 1015817732197453824, 1, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018803973427826688, 1015841864515588096, '张大', 1015817732197453824, 1, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018803982235865088, 1015841864515588096, '张大', 1015817732197453824, 1, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018803988154028032, 1015841864515588096, '张大', 1015817732197453824, 1, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018804009414955008, 1015841864515588096, '张大', 1015817732197453824, 1, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018804025521082368, 1015841864515588096, '张大', 1015817732197453824, 1, 4, 1, 342, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018804040956121088, 1015841864515588096, '张大', 1015817732197453824, 1, 4, 0, 324, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018804057104191488, 1015841864515588096, '张大', 1015817732197453824, 1, 4, 2, 41, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:14:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018804073457782784, 1015841864515588096, '张大', 1015817732197453824, 1, 5, 2, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:15:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018804090696372224, 1015841864515588096, '张大', 1015817732197453824, 1, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:15:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018804111659503616, 1015841864515588096, '张大', 1015817732197453824, 1, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:15:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018804134585569280, 1015841864515588096, '张大', 1015817732197453824, 1, 9, 0, NULL, 15, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:15:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018804139606151168, 1015841864515588096, '张大', 1015817732197453824, 1, 9, 0, NULL, 60, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:15:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018804156295286784, 1015841864515588096, '张大', 1015817732197453824, 1, 9, 1, NULL, 48, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:15:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018804244874792960, 1015841864515588096, '张大', 1015817732197453824, 1, 10, 1, NULL, NULL, 4, NULL, NULL, NULL, NULL, '2020-01-10 11:15:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018804264130842624, 1015841864515588096, '张大', 1015817732197453824, 1, 10, 0, NULL, NULL, 10, NULL, NULL, NULL, NULL, '2020-01-10 11:15:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018806531059879936, 1015841864515588096, '张大', 1015817732197453824, 2, 0, 0, NULL, NULL, NULL, NULL, NULL, 545, NULL, '2020-01-10 11:15:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018806537225506816, 1015841864515588096, '张大', 1015817732197453824, 2, 0, 0, NULL, NULL, NULL, NULL, NULL, 743, NULL, '2020-01-10 11:15:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018806554631868416, 1015841864515588096, '张大', 1015817732197453824, 2, 0, 1, NULL, NULL, NULL, NULL, NULL, 429, NULL, '2020-01-10 11:15:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018806571031597056, 1015841864515588096, '张大', 1015817732197453824, 2, 1, 1, NULL, NULL, NULL, NULL, 3, NULL, NULL, '2020-01-10 11:15:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018806573841780736, 1015841864515588096, '张大', 1015817732197453824, 2, 1, 1, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-10 11:16:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018806589612363776, 1015841864515588096, '张大', 1015817732197453824, 2, 1, 2, NULL, NULL, NULL, NULL, 3, NULL, NULL, '2020-01-10 11:16:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018806602698592256, 1015841864515588096, '张大', 1015817732197453824, 2, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:16:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018806617378656256, 1015841864515588096, '张大', 1015817732197453824, 2, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:16:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018806622076276736, 1015841864515588096, '张大', 1015817732197453824, 2, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:16:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018806639230980096, 1015841864515588096, '张大', 1015817732197453824, 2, 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:16:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018806643047796736, 1015841864515588096, '张大', 1015817732197453824, 2, 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:16:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018806664732348416, 1015841864515588096, '张大', 1015817732197453824, 2, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:16:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018806668976984064, 1015841864515588096, '张大', 1015817732197453824, 2, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:16:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018806682558140416, 1015841864515588096, '张大', 1015817732197453824, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:16:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018806691030634496, 1015841864515588096, '张大', 1015817732197453824, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:16:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018806709733036032, 1015841864515588096, '张大', 1015817732197453824, 2, 9, 1, NULL, 49, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:16:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018806725126131712, 1015841864515588096, '张大', 1015817732197453824, 2, 9, 0, NULL, 84, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018806755786493952, 1015841864515588096, '张大', 1015817732197453824, 2, 10, 0, NULL, NULL, 6, NULL, NULL, NULL, NULL, '2020-01-10 11:17:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018806774576975872, 1015841864515588096, '张大', 1015817732197453824, 4, 10, 0, NULL, NULL, 8, NULL, NULL, NULL, NULL, '2020-01-10 11:17:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018806780532887552, 1015841864515588096, '张大', 1015817732197453824, 4, 10, 0, NULL, NULL, 8, NULL, NULL, NULL, NULL, '2020-01-10 11:17:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018806796135698432, 1015841864515588096, '张大', 1015817732197453824, 4, 9, 0, NULL, 33, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018806799491141632, 1015841864515588096, '张大', 1015817732197453824, 4, 9, 0, NULL, 22, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018806813844049920, 1015841864515588096, '张大', 1015817732197453824, 4, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:17:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018806817694420992, 1015841864515588096, '张大', 1015817732197453824, 4, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, '2020-01-10 11:17:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018806836275187712, 1015841864515588096, '张大', 1015817732197453824, 4, 4, 0, 627, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018806840423354368, 1015841864515588096, '张大', 1015817732197453824, 4, 4, 0, 463, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018806858966372352, 1015841864515588096, '张大', 1015817732197453824, 4, 4, 1, 104, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018806862112100352, 1015841864515588096, '张大', 1015817732197453824, 4, 4, 1, 329, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:17:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018806877714911232, 1015841864515588096, '张大', 1015817732197453824, 4, 4, 2, 601, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:18:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018806899365908480, 1015841864515588096, '张大', 1015817732197453824, 4, 4, 2, 863, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:18:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018806913865617408, 1015841864515588096, '张大', 1015817732197453824, 4, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:18:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018806916679995392, 1015841864515588096, '张大', 1015817732197453824, 4, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:18:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018806932240863232, 1015841864515588096, '张大', 1015817732197453824, 4, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:18:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018806950439948288, 1015841864515588096, '张大', 1015817732197453824, 4, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:18:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018806964746719232, 1015841864515588096, '张大', 1015817732197453824, 4, 0, 1, NULL, NULL, NULL, NULL, NULL, 618, NULL, '2020-01-10 11:18:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018806967473016832, 1015841864515588096, '张大', 1015817732197453824, 4, 0, 1, NULL, NULL, NULL, NULL, NULL, 25, NULL, '2020-01-10 11:18:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018806982023057408, 1015841864515588096, '张大', 1015817732197453824, 4, 0, 0, NULL, NULL, NULL, NULL, NULL, 523, NULL, '2020-01-10 11:18:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018806984879378432, 1015841864515588096, '张大', 1015817732197453824, 4, 0, 0, NULL, NULL, NULL, NULL, NULL, 715, NULL, '2020-01-10 11:18:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018807041246629888, 1015842628948463616, '张三', 1015818056597508096, 2, 0, 0, NULL, NULL, NULL, NULL, NULL, 269, NULL, '2020-01-10 11:18:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018807044560130048, 1015842628948463616, '张三', 1015818056597508096, 2, 0, 0, NULL, NULL, NULL, NULL, NULL, 23, NULL, '2020-01-10 11:18:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018807060251021312, 1015842628948463616, '张三', 1015818056597508096, 2, 1, 0, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-10 11:19:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018807064650846208, 1015842628948463616, '张三', 1015818056597508096, 2, 1, 0, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-10 11:19:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018807069302329344, 1015842628948463616, '张三', 1015818056597508096, 2, 1, 0, NULL, NULL, NULL, NULL, 5, NULL, NULL, '2020-01-10 11:19:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018807073211420672, 1015842628948463616, '张三', 1015818056597508096, 2, 1, 0, NULL, NULL, NULL, NULL, 1, NULL, NULL, '2020-01-10 11:19:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018807086876463104, 1015842628948463616, '张三', 1015818056597508096, 2, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018807102311501824, 1015842628948463616, '张三', 1015818056597508096, 2, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018807118379880448, 1015842628948463616, '张三', 1015818056597508096, 2, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018807134397927424, 1015842628948463616, '张三', 1015818056597508096, 2, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018807148918607872, 1015842628948463616, '张三', 1015818056597508096, 2, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018807151863009280, 1015842628948463616, '张三', 1015818056597508096, 2, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018807176013811712, 1015842628948463616, '张三', 1015818056597508096, 2, 4, 1, 434, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:19:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018807190026981376, 1015842628948463616, '张三', 1015818056597508096, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:19:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018807205868867584, 1015842628948463616, '张三', 1015818056597508096, 2, 9, 1, NULL, 100, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:20:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018807221144522752, 1015842628948463616, '张三', 1015818056597508096, 2, 9, 0, NULL, 34, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:20:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018807245962219520, 1015842628948463616, '张三', 1015818056597508096, 3, 9, 0, NULL, 57, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:20:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018807249124724736, 1015842628948463616, '张三', 1015818056597508096, 3, 9, 0, NULL, 22, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:20:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018807263423107072, 1015842628948463616, '张三', 1015818056597508096, 3, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:20:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018807267189592064, 1015842628948463616, '张三', 1015818056597508096, 3, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:20:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018807284394627072, 1015842628948463616, '张三', 1015818056597508096, 3, 10, 0, NULL, NULL, 6, NULL, NULL, NULL, NULL, '2020-01-10 11:20:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018807287661989888, 1015842628948463616, '张三', 1015818056597508096, 3, 10, 0, NULL, NULL, 4, NULL, NULL, NULL, NULL, '2020-01-10 11:20:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018807304527286272, 1015842628948463616, '张三', 1015818056597508096, 3, 10, 2, NULL, NULL, 8, NULL, NULL, NULL, NULL, '2020-01-10 11:20:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018807321082204160, 1015842628948463616, '张三', 1015818056597508096, 3, 5, 2, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:20:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018807323640729600, 1015842628948463616, '张三', 1015818056597508096, 3, 5, 2, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:20:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018807341474910208, 1015842628948463616, '张三', 1015818056597508096, 3, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:20:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018807358168240128, 1015842628948463616, '张三', 1015818056597508096, 3, 4, 1, 109, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018807377902440448, 1015842628948463616, '张三', 1015818056597508096, 3, 4, 0, 923, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018807396172828672, 1015842628948463616, '张三', 1015818056597508096, 3, 4, 2, 598, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018807399939313664, 1015842628948463616, '张三', 1015818056597508096, 3, 4, 2, 636, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018807412731940864, 1015842628948463616, '张三', 1015818056597508096, 3, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018807416288710656, 1015842628948463616, '张三', 1015818056597508096, 3, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018807429895032832, 1015842628948463616, '张三', 1015818056597508096, 3, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018807443853676544, 1015842628948463616, '张三', 1015818056597508096, 3, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018807458953170944, 1015842628948463616, '张三', 1015818056597508096, 3, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:21:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018807471968096256, 1015842628948463616, '张三', 1015818056597508096, 3, 1, 0, NULL, NULL, NULL, NULL, 3, NULL, NULL, '2020-01-10 11:21:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018807475562614784, 1015842628948463616, '张三', 1015818056597508096, 3, 1, 0, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-10 11:21:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018807497494630400, 1015842628948463616, '张三', 1015818056597508096, 3, 0, 1, NULL, NULL, NULL, NULL, NULL, 546, NULL, '2020-01-10 11:21:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018807510580858880, 1015842628948463616, '张三', 1015818056597508096, 3, 0, 2, NULL, NULL, NULL, NULL, NULL, 797, NULL, '2020-01-10 11:22:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018807530558328832, 1015842628948463616, '张三', 1015818056597508096, 4, 0, 2, NULL, NULL, NULL, NULL, NULL, 668, NULL, '2020-01-10 11:22:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018807544810573824, 1015842628948463616, '张三', 1015818056597508096, 4, 0, 2, NULL, NULL, NULL, NULL, NULL, 98, NULL, '2020-01-10 11:22:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018807559650021376, 1015842628948463616, '张三', 1015818056597508096, 4, 1, 2, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-10 11:22:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018807565647876096, 1015842628948463616, '张三', 1015818056597508096, 4, 1, 2, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-10 11:22:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018807581548482560, 1015842628948463616, '张三', 1015818056597508096, 4, 1, 1, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-10 11:22:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018807596224352256, 1015842628948463616, '张三', 1015818056597508096, 4, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:22:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018807598866763776, 1015842628948463616, '张三', 1015818056597508096, 4, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:22:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018807614889005056, 1015842628948463616, '张三', 1015818056597508096, 4, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:22:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018807628856037376, 1015842628948463616, '张三', 1015818056597508096, 4, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:22:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018807632249229312, 1015842628948463616, '张三', 1015818056597508096, 4, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:22:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018807646891544576, 1015842628948463616, '张三', 1015818056597508096, 4, 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:22:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018807659432513536, 1015842628948463616, '张三', 1015818056597508096, 4, 4, 0, 931, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:23:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018807675786104832, 1015842628948463616, '张三', 1015818056597508096, 4, 4, 1, 549, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:23:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018807693569953792, 1015842628948463616, '张三', 1015818056597508096, 4, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:23:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018807696216559616, 1015842628948463616, '张三', 1015818056597508096, 4, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:23:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018807710099705856, 1015842628948463616, '张三', 1015818056597508096, 4, 5, 2, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:23:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018807726746898432, 1015842628948463616, '张三', 1015818056597508096, 4, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-10 11:23:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018807743188570112, 1015842628948463616, '张三', 1015818056597508096, 4, 9, 0, NULL, 89, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:23:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018807747508703232, 1015842628948463616, '张三', 1015818056597508096, 4, 9, 0, NULL, 45, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:23:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018807762734026752, 1015842628948463616, '张三', 1015818056597508096, 4, 9, 1, NULL, 26, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:23:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018807779007926272, 1015842628948463616, '张三', 1015818056597508096, 4, 9, 2, NULL, 52, NULL, NULL, NULL, NULL, NULL, '2020-01-10 11:23:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018807795281825792, 1015842628948463616, '张三', 1015818056597508096, 4, 10, 2, NULL, NULL, 9, NULL, NULL, NULL, NULL, '2020-01-10 11:23:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018807814282022912, 1015842628948463616, '张三', 1015818056597508096, 4, 10, 1, NULL, NULL, 9, NULL, NULL, NULL, NULL, '2020-01-10 11:23:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018807818304360448, 1015842628948463616, '张三', 1015818056597508096, 4, 10, 1, NULL, NULL, 10, NULL, NULL, NULL, NULL, '2020-01-10 11:24:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018807839112302592, 1015842628948463616, '张三', 1015818056597508096, 4, 10, 0, NULL, NULL, 5, NULL, NULL, NULL, NULL, '2020-01-10 11:24:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018807937338707968, 1015852480873631744, '李军', 1015817732197453824, 1, 0, 0, NULL, NULL, NULL, NULL, NULL, 868, NULL, '2020-01-11 11:24:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018807958184398848, 1015852480873631744, '李军', 1015817732197453824, 1, 0, 1, NULL, NULL, NULL, NULL, NULL, 251, NULL, '2020-01-11 11:24:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018807973283893248, 1015852480873631744, '李军', 1015817732197453824, 1, 1, 1, NULL, NULL, NULL, NULL, 3, NULL, NULL, '2020-01-11 11:24:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018807976429621248, 1015852480873631744, '李军', 1015817732197453824, 1, 1, 1, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-11 11:24:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018807990446985216, 1015852480873631744, '李军', 1015817732197453824, 1, 1, 0, NULL, NULL, NULL, NULL, 5, NULL, NULL, '2020-01-11 11:24:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018808007266144256, 1015852480873631744, '李军', 1015817732197453824, 1, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:24:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018808010520924160, 1015852480873631744, '李军', 1015817732197453824, 1, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:24:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018808029248491520, 1015852480873631744, '李军', 1015817732197453824, 1, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:24:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018808046189285376, 1015852480873631744, '李军', 1015817732197453824, 1, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:24:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018808049536339968, 1015852480873631744, '李军', 1015817732197453824, 1, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:24:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018808063356571648, 1015852480873631744, '李军', 1015817732197453824, 1, 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:25:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018808090606964736, 1015852480873631744, '李军', 1015817732197453824, 1, 4, 0, 331, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:25:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018808105442217984, 1015852480873631744, '李军', 1015817732197453824, 1, 4, 1, 180, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:25:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018808123947487232, 1015852480873631744, '李军', 1015817732197453824, 1, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:25:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018808139374137344, 1015852480873631744, '李军', 1015817732197453824, 1, 5, 2, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:25:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018808163239727104, 1015852480873631744, '李军', 1015817732197453824, 1, 9, 2, NULL, 73, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:25:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018808178884481024, 1015852480873631744, '李军', 1015817732197453824, 1, 9, 1, NULL, 85, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:25:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018808202037039104, 1015852480873631744, '李军', 1015817732197453824, 1, 9, 0, NULL, 58, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:25:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018808225227345920, 1015852480873631744, '李军', 1015817732197453824, 1, 10, 0, NULL, NULL, 3, NULL, NULL, NULL, NULL, '2020-01-11 11:25:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018808239072743424, 1015852480873631744, '李军', 1015817732197453824, 1, 10, 1, NULL, NULL, 10, NULL, NULL, NULL, NULL, '2020-01-11 11:25:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018808259285094400, 1015852480873631744, '李军', 1015817732197453824, 2, 10, 1, NULL, NULL, 6, NULL, NULL, NULL, NULL, '2020-01-11 11:25:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018808281019977728, 1015852480873631744, '李军', 1015817732197453824, 2, 10, 0, NULL, NULL, 6, NULL, NULL, NULL, NULL, '2020-01-11 11:25:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018808284450918400, 1015852480873631744, '李军', 1015817732197453824, 2, 10, 0, NULL, NULL, 8, NULL, NULL, NULL, NULL, '2020-01-11 11:26:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018808301647564800, 1015852480873631744, '李军', 1015817732197453824, 2, 9, 0, NULL, 44, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018808305003008000, 1015852480873631744, '李军', 1015817732197453824, 2, 9, 0, NULL, 98, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018808319687266304, 1015852480873631744, '李军', 1015817732197453824, 2, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:26:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018808334279249920, 1015852480873631744, '李军', 1015817732197453824, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:26:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018808337051684864, 1015852480873631744, '李军', 1015817732197453824, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:26:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018808352482529280, 1015852480873631744, '李军', 1015817732197453824, 2, 4, 1, 829, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018808368341192704, 1015852480873631744, '李军', 1015817732197453824, 2, 4, 2, 143, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018808371201708032, 1015852480873631744, '李军', 1015817732197453824, 2, 4, 2, 727, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018808386959708160, 1015852480873631744, '李军', 1015817732197453824, 2, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018808389941858304, 1015852480873631744, '李军', 1015817732197453824, 2, 3, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018808403061641216, 1015852480873631744, '李军', 1015817732197453824, 2, 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:26:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018808417364217856, 1015852480873631744, '李军', 1015817732197453824, 2, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:27:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018808431247364096, 1015852480873631744, '李军', 1015817732197453824, 2, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:27:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018808434900602880, 1015852480873631744, '李军', 1015817732197453824, 2, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:27:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018808450344030208, 1015852480873631744, '李军', 1015817732197453824, 2, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:27:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018808468366954496, 1015852480873631744, '李军', 1015817732197453824, 2, 1, 0, NULL, NULL, NULL, NULL, 1, NULL, NULL, '2020-01-11 11:27:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018808471776923648, 1015852480873631744, '李军', 1015817732197453824, 2, 1, 0, NULL, NULL, NULL, NULL, 1, NULL, NULL, '2020-01-11 11:27:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018808486574428160, 1015852480873631744, '李军', 1015817732197453824, 2, 1, 1, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-11 11:27:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018808489720156160, 1015852480873631744, '李军', 1015817732197453824, 2, 1, 1, NULL, NULL, NULL, NULL, 1, NULL, NULL, '2020-01-11 11:27:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018808519092867072, 1015852480873631744, '李军', 1015817732197453824, 2, 0, 1, NULL, NULL, NULL, NULL, NULL, 23, NULL, '2020-01-11 11:27:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018808533722599424, 1015852480873631744, '李军', 1015817732197453824, 2, 0, 0, NULL, NULL, NULL, NULL, NULL, 486, NULL, '2020-01-11 11:27:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018808549908418560, 1015852480873631744, '李军', 1015817732197453824, 3, 0, 0, NULL, NULL, NULL, NULL, NULL, 937, NULL, '2020-01-11 11:27:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018808553595211776, 1015852480873631744, '李军', 1015817732197453824, 3, 0, 0, NULL, NULL, NULL, NULL, NULL, 634, NULL, '2020-01-11 11:27:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018808567696461824, 1015852480873631744, '李军', 1015817732197453824, 3, 1, 0, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-11 11:28:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018808589381013504, 1015852480873631744, '李军', 1015817732197453824, 3, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018808603381600256, 1015852480873631744, '李军', 1015817732197453824, 3, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018808627708563456, 1015852853839532032, '王石', 1015817732197453824, 3, 2, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018808643911159808, 1015852853839532032, '王石', 1015817732197453824, 3, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018808647878971392, 1015852853839532032, '王石', 1015817732197453824, 3, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018808662647115776, 1015852853839532032, '王石', 1015817732197453824, 3, 3, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018808676190523392, 1015852853839532032, '王石', 1015817732197453824, 3, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:28:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018808679671795712, 1015852853839532032, '王石', 1015817732197453824, 3, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:28:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018808713146535936, 1015841864515588096, '张大', 1015817732197453824, 3, 5, 2, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:28:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018808727696576512, 1015841864515588096, '张大', 1015817732197453824, 3, 9, 2, NULL, 93, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018808730968133632, 1015841864515588096, '张大', 1015817732197453824, 3, 9, 2, NULL, 39, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:28:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018808745056800768, 1015841864515588096, '张大', 1015817732197453824, 3, 9, 0, NULL, 26, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:29:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018808762224087040, 1015841864515588096, '张大', 1015817732197453824, 3, 10, 0, NULL, NULL, 4, NULL, NULL, NULL, NULL, '2020-01-11 11:29:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018808766552608768, 1015841864515588096, '张大', 1015817732197453824, 3, 10, 0, NULL, NULL, 7, NULL, NULL, NULL, NULL, '2020-01-11 11:29:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018808834777157632, 1015841864515588096, '张大', 1015818056597508096, 2, 10, 0, NULL, NULL, 8, NULL, NULL, NULL, NULL, '2020-01-11 11:29:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018808837880942592, 1015841864515588096, '张大', 1015818056597508096, 2, 10, 0, NULL, NULL, 7, NULL, NULL, NULL, NULL, '2020-01-11 11:29:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018808852263211008, 1015841864515588096, '张大', 1015818056597508096, 2, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:29:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018808870055448576, 1015841864515588096, '张大', 1015818056597508096, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:29:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018808872664305664, 1015841864515588096, '张大', 1015818056597508096, 2, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:29:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018808889886117888, 1015841864515588096, '张大', 1015818056597508096, 2, 3, 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:29:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018808905585397760, 1015841864515588096, '张大', 1015818056597508096, 2, 4, 1, 756, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:29:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018808924665286656, 1015841864515588096, '张大', 1015818056597508096, 2, 4, 2, 35, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:29:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018808927844569088, 1015841864515588096, '张大', 1015818056597508096, 2, 4, 2, 489, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:29:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018808941014683648, 1015841864515588096, '张大', 1015818056597508096, 2, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:30:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018808944089108480, 1015841864515588096, '张大', 1015818056597508096, 2, 2, 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:30:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018808963789754368, 1015841864515588096, '张大', 1015818056597508096, 2, 0, 2, NULL, NULL, NULL, NULL, NULL, 342, NULL, '2020-01-11 11:30:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018808967061311488, 1015841864515588096, '张大', 1015818056597508096, 2, 0, 2, NULL, NULL, NULL, NULL, NULL, 894, NULL, '2020-01-11 11:30:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018808971549216768, 1015841864515588096, '张大', 1015818056597508096, 2, 0, 2, NULL, NULL, NULL, NULL, NULL, 505, NULL, '2020-01-11 11:30:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018809014373060608, 1015841864515588096, '张大', 1015818056597508096, 3, 0, 2, NULL, NULL, NULL, NULL, NULL, 870, NULL, '2020-01-11 11:30:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018809017279713280, 1015841864515588096, '张大', 1015818056597508096, 3, 0, 2, NULL, NULL, NULL, NULL, NULL, 832, NULL, '2020-01-11 11:30:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018809030013620224, 1015841864515588096, '张大', 1015818056597508096, 3, 1, 2, NULL, NULL, NULL, NULL, 1, NULL, NULL, '2020-01-11 11:30:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018809043577999360, 1015841864515588096, '张大', 1015818056597508096, 3, 1, 0, NULL, NULL, NULL, NULL, 2, NULL, NULL, '2020-01-11 11:30:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018809058333560832, 1015841864515588096, '张大', 1015818056597508096, 3, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:30:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018809068521525248, 1015841864515588096, '张大', 1015818056597508096, 3, 2, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:30:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018809083839123456, 1015841864515588096, '张大', 1015818056597508096, 3, 4, 0, 484, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:30:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018809101107073024, 1015841864515588096, '张大', 1015818056597508096, 3, 4, 1, 822, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:31:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018809116709883904, 1015841864515588096, '张大', 1015818056597508096, 3, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:31:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018809119352295424, 1015841864515588096, '张大', 1015818056597508096, 3, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:31:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018809140072157184, 1015841864515588096, '张大', 1015818056597508096, 3, 9, 1, NULL, 92, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:31:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018809153410043904, 1015841864515588096, '张大', 1015818056597508096, 3, 9, 0, NULL, 23, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:31:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018809156404776960, 1015841864515588096, '张大', 1015818056597508096, 3, 9, 0, NULL, 61, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:31:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018809187635564544, 1015841864515588096, '张大', 1015818056597508096, 4, 9, 0, NULL, 26, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:31:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018809205096452096, 1015841864515588096, '张大', 1015818056597508096, 4, 9, 1, NULL, 96, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:31:35'); +INSERT INTO `zz_student_action_trans` VALUES (1018809219889762304, 1015841864515588096, '张大', 1015818056597508096, 4, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:31:40'); +INSERT INTO `zz_student_action_trans` VALUES (1018809223115182080, 1015841864515588096, '张大', 1015818056597508096, 4, 5, 1, NULL, NULL, NULL, NULL, NULL, NULL, 1, '2020-01-11 11:31:45'); +INSERT INTO `zz_student_action_trans` VALUES (1018809241318461440, 1015841864515588096, '张大', 1015818056597508096, 4, 10, 1, NULL, NULL, 4, NULL, NULL, NULL, NULL, '2020-01-11 11:31:50'); +INSERT INTO `zz_student_action_trans` VALUES (1018809244799733760, 1015841864515588096, '张大', 1015818056597508096, 4, 10, 1, NULL, NULL, 5, NULL, NULL, NULL, NULL, '2020-01-11 11:31:55'); +INSERT INTO `zz_student_action_trans` VALUES (1018809259483992064, 1015841864515588096, '张大', 1015818056597508096, 4, 4, 1, 244, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:32:00'); +INSERT INTO `zz_student_action_trans` VALUES (1018809272926736384, 1015841864515588096, '张大', 1015818056597508096, 4, 4, 0, 736, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:32:05'); +INSERT INTO `zz_student_action_trans` VALUES (1018809275388792832, 1015841864515588096, '张大', 1015818056597508096, 4, 4, 0, 230, NULL, NULL, NULL, NULL, NULL, NULL, '2020-01-11 11:32:10'); +INSERT INTO `zz_student_action_trans` VALUES (1018809289016086528, 1015841864515588096, '张大', 1015818056597508096, 4, 1, 0, NULL, NULL, NULL, NULL, 3, NULL, NULL, '2020-01-11 11:32:15'); +INSERT INTO `zz_student_action_trans` VALUES (1018809291985653760, 1015841864515588096, '张大', 1015818056597508096, 4, 1, 0, NULL, NULL, NULL, NULL, 4, NULL, NULL, '2020-01-11 11:32:20'); +INSERT INTO `zz_student_action_trans` VALUES (1018809313879920640, 1015841864515588096, '张大', 1015818056597508096, 4, 0, 0, NULL, NULL, NULL, NULL, NULL, 441, NULL, '2020-01-11 11:32:25'); +INSERT INTO `zz_student_action_trans` VALUES (1018809333760921600, 1015841864515588096, '张大', 1015818056597508096, 4, 0, 1, NULL, NULL, NULL, NULL, NULL, 202, NULL, '2020-01-11 11:32:30'); +INSERT INTO `zz_student_action_trans` VALUES (1018809347316912128, 1015841864515588096, '张大', 1015818056597508096, 4, 0, 2, NULL, NULL, NULL, NULL, NULL, 614, NULL, '2020-01-11 11:32:35'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_menu`; +CREATE TABLE `zz_sys_menu` ( + `menu_id` bigint(20) NOT NULL COMMENT '主键Id', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单Id,目录菜单的父菜单为null', + `menu_name` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '菜单显示名称', + `menu_type` int(11) NOT NULL COMMENT '(0: 目录 1: 菜单 2: 按钮 3: UI片段)', + `form_router_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '前端表单路由名称,仅用于menu_type为1的菜单类型', + `show_order` int(11) NOT NULL COMMENT '菜单显示顺序 (值越小,排序越靠前)', + `icon` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '菜单图标', + `create_time` datetime NOT NULL COMMENT '创建时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`menu_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='菜单和操作权限管理表'; + +-- ---------------------------- +-- Records of zz_sys_menu +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_menu` VALUES (1093376634899927040, NULL, '系统管理', 0, NULL, 1, 'el-icon-setting', CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093376634916704256, 1093376634899927040, '用户管理', 1, 'formSysUser', 100, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093376634916704258, 1093376634899927040, '角色管理', 1, 'formSysRole', 110, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093376634916704259, 1093376634899927040, '菜单管理', 1, 'formSysMenu', 120, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093376634916704260, 1093376634899927040, '权限字管理', 1, 'formSysPermCode', 125, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093376634916704261, 1093376634899927040, '权限管理', 1, 'formSysPerm', 130, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093376634916704262, 1093376634899927040, '字典管理', 1, 'formSysDict', 135, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093478813098840064, NULL, '业务管理', 0, NULL, 10, 'el-icon-s-goods', CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093478847987060736, NULL, '统计管理', 0, NULL, 20, 'el-icon-s-data', CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093478946238631936, 1093478813098840064, '校区管理', 1, 'formSchool', 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093479020943380480, 1093478813098840064, '学生管理', 1, 'formStudent', 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093479114610577408, 1093478813098840064, '课程管理', 1, 'formCourse', 10, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093479177793572864, 1093478813098840064, '班级管理', 1, 'formClass', 15, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093479249499394048, 1093478847987060736, '课程统计', 1, 'formCourseStats', 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093479313416392704, 1093478847987060736, '学生行为统计', 1, 'formStudentActionStats', 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376532, 1093376634916704256, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376533, 1093376634916704256, '新增', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376534, 1093376634916704256, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376535, 1093376634916704256, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376536, 1093376634916704256, '重置密码', 3, NULL, 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376554, 1093376634916704258, '角色管理', 2, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376555, 1093376634916704258, '用户授权', 2, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376556, 1093809448598376554, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376557, 1093809448598376554, '新增', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376558, 1093809448598376554, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376559, 1093809448598376554, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376560, 1093809448598376555, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376561, 1093809448598376555, '授权用户', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376562, 1093809448598376555, '移除用户', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376572, 1093376634916704259, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376573, 1093376634916704259, '新增', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376574, 1093376634916704259, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376575, 1093376634916704259, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376576, 1093376634916704259, '权限列表', 3, NULL, 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376584, 1093376634916704260, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376585, 1093376634916704260, '新增', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376586, 1093376634916704260, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376587, 1093376634916704260, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376594, 1093376634916704261, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376595, 1093376634916704261, '新增模块', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376596, 1093376634916704261, '编辑模块', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376597, 1093376634916704261, '删除模块', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376598, 1093376634916704261, '新增权限', 3, NULL, 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376599, 1093376634916704261, '编辑权限', 3, NULL, 6, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376600, 1093376634916704261, '删除权限', 3, NULL, 7, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376610, 1093376634916704262, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376611, 1093376634916704262, '新增', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376612, 1093376634916704262, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376613, 1093376634916704262, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376614, 1093376634916704262, '同步缓存', 3, NULL, 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376624, 1093478946238631936, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376625, 1093478946238631936, '新建', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376626, 1093478946238631936, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376627, 1093478946238631936, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376629, 1093479020943380480, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376630, 1093479020943380480, '新建', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376631, 1093479020943380480, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376632, 1093479020943380480, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376634, 1093479114610577408, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376635, 1093479114610577408, '新建', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376636, 1093479114610577408, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376637, 1093479114610577408, '删除', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376639, 1093479177793572864, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376640, 1093479177793572864, '新建', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376641, 1093479177793572864, '编辑', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376642, 1093479177793572864, '学生', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376643, 1093479177793572864, '课程', 3, NULL, 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376644, 1093479177793572864, '删除', 3, NULL, 6, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376646, 1093479249499394048, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376648, 1093479313416392704, '显示', 3, NULL, 1, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376649, 1093479313416392704, '学生行为详情', 3, NULL, 2, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376650, 1093479313416392704, '学生行为详情', 3, NULL, 3, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376651, 1093479313416392704, '学生行为详情', 3, NULL, 4, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376652, 1093479313416392704, '学生行为详情', 3, NULL, 5, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376653, 1093479313416392704, '学生行为详情', 3, NULL, 6, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376654, 1093479313416392704, '学生行为详情', 3, NULL, 7, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376655, 1093479313416392704, '学生行为详情', 3, NULL, 8, NULL, CURDATE(), 1); +INSERT INTO `zz_sys_menu` VALUES (1093809448598376656, 1093479313416392704, '学生行为详情', 3, NULL, 9, NULL, CURDATE(), 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_menu_perm_code +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_menu_perm_code`; +CREATE TABLE `zz_sys_menu_perm_code` ( + `menu_id` bigint(20) NOT NULL COMMENT '关联菜单Id', + `perm_code_id` bigint(20) NOT NULL COMMENT '关联权限字Id', + PRIMARY KEY (`menu_id`,`perm_code_id`) USING BTREE, + KEY `idx_perm_code_id` (`perm_code_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='菜单和权限关系表'; + +-- ---------------------------- +-- Records of zz_sys_menu_perm_code +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376624, 1093809448598376449); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376625, 1093809448598376450); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376626, 1093809448598376451); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376627, 1093809448598376452); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376625, 1093809448598376453); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376625, 1093809448598376454); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376625, 1093809448598376455); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376625, 1093809448598376456); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376626, 1093809448598376457); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376626, 1093809448598376458); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376626, 1093809448598376459); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376626, 1093809448598376460); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376629, 1093809448598376462); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376630, 1093809448598376463); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376631, 1093809448598376464); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376632, 1093809448598376465); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376630, 1093809448598376466); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376630, 1093809448598376467); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376630, 1093809448598376468); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376630, 1093809448598376469); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376631, 1093809448598376470); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376631, 1093809448598376471); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376631, 1093809448598376472); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376631, 1093809448598376473); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376634, 1093809448598376475); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376635, 1093809448598376476); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376636, 1093809448598376477); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376637, 1093809448598376478); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376635, 1093809448598376479); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376635, 1093809448598376480); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376635, 1093809448598376481); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376635, 1093809448598376482); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376636, 1093809448598376483); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376636, 1093809448598376484); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376636, 1093809448598376485); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376636, 1093809448598376486); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376639, 1093809448598376488); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376640, 1093809448598376489); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376641, 1093809448598376490); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376491); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376492); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376644, 1093809448598376493); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376640, 1093809448598376494); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376640, 1093809448598376495); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376640, 1093809448598376496); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376640, 1093809448598376497); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376641, 1093809448598376498); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376641, 1093809448598376499); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376641, 1093809448598376500); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376641, 1093809448598376501); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376502); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376503); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376504); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376505); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376506); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376507); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376508); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376509); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376510); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376511); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376642, 1093809448598376512); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376513); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376514); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376643, 1093809448598376515); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376646, 1093809448598376517); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376648, 1093809448598376519); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376649, 1093809448598376520); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376650, 1093809448598376521); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376651, 1093809448598376522); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376652, 1093809448598376523); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376653, 1093809448598376524); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376654, 1093809448598376525); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376655, 1093809448598376526); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376656, 1093809448598376527); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376649, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376650, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376651, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376652, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376653, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376654, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376655, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376656, 1093809448598376528); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376649, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376650, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376651, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376652, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376653, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376654, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376655, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376656, 1093809448598376529); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376532, 1093809448598376538); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376533, 1093809448598376539); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376534, 1093809448598376540); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376535, 1093809448598376541); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376536, 1093809448598376542); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376556, 1093809448598376564); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376560, 1093809448598376565); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376557, 1093809448598376566); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376558, 1093809448598376567); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376559, 1093809448598376568); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376561, 1093809448598376569); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376562, 1093809448598376570); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376572, 1093809448598376578); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376573, 1093809448598376579); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376574, 1093809448598376580); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376575, 1093809448598376581); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376576, 1093809448598376582); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376584, 1093809448598376589); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376585, 1093809448598376590); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376586, 1093809448598376591); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376587, 1093809448598376592); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376594, 1093809448598376602); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376595, 1093809448598376603); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376596, 1093809448598376604); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376597, 1093809448598376605); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376598, 1093809448598376606); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376599, 1093809448598376607); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376600, 1093809448598376608); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093376634916704262, 1093809448598376616); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376610, 1093809448598376616); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093376634916704262, 1093809448598376617); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376611, 1093809448598376617); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093376634916704262, 1093809448598376618); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376612, 1093809448598376618); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093376634916704262, 1093809448598376619); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376613, 1093809448598376619); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093376634916704262, 1093809448598376620); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1093809448598376614, 1093809448598376620); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm`; +CREATE TABLE `zz_sys_perm` ( + `perm_id` bigint(20) NOT NULL COMMENT '权限id', + `module_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '权限所在的权限模块id', + `perm_name` varchar(64) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '权限名称', + `url` varchar(128) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '关联的url', + `show_order` int(11) NOT NULL DEFAULT '0' COMMENT '权限在当前模块下的顺序,由小到大', + `create_time` datetime NOT NULL COMMENT '创建时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`perm_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE, + KEY `idx_module_id` (`module_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限表'; + +-- ---------------------------- +-- Records of zz_sys_perm +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm` VALUES (1093809448569016321, 1093809448569016320, '新增', '/admin/CourseClass/course/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016322, 1093809448569016320, '编辑', '/admin/CourseClass/course/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016323, 1093809448569016320, '删除', '/admin/CourseClass/course/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016324, 1093809448569016320, '显示列表', '/admin/CourseClass/course/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016325, 1093809448569016320, '导出', '/admin/CourseClass/course/export', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016326, 1093809448569016320, '详情', '/admin/CourseClass/course/view', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016327, 1093809448569016320, '打印', '/admin/CourseClass/course/print', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016328, 1093809448569016320, '课程数据文件上传', '/admin/CourseClass/course/upload', 8, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016329, 1093809448569016320, '课程数据文件下载', '/admin/CourseClass/course/download', 9, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016331, 1093809448569016330, '新增', '/admin/CourseClass/schoolInfo/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016332, 1093809448569016330, '编辑', '/admin/CourseClass/schoolInfo/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016333, 1093809448569016330, '删除', '/admin/CourseClass/schoolInfo/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016334, 1093809448569016330, '显示列表', '/admin/CourseClass/schoolInfo/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016335, 1093809448569016330, '导出', '/admin/CourseClass/schoolInfo/export', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016336, 1093809448569016330, '详情', '/admin/CourseClass/schoolInfo/view', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016337, 1093809448569016330, '打印', '/admin/CourseClass/schoolInfo/print', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016339, 1093809448569016338, '新增', '/admin/CourseClass/student/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016340, 1093809448569016338, '编辑', '/admin/CourseClass/student/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016341, 1093809448569016338, '删除', '/admin/CourseClass/student/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016342, 1093809448569016338, '显示列表', '/admin/CourseClass/student/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016343, 1093809448569016338, '导出', '/admin/CourseClass/student/export', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016344, 1093809448569016338, '详情', '/admin/CourseClass/student/view', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016345, 1093809448569016338, '打印', '/admin/CourseClass/student/print', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016347, 1093809448569016346, '新增', '/admin/upms/sysUser/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016348, 1093809448569016346, '编辑', '/admin/upms/sysUser/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016349, 1093809448569016346, '删除', '/admin/upms/sysUser/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016350, 1093809448569016346, '显示列表', '/admin/upms/sysUser/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016351, 1093809448569016346, '导出', '/admin/upms/sysUser/export', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016352, 1093809448569016346, '详情', '/admin/upms/sysUser/view', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016353, 1093809448569016346, '打印', '/admin/upms/sysUser/print', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016354, 1093809448569016346, '重置密码', '/admin/upms/sysUser/resetPassword', 8, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016356, 1093809448569016355, '新增', '/admin/CourseClass/studentClass/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016357, 1093809448569016355, '编辑', '/admin/CourseClass/studentClass/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016358, 1093809448569016355, '删除', '/admin/CourseClass/studentClass/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016359, 1093809448569016355, '显示列表', '/admin/CourseClass/studentClass/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016360, 1093809448569016355, '导出', '/admin/CourseClass/studentClass/export', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016361, 1093809448569016355, '详情', '/admin/CourseClass/studentClass/view', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016362, 1093809448569016355, '打印', '/admin/CourseClass/studentClass/print', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016363, 1093809448569016355, '新增班级课程', '/admin/CourseClass/studentClass/addClassCourse', 8, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016364, 1093809448569016355, '移除班级课程', '/admin/CourseClass/studentClass/deleteClassCourse', 9, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016365, 1093809448569016355, '班级课程列表', '/admin/CourseClass/studentClass/listClassCourse', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016366, 1093809448569016355, '班级课程未关联列表', '/admin/CourseClass/studentClass/listNotInClassCourse', 11, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016367, 1093809448569016355, '新增班级学生', '/admin/CourseClass/studentClass/addClassStudent', 12, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016368, 1093809448569016355, '移除班级学生', '/admin/CourseClass/studentClass/deleteClassStudent', 13, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016369, 1093809448569016355, '班级学生列表', '/admin/CourseClass/studentClass/listClassStudent', 14, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016370, 1093809448569016355, '班级学生未关联列表', '/admin/CourseClass/studentClass/listNotInClassStudent', 15, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016372, 1093809448569016371, '分组列表', '/admin/stats/courseTransStats/listWithGroup', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016373, 1093809448569016371, '显示列表', '/admin/stats/courseTransStats/list', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016374, 1093809448569016371, '导出', '/admin/stats/courseTransStats/export', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016375, 1093809448569016371, '详情', '/admin/stats/courseTransStats/view', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016376, 1093809448569016371, '打印', '/admin/stats/courseTransStats/print', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016378, 1093809448569016377, '分组列表', '/admin/stats/studentActionStats/listWithGroup', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016379, 1093809448569016377, '显示列表', '/admin/stats/studentActionStats/list', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016380, 1093809448569016377, '导出', '/admin/stats/studentActionStats/export', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016381, 1093809448569016377, '详情', '/admin/stats/studentActionStats/view', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016382, 1093809448569016377, '打印', '/admin/stats/studentActionStats/print', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016384, 1093809448569016383, '新增', '/admin/stats/studentActionTrans/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016385, 1093809448569016383, '编辑', '/admin/stats/studentActionTrans/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016386, 1093809448569016383, '删除', '/admin/stats/studentActionTrans/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016387, 1093809448569016383, '显示列表', '/admin/stats/studentActionTrans/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016388, 1093809448569016383, '导出', '/admin/stats/studentActionTrans/export', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016389, 1093809448569016383, '详情', '/admin/stats/studentActionTrans/view', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016390, 1093809448569016383, '打印', '/admin/stats/studentActionTrans/print', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016392, 1093809448569016391, '新增', '/admin/upms/sysRole/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016393, 1093809448569016391, '编辑', '/admin/upms/sysRole/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016394, 1093809448569016391, '删除', '/admin/upms/sysRole/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016395, 1093809448569016391, '显示列表', '/admin/upms/sysRole/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016396, 1093809448569016391, '详情', '/admin/upms/sysRole/view', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016397, 1093809448569016391, '授权用户', '/admin/upms/sysRole/addUserRole', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016398, 1093809448569016391, '移除用户', '/admin/upms/sysRole/deleteUserRole', 7, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016399, 1093809448569016391, '角色用户列表', '/admin/upms/sysRole/listUserRole', 8, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016400, 1093809448569016391, '角色未添加用户列表', '/admin/upms/sysRole/listNotInUserRole', 9, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016402, 1093809448569016401, '新增', '/admin/upms/sysMenu/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016403, 1093809448569016401, '编辑', '/admin/upms/sysMenu/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016404, 1093809448569016401, '删除', '/admin/upms/sysMenu/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016405, 1093809448569016401, '显示列表', '/admin/upms/sysMenu/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016406, 1093809448569016401, '详情', '/admin/upms/sysMenu/view', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016407, 1093809448569016401, '权限资源列表', '/admin/upms/sysMenu/listMenuPerm', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016409, 1093809448569016408, '新增', '/admin/upms/sysPermCode/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016410, 1093809448569016408, '编辑', '/admin/upms/sysPermCode/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016411, 1093809448569016408, '删除', '/admin/upms/sysPermCode/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016412, 1093809448569016408, '显示列表', '/admin/upms/sysPermCode/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016413, 1093809448569016408, '详情', '/admin/upms/sysPermCode/view', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016415, 1093809448569016414, '新增', '/admin/upms/sysPermModule/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016416, 1093809448569016414, '编辑', '/admin/upms/sysPermModule/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016417, 1093809448569016414, '删除', '/admin/upms/sysPermModule/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016418, 1093809448569016414, '显示列表', '/admin/upms/sysPermModule/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016419, 1093809448569016414, '显示全部', '/admin/upms/sysPermModule/listAll', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016421, 1093809448569016420, '新增', '/admin/upms/sysPerm/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016422, 1093809448569016420, '编辑', '/admin/upms/sysPerm/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016423, 1093809448569016420, '删除', '/admin/upms/sysPerm/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016424, 1093809448569016420, '显示列表', '/admin/upms/sysPerm/list', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016425, 1093809448569016420, '详情', '/admin/upms/sysPerm/view', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016428, 1093809448569016427, '新增', '/admin/CourseClass/areaCode/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016429, 1093809448569016427, '编辑', '/admin/CourseClass/areaCode/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016430, 1093809448569016427, '删除', '/admin/CourseClass/areaCode/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016431, 1093809448569016427, '同步缓存', '/admin/CourseClass/areaCode/reloadCachedData', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016433, 1093809448569016432, '新增', '/admin/CourseClass/grade/add', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016434, 1093809448569016432, '编辑', '/admin/CourseClass/grade/update', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016435, 1093809448569016432, '删除', '/admin/CourseClass/grade/delete', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm` VALUES (1093809448569016436, 1093809448569016432, '同步缓存', '/admin/CourseClass/grade/reloadCachedData', 4, CURDATE(), 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_code +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_code`; +CREATE TABLE `zz_sys_perm_code` ( + `perm_code_id` bigint(20) NOT NULL COMMENT '主键Id', + `parent_id` bigint(20) DEFAULT NULL COMMENT '上级权限字Id', + `perm_code` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '权限字标识(一般为有含义的英文字符串)', + `perm_code_type` int(11) NOT NULL COMMENT '类型(0: 表单 1: UI片段 2: 操作)', + `show_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '显示名称', + `show_order` int(11) NOT NULL COMMENT '显示顺序(数值越小,越靠前)', + `create_time` datetime NOT NULL COMMENT '创建时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`perm_code_id`), + UNIQUE KEY `idx_perm_code` (`perm_code`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限资源表'; + +-- ---------------------------- +-- Records of zz_sys_perm_code +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376448, NULL, 'formSchool', 0, '校区管理', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376449, 1093809448598376448, 'formSchool:formSchool', 1, '校区管理', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376450, 1093809448598376449, 'formSchool:formSchool:formCreateClass', 2, '新建', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376451, 1093809448598376449, 'formSchool:formSchool:formEditSchool', 2, '编辑', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376452, 1093809448598376449, 'formSchool:formSchool:delete', 2, '删除', 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376453, NULL, 'formCreateSchool', 0, '新建校区', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376454, 1093809448598376453, 'formCreateSchool:formCreateClass', 1, '新建校区', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376455, 1093809448598376454, 'formCreateSchool:formCreateClass:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376456, 1093809448598376454, 'formCreateSchool:formCreateClass:add', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376457, NULL, 'formEditSchool', 0, '编辑校区', 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376458, 1093809448598376457, 'formEditSchool:formEditSchool', 1, '编辑校区', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376459, 1093809448598376458, 'formEditSchool:formEditSchool:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376460, 1093809448598376458, 'formEditSchool:formEditSchool:update', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376461, NULL, 'formStudent', 0, '学生管理', 30, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376462, 1093809448598376461, 'formStudent:formStudent', 1, '学生管理', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376463, 1093809448598376462, 'formStudent:formStudent:formCreateStudent', 2, '新建', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376464, 1093809448598376462, 'formStudent:formStudent:formEditStudent', 2, '编辑', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376465, 1093809448598376462, 'formStudent:formStudent:delete', 2, '删除', 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376466, NULL, 'formCreateStudent', 0, '新建学生', 40, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376467, 1093809448598376466, 'formCreateStudent:formCreateStudent', 1, '新建学生', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376468, 1093809448598376467, 'formCreateStudent:formCreateStudent:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376469, 1093809448598376467, 'formCreateStudent:formCreateStudent:update', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376470, NULL, 'formEditStudent', 0, '编辑学生', 50, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376471, 1093809448598376470, 'formEditStudent:formEditStudent', 1, '编辑学生', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376472, 1093809448598376471, 'formEditStudent:formEditStudent:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376473, 1093809448598376471, 'formEditStudent:formEditStudent:update', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376474, NULL, 'formCourse', 0, '课程管理', 60, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376475, 1093809448598376474, 'formCourse:formCourse', 1, '课程管理', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376476, 1093809448598376475, 'formCourse:formCourse:formCreateCourse', 2, '新建', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376477, 1093809448598376475, 'formCourse:formCourse:formEditCourse', 2, '编辑', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376478, 1093809448598376475, 'formCourse:formCourse:delete', 2, '删除', 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376479, NULL, 'formCreateCourse', 0, '新建课程', 70, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376480, 1093809448598376479, 'formCreateCourse:formCreateCourse', 1, '新建课程', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376481, 1093809448598376480, 'formCreateCourse:formCreateCourse:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376482, 1093809448598376480, 'formCreateCourse:formCreateCourse:add', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376483, NULL, 'formEditCourse', 0, '编辑课程', 80, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376484, 1093809448598376483, 'formEditCourse:formEditCourse', 1, '编辑课程', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376485, 1093809448598376484, 'formEditCourse:formEditCourse:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376486, 1093809448598376484, 'formEditCourse:formEditCourse:update', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376487, NULL, 'formClass', 0, '班级管理', 90, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376488, 1093809448598376487, 'formClass:formClass', 1, '班级管理', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376489, 1093809448598376488, 'formClass:formClass:formCreateClass', 2, '新建', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376490, 1093809448598376488, 'formClass:formClass:formEditClass', 2, '编辑', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376491, 1093809448598376488, 'formClass:formClass:formClassStudent', 2, '学生', 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376492, 1093809448598376488, 'formClass:formClass:formClassCourse', 2, '课程', 30, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376493, 1093809448598376488, 'formClass:formClass:delete', 2, '删除', 40, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376494, NULL, 'formCreateClass', 0, '新建班级', 100, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376495, 1093809448598376494, 'formCreateClass:formCreateClass', 1, '新建班级', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376496, 1093809448598376495, 'formCreateClass:formCreateClass:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376497, 1093809448598376495, 'formCreateClass:formCreateClass:add', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376498, NULL, 'formEditClass', 0, '编辑班级', 110, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376499, 1093809448598376498, 'formEditClass:formEditClass', 1, '编辑班级', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376500, 1093809448598376499, 'formEditClass:formEditClass:cancel', 2, '取消', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376501, 1093809448598376499, 'formEditClass:formEditClass:update', 2, '保存', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376502, NULL, 'formClassStudent', 0, '班级学生', 120, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376503, 1093809448598376502, 'formClassStudent:formClassStudent', 1, '班级学生', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376504, 1093809448598376503, 'formClassStudent:formClassStudent:formSetClassStudent', 2, '设置班级学生', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376505, 1093809448598376503, 'formClassStudent:formClassStudent:deleteClassStudent', 2, '移除', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376506, NULL, 'formClassCourse', 0, '班级课程', 130, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376507, 1093809448598376506, 'formClassCourse:formClassCourse', 1, '班级课程', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376508, 1093809448598376507, 'formClassCourse:formClassCourse:formSetClassCourse', 2, '设置班级课程', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376509, 1093809448598376507, 'formClassCourse:formClassCourse:deleteClassCourse', 2, '移除', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376510, NULL, 'formSetClassStudent', 0, '设置班级学生', 140, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376511, 1093809448598376510, 'formSetClassStudent:formSetClassStudent', 1, '设置班级学生', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376512, 1093809448598376511, 'formSetClassStudent:formSetClassStudent:addClassStudent', 2, '添加', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376513, NULL, 'formSetClassCourse', 0, '设置班级课程', 150, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376514, 1093809448598376513, 'formSetClassCourse:formSetClassCourse', 1, '设置班级课程', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376515, 1093809448598376514, 'formSetClassCourse:formSetClassCourse:addClassCourse', 2, '添加', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376516, NULL, 'formCourseStats', 0, '课程统计', 160, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376517, 1093809448598376516, 'formCourseStats:formCourseStats', 1, '课程统计', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376518, NULL, 'formStudentActionStats', 0, '学生行为统计', 170, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376519, 1093809448598376518, 'formStudentActionStats:formStudentActionStats', 1, '学生行为统计', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376520, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formBuyCourseDetail', 2, '学生行为详情', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376521, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formBuyVideoDetail', 2, '学生行为详情', 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376522, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formBuyFlowerDetail', 2, '学生行为详情', 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376523, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formBuyPaperDetail', 2, '学生行为详情', 30, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376524, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formBuyCoinDetail', 2, '学生行为详情', 40, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376525, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formDoCourseDetail', 2, '学生行为详情', 50, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376526, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formWatchVideoDetail', 2, '学生行为详情', 60, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376527, 1093809448598376519, 'formStudentActionStats:formStudentActionStats:formRfreshDetail', 2, '学生行为详情', 70, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376528, NULL, 'formStudentActionDetail', 0, '学生行为详情', 180, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376529, 1093809448598376528, 'formStudentActionDetail:formStudentActionDetail', 1, '学生行为详情', 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376537, NULL, 'formSysUser', 0, '用户管理', 10000, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376538, 1093809448598376537, 'formSysUser:fragmentSysUser', 1, '用户管理', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376539, 1093809448598376538, 'formSysUser:fragmentSysUser:add', 2, '新增', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376540, 1093809448598376538, 'formSysUser:fragmentSysUser:update', 2, '编辑', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376541, 1093809448598376538, 'formSysUser:fragmentSysUser:delete', 2, '删除', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376542, 1093809448598376538, 'formSysUser:fragmentSysUser:resetPassword', 2, '重置密码', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376563, NULL, 'formSysRole', 0, '角色管理', 10200, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376564, 1093809448598376563, 'formSysRole:fragmentSysRole', 1, '角色管理', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376565, 1093809448598376563, 'formSysRole:fragmentSysRoleUser', 1, '用户授权', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376566, 1093809448598376564, 'formSysRole:fragmentSysRole:add', 2, '新增', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376567, 1093809448598376564, 'formSysRole:fragmentSysRole:update', 2, '编辑', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376568, 1093809448598376564, 'formSysRole:fragmentSysRole:delete', 2, '删除', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376569, 1093809448598376565, 'formSysRole:fragmentSysRoleUser:addUserRole', 2, '授权用户', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376570, 1093809448598376565, 'formSysRole:fragmentSysRoleUser:deleteUserRole', 2, '移除用户', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376577, NULL, 'formSysMenu', 0, '菜单管理', 10600, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376578, 1093809448598376577, 'formSysMenu:fragmentSysMenu', 1, '菜单管理', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376579, 1093809448598376578, 'formSysMenu:fragmentSysMenu:add', 2, '新增', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376580, 1093809448598376578, 'formSysMenu:fragmentSysMenu:update', 2, '编辑', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376581, 1093809448598376578, 'formSysMenu:fragmentSysMenu:delete', 2, '删除', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376582, 1093809448598376578, 'formSysMenu:fragmentSysMenu:listMenuPerm', 2, '权限列表', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376588, NULL, 'formSysPermCode', 0, '权限字管理', 10700, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376589, 1093809448598376588, 'formSysPermCode:fragmentSysPermCode', 1, '权限字管理', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376590, 1093809448598376589, 'formSysPermCode:fragmentSysPermCode:add', 2, '新增', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376591, 1093809448598376589, 'formSysPermCode:fragmentSysPermCode:update', 2, '编辑', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376592, 1093809448598376589, 'formSysPermCode:fragmentSysPermCode:delete', 2, '删除', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376601, NULL, 'formSysPerm', 0, '权限管理', 10800, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376602, 1093809448598376601, 'formSysPerm:fragmentSysPerm', 1, '权限管理', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376603, 1093809448598376602, 'formSysPerm:fragmentSysPerm:addPermModule', 2, '新增模块', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376604, 1093809448598376602, 'formSysPerm:fragmentSysPerm:updatePermModule', 2, '编辑模块', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376605, 1093809448598376602, 'formSysPerm:fragmentSysPerm:deletePermModule', 2, '删除模块', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376606, 1093809448598376602, 'formSysPerm:fragmentSysPerm:addPerm', 2, '新增权限', 4, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376607, 1093809448598376602, 'formSysPerm:fragmentSysPerm:updatePerm', 2, '编辑权限', 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376608, 1093809448598376602, 'formSysPerm:fragmentSysPerm:deletePerm', 2, '删除权限', 6, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376615, NULL, 'formSysDict', 0, '字典管理', 10900, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376616, 1093809448598376615, 'formSysDict:fragmentSysDict', 1, '字典管理', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376617, 1093809448598376616, 'formSysDict:fragmentSysDict:add', 2, '新增', 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376618, 1093809448598376616, 'formSysDict:fragmentSysDict:update', 2, '编辑', 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376619, 1093809448598376616, 'formSysDict:fragmentSysDict:delete', 2, '删除', 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_code` VALUES (1093809448598376620, 1093809448598376616, 'formSysDict:fragmentSysDict:reloadCache', 2, '同步缓存', 4, CURDATE(), 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_code_perm +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_code_perm`; +CREATE TABLE `zz_sys_perm_code_perm` ( + `perm_code_id` bigint(20) NOT NULL COMMENT '权限字Id', + `perm_id` bigint(20) NOT NULL COMMENT '权限id', + PRIMARY KEY (`perm_code_id`,`perm_id`), + KEY `idx_perm_id` (`perm_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限字和权限资源关联表'; + +-- ---------------------------- +-- Records of zz_sys_perm_code_perm +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376482, 1093809448569016321); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376486, 1093809448569016322); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376478, 1093809448569016323); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376475, 1093809448569016324); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376484, 1093809448569016326); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376482, 1093809448569016328); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376486, 1093809448569016328); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376475, 1093809448569016329); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376484, 1093809448569016329); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376456, 1093809448569016331); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376460, 1093809448569016332); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376452, 1093809448569016333); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376449, 1093809448569016334); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376458, 1093809448569016336); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376469, 1093809448569016340); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376473, 1093809448569016340); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376465, 1093809448569016341); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376462, 1093809448569016342); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376539, 1093809448569016347); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376540, 1093809448569016348); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376541, 1093809448569016349); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376538, 1093809448569016350); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376538, 1093809448569016351); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376540, 1093809448569016352); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376540, 1093809448569016353); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376542, 1093809448569016354); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376497, 1093809448569016356); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376501, 1093809448569016357); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376493, 1093809448569016358); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376488, 1093809448569016359); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376499, 1093809448569016361); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376515, 1093809448569016363); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376509, 1093809448569016364); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376507, 1093809448569016365); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376514, 1093809448569016366); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376512, 1093809448569016367); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376505, 1093809448569016368); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376503, 1093809448569016369); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376511, 1093809448569016370); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376517, 1093809448569016372); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376517, 1093809448569016373); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376519, 1093809448569016378); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376519, 1093809448569016379); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376529, 1093809448569016387); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376566, 1093809448569016392); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376567, 1093809448569016393); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376568, 1093809448569016394); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376539, 1093809448569016395); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376540, 1093809448569016395); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376564, 1093809448569016395); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376567, 1093809448569016396); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376569, 1093809448569016397); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376570, 1093809448569016398); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376565, 1093809448569016399); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376569, 1093809448569016400); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376579, 1093809448569016402); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376580, 1093809448569016403); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376581, 1093809448569016404); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376566, 1093809448569016405); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376567, 1093809448569016405); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376578, 1093809448569016405); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376580, 1093809448569016406); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376582, 1093809448569016407); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376590, 1093809448569016409); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376591, 1093809448569016410); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376592, 1093809448569016411); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376579, 1093809448569016412); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376580, 1093809448569016412); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376589, 1093809448569016412); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376591, 1093809448569016413); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376603, 1093809448569016415); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376604, 1093809448569016416); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376605, 1093809448569016417); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376602, 1093809448569016418); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376590, 1093809448569016419); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376591, 1093809448569016419); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376602, 1093809448569016419); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376606, 1093809448569016421); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376607, 1093809448569016422); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376608, 1093809448569016423); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376602, 1093809448569016424); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376607, 1093809448569016425); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016428); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016429); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016430); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016431); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016433); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016434); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016435); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1093809448598376616, 1093809448569016436); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_module +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_module`; +CREATE TABLE `zz_sys_perm_module` ( + `module_id` bigint(20) NOT NULL COMMENT '权限模块id', + `parent_id` bigint(20) DEFAULT '0' COMMENT '上级权限模块id', + `module_name` varchar(64) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '权限模块名称', + `module_type` int(11) NOT NULL COMMENT '模块类型(0: 普通模块 1: Controller模块)', + `show_order` int(11) NOT NULL DEFAULT '0' COMMENT '权限模块在当前层级下的顺序,由小到大', + `create_time` datetime NOT NULL COMMENT '创建时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`module_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE, + KEY `idx_module_type` (`module_type`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限模块表'; + +-- ---------------------------- +-- Records of zz_sys_perm_module +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_module` VALUES (1093376634891538435, NULL, '用户权限', 0, 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093376634933481472, NULL, '系统配置', 0, 2, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093376634933481473, NULL, '缺省分组', 0, 3, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016320, 1093376634933481473, '课程数据', 1, 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016330, 1093376634933481473, '校区数据', 1, 5, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016338, 1093376634933481473, '学生数据', 1, 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016346, 1093376634891538435, '用户管理', 1, 0, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016355, 1093376634933481473, '班级数据', 1, 15, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016371, 1093376634933481473, '课程统计', 1, 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016377, 1093376634933481473, '学生行为统计', 1, 25, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016383, 1093376634933481473, '学生行为流水', 1, 30, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016391, 1093376634891538435, '角色管理', 1, 10, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016401, 1093376634891538435, '菜单管理', 1, 15, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016408, 1093376634891538435, '权限字管理', 1, 20, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016414, 1093376634891538435, '权限模块管理', 1, 25, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016420, 1093376634891538435, '权限资源管理', 1, 30, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016426, 1093376634933481472, '字典管理', 0, 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016427, 1093809448569016426, '行政区划', 1, 1, CURDATE(), 1); +INSERT INTO `zz_sys_perm_module` VALUES (1093809448569016432, 1093809448569016426, '年级', 1, 2, CURDATE(), 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_whitelist +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_whitelist`; +CREATE TABLE `zz_sys_perm_whitelist` ( + `perm_url` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '权限资源的url', + `module_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '权限资源所属模块名字(通常是Controller的名字)', + `perm_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '权限的名称', + PRIMARY KEY (`perm_url`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='权限资源白名单表(认证用户均可访问的url资源)'; + +-- ---------------------------- +-- Records of zz_sys_perm_whitelist +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/CourseClass/areaCode/listDictAreaCode', '行政区划', '行政区划列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/CourseClass/areaCode/listDictAreaCodeByParentId', '行政区划', '行政区划过滤列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/CourseClass/course/listDictCourse', '课程数据', '课程字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/CourseClass/grade/listDictGrade', '年级', '字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/CourseClass/schoolInfo/listDictSchoolInfo', '校区数据', '校区字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/CourseClass/student/listDictStudent', '学生数据', '学生字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/login/doLogout', '登录模块', '退出登陆'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_role`; +CREATE TABLE `zz_sys_role` ( + `role_id` bigint(20) NOT NULL COMMENT '主键Id', + `role_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '角色名称', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_username` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '创建用户显示名', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统角色表'; + +-- ---------------------------- +-- Table structure for zz_sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_role_menu`; +CREATE TABLE `zz_sys_role_menu` ( + `role_id` bigint(20) NOT NULL COMMENT '角色Id', + `menu_id` bigint(20) NOT NULL COMMENT '菜单Id', + PRIMARY KEY (`role_id`,`menu_id`) USING BTREE, + KEY `idx_menu_id` (`menu_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='角色与菜单对应关系表'; + +-- ---------------------------- +-- Table structure for zz_sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_user`; +CREATE TABLE `zz_sys_user` ( + `user_id` bigint(20) NOT NULL COMMENT '主键Id', + `login_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '用户登录名称', + `password` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '密码', + `show_name` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '用户显示名称', + `user_type` int(11) NOT NULL COMMENT '用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)', + `head_image_url` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户头像的Url', + `user_status` int(11) NOT NULL COMMENT '状态(0: 正常 1: 锁定)', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_username` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '创建用户名', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`user_id`) USING BTREE, + UNIQUE KEY `uk_login_name` (`login_name`) USING BTREE, + KEY `idx_status` (`user_status`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统用户表'; + +-- ---------------------------- +-- Records of zz_sys_user +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_user` VALUES (1093809448606765057, 'admin', '$2a$10$gvX5Jvv.AF3rKA7H0AVrCu8gQ2v6zPKvUazqRzAEwE1JabSUz9FFm', '管理员', 0, 'CHANGE TO YOUR HEAD IMAGE URL!!!', 0, 1093809448606765057, '管理员', CURDATE(), CURDATE(), 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_user_role`; +CREATE TABLE `zz_sys_user_role` ( + `user_id` bigint(20) NOT NULL COMMENT '用户Id', + `role_id` bigint(20) NOT NULL COMMENT '角色Id', + PRIMARY KEY (`user_id`,`role_id`) USING BTREE, + KEY `idx_role_id` (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='用户与角色对应关系表'; + +-- ---------------------------- +-- Table structure for zz_area_code +-- ---------------------------- +DROP TABLE IF EXISTS `zz_area_code`; +CREATE TABLE `zz_area_code` ( + `area_id` bigint(20) unsigned NOT NULL COMMENT '行政区划主键Id', + `area_name` varchar(128) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '行政区划名称', + `area_level` int(11) NOT NULL COMMENT '行政区划级别 (1: 省级别 2: 市级别 3: 区级别)', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父级行政区划Id', + PRIMARY KEY (`area_id`) USING BTREE, + KEY `idx_level` (`area_level`) USING BTREE, + KEY `idx_area_name` (`area_name`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='行政区划表'; + +-- ---------------------------- +-- Records of zz_area_code +-- ---------------------------- +BEGIN; +INSERT INTO `zz_area_code` VALUES (110000000000, '北京市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (110100000000, '市辖区', 2, 110000000000); +INSERT INTO `zz_area_code` VALUES (110101000000, '东城区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110102000000, '西城区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110105000000, '朝阳区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110106000000, '丰台区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110107000000, '石景山区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110108000000, '海淀区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110109000000, '门头沟区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110111000000, '房山区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110112000000, '通州区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110113000000, '顺义区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110114000000, '昌平区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110115000000, '大兴区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110116000000, '怀柔区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110117000000, '平谷区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110118000000, '密云区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110119000000, '延庆区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (120000000000, '天津市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (120100000000, '市辖区', 2, 120000000000); +INSERT INTO `zz_area_code` VALUES (120101000000, '和平区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120102000000, '河东区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120103000000, '河西区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120104000000, '南开区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120105000000, '河北区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120106000000, '红桥区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120110000000, '东丽区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120111000000, '西青区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120112000000, '津南区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120113000000, '北辰区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120114000000, '武清区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120115000000, '宝坻区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120116000000, '滨海新区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120117000000, '宁河区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120118000000, '静海区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120119000000, '蓟州区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (130000000000, '河北省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (130100000000, '石家庄市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130101000000, '市辖区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130102000000, '长安区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130104000000, '桥西区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130105000000, '新华区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130107000000, '井陉矿区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130108000000, '裕华区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130109000000, '藁城区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130110000000, '鹿泉区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130111000000, '栾城区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130121000000, '井陉县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130123000000, '正定县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130125000000, '行唐县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130126000000, '灵寿县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130127000000, '高邑县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130128000000, '深泽县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130129000000, '赞皇县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130130000000, '无极县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130131000000, '平山县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130132000000, '元氏县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130133000000, '赵县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130171000000, '石家庄高新技术产业开发区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130172000000, '石家庄循环化工园区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130181000000, '辛集市', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130183000000, '晋州市', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130184000000, '新乐市', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130200000000, '唐山市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130201000000, '市辖区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130202000000, '路南区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130203000000, '路北区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130204000000, '古冶区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130205000000, '开平区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130207000000, '丰南区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130208000000, '丰润区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130209000000, '曹妃甸区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130224000000, '滦南县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130225000000, '乐亭县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130227000000, '迁西县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130229000000, '玉田县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130271000000, '唐山市芦台经济技术开发区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130272000000, '唐山市汉沽管理区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130273000000, '唐山高新技术产业开发区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130274000000, '河北唐山海港经济开发区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130281000000, '遵化市', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130283000000, '迁安市', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130284000000, '滦州市', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130300000000, '秦皇岛市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130301000000, '市辖区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130302000000, '海港区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130303000000, '山海关区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130304000000, '北戴河区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130306000000, '抚宁区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130321000000, '青龙满族自治县', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130322000000, '昌黎县', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130324000000, '卢龙县', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130371000000, '秦皇岛市经济技术开发区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130372000000, '北戴河新区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130400000000, '邯郸市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130401000000, '市辖区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130402000000, '邯山区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130403000000, '丛台区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130404000000, '复兴区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130406000000, '峰峰矿区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130407000000, '肥乡区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130408000000, '永年区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130423000000, '临漳县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130424000000, '成安县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130425000000, '大名县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130426000000, '涉县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130427000000, '磁县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130430000000, '邱县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130431000000, '鸡泽县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130432000000, '广平县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130433000000, '馆陶县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130434000000, '魏县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130435000000, '曲周县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130471000000, '邯郸经济技术开发区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130473000000, '邯郸冀南新区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130481000000, '武安市', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130500000000, '邢台市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130501000000, '市辖区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130502000000, '桥东区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130503000000, '桥西区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130521000000, '邢台县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130522000000, '临城县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130523000000, '内丘县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130524000000, '柏乡县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130525000000, '隆尧县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130526000000, '任县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130527000000, '南和县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130528000000, '宁晋县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130529000000, '巨鹿县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130530000000, '新河县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130531000000, '广宗县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130532000000, '平乡县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130533000000, '威县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130534000000, '清河县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130535000000, '临西县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130571000000, '河北邢台经济开发区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130581000000, '南宫市', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130582000000, '沙河市', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130600000000, '保定市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130601000000, '市辖区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130602000000, '竞秀区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130606000000, '莲池区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130607000000, '满城区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130608000000, '清苑区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130609000000, '徐水区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130623000000, '涞水县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130624000000, '阜平县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130626000000, '定兴县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130627000000, '唐县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130628000000, '高阳县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130629000000, '容城县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130630000000, '涞源县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130631000000, '望都县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130632000000, '安新县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130633000000, '易县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130634000000, '曲阳县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130635000000, '蠡县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130636000000, '顺平县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130637000000, '博野县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130638000000, '雄县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130671000000, '保定高新技术产业开发区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130672000000, '保定白沟新城', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130681000000, '涿州市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130682000000, '定州市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130683000000, '安国市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130684000000, '高碑店市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130700000000, '张家口市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130701000000, '市辖区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130702000000, '桥东区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130703000000, '桥西区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130705000000, '宣化区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130706000000, '下花园区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130708000000, '万全区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130709000000, '崇礼区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130722000000, '张北县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130723000000, '康保县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130724000000, '沽源县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130725000000, '尚义县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130726000000, '蔚县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130727000000, '阳原县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130728000000, '怀安县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130730000000, '怀来县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130731000000, '涿鹿县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130732000000, '赤城县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130771000000, '张家口市高新技术产业开发区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130772000000, '张家口市察北管理区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130773000000, '张家口市塞北管理区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130800000000, '承德市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130801000000, '市辖区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130802000000, '双桥区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130803000000, '双滦区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130804000000, '鹰手营子矿区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130821000000, '承德县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130822000000, '兴隆县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130824000000, '滦平县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130825000000, '隆化县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130826000000, '丰宁满族自治县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130827000000, '宽城满族自治县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130828000000, '围场满族蒙古族自治县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130871000000, '承德高新技术产业开发区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130881000000, '平泉市', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130900000000, '沧州市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130901000000, '市辖区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130902000000, '新华区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130903000000, '运河区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130921000000, '沧县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130922000000, '青县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130923000000, '东光县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130924000000, '海兴县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130925000000, '盐山县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130926000000, '肃宁县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130927000000, '南皮县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130928000000, '吴桥县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130929000000, '献县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130930000000, '孟村回族自治县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130971000000, '河北沧州经济开发区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130972000000, '沧州高新技术产业开发区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130973000000, '沧州渤海新区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130981000000, '泊头市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130982000000, '任丘市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130983000000, '黄骅市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130984000000, '河间市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (131000000000, '廊坊市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (131001000000, '市辖区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131002000000, '安次区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131003000000, '广阳区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131022000000, '固安县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131023000000, '永清县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131024000000, '香河县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131025000000, '大城县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131026000000, '文安县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131028000000, '大厂回族自治县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131071000000, '廊坊经济技术开发区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131081000000, '霸州市', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131082000000, '三河市', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131100000000, '衡水市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (131101000000, '市辖区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131102000000, '桃城区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131103000000, '冀州区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131121000000, '枣强县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131122000000, '武邑县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131123000000, '武强县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131124000000, '饶阳县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131125000000, '安平县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131126000000, '故城县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131127000000, '景县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131128000000, '阜城县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131171000000, '河北衡水高新技术产业开发区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131172000000, '衡水滨湖新区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131182000000, '深州市', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (140000000000, '山西省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (140100000000, '太原市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140101000000, '市辖区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140105000000, '小店区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140106000000, '迎泽区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140107000000, '杏花岭区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140108000000, '尖草坪区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140109000000, '万柏林区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140110000000, '晋源区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140121000000, '清徐县', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140122000000, '阳曲县', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140123000000, '娄烦县', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140171000000, '山西转型综合改革示范区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140181000000, '古交市', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140200000000, '大同市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140201000000, '市辖区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140212000000, '新荣区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140213000000, '平城区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140214000000, '云冈区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140215000000, '云州区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140221000000, '阳高县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140222000000, '天镇县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140223000000, '广灵县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140224000000, '灵丘县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140225000000, '浑源县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140226000000, '左云县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140271000000, '山西大同经济开发区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140300000000, '阳泉市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140301000000, '市辖区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140302000000, '城区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140303000000, '矿区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140311000000, '郊区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140321000000, '平定县', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140322000000, '盂县', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140400000000, '长治市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140401000000, '市辖区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140403000000, '潞州区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140404000000, '上党区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140405000000, '屯留区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140406000000, '潞城区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140423000000, '襄垣县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140425000000, '平顺县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140426000000, '黎城县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140427000000, '壶关县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140428000000, '长子县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140429000000, '武乡县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140430000000, '沁县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140431000000, '沁源县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140471000000, '山西长治高新技术产业园区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140500000000, '晋城市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140501000000, '市辖区', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140502000000, '城区', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140521000000, '沁水县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140522000000, '阳城县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140524000000, '陵川县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140525000000, '泽州县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140581000000, '高平市', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140600000000, '朔州市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140601000000, '市辖区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140602000000, '朔城区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140603000000, '平鲁区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140621000000, '山阴县', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140622000000, '应县', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140623000000, '右玉县', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140671000000, '山西朔州经济开发区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140681000000, '怀仁市', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140700000000, '晋中市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140701000000, '市辖区', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140702000000, '榆次区', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140721000000, '榆社县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140722000000, '左权县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140723000000, '和顺县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140724000000, '昔阳县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140725000000, '寿阳县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140726000000, '太谷县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140727000000, '祁县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140728000000, '平遥县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140729000000, '灵石县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140781000000, '介休市', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140800000000, '运城市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140801000000, '市辖区', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140802000000, '盐湖区', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140821000000, '临猗县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140822000000, '万荣县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140823000000, '闻喜县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140824000000, '稷山县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140825000000, '新绛县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140826000000, '绛县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140827000000, '垣曲县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140828000000, '夏县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140829000000, '平陆县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140830000000, '芮城县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140881000000, '永济市', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140882000000, '河津市', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140900000000, '忻州市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140901000000, '市辖区', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140902000000, '忻府区', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140921000000, '定襄县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140922000000, '五台县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140923000000, '代县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140924000000, '繁峙县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140925000000, '宁武县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140926000000, '静乐县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140927000000, '神池县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140928000000, '五寨县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140929000000, '岢岚县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140930000000, '河曲县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140931000000, '保德县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140932000000, '偏关县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140971000000, '五台山风景名胜区', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140981000000, '原平市', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (141000000000, '临汾市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (141001000000, '市辖区', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141002000000, '尧都区', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141021000000, '曲沃县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141022000000, '翼城县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141023000000, '襄汾县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141024000000, '洪洞县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141025000000, '古县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141026000000, '安泽县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141027000000, '浮山县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141028000000, '吉县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141029000000, '乡宁县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141030000000, '大宁县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141031000000, '隰县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141032000000, '永和县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141033000000, '蒲县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141034000000, '汾西县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141081000000, '侯马市', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141082000000, '霍州市', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141100000000, '吕梁市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (141101000000, '市辖区', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141102000000, '离石区', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141121000000, '文水县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141122000000, '交城县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141123000000, '兴县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141124000000, '临县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141125000000, '柳林县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141126000000, '石楼县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141127000000, '岚县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141128000000, '方山县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141129000000, '中阳县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141130000000, '交口县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141181000000, '孝义市', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141182000000, '汾阳市', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (150000000000, '内蒙古自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (150100000000, '呼和浩特市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150101000000, '市辖区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150102000000, '新城区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150103000000, '回民区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150104000000, '玉泉区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150105000000, '赛罕区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150121000000, '土默特左旗', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150122000000, '托克托县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150123000000, '和林格尔县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150124000000, '清水河县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150125000000, '武川县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150171000000, '呼和浩特金海工业园区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150172000000, '呼和浩特经济技术开发区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150200000000, '包头市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150201000000, '市辖区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150202000000, '东河区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150203000000, '昆都仑区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150204000000, '青山区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150205000000, '石拐区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150206000000, '白云鄂博矿区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150207000000, '九原区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150221000000, '土默特右旗', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150222000000, '固阳县', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150223000000, '达尔罕茂明安联合旗', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150271000000, '包头稀土高新技术产业开发区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150300000000, '乌海市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150301000000, '市辖区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150302000000, '海勃湾区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150303000000, '海南区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150304000000, '乌达区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150400000000, '赤峰市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150401000000, '市辖区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150402000000, '红山区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150403000000, '元宝山区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150404000000, '松山区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150421000000, '阿鲁科尔沁旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150422000000, '巴林左旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150423000000, '巴林右旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150424000000, '林西县', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150425000000, '克什克腾旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150426000000, '翁牛特旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150428000000, '喀喇沁旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150429000000, '宁城县', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150430000000, '敖汉旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150500000000, '通辽市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150501000000, '市辖区', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150502000000, '科尔沁区', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150521000000, '科尔沁左翼中旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150522000000, '科尔沁左翼后旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150523000000, '开鲁县', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150524000000, '库伦旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150525000000, '奈曼旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150526000000, '扎鲁特旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150571000000, '通辽经济技术开发区', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150581000000, '霍林郭勒市', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150600000000, '鄂尔多斯市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150601000000, '市辖区', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150602000000, '东胜区', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150603000000, '康巴什区', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150621000000, '达拉特旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150622000000, '准格尔旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150623000000, '鄂托克前旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150624000000, '鄂托克旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150625000000, '杭锦旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150626000000, '乌审旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150627000000, '伊金霍洛旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150700000000, '呼伦贝尔市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150701000000, '市辖区', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150702000000, '海拉尔区', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150703000000, '扎赉诺尔区', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150721000000, '阿荣旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150722000000, '莫力达瓦达斡尔族自治旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150723000000, '鄂伦春自治旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150724000000, '鄂温克族自治旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150725000000, '陈巴尔虎旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150726000000, '新巴尔虎左旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150727000000, '新巴尔虎右旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150781000000, '满洲里市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150782000000, '牙克石市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150783000000, '扎兰屯市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150784000000, '额尔古纳市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150785000000, '根河市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150800000000, '巴彦淖尔市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150801000000, '市辖区', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150802000000, '临河区', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150821000000, '五原县', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150822000000, '磴口县', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150823000000, '乌拉特前旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150824000000, '乌拉特中旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150825000000, '乌拉特后旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150826000000, '杭锦后旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150900000000, '乌兰察布市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150901000000, '市辖区', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150902000000, '集宁区', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150921000000, '卓资县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150922000000, '化德县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150923000000, '商都县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150924000000, '兴和县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150925000000, '凉城县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150926000000, '察哈尔右翼前旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150927000000, '察哈尔右翼中旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150928000000, '察哈尔右翼后旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150929000000, '四子王旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150981000000, '丰镇市', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (152200000000, '兴安盟', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (152201000000, '乌兰浩特市', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152202000000, '阿尔山市', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152221000000, '科尔沁右翼前旗', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152222000000, '科尔沁右翼中旗', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152223000000, '扎赉特旗', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152224000000, '突泉县', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152500000000, '锡林郭勒盟', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (152501000000, '二连浩特市', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152502000000, '锡林浩特市', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152522000000, '阿巴嘎旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152523000000, '苏尼特左旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152524000000, '苏尼特右旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152525000000, '东乌珠穆沁旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152526000000, '西乌珠穆沁旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152527000000, '太仆寺旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152528000000, '镶黄旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152529000000, '正镶白旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152530000000, '正蓝旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152531000000, '多伦县', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152571000000, '乌拉盖管委会', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152900000000, '阿拉善盟', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (152921000000, '阿拉善左旗', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (152922000000, '阿拉善右旗', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (152923000000, '额济纳旗', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (152971000000, '内蒙古阿拉善经济开发区', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (210000000000, '辽宁省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (210100000000, '沈阳市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210101000000, '市辖区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210102000000, '和平区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210103000000, '沈河区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210104000000, '大东区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210105000000, '皇姑区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210106000000, '铁西区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210111000000, '苏家屯区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210112000000, '浑南区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210113000000, '沈北新区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210114000000, '于洪区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210115000000, '辽中区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210123000000, '康平县', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210124000000, '法库县', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210181000000, '新民市', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210200000000, '大连市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210201000000, '市辖区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210202000000, '中山区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210203000000, '西岗区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210204000000, '沙河口区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210211000000, '甘井子区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210212000000, '旅顺口区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210213000000, '金州区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210214000000, '普兰店区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210224000000, '长海县', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210281000000, '瓦房店市', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210283000000, '庄河市', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210300000000, '鞍山市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210301000000, '市辖区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210302000000, '铁东区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210303000000, '铁西区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210304000000, '立山区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210311000000, '千山区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210321000000, '台安县', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210323000000, '岫岩满族自治县', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210381000000, '海城市', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210400000000, '抚顺市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210401000000, '市辖区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210402000000, '新抚区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210403000000, '东洲区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210404000000, '望花区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210411000000, '顺城区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210421000000, '抚顺县', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210422000000, '新宾满族自治县', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210423000000, '清原满族自治县', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210500000000, '本溪市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210501000000, '市辖区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210502000000, '平山区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210503000000, '溪湖区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210504000000, '明山区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210505000000, '南芬区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210521000000, '本溪满族自治县', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210522000000, '桓仁满族自治县', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210600000000, '丹东市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210601000000, '市辖区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210602000000, '元宝区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210603000000, '振兴区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210604000000, '振安区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210624000000, '宽甸满族自治县', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210681000000, '东港市', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210682000000, '凤城市', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210700000000, '锦州市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210701000000, '市辖区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210702000000, '古塔区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210703000000, '凌河区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210711000000, '太和区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210726000000, '黑山县', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210727000000, '义县', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210781000000, '凌海市', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210782000000, '北镇市', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210800000000, '营口市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210801000000, '市辖区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210802000000, '站前区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210803000000, '西市区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210804000000, '鲅鱼圈区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210811000000, '老边区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210881000000, '盖州市', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210882000000, '大石桥市', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210900000000, '阜新市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210901000000, '市辖区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210902000000, '海州区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210903000000, '新邱区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210904000000, '太平区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210905000000, '清河门区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210911000000, '细河区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210921000000, '阜新蒙古族自治县', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210922000000, '彰武县', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (211000000000, '辽阳市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211001000000, '市辖区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211002000000, '白塔区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211003000000, '文圣区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211004000000, '宏伟区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211005000000, '弓长岭区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211011000000, '太子河区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211021000000, '辽阳县', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211081000000, '灯塔市', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211100000000, '盘锦市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211101000000, '市辖区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211102000000, '双台子区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211103000000, '兴隆台区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211104000000, '大洼区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211122000000, '盘山县', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211200000000, '铁岭市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211201000000, '市辖区', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211202000000, '银州区', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211204000000, '清河区', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211221000000, '铁岭县', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211223000000, '西丰县', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211224000000, '昌图县', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211281000000, '调兵山市', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211282000000, '开原市', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211300000000, '朝阳市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211301000000, '市辖区', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211302000000, '双塔区', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211303000000, '龙城区', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211321000000, '朝阳县', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211322000000, '建平县', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211324000000, '喀喇沁左翼蒙古族自治县', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211381000000, '北票市', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211382000000, '凌源市', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211400000000, '葫芦岛市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211401000000, '市辖区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211402000000, '连山区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211403000000, '龙港区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211404000000, '南票区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211421000000, '绥中县', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211422000000, '建昌县', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211481000000, '兴城市', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (220000000000, '吉林省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (220100000000, '长春市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220101000000, '市辖区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220102000000, '南关区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220103000000, '宽城区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220104000000, '朝阳区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220105000000, '二道区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220106000000, '绿园区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220112000000, '双阳区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220113000000, '九台区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220122000000, '农安县', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220171000000, '长春经济技术开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220172000000, '长春净月高新技术产业开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220173000000, '长春高新技术产业开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220174000000, '长春汽车经济技术开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220182000000, '榆树市', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220183000000, '德惠市', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220200000000, '吉林市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220201000000, '市辖区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220202000000, '昌邑区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220203000000, '龙潭区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220204000000, '船营区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220211000000, '丰满区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220221000000, '永吉县', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220271000000, '吉林经济开发区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220272000000, '吉林高新技术产业开发区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220273000000, '吉林中国新加坡食品区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220281000000, '蛟河市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220282000000, '桦甸市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220283000000, '舒兰市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220284000000, '磐石市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220300000000, '四平市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220301000000, '市辖区', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220302000000, '铁西区', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220303000000, '铁东区', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220322000000, '梨树县', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220323000000, '伊通满族自治县', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220381000000, '公主岭市', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220382000000, '双辽市', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220400000000, '辽源市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220401000000, '市辖区', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220402000000, '龙山区', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220403000000, '西安区', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220421000000, '东丰县', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220422000000, '东辽县', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220500000000, '通化市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220501000000, '市辖区', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220502000000, '东昌区', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220503000000, '二道江区', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220521000000, '通化县', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220523000000, '辉南县', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220524000000, '柳河县', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220581000000, '梅河口市', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220582000000, '集安市', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220600000000, '白山市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220601000000, '市辖区', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220602000000, '浑江区', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220605000000, '江源区', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220621000000, '抚松县', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220622000000, '靖宇县', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220623000000, '长白朝鲜族自治县', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220681000000, '临江市', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220700000000, '松原市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220701000000, '市辖区', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220702000000, '宁江区', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220721000000, '前郭尔罗斯蒙古族自治县', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220722000000, '长岭县', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220723000000, '乾安县', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220771000000, '吉林松原经济开发区', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220781000000, '扶余市', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220800000000, '白城市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220801000000, '市辖区', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220802000000, '洮北区', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220821000000, '镇赉县', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220822000000, '通榆县', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220871000000, '吉林白城经济开发区', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220881000000, '洮南市', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220882000000, '大安市', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (222400000000, '延边朝鲜族自治州', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (222401000000, '延吉市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222402000000, '图们市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222403000000, '敦化市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222404000000, '珲春市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222405000000, '龙井市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222406000000, '和龙市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222424000000, '汪清县', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222426000000, '安图县', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (230000000000, '黑龙江省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (230100000000, '哈尔滨市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230101000000, '市辖区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230102000000, '道里区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230103000000, '南岗区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230104000000, '道外区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230108000000, '平房区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230109000000, '松北区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230110000000, '香坊区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230111000000, '呼兰区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230112000000, '阿城区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230113000000, '双城区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230123000000, '依兰县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230124000000, '方正县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230125000000, '宾县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230126000000, '巴彦县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230127000000, '木兰县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230128000000, '通河县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230129000000, '延寿县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230183000000, '尚志市', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230184000000, '五常市', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230200000000, '齐齐哈尔市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230201000000, '市辖区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230202000000, '龙沙区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230203000000, '建华区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230204000000, '铁锋区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230205000000, '昂昂溪区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230206000000, '富拉尔基区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230207000000, '碾子山区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230208000000, '梅里斯达斡尔族区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230221000000, '龙江县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230223000000, '依安县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230224000000, '泰来县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230225000000, '甘南县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230227000000, '富裕县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230229000000, '克山县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230230000000, '克东县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230231000000, '拜泉县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230281000000, '讷河市', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230300000000, '鸡西市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230301000000, '市辖区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230302000000, '鸡冠区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230303000000, '恒山区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230304000000, '滴道区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230305000000, '梨树区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230306000000, '城子河区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230307000000, '麻山区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230321000000, '鸡东县', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230381000000, '虎林市', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230382000000, '密山市', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230400000000, '鹤岗市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230401000000, '市辖区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230402000000, '向阳区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230403000000, '工农区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230404000000, '南山区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230405000000, '兴安区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230406000000, '东山区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230407000000, '兴山区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230421000000, '萝北县', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230422000000, '绥滨县', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230500000000, '双鸭山市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230501000000, '市辖区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230502000000, '尖山区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230503000000, '岭东区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230505000000, '四方台区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230506000000, '宝山区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230521000000, '集贤县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230522000000, '友谊县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230523000000, '宝清县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230524000000, '饶河县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230600000000, '大庆市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230601000000, '市辖区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230602000000, '萨尔图区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230603000000, '龙凤区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230604000000, '让胡路区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230605000000, '红岗区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230606000000, '大同区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230621000000, '肇州县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230622000000, '肇源县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230623000000, '林甸县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230624000000, '杜尔伯特蒙古族自治县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230671000000, '大庆高新技术产业开发区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230700000000, '伊春市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230701000000, '市辖区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230702000000, '伊春区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230703000000, '南岔区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230704000000, '友好区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230705000000, '西林区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230706000000, '翠峦区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230707000000, '新青区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230708000000, '美溪区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230709000000, '金山屯区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230710000000, '五营区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230711000000, '乌马河区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230712000000, '汤旺河区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230713000000, '带岭区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230714000000, '乌伊岭区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230715000000, '红星区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230716000000, '上甘岭区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230722000000, '嘉荫县', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230781000000, '铁力市', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230800000000, '佳木斯市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230801000000, '市辖区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230803000000, '向阳区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230804000000, '前进区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230805000000, '东风区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230811000000, '郊区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230822000000, '桦南县', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230826000000, '桦川县', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230828000000, '汤原县', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230881000000, '同江市', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230882000000, '富锦市', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230883000000, '抚远市', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230900000000, '七台河市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230901000000, '市辖区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230902000000, '新兴区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230903000000, '桃山区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230904000000, '茄子河区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230921000000, '勃利县', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (231000000000, '牡丹江市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (231001000000, '市辖区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231002000000, '东安区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231003000000, '阳明区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231004000000, '爱民区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231005000000, '西安区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231025000000, '林口县', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231071000000, '牡丹江经济技术开发区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231081000000, '绥芬河市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231083000000, '海林市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231084000000, '宁安市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231085000000, '穆棱市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231086000000, '东宁市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231100000000, '黑河市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (231101000000, '市辖区', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231102000000, '爱辉区', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231121000000, '嫩江县', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231123000000, '逊克县', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231124000000, '孙吴县', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231181000000, '北安市', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231182000000, '五大连池市', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231200000000, '绥化市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (231201000000, '市辖区', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231202000000, '北林区', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231221000000, '望奎县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231222000000, '兰西县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231223000000, '青冈县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231224000000, '庆安县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231225000000, '明水县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231226000000, '绥棱县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231281000000, '安达市', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231282000000, '肇东市', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231283000000, '海伦市', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (232700000000, '大兴安岭地区', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (232701000000, '漠河市', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232721000000, '呼玛县', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232722000000, '塔河县', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232761000000, '加格达奇区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232762000000, '松岭区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232763000000, '新林区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232764000000, '呼中区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (310000000000, '上海市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (310100000000, '市辖区', 2, 310000000000); +INSERT INTO `zz_area_code` VALUES (310101000000, '黄浦区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310104000000, '徐汇区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310105000000, '长宁区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310106000000, '静安区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310107000000, '普陀区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310109000000, '虹口区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310110000000, '杨浦区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310112000000, '闵行区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310113000000, '宝山区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310114000000, '嘉定区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310115000000, '浦东新区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310116000000, '金山区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310117000000, '松江区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310118000000, '青浦区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310120000000, '奉贤区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310151000000, '崇明区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (320000000000, '江苏省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (320100000000, '南京市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320101000000, '市辖区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320102000000, '玄武区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320104000000, '秦淮区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320105000000, '建邺区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320106000000, '鼓楼区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320111000000, '浦口区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320113000000, '栖霞区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320114000000, '雨花台区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320115000000, '江宁区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320116000000, '六合区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320117000000, '溧水区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320118000000, '高淳区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320200000000, '无锡市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320201000000, '市辖区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320205000000, '锡山区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320206000000, '惠山区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320211000000, '滨湖区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320213000000, '梁溪区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320214000000, '新吴区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320281000000, '江阴市', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320282000000, '宜兴市', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320300000000, '徐州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320301000000, '市辖区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320302000000, '鼓楼区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320303000000, '云龙区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320305000000, '贾汪区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320311000000, '泉山区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320312000000, '铜山区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320321000000, '丰县', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320322000000, '沛县', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320324000000, '睢宁县', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320371000000, '徐州经济技术开发区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320381000000, '新沂市', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320382000000, '邳州市', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320400000000, '常州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320401000000, '市辖区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320402000000, '天宁区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320404000000, '钟楼区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320411000000, '新北区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320412000000, '武进区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320413000000, '金坛区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320481000000, '溧阳市', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320500000000, '苏州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320501000000, '市辖区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320505000000, '虎丘区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320506000000, '吴中区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320507000000, '相城区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320508000000, '姑苏区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320509000000, '吴江区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320571000000, '苏州工业园区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320581000000, '常熟市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320582000000, '张家港市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320583000000, '昆山市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320585000000, '太仓市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320600000000, '南通市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320601000000, '市辖区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320602000000, '崇川区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320611000000, '港闸区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320612000000, '通州区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320623000000, '如东县', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320671000000, '南通经济技术开发区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320681000000, '启东市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320682000000, '如皋市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320684000000, '海门市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320685000000, '海安市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320700000000, '连云港市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320701000000, '市辖区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320703000000, '连云区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320706000000, '海州区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320707000000, '赣榆区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320722000000, '东海县', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320723000000, '灌云县', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320724000000, '灌南县', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320771000000, '连云港经济技术开发区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320772000000, '连云港高新技术产业开发区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320800000000, '淮安市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320801000000, '市辖区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320803000000, '淮安区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320804000000, '淮阴区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320812000000, '清江浦区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320813000000, '洪泽区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320826000000, '涟水县', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320830000000, '盱眙县', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320831000000, '金湖县', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320871000000, '淮安经济技术开发区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320900000000, '盐城市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320901000000, '市辖区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320902000000, '亭湖区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320903000000, '盐都区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320904000000, '大丰区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320921000000, '响水县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320922000000, '滨海县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320923000000, '阜宁县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320924000000, '射阳县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320925000000, '建湖县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320971000000, '盐城经济技术开发区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320981000000, '东台市', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (321000000000, '扬州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321001000000, '市辖区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321002000000, '广陵区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321003000000, '邗江区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321012000000, '江都区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321023000000, '宝应县', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321071000000, '扬州经济技术开发区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321081000000, '仪征市', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321084000000, '高邮市', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321100000000, '镇江市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321101000000, '市辖区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321102000000, '京口区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321111000000, '润州区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321112000000, '丹徒区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321171000000, '镇江新区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321181000000, '丹阳市', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321182000000, '扬中市', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321183000000, '句容市', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321200000000, '泰州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321201000000, '市辖区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321202000000, '海陵区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321203000000, '高港区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321204000000, '姜堰区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321271000000, '泰州医药高新技术产业开发区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321281000000, '兴化市', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321282000000, '靖江市', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321283000000, '泰兴市', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321300000000, '宿迁市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321301000000, '市辖区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321302000000, '宿城区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321311000000, '宿豫区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321322000000, '沭阳县', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321323000000, '泗阳县', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321324000000, '泗洪县', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321371000000, '宿迁经济技术开发区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (330000000000, '浙江省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (330100000000, '杭州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330101000000, '市辖区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330102000000, '上城区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330103000000, '下城区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330104000000, '江干区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330105000000, '拱墅区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330106000000, '西湖区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330108000000, '滨江区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330109000000, '萧山区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330110000000, '余杭区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330111000000, '富阳区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330112000000, '临安区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330122000000, '桐庐县', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330127000000, '淳安县', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330182000000, '建德市', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330200000000, '宁波市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330201000000, '市辖区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330203000000, '海曙区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330205000000, '江北区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330206000000, '北仑区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330211000000, '镇海区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330212000000, '鄞州区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330213000000, '奉化区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330225000000, '象山县', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330226000000, '宁海县', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330281000000, '余姚市', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330282000000, '慈溪市', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330300000000, '温州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330301000000, '市辖区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330302000000, '鹿城区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330303000000, '龙湾区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330304000000, '瓯海区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330305000000, '洞头区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330324000000, '永嘉县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330326000000, '平阳县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330327000000, '苍南县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330328000000, '文成县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330329000000, '泰顺县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330371000000, '温州经济技术开发区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330381000000, '瑞安市', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330382000000, '乐清市', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330400000000, '嘉兴市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330401000000, '市辖区', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330402000000, '南湖区', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330411000000, '秀洲区', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330421000000, '嘉善县', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330424000000, '海盐县', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330481000000, '海宁市', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330482000000, '平湖市', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330483000000, '桐乡市', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330500000000, '湖州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330501000000, '市辖区', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330502000000, '吴兴区', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330503000000, '南浔区', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330521000000, '德清县', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330522000000, '长兴县', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330523000000, '安吉县', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330600000000, '绍兴市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330601000000, '市辖区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330602000000, '越城区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330603000000, '柯桥区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330604000000, '上虞区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330624000000, '新昌县', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330681000000, '诸暨市', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330683000000, '嵊州市', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330700000000, '金华市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330701000000, '市辖区', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330702000000, '婺城区', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330703000000, '金东区', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330723000000, '武义县', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330726000000, '浦江县', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330727000000, '磐安县', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330781000000, '兰溪市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330782000000, '义乌市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330783000000, '东阳市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330784000000, '永康市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330800000000, '衢州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330801000000, '市辖区', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330802000000, '柯城区', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330803000000, '衢江区', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330822000000, '常山县', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330824000000, '开化县', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330825000000, '龙游县', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330881000000, '江山市', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330900000000, '舟山市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330901000000, '市辖区', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330902000000, '定海区', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330903000000, '普陀区', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330921000000, '岱山县', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330922000000, '嵊泗县', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (331000000000, '台州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (331001000000, '市辖区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331002000000, '椒江区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331003000000, '黄岩区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331004000000, '路桥区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331022000000, '三门县', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331023000000, '天台县', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331024000000, '仙居县', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331081000000, '温岭市', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331082000000, '临海市', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331083000000, '玉环市', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331100000000, '丽水市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (331101000000, '市辖区', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331102000000, '莲都区', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331121000000, '青田县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331122000000, '缙云县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331123000000, '遂昌县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331124000000, '松阳县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331125000000, '云和县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331126000000, '庆元县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331127000000, '景宁畲族自治县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331181000000, '龙泉市', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (340000000000, '安徽省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (340100000000, '合肥市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340101000000, '市辖区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340102000000, '瑶海区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340103000000, '庐阳区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340104000000, '蜀山区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340111000000, '包河区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340121000000, '长丰县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340122000000, '肥东县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340123000000, '肥西县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340124000000, '庐江县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340171000000, '合肥高新技术产业开发区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340172000000, '合肥经济技术开发区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340173000000, '合肥新站高新技术产业开发区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340181000000, '巢湖市', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340200000000, '芜湖市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340201000000, '市辖区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340202000000, '镜湖区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340203000000, '弋江区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340207000000, '鸠江区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340208000000, '三山区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340221000000, '芜湖县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340222000000, '繁昌县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340223000000, '南陵县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340225000000, '无为县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340271000000, '芜湖经济技术开发区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340272000000, '安徽芜湖长江大桥经济开发区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340300000000, '蚌埠市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340301000000, '市辖区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340302000000, '龙子湖区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340303000000, '蚌山区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340304000000, '禹会区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340311000000, '淮上区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340321000000, '怀远县', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340322000000, '五河县', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340323000000, '固镇县', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340371000000, '蚌埠市高新技术开发区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340372000000, '蚌埠市经济开发区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340400000000, '淮南市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340401000000, '市辖区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340402000000, '大通区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340403000000, '田家庵区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340404000000, '谢家集区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340405000000, '八公山区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340406000000, '潘集区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340421000000, '凤台县', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340422000000, '寿县', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340500000000, '马鞍山市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340501000000, '市辖区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340503000000, '花山区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340504000000, '雨山区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340506000000, '博望区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340521000000, '当涂县', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340522000000, '含山县', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340523000000, '和县', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340600000000, '淮北市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340601000000, '市辖区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340602000000, '杜集区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340603000000, '相山区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340604000000, '烈山区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340621000000, '濉溪县', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340700000000, '铜陵市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340701000000, '市辖区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340705000000, '铜官区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340706000000, '义安区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340711000000, '郊区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340722000000, '枞阳县', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340800000000, '安庆市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340801000000, '市辖区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340802000000, '迎江区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340803000000, '大观区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340811000000, '宜秀区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340822000000, '怀宁县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340825000000, '太湖县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340826000000, '宿松县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340827000000, '望江县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340828000000, '岳西县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340871000000, '安徽安庆经济开发区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340881000000, '桐城市', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340882000000, '潜山市', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (341000000000, '黄山市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341001000000, '市辖区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341002000000, '屯溪区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341003000000, '黄山区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341004000000, '徽州区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341021000000, '歙县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341022000000, '休宁县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341023000000, '黟县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341024000000, '祁门县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341100000000, '滁州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341101000000, '市辖区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341102000000, '琅琊区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341103000000, '南谯区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341122000000, '来安县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341124000000, '全椒县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341125000000, '定远县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341126000000, '凤阳县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341171000000, '苏滁现代产业园', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341172000000, '滁州经济技术开发区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341181000000, '天长市', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341182000000, '明光市', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341200000000, '阜阳市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341201000000, '市辖区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341202000000, '颍州区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341203000000, '颍东区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341204000000, '颍泉区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341221000000, '临泉县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341222000000, '太和县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341225000000, '阜南县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341226000000, '颍上县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341271000000, '阜阳合肥现代产业园区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341272000000, '阜阳经济技术开发区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341282000000, '界首市', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341300000000, '宿州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341301000000, '市辖区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341302000000, '埇桥区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341321000000, '砀山县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341322000000, '萧县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341323000000, '灵璧县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341324000000, '泗县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341371000000, '宿州马鞍山现代产业园区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341372000000, '宿州经济技术开发区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341500000000, '六安市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341501000000, '市辖区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341502000000, '金安区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341503000000, '裕安区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341504000000, '叶集区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341522000000, '霍邱县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341523000000, '舒城县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341524000000, '金寨县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341525000000, '霍山县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341600000000, '亳州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341601000000, '市辖区', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341602000000, '谯城区', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341621000000, '涡阳县', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341622000000, '蒙城县', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341623000000, '利辛县', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341700000000, '池州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341701000000, '市辖区', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341702000000, '贵池区', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341721000000, '东至县', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341722000000, '石台县', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341723000000, '青阳县', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341800000000, '宣城市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341801000000, '市辖区', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341802000000, '宣州区', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341821000000, '郎溪县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341822000000, '广德县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341823000000, '泾县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341824000000, '绩溪县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341825000000, '旌德县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341871000000, '宣城市经济开发区', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341881000000, '宁国市', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (350000000000, '福建省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (350100000000, '福州市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350101000000, '市辖区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350102000000, '鼓楼区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350103000000, '台江区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350104000000, '仓山区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350105000000, '马尾区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350111000000, '晋安区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350112000000, '长乐区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350121000000, '闽侯县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350122000000, '连江县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350123000000, '罗源县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350124000000, '闽清县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350125000000, '永泰县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350128000000, '平潭县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350181000000, '福清市', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350200000000, '厦门市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350201000000, '市辖区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350203000000, '思明区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350205000000, '海沧区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350206000000, '湖里区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350211000000, '集美区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350212000000, '同安区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350213000000, '翔安区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350300000000, '莆田市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350301000000, '市辖区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350302000000, '城厢区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350303000000, '涵江区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350304000000, '荔城区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350305000000, '秀屿区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350322000000, '仙游县', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350400000000, '三明市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350401000000, '市辖区', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350402000000, '梅列区', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350403000000, '三元区', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350421000000, '明溪县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350423000000, '清流县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350424000000, '宁化县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350425000000, '大田县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350426000000, '尤溪县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350427000000, '沙县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350428000000, '将乐县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350429000000, '泰宁县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350430000000, '建宁县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350481000000, '永安市', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350500000000, '泉州市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350501000000, '市辖区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350502000000, '鲤城区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350503000000, '丰泽区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350504000000, '洛江区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350505000000, '泉港区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350521000000, '惠安县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350524000000, '安溪县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350525000000, '永春县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350526000000, '德化县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350527000000, '金门县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350581000000, '石狮市', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350582000000, '晋江市', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350583000000, '南安市', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350600000000, '漳州市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350601000000, '市辖区', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350602000000, '芗城区', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350603000000, '龙文区', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350622000000, '云霄县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350623000000, '漳浦县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350624000000, '诏安县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350625000000, '长泰县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350626000000, '东山县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350627000000, '南靖县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350628000000, '平和县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350629000000, '华安县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350681000000, '龙海市', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350700000000, '南平市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350701000000, '市辖区', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350702000000, '延平区', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350703000000, '建阳区', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350721000000, '顺昌县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350722000000, '浦城县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350723000000, '光泽县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350724000000, '松溪县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350725000000, '政和县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350781000000, '邵武市', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350782000000, '武夷山市', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350783000000, '建瓯市', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350800000000, '龙岩市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350801000000, '市辖区', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350802000000, '新罗区', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350803000000, '永定区', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350821000000, '长汀县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350823000000, '上杭县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350824000000, '武平县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350825000000, '连城县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350881000000, '漳平市', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350900000000, '宁德市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350901000000, '市辖区', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350902000000, '蕉城区', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350921000000, '霞浦县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350922000000, '古田县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350923000000, '屏南县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350924000000, '寿宁县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350925000000, '周宁县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350926000000, '柘荣县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350981000000, '福安市', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350982000000, '福鼎市', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (360000000000, '江西省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (360100000000, '南昌市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360101000000, '市辖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360102000000, '东湖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360103000000, '西湖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360104000000, '青云谱区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360105000000, '湾里区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360111000000, '青山湖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360112000000, '新建区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360121000000, '南昌县', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360123000000, '安义县', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360124000000, '进贤县', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360200000000, '景德镇市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360201000000, '市辖区', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360202000000, '昌江区', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360203000000, '珠山区', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360222000000, '浮梁县', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360281000000, '乐平市', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360300000000, '萍乡市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360301000000, '市辖区', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360302000000, '安源区', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360313000000, '湘东区', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360321000000, '莲花县', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360322000000, '上栗县', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360323000000, '芦溪县', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360400000000, '九江市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360401000000, '市辖区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360402000000, '濂溪区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360403000000, '浔阳区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360404000000, '柴桑区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360423000000, '武宁县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360424000000, '修水县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360425000000, '永修县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360426000000, '德安县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360428000000, '都昌县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360429000000, '湖口县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360430000000, '彭泽县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360481000000, '瑞昌市', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360482000000, '共青城市', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360483000000, '庐山市', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360500000000, '新余市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360501000000, '市辖区', 3, 360500000000); +INSERT INTO `zz_area_code` VALUES (360502000000, '渝水区', 3, 360500000000); +INSERT INTO `zz_area_code` VALUES (360521000000, '分宜县', 3, 360500000000); +INSERT INTO `zz_area_code` VALUES (360600000000, '鹰潭市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360601000000, '市辖区', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360602000000, '月湖区', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360603000000, '余江区', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360681000000, '贵溪市', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360700000000, '赣州市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360701000000, '市辖区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360702000000, '章贡区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360703000000, '南康区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360704000000, '赣县区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360722000000, '信丰县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360723000000, '大余县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360724000000, '上犹县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360725000000, '崇义县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360726000000, '安远县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360727000000, '龙南县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360728000000, '定南县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360729000000, '全南县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360730000000, '宁都县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360731000000, '于都县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360732000000, '兴国县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360733000000, '会昌县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360734000000, '寻乌县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360735000000, '石城县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360781000000, '瑞金市', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360800000000, '吉安市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360801000000, '市辖区', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360802000000, '吉州区', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360803000000, '青原区', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360821000000, '吉安县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360822000000, '吉水县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360823000000, '峡江县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360824000000, '新干县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360825000000, '永丰县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360826000000, '泰和县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360827000000, '遂川县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360828000000, '万安县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360829000000, '安福县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360830000000, '永新县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360881000000, '井冈山市', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360900000000, '宜春市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360901000000, '市辖区', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360902000000, '袁州区', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360921000000, '奉新县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360922000000, '万载县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360923000000, '上高县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360924000000, '宜丰县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360925000000, '靖安县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360926000000, '铜鼓县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360981000000, '丰城市', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360982000000, '樟树市', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360983000000, '高安市', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (361000000000, '抚州市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (361001000000, '市辖区', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361002000000, '临川区', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361003000000, '东乡区', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361021000000, '南城县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361022000000, '黎川县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361023000000, '南丰县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361024000000, '崇仁县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361025000000, '乐安县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361026000000, '宜黄县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361027000000, '金溪县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361028000000, '资溪县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361030000000, '广昌县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361100000000, '上饶市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (361101000000, '市辖区', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361102000000, '信州区', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361103000000, '广丰区', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361121000000, '上饶县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361123000000, '玉山县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361124000000, '铅山县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361125000000, '横峰县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361126000000, '弋阳县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361127000000, '余干县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361128000000, '鄱阳县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361129000000, '万年县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361130000000, '婺源县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361181000000, '德兴市', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (370000000000, '山东省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (370100000000, '济南市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370101000000, '市辖区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370102000000, '历下区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370103000000, '市中区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370104000000, '槐荫区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370105000000, '天桥区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370112000000, '历城区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370113000000, '长清区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370114000000, '章丘区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370115000000, '济阳区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370124000000, '平阴县', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370126000000, '商河县', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370171000000, '济南高新技术产业开发区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370200000000, '青岛市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370201000000, '市辖区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370202000000, '市南区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370203000000, '市北区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370211000000, '黄岛区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370212000000, '崂山区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370213000000, '李沧区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370214000000, '城阳区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370215000000, '即墨区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370271000000, '青岛高新技术产业开发区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370281000000, '胶州市', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370283000000, '平度市', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370285000000, '莱西市', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370300000000, '淄博市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370301000000, '市辖区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370302000000, '淄川区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370303000000, '张店区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370304000000, '博山区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370305000000, '临淄区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370306000000, '周村区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370321000000, '桓台县', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370322000000, '高青县', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370323000000, '沂源县', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370400000000, '枣庄市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370401000000, '市辖区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370402000000, '市中区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370403000000, '薛城区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370404000000, '峄城区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370405000000, '台儿庄区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370406000000, '山亭区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370481000000, '滕州市', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370500000000, '东营市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370501000000, '市辖区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370502000000, '东营区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370503000000, '河口区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370505000000, '垦利区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370522000000, '利津县', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370523000000, '广饶县', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370571000000, '东营经济技术开发区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370572000000, '东营港经济开发区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370600000000, '烟台市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370601000000, '市辖区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370602000000, '芝罘区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370611000000, '福山区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370612000000, '牟平区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370613000000, '莱山区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370634000000, '长岛县', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370671000000, '烟台高新技术产业开发区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370672000000, '烟台经济技术开发区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370681000000, '龙口市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370682000000, '莱阳市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370683000000, '莱州市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370684000000, '蓬莱市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370685000000, '招远市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370686000000, '栖霞市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370687000000, '海阳市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370700000000, '潍坊市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370701000000, '市辖区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370702000000, '潍城区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370703000000, '寒亭区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370704000000, '坊子区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370705000000, '奎文区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370724000000, '临朐县', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370725000000, '昌乐县', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370772000000, '潍坊滨海经济技术开发区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370781000000, '青州市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370782000000, '诸城市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370783000000, '寿光市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370784000000, '安丘市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370785000000, '高密市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370786000000, '昌邑市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370800000000, '济宁市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370801000000, '市辖区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370811000000, '任城区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370812000000, '兖州区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370826000000, '微山县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370827000000, '鱼台县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370828000000, '金乡县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370829000000, '嘉祥县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370830000000, '汶上县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370831000000, '泗水县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370832000000, '梁山县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370871000000, '济宁高新技术产业开发区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370881000000, '曲阜市', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370883000000, '邹城市', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370900000000, '泰安市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370901000000, '市辖区', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370902000000, '泰山区', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370911000000, '岱岳区', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370921000000, '宁阳县', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370923000000, '东平县', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370982000000, '新泰市', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370983000000, '肥城市', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (371000000000, '威海市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371001000000, '市辖区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371002000000, '环翠区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371003000000, '文登区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371071000000, '威海火炬高技术产业开发区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371072000000, '威海经济技术开发区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371073000000, '威海临港经济技术开发区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371082000000, '荣成市', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371083000000, '乳山市', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371100000000, '日照市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371101000000, '市辖区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371102000000, '东港区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371103000000, '岚山区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371121000000, '五莲县', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371122000000, '莒县', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371171000000, '日照经济技术开发区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371200000000, '莱芜市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371201000000, '市辖区', 3, 371200000000); +INSERT INTO `zz_area_code` VALUES (371202000000, '莱城区', 3, 371200000000); +INSERT INTO `zz_area_code` VALUES (371203000000, '钢城区', 3, 371200000000); +INSERT INTO `zz_area_code` VALUES (371300000000, '临沂市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371301000000, '市辖区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371302000000, '兰山区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371311000000, '罗庄区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371312000000, '河东区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371321000000, '沂南县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371322000000, '郯城县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371323000000, '沂水县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371324000000, '兰陵县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371325000000, '费县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371326000000, '平邑县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371327000000, '莒南县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371328000000, '蒙阴县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371329000000, '临沭县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371371000000, '临沂高新技术产业开发区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371372000000, '临沂经济技术开发区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371373000000, '临沂临港经济开发区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371400000000, '德州市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371401000000, '市辖区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371402000000, '德城区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371403000000, '陵城区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371422000000, '宁津县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371423000000, '庆云县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371424000000, '临邑县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371425000000, '齐河县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371426000000, '平原县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371427000000, '夏津县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371428000000, '武城县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371471000000, '德州经济技术开发区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371472000000, '德州运河经济开发区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371481000000, '乐陵市', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371482000000, '禹城市', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371500000000, '聊城市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371501000000, '市辖区', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371502000000, '东昌府区', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371521000000, '阳谷县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371522000000, '莘县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371523000000, '茌平县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371524000000, '东阿县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371525000000, '冠县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371526000000, '高唐县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371581000000, '临清市', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371600000000, '滨州市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371601000000, '市辖区', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371602000000, '滨城区', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371603000000, '沾化区', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371621000000, '惠民县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371622000000, '阳信县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371623000000, '无棣县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371625000000, '博兴县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371681000000, '邹平市', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371700000000, '菏泽市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371701000000, '市辖区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371702000000, '牡丹区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371703000000, '定陶区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371721000000, '曹县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371722000000, '单县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371723000000, '成武县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371724000000, '巨野县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371725000000, '郓城县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371726000000, '鄄城县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371728000000, '东明县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371771000000, '菏泽经济技术开发区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371772000000, '菏泽高新技术开发区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (410000000000, '河南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (410100000000, '郑州市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410101000000, '市辖区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410102000000, '中原区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410103000000, '二七区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410104000000, '管城回族区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410105000000, '金水区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410106000000, '上街区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410108000000, '惠济区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410122000000, '中牟县', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410171000000, '郑州经济技术开发区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410172000000, '郑州高新技术产业开发区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410173000000, '郑州航空港经济综合实验区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410181000000, '巩义市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410182000000, '荥阳市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410183000000, '新密市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410184000000, '新郑市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410185000000, '登封市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410200000000, '开封市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410201000000, '市辖区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410202000000, '龙亭区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410203000000, '顺河回族区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410204000000, '鼓楼区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410205000000, '禹王台区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410212000000, '祥符区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410221000000, '杞县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410222000000, '通许县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410223000000, '尉氏县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410225000000, '兰考县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410300000000, '洛阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410301000000, '市辖区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410302000000, '老城区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410303000000, '西工区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410304000000, '瀍河回族区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410305000000, '涧西区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410306000000, '吉利区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410311000000, '洛龙区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410322000000, '孟津县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410323000000, '新安县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410324000000, '栾川县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410325000000, '嵩县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410326000000, '汝阳县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410327000000, '宜阳县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410328000000, '洛宁县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410329000000, '伊川县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410371000000, '洛阳高新技术产业开发区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410381000000, '偃师市', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410400000000, '平顶山市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410401000000, '市辖区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410402000000, '新华区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410403000000, '卫东区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410404000000, '石龙区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410411000000, '湛河区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410421000000, '宝丰县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410422000000, '叶县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410423000000, '鲁山县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410425000000, '郏县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410471000000, '平顶山高新技术产业开发区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410472000000, '平顶山市新城区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410481000000, '舞钢市', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410482000000, '汝州市', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410500000000, '安阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410501000000, '市辖区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410502000000, '文峰区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410503000000, '北关区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410505000000, '殷都区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410506000000, '龙安区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410522000000, '安阳县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410523000000, '汤阴县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410526000000, '滑县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410527000000, '内黄县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410571000000, '安阳高新技术产业开发区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410581000000, '林州市', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410600000000, '鹤壁市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410601000000, '市辖区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410602000000, '鹤山区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410603000000, '山城区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410611000000, '淇滨区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410621000000, '浚县', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410622000000, '淇县', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410671000000, '鹤壁经济技术开发区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410700000000, '新乡市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410701000000, '市辖区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410702000000, '红旗区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410703000000, '卫滨区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410704000000, '凤泉区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410711000000, '牧野区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410721000000, '新乡县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410724000000, '获嘉县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410725000000, '原阳县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410726000000, '延津县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410727000000, '封丘县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410728000000, '长垣县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410771000000, '新乡高新技术产业开发区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410772000000, '新乡经济技术开发区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410773000000, '新乡市平原城乡一体化示范区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410781000000, '卫辉市', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410782000000, '辉县市', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410800000000, '焦作市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410801000000, '市辖区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410802000000, '解放区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410803000000, '中站区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410804000000, '马村区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410811000000, '山阳区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410821000000, '修武县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410822000000, '博爱县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410823000000, '武陟县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410825000000, '温县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410871000000, '焦作城乡一体化示范区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410882000000, '沁阳市', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410883000000, '孟州市', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410900000000, '濮阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410901000000, '市辖区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410902000000, '华龙区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410922000000, '清丰县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410923000000, '南乐县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410926000000, '范县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410927000000, '台前县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410928000000, '濮阳县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410971000000, '河南濮阳工业园区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410972000000, '濮阳经济技术开发区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (411000000000, '许昌市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411001000000, '市辖区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411002000000, '魏都区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411003000000, '建安区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411024000000, '鄢陵县', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411025000000, '襄城县', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411071000000, '许昌经济技术开发区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411081000000, '禹州市', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411082000000, '长葛市', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411100000000, '漯河市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411101000000, '市辖区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411102000000, '源汇区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411103000000, '郾城区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411104000000, '召陵区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411121000000, '舞阳县', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411122000000, '临颍县', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411171000000, '漯河经济技术开发区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411200000000, '三门峡市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411201000000, '市辖区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411202000000, '湖滨区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411203000000, '陕州区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411221000000, '渑池县', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411224000000, '卢氏县', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411271000000, '河南三门峡经济开发区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411281000000, '义马市', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411282000000, '灵宝市', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411300000000, '南阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411301000000, '市辖区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411302000000, '宛城区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411303000000, '卧龙区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411321000000, '南召县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411322000000, '方城县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411323000000, '西峡县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411324000000, '镇平县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411325000000, '内乡县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411326000000, '淅川县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411327000000, '社旗县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411328000000, '唐河县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411329000000, '新野县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411330000000, '桐柏县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411371000000, '南阳高新技术产业开发区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411372000000, '南阳市城乡一体化示范区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411381000000, '邓州市', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411400000000, '商丘市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411401000000, '市辖区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411402000000, '梁园区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411403000000, '睢阳区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411421000000, '民权县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411422000000, '睢县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411423000000, '宁陵县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411424000000, '柘城县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411425000000, '虞城县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411426000000, '夏邑县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411471000000, '豫东综合物流产业聚集区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411472000000, '河南商丘经济开发区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411481000000, '永城市', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411500000000, '信阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411501000000, '市辖区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411502000000, '浉河区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411503000000, '平桥区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411521000000, '罗山县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411522000000, '光山县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411523000000, '新县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411524000000, '商城县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411525000000, '固始县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411526000000, '潢川县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411527000000, '淮滨县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411528000000, '息县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411571000000, '信阳高新技术产业开发区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411600000000, '周口市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411601000000, '市辖区', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411602000000, '川汇区', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411621000000, '扶沟县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411622000000, '西华县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411623000000, '商水县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411624000000, '沈丘县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411625000000, '郸城县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411626000000, '淮阳县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411627000000, '太康县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411628000000, '鹿邑县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411671000000, '河南周口经济开发区', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411681000000, '项城市', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411700000000, '驻马店市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411701000000, '市辖区', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411702000000, '驿城区', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411721000000, '西平县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411722000000, '上蔡县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411723000000, '平舆县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411724000000, '正阳县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411725000000, '确山县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411726000000, '泌阳县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411727000000, '汝南县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411728000000, '遂平县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411729000000, '新蔡县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411771000000, '河南驻马店经济开发区', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (419000000000, '省直辖县级行政区划', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (419001000000, '济源市', 3, 419000000000); +INSERT INTO `zz_area_code` VALUES (420000000000, '湖北省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (420100000000, '武汉市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420101000000, '市辖区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420102000000, '江岸区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420103000000, '江汉区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420104000000, '硚口区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420105000000, '汉阳区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420106000000, '武昌区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420107000000, '青山区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420111000000, '洪山区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420112000000, '东西湖区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420113000000, '汉南区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420114000000, '蔡甸区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420115000000, '江夏区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420116000000, '黄陂区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420117000000, '新洲区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420200000000, '黄石市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420201000000, '市辖区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420202000000, '黄石港区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420203000000, '西塞山区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420204000000, '下陆区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420205000000, '铁山区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420222000000, '阳新县', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420281000000, '大冶市', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420300000000, '十堰市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420301000000, '市辖区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420302000000, '茅箭区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420303000000, '张湾区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420304000000, '郧阳区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420322000000, '郧西县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420323000000, '竹山县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420324000000, '竹溪县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420325000000, '房县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420381000000, '丹江口市', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420500000000, '宜昌市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420501000000, '市辖区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420502000000, '西陵区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420503000000, '伍家岗区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420504000000, '点军区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420505000000, '猇亭区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420506000000, '夷陵区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420525000000, '远安县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420526000000, '兴山县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420527000000, '秭归县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420528000000, '长阳土家族自治县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420529000000, '五峰土家族自治县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420581000000, '宜都市', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420582000000, '当阳市', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420583000000, '枝江市', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420600000000, '襄阳市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420601000000, '市辖区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420602000000, '襄城区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420606000000, '樊城区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420607000000, '襄州区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420624000000, '南漳县', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420625000000, '谷城县', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420626000000, '保康县', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420682000000, '老河口市', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420683000000, '枣阳市', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420684000000, '宜城市', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420700000000, '鄂州市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420701000000, '市辖区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420702000000, '梁子湖区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420703000000, '华容区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420704000000, '鄂城区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420800000000, '荆门市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420801000000, '市辖区', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420802000000, '东宝区', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420804000000, '掇刀区', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420822000000, '沙洋县', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420881000000, '钟祥市', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420882000000, '京山市', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420900000000, '孝感市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420901000000, '市辖区', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420902000000, '孝南区', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420921000000, '孝昌县', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420922000000, '大悟县', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420923000000, '云梦县', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420981000000, '应城市', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420982000000, '安陆市', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420984000000, '汉川市', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (421000000000, '荆州市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421001000000, '市辖区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421002000000, '沙市区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421003000000, '荆州区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421022000000, '公安县', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421023000000, '监利县', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421024000000, '江陵县', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421071000000, '荆州经济技术开发区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421081000000, '石首市', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421083000000, '洪湖市', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421087000000, '松滋市', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421100000000, '黄冈市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421101000000, '市辖区', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421102000000, '黄州区', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421121000000, '团风县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421122000000, '红安县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421123000000, '罗田县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421124000000, '英山县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421125000000, '浠水县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421126000000, '蕲春县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421127000000, '黄梅县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421171000000, '龙感湖管理区', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421181000000, '麻城市', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421182000000, '武穴市', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421200000000, '咸宁市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421201000000, '市辖区', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421202000000, '咸安区', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421221000000, '嘉鱼县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421222000000, '通城县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421223000000, '崇阳县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421224000000, '通山县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421281000000, '赤壁市', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421300000000, '随州市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421301000000, '市辖区', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (421303000000, '曾都区', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (421321000000, '随县', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (421381000000, '广水市', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (422800000000, '恩施土家族苗族自治州', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (422801000000, '恩施市', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422802000000, '利川市', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422822000000, '建始县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422823000000, '巴东县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422825000000, '宣恩县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422826000000, '咸丰县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422827000000, '来凤县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422828000000, '鹤峰县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (429000000000, '省直辖县级行政区划', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (429004000000, '仙桃市', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (429005000000, '潜江市', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (429006000000, '天门市', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (429021000000, '神农架林区', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (430000000000, '湖南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (430100000000, '长沙市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430101000000, '市辖区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430102000000, '芙蓉区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430103000000, '天心区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430104000000, '岳麓区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430105000000, '开福区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430111000000, '雨花区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430112000000, '望城区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430121000000, '长沙县', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430181000000, '浏阳市', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430182000000, '宁乡市', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430200000000, '株洲市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430201000000, '市辖区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430202000000, '荷塘区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430203000000, '芦淞区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430204000000, '石峰区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430211000000, '天元区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430212000000, '渌口区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430223000000, '攸县', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430224000000, '茶陵县', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430225000000, '炎陵县', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430271000000, '云龙示范区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430281000000, '醴陵市', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430300000000, '湘潭市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430301000000, '市辖区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430302000000, '雨湖区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430304000000, '岳塘区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430321000000, '湘潭县', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430371000000, '湖南湘潭高新技术产业园区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430372000000, '湘潭昭山示范区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430373000000, '湘潭九华示范区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430381000000, '湘乡市', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430382000000, '韶山市', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430400000000, '衡阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430401000000, '市辖区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430405000000, '珠晖区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430406000000, '雁峰区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430407000000, '石鼓区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430408000000, '蒸湘区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430412000000, '南岳区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430421000000, '衡阳县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430422000000, '衡南县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430423000000, '衡山县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430424000000, '衡东县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430426000000, '祁东县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430471000000, '衡阳综合保税区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430472000000, '湖南衡阳高新技术产业园区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430473000000, '湖南衡阳松木经济开发区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430481000000, '耒阳市', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430482000000, '常宁市', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430500000000, '邵阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430501000000, '市辖区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430502000000, '双清区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430503000000, '大祥区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430511000000, '北塔区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430521000000, '邵东县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430522000000, '新邵县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430523000000, '邵阳县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430524000000, '隆回县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430525000000, '洞口县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430527000000, '绥宁县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430528000000, '新宁县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430529000000, '城步苗族自治县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430581000000, '武冈市', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430600000000, '岳阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430601000000, '市辖区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430602000000, '岳阳楼区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430603000000, '云溪区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430611000000, '君山区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430621000000, '岳阳县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430623000000, '华容县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430624000000, '湘阴县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430626000000, '平江县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430671000000, '岳阳市屈原管理区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430681000000, '汨罗市', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430682000000, '临湘市', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430700000000, '常德市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430701000000, '市辖区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430702000000, '武陵区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430703000000, '鼎城区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430721000000, '安乡县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430722000000, '汉寿县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430723000000, '澧县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430724000000, '临澧县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430725000000, '桃源县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430726000000, '石门县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430771000000, '常德市西洞庭管理区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430781000000, '津市市', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430800000000, '张家界市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430801000000, '市辖区', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430802000000, '永定区', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430811000000, '武陵源区', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430821000000, '慈利县', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430822000000, '桑植县', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430900000000, '益阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430901000000, '市辖区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430902000000, '资阳区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430903000000, '赫山区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430921000000, '南县', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430922000000, '桃江县', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430923000000, '安化县', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430971000000, '益阳市大通湖管理区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430972000000, '湖南益阳高新技术产业园区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430981000000, '沅江市', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (431000000000, '郴州市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431001000000, '市辖区', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431002000000, '北湖区', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431003000000, '苏仙区', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431021000000, '桂阳县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431022000000, '宜章县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431023000000, '永兴县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431024000000, '嘉禾县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431025000000, '临武县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431026000000, '汝城县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431027000000, '桂东县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431028000000, '安仁县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431081000000, '资兴市', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431100000000, '永州市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431101000000, '市辖区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431102000000, '零陵区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431103000000, '冷水滩区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431121000000, '祁阳县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431122000000, '东安县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431123000000, '双牌县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431124000000, '道县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431125000000, '江永县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431126000000, '宁远县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431127000000, '蓝山县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431128000000, '新田县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431129000000, '江华瑶族自治县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431171000000, '永州经济技术开发区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431172000000, '永州市金洞管理区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431173000000, '永州市回龙圩管理区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431200000000, '怀化市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431201000000, '市辖区', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431202000000, '鹤城区', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431221000000, '中方县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431222000000, '沅陵县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431223000000, '辰溪县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431224000000, '溆浦县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431225000000, '会同县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431226000000, '麻阳苗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431227000000, '新晃侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431228000000, '芷江侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431229000000, '靖州苗族侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431230000000, '通道侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431271000000, '怀化市洪江管理区', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431281000000, '洪江市', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431300000000, '娄底市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431301000000, '市辖区', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431302000000, '娄星区', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431321000000, '双峰县', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431322000000, '新化县', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431381000000, '冷水江市', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431382000000, '涟源市', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (433100000000, '湘西土家族苗族自治州', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (433101000000, '吉首市', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433122000000, '泸溪县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433123000000, '凤凰县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433124000000, '花垣县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433125000000, '保靖县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433126000000, '古丈县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433127000000, '永顺县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433130000000, '龙山县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433172000000, '湖南吉首经济开发区', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433173000000, '湖南永顺经济开发区', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (440000000000, '广东省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (440100000000, '广州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440101000000, '市辖区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440103000000, '荔湾区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440104000000, '越秀区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440105000000, '海珠区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440106000000, '天河区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440111000000, '白云区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440112000000, '黄埔区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440113000000, '番禺区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440114000000, '花都区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440115000000, '南沙区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440117000000, '从化区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440118000000, '增城区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440200000000, '韶关市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440201000000, '市辖区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440203000000, '武江区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440204000000, '浈江区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440205000000, '曲江区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440222000000, '始兴县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440224000000, '仁化县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440229000000, '翁源县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440232000000, '乳源瑶族自治县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440233000000, '新丰县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440281000000, '乐昌市', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440282000000, '南雄市', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440300000000, '深圳市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440301000000, '市辖区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440303000000, '罗湖区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440304000000, '福田区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440305000000, '南山区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440306000000, '宝安区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440307000000, '龙岗区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440308000000, '盐田区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440309000000, '龙华区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440310000000, '坪山区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440311000000, '光明区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440400000000, '珠海市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440401000000, '市辖区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440402000000, '香洲区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440403000000, '斗门区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440404000000, '金湾区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440500000000, '汕头市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440501000000, '市辖区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440507000000, '龙湖区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440511000000, '金平区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440512000000, '濠江区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440513000000, '潮阳区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440514000000, '潮南区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440515000000, '澄海区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440523000000, '南澳县', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440600000000, '佛山市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440601000000, '市辖区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440604000000, '禅城区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440605000000, '南海区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440606000000, '顺德区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440607000000, '三水区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440608000000, '高明区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440700000000, '江门市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440701000000, '市辖区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440703000000, '蓬江区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440704000000, '江海区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440705000000, '新会区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440781000000, '台山市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440783000000, '开平市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440784000000, '鹤山市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440785000000, '恩平市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440800000000, '湛江市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440801000000, '市辖区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440802000000, '赤坎区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440803000000, '霞山区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440804000000, '坡头区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440811000000, '麻章区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440823000000, '遂溪县', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440825000000, '徐闻县', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440881000000, '廉江市', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440882000000, '雷州市', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440883000000, '吴川市', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440900000000, '茂名市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440901000000, '市辖区', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440902000000, '茂南区', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440904000000, '电白区', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440981000000, '高州市', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440982000000, '化州市', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440983000000, '信宜市', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (441200000000, '肇庆市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441201000000, '市辖区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441202000000, '端州区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441203000000, '鼎湖区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441204000000, '高要区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441223000000, '广宁县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441224000000, '怀集县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441225000000, '封开县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441226000000, '德庆县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441284000000, '四会市', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441300000000, '惠州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441301000000, '市辖区', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441302000000, '惠城区', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441303000000, '惠阳区', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441322000000, '博罗县', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441323000000, '惠东县', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441324000000, '龙门县', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441400000000, '梅州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441401000000, '市辖区', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441402000000, '梅江区', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441403000000, '梅县区', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441422000000, '大埔县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441423000000, '丰顺县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441424000000, '五华县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441426000000, '平远县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441427000000, '蕉岭县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441481000000, '兴宁市', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441500000000, '汕尾市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441501000000, '市辖区', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441502000000, '城区', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441521000000, '海丰县', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441523000000, '陆河县', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441581000000, '陆丰市', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441600000000, '河源市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441601000000, '市辖区', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441602000000, '源城区', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441621000000, '紫金县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441622000000, '龙川县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441623000000, '连平县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441624000000, '和平县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441625000000, '东源县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441700000000, '阳江市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441701000000, '市辖区', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441702000000, '江城区', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441704000000, '阳东区', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441721000000, '阳西县', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441781000000, '阳春市', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441800000000, '清远市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441801000000, '市辖区', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441802000000, '清城区', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441803000000, '清新区', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441821000000, '佛冈县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441823000000, '阳山县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441825000000, '连山壮族瑶族自治县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441826000000, '连南瑶族自治县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441881000000, '英德市', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441882000000, '连州市', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441900000000, '东莞市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (442000000000, '中山市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445100000000, '潮州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445101000000, '市辖区', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445102000000, '湘桥区', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445103000000, '潮安区', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445122000000, '饶平县', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445200000000, '揭阳市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445201000000, '市辖区', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445202000000, '榕城区', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445203000000, '揭东区', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445222000000, '揭西县', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445224000000, '惠来县', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445281000000, '普宁市', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445300000000, '云浮市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445301000000, '市辖区', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445302000000, '云城区', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445303000000, '云安区', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445321000000, '新兴县', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445322000000, '郁南县', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445381000000, '罗定市', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (450000000000, '广西壮族自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (450100000000, '南宁市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450101000000, '市辖区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450102000000, '兴宁区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450103000000, '青秀区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450105000000, '江南区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450107000000, '西乡塘区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450108000000, '良庆区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450109000000, '邕宁区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450110000000, '武鸣区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450123000000, '隆安县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450124000000, '马山县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450125000000, '上林县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450126000000, '宾阳县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450127000000, '横县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450200000000, '柳州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450201000000, '市辖区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450202000000, '城中区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450203000000, '鱼峰区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450204000000, '柳南区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450205000000, '柳北区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450206000000, '柳江区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450222000000, '柳城县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450223000000, '鹿寨县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450224000000, '融安县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450225000000, '融水苗族自治县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450226000000, '三江侗族自治县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450300000000, '桂林市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450301000000, '市辖区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450302000000, '秀峰区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450303000000, '叠彩区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450304000000, '象山区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450305000000, '七星区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450311000000, '雁山区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450312000000, '临桂区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450321000000, '阳朔县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450323000000, '灵川县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450324000000, '全州县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450325000000, '兴安县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450326000000, '永福县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450327000000, '灌阳县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450328000000, '龙胜各族自治县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450329000000, '资源县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450330000000, '平乐县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450332000000, '恭城瑶族自治县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450381000000, '荔浦市', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450400000000, '梧州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450401000000, '市辖区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450403000000, '万秀区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450405000000, '长洲区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450406000000, '龙圩区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450421000000, '苍梧县', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450422000000, '藤县', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450423000000, '蒙山县', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450481000000, '岑溪市', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450500000000, '北海市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450501000000, '市辖区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450502000000, '海城区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450503000000, '银海区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450512000000, '铁山港区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450521000000, '合浦县', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450600000000, '防城港市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450601000000, '市辖区', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450602000000, '港口区', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450603000000, '防城区', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450621000000, '上思县', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450681000000, '东兴市', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450700000000, '钦州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450701000000, '市辖区', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450702000000, '钦南区', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450703000000, '钦北区', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450721000000, '灵山县', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450722000000, '浦北县', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450800000000, '贵港市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450801000000, '市辖区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450802000000, '港北区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450803000000, '港南区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450804000000, '覃塘区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450821000000, '平南县', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450881000000, '桂平市', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450900000000, '玉林市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450901000000, '市辖区', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450902000000, '玉州区', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450903000000, '福绵区', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450921000000, '容县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450922000000, '陆川县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450923000000, '博白县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450924000000, '兴业县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450981000000, '北流市', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (451000000000, '百色市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451001000000, '市辖区', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451002000000, '右江区', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451021000000, '田阳县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451022000000, '田东县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451023000000, '平果县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451024000000, '德保县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451026000000, '那坡县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451027000000, '凌云县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451028000000, '乐业县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451029000000, '田林县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451030000000, '西林县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451031000000, '隆林各族自治县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451081000000, '靖西市', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451100000000, '贺州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451101000000, '市辖区', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451102000000, '八步区', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451103000000, '平桂区', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451121000000, '昭平县', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451122000000, '钟山县', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451123000000, '富川瑶族自治县', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451200000000, '河池市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451201000000, '市辖区', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451202000000, '金城江区', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451203000000, '宜州区', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451221000000, '南丹县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451222000000, '天峨县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451223000000, '凤山县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451224000000, '东兰县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451225000000, '罗城仫佬族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451226000000, '环江毛南族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451227000000, '巴马瑶族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451228000000, '都安瑶族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451229000000, '大化瑶族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451300000000, '来宾市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451301000000, '市辖区', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451302000000, '兴宾区', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451321000000, '忻城县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451322000000, '象州县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451323000000, '武宣县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451324000000, '金秀瑶族自治县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451381000000, '合山市', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451400000000, '崇左市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451401000000, '市辖区', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451402000000, '江州区', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451421000000, '扶绥县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451422000000, '宁明县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451423000000, '龙州县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451424000000, '大新县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451425000000, '天等县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451481000000, '凭祥市', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (460000000000, '海南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (460100000000, '海口市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (460101000000, '市辖区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460105000000, '秀英区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460106000000, '龙华区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460107000000, '琼山区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460108000000, '美兰区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460200000000, '三亚市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (460201000000, '市辖区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460202000000, '海棠区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460203000000, '吉阳区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460204000000, '天涯区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460205000000, '崖州区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460300000000, '三沙市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (460321000000, '西沙群岛', 3, 460300000000); +INSERT INTO `zz_area_code` VALUES (460322000000, '南沙群岛', 3, 460300000000); +INSERT INTO `zz_area_code` VALUES (460323000000, '中沙群岛的岛礁及其海域', 3, 460300000000); +INSERT INTO `zz_area_code` VALUES (460400000000, '儋州市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (469000000000, '省直辖县级行政区划', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (469001000000, '五指山市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469002000000, '琼海市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469005000000, '文昌市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469006000000, '万宁市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469007000000, '东方市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469021000000, '定安县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469022000000, '屯昌县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469023000000, '澄迈县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469024000000, '临高县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469025000000, '白沙黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469026000000, '昌江黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469027000000, '乐东黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469028000000, '陵水黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469029000000, '保亭黎族苗族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469030000000, '琼中黎族苗族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (500000000000, '重庆市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (500100000000, '市辖区', 2, 500000000000); +INSERT INTO `zz_area_code` VALUES (500101000000, '万州区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500102000000, '涪陵区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500103000000, '渝中区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500104000000, '大渡口区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500105000000, '江北区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500106000000, '沙坪坝区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500107000000, '九龙坡区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500108000000, '南岸区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500109000000, '北碚区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500110000000, '綦江区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500111000000, '大足区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500112000000, '渝北区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500113000000, '巴南区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500114000000, '黔江区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500115000000, '长寿区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500116000000, '江津区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500117000000, '合川区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500118000000, '永川区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500119000000, '南川区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500120000000, '璧山区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500151000000, '铜梁区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500152000000, '潼南区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500153000000, '荣昌区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500154000000, '开州区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500155000000, '梁平区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500156000000, '武隆区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500200000000, '县', 2, 500000000000); +INSERT INTO `zz_area_code` VALUES (500229000000, '城口县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500230000000, '丰都县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500231000000, '垫江县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500233000000, '忠县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500235000000, '云阳县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500236000000, '奉节县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500237000000, '巫山县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500238000000, '巫溪县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500240000000, '石柱土家族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500241000000, '秀山土家族苗族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500242000000, '酉阳土家族苗族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500243000000, '彭水苗族土家族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (510000000000, '四川省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (510100000000, '成都市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510101000000, '市辖区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510104000000, '锦江区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510105000000, '青羊区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510106000000, '金牛区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510107000000, '武侯区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510108000000, '成华区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510112000000, '龙泉驿区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510113000000, '青白江区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510114000000, '新都区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510115000000, '温江区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510116000000, '双流区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510117000000, '郫都区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510121000000, '金堂县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510129000000, '大邑县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510131000000, '蒲江县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510132000000, '新津县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510181000000, '都江堰市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510182000000, '彭州市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510183000000, '邛崃市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510184000000, '崇州市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510185000000, '简阳市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510300000000, '自贡市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510301000000, '市辖区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510302000000, '自流井区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510303000000, '贡井区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510304000000, '大安区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510311000000, '沿滩区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510321000000, '荣县', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510322000000, '富顺县', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510400000000, '攀枝花市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510401000000, '市辖区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510402000000, '东区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510403000000, '西区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510411000000, '仁和区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510421000000, '米易县', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510422000000, '盐边县', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510500000000, '泸州市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510501000000, '市辖区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510502000000, '江阳区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510503000000, '纳溪区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510504000000, '龙马潭区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510521000000, '泸县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510522000000, '合江县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510524000000, '叙永县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510525000000, '古蔺县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510600000000, '德阳市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510601000000, '市辖区', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510603000000, '旌阳区', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510604000000, '罗江区', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510623000000, '中江县', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510681000000, '广汉市', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510682000000, '什邡市', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510683000000, '绵竹市', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510700000000, '绵阳市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510701000000, '市辖区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510703000000, '涪城区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510704000000, '游仙区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510705000000, '安州区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510722000000, '三台县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510723000000, '盐亭县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510725000000, '梓潼县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510726000000, '北川羌族自治县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510727000000, '平武县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510781000000, '江油市', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510800000000, '广元市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510801000000, '市辖区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510802000000, '利州区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510811000000, '昭化区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510812000000, '朝天区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510821000000, '旺苍县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510822000000, '青川县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510823000000, '剑阁县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510824000000, '苍溪县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510900000000, '遂宁市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510901000000, '市辖区', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510903000000, '船山区', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510904000000, '安居区', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510921000000, '蓬溪县', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510922000000, '射洪县', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510923000000, '大英县', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (511000000000, '内江市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511001000000, '市辖区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511002000000, '市中区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511011000000, '东兴区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511024000000, '威远县', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511025000000, '资中县', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511071000000, '内江经济开发区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511083000000, '隆昌市', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511100000000, '乐山市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511101000000, '市辖区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511102000000, '市中区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511111000000, '沙湾区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511112000000, '五通桥区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511113000000, '金口河区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511123000000, '犍为县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511124000000, '井研县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511126000000, '夹江县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511129000000, '沐川县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511132000000, '峨边彝族自治县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511133000000, '马边彝族自治县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511181000000, '峨眉山市', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511300000000, '南充市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511301000000, '市辖区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511302000000, '顺庆区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511303000000, '高坪区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511304000000, '嘉陵区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511321000000, '南部县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511322000000, '营山县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511323000000, '蓬安县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511324000000, '仪陇县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511325000000, '西充县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511381000000, '阆中市', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511400000000, '眉山市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511401000000, '市辖区', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511402000000, '东坡区', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511403000000, '彭山区', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511421000000, '仁寿县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511423000000, '洪雅县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511424000000, '丹棱县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511425000000, '青神县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511500000000, '宜宾市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511501000000, '市辖区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511502000000, '翠屏区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511503000000, '南溪区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511504000000, '叙州区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511523000000, '江安县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511524000000, '长宁县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511525000000, '高县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511526000000, '珙县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511527000000, '筠连县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511528000000, '兴文县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511529000000, '屏山县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511600000000, '广安市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511601000000, '市辖区', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511602000000, '广安区', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511603000000, '前锋区', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511621000000, '岳池县', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511622000000, '武胜县', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511623000000, '邻水县', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511681000000, '华蓥市', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511700000000, '达州市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511701000000, '市辖区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511702000000, '通川区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511703000000, '达川区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511722000000, '宣汉县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511723000000, '开江县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511724000000, '大竹县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511725000000, '渠县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511771000000, '达州经济开发区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511781000000, '万源市', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511800000000, '雅安市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511801000000, '市辖区', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511802000000, '雨城区', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511803000000, '名山区', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511822000000, '荥经县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511823000000, '汉源县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511824000000, '石棉县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511825000000, '天全县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511826000000, '芦山县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511827000000, '宝兴县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511900000000, '巴中市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511901000000, '市辖区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511902000000, '巴州区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511903000000, '恩阳区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511921000000, '通江县', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511922000000, '南江县', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511923000000, '平昌县', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511971000000, '巴中经济开发区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (512000000000, '资阳市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (512001000000, '市辖区', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (512002000000, '雁江区', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (512021000000, '安岳县', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (512022000000, '乐至县', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (513200000000, '阿坝藏族羌族自治州', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (513201000000, '马尔康市', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513221000000, '汶川县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513222000000, '理县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513223000000, '茂县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513224000000, '松潘县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513225000000, '九寨沟县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513226000000, '金川县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513227000000, '小金县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513228000000, '黑水县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513230000000, '壤塘县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513231000000, '阿坝县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513232000000, '若尔盖县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513233000000, '红原县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513300000000, '甘孜藏族自治州', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (513301000000, '康定市', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513322000000, '泸定县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513323000000, '丹巴县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513324000000, '九龙县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513325000000, '雅江县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513326000000, '道孚县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513327000000, '炉霍县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513328000000, '甘孜县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513329000000, '新龙县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513330000000, '德格县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513331000000, '白玉县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513332000000, '石渠县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513333000000, '色达县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513334000000, '理塘县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513335000000, '巴塘县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513336000000, '乡城县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513337000000, '稻城县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513338000000, '得荣县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513400000000, '凉山彝族自治州', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (513401000000, '西昌市', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513422000000, '木里藏族自治县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513423000000, '盐源县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513424000000, '德昌县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513425000000, '会理县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513426000000, '会东县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513427000000, '宁南县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513428000000, '普格县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513429000000, '布拖县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513430000000, '金阳县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513431000000, '昭觉县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513432000000, '喜德县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513433000000, '冕宁县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513434000000, '越西县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513435000000, '甘洛县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513436000000, '美姑县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513437000000, '雷波县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (520000000000, '贵州省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (520100000000, '贵阳市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520101000000, '市辖区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520102000000, '南明区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520103000000, '云岩区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520111000000, '花溪区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520112000000, '乌当区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520113000000, '白云区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520115000000, '观山湖区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520121000000, '开阳县', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520122000000, '息烽县', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520123000000, '修文县', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520181000000, '清镇市', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520200000000, '六盘水市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520201000000, '钟山区', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520203000000, '六枝特区', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520221000000, '水城县', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520281000000, '盘州市', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520300000000, '遵义市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520301000000, '市辖区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520302000000, '红花岗区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520303000000, '汇川区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520304000000, '播州区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520322000000, '桐梓县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520323000000, '绥阳县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520324000000, '正安县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520325000000, '道真仡佬族苗族自治县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520326000000, '务川仡佬族苗族自治县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520327000000, '凤冈县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520328000000, '湄潭县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520329000000, '余庆县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520330000000, '习水县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520381000000, '赤水市', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520382000000, '仁怀市', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520400000000, '安顺市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520401000000, '市辖区', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520402000000, '西秀区', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520403000000, '平坝区', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520422000000, '普定县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520423000000, '镇宁布依族苗族自治县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520424000000, '关岭布依族苗族自治县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520425000000, '紫云苗族布依族自治县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520500000000, '毕节市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520501000000, '市辖区', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520502000000, '七星关区', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520521000000, '大方县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520522000000, '黔西县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520523000000, '金沙县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520524000000, '织金县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520525000000, '纳雍县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520526000000, '威宁彝族回族苗族自治县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520527000000, '赫章县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520600000000, '铜仁市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520601000000, '市辖区', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520602000000, '碧江区', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520603000000, '万山区', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520621000000, '江口县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520622000000, '玉屏侗族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520623000000, '石阡县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520624000000, '思南县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520625000000, '印江土家族苗族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520626000000, '德江县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520627000000, '沿河土家族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520628000000, '松桃苗族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (522300000000, '黔西南布依族苗族自治州', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (522301000000, '兴义市', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522302000000, '兴仁市', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522323000000, '普安县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522324000000, '晴隆县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522325000000, '贞丰县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522326000000, '望谟县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522327000000, '册亨县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522328000000, '安龙县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522600000000, '黔东南苗族侗族自治州', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (522601000000, '凯里市', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522622000000, '黄平县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522623000000, '施秉县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522624000000, '三穗县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522625000000, '镇远县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522626000000, '岑巩县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522627000000, '天柱县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522628000000, '锦屏县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522629000000, '剑河县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522630000000, '台江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522631000000, '黎平县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522632000000, '榕江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522633000000, '从江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522634000000, '雷山县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522635000000, '麻江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522636000000, '丹寨县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522700000000, '黔南布依族苗族自治州', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (522701000000, '都匀市', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522702000000, '福泉市', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522722000000, '荔波县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522723000000, '贵定县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522725000000, '瓮安县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522726000000, '独山县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522727000000, '平塘县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522728000000, '罗甸县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522729000000, '长顺县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522730000000, '龙里县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522731000000, '惠水县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522732000000, '三都水族自治县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (530000000000, '云南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (530100000000, '昆明市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530101000000, '市辖区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530102000000, '五华区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530103000000, '盘龙区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530111000000, '官渡区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530112000000, '西山区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530113000000, '东川区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530114000000, '呈贡区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530115000000, '晋宁区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530124000000, '富民县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530125000000, '宜良县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530126000000, '石林彝族自治县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530127000000, '嵩明县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530128000000, '禄劝彝族苗族自治县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530129000000, '寻甸回族彝族自治县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530181000000, '安宁市', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530300000000, '曲靖市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530301000000, '市辖区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530302000000, '麒麟区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530303000000, '沾益区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530304000000, '马龙区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530322000000, '陆良县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530323000000, '师宗县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530324000000, '罗平县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530325000000, '富源县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530326000000, '会泽县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530381000000, '宣威市', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530400000000, '玉溪市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530401000000, '市辖区', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530402000000, '红塔区', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530403000000, '江川区', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530422000000, '澄江县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530423000000, '通海县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530424000000, '华宁县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530425000000, '易门县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530426000000, '峨山彝族自治县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530427000000, '新平彝族傣族自治县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530428000000, '元江哈尼族彝族傣族自治县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530500000000, '保山市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530501000000, '市辖区', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530502000000, '隆阳区', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530521000000, '施甸县', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530523000000, '龙陵县', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530524000000, '昌宁县', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530581000000, '腾冲市', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530600000000, '昭通市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530601000000, '市辖区', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530602000000, '昭阳区', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530621000000, '鲁甸县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530622000000, '巧家县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530623000000, '盐津县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530624000000, '大关县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530625000000, '永善县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530626000000, '绥江县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530627000000, '镇雄县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530628000000, '彝良县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530629000000, '威信县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530681000000, '水富市', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530700000000, '丽江市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530701000000, '市辖区', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530702000000, '古城区', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530721000000, '玉龙纳西族自治县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530722000000, '永胜县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530723000000, '华坪县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530724000000, '宁蒗彝族自治县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530800000000, '普洱市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530801000000, '市辖区', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530802000000, '思茅区', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530821000000, '宁洱哈尼族彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530822000000, '墨江哈尼族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530823000000, '景东彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530824000000, '景谷傣族彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530825000000, '镇沅彝族哈尼族拉祜族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530826000000, '江城哈尼族彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530827000000, '孟连傣族拉祜族佤族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530828000000, '澜沧拉祜族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530829000000, '西盟佤族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530900000000, '临沧市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530901000000, '市辖区', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530902000000, '临翔区', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530921000000, '凤庆县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530922000000, '云县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530923000000, '永德县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530924000000, '镇康县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530925000000, '双江拉祜族佤族布朗族傣族自治县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530926000000, '耿马傣族佤族自治县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530927000000, '沧源佤族自治县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (532300000000, '楚雄彝族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532301000000, '楚雄市', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532322000000, '双柏县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532323000000, '牟定县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532324000000, '南华县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532325000000, '姚安县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532326000000, '大姚县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532327000000, '永仁县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532328000000, '元谋县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532329000000, '武定县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532331000000, '禄丰县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532500000000, '红河哈尼族彝族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532501000000, '个旧市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532502000000, '开远市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532503000000, '蒙自市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532504000000, '弥勒市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532523000000, '屏边苗族自治县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532524000000, '建水县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532525000000, '石屏县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532527000000, '泸西县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532528000000, '元阳县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532529000000, '红河县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532530000000, '金平苗族瑶族傣族自治县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532531000000, '绿春县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532532000000, '河口瑶族自治县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532600000000, '文山壮族苗族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532601000000, '文山市', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532622000000, '砚山县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532623000000, '西畴县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532624000000, '麻栗坡县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532625000000, '马关县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532626000000, '丘北县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532627000000, '广南县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532628000000, '富宁县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532800000000, '西双版纳傣族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532801000000, '景洪市', 3, 532800000000); +INSERT INTO `zz_area_code` VALUES (532822000000, '勐海县', 3, 532800000000); +INSERT INTO `zz_area_code` VALUES (532823000000, '勐腊县', 3, 532800000000); +INSERT INTO `zz_area_code` VALUES (532900000000, '大理白族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532901000000, '大理市', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532922000000, '漾濞彝族自治县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532923000000, '祥云县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532924000000, '宾川县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532925000000, '弥渡县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532926000000, '南涧彝族自治县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532927000000, '巍山彝族回族自治县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532928000000, '永平县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532929000000, '云龙县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532930000000, '洱源县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532931000000, '剑川县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532932000000, '鹤庆县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (533100000000, '德宏傣族景颇族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (533102000000, '瑞丽市', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533103000000, '芒市', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533122000000, '梁河县', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533123000000, '盈江县', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533124000000, '陇川县', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533300000000, '怒江傈僳族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (533301000000, '泸水市', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533323000000, '福贡县', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533324000000, '贡山独龙族怒族自治县', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533325000000, '兰坪白族普米族自治县', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533400000000, '迪庆藏族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (533401000000, '香格里拉市', 3, 533400000000); +INSERT INTO `zz_area_code` VALUES (533422000000, '德钦县', 3, 533400000000); +INSERT INTO `zz_area_code` VALUES (533423000000, '维西傈僳族自治县', 3, 533400000000); +INSERT INTO `zz_area_code` VALUES (540000000000, '西藏自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (540100000000, '拉萨市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540101000000, '市辖区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540102000000, '城关区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540103000000, '堆龙德庆区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540104000000, '达孜区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540121000000, '林周县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540122000000, '当雄县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540123000000, '尼木县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540124000000, '曲水县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540127000000, '墨竹工卡县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540171000000, '格尔木藏青工业园区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540172000000, '拉萨经济技术开发区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540173000000, '西藏文化旅游创意园区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540174000000, '达孜工业园区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540200000000, '日喀则市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540202000000, '桑珠孜区', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540221000000, '南木林县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540222000000, '江孜县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540223000000, '定日县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540224000000, '萨迦县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540225000000, '拉孜县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540226000000, '昂仁县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540227000000, '谢通门县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540228000000, '白朗县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540229000000, '仁布县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540230000000, '康马县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540231000000, '定结县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540232000000, '仲巴县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540233000000, '亚东县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540234000000, '吉隆县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540235000000, '聂拉木县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540236000000, '萨嘎县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540237000000, '岗巴县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540300000000, '昌都市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540302000000, '卡若区', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540321000000, '江达县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540322000000, '贡觉县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540323000000, '类乌齐县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540324000000, '丁青县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540325000000, '察雅县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540326000000, '八宿县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540327000000, '左贡县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540328000000, '芒康县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540329000000, '洛隆县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540330000000, '边坝县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540400000000, '林芝市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540402000000, '巴宜区', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540421000000, '工布江达县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540422000000, '米林县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540423000000, '墨脱县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540424000000, '波密县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540425000000, '察隅县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540426000000, '朗县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540500000000, '山南市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540501000000, '市辖区', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540502000000, '乃东区', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540521000000, '扎囊县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540522000000, '贡嘎县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540523000000, '桑日县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540524000000, '琼结县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540525000000, '曲松县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540526000000, '措美县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540527000000, '洛扎县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540528000000, '加查县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540529000000, '隆子县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540530000000, '错那县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540531000000, '浪卡子县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540600000000, '那曲市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540602000000, '色尼区', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540621000000, '嘉黎县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540622000000, '比如县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540623000000, '聂荣县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540624000000, '安多县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540625000000, '申扎县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540626000000, '索县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540627000000, '班戈县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540628000000, '巴青县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540629000000, '尼玛县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540630000000, '双湖县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (542500000000, '阿里地区', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (542521000000, '普兰县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542522000000, '札达县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542523000000, '噶尔县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542524000000, '日土县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542525000000, '革吉县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542526000000, '改则县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542527000000, '措勤县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (610000000000, '陕西省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (610100000000, '西安市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610101000000, '市辖区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610102000000, '新城区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610103000000, '碑林区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610104000000, '莲湖区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610111000000, '灞桥区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610112000000, '未央区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610113000000, '雁塔区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610114000000, '阎良区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610115000000, '临潼区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610116000000, '长安区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610117000000, '高陵区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610118000000, '鄠邑区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610122000000, '蓝田县', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610124000000, '周至县', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610200000000, '铜川市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610201000000, '市辖区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610202000000, '王益区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610203000000, '印台区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610204000000, '耀州区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610222000000, '宜君县', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610300000000, '宝鸡市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610301000000, '市辖区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610302000000, '渭滨区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610303000000, '金台区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610304000000, '陈仓区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610322000000, '凤翔县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610323000000, '岐山县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610324000000, '扶风县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610326000000, '眉县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610327000000, '陇县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610328000000, '千阳县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610329000000, '麟游县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610330000000, '凤县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610331000000, '太白县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610400000000, '咸阳市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610401000000, '市辖区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610402000000, '秦都区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610403000000, '杨陵区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610404000000, '渭城区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610422000000, '三原县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610423000000, '泾阳县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610424000000, '乾县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610425000000, '礼泉县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610426000000, '永寿县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610428000000, '长武县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610429000000, '旬邑县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610430000000, '淳化县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610431000000, '武功县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610481000000, '兴平市', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610482000000, '彬州市', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610500000000, '渭南市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610501000000, '市辖区', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610502000000, '临渭区', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610503000000, '华州区', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610522000000, '潼关县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610523000000, '大荔县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610524000000, '合阳县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610525000000, '澄城县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610526000000, '蒲城县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610527000000, '白水县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610528000000, '富平县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610581000000, '韩城市', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610582000000, '华阴市', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610600000000, '延安市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610601000000, '市辖区', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610602000000, '宝塔区', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610603000000, '安塞区', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610621000000, '延长县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610622000000, '延川县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610623000000, '子长县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610625000000, '志丹县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610626000000, '吴起县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610627000000, '甘泉县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610628000000, '富县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610629000000, '洛川县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610630000000, '宜川县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610631000000, '黄龙县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610632000000, '黄陵县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610700000000, '汉中市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610701000000, '市辖区', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610702000000, '汉台区', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610703000000, '南郑区', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610722000000, '城固县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610723000000, '洋县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610724000000, '西乡县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610725000000, '勉县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610726000000, '宁强县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610727000000, '略阳县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610728000000, '镇巴县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610729000000, '留坝县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610730000000, '佛坪县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610800000000, '榆林市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610801000000, '市辖区', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610802000000, '榆阳区', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610803000000, '横山区', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610822000000, '府谷县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610824000000, '靖边县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610825000000, '定边县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610826000000, '绥德县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610827000000, '米脂县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610828000000, '佳县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610829000000, '吴堡县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610830000000, '清涧县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610831000000, '子洲县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610881000000, '神木市', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610900000000, '安康市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610901000000, '市辖区', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610902000000, '汉滨区', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610921000000, '汉阴县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610922000000, '石泉县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610923000000, '宁陕县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610924000000, '紫阳县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610925000000, '岚皋县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610926000000, '平利县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610927000000, '镇坪县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610928000000, '旬阳县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610929000000, '白河县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (611000000000, '商洛市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (611001000000, '市辖区', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611002000000, '商州区', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611021000000, '洛南县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611022000000, '丹凤县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611023000000, '商南县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611024000000, '山阳县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611025000000, '镇安县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611026000000, '柞水县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (620000000000, '甘肃省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (620100000000, '兰州市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620101000000, '市辖区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620102000000, '城关区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620103000000, '七里河区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620104000000, '西固区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620105000000, '安宁区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620111000000, '红古区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620121000000, '永登县', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620122000000, '皋兰县', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620123000000, '榆中县', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620171000000, '兰州新区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620200000000, '嘉峪关市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620201000000, '市辖区', 3, 620200000000); +INSERT INTO `zz_area_code` VALUES (620300000000, '金昌市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620301000000, '市辖区', 3, 620300000000); +INSERT INTO `zz_area_code` VALUES (620302000000, '金川区', 3, 620300000000); +INSERT INTO `zz_area_code` VALUES (620321000000, '永昌县', 3, 620300000000); +INSERT INTO `zz_area_code` VALUES (620400000000, '白银市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620401000000, '市辖区', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620402000000, '白银区', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620403000000, '平川区', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620421000000, '靖远县', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620422000000, '会宁县', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620423000000, '景泰县', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620500000000, '天水市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620501000000, '市辖区', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620502000000, '秦州区', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620503000000, '麦积区', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620521000000, '清水县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620522000000, '秦安县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620523000000, '甘谷县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620524000000, '武山县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620525000000, '张家川回族自治县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620600000000, '武威市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620601000000, '市辖区', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620602000000, '凉州区', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620621000000, '民勤县', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620622000000, '古浪县', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620623000000, '天祝藏族自治县', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620700000000, '张掖市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620701000000, '市辖区', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620702000000, '甘州区', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620721000000, '肃南裕固族自治县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620722000000, '民乐县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620723000000, '临泽县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620724000000, '高台县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620725000000, '山丹县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620800000000, '平凉市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620801000000, '市辖区', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620802000000, '崆峒区', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620821000000, '泾川县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620822000000, '灵台县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620823000000, '崇信县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620825000000, '庄浪县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620826000000, '静宁县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620881000000, '华亭市', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620900000000, '酒泉市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620901000000, '市辖区', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620902000000, '肃州区', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620921000000, '金塔县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620922000000, '瓜州县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620923000000, '肃北蒙古族自治县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620924000000, '阿克塞哈萨克族自治县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620981000000, '玉门市', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620982000000, '敦煌市', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (621000000000, '庆阳市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (621001000000, '市辖区', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621002000000, '西峰区', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621021000000, '庆城县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621022000000, '环县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621023000000, '华池县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621024000000, '合水县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621025000000, '正宁县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621026000000, '宁县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621027000000, '镇原县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621100000000, '定西市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (621101000000, '市辖区', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621102000000, '安定区', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621121000000, '通渭县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621122000000, '陇西县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621123000000, '渭源县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621124000000, '临洮县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621125000000, '漳县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621126000000, '岷县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621200000000, '陇南市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (621201000000, '市辖区', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621202000000, '武都区', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621221000000, '成县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621222000000, '文县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621223000000, '宕昌县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621224000000, '康县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621225000000, '西和县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621226000000, '礼县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621227000000, '徽县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621228000000, '两当县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (622900000000, '临夏回族自治州', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (622901000000, '临夏市', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622921000000, '临夏县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622922000000, '康乐县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622923000000, '永靖县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622924000000, '广河县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622925000000, '和政县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622926000000, '东乡族自治县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622927000000, '积石山保安族东乡族撒拉族自治县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (623000000000, '甘南藏族自治州', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (623001000000, '合作市', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623021000000, '临潭县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623022000000, '卓尼县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623023000000, '舟曲县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623024000000, '迭部县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623025000000, '玛曲县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623026000000, '碌曲县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623027000000, '夏河县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (630000000000, '青海省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (630100000000, '西宁市', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (630101000000, '市辖区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630102000000, '城东区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630103000000, '城中区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630104000000, '城西区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630105000000, '城北区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630121000000, '大通回族土族自治县', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630122000000, '湟中县', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630123000000, '湟源县', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630200000000, '海东市', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (630202000000, '乐都区', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630203000000, '平安区', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630222000000, '民和回族土族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630223000000, '互助土族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630224000000, '化隆回族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630225000000, '循化撒拉族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (632200000000, '海北藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632221000000, '门源回族自治县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632222000000, '祁连县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632223000000, '海晏县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632224000000, '刚察县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632300000000, '黄南藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632321000000, '同仁县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632322000000, '尖扎县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632323000000, '泽库县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632324000000, '河南蒙古族自治县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632500000000, '海南藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632521000000, '共和县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632522000000, '同德县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632523000000, '贵德县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632524000000, '兴海县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632525000000, '贵南县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632600000000, '果洛藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632621000000, '玛沁县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632622000000, '班玛县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632623000000, '甘德县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632624000000, '达日县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632625000000, '久治县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632626000000, '玛多县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632700000000, '玉树藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632701000000, '玉树市', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632722000000, '杂多县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632723000000, '称多县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632724000000, '治多县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632725000000, '囊谦县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632726000000, '曲麻莱县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632800000000, '海西蒙古族藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632801000000, '格尔木市', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632802000000, '德令哈市', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632803000000, '茫崖市', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632821000000, '乌兰县', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632822000000, '都兰县', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632823000000, '天峻县', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632857000000, '大柴旦行政委员会', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (640000000000, '宁夏回族自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (640100000000, '银川市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640101000000, '市辖区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640104000000, '兴庆区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640105000000, '西夏区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640106000000, '金凤区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640121000000, '永宁县', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640122000000, '贺兰县', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640181000000, '灵武市', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640200000000, '石嘴山市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640201000000, '市辖区', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640202000000, '大武口区', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640205000000, '惠农区', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640221000000, '平罗县', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640300000000, '吴忠市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640301000000, '市辖区', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640302000000, '利通区', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640303000000, '红寺堡区', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640323000000, '盐池县', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640324000000, '同心县', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640381000000, '青铜峡市', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640400000000, '固原市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640401000000, '市辖区', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640402000000, '原州区', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640422000000, '西吉县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640423000000, '隆德县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640424000000, '泾源县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640425000000, '彭阳县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640500000000, '中卫市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640501000000, '市辖区', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (640502000000, '沙坡头区', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (640521000000, '中宁县', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (640522000000, '海原县', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (650000000000, '新疆维吾尔自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (650100000000, '乌鲁木齐市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650101000000, '市辖区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650102000000, '天山区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650103000000, '沙依巴克区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650104000000, '新市区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650105000000, '水磨沟区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650106000000, '头屯河区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650107000000, '达坂城区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650109000000, '米东区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650121000000, '乌鲁木齐县', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650171000000, '乌鲁木齐经济技术开发区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650172000000, '乌鲁木齐高新技术产业开发区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650200000000, '克拉玛依市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650201000000, '市辖区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650202000000, '独山子区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650203000000, '克拉玛依区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650204000000, '白碱滩区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650205000000, '乌尔禾区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650400000000, '吐鲁番市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650402000000, '高昌区', 3, 650400000000); +INSERT INTO `zz_area_code` VALUES (650421000000, '鄯善县', 3, 650400000000); +INSERT INTO `zz_area_code` VALUES (650422000000, '托克逊县', 3, 650400000000); +INSERT INTO `zz_area_code` VALUES (650500000000, '哈密市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650502000000, '伊州区', 3, 650500000000); +INSERT INTO `zz_area_code` VALUES (650521000000, '巴里坤哈萨克自治县', 3, 650500000000); +INSERT INTO `zz_area_code` VALUES (650522000000, '伊吾县', 3, 650500000000); +INSERT INTO `zz_area_code` VALUES (652300000000, '昌吉回族自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652301000000, '昌吉市', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652302000000, '阜康市', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652323000000, '呼图壁县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652324000000, '玛纳斯县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652325000000, '奇台县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652327000000, '吉木萨尔县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652328000000, '木垒哈萨克自治县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652700000000, '博尔塔拉蒙古自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652701000000, '博乐市', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652702000000, '阿拉山口市', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652722000000, '精河县', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652723000000, '温泉县', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652800000000, '巴音郭楞蒙古自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652801000000, '库尔勒市', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652822000000, '轮台县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652823000000, '尉犁县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652824000000, '若羌县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652825000000, '且末县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652826000000, '焉耆回族自治县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652827000000, '和静县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652828000000, '和硕县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652829000000, '博湖县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652871000000, '库尔勒经济技术开发区', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652900000000, '阿克苏地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652901000000, '阿克苏市', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652922000000, '温宿县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652923000000, '库车县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652924000000, '沙雅县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652925000000, '新和县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652926000000, '拜城县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652927000000, '乌什县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652928000000, '阿瓦提县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652929000000, '柯坪县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (653000000000, '克孜勒苏柯尔克孜自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (653001000000, '阿图什市', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653022000000, '阿克陶县', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653023000000, '阿合奇县', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653024000000, '乌恰县', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653100000000, '喀什地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (653101000000, '喀什市', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653121000000, '疏附县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653122000000, '疏勒县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653123000000, '英吉沙县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653124000000, '泽普县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653125000000, '莎车县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653126000000, '叶城县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653127000000, '麦盖提县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653128000000, '岳普湖县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653129000000, '伽师县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653130000000, '巴楚县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653131000000, '塔什库尔干塔吉克自治县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653200000000, '和田地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (653201000000, '和田市', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653221000000, '和田县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653222000000, '墨玉县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653223000000, '皮山县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653224000000, '洛浦县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653225000000, '策勒县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653226000000, '于田县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653227000000, '民丰县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (654000000000, '伊犁哈萨克自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (654002000000, '伊宁市', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654003000000, '奎屯市', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654004000000, '霍尔果斯市', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654021000000, '伊宁县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654022000000, '察布查尔锡伯自治县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654023000000, '霍城县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654024000000, '巩留县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654025000000, '新源县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654026000000, '昭苏县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654027000000, '特克斯县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654028000000, '尼勒克县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654200000000, '塔城地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (654201000000, '塔城市', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654202000000, '乌苏市', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654221000000, '额敏县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654223000000, '沙湾县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654224000000, '托里县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654225000000, '裕民县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654226000000, '和布克赛尔蒙古自治县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654300000000, '阿勒泰地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (654301000000, '阿勒泰市', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654321000000, '布尔津县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654322000000, '富蕴县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654323000000, '福海县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654324000000, '哈巴河县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654325000000, '青河县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654326000000, '吉木乃县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (659000000000, '自治区直辖县级行政区划', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (659001000000, '石河子市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659002000000, '阿拉尔市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659003000000, '图木舒克市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659004000000, '五家渠市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659006000000, '铁门关市', 3, 659000000000); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/orange-demo-single-service/zz-resource/upload-files/app/image/Course/pictureUrl/eef356943ce74b7b809dcce178cb92d2.png b/orange-demo-single-service/zz-resource/upload-files/app/image/Course/pictureUrl/eef356943ce74b7b809dcce178cb92d2.png new file mode 100644 index 00000000..8a9df82d Binary files /dev/null and b/orange-demo-single-service/zz-resource/upload-files/app/image/Course/pictureUrl/eef356943ce74b7b809dcce178cb92d2.png differ diff --git a/orange-demo-single-web/.browserslistrc b/orange-demo-single-web/.browserslistrc new file mode 100644 index 00000000..d6471a38 --- /dev/null +++ b/orange-demo-single-web/.browserslistrc @@ -0,0 +1,2 @@ +> 1% +last 2 versions diff --git a/orange-demo-single-web/.editorconfig b/orange-demo-single-web/.editorconfig new file mode 100644 index 00000000..7053c49a --- /dev/null +++ b/orange-demo-single-web/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/orange-demo-single-web/.eslintrc.js b/orange-demo-single-web/.eslintrc.js new file mode 100644 index 00000000..f62621ce --- /dev/null +++ b/orange-demo-single-web/.eslintrc.js @@ -0,0 +1,40 @@ +module.exports = { + root: true, + env: { + node: true + }, + 'extends': [ + 'plugin:vue/essential', + '@vue/standard' + ], + parserOptions: { + parser: 'babel-eslint' + }, + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'semi': ['off', 'always'], + 'prefer-promise-reject-errors': ['error', { 'allowEmptyReject': true }], + 'no-trailing-spaces': ['error', { 'skipBlankLines': true }], + 'prefer-const': ['off'], + 'quote-props': ['off'], + 'object-curly-spacing': ['off'], + 'dot-notation': ['off'], + 'lines-between-class-members': ['off'], + // 'no-undef': ['off', 'always'], + // 'no-unused-vars': ['off', 'always'], + 'no-new-func': ['off', 'always'], + 'no-console': ['off'] + }, + overrides: [ + { + files: [ + '**/__tests__/*.{j,t}s?(x)', + '**/tests/unit/**/*.spec.{j,t}s?(x)' + ], + env: { + jest: true + } + } + ] +} diff --git a/orange-demo-single-web/.gitignore b/orange-demo-single-web/.gitignore new file mode 100644 index 00000000..a0dddc6f --- /dev/null +++ b/orange-demo-single-web/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/orange-demo-single-web/README.md b/orange-demo-single-web/README.md new file mode 100644 index 00000000..3b5fbf8e --- /dev/null +++ b/orange-demo-single-web/README.md @@ -0,0 +1,15 @@ +## 橙单代码生成器 +### 构建命令 +``` bash +# install dependencies +npm install + +# serve with hot reload at localhost:8080 +npm run dev + +# build for production with minification +npm run build + +# run all tests +npm test +``` diff --git a/orange-demo-single-web/babel.config.js b/orange-demo-single-web/babel.config.js new file mode 100644 index 00000000..e9558405 --- /dev/null +++ b/orange-demo-single-web/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/orange-demo-single-web/jest.config.js b/orange-demo-single-web/jest.config.js new file mode 100644 index 00000000..0f957914 --- /dev/null +++ b/orange-demo-single-web/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: '@vue/cli-plugin-unit-jest' +} diff --git a/orange-demo-single-web/package.json b/orange-demo-single-web/package.json new file mode 100644 index 00000000..1fcb6289 --- /dev/null +++ b/orange-demo-single-web/package.json @@ -0,0 +1,61 @@ +{ + "name": "orange-single-page-project", + "version": "1.0.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "dev": "vue-cli-service serve", + "build": "vue-cli-service build", + "test:unit": "vue-cli-service test:unit", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^0.18.0", + "echarts": "^4.2.1", + "element-ui": "^2.13.0", + "jquery": "^3.3.1", + "jsencrypt": "^3.0.0-rc.1", + "json-bigint": "^0.3.0", + "layui-layer": "^1.0.9", + "lodash": "^4.17.5", + "core-js": "^3.6.4", + "register-service-worker": "^1.6.2", + "sortablejs": "^1.7.0", + "v-charts": "^1.19.0", + "vue": "^2.6.11", + "vue-router": "^3.1.5", + "vuex": "^3.1.2", + "wangeditor": "^3.1.1" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~4.2.0", + "@vue/cli-plugin-eslint": "~4.2.0", + "@vue/cli-plugin-pwa": "~4.2.0", + "@vue/cli-plugin-router": "~4.2.0", + "@vue/cli-plugin-unit-jest": "~4.2.0", + "@vue/cli-plugin-vuex": "~4.2.0", + "@vue/cli-service": "~4.2.0", + "@vue/eslint-config-standard": "^5.1.0", + "@vue/test-utils": "1.0.0-beta.31", + "babel-eslint": "^10.0.3", + "eslint": "^6.7.2", + "eslint-plugin-import": "^2.20.1", + "eslint-plugin-node": "^11.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.0", + "eslint-plugin-vue": "^6.1.2", + "lint-staged": "^9.5.0", + "node-sass": "^4.13.1", + "sass-loader": "^7.3.1", + "vue-template-compiler": "^2.6.11" + }, + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.{js,jsx,vue}": [ + "vue-cli-service lint", + "git add" + ] + } +} diff --git a/orange-demo-single-web/public/favicon.ico b/orange-demo-single-web/public/favicon.ico new file mode 100644 index 00000000..df36fcfb Binary files /dev/null and b/orange-demo-single-web/public/favicon.ico differ diff --git a/orange-demo-single-web/public/img/icons/android-chrome-192x192.png b/orange-demo-single-web/public/img/icons/android-chrome-192x192.png new file mode 100644 index 00000000..b02aa64d Binary files /dev/null and b/orange-demo-single-web/public/img/icons/android-chrome-192x192.png differ diff --git a/orange-demo-single-web/public/img/icons/android-chrome-512x512.png b/orange-demo-single-web/public/img/icons/android-chrome-512x512.png new file mode 100644 index 00000000..06088b01 Binary files /dev/null and b/orange-demo-single-web/public/img/icons/android-chrome-512x512.png differ diff --git a/orange-demo-single-web/public/img/icons/android-chrome-maskable-192x192.png b/orange-demo-single-web/public/img/icons/android-chrome-maskable-192x192.png new file mode 100644 index 00000000..791e9c8c Binary files /dev/null and b/orange-demo-single-web/public/img/icons/android-chrome-maskable-192x192.png differ diff --git a/orange-demo-single-web/public/img/icons/android-chrome-maskable-512x512.png b/orange-demo-single-web/public/img/icons/android-chrome-maskable-512x512.png new file mode 100644 index 00000000..5f2098ed Binary files /dev/null and b/orange-demo-single-web/public/img/icons/android-chrome-maskable-512x512.png differ diff --git a/orange-demo-single-web/public/img/icons/apple-touch-icon-120x120.png b/orange-demo-single-web/public/img/icons/apple-touch-icon-120x120.png new file mode 100644 index 00000000..1427cf62 Binary files /dev/null and b/orange-demo-single-web/public/img/icons/apple-touch-icon-120x120.png differ diff --git a/orange-demo-single-web/public/img/icons/apple-touch-icon-152x152.png b/orange-demo-single-web/public/img/icons/apple-touch-icon-152x152.png new file mode 100644 index 00000000..f24d454a Binary files /dev/null and b/orange-demo-single-web/public/img/icons/apple-touch-icon-152x152.png differ diff --git a/orange-demo-single-web/public/img/icons/apple-touch-icon-180x180.png b/orange-demo-single-web/public/img/icons/apple-touch-icon-180x180.png new file mode 100644 index 00000000..404e192a Binary files /dev/null and b/orange-demo-single-web/public/img/icons/apple-touch-icon-180x180.png differ diff --git a/orange-demo-single-web/public/img/icons/apple-touch-icon-60x60.png b/orange-demo-single-web/public/img/icons/apple-touch-icon-60x60.png new file mode 100644 index 00000000..cf10a560 Binary files /dev/null and b/orange-demo-single-web/public/img/icons/apple-touch-icon-60x60.png differ diff --git a/orange-demo-single-web/public/img/icons/apple-touch-icon-76x76.png b/orange-demo-single-web/public/img/icons/apple-touch-icon-76x76.png new file mode 100644 index 00000000..c500769e Binary files /dev/null and b/orange-demo-single-web/public/img/icons/apple-touch-icon-76x76.png differ diff --git a/orange-demo-single-web/public/img/icons/apple-touch-icon.png b/orange-demo-single-web/public/img/icons/apple-touch-icon.png new file mode 100644 index 00000000..03c0c5d5 Binary files /dev/null and b/orange-demo-single-web/public/img/icons/apple-touch-icon.png differ diff --git a/orange-demo-single-web/public/img/icons/favicon-16x16.png b/orange-demo-single-web/public/img/icons/favicon-16x16.png new file mode 100644 index 00000000..42af0096 Binary files /dev/null and b/orange-demo-single-web/public/img/icons/favicon-16x16.png differ diff --git a/orange-demo-single-web/public/img/icons/favicon-32x32.png b/orange-demo-single-web/public/img/icons/favicon-32x32.png new file mode 100644 index 00000000..46ca04de Binary files /dev/null and b/orange-demo-single-web/public/img/icons/favicon-32x32.png differ diff --git a/orange-demo-single-web/public/img/icons/msapplication-icon-144x144.png b/orange-demo-single-web/public/img/icons/msapplication-icon-144x144.png new file mode 100644 index 00000000..7808237a Binary files /dev/null and b/orange-demo-single-web/public/img/icons/msapplication-icon-144x144.png differ diff --git a/orange-demo-single-web/public/img/icons/mstile-150x150.png b/orange-demo-single-web/public/img/icons/mstile-150x150.png new file mode 100644 index 00000000..3b37a43a Binary files /dev/null and b/orange-demo-single-web/public/img/icons/mstile-150x150.png differ diff --git a/orange-demo-single-web/public/img/icons/safari-pinned-tab.svg b/orange-demo-single-web/public/img/icons/safari-pinned-tab.svg new file mode 100644 index 00000000..732afd8e --- /dev/null +++ b/orange-demo-single-web/public/img/icons/safari-pinned-tab.svg @@ -0,0 +1,149 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/orange-demo-single-web/public/index.html b/orange-demo-single-web/public/index.html new file mode 100644 index 00000000..37e411e8 --- /dev/null +++ b/orange-demo-single-web/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + 橙单工程 + + + +
+ + + diff --git a/orange-demo-single-web/public/robots.txt b/orange-demo-single-web/public/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/orange-demo-single-web/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/orange-demo-single-web/src/App.vue b/orange-demo-single-web/src/App.vue new file mode 100644 index 00000000..907f4e8c --- /dev/null +++ b/orange-demo-single-web/src/App.vue @@ -0,0 +1,19 @@ + + + diff --git a/orange-demo-single-web/src/api/Controller/CourseController.js b/orange-demo-single-web/src/api/Controller/CourseController.js new file mode 100644 index 00000000..daa782e3 --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/CourseController.js @@ -0,0 +1,25 @@ +export default class CourseController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/course/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/course/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/course/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/course/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/course/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/course/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/CourseTransStatsController.js b/orange-demo-single-web/src/api/Controller/CourseTransStatsController.js new file mode 100644 index 00000000..9b42412e --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/CourseTransStatsController.js @@ -0,0 +1,17 @@ +export default class CourseTransStatsController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/courseTransStats/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/courseTransStats/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/courseTransStats/export', params, fileName); + } + + static listWithGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/courseTransStats/listWithGroup', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/DictionaryController.js b/orange-demo-single-web/src/api/Controller/DictionaryController.js new file mode 100644 index 00000000..636ff2e4 --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/DictionaryController.js @@ -0,0 +1,155 @@ +import * as staticDict from '@/staticDict' + +export default class DictionaryController { + static dictSysUserStatus () { + return new Promise((resolve) => { + resolve(staticDict.SysUserStatus); + }); + } + static dictSysUserType () { + return new Promise((resolve) => { + resolve(staticDict.SysUserType); + }); + } + static dictSubject () { + return new Promise((resolve) => { + resolve(staticDict.Subject); + }); + } + static dictStudentActionType () { + return new Promise((resolve) => { + resolve(staticDict.StudentActionType); + }); + } + static dictDeviceType () { + return new Promise((resolve) => { + resolve(staticDict.DeviceType); + }); + } + static dictGender () { + return new Promise((resolve) => { + resolve(staticDict.Gender); + }); + } + static dictExpLevel () { + return new Promise((resolve) => { + resolve(staticDict.ExpLevel); + }); + } + static dictStudentStatus () { + return new Promise((resolve) => { + resolve(staticDict.StudentStatus); + }); + } + static dictClassStatus () { + return new Promise((resolve) => { + resolve(staticDict.ClassStatus); + }); + } + static dictClassLevel () { + return new Promise((resolve) => { + resolve(staticDict.ClassLevel); + }); + } + static dictCourseDifficult () { + return new Promise((resolve) => { + resolve(staticDict.CourseDifficult); + }); + } + static dictAreaCode (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/areaCode/listDictAreaCode', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictAreaCodeByParentId (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/areaCode/listDictAreaCodeByParentId', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictAddAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictDeleteAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictBatchDeleteAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictUpdateAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictReloadAreaCodeCachedData (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'get', params, axiosOption, httpOption); + } + static dictCourse (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/course/listDictCourse', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictGrade (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/grade/listDictGrade', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictAddGrade (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/grade/add', 'post', params, axiosOption, httpOption); + } + static dictDeleteGrade (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/grade/delete', 'post', params, axiosOption, httpOption); + } + static dictBatchDeleteGrade (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictUpdateGrade (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/grade/update', 'post', params, axiosOption, httpOption); + } + static dictReloadGradeCachedData (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/grade/reloadCachedData', 'get', params, axiosOption, httpOption); + } + static dictSchoolInfo (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/schoolInfo/listDictSchoolInfo', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictStudent (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/student/listDictStudent', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } +} diff --git a/orange-demo-single-web/src/api/Controller/SchoolInfoController.js b/orange-demo-single-web/src/api/Controller/SchoolInfoController.js new file mode 100644 index 00000000..c66096ee --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/SchoolInfoController.js @@ -0,0 +1,25 @@ +export default class SchoolInfoController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/schoolInfo/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/schoolInfo/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/schoolInfo/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/schoolInfo/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/schoolInfo/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/schoolInfo/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/StudentActionStatsController.js b/orange-demo-single-web/src/api/Controller/StudentActionStatsController.js new file mode 100644 index 00000000..8999db45 --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/StudentActionStatsController.js @@ -0,0 +1,17 @@ +export default class StudentActionStatsController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionStats/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionStats/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/studentActionStats/export', params, fileName); + } + + static listWithGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionStats/listWithGroup', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/StudentActionTransController.js b/orange-demo-single-web/src/api/Controller/StudentActionTransController.js new file mode 100644 index 00000000..bada6b3a --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/StudentActionTransController.js @@ -0,0 +1,25 @@ +export default class StudentActionTransController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionTrans/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionTrans/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/studentActionTrans/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionTrans/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionTrans/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentActionTrans/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/StudentClassController.js b/orange-demo-single-web/src/api/Controller/StudentClassController.js new file mode 100644 index 00000000..579b88e8 --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/StudentClassController.js @@ -0,0 +1,65 @@ +export default class StudentClassController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/studentClass/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/delete', 'post', params, axiosOption, httpOption); + } + + static listClassCourse (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/listClassCourse', 'post', params, axiosOption, httpOption); + } + + static listNotInClassCourse (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/listNotInClassCourse', 'post', params, axiosOption, httpOption); + } + + static addClassCourse (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/addClassCourse', 'post', params, axiosOption, httpOption); + } + + static deleteClassCourse (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/deleteClassCourse', 'post', params, axiosOption, httpOption); + } + + static updateClassCourse (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/updateClassCourse', 'post', params, axiosOption, httpOption); + } + + static listClassStudent (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/listClassStudent', 'post', params, axiosOption, httpOption); + } + + static listNotInClassStudent (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/listNotInClassStudent', 'post', params, axiosOption, httpOption); + } + + static addClassStudent (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/addClassStudent', 'post', params, axiosOption, httpOption); + } + + static deleteClassStudent (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/deleteClassStudent', 'post', params, axiosOption, httpOption); + } + + static updateClassStudent (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/studentClass/updateClassStudent', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/StudentController.js b/orange-demo-single-web/src/api/Controller/StudentController.js new file mode 100644 index 00000000..f89892df --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/StudentController.js @@ -0,0 +1,25 @@ +export default class StudentController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/student/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/student/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/student/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/student/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/student/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/student/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/SysDataPermController.js b/orange-demo-single-web/src/api/Controller/SysDataPermController.js new file mode 100644 index 00000000..15fd5ccc --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/SysDataPermController.js @@ -0,0 +1,61 @@ +export default class SysDataPermController { + /** + * @param params {dataPermId, dataPermName, deptIdListString} + */ + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/add', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, dataPermName, deptIdListString} + */ + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/update', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId} + */ + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/delete', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermName} + */ + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/list', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId} + */ + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/view', 'get', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, searchString} + */ + static listDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/listDataPermUser', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, userIdListString} + */ + static addDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/addDataPermUser', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, userId} + */ + static deleteDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/deleteDataPermUser', 'post', params, axiosOption, httpOption); + } + + static listNotInDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/listNotInDataPermUser', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/SysUserController.js b/orange-demo-single-web/src/api/Controller/SysUserController.js new file mode 100644 index 00000000..26dec1aa --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/SysUserController.js @@ -0,0 +1,25 @@ +export default class SysUserController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysUser/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysUser/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/upms/sysUser/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysUser/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysUser/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysUser/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/Controller/SystemController.js b/orange-demo-single-web/src/api/Controller/SystemController.js new file mode 100644 index 00000000..ea22c72e --- /dev/null +++ b/orange-demo-single-web/src/api/Controller/SystemController.js @@ -0,0 +1,201 @@ +export default class SystemController { + static login (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/login/doLogin', 'get', params, axiosOption, httpOption); + } + + static logout (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/login/doLogout', 'post', params, axiosOption, httpOption); + } + + static changePassword (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/login/changePassword', 'post', params, axiosOption, httpOption); + } + + static getDictList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDict/list', 'post', params, axiosOption, httpOption); + } + + static getRoleList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/list', 'post', params, axiosOption, httpOption); + } + + static getRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/view', 'get', params, axiosOption, httpOption); + } + + static deleteRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/delete', 'post', params, axiosOption, httpOption); + } + + static addRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/add', 'post', params, axiosOption, httpOption); + } + + static updateRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/update', 'post', params, axiosOption, httpOption); + } + + static getUserList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/list', 'post', params, axiosOption, httpOption); + } + + static getUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/view', 'get', params, axiosOption, httpOption); + } + + static resetUserPassword (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/resetPassword', 'post', params, axiosOption, httpOption); + } + + static deleteUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/delete', 'post', params, axiosOption, httpOption); + } + + static addUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/add', 'post', params, axiosOption, httpOption); + } + + static updateUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/update', 'post', params, axiosOption, httpOption); + } + + // 菜单接口 + static getMenuPermList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/list', 'get', params, axiosOption, httpOption); + } + + static addMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/add', 'post', params, axiosOption, httpOption); + } + + static updateMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/update', 'post', params, axiosOption, httpOption); + } + + static deleteMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/delete', 'post', params, axiosOption, httpOption); + } + + static viewMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/view', 'get', params, axiosOption, httpOption); + } + + static listMenuPerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/listMenuPerm', 'get', params, axiosOption, httpOption); + } + + // 权限字接口 + static getPermCodeList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/list', 'post', params, axiosOption, httpOption); + } + + static addPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/add', 'post', params, axiosOption, httpOption); + } + + static updatePermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/update', 'post', params, axiosOption, httpOption); + } + + static deletePermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/delete', 'post', params, axiosOption, httpOption); + } + + static viewPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/view', 'get', params, axiosOption, httpOption); + } + + // 权限资源接口 + static getAllPermList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/listAll', 'get', params, axiosOption, httpOption); + } + + static getPermGroupList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/list', 'get', params, axiosOption, httpOption); + } + + static addPermGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/add', 'post', params, axiosOption, httpOption); + } + + static updatePermGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/update', 'post', params, axiosOption, httpOption); + } + + static deletePermGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/delete', 'post', params, axiosOption, httpOption); + } + + static getPermList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/list', 'post', params, axiosOption, httpOption); + } + + static viewPerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/view', 'get', params, axiosOption, httpOption); + } + + static addPerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/add', 'post', params, axiosOption, httpOption); + } + + static updatePerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/update', 'post', params, axiosOption, httpOption); + } + + static deletePerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/delete', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {roleId, searchString} + */ + static listRoleUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listUserRole', 'post', params, axiosOption, httpOption); + } + + static listNotInUserRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listNotInUserRole', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {roleId, userIdListString} + */ + static addRoleUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/addUserRole', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {roleId, userId} + */ + static deleteRoleUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/deleteUserRole', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {} + */ + static queryRoleByPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listAllRolesByPermCode', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {} + */ + static queryRoleByURL (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listAllRolesByPerm', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {} + */ + static queryPerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/listAllPerms', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {} + */ + static queryPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/deleteUserRole', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-single-web/src/api/index.js b/orange-demo-single-web/src/api/index.js new file mode 100644 index 00000000..aca4fa48 --- /dev/null +++ b/orange-demo-single-web/src/api/index.js @@ -0,0 +1,25 @@ +import SystemController from './Controller/SystemController' +import SysDataPermController from './Controller/SysDataPermController' +import DictionaryController from './Controller/DictionaryController' +import CourseController from './Controller/CourseController.js' +import SchoolInfoController from './Controller/SchoolInfoController.js' +import StudentController from './Controller/StudentController.js' +import SysUserController from './Controller/SysUserController.js' +import StudentClassController from './Controller/StudentClassController.js' +import CourseTransStatsController from './Controller/CourseTransStatsController.js' +import StudentActionStatsController from './Controller/StudentActionStatsController.js' +import StudentActionTransController from './Controller/StudentActionTransController.js' + +export { + SystemController, + SysDataPermController, + DictionaryController, + CourseController, + SchoolInfoController, + StudentController, + SysUserController, + StudentClassController, + CourseTransStatsController, + StudentActionStatsController, + StudentActionTransController +} diff --git a/orange-demo-single-web/src/assets/img/default-header.jpg b/orange-demo-single-web/src/assets/img/default-header.jpg new file mode 100644 index 00000000..222d18da Binary files /dev/null and b/orange-demo-single-web/src/assets/img/default-header.jpg differ diff --git a/orange-demo-single-web/src/assets/img/login_bg.jpg b/orange-demo-single-web/src/assets/img/login_bg.jpg new file mode 100644 index 00000000..efc558de Binary files /dev/null and b/orange-demo-single-web/src/assets/img/login_bg.jpg differ diff --git a/orange-demo-single-web/src/assets/img/logo.jpg b/orange-demo-single-web/src/assets/img/logo.jpg new file mode 100644 index 00000000..a88fc0d0 Binary files /dev/null and b/orange-demo-single-web/src/assets/img/logo.jpg differ diff --git a/orange-demo-single-web/src/assets/img/orange-group1.png b/orange-demo-single-web/src/assets/img/orange-group1.png new file mode 100644 index 00000000..efd59f26 Binary files /dev/null and b/orange-demo-single-web/src/assets/img/orange-group1.png differ diff --git a/orange-demo-single-web/src/assets/style/base.scss b/orange-demo-single-web/src/assets/style/base.scss new file mode 100644 index 00000000..2ceda7be --- /dev/null +++ b/orange-demo-single-web/src/assets/style/base.scss @@ -0,0 +1,593 @@ +@import "element-color.scss"; +@import "transition.scss"; + +html, body { + padding: 0; + margin: 0; + font-size: 14px; + font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif; + background-color: rgb(228,240,255); +} + +*, +*:before, +*:after { + box-sizing: border-box; +} + +$header-height: 60px; + +// 过滤组件长度 +$filter-item-width: 250px; +// 范围选择过滤组件长度 +$filter-item-range-width: 400px; +// 左侧过滤树组件每一项高度 +$tree-node-height: 40px; +// 高级管理表单标题高度 +$advanced-title-height: 50px; +$border-color: rgb(216, 220, 229); +$menuHover: rgba(255,255,255,0.3); +$menu-background-color: transparent; +$tabs-header-margin-bottom: 25px; +$tab-header-background-color: #EBEEF5; +$image-item-width: 65px; +$box-padding-size: 25px; + +/** + * 弹窗样式,封装的layer的弹窗 + **/ +body .layer-dialog .layui-layer-title{ + border-radius: 4px 4px 0px 0px; + border:1px solid #01000000; +} + +body .layer-dialog .layui-layer-setwin {color: #ffffff} + +body .layer-dialog { + border-radius: 4px; + border:1px solid #01000000; +} + +body .layer-dialog .layui-layer-content { + padding: $box-padding-size; +} + + +.demo-project { + .el-main { + padding: 0px; + } + .flex-box { + flex-wrap: wrap; + } + .scrollbar_dropdown__wrap { + overflow-x: hidden; + } + + .icon-btn.el-button { + font-size: 18px; + padding: 5px 0px; + } + + .default-padding-box { + padding: $box-padding-size; + } + + .padding-no-top { + padding: 0px $box-padding-size $box-padding-size $box-padding-size; + } + + .default-border { + border: 1px solid $border-color1; + } + + .default-border-left { + border-left: 1px solid $border-color1; + } + + .default-border-right { + border-right: 1px solid $border-color1; + } + + .default-border-top { + border-top: 1px solid $border-color1; + } + + .default-border-bottom { + border-bottom: 1px solid $border-color1; + } + + .page-close-box { + position: absolute; + background: #13ce66; + transform: rotate(45deg); + height: 60px; + width: 60px; + right: -30px; + top:-30px; + text-align: center; + + .el-button { + transform: rotate(-45deg); + color: white; + margin-top: 30px; + } + } + + /** + * 过滤组件样式 + **/ + .mask-box { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.5); + top: 0; + z-index: 10; + } + + .filter-box { + position: relative; + background-color: white; + padding: $box-padding-size $box-padding-size 0px $box-padding-size; + z-index: 20; + } + + .advance-filter-box { + padding-bottom: 25px; + } + + .filter-item { + width: $filter-item-width; + } + + .cascader-item { + width: 160px!important; + } + + .is-range, .is-search { + width: $filter-item-range-width; + } + + .table-operation-box { + align-self: flex-end; + margin-bottom: 10px; + overflow: hidden; + } + + /** + * 左侧树状组件的样式,用户高级管理表单以及用户管理表单 + **/ + .advanced-left-box { + border-right: 1px solid $border-color; + .el-tree-node__content { + height: $tree-node-height; + } + + .tree-node-item { + height: $tree-node-height; + line-height: $tree-node-height; + width: 100%; + + .tree-node-menu { + display: none; + float: right; + padding-right: 10px; + color: red!important; + } + + &:hover .tree-node-menu { + display: block; + } + } + + .el-tree-node .el-button+.el-button { + margin-left: 5px; + } + } + /** + * form表单输入组件宽度 + **/ + .full-width-input { + .el-select { + width: 100%; + } + + .el-input { + width: 100%; + } + + .el-cascader { + width: 100%; + } + + .el-date-editor { + width: 100%; + } + + .el-input-number { + width: 100%; + } + } + /** + * 左侧菜单样式 + **/ + .sidebar-bg { + background: linear-gradient(#FC8051, #EB6265); + } + + .sidebar-title { + height: 160px; + overflow: hidden; + } + + .sidebar-title-text { + width: 100%; + font-size: 18px; + color: #fff; + text-align: center; + margin: 0px; + } + .el-menu { + background-color: $menu-background-color; + border-right-width: 0px; + } + + .menu-wrapper { + .el-menu { + background: linear-gradient(#FC8051, #EB6265); + } + + .el-menu-item { + color: white; + i { + color: white; + } + &:hover { + background-color: rgba(255,255,255,0.3)!important; + } + } + + .el-submenu { + .el-menu { + background: none; + } + } + } + + .el-submenu__title i { + color: white; + } + + .el-menu--collapse { + .el-submenu__icon-arrow { + display: none; + } + } + + .nest-menu .el-submenu>.el-submenu__title, .el-submenu .el-menu-item { + min-width: 180px!important; + background: $menu-background-color; + } + + .el-menu-item.is-active { + border-left: 3px solid #47ba5a; + background-color: rgba(255,255,255,0.3)!important; + } + + .el-submenu__title { + background-color: $menu-background-color!important; + } + + .el-menu { + border-right-width: 0px; + } + + .menu-collapse-btn { + padding: 0px; + width: 15px; + border-radius: 2px; + border: none; + height: 100px; + background-color: $--color-primary-light-5; + position: fixed; + top: 20%; + z-index: -1; + color: white; + + &:hover { + background-color: $--color-primary-light-7; + } + .chart-border { + border: 1px solid #EBEEF5; + } + } + + /** + * 多tab页表单,tab样式 + **/ + .el-tabs__header { + margin: 0 0 20px; + } + /** + * 表格表头背景色 + **/ + .table-header-gray, .has-gutter .gutter { + background-color: $tab-header-background-color; + } + + /** + * 图片上传以及显示样式 + **/ + .upload-image-item { + font-size: 28px; + color: #8c939d; + width: $image-item-width; + height: $image-item-width; + text-align: center; + display: block; + + .el-upload i { + line-height: $image-item-width; + } + } + + .upload-image-multi { + display: inline; + } + + .upload-image-item .el-upload { + border: 1px dashed #d9d9d9; + border-radius: 6px; + cursor: pointer; + position: relative; + overflow: hidden; + } + .upload-image-item .el-upload:hover { + border-color: #409eff; + } + + .upload-image-show { + width: $image-item-width; + height: $image-item-width; + display: inline; + } + + .table-cell-image { + width: $image-item-width; + height: $image-item-width; + line-height: $image-item-width; + text-align: center; + font-size: $image-item-width; + color: #606266; + margin: 0px 5px; + } + + .upload-image-list .el-upload-list__item { + width: $image-item-width; + height: $image-item-width; + line-height: $image-item-width; + } + + .upload-image-item .el-upload-list--picture-card .el-upload-list__item { + width: $image-item-width; + height: $image-item-width; + } + + .upload-image-item .el-upload.el-upload--text { + width: $image-item-width; + height: $image-item-width; + } + + .upload-image-item .el-upload--picture-card { + width: $image-item-width; + height: $image-item-width; + line-height: $image-item-width; + } + /** + * + **/ + $header-menu-height: 32px; + + .sidebar { + height: 100%; + background-color: #304156; + overflow: hidden; + } + + .header { + display: flex; + height: $header-height; + background-color: white; + } + + .header .menu-column { + margin-right: 20px; + .el-menu-item.is-active { + border-left: 0px solid #47ba5a; + } + } + + .header-menu { + float: right; + height: $header-menu-height; + line-height: $header-menu-height; + margin-top: ($header-height - $header-menu-height) / 2; + } + + .header-img { + width: $header-menu-height; + height: $header-menu-height; + border-radius: 50%; + margin-left: 10px; + float: right; + } + + .user-dropdown { + color: $sub-text-color; + cursor: pointer; + font-size: 12px; + } + .user-dropdown-item { + font-size: 12px; + color: $main-text-color; + } + + .hamburger-container { + line-height: 70px; + height: $header-height; + float: left; + padding: 0 10px; + } + + .el-submenu__title { + background: #00000000; + } + + ::-webkit-scrollbar { + width: 7px; + height: 7px; + background: none; + } + + ::-webkit-scrollbar-thumb { + background: #DDDEE0; + border-radius: 7px; + } + + ::-webkit-scrollbar-thumb:hover { + background: #A8A8A8; + } + .tree-select { + .el-tree-node__content { + height: 34px; + line-height: 34px; + padding-right: 10px; + } + } + + .tree-select.single-select-tree { + .el-tree-node.is-current > .el-tree-node__content > .el-tree-node__label { + color: $--color-primary; + font-weight: 700; + } + } + + .cell { + .operation-cell { + color: #006CDC; + cursor: pointer; + text-decoration: underline; + } + } + + .single-select-tree { + min-width: 200px!important; + } + + .base-card-header { + display: flex; + align-items: center; + height: 50px; + line-height: 50px; + } + + .base-card-operation { + flex-grow: 1; + display: flex; + justify-content: flex-end; + } + + .el-card__header { + padding: 0px 15px; + } + .el-card__body { + padding: 15px; + } + + .custom-cascader { + width: 200px!important; + } + + .no-scroll { + overflow: hidden; + } + + .custom-scroll .el-scrollbar__view { + overflow-x: hidden!important; + } + + .upload-img-del { + position: absolute; + height: 20px; + width: 20px; + line-height: 20px; + font-size: 16px; + top: 2px; + right: 2px; + color: #C0C4CC; + } + + .upload-img-del:hover { + color: #EF5E1C; + } + + .input-label { + display: inline-block; + height: 29px; + line-height: 28px; + } + + .input-progress { + height: 29px; + display: flex; + align-items: center; + } + + .input-item { + width: 100%!important; + } + + .table-header-gray { + background: rgba(237,237,237,1); + } + + .card-header { + display: flex; + justify-content: space-between; + padding: 10px 0px; + line-height: 28px; + } +} + +.ml20 { + margin-left: 20px; +} + +.mr20 { + margin-right: 20px; +} + +.mt20 { + margin-top: 20px; +} + +.mb20 { + margin-bottom: 20px; +} + +.pl20 { + padding-left: 20px; +} + +.pr20 { + padding-right: 20px; +} + +.pt20 { + padding-top: 20px; +} + +.pb20 { + padding-bottom: 20px; +} diff --git a/orange-demo-single-web/src/assets/style/element-color.scss b/orange-demo-single-web/src/assets/style/element-color.scss new file mode 100644 index 00000000..7487d64c --- /dev/null +++ b/orange-demo-single-web/src/assets/style/element-color.scss @@ -0,0 +1,25 @@ +$main-text-color: #303133; +$normal-text-color: #606266; +$sub-text-color: #909399; +$placeholder-text-color: #C0C4CC; + +$border-color1: #DCDFE6; +$border-color2: #E4E7ED; +$border-color3: #EBEEF5; +$border-color4: #F2F6FC; + +$success-color: #67C23A; +$warning-color: #E6A23C; +$danger-color: #F56C6C; +$info-color: #909399; +$--color-white: white; +$--color-primary: #EF5E1C !default; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */ diff --git a/orange-demo-single-web/src/assets/style/form-style.scss b/orange-demo-single-web/src/assets/style/form-style.scss new file mode 100644 index 00000000..f13e0e01 --- /dev/null +++ b/orange-demo-single-web/src/assets/style/form-style.scss @@ -0,0 +1,112 @@ +.form-advanced-manager { + .advance-filter-box { + position: absolute; + top: 100%; + left: 0px; + background-color: white; + width: 100%; + padding: 10px $box-padding-size 15px $box-padding-size; + } + + .title-box { + border-bottom: 1px solid $border-color; + padding: 0px 20px; + z-index: 20; + background-color: white; + height: $advanced-title-height; + + .title { + line-height: $advanced-title-height; + color: #606266; + } + + .menu-box { + position: absolute; + top: 0px; + right: 10px; + height: $advanced-title-height; + + .el-row { + margin: 10px 0px; + height: $advanced-title-height - 20; + } + } + } + + .advanced-right-box { + padding: 0px; + .gutter-box { + margin: (($advanced-title-height - 16)/2) 0px; + height: 16px; + width: 3px; + background-color: $--color-primary; + float: left + } + } +} + +.form-dict-manager { + .dict-title { + height: 50px; + line-height: 50px; + color: $main-text-color; + border-bottom: 1px solid $border-color1; + font-size: 14px; + + span { + margin-left: 20px; + } + } + + .dict-item { + width: 100%; + height: 40px; + line-height: 40px; + color: #606266; + cursor: pointer; + padding-left: 20px; + + &:hover { + background-color: $--color-primary-light-9; + } + } + + .active-dict-item { + border-left: 3px solid $--color-primary; + color: $--color-primary; + background-color: $--color-primary-light-9 !important; + } + + .el-scrollbar__bar.is-horizontal { + display: none!important; + } +} + + +.form-table-manager { + .advance-filter-box { + position: absolute; + padding: 20px; + top: 100%; + left: 0px; + background-color: white; + width: 100%; + padding: 10px $box-padding-size 15px $box-padding-size; + } +} + +.form-table-multi-select { + // +} + +.form-config { + padding: $box-padding-size; +} + +.form-multi-fragment { + // +} + +.form-single-fragment { + // +} \ No newline at end of file diff --git a/orange-demo-single-web/src/assets/style/index.scss b/orange-demo-single-web/src/assets/style/index.scss new file mode 100644 index 00000000..a88aa046 --- /dev/null +++ b/orange-demo-single-web/src/assets/style/index.scss @@ -0,0 +1,3 @@ +@import "../theme/index.css"; +@import "base.scss"; +@import "form-style.scss"; \ No newline at end of file diff --git a/orange-demo-single-web/src/assets/style/transition.scss b/orange-demo-single-web/src/assets/style/transition.scss new file mode 100644 index 00000000..49d81925 --- /dev/null +++ b/orange-demo-single-web/src/assets/style/transition.scss @@ -0,0 +1,31 @@ +/*fade*/ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/*fade*/ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all .5s; +} + +.breadcrumb-enter, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} + +.breadcrumb-move { + transition: all .5s; +} + +.breadcrumb-leave-active { + position: absolute; +} + diff --git a/orange-demo-single-web/src/assets/theme/fonts/element-icons.ttf b/orange-demo-single-web/src/assets/theme/fonts/element-icons.ttf new file mode 100644 index 00000000..91b74de3 Binary files /dev/null and b/orange-demo-single-web/src/assets/theme/fonts/element-icons.ttf differ diff --git a/orange-demo-single-web/src/assets/theme/fonts/element-icons.woff b/orange-demo-single-web/src/assets/theme/fonts/element-icons.woff new file mode 100644 index 00000000..02b9a253 Binary files /dev/null and b/orange-demo-single-web/src/assets/theme/fonts/element-icons.woff differ diff --git a/orange-demo-single-web/src/assets/theme/index.css b/orange-demo-single-web/src/assets/theme/index.css new file mode 100644 index 00000000..862181da --- /dev/null +++ b/orange-demo-single-web/src/assets/theme/index.css @@ -0,0 +1 @@ +@charset "UTF-8";.el-pagination--small .arrow.disabled,.el-table .hidden-columns,.el-table td.is-hidden>*,.el-table th.is-hidden>*,.el-table--hidden{visibility:hidden}.el-input__suffix,.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing),.el-message__closeBtn:focus,.el-message__content:focus,.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing),.el-rate:active,.el-rate:focus,.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing),.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}@font-face{font-family:element-icons;src:url(fonts/element-icons.woff) format("woff"),url(fonts/element-icons.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:""}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#FDA833}.el-pagination button:disabled{color:#C0C4CC;background-color:#FFF;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #FFF;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#C0C4CC;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#FDA833}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#C0C4CC}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#FDA833}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#FDA833;color:#FFF}.el-dialog,.el-pager li{background:#FFF;-webkit-box-sizing:border-box}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-date-table,.el-table th{-webkit-user-select:none;-moz-user-select:none}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-menu--collapse .el-menu .el-submenu,.el-menu--popup{min-width:200px}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#C0C4CC}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#FDA833}.el-pager li.active{color:#FDA833;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#FDA833}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #E4E7ED;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#FFF}.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{z-index:10;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#F5F7FA}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#FFF}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default::before{background:rgba(220,223,230,.5)}.el-dropdown .el-dropdown__caret-button:hover::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown-menu{position:absolute;top:0;left:0;padding:10px 0;margin:5px 0;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:rgb(255, 246, 235);color:rgb(253, 185, 92)}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #EBEEF5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px;background-color:#FFF}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0;background-color:#FFF}.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu::after,.el-menu::before{display:table;content:""}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #FDA833;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#FFF;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #FDA833;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;border:1px solid #E4E7ED;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;position:relative;-webkit-box-sizing:border-box;white-space:nowrap;list-style:none}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:rgb(255, 246, 235)}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#FDA833}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:rgb(255, 246, 235)}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:rgb(255, 246, 235)}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#FDA833}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{white-space:nowrap;background:#FFF;border:1px solid #DCDFE6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;position:relative;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#FDA833}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#FFF;background-color:#FDA833;border-color:#FDA833;-webkit-box-shadow:-1px 0 0 0 #FDA833;box-shadow:-1px 0 0 0 #FDA833}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#F2F6FC}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-popover,.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #FDA833;box-shadow:0 0 2px 2px #FDA833}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#FDA833}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #DCDFE6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#DCDFE6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#FFF}.el-switch.is-checked .el-switch__core{border-color:#FDA833;background-color:#FDA833}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #E4E7ED;border-radius:4px;background-color:#FFF;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#FDA833;background-color:#FFF}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#F5F7FA}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#FFF}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#F5F7FA}.el-select-dropdown__item.selected{color:#FDA833;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#E4E7ED}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#C0C4CC}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#FDA833}.el-select .el-input .el-select__caret{color:#C0C4CC;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#C0C4CC;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#E4E7ED}.el-select .el-input.is-focus .el-input__inner{border-color:#FDA833}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#C0C4CC;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select .el-tag__close{margin-top:-2px}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5}.el-select .el-tag__close.el-icon-close{background-color:#C0C4CC;right:-7px;top:0;color:#FFF}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#FFF}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table--mini,.el-table--small,.el-table__expand-icon{font-size:12px}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit td.gutter,.el-table--fit th.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th{background:#F5F7FA}.el-table th,.el-table tr{background-color:#FFF}.el-table td,.el-table th{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table td.is-center,.el-table th.is-center{text-align:center}.el-table td.is-right,.el-table th.is-right{text-align:right}.el-table td.gutter,.el-table th.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table--medium td,.el-table--medium th{padding:10px 0}.el-table--small td,.el-table--small th{padding:8px 0}.el-table--mini td,.el-table--mini th{padding:6px 0}.el-table .cell,.el-table--border td:first-child .cell,.el-table--border th:first-child .cell{padding-left:10px}.el-table tr input[type=checkbox]{margin:0}.el-table td,.el-table th.is-leaf{border-bottom:1px solid #EBEEF5}.el-table th.is-sortable{cursor:pointer}.el-table th{overflow:hidden;-ms-user-select:none;user-select:none}.el-table th>.cell{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th>.cell.highlight{color:#FDA833}.el-table th.required>div::before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-right:10px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #EBEEF5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#EBEEF5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border td,.el-table--border th,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #EBEEF5}.el-table--border th.gutter:last-of-type{border-bottom:1px solid #EBEEF5;border-bottom-width:1px}.el-table--border th,.el-table__fixed-right-patch{border-bottom:1px solid #EBEEF5}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#EBEEF5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#FFF}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td{border-top:1px solid #EBEEF5;background-color:#F5F7FA;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td{border-top:1px solid #EBEEF5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td,.el-table__header-wrapper tbody td{background-color:#F5F7FA;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-picker-panel,.el-table-filter{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #EBEEF5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#C0C4CC;top:5px}.el-table .sort-caret.descending{border-top-color:#C0C4CC;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#FDA833}.el-table .descending .sort-caret.descending{border-top-color:#FDA833}.el-table .hidden-columns{position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td{background-color:rgb(255, 246, 235)}.el-table__body tr.hover-row.current-row>td,.el-table__body tr.hover-row.el-table__row--striped.current-row>td,.el-table__body tr.hover-row.el-table__row--striped>td,.el-table__body tr.hover-row>td{background-color:#F5F7FA}.el-table__body tr.current-row>td{background-color:rgb(255, 246, 235)}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #EBEEF5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td{background-color:#F5F7FA}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #EBEEF5;border-radius:2px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:2px 0}.el-date-table td,.el-date-table td div{height:30px;-webkit-box-sizing:border-box}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:rgb(255, 246, 235);color:rgb(253, 185, 92)}.el-table-filter__list-item.is-active{background-color:#FDA833;color:#FFF}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #EBEEF5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#F2F6FC}.el-table-filter__bottom button:hover{color:#FDA833}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{padding:3px 0;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#C0C4CC}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#FDA833;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#FFF}.el-date-table td.available:hover{color:#FDA833}.el-date-table td.current:not(.disabled) span{color:#FFF;background-color:#FDA833}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#FFF}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#FDA833}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#F5F7FA;opacity:1;cursor:not-allowed;color:#C0C4CC}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#F2F6FC;border-radius:15px}.el-date-table td.selected div:hover{background-color:#F2F6FC}.el-date-table td.selected span{background-color:#FDA833;color:#FFF;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #EBEEF5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#FDA833;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#FFF}.el-month-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-month-table td.disabled .cell:hover{color:#C0C4CC}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#FDA833}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#F2F6FC}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#FFF}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#FFF;background-color:#FDA833}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#FDA833}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#FDA833;font-weight:700}.el-year-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-year-table td.disabled .cell:hover{color:#C0C4CC}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#FDA833}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#FFF}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #EBEEF5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#FDA833}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#FDA833;font-weight:700}.time-select-item.disabled{color:#E4E7ED;cursor:not-allowed}.time-select-item:hover{background-color:#F5F7FA;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#C0C4CC;float:left;line-height:32px}.el-date-editor .el-range-input,.el-date-editor .el-range-separator{height:100%;margin:0;text-align:center;display:inline-block;font-size:14px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;padding:0;width:39%;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input:-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::placeholder{color:#C0C4CC}.el-date-editor .el-range-separator{padding:0 5px;line-height:32px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#C0C4CC;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor.is-active,.el-range-editor.is-active:hover{border-color:#FDA833}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#E4E7ED}.el-range-editor.is-disabled input{background-color:#F5F7FA;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::placeholder{color:#C0C4CC}.el-range-editor.is-disabled .el-range-separator{color:#C0C4CC}.el-picker-panel{color:#606266;border:1px solid #E4E7ED;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#FFF;border-radius:4px;line-height:30px;margin:5px 0}.el-popover,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#FFF;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#FDA833}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#FDA833}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#FDA833}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#FFF;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#FFF;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#FDA833}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#F5F7FA;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#C0C4CC;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #E4E7ED;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-slider__button,.el-slider__button-wrapper{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #E4E7ED;border-bottom:1px solid #E4E7ED}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#FDA833}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #E4E7ED}.el-popover{position:absolute;background:#FFF;min-width:150px;border:1px solid #EBEEF5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#FFF;border-radius:4px;border:1px solid #EBEEF5;font-size:18px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#F56C6C}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#FDA833}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67C23A}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#E6A23C}.el-message-box__status.el-icon-error{color:#F56C6C}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#F56C6C;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#FDA833;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content::after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#FDA833;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-collapse-item__arrow,.el-tabs__nav{-webkit-transition:-webkit-transform .3s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#FDA833}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#E4E7ED;z-index:1}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after,.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #FDA833 inset;box-shadow:0 0 2px 2px #FDA833 inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs__item .el-icon-close:hover{background-color:#C0C4CC;color:#FFF}.el-tabs__item.is-active{color:#FDA833}.el-tabs__item:hover{color:#FDA833;cursor:pointer}.el-tabs__item.is-disabled{color:#C0C4CC;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #E4E7ED}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #E4E7ED;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__active-bar{display:none}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close,.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #E4E7ED;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#FFF}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--border-card{background:#FFF;border:1px solid #DCDFE6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#F5F7FA;border-bottom:1px solid #E4E7ED;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#FDA833;background-color:#FFF;border-right-color:#DCDFE6;border-left-color:#DCDFE6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#FDA833}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#C0C4CC}.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #DCDFE6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #E4E7ED;border-bottom:none;border-top:1px solid #E4E7ED;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #E4E7ED;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #E4E7ED;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #E4E7ED;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #E4E7ED}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #E4E7ED;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #E4E7ED;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #E4E7ED;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#FFF;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#FDA833}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#F5F7FA}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#FDA833;color:#fff}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree-node__content:hover{background-color:#F5F7FA}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#C0C4CC;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#C0C4CC}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #EBEEF5;position:fixed;background-color:#FFF;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67C23A}.el-notification .el-icon-error{color:#F56C6C}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#E6A23C}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#F5F7FA;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#FDA833}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#FDA833}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #DCDFE6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #DCDFE6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#E4E7ED;color:#E4E7ED}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#E4E7ED;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #DCDFE6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #DCDFE6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-upload-cover::after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#FFF}.el-tooltip__popper.is-light{background:#FFF;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#FFF}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#FFF}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#FFF}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#FFF}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{vertical-align:middle;display:inline-block}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#E4E7ED;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button{border-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#FDA833;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;transform:translateX(-50%);background-color:transparent;text-align:center;user-select:none;line-height:normal}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #FDA833;background-color:#FFF;border-radius:50%;-webkit-transition:.2s;transition:.2s;user-select:none}.el-image-viewer__btn,.el-step__icon-inner{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#FFF;transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #DCDFE6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#C0C4CC}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#FDA833}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row{position:relative}.el-loading-spinner .el-loading-text{color:#FDA833;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#FDA833;stroke-linecap:round}.el-loading-spinner i{color:#FDA833}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-upload--picture-card,.el-upload-dragger{-webkit-box-sizing:border-box;cursor:pointer}.el-col-0{width:0%}.el-col-offset-0{margin-left:0}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{position:relative;right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0%}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0%}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0%}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0%}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0%}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;box-sizing:border-box;width:148px;height:148px;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#FDA833;color:#FDA833}.el-upload:focus .el-upload-dragger{border-color:#FDA833}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;box-sizing:border-box;width:360px;height:180px;text-align:center;position:relative;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#C0C4CC;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #DCDFE6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#FDA833;font-style:normal}.el-upload-dragger:hover{border-color:#FDA833}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #FDA833}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67C23A}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#FDA833}.el-upload-list__item:hover{background-color:#F5F7FA}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#FDA833;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#FDA833}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#FFF}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#FFF;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#FFF;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#FFF;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner::after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67C23A}.el-progress.is-success .el-progress__text{color:#67C23A}.el-progress.is-warning .el-progress-bar__inner{background-color:#E6A23C}.el-progress.is-warning .el-progress__text{color:#E6A23C}.el-progress.is-exception .el-progress-bar__inner{background-color:#F56C6C}.el-progress.is-exception .el-progress__text{color:#F56C6C}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#EBEEF5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#FDA833;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-card,.el-message{border-radius:4px;overflow:hidden}.el-progress-bar__inner::after{height:100%}.el-progress-bar__innerText{color:#FFF;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;-webkit-box-sizing:border-box;box-sizing:border-box;border-width:1px;border-style:solid;border-color:#EBEEF5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67C23A}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#E6A23C}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#F56C6C}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#C0C4CC;font-size:16px}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67C23A}.el-message .el-icon-error{color:#F56C6C}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#E6A23C}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#F56C6C;border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#FDA833}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}.el-card{border:1px solid #EBEEF5;background-color:#FFF;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}.el-rate{height:20px;line-height:1}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#C0C4CC;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#F5F7FA}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#C0C4CC;border-color:#C0C4CC}.el-step__head.is-success{color:#67C23A;border-color:#67C23A}.el-step__head.is-error{color:#F56C6C;border-color:#F56C6C}.el-step__head.is-finish{color:#FDA833;border-color:#FDA833}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#FFF;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{display:inline-block;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#C0C4CC}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#C0C4CC}.el-step__title.is-success{color:#67C23A}.el-step__title.is-error{color:#F56C6C}.el-step__title.is-finish{color:#FDA833}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#C0C4CC}.el-step__description.is-success{color:#67C23A}.el-step__description.is-error{color:#F56C6C}.el-step__description.is-finish{color:#FDA833}.el-step.is-horizontal{display:inline-block}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#C0C4CC}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;top:0;left:0;position:absolute}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}.el-fade-in-enter,.el-fade-in-leave-active,.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active,.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #EBEEF5;border-bottom:1px solid #EBEEF5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#FFF;color:#303133;cursor:pointer;border-bottom:1px solid #EBEEF5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#FDA833}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#FFF;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #EBEEF5}.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#EBEEF5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#FFF;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#EBEEF5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#FFF}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#EBEEF5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#FFF;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#EBEEF5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#FFF}.el-tag{background-color:rgb(255, 246, 235);border-color:rgb(255, 238, 214);display:inline-block;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#FDA833;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#FDA833}.el-tag .el-tag__close{color:#FDA833}.el-tag .el-tag__close:hover{color:#FFF;background-color:#FDA833}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67C23A}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close::before{display:block}.el-tag--dark{background-color:#FDA833;border-color:#FDA833;color:#fff}.el-tag--dark.is-hit{border-color:#FDA833}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#FFF;background-color:rgb(253, 185, 92)}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67C23A}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:rgb(254, 220, 173);color:#FDA833}.el-tag--plain.is-hit{border-color:#FDA833}.el-tag--plain .el-tag__close{color:#FDA833}.el-tag--plain .el-tag__close:hover{color:#FFF;background-color:#FDA833}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67C23A}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{display:inline-block;position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#C0C4CC}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#FDA833}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#C0C4CC}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#FFF;border:1px solid #E4E7ED;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#C0C4CC;color:#FFF}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#F5F7FA}.el-cascader__suggestion-item.is-checked{color:#FDA833;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#C0C4CC}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#C0C4CC}.el-cascader__search-input:-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::placeholder{color:#C0C4CC}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #FDA833;box-shadow:0 0 3px 2px #FDA833}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{content:"";display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#FDA833;border-color:#FDA833}.el-color-dropdown__link-btn{cursor:pointer;color:#FDA833;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(primary,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty,.el-color-picker__icon{top:50%;left:50%;font-size:12px;position:absolute}.el-color-picker__empty{color:#999;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;width:100%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#FFF;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{position:relative;display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#FFF;background-image:none;border:1px solid #DCDFE6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea__inner:hover{border-color:#C0C4CC}.el-textarea__inner:focus{outline:0;border-color:#FDA833}.el-textarea .el-input__count{color:#909399;background:#FFF;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea.is-exceed .el-textarea__inner{border-color:#F56C6C}.el-textarea.is-exceed .el-input__count{color:#F56C6C}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#C0C4CC;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#FFF;line-height:initial;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#FFF;background-image:none;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#C0C4CC;text-align:center}.el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input__inner::placeholder{color:#C0C4CC}.el-input__inner:hover{border-color:#C0C4CC}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#FDA833;outline:0}.el-input__suffix{right:5px;transition:all .3s}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-input.is-exceed .el-input__inner{border-color:#F56C6C}.el-input.is-exceed .el-input__suffix .el-input__count{color:#F56C6C}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#F5F7FA;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #DCDFE6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#FFF;background-color:#FDA833;font-size:0}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #DCDFE6;background-color:#F5F7FA;color:#C0C4CC}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-transfer-panel{border:1px solid #EBEEF5;border-radius:4px;overflow:hidden;background:#FFF;display:inline-block;vertical-align:middle;width:200px;max-height:100%;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block}.el-transfer-panel__item+.el-transfer-panel__item{margin-left:0;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#FDA833}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#F5F7FA;margin:0;padding-left:15px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-divider__text,.el-link{font-weight:500;font-size:14px}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#FFF;margin:0;padding:0;border-top:1px solid #EBEEF5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0}.el-container.is-vertical,.el-drawer{-webkit-box-orient:vertical;-webkit-box-direction:normal}.el-aside,.el-header{-webkit-box-sizing:border-box}.el-container.is-vertical{-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-footer,.el-main{-webkit-box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;box-sizing:border-box;padding:20px}.el-footer{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;font-size:14px;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #E4E7ED}.el-timeline-item__icon{color:#FFF;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#E4E7ED;border-radius:50%;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-webkit-box;display:-ms-flexbox}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#FDA833}.el-timeline-item__node--success{background-color:#67C23A}.el-timeline-item__node--warning{background-color:#E6A23C}.el-timeline-item__node--danger{background-color:#F56C6C}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0}.el-link.is-underline:hover:after{content:"";position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #FDA833}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#FDA833}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#FDA833}.el-link.el-link--default.is-disabled{color:#C0C4CC}.el-link.el-link--primary{color:#FDA833}.el-link.el-link--primary:hover{color:rgb(253, 185, 92)}.el-link.el-link--primary.is-disabled{color:rgb(254, 212, 153)}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#F56C6C}.el-link.el-link--danger{color:#F56C6C}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67C23A}.el-link.el-link--success{color:#67C23A}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#E6A23C}.el-link.el-link--warning{color:#E6A23C}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#DCDFE6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;color:#303133}.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;color:#C0C4CC;vertical-align:middle}.el-image__preview{cursor:pointer}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;user-select:none}.el-button,.el-checkbox{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:40px}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{top:50%;width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button{margin-left:10px}.el-button:focus,.el-button:hover{color:#FDA833;border-color:rgb(254, 229, 194);background-color:rgb(255, 246, 235)}.el-button:active{color:rgb(228, 151, 46);border-color:rgb(228, 151, 46);outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#FFF;border-color:#FDA833;color:#FDA833}.el-button.is-active,.el-button.is-plain:active{color:rgb(228, 151, 46);border-color:rgb(228, 151, 46)}.el-button.is-plain:active{background:#FFF;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#FFF;border-color:#EBEEF5;color:#C0C4CC}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#FFF;background-color:#FDA833;border-color:#FDA833}.el-button--primary:focus,.el-button--primary:hover{background:rgb(253, 185, 92);border-color:rgb(253, 185, 92);color:#FFF}.el-button--primary.is-active,.el-button--primary:active{background:rgb(228, 151, 46);border-color:rgb(228, 151, 46);color:#FFF}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#FFF;background-color:rgb(254, 212, 153);border-color:rgb(254, 212, 153)}.el-button--primary.is-plain{color:#FDA833;background:rgb(255, 246, 235);border-color:rgb(254, 220, 173)}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#FDA833;border-color:#FDA833;color:#FFF}.el-button--primary.is-plain:active{background:rgb(228, 151, 46);border-color:rgb(228, 151, 46);color:#FFF;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:rgb(254, 203, 133);background-color:rgb(255, 246, 235);border-color:rgb(255, 238, 214)}.el-button--success{color:#FFF;background-color:#67C23A;border-color:#67C23A}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#FFF}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#FFF}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#FFF;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67C23A;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67C23A;border-color:#67C23A;color:#FFF}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#FFF;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#FFF;background-color:#E6A23C;border-color:#E6A23C}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#FFF}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#FFF}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#FFF;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#E6A23C;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#E6A23C;border-color:#E6A23C;color:#FFF}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#FFF;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#FFF;background-color:#F56C6C;border-color:#F56C6C}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#FFF}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#FFF}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#FFF;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#F56C6C;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#F56C6C;border-color:#F56C6C;color:#FFF}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#FFF;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#FFF;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#FFF}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#FFF}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#FFF;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#FFF}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#FFF;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--text,.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover,.el-button--text:active{border-color:transparent}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--mini,.el-button--small{font-size:12px;border-radius:3px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small,.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini.is-circle{padding:7px}.el-button--text{color:#FDA833;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:rgb(253, 185, 92);border-color:transparent;background-color:transparent}.el-button--text:active{color:rgb(228, 151, 46);background-color:transparent}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table;content:""}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button+.el-button{margin-left:0}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button:not(:last-child){margin-right:-1px}.el-button-group>.el-button.is-active,.el-button-group>.el-button:active,.el-button-group>.el-button:focus,.el-button-group>.el-button:hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0;border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--primary:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--success:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:first-child{border-right-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:last-child{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--info:not(:first-child):not(:last-child){border-left-color:rgba(255,255,255,.5);border-right-color:rgba(255,255,255,.5)}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #EBEEF5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#C0C4CC}.el-backtop,.el-calendar-table td.is-today{color:#FDA833}.el-calendar-table td{border-bottom:1px solid #EBEEF5;border-right:1px solid #EBEEF5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#F2F8FE}.el-calendar-table tr:first-child td{border-top:1px solid #EBEEF5}.el-calendar-table tr td:first-child{border-left:1px solid #EBEEF5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#F2F8FE}.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left::after{content:"";position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#DCDFE6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox-button__inner,.el-radio{font-weight:500;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#FDA833}.el-checkbox.is-bordered.is-disabled{border-color:#EBEEF5;cursor:not-allowed}.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#DCDFE6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#C0C4CC}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#C0C4CC}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#C0C4CC;border-color:#C0C4CC}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#FDA833;border-color:#FDA833}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#C0C4CC;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#FDA833}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#FDA833}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#FFF;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #DCDFE6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#FFF;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#FDA833}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #FFF;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#FDA833}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-radio,.el-radio__input{line-height:1;outline:0;white-space:nowrap}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#FFF;background-color:#FDA833;border-color:#FDA833;-webkit-box-shadow:-1px 0 0 0 rgb(254, 203, 133);box-shadow:-1px 0 0 0 rgb(254, 203, 133)}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#FDA833}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#EBEEF5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#FDA833}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-radio,.el-radio--medium.is-bordered .el-radio__label{font-size:14px}.el-radio{color:#606266;cursor:pointer;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-radio.is-bordered.is-checked{border-color:#FDA833}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#EBEEF5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#F5F7FA;border-color:#E4E7ED}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{cursor:pointer;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#F5F7FA}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#C0C4CC}.el-radio__input.is-disabled+span.el-radio__label{color:#C0C4CC;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#FDA833;background:#FDA833}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#FDA833}.el-radio__input.is-focus .el-radio__inner{border-color:#FDA833}.el-radio__inner{border:1px solid #DCDFE6;border-radius:100%;width:14px;height:14px;background-color:#FFF;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box}.el-radio__inner:hover{border-color:#FDA833}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#FFF;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #FDA833;box-shadow:0 0 2px 2px #FDA833}.el-radio__label{font-size:14px;padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px;font-size:14px}.el-cascader-panel.is-bordered{border:1px solid #E4E7ED;border-radius:4px}.el-cascader-menu{min-width:180px;-webkit-box-sizing:border-box;box-sizing:border-box;color:#606266;border-right:solid 1px #E4E7ED}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu:last-child .el-cascader-node{padding-right:20px}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;-webkit-box-sizing:border-box;box-sizing:border-box}.el-avatar,.el-drawer{-webkit-box-sizing:border-box;overflow:hidden}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#C0C4CC}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#FDA833;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#F5F7FA}.el-cascader-node.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;box-sizing:border-box;text-align:center;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-drawer,.el-drawer__header{display:-webkit-box;display:-ms-flexbox}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}.el-drawer.btt,.el-drawer.ttb,.el-drawer__container{left:0;right:0;width:100%}.el-drawer.ltr,.el-drawer.rtl,.el-drawer__container{top:0;bottom:0;height:100%}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@-webkit-keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@-webkit-keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@-webkit-keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}@keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#FFF;display:flex;-ms-flex-direction:column;flex-direction:column;-webkit-box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12)}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#72767b;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__title{margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__body>*{-webkit-box-sizing:border-box;box-sizing:border-box}.el-drawer__container{position:relative}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-popconfirm__main{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0} \ No newline at end of file diff --git a/orange-demo-single-web/src/components/DateRange/index.vue b/orange-demo-single-web/src/components/DateRange/index.vue new file mode 100644 index 00000000..f4dd2c0b --- /dev/null +++ b/orange-demo-single-web/src/components/DateRange/index.vue @@ -0,0 +1,305 @@ + + + + + diff --git a/orange-demo-single-web/src/components/Dialog/index.js b/orange-demo-single-web/src/components/Dialog/index.js new file mode 100644 index 00000000..0e5c545f --- /dev/null +++ b/orange-demo-single-web/src/components/Dialog/index.js @@ -0,0 +1,77 @@ +import $ from 'jquery'; +import Vue from 'vue'; +import router from '@/router'; +import store from '@/store'; + +window.jQuery = $; +const layer = require('layui-layer'); + +class Dialog { + /** + * 关闭弹窗 + * @param {*} index 要关闭的弹窗的index + */ + static close (index) { + layer.close(index); + } + /** + * 关闭所有弹窗 + */ + static closeAll () { + layer.closeAll(); + } + /** + * 打开弹窗 + * @param {*} title 弹窗标题 + * @param {*} component 弹窗内容的组件 + * @param {*} options 弹窗设置(详情请见layui官网) + * @param {*} params 弹窗组件参数 + */ + static show (title, component, options, params) { + return new Promise((resolve, reject) => { + let layerOptions = { + title: title, + type: 1, + skin: 'layer-dialog', + resize: false, + offset: 'auto', + zIndex: 1000, + index: 0, + contentDom: null + }; + + layerOptions = {...layerOptions, ...options}; + layerOptions.end = () => { + if (layerOptions.contentDom) document.body.removeChild(layerOptions.contentDom); + } + + let observer = { + cancel: function (isSuccess = false) { + layer.close(this.index); + if (isSuccess) { + resolve(); + } else { + reject(); + } + }, + index: -1 + } + layerOptions.cancel = () => { + reject(); + } + let dom = document.createElement('div'); + document.body.appendChild(dom); + let Content = Vue.extend(component); + let vueObj = new Content({router: router, store: store, propsData: params}); + vueObj.observer = observer; + vueObj.$mount(dom); + layerOptions.contentDom = vueObj.$el; + layerOptions.content = $(layerOptions.contentDom); + observer.index = layer.open(layerOptions); + }); + } +} + +Vue.prototype.$dialog = Dialog; + +export default Dialog; diff --git a/orange-demo-single-web/src/components/FilterBox/index.vue b/orange-demo-single-web/src/components/FilterBox/index.vue new file mode 100644 index 00000000..d7350358 --- /dev/null +++ b/orange-demo-single-web/src/components/FilterBox/index.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/orange-demo-single-web/src/components/Hamburger/index.vue b/orange-demo-single-web/src/components/Hamburger/index.vue new file mode 100644 index 00000000..6df80299 --- /dev/null +++ b/orange-demo-single-web/src/components/Hamburger/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/orange-demo-single-web/src/components/IconSelect/icon.json b/orange-demo-single-web/src/components/IconSelect/icon.json new file mode 100644 index 00000000..13f2f58b --- /dev/null +++ b/orange-demo-single-web/src/components/IconSelect/icon.json @@ -0,0 +1,280 @@ +[ + "el-icon-delete-solid", + "el-icon-delete", + "el-icon-s-tools", + "el-icon-setting", + "el-icon-user-solid", + "el-icon-user", + "el-icon-phone", + "el-icon-phone-outline", + "el-icon-more", + "el-icon-more-outline", + "el-icon-star-on", + "el-icon-star-off", + "el-icon-s-goods", + "el-icon-goods", + "el-icon-warning", + "el-icon-warning-outline", + "el-icon-question", + "el-icon-info", + "el-icon-remove", + "el-icon-circle-plus", + "el-icon-success", + "el-icon-error", + "el-icon-zoom-in", + "el-icon-zoom-out", + "el-icon-remove-outline", + "el-icon-circle-plus-outline", + "el-icon-circle-check", + "el-icon-circle-close", + "el-icon-s-help", + "el-icon-help", + "el-icon-minus", + "el-icon-plus", + "el-icon-check", + "el-icon-close", + "el-icon-picture", + "el-icon-picture-outline", + "el-icon-picture-outline-round", + "el-icon-upload", + "el-icon-upload2", + "el-icon-download", + "el-icon-camera-solid", + "el-icon-camera", + "el-icon-video-camera-solid", + "el-icon-video-camera", + "el-icon-message-solid", + "el-icon-bell", + "el-icon-s-cooperation", + "el-icon-s-order", + "el-icon-s-platform", + "el-icon-s-fold", + "el-icon-s-unfold", + "el-icon-s-operation", + "el-icon-s-promotion", + "el-icon-s-home", + "el-icon-s-release", + "el-icon-s-ticket", + "el-icon-s-management", + "el-icon-s-open", + "el-icon-s-shop", + "el-icon-s-marketing", + "el-icon-s-flag", + "el-icon-s-comment", + "el-icon-s-finance", + "el-icon-s-claim", + "el-icon-s-custom", + "el-icon-s-opportunity", + "el-icon-s-data", + "el-icon-s-check", + "el-icon-s-grid", + "el-icon-menu", + "el-icon-share", + "el-icon-d-caret", + "el-icon-caret-left", + "el-icon-caret-right", + "el-icon-caret-bottom", + "el-icon-caret-top", + "el-icon-bottom-left", + "el-icon-bottom-right", + "el-icon-back", + "el-icon-right", + "el-icon-bottom", + "el-icon-top", + "el-icon-top-left", + "el-icon-top-right", + "el-icon-arrow-left", + "el-icon-arrow-right", + "el-icon-arrow-down", + "el-icon-arrow-up", + "el-icon-d-arrow-left", + "el-icon-d-arrow-right", + "el-icon-video-pause", + "el-icon-video-play", + "el-icon-refresh", + "el-icon-refresh-right", + "el-icon-refresh-left", + "el-icon-finished", + "el-icon-sort", + "el-icon-sort-up", + "el-icon-sort-down", + "el-icon-rank", + "el-icon-loading", + "el-icon-view", + "el-icon-c-scale-to-original", + "el-icon-date", + "el-icon-edit", + "el-icon-edit-outline", + "el-icon-folder", + "el-icon-folder-opened", + "el-icon-folder-add", + "el-icon-folder-remove", + "el-icon-folder-delete", + "el-icon-folder-checked", + "el-icon-tickets", + "el-icon-document-remove", + "el-icon-document-delete", + "el-icon-document-copy", + "el-icon-document-checked", + "el-icon-document", + "el-icon-document-add", + "el-icon-printer", + "el-icon-paperclip", + "el-icon-takeaway-box", + "el-icon-search", + "el-icon-monitor", + "el-icon-attract", + "el-icon-mobile", + "el-icon-scissors", + "el-icon-umbrella", + "el-icon-headset", + "el-icon-brush", + "el-icon-mouse", + "el-icon-coordinate", + "el-icon-magic-stick", + "el-icon-reading", + "el-icon-data-line", + "el-icon-data-board", + "el-icon-pie-chart", + "el-icon-data-analysis", + "el-icon-collection-tag", + "el-icon-film", + "el-icon-suitcase", + "el-icon-suitcase-1", + "el-icon-receiving", + "el-icon-collection", + "el-icon-files", + "el-icon-notebook-1", + "el-icon-notebook-2", + "el-icon-toilet-paper", + "el-icon-office-building", + "el-icon-school", + "el-icon-table-lamp", + "el-icon-house", + "el-icon-no-smoking", + "el-icon-smoking", + "el-icon-shopping-cart-full", + "el-icon-shopping-cart-1", + "el-icon-shopping-cart-2", + "el-icon-shopping-bag-1", + "el-icon-shopping-bag-2", + "el-icon-sold-out", + "el-icon-sell", + "el-icon-present", + "el-icon-box", + "el-icon-bank-card", + "el-icon-money", + "el-icon-coin", + "el-icon-wallet", + "el-icon-discount", + "el-icon-price-tag", + "el-icon-news", + "el-icon-guide", + "el-icon-male", + "el-icon-female", + "el-icon-thumb", + "el-icon-cpu", + "el-icon-link", + "el-icon-connection", + "el-icon-open", + "el-icon-turn-off", + "el-icon-set-up", + "el-icon-chat-round", + "el-icon-chat-line-round", + "el-icon-chat-square", + "el-icon-chat-dot-round", + "el-icon-chat-dot-square", + "el-icon-chat-line-square", + "el-icon-message", + "el-icon-postcard", + "el-icon-position", + "el-icon-turn-off-microphone", + "el-icon-microphone", + "el-icon-close-notification", + "el-icon-bangzhu", + "el-icon-time", + "el-icon-odometer", + "el-icon-crop", + "el-icon-aim", + "el-icon-switch-button", + "el-icon-full-screen", + "el-icon-copy-document", + "el-icon-mic", + "el-icon-stopwatch", + "el-icon-medal-1", + "el-icon-medal", + "el-icon-trophy", + "el-icon-trophy-1", + "el-icon-first-aid-kit", + "el-icon-discover", + "el-icon-place", + "el-icon-location", + "el-icon-location-outline", + "el-icon-location-information", + "el-icon-add-location", + "el-icon-delete-location", + "el-icon-map-location", + "el-icon-alarm-clock", + "el-icon-timer", + "el-icon-watch-1", + "el-icon-watch", + "el-icon-lock", + "el-icon-unlock", + "el-icon-key", + "el-icon-service", + "el-icon-mobile-phone", + "el-icon-bicycle", + "el-icon-truck", + "el-icon-ship", + "el-icon-basketball", + "el-icon-football", + "el-icon-soccer", + "el-icon-baseball", + "el-icon-wind-power", + "el-icon-light-rain", + "el-icon-lightning", + "el-icon-heavy-rain", + "el-icon-sunrise", + "el-icon-sunrise-1", + "el-icon-sunset", + "el-icon-sunny", + "el-icon-cloudy", + "el-icon-partly-cloudy", + "el-icon-cloudy-and-sunny", + "el-icon-moon", + "el-icon-moon-night", + "el-icon-dish", + "el-icon-dish-1", + "el-icon-food", + "el-icon-chicken", + "el-icon-fork-spoon", + "el-icon-knife-fork", + "el-icon-burger", + "el-icon-tableware", + "el-icon-sugar", + "el-icon-dessert", + "el-icon-ice-cream", + "el-icon-hot-water", + "el-icon-water-cup", + "el-icon-coffee-cup", + "el-icon-cold-drink", + "el-icon-goblet", + "el-icon-goblet-full", + "el-icon-goblet-square", + "el-icon-goblet-square-full", + "el-icon-refrigerator", + "el-icon-grape", + "el-icon-watermelon", + "el-icon-cherry", + "el-icon-apple", + "el-icon-pear", + "el-icon-orange", + "el-icon-coffee", + "el-icon-ice-tea", + "el-icon-ice-drink", + "el-icon-milk-tea", + "el-icon-potato-strips", + "el-icon-lollipop", + "el-icon-ice-cream-square", + "el-icon-ice-cream-round" +] \ No newline at end of file diff --git a/orange-demo-single-web/src/components/IconSelect/index.vue b/orange-demo-single-web/src/components/IconSelect/index.vue new file mode 100644 index 00000000..06be852b --- /dev/null +++ b/orange-demo-single-web/src/components/IconSelect/index.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/orange-demo-single-web/src/components/InputNumberRange/index.vue b/orange-demo-single-web/src/components/InputNumberRange/index.vue new file mode 100644 index 00000000..94f59ba4 --- /dev/null +++ b/orange-demo-single-web/src/components/InputNumberRange/index.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/orange-demo-single-web/src/components/Progress/index.vue b/orange-demo-single-web/src/components/Progress/index.vue new file mode 100644 index 00000000..2225e489 --- /dev/null +++ b/orange-demo-single-web/src/components/Progress/index.vue @@ -0,0 +1,44 @@ + + + diff --git a/orange-demo-single-web/src/components/RichEditor/index.vue b/orange-demo-single-web/src/components/RichEditor/index.vue new file mode 100644 index 00000000..d839a475 --- /dev/null +++ b/orange-demo-single-web/src/components/RichEditor/index.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/orange-demo-single-web/src/components/TableProgressColumn/index.vue b/orange-demo-single-web/src/components/TableProgressColumn/index.vue new file mode 100644 index 00000000..7e82a4eb --- /dev/null +++ b/orange-demo-single-web/src/components/TableProgressColumn/index.vue @@ -0,0 +1,119 @@ + + + diff --git a/orange-demo-single-web/src/components/TreeSelect/index.vue b/orange-demo-single-web/src/components/TreeSelect/index.vue new file mode 100644 index 00000000..9099558f --- /dev/null +++ b/orange-demo-single-web/src/components/TreeSelect/index.vue @@ -0,0 +1,300 @@ + + + + + diff --git a/orange-demo-single-web/src/core/config/development.js b/orange-demo-single-web/src/core/config/development.js new file mode 100644 index 00000000..c866c9ed --- /dev/null +++ b/orange-demo-single-web/src/core/config/development.js @@ -0,0 +1,4 @@ +module.exports = { + baseUrl: 'http://localhost:8082/', + projectName: '橙单生成器项目' +} diff --git a/orange-demo-single-web/src/core/config/index.js b/orange-demo-single-web/src/core/config/index.js new file mode 100644 index 00000000..be8f130e --- /dev/null +++ b/orange-demo-single-web/src/core/config/index.js @@ -0,0 +1,12 @@ +const projectConfig = require('../config/' + process.env.NODE_ENV); + +export const globalConfig = { + httpOption: { + showMask: true, + showError: true + }, + axiosOption: { + } +}; + +export default projectConfig; diff --git a/orange-demo-single-web/src/core/config/production.js b/orange-demo-single-web/src/core/config/production.js new file mode 100644 index 00000000..c866c9ed --- /dev/null +++ b/orange-demo-single-web/src/core/config/production.js @@ -0,0 +1,4 @@ +module.exports = { + baseUrl: 'http://localhost:8082/', + projectName: '橙单生成器项目' +} diff --git a/orange-demo-single-web/src/core/directive/sortable.js b/orange-demo-single-web/src/core/directive/sortable.js new file mode 100644 index 00000000..410de2d9 --- /dev/null +++ b/orange-demo-single-web/src/core/directive/sortable.js @@ -0,0 +1,14 @@ +import Vue from 'vue' +import { SortableData } from './sortableData'; + +/** + * 拖拽排序指令 + */ +Vue.directive('sortable', { + inserted: function (el, binding, vnode) { + let sortableData = binding.value; + if (sortableData == null || !(sortableData instanceof SortableData)) return; + + sortableData.init(vnode.elm); + } +}); diff --git a/orange-demo-single-web/src/core/directive/sortableData.js b/orange-demo-single-web/src/core/directive/sortableData.js new file mode 100644 index 00000000..4993e08a --- /dev/null +++ b/orange-demo-single-web/src/core/directive/sortableData.js @@ -0,0 +1,60 @@ +import sortable from 'sortablejs' +/** + * 拖拽排序对象 + * expample + *
    + *
  • A
  • + *
  • B
  • + *
  • C
  • + *
  • D
  • + *
+ */ +export class SortableData { + constructor (data, group) { + this.list = data; + this.group = group; + this.ghostClass = 'sortable-ghost'; + this.sortable = null; + this.disabled = false; + }; + + setData (list) { + this.list = list; + } + + getElement (el) { + return el; + }; + + onEnd (oldIndex, newIndex) { + if (oldIndex === newIndex || this.list == null) return; + let targetRow = this.list.splice(oldIndex, 1)[0] + this.list.splice(newIndex, 0, targetRow); + }; + + init (el) { + var _this = this; + + var _option = {}; + if (this.ghostClass != null) _option.ghostClass = this.ghostClass; + if (this.group != null) _option.group = this.group; + if (this.disabled != null) _option.disabled = this.disabled; + // 列表中能拖动的dom的选择器(例如:.drag-item) + if (this.draggable != null) _option.draggable = this.draggable; + // 列表中拖动项,拖动把柄的选择器,只有点击这个选择出来的dom才可以开始拖动(例如:.drag-handle) + if (this.handle != null) _option.handle = this.handle; + _option.setData = function (dataTransfer) { + dataTransfer.setData('Text', ''); + }; + _option.onEnd = function (evt) { + _this.onEnd(evt.oldIndex, evt.newIndex); + }; + + this.sortable = sortable.create(_this.getElement(el), _option); + }; + + release () { + if (this.sortable != null) this.sortable.destroy(); + this.sortable = null; + } +}; diff --git a/orange-demo-single-web/src/core/http/index.js b/orange-demo-single-web/src/core/http/index.js new file mode 100644 index 00000000..ed4b2be0 --- /dev/null +++ b/orange-demo-single-web/src/core/http/index.js @@ -0,0 +1,185 @@ +import Vue from 'vue'; +import { Loading, Message } from 'element-ui'; +import request from './request'; +import requestUrl from './requestUrl'; +import merge from 'lodash/merge'; +import { globalConfig } from '@/core/config'; + +/** + * 遮罩管理,多次调用支持引用计数 + */ +class LoadingManager { + constructor (options) { + this.options = options; + this.refCount = 0; + this.loading = undefined; + } + + showMask () { + this.loading = Loading.service(this.options); + this.refCount++; + } + + hideMask () { + if (this.refCount <= 1 && this.loading != null) { + this.loading.close(); + this.loading = null; + } + this.refCount--; + this.refCount = Math.max(0, this.refCount); + } +} + +const loadingManager = new LoadingManager({ + fullscreen: true, + background: 'rgba(0, 0, 0, 0.1)' +}); + +/** + * post请求 + * @param {String} url 请求的url + * @param {Object} params 请求参数 + * @param {Object} options axios设置项 + * @returns {Promise} + */ +const fetchPost = function (url, params, options) { + if (options == null) return {}; + let tempOptions = { + ...options, + method: 'post', + url: requestUrl(url), + data: params + }; + + return request(tempOptions); +}; +/** + * get请求 + * @param {String} url 请求的url + * @param {Object} params 请求参数 + * @param {Object} options axios设置项 + * @returns {Promise} + */ +const fetchGet = function (url, params, options) { + if (options == null) return {}; + let tempOptions = { + ...options, + method: 'get', + url: requestUrl(url), + params + }; + return request(tempOptions); +}; +/** + * 下载请求 + * @param {String} url 请求的url + * @param {Object} params 请求参数 + * @param {String} fileName 下载后保存的文件名 + * @returns {Promise} + */ +const fetchDownload = function (url, params, fileName) { + return new Promise((resolve, reject) => { + request({ + url: requestUrl(url), + method: 'post', + data: params, + responseType: 'blob', + transformResponse: function (data) { + return (data instanceof Blob && data.size > 0) ? data : undefined; + } + }).then(res => { + if (res.data == null) { + reject(new Error('下载文件失败')); + } else { + let blobData = new Blob([res.data], { type: 'application/octet-stream' }); + let blobUrl = window.URL.createObjectURL(blobData); + let linkDom = document.createElement('a'); + linkDom.style.display = 'none'; + linkDom.href = blobUrl; + linkDom.setAttribute('download', fileName); + if (typeof linkDom.download === 'undefined') { + linkDom.setAttribute('target', '_blank'); + } + document.body.appendChild(linkDom); + linkDom.click(); + document.body.removeChild(linkDom); + window.URL.revokeObjectURL(blobData); + resolve(); + } + }).catch(e => { + if (e instanceof Blob) { + let reader = new FileReader(); + reader.onload = function () { + let jsonObj = JSON.parse(reader.result); + reject((jsonObj || {}).errorMessage || '下载文件失败'); + } + reader.readAsText(e); + } else { + reject(e); + } + }); + }); +} +/** + * 数据请求 + * @param {String} url 请求的url + * @param {String} type 请求类型(get,post) + * @param {Object} params 请求参数 + * @param {Object} axiosOption axios设置 + * @param {Object} options 显示设置 + */ +const doUrl = function (url, type, params, axiosOption, options) { + options = merge(globalConfig.httpOption, options); + axiosOption = merge(globalConfig.axiosOption, axiosOption); + if (type == null || type === '') type = 'post'; + + return new Promise((resolve, reject) => { + if (options.showMask) loadingManager.showMask(); + let ajaxCall = null; + if (type.toLowerCase() === 'get') { + ajaxCall = fetchGet(url, params, axiosOption); + } else if (type.toLowerCase() === 'post') { + ajaxCall = fetchPost(url, params, axiosOption); + } + + if (ajaxCall != null) { + ajaxCall.then(res => { + if (options.showMask) loadingManager.hideMask(); + if (res.data && res.data.success) { + resolve(res.data); + } else { + if (options.showError) { + Message.error({ + showClose: true, + message: res.data.errorMessage ? res.data.errorMessage : '数据请求失败' + }); + } + reject(res.data); + } + }).catch(e => { + if (options.showMask) loadingManager.hideMask(); + if (options.showError) { + Message.error({ + showClose: true, + message: e.errorMessage ? e.errorMessage : '网络请求错误' + }); + } + reject(e); + }); + } else { + if (options.showMask) loadingManager.hideMask(); + reject(new Error('错误的请求类型 - ' + type)); + } + }); +}; + +Vue.prototype.download = fetchDownload; +Vue.prototype.doUrl = doUrl; +Vue.prototype.loadingManager = loadingManager; + +export default { + doUrl, + fetchPost, + fetchGet, + fetchDownload +} diff --git a/orange-demo-single-web/src/core/http/request.js b/orange-demo-single-web/src/core/http/request.js new file mode 100644 index 00000000..939ed4ce --- /dev/null +++ b/orange-demo-single-web/src/core/http/request.js @@ -0,0 +1,73 @@ +import axios from 'axios'; +import router from '@/router'; +import dialog from '@/components/Dialog'; +import JSONbig from 'json-bigint'; + +// 创建axios实例 +const service = axios.create({ + timeout: 1000 * 30, + withCredentials: true, + headers: { + // 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' + 'Content-Type': 'application/json; charset=utf-8' + }, + transformResponse: [ + function (data) { + if (typeof data === 'string') { + const JSONbigString = new JSONbig({storeAsString: true}); + return JSONbigString.parse(data); + } else { + return data; + } + } + ] +}) + +// request拦截器 +service.interceptors.request.use( + config => { + let token = window.sessionStorage.getItem('token'); + let menuIdJsonStr = window.sessionStorage.getItem('currentMenuId'); + let currentMenuId; + if (menuIdJsonStr != null) { + currentMenuId = (JSON.parse(menuIdJsonStr) || {}).data; + } + if (token != null) config.headers['Authorization'] = token; + if (currentMenuId != null) config.headers['MenuId'] = currentMenuId; + return config + }, error => { + return Promise.reject(error) + } +); + +// response拦截器 +service.interceptors.response.use( + response => { + if (response.data && response.data.errorCode === 'UNAUTHORIZED_LOGIN') { // 401, token失效 + dialog.closeAll(); + router.push({ name: 'login' }) + } else { + if (response.headers['refreshedtoken'] != null) { + window.sessionStorage.setItem('token', response.headers['refreshedtoken']); + } + } + return response + }, error => { + let response = error.response; + + if (response && response.data) { + if (response.data.errorCode === 'UNAUTHORIZED_LOGIN') { + dialog.closeAll(); + router.push({ name: 'login' }); + } + + return Promise.reject(response.data); + } else { + return Promise.reject(new Error({ + errorMessage: '数据获取失败,请稍后再试' + })); + } + } +); + +export default service diff --git a/orange-demo-single-web/src/core/http/requestUrl.js b/orange-demo-single-web/src/core/http/requestUrl.js new file mode 100644 index 00000000..96a921e1 --- /dev/null +++ b/orange-demo-single-web/src/core/http/requestUrl.js @@ -0,0 +1,27 @@ +import projectConfig from '@/core/config'; +import { objectToQueryString } from '@/utils'; +console.log(process.env.NODE_ENV, projectConfig); + +/** + * 请求地址统一处理/组装 + * @param actionName action方法名称 + */ +export default function (actionName) { + if (actionName != null && actionName !== '') { + if (actionName.substr(0, 1) === '/') actionName = actionName.substr(1); + } + return projectConfig.baseUrl + actionName; +} + +export function buildGetUrl (actionName, params) { + let queryString = objectToQueryString(params); + if (actionName != null && actionName !== '') { + if (actionName.substr(0, 1) === '/') actionName = actionName.substr(1); + } + + return projectConfig.baseUrl + actionName + (queryString == null ? '' : ('?' + queryString)); +} + +export { + projectConfig +} diff --git a/orange-demo-single-web/src/core/mixins/global.js b/orange-demo-single-web/src/core/mixins/global.js new file mode 100644 index 00000000..eb756b40 --- /dev/null +++ b/orange-demo-single-web/src/core/mixins/global.js @@ -0,0 +1,117 @@ +import Vue from 'vue'; +import Request from '@/core/http/request.js'; +import { mapMutations, mapGetters } from 'vuex'; + +// 全局mixin对象 +const globalMixin = { + data () { + return { + isHttpLoading: false + } + }, + methods: { + /** + * 是否显示遮罩 + * @param {Boolean} isShow 是否显示 + */ + showMask (isShow) { + isShow ? this.loadingManager.showMask() : this.loadingManager.hideMask(); + }, + /** + * 判读用户是否有权限 + * @param {String} permCode 权限字 + */ + checkPermCodeExist (permCode) { + if (this.getUserInfo.permCodeSet != null) { + return this.getUserInfo.permCodeSet.has(permCode); + } else { + return this.getUserInfo.isAdmin; + } + }, + /** + * 将输入的值转换成指定的类型 + * @param {Any} value + * @param {String} type 要转换的类型(integer、float、boolean、string) + */ + parseParams (value, type = 'string') { + if (value == null) return value; + switch (type) { + case 'integer': return Number.parseInt(value); + case 'float': return Number.parseFloat(value); + case 'boolean': return (value === 'true' || value); + default: return String(value); + } + }, + /** + * 将输入值转换为执行的类型数组 + * @param {Array} value 输入数组 + * @param {String} type 要转换的类型(integer、float、boolean、string) + */ + parseArrayParams (value, type = 'string') { + if (Array.isArray(value)) { + return value.map((item) => { + switch (type) { + case 'integer': return Number.parseInt(item); + case 'float': return Number.parseFloat(item); + case 'boolean': return (item === 'true' || item); + default: return String(item); + } + }); + } else { + return []; + } + }, + /** + * 下载上传的文件 + * @param {*} url 下载文件的url + * @param {*} fileName 下载文件名 + */ + downloadFile (url, fileName) { + console.log(fileName); + Request({ + url: url, + method: 'get', + responseType: 'blob', + transformResponse: function (data) { + console.log(data); + return data; + } + }).then(res => { + console.log(res); + let data = res.data; + if (res.status === 200 && data instanceof Blob) { + let url = window.URL.createObjectURL(data); + let link = document.createElement('a'); + link.style.display = 'none'; + link.href = url; + link.setAttribute('download', fileName); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } else { + this.$message.error('下载文件失败'); + } + }).catch(e => { + let reader = new FileReader(); + reader.onload = () => { + let jsonObj = JSON.parse(reader.result); + this.$message.error((jsonObj || {}).errorMessage || '下载文件失败'); + } + reader.readAsText(e); + }); + }, + ...mapMutations(['setLoadingStatus']) + }, + computed: { + ...mapGetters(['getUserInfo']) + }, + watch: { + 'loadingManager.loading': { + handler: function (newValue) { + this.isHttpLoading = (newValue != null); + } + } + } +} + +Vue.mixin(globalMixin); diff --git a/orange-demo-single-web/src/core/mixins/index.js b/orange-demo-single-web/src/core/mixins/index.js new file mode 100644 index 00000000..8a18b8b2 --- /dev/null +++ b/orange-demo-single-web/src/core/mixins/index.js @@ -0,0 +1,293 @@ +import projectConfig from '@/core/config'; +import { buildGetUrl } from '@/core/http/requestUrl.js'; +import { formatDate, parseDate } from 'element-ui/src/utils/date-util'; +import { mapMutations } from 'vuex'; +/** + * 上传文件组件相关方法 + */ +const uploadMixin = { + methods: { + /** + * 解析返回的上传文件数据 + * @param {String} jsonData 上传文件数据,[{name, downloadUri, filename}] + * @param {Object} params 上传文件的参数 + * @returns {Array} 上传文件信息,[{name, downloadUri, filename, url}] + */ + parseUploadData (jsonData, params) { + let pathList = []; + if (jsonData != null) { + try { + pathList = JSON.parse(jsonData); + } catch (e) { + console.error(e); + } + } + + return pathList.map((item) => { + let downloadParams = {...params}; + downloadParams.filename = item.filename; + return { + ...item, + url: this.getUploadFileUrl(item, downloadParams) + } + }); + }, + /** + * 获得上传文件url列表 + * @param {*} jsonData 上传文件数据,[{name, downloadUri, filename}] + * @param {*} params 上传文件的参数 + * @returns {Array} 文件url列表 + */ + getPictureList (jsonData, params) { + let tempList = this.parseUploadData(jsonData, params); + if (Array.isArray(tempList)) { + return tempList.map(item => item.url); + } else { + return []; + } + }, + /** + * 将选中文件信息格式化成json信息 + * @param {Array} fileList 上传文件列表,[{name, fileUrl, data}] + */ + fileListToJson (fileList) { + if (Array.isArray(fileList)) { + return JSON.stringify(fileList.map((item) => { + return { + name: item.name, + downloadUri: item.downloadUri || item.response.data.downloadUri, + filename: item.filename || item.response.data.filename + } + })); + } else { + return undefined; + } + }, + /** + * 获得上传文件url + * @param {*} item 上传文件 + * @param {*} params 上传文件的参数 + */ + getUploadFileUrl (item, params) { + if (item == null || item.downloadUri == null) { + return null; + } else { + let menuIdJsonStr = window.sessionStorage.getItem('currentMenuId'); + let currentMenuId; + if (menuIdJsonStr != null) { + currentMenuId = (JSON.parse(menuIdJsonStr) || {}).data; + } + params.Authorization = window.sessionStorage.getItem('token'); + params.MenuId = currentMenuId; + return buildGetUrl(item.downloadUri, params); + } + }, + /** + * 获得上传接口 + * @param {*} url 上传路径 + */ + getUploadActionUrl (url) { + if (url != null && url[0] === '/') { + url = url.substr(1); + } + return projectConfig.baseUrl + url; + }, + /** + * 上传文件是否图片文件 + * @param {*} file 上传文件 + */ + pictureFile (file) { + if (['image/jpeg', 'image/jpg', 'image/png'].indexOf(file.type) !== -1) { + return true; + } else { + this.$message.error('图片文件格式不正确,请重新选择'); + return false; + } + } + }, + computed: { + getUploadHeaders () { + let token = window.sessionStorage.getItem('token'); + return { + Authorization: token + } + } + } +}; + +const allowStatsType = [ + 'time', + 'datetime', + 'day', + 'month', + 'year' +]; +/** + * 日期相关方法 + */ +const statsDateRangeMixin = { + methods: { + /** + * 根据输入的日期获得日期范围(例如:输入2019-12-12,输出['2019-12-12 00:00:00', '2019-12-12 23:59:59']) + * @param {Date|String} date 要转换的日期 + * @param {String} statsType 转换类型(day, month, year) + * @param {String} format 输出格式 + */ + getDateRangeFilter (date, statsType = 'day', format = 'yyyy-MM-dd HH:mm:ss') { + if (date == null) return []; + + statsType = allowStatsType.indexOf(statsType) === -1 ? 'day' : statsType; + date = date.substr(0, date.indexOf(' ')); + let tempList = date.split('-'); + let year = Number.parseInt(tempList[0]); + let month = Number.parseInt(tempList[1]); + let day = Number.parseInt(tempList[2]); + if (isNaN(year) || isNaN(month) || isNaN(day)) { + return []; + } + let tempDate = new Date(year, month - 1, day); + // 判断是否正确的日期 + if (isNaN(tempDate.getTime())) return []; + + tempDate.setHours(0, 0, 0, 0); + let retDate; + switch (statsType) { + case 'day': + retDate = [ + new Date(tempDate), + new Date(tempDate.setDate(tempDate.getDate() + 1)) + ]; + break; + case 'month': + tempDate.setDate(1); + retDate = [ + new Date(tempDate), + new Date(tempDate.setMonth(tempDate.getMonth() + 1)) + ]; + break; + case 'year': + tempDate.setDate(1); + tempDate.setMonth(0); + retDate = [ + new Date(tempDate), + new Date(tempDate.setFullYear(tempDate.getFullYear() + 1)) + ] + } + + retDate[1] = new Date(retDate[1].getTime() - 1); + + return [ + formatDate(retDate[0], format), + formatDate(retDate[1], format) + ]; + }, + /** + * 格式化日期 + * @param {Date|String} date 要格式化的日期 + * @param {String} statsType 输出日期类型 + * @param {String} format 输入日期的格式 + */ + formatDateByStatsType (date, statsType = 'day', format = 'yyyy-MM-dd') { + if (date == null) return undefined; + statsType = allowStatsType.indexOf(statsType) === -1 ? 'day' : statsType; + if (statsType === 'datetime') format = 'yyyy-MM-dd HH:mm:ss'; + + let tempDate = ((date instanceof Date) ? date : parseDate(date, format)); + if (!tempDate) return undefined; + switch (statsType) { + case 'time': + return formatDate(tempDate, 'HH:mm:ss'); + case 'datetime': + return formatDate(tempDate, 'yyyy-MM-dd HH:mm:ss'); + case 'day': + return formatDate(tempDate, 'yyyy-MM-dd'); + case 'month': + return formatDate(tempDate, 'yyyy-MM'); + case 'year': + return formatDate(tempDate, 'yyyy'); + default: + return formatDate(tempDate, 'yyyy-MM-dd'); + } + }, + /** + * 获得统计类型中文名称 + * @param {String} statsType 统计类型(day, month, year) + */ + getStatsTypeShowName (statsType) { + statsType = allowStatsType.indexOf(statsType) === -1 ? 'day' : statsType; + switch (statsType) { + case 'day': return '日统计'; + case 'month': return '月统计'; + case 'year': return '年统计'; + } + }, + /** + * 获取统计类型字典列表 + * @param {Array} statsTypeList 统计类型列表 + */ + getAllowStatsTypeList (statsTypeList) { + if (Array.isArray(statsTypeList) && statsTypeList.length > 0) { + return statsTypeList.map((item) => { + return { + id: item, + name: this.getStatsTypeShowName(item) + } + }); + } else { + return []; + } + } + } +} +/** + * 页面缓存相关方法 + */ +const cachePageMixin = { + methods: { + /** + * 移除缓存页面 + * @param {*} name 缓存组件的名称 + */ + removeCachePage (name) { + this.removeCachePage(name); + }, + /** + * 从跳转页面返回并且刷新当前页面时调用 + */ + onResume () { + }, + ...mapMutations(['addCachePage', 'removeCachePage']) + }, + created () { + this.addCachePage(this.$options.name); + }, + activated () { + if (this.$route && this.$route.meta && this.$route.meta.refresh) { + this.onResume(); + this.$route.meta.refresh = false; + } + } +} +/** + * 缓存页面跳转页面相关方法 + */ +const cachedPageChildMixin = { + data () { + return { + // 是否刷新父页面 + refreshParentCachedPage: false + } + }, + beforeRouteLeave (to, from, next) { + if (to.meta == null) to.meta = {}; + to.meta.refresh = this.refreshParentCachedPage; + next(); + } +} + +export { + uploadMixin, + statsDateRangeMixin, + cachePageMixin, + cachedPageChildMixin +} diff --git a/orange-demo-single-web/src/main.js b/orange-demo-single-web/src/main.js new file mode 100644 index 00000000..fcdd3963 --- /dev/null +++ b/orange-demo-single-web/src/main.js @@ -0,0 +1,36 @@ +import '@/core/http'; +import '@/components/Dialog'; +import Vue from 'vue'; +import ElementUI from 'element-ui'; +// import 'element-ui/lib/theme-chalk/index.css' +import '@/assets/style/index.scss'; +import '@/core/mixins/global.js'; +import App from './App'; +import router from './router'; +import store from './store'; +import TreeSelect from '@/components/TreeSelect'; +import RichEditor from '@/components/RichEditor'; +import InputNumberRange from '@/components/InputNumberRange'; +import DateRange from '@/components/DateRange'; +import FilterBox from '@/components/FilterBox'; +import TableProgressColumn from '@/components/TableProgressColumn'; +import VCharts from 'v-charts'; + +Vue.component('tree-select', TreeSelect); +Vue.component('rich-editor', RichEditor); +Vue.component('input-number-range', InputNumberRange); +Vue.component('date-range', DateRange); +Vue.component('filter-box', FilterBox); +Vue.component('table-progress-column', TableProgressColumn); + +Vue.use(ElementUI); +Vue.use(VCharts); + +Vue.config.productionTip = false; + +/* eslint-disable no-new */ +new Vue({ + router, + store, + render: h => h(App) +}).$mount('#app'); diff --git a/orange-demo-single-web/src/registerServiceWorker.js b/orange-demo-single-web/src/registerServiceWorker.js new file mode 100644 index 00000000..76cede07 --- /dev/null +++ b/orange-demo-single-web/src/registerServiceWorker.js @@ -0,0 +1,32 @@ +/* eslint-disable no-console */ + +import { register } from 'register-service-worker' + +if (process.env.NODE_ENV === 'production') { + register(`${process.env.BASE_URL}service-worker.js`, { + ready () { + console.log( + 'App is being served from cache by a service worker.\n' + + 'For more details, visit https://goo.gl/AFskqB' + ) + }, + registered () { + console.log('Service worker has been registered.') + }, + cached () { + console.log('Content has been cached for offline use.') + }, + updatefound () { + console.log('New content is downloading.') + }, + updated () { + console.log('New content is available; please refresh.') + }, + offline () { + console.log('No internet connection found. App is running in offline mode.') + }, + error (error) { + console.error('Error during service worker registration:', error) + } + }) +} diff --git a/orange-demo-single-web/src/router/import-development.js b/orange-demo-single-web/src/router/import-development.js new file mode 100644 index 00000000..b29a72d9 --- /dev/null +++ b/orange-demo-single-web/src/router/import-development.js @@ -0,0 +1 @@ +module.exports = file => require('../views/' + file + '.vue').default diff --git a/orange-demo-single-web/src/router/import-production.js b/orange-demo-single-web/src/router/import-production.js new file mode 100644 index 00000000..10d919de --- /dev/null +++ b/orange-demo-single-web/src/router/import-production.js @@ -0,0 +1 @@ +module.exports = file => () => import('../views/' + file + '.vue') diff --git a/orange-demo-single-web/src/router/index.js b/orange-demo-single-web/src/router/index.js new file mode 100644 index 00000000..77356d50 --- /dev/null +++ b/orange-demo-single-web/src/router/index.js @@ -0,0 +1,30 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import routers from './systemRouters.js'; +import dialog from '@/components/Dialog'; + +Vue.use(Router) + +const router = new Router({ + mode: 'hash', + routes: routers +}); + +/** + * 路由跳转的时候判断token是否存在 + */ +router.beforeResolve((to, from, next) => { + if (to.name === 'login') { + next(); + } else { + let token = sessionStorage.getItem('token'); + if (!token || !/\S/.test(token)) { + dialog.closeAll(); + next({ name: 'login' }) + } else { + next(); + } + } +}); + +export default router; diff --git a/orange-demo-single-web/src/router/systemRouters.js b/orange-demo-single-web/src/router/systemRouters.js new file mode 100644 index 00000000..992adf39 --- /dev/null +++ b/orange-demo-single-web/src/router/systemRouters.js @@ -0,0 +1,52 @@ +import state from '../store/state.js'; +// 开发环境不使用懒加载, 因为懒加载页面太多的话会造成webpack热更新太慢, 所以只有开发环境使用懒加载 +const _import = require('./import-' + process.env.NODE_ENV) + +function getProps (route) { + return route.query; +} + +// 系统生成路由 +const routers = [ + { path: '/login', component: _import('login/index'), name: 'login', props: getProps, desc: '登录' }, + { + path: '/', + component: _import('login/index'), + name: 'root' + }, + { + path: '/main', + component: _import('layout/index'), + name: 'main', + props: getProps, + redirect: { + name: 'welcome' + }, + meta: { + title: '主页', + showOnly: true + }, + children: [ + {path: 'welcome', component: _import('welcome/index'), name: 'welcome', meta: {title: '欢迎'}}, + {path: 'formSysUser', component: _import('upms/formSysUser/index'), name: 'formSysUser', meta: {title: '用户管理'}}, + {path: 'formSysRole', component: _import('upms/formSysRole/index'), name: 'formSysRole', meta: {title: '角色管理'}}, + {path: 'formSysMenu', component: _import(state.supportColumn ? 'upms/formSysMenu/formSysColumnMenu' : 'upms/formSysMenu/index'), name: 'formSysMenu', meta: {title: '菜单列表'}}, + {path: 'formSysDict', component: _import('upms/formDictManagement/index'), name: 'formSysDict', meta: {title: '字典管理'}}, + {path: 'formSysPermCode', component: _import('upms/formSysPermCode/index'), name: 'formSysPermCode', meta: {title: '权限字管理'}}, + {path: 'formSysPerm', component: _import('upms/formSysPerm/index'), name: 'formSysPerm', meta: {title: '权限资源管理'}}, + {path: 'formSchool', component: _import('generated/formSchool/index'), name: 'formSchool', props: getProps, meta: {title: '校区管理'}}, + {path: 'formStudent', component: _import('generated/formStudent/index'), name: 'formStudent', props: getProps, meta: {title: '学生管理'}}, + {path: 'formCourse', component: _import('generated/formCourse/index'), name: 'formCourse', props: getProps, meta: {title: '课程管理'}}, + {path: 'formClass', component: _import('generated/formClass/index'), name: 'formClass', props: getProps, meta: {title: '班级管理'}}, + {path: 'formClassStudent', component: _import('generated/formClassStudent/index'), name: 'formClassStudent', props: getProps, meta: {title: '班级学生'}}, + {path: 'formClassCourse', component: _import('generated/formClassCourse/index'), name: 'formClassCourse', props: getProps, meta: {title: '班级课程'}}, + {path: 'formSetClassStudent', component: _import('generated/formSetClassStudent/index'), name: 'formSetClassStudent', props: getProps, meta: {title: '设置班级学生'}}, + {path: 'formSetClassCourse', component: _import('generated/formSetClassCourse/index'), name: 'formSetClassCourse', props: getProps, meta: {title: '设置班级课程'}}, + {path: 'formCourseStats', component: _import('generated/formCourseStats/index'), name: 'formCourseStats', props: getProps, meta: {title: '课程统计'}}, + {path: 'formStudentActionStats', component: _import('generated/formStudentActionStats/index'), name: 'formStudentActionStats', props: getProps, meta: {title: '学生行为统计'}}, + {path: 'formStudentActionDetail', component: _import('generated/formStudentActionDetail/index'), name: 'formStudentActionDetail', props: getProps, meta: {title: '学生行为详情'}} + ] + } +]; + +export default routers; diff --git a/orange-demo-single-web/src/staticDict/index.js b/orange-demo-single-web/src/staticDict/index.js new file mode 100644 index 00000000..1f3cb72c --- /dev/null +++ b/orange-demo-single-web/src/staticDict/index.js @@ -0,0 +1,351 @@ +/** + * 常量字典数据 + */ +import Vue from 'vue'; + +class DictionaryBase extends Map { + constructor (dataList, keyId = 'id', symbolId = 'symbol') { + super(); + this.setList(dataList, keyId, symbolId); + } + + setList (dataList, keyId = 'id', symbolId = 'symbol') { + this.clear(); + if (Array.isArray(dataList)) { + dataList.forEach((item) => { + this.set(item[keyId], item); + if (item[symbolId] != null) { + Object.defineProperty(this, item[symbolId], { + get: function () { + return item[keyId]; + } + }); + } + }); + } + } + + getList (valueId = 'name', parentIdKey = 'parentId', filter) { + let temp = []; + this.forEach((value, key) => { + let obj = { + id: key, + name: (typeof value === 'string') ? value : value[valueId], + parentId: value[parentIdKey] + }; + if (typeof filter !== 'function' || filter(obj)) { + temp.push(obj); + } + }); + + return temp; + } + + getValue (id, valueId = 'name') { + return (this.get(id) || {})[valueId]; + } +} + +const SysUserStatus = new DictionaryBase([ + { + id: 0, + name: '正常状态', + symbol: 'NORMAL' + }, + { + id: 1, + name: '锁定状态', + symbol: 'LOCKED' + } +]); +Vue.prototype.SysUserStatus = SysUserStatus; + +const SysUserType = new DictionaryBase([ + { + id: 0, + name: '管理员', + symbol: 'ADMIN' + }, + { + id: 1, + name: '系统操作员', + symbol: 'SYSTEM' + }, + { + id: 2, + name: '普通操作员', + symbol: 'OPERATOR' + } +]); +Vue.prototype.SysUserType = SysUserType; + +const Subject = new DictionaryBase([ + { + id: 0, + name: '语文', + symbol: 'CHINESE' + }, + { + id: 1, + name: '数学', + symbol: 'MATCH' + }, + { + id: 2, + name: '英语', + symbol: 'ENGLISH' + } +]); +Vue.prototype.Subject = Subject; + +const StudentActionType = new DictionaryBase([ + { + id: 0, + name: '充值', + symbol: 'RECHARGE' + }, + { + id: 1, + name: '购课', + symbol: 'BUY_COURSE' + }, + { + id: 2, + name: '上课签到', + symbol: 'SIGNIN_COURSE' + }, + { + id: 3, + name: '上课签退', + symbol: 'SIGNOUT_COURSE' + }, + { + id: 4, + name: '看视频课', + symbol: 'WATCH_VIDEO' + }, + { + id: 5, + name: '做作业', + symbol: 'DO_PAPER' + }, + { + id: 6, + name: '刷题', + symbol: 'REFRESH_EXERCISE' + }, + { + id: 7, + name: '献花', + symbol: 'PRESENT_FLOWER' + }, + { + id: 8, + name: '购买视频', + symbol: 'BUY_VIDEO_COURSE' + }, + { + id: 9, + name: '购买鲜花', + symbol: 'BUY_FLOWER' + }, + { + id: 10, + name: '购买作业', + symbol: 'BUY_PAPER' + } +]); +Vue.prototype.StudentActionType = StudentActionType; + +const DeviceType = new DictionaryBase([ + { + id: 0, + name: 'iOS', + symbol: 'IOS' + }, + { + id: 1, + name: 'Android', + symbol: 'ANDROID' + }, + { + id: 2, + name: 'PC', + symbol: 'PC' + } +]); +Vue.prototype.DeviceType = DeviceType; + +const Gender = new DictionaryBase([ + { + id: 1, + name: '男', + symbol: 'MALE' + }, + { + id: 0, + name: '女', + symbol: 'FEMALE' + } +]); +Vue.prototype.Gender = Gender; + +const ExpLevel = new DictionaryBase([ + { + id: 0, + name: '初级学员', + symbol: 'LOWER' + }, + { + id: 1, + name: '中级学员', + symbol: 'MIDDLE' + }, + { + id: 2, + name: '高级学员', + symbol: 'HIGH' + } +]); +Vue.prototype.ExpLevel = ExpLevel; + +const StudentStatus = new DictionaryBase([ + { + id: 0, + name: '正常', + symbol: 'NORMAL' + }, + { + id: 1, + name: '锁定', + symbol: 'LOCKED' + }, + { + id: 2, + name: '注销', + symbol: 'DELETED' + } +]); +Vue.prototype.StudentStatus = StudentStatus; + +const ClassStatus = new DictionaryBase([ + { + id: 1, + name: '正常', + symbol: 'NORAML' + }, + { + id: -1, + name: '解散', + symbol: 'DELETED' + } +]); +Vue.prototype.ClassStatus = ClassStatus; + +const ClassLevel = new DictionaryBase([ + { + id: 0, + name: '初级班', + symbol: 'NORMAL' + }, + { + id: 1, + name: '中级班', + symbol: 'MIDDLE' + }, + { + id: 2, + name: '高级班', + symbol: 'HIGH' + } +]); +Vue.prototype.ClassLevel = ClassLevel; + +const CourseDifficult = new DictionaryBase([ + { + id: 0, + name: '容易', + symbol: 'NORMAL' + }, + { + id: 1, + name: '普通', + symbol: 'MIDDLE' + }, + { + id: 2, + name: '困难', + symbol: 'HIGH' + } +]); +Vue.prototype.CourseDifficult = CourseDifficult; + +const SysPermModuleType = new DictionaryBase([ + { + id: 0, + name: '分组模块', + symbol: 'GROUP' + }, { + id: 1, + name: '接口模块', + symbol: 'CONTROLLER' + } +]); +Vue.prototype.SysPermModuleType = SysPermModuleType; + +const SysPermCodeType = new DictionaryBase([{ + id: 0, + name: '表单', + symbol: 'FORM' +}, { + id: 1, + name: '片段', + symbol: 'FRAGMENT' +}, { + id: 2, + name: '操作', + symbol: 'OPERATION' +}]); +Vue.prototype.SysPermCodeType = SysPermCodeType; + +const SysMenuType = new DictionaryBase([ + { + id: 0, + name: '目录', + symbol: 'DIRECTORY' + }, + { + id: 1, + name: '表单', + symbol: 'MENU' + }, + { + id: 2, + name: '片段', + symbol: 'FRAGMENT' + }, + { + id: 3, + name: '按钮', + symbol: 'BUTTON' + } +]); +Vue.prototype.SysMenuType = SysMenuType; + +export { + DictionaryBase, + SysUserStatus, + SysUserType, + Subject, + StudentActionType, + DeviceType, + Gender, + ExpLevel, + StudentStatus, + ClassStatus, + ClassLevel, + CourseDifficult, + SysPermModuleType, + SysPermCodeType, + SysMenuType +} diff --git a/orange-demo-single-web/src/store/actions.js b/orange-demo-single-web/src/store/actions.js new file mode 100644 index 00000000..b1c6ea43 --- /dev/null +++ b/orange-demo-single-web/src/store/actions.js @@ -0,0 +1 @@ +export default {} diff --git a/orange-demo-single-web/src/store/getters.js b/orange-demo-single-web/src/store/getters.js new file mode 100644 index 00000000..ee6e1881 --- /dev/null +++ b/orange-demo-single-web/src/store/getters.js @@ -0,0 +1,80 @@ +import { findMenuItem } from './utils'; +import * as StaticDict from '@/staticDict'; + +export default { + getMultiTags: (state) => { + return state.supportTags; + }, + getCollapse: (state) => { + return state.isCollapse; + }, + getClientHeight: (state) => { + return state.documentClientHeight; + }, + getMainContextHeight: (state) => { + return state.documentClientHeight - (state.supportTags ? 130 : 90); + }, + getUserInfo: (state) => { + return state.userInfo; + }, + getCachePages: (state) => { + return state.cachePages; + }, + getTagList: (state) => { + return state.tagList; + }, + getMenuList: (state) => { + if (state.supportColumn) { + if (state.currentColumnId == null || state.currentColumnId === '') return []; + for (let i = 0; i < state.menuList.length; i++) { + if (state.menuList[i].menuId === state.currentColumnId) { + return state.menuList[i].children || []; + } + } + + return []; + } else { + return state.menuList; + } + }, + getColumnList: (state) => { + if (!state.supportColumn) return []; + return state.menuList.map(menu => { + if (menu.menuType === StaticDict.SysMenuType.DIRECTORY) { + return { + columnId: menu.menuId, + columnName: menu.menuName + } + } + }).filter(item => item != null); + }, + getCurrentMenuId: (state) => { + return state.currentMenuId; + }, + getMenuItem: (state) => { + if (Array.isArray(state.menuList)) { + for (let i = 0; i < state.menuList.length; i++) { + let temp = findMenuItem(state.menuList[i], state.currentMenuId); + if (temp != null) return temp; + } + } + return null; + }, + getCurrentMenuPath: (state) => { + let menuPath = []; + if (Array.isArray(state.menuList)) { + for (let i = 0; i < state.menuList.length; i++) { + let temp = findMenuItem(state.menuList[i], state.currentMenuId, menuPath); + if (temp != null) break; + } + } + + return menuPath; + }, + getMultiColumn: (state) => { + return state.supportColumn; + }, + getCurrentColumnId: (state) => { + return state.currentColumnId; + } +} diff --git a/orange-demo-single-web/src/store/index.js b/orange-demo-single-web/src/store/index.js new file mode 100644 index 00000000..5fc44198 --- /dev/null +++ b/orange-demo-single-web/src/store/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import state from './state.js'; +import getters from './getters.js'; +import mutations from './mutations.js'; +import actions from './actions.js'; + +Vue.use(Vuex); +export default new Vuex.Store({ + state, + getters, + mutations, + actions, + strict: process.env.NODE_ENV !== 'production' +}); diff --git a/orange-demo-single-web/src/store/mutations.js b/orange-demo-single-web/src/store/mutations.js new file mode 100644 index 00000000..41b411ac --- /dev/null +++ b/orange-demo-single-web/src/store/mutations.js @@ -0,0 +1,145 @@ +import { initUserInfo, findMenuItem } from './utils'; +import { setObjectToSessionStorage, findItemFromList, treeDataTranslate } from '@/utils'; + +export default { + setCollapse: (state, isCollapse) => { + state.isCollapse = isCollapse; + }, + setClientHeight: (state, height) => { + state.documentClientHeight = height; + }, + setUserInfo: (state, info) => { + setObjectToSessionStorage('userInfo', info); + state.userInfo = initUserInfo(info); + }, + addCachePage (state, name) { + if (state.cachePages.indexOf(name) === -1) { + let temp = [...state.cachePages]; + temp.push(name); + setObjectToSessionStorage('cachePages', temp); + state.cachePages = temp; + } + }, + removeCachePage (state, name) { + let pos = state.cachePages.indexOf(name); + if (pos !== -1) { + let temp = [...state.cachePages]; + temp.splice(pos, 1); + setObjectToSessionStorage('cachePages', temp); + state.cachePages = temp; + } + }, + clearCachePage (state) { + setObjectToSessionStorage('cachePages', []); + state.cachePages = []; + }, + addTag (state, id) { + if (id == null || id === '') return; + // 新增的标签是否存在 + let tagList = state.tagList; + let tagItem = null; + if (Array.isArray(tagList)) { + tagItem = findItemFromList(tagList, id, 'menuId'); + } + if (tagItem != null) return; + // 添加新增标签以及更新页面缓存 + let menuList = state.menuList; + let menuObject = null; + if (Array.isArray(menuList)) { + for (let i = 0; i < menuList.length; i++) { + menuObject = findMenuItem(menuList[i], id); + if (menuObject != null) break; + } + } + if (menuObject != null) { + state.tagList = [...state.tagList, menuObject]; + if (Array.isArray(state.cachePages) && state.cachePages.indexOf(menuObject.formRouterName) === -1) { + state.cachePages = [...state.cachePages, menuObject.formRouterName]; + } + } + setObjectToSessionStorage('cachePages', state.cachePages); + setObjectToSessionStorage('tagList', state.tagList); + }, + removeTag (state, id) { + if (id == null || id === '') return; + // 移除标签 + let nextPos = -1; + let tagItem = null; + for (let i = 0; i < state.tagList.length; i++) { + if (state.tagList[i].menuId === id) { + tagItem = state.tagList[i]; + state.tagList.splice(i, 1); + nextPos = Math.min(i, state.tagList.length - 1); + } + } + // let tagItem = findItemFromList(state.tagList, id, 'menuId', true); + if (tagItem == null) return; + // 移除页面缓存 + findItemFromList(state.cachePages, tagItem.formRouterName, undefined, true); + setObjectToSessionStorage('cachePages', state.cachePages); + setObjectToSessionStorage('tagList', state.tagList); + // 如果移除的是当前显示页面,重新选择显示页面 + let showTag = null; + if (state.currentMenuId === id) { + showTag = state.tagList[nextPos]; + let tempId = (showTag || {}).menuId; + if (setObjectToSessionStorage('currentMenuId', tempId)) state.currentMenuId = tempId; + } + }, + closeOtherTags (state, id) { + if (id == null || id === '') return; + // 移除其他所有标签 + if (Array.isArray(state.tagList)) { + state.tagList = state.tagList.filter((item) => { + return item.menuId === id; + }); + } + + let menuObject = state.tagList[0]; + if (menuObject && menuObject.formRouterName && menuObject.formRouterName !== '') { + state.cachePages = [menuObject.formRouterName]; + if (setObjectToSessionStorage('currentMenuId', menuObject.menuId)) state.currentMenuId = menuObject.menuId; + } + setObjectToSessionStorage('cachePages', state.cachePages); + setObjectToSessionStorage('tagList', state.tagList); + }, + clearAllTags (state) { + if (setObjectToSessionStorage('currentMenuId', undefined)) state.currentMenuId = undefined; + if (setObjectToSessionStorage('cachePages', [])) state.cachePages = []; + if (setObjectToSessionStorage('tagList', [])) state.tagList = []; + }, + setMenuList: (state, list) => { + if (Array.isArray(list)) { + if (setObjectToSessionStorage('menuList', list)) state.menuList = treeDataTranslate(list, 'menuId', 'parentId'); + let columnId = (state.menuList[0] || {}).menuId; + if (setObjectToSessionStorage('currentColumnId', columnId)) state.currentColumnId = columnId; + } + }, + setCurrentMenuId: (state, menuId) => { + let menuItem = null; + if (setObjectToSessionStorage('currentMenuId', menuId)) state.currentMenuId = menuId; + if (Array.isArray(state.tagList) && Array.isArray(state.menuList)) { + for (let i = 0; i < state.menuList.length; i++) { + menuItem = findMenuItem(state.menuList[i], menuId, 'menuId'); + if (menuItem != null) { + // 添加新的tag + let tagItem = findItemFromList(state.tagList, menuId, 'menuId'); + if (tagItem == null) { + state.tagList = [...state.tagList, menuItem]; + setObjectToSessionStorage('tagList', state.tagList); + } + // 添加新缓存 + if (Array.isArray(state.cachePages) && state.cachePages.indexOf(menuItem.formRouterName) === -1) { + state.cachePages = [...state.cachePages, menuItem.formRouterName]; + setObjectToSessionStorage('cachePages', state.cachePages); + } + break; + } + } + } + }, + setCurrentColumnId: (state, columnId) => { + if (setObjectToSessionStorage('currentColumnId', columnId)) state.currentColumnId = columnId; + if (setObjectToSessionStorage('currentMenuId', null)) state.currentMenuId = null; + } +} diff --git a/orange-demo-single-web/src/store/state.js b/orange-demo-single-web/src/store/state.js new file mode 100644 index 00000000..ebde637f --- /dev/null +++ b/orange-demo-single-web/src/store/state.js @@ -0,0 +1,25 @@ +import { initUserInfo } from './utils'; +import { getObjectFromSessionStorage, treeDataTranslate } from '@/utils'; + +export default { + // 是否左侧菜单折叠 + isCollapse: false, + // 是否多栏目 + supportColumn: false, + // 是否多标签 + supportTags: false, + // 浏览器客户区高度 + documentClientHeight: 100, + // 用户登录信息 + userInfo: initUserInfo(), + // 缓存页面 + cachePages: getObjectFromSessionStorage('cachePages', []), + // 当前标签 + tagList: getObjectFromSessionStorage('tagList', []), + // 菜单列表 + menuList: treeDataTranslate(getObjectFromSessionStorage('menuList', []), 'menuId', 'parentId'), + // 当前菜单 + currentMenuId: getObjectFromSessionStorage('currentMenuId', undefined), + // 当前栏目 + currentColumnId: getObjectFromSessionStorage('currentColumnId', undefined) +} diff --git a/orange-demo-single-web/src/store/utils/index.js b/orange-demo-single-web/src/store/utils/index.js new file mode 100644 index 00000000..ec129435 --- /dev/null +++ b/orange-demo-single-web/src/store/utils/index.js @@ -0,0 +1,36 @@ +import { getObjectFromSessionStorage } from '@/utils'; + +function findMenuItem (menuItem, menuId, path) { + if (Array.isArray(path)) path.push(menuItem); + if ((menuItem.menuId + '') === (menuId + '')) return menuItem; + + let bFind = false; + let findItem = null; + if (Array.isArray(menuItem.children)) { + for (let i = 0; i < menuItem.children.length; i++) { + findItem = findMenuItem(menuItem.children[i], menuId, path); + if (findItem != null) { + bFind = true; + break; + } + } + } + + if (!bFind && Array.isArray(path)) path.pop(); + return bFind ? findItem : null; +} + +function initUserInfo (userInfo) { + if (userInfo == null) userInfo = getObjectFromSessionStorage('userInfo'); + + if (userInfo != null && userInfo.permCodeList != null && Array.isArray(userInfo.permCodeList)) { + userInfo.permCodeSet = new Set(userInfo.permCodeList); + } + + return userInfo; +} + +export { + findMenuItem, + initUserInfo +} diff --git a/orange-demo-single-web/src/utils/chartOption.js b/orange-demo-single-web/src/utils/chartOption.js new file mode 100644 index 00000000..76b12e02 --- /dev/null +++ b/orange-demo-single-web/src/utils/chartOption.js @@ -0,0 +1,56 @@ +const defaultLineChartOption = { + grid: { + left: '3%', + right: '4%', + bottom: '20px', + containLabel: true + }, + xAxis: { + axisLabel: { + interval: 0, + showMaxLabel: true + } + }, + legend: { + top: '3%' + } +} + +const defaultBarChartOption = { + grid: { + left: '3%', + right: '4%', + bottom: '20px', + containLabel: true + }, + xAxis: { + axisLabel: { + interval: 0, + showMaxLabel: true + } + }, + legend: { + top: '3%' + } +} + +const defaultPieChartOption = { + grid: { + left: '3%', + right: '4%', + bottom: '20px', + containLabel: true + }, + legend: { + top: '3%' + }, + series: { + center: ['50%', '60%'] + } +} + +export { + defaultLineChartOption, + defaultBarChartOption, + defaultPieChartOption +} diff --git a/orange-demo-single-web/src/utils/index.js b/orange-demo-single-web/src/utils/index.js new file mode 100644 index 00000000..7c48d739 --- /dev/null +++ b/orange-demo-single-web/src/utils/index.js @@ -0,0 +1,222 @@ +import JSEncrypt from 'jsencrypt'; + +/** + * 列表数据转换树形数据 + * @param {Array} data 要转换的列表 + * @param {String} id 主键字段字段名 + * @param {String} pid 父字段字段名 + * @returns {Array} 转换后的树数据 + */ +export function treeDataTranslate (data, id = 'id', pid = 'parentId') { + var res = [] + var temp = {} + for (var i = 0; i < data.length; i++) { + temp[data[i][id]] = data[i] + } + for (var k = 0; k < data.length; k++) { + if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) { + if (!temp[data[k][pid]]['children']) { + temp[data[k][pid]]['children'] = [] + } + if (!temp[data[k][pid]]['_level']) { + temp[data[k][pid]]['_level'] = 1 + } + data[k]['_level'] = temp[data[k][pid]]._level + 1 + data[k]['_parent'] = data[k][pid] + temp[data[k][pid]]['children'].push(data[k]) + } else { + res.push(data[k]) + } + } + + return res +} +/** + * 获取字符串字节长度(中文算2个字符) + * @param {String} str 要获取长度的字符串 + */ +export function getStringLength (str) { + return str.replace(/[\u4e00-\u9fa5\uff00-\uffff]/g, '**').length +} +/** + * 获取uuid + */ +export function getUUID () { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16) + }); +} +/** + * 大小驼峰变换函数 + * @param name 要转换的字符串 + * @param type 转换的类型0:转换成小驼峰,1:转换成大驼峰 + */ +export function nameTranslate (name, type) { + name = name.toLowerCase(); + let nameArray = name.split('_'); + nameArray.forEach((item, index) => { + if (index === 0) { + name = type === 1 ? item.slice(0, 1).toUpperCase() + item.slice(1) : item; + } else { + name = name + item.slice(0, 1).toUpperCase() + item.slice(1); + } + }); + + nameArray = name.split('-'); + nameArray.forEach((item, index) => { + if (index === 0) { + name = type === 1 ? item.slice(0, 1).toUpperCase() + item.slice(1) : item; + } else { + name = name + item.slice(0, 1).toUpperCase() + item.slice(1); + } + }); + return name; +} +/** + * 通过id从树中获取指定的节点 + * @param {Object} node 根节点 + * @param {String|Nubmer} id 键值 + * @param {Array} list 保存查询路径 + * @param {String} idKey 主键字段名 + * @param {String} childKey 子节点字段名 + */ +function findNode (node, id, list, idKey = 'id', childKey = 'children') { + if (Array.isArray(list)) list.push(node[idKey]); + if (node[idKey] === id) { + return node; + } + + if (node[childKey] != null && Array.isArray(node[childKey])) { + for (let i = 0; i < node[childKey].length; i++) { + let tempNode = findNode(node[childKey][i], id, list, idKey, childKey); + if (tempNode) return tempNode; + } + } + + if (Array.isArray(list)) list.pop(); +} +/** + * 通过id返回从根节点到指定节点的路径 + * @param {Array} treeRoot 树根节点数组 + * @param {*} id 要查询的节点的id + * @param {*} idKey 主键字段名 + * @param {*} childKey 子节点字段名 + */ +export function findTreeNodePath (treeRoot, id, idKey = 'id', childKey = 'children') { + let tempList = []; + for (let i = 0; i < treeRoot.length; i++) { + if (findNode(treeRoot[i], id, tempList, idKey, childKey)) { + return tempList; + } + } + + return []; +} +/** + * 通过id从树中查找节点 + * @param {Array} treeRoot 根节点数组 + * @param {*} id 要查找的节点的id + * @param {*} idKey 主键字段名 + * @param {*} childKey 子节点字段名 + */ +export function findTreeNode (treeRoot, id, idKey = 'id', childKey = 'children') { + for (let i = 0; i < treeRoot.length; i++) { + let tempNode = findNode(treeRoot[i], id, undefined, idKey, childKey); + if (tempNode) return tempNode; + } +} +/** + * 把Object转换成query字符串 + * @param {Object} params 要转换的Object + */ +export function objectToQueryString (params) { + if (params == null) { + return null; + } else { + return Object.keys(params).map((key) => { + return `${key}=${params[key]}`; + }).join('&'); + } +} +/** + * 从数组中查找某一项 + * @param {Array} list 要查找的数组 + * @param {String} id 要查找的节点id + * @param {String} idKey 主键字段名(如果为null则直接比较) + * @param {Boolean} removeItem 是否从数组中移除查找到的节点 + * @returns {Object} 找到返回节点,没找到返回undefined + */ +export function findItemFromList (list, id, idKey, removeItem = false) { + if (Array.isArray(list) && list.length > 0 && id != null) { + for (let i = 0; i < list.length; i++) { + let item = list[i]; + if (((idKey == null || idKey === '') && item === id) || (idKey != null && item[idKey] === id)) { + if (removeItem) list.splice(i, 1); + return item; + } + } + } + return null; +} +/** + * 将数据保存到sessionStorage + * @param {*} key sessionStorage的键值 + * @param {*} value 要保存的数据 + */ +export function setObjectToSessionStorage (key, value) { + if (key == null || key === '') return false; + if (value == null) { + window.sessionStorage.removeItem(key); + return true; + } else { + let jsonObj = { + data: value + } + window.sessionStorage.setItem(key, JSON.stringify(jsonObj)); + return true; + } +} +/** + * 从sessionStorage里面获取数据 + * @param {String} key 键值 + * @param {*} defaultValue 默认值 + */ +export function getObjectFromSessionStorage (key, defaultValue) { + let jsonObj = null; + try { + jsonObj = JSON.parse(window.sessionStorage.getItem(key)); + jsonObj = (jsonObj || {}).data; + } catch (e) { + jsonObj = defaultValue; + }; + return (jsonObj != null) ? jsonObj : defaultValue; +} +/** + * 判读字符串是否一个数字 + * @param {String} str 要判断的字符串 + */ +export function isNumber (str) { + let num = Number.parseFloat(str); + if (Number.isNaN(num)) return false; + return num.toString() === str; +} +/** + * 生成随机数 + * @param {Integer} min 随机数最小值 + * @param {Integer} max 随机数最大值 + */ +export function random (min, max) { + let base = Math.random(); + return min + base * (max - min); +} +/** + * 加密 + * @param {*} value 要加密的字符串 + */ +const publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpC4QMnbTrQOFriJJCCFFWhlruBJThAEBfRk7pRx1jsAhyNVL3CqJb0tRvpnbCnJhrRAEPdgFHXv5A0RrvFp+5Cw7QoFH6O9rKB8+0H7+aVQeKITMUHf/XMXioymw6Iq4QfWd8RhdtM1KM6eGTy8aU7SO2s69Mc1LXefg/x3yw6wIDAQAB'; +export function encrypt (value) { + if (value == null || value === '') return null; + let encrypt = new JSEncrypt(); + encrypt.setPublicKey(publicKey); + return encodeURIComponent(encrypt.encrypt(value)); +} diff --git a/orange-demo-single-web/src/utils/validate.js b/orange-demo-single-web/src/utils/validate.js new file mode 100644 index 00000000..5b148e39 --- /dev/null +++ b/orange-demo-single-web/src/utils/validate.js @@ -0,0 +1,33 @@ +const pattern = { + mobie: /^((\+?86)|(\(\+86\)))?(13[012356789][0-9]{8}|15[012356789][0-9]{8}|18[02356789][0-9]{8}|147[0-9]{8}|1349[0-9]{7})$/, + english: /^[a-zA-Z]+$/, + englishAndNumber: /^[a-zA-Z0-9]+$/ +} + +/** + * 邮箱 + * @param str + */ +export function isEmail (str) { + return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(str) +} + +/** + * 手机号码 + * @param str + */ +export function isMobile (str) { + return pattern.mobie.test(str) +} + +/** + * 电话号码 + * @param str + */ +export function isPhone (str) { + return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(str) +} + +export default { + pattern +} diff --git a/orange-demo-single-web/src/utils/widget.js b/orange-demo-single-web/src/utils/widget.js new file mode 100644 index 00000000..db2cfa81 --- /dev/null +++ b/orange-demo-single-web/src/utils/widget.js @@ -0,0 +1,297 @@ +import { Message } from 'element-ui'; +import { treeDataTranslate } from '@/utils'; + +const DEFAULT_PAGE_SIZE = 10; + +export class DropdownWidget { + /** + * 下拉组件(Select、Cascade、TreeSelect等) + * @param {function () : Promise} loadDropdownData 下拉数据获取函数 + * @param {Boolean} isTree 是否是树数据 + * @param {String} idKey 键字段字段名 + * @param {String} parentIdKey 父字段字段名 + */ + constructor (loadDropdownData, isTree = false, idKey = 'id', parentIdKey = 'parentId') { + this.loading = false; + this.dirty = true; + this.dropdownList = []; + this.isTree = isTree; + this.idKey = idKey; + this.parentIdKey = parentIdKey; + this.loadDropdownData = loadDropdownData; + this.setDropdownList = this.setDropdownList.bind(this); + this.onVisibleChange = this.onVisibleChange.bind(this); + } + /** + * 重新获取下拉数据 + */ + reloadDropdownData () { + return new Promise((resolve, reject) => { + if (!this.loading) { + if (typeof this.loadDropdownData === 'function') { + this.loading = true; + this.loadDropdownData().then(dataList => { + this.setDropdownList(dataList); + this.loading = false; + this.dirty = false; + resolve(this.dropdownList); + }).catch(e => { + this.setDropdownList([]); + this.loading = false; + reject(this.dropdownList); + }); + } else { + reject(new Error('获取下拉数据失败')); + } + } else { + resolve(this.dropdownList); + } + }); + } + /** + * 下拉框显示或隐藏时调用 + * @param {Boolean} isShow 正在显示或者隐藏 + */ + onVisibleChange (isShow) { + return new Promise((resolve, reject) => { + if (isShow && this.dirty && !this.loading) { + this.reloadDropdownData().then(res => { + resolve(res); + }).catch(e => { + reject(e); + }); + } else { + resolve(this.dropdownList); + } + }); + } + /** + * 设置下拉数据 + * @param {Array} dataList 要显示的下拉数据 + */ + setDropdownList (dataList) { + if (Array.isArray(dataList)) { + this.dropdownList = this.isTree ? treeDataTranslate(dataList, this.idKey, this.parentIdKey) : dataList; + } + } +} + +export class TableWidget { + /** + * 表格组件 + * @param {function (params: Object) : Promise} loadTableData 表数据获取函数 + * @param {function () : Boolean} verifyTableParameter 表数据获取检验函数 + * @param {Boolean} paged 是否支持分页 + * @param {String} orderFieldName 默认排序字段 + * @param {Boolean} ascending 默认排序方式(true为正序,false为倒序) + * @param {String} dateAggregateBy 默认排序字段的日期统计类型 + */ + constructor (loadTableData, verifyTableParameter, paged, orderFieldName, ascending, dateAggregateBy) { + this.oldPage = 0; + this.currentPage = 1; + this.oldPageSize = DEFAULT_PAGE_SIZE; + this.pageSize = DEFAULT_PAGE_SIZE; + this.totalCount = 0; + this.dataList = []; + this.orderInfo = { + fieldName: orderFieldName, + asc: ascending, + dateAggregateBy: dateAggregateBy + }; + this.paged = paged; + this.searchVerify = verifyTableParameter || function () { return true; }; + this.loadTableData = loadTableData || function () { return Promise.resolve(); }; + this.onCurrentPageChange = this.onCurrentPageChange.bind(this); + this.onPageSizeChange = this.onPageSizeChange.bind(this); + this.onSortChange = this.onSortChange.bind(this); + this.getTableIndex = this.getTableIndex.bind(this); + } + /** + * 表格分页变化 + * @param {Integer} newCurrentPage 变化后的显示页面 + */ + onCurrentPageChange (newCurrentPage) { + this.loadTableDataImpl(newCurrentPage, this.pageSize).then(() => { + this.oldPage = this.currentPage = newCurrentPage; + }).catch(() => { + this.currentPage = this.oldPage; + }); + } + /** + * 表格分页每页显示数量变化 + * @param {Integer} newPageSize 变化后的每页显示数量 + */ + onPageSizeChange (newPageSize) { + this.loadTableDataImpl(1, newPageSize).then(() => { + this.oldPage = this.currentPage = 1; + this.oldPageSize = this.pageSize = newPageSize; + }).catch(e => { + this.currentPage = this.oldPage; + this.pageSize = this.oldPageSize; + }); + } + /** + * 表格排序字段变化 + * @param {String} prop 排序字段的字段名 + * @param {String} order 正序还是倒序 + */ + onSortChange ({ prop, order }) { + this.orderInfo.fieldName = prop; + this.orderInfo.asc = (order === 'ascending'); + this.refreshTable(); + } + /** + * 获取每一行的index信息 + * @param {Integer} index 表格在本页位置 + */ + getTableIndex (index) { + return this.paged ? ((this.currentPage - 1) * this.pageSize + (index + 1)) : (index + 1); + } + /** + * 获取表格数据 + * @param {Integer} pageNum 当前分页 + * @param {Integer} pageSize 每页数量 + * @param {Boolean} reload 是否重新获取数据 + */ + loadTableDataImpl (pageNum, pageSize, reload = false) { + return new Promise((resolve, reject) => { + if (typeof this.loadTableData !== 'function') { + reject(); + } else { + // 如果pageSize和pageNum没有变化,并且不强制刷新 + if (this.paged && !reload && this.oldPage === pageNum && this.oldPageSize === pageSize) { + resolve(); + } else { + let params = {}; + if (this.orderInfo.fieldName != null) params.orderParam = [this.orderInfo]; + if (this.paged) { + params.pageParam = { + pageNum, + pageSize + } + } + this.loadTableData(params).then(tableData => { + this.dataList = tableData.dataList; + this.totalCount = tableData.totalCount; + resolve(); + }).catch(e => { + reject(e); + }); + } + } + }); + } + /** + * 刷新表格数据 + * @param {Boolean} research 是否按照新的查询条件重新查询(调用verify函数) + * @param {Integer} pageNum 当前页面 + */ + refreshTable (research = false, pageNum = undefined, showMsg = false) { + let reload = false; + if (research) { + if (typeof this.searchVerify === 'function' && !this.searchVerify()) return; + reload = true; + } + + if (Number.isInteger(pageNum) && pageNum !== this.currentPage) { + this.loadTableDataImpl(pageNum, this.pageSize, reload).then(res => { + this.oldPage = this.currentPage = pageNum; + if (research && showMsg) Message.success('查询成功'); + }).catch(e => { + this.currentPage = this.oldPage; + }); + } else { + this.loadTableDataImpl(this.currentPage, this.pageSize, true).catch(e => {}); + } + } +} + +export class UploadWidget { + /** + * 上传组件 + * @param {Integer} maxCount 最大上传数量 + */ + constructor (maxCount = 1) { + this.maxCount = maxCount; + this.fileList = []; + this.onFileChange = this.onFileChange.bind(this); + } + /** + * 上传文件列表改变 + * @param {Object} file 改变的文件 + * @param {Array} fileList 改变后的文件列表 + */ + onFileChange (file, fileList) { + if (Array.isArray(fileList) && fileList.length > 0) { + if (this.maxCount === 1) { + this.fileList = [fileList[fileList.length - 1]]; + } else { + this.fileList = fileList; + } + } else { + this.fileList = []; + } + return this.fileList; + } +} + +export class ChartWidget { + /** + * 图表组件 + * @param {function (params) : Promise} loadTableData chart数据获取函数 + * @param {function () : Boolean} verifyTableParameter 数据参数检验函数 + * @param {Array} columns 数据列 + */ + constructor (loadTableData, verifyTableParameter, columns) { + this.columns = columns; + this.loading = false; + this.dataEmpty = false; + this.chartData = undefined; + this.chartObject = undefined; + this.dimensionMaps = new Map(); + this.chartSetting = undefined; + this.searchVerify = verifyTableParameter || function () { return true; }; + this.loadTableData = loadTableData || function () { return Promise.resolve(); }; + } + /** + * 获取图表数据 + * @param {Boolean} reload 是否重新获取数据 + */ + loadChartDataImpl (reload = false) { + return new Promise((resolve, reject) => { + if (typeof this.loadTableData !== 'function') { + reject(); + } else { + if (!reload) { + resolve(); + } else { + this.loading = true; + this.loadTableData().then(tableData => { + this.chartData = { + columns: this.columns, + rows: tableData.dataList + } + this.loading = false; + if (this.chartObject) this.chartObject.resize(); + resolve(); + }).catch(e => { + console.error(e); + this.loading = false; + reject(e); + }); + } + } + }); + } + /** + * 刷新图表数据 + * @param {Boolean} research 是否按照新的查询条件重新查询(调用verify函数) + */ + refreshChart (research = false) { + if (research) { + if (typeof this.searchVerify === 'function' && !this.searchVerify()) return; + } + + this.loadChartDataImpl(true).catch(e => {}); + } +} diff --git a/orange-demo-single-web/src/views/generated/formClass/index.vue b/orange-demo-single-web/src/views/generated/formClass/index.vue new file mode 100644 index 00000000..196c5948 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formClass/index.vue @@ -0,0 +1,290 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formClassCourse/index.vue b/orange-demo-single-web/src/views/generated/formClassCourse/index.vue new file mode 100644 index 00000000..63b69c2e --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formClassCourse/index.vue @@ -0,0 +1,175 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formClassStudent/index.vue b/orange-demo-single-web/src/views/generated/formClassStudent/index.vue new file mode 100644 index 00000000..ae00f090 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formClassStudent/index.vue @@ -0,0 +1,169 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formCourse/index.vue b/orange-demo-single-web/src/views/generated/formCourse/index.vue new file mode 100644 index 00000000..1dcfdb7e --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formCourse/index.vue @@ -0,0 +1,308 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formCourseStats/index.vue b/orange-demo-single-web/src/views/generated/formCourseStats/index.vue new file mode 100644 index 00000000..5c4376e0 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formCourseStats/index.vue @@ -0,0 +1,314 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formCreateClass/index.vue b/orange-demo-single-web/src/views/generated/formCreateClass/index.vue new file mode 100644 index 00000000..75984899 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formCreateClass/index.vue @@ -0,0 +1,276 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formCreateCourse/index.vue b/orange-demo-single-web/src/views/generated/formCreateCourse/index.vue new file mode 100644 index 00000000..bd006e71 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formCreateCourse/index.vue @@ -0,0 +1,310 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formCreateSchool/index.vue b/orange-demo-single-web/src/views/generated/formCreateSchool/index.vue new file mode 100644 index 00000000..477960ac --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formCreateSchool/index.vue @@ -0,0 +1,197 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formCreateStudent/index.vue b/orange-demo-single-web/src/views/generated/formCreateStudent/index.vue new file mode 100644 index 00000000..3729a77b --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formCreateStudent/index.vue @@ -0,0 +1,429 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formEditClass/index.vue b/orange-demo-single-web/src/views/generated/formEditClass/index.vue new file mode 100644 index 00000000..a8850b54 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formEditClass/index.vue @@ -0,0 +1,280 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formEditCourse/index.vue b/orange-demo-single-web/src/views/generated/formEditCourse/index.vue new file mode 100644 index 00000000..b2fd7bb1 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formEditCourse/index.vue @@ -0,0 +1,345 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formEditSchool/index.vue b/orange-demo-single-web/src/views/generated/formEditSchool/index.vue new file mode 100644 index 00000000..f1176b99 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formEditSchool/index.vue @@ -0,0 +1,225 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formEditStudent/index.vue b/orange-demo-single-web/src/views/generated/formEditStudent/index.vue new file mode 100644 index 00000000..d2702c80 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formEditStudent/index.vue @@ -0,0 +1,519 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formSchool/index.vue b/orange-demo-single-web/src/views/generated/formSchool/index.vue new file mode 100644 index 00000000..7500d6b6 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formSchool/index.vue @@ -0,0 +1,263 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formSetClassCourse/index.vue b/orange-demo-single-web/src/views/generated/formSetClassCourse/index.vue new file mode 100644 index 00000000..a6c1ed4c --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formSetClassCourse/index.vue @@ -0,0 +1,281 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formSetClassStudent/index.vue b/orange-demo-single-web/src/views/generated/formSetClassStudent/index.vue new file mode 100644 index 00000000..04979609 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formSetClassStudent/index.vue @@ -0,0 +1,207 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formStudent/index.vue b/orange-demo-single-web/src/views/generated/formStudent/index.vue new file mode 100644 index 00000000..89630002 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formStudent/index.vue @@ -0,0 +1,327 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formStudentActionDetail/index.vue b/orange-demo-single-web/src/views/generated/formStudentActionDetail/index.vue new file mode 100644 index 00000000..129c6a1d --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formStudentActionDetail/index.vue @@ -0,0 +1,240 @@ + + + diff --git a/orange-demo-single-web/src/views/generated/formStudentActionStats/index.vue b/orange-demo-single-web/src/views/generated/formStudentActionStats/index.vue new file mode 100644 index 00000000..02b32705 --- /dev/null +++ b/orange-demo-single-web/src/views/generated/formStudentActionStats/index.vue @@ -0,0 +1,315 @@ + + + diff --git a/orange-demo-single-web/src/views/layout/components/breadcrumb/index.vue b/orange-demo-single-web/src/views/layout/components/breadcrumb/index.vue new file mode 100644 index 00000000..de4573a8 --- /dev/null +++ b/orange-demo-single-web/src/views/layout/components/breadcrumb/index.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/orange-demo-single-web/src/views/layout/components/formModifyPassword/index.vue b/orange-demo-single-web/src/views/layout/components/formModifyPassword/index.vue new file mode 100644 index 00000000..f85c24e2 --- /dev/null +++ b/orange-demo-single-web/src/views/layout/components/formModifyPassword/index.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/orange-demo-single-web/src/views/layout/components/sidebar/menu-item.vue b/orange-demo-single-web/src/views/layout/components/sidebar/menu-item.vue new file mode 100644 index 00000000..3a28543f --- /dev/null +++ b/orange-demo-single-web/src/views/layout/components/sidebar/menu-item.vue @@ -0,0 +1,59 @@ + + + diff --git a/orange-demo-single-web/src/views/layout/components/sidebar/sidebar.vue b/orange-demo-single-web/src/views/layout/components/sidebar/sidebar.vue new file mode 100644 index 00000000..de79cada --- /dev/null +++ b/orange-demo-single-web/src/views/layout/components/sidebar/sidebar.vue @@ -0,0 +1,72 @@ + + + diff --git a/orange-demo-single-web/src/views/layout/components/tags/tagItem.vue b/orange-demo-single-web/src/views/layout/components/tags/tagItem.vue new file mode 100644 index 00000000..80c21563 --- /dev/null +++ b/orange-demo-single-web/src/views/layout/components/tags/tagItem.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/orange-demo-single-web/src/views/layout/components/tags/tagPanel.vue b/orange-demo-single-web/src/views/layout/components/tags/tagPanel.vue new file mode 100644 index 00000000..adaed9e1 --- /dev/null +++ b/orange-demo-single-web/src/views/layout/components/tags/tagPanel.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/orange-demo-single-web/src/views/layout/index.vue b/orange-demo-single-web/src/views/layout/index.vue new file mode 100644 index 00000000..c7ca7762 --- /dev/null +++ b/orange-demo-single-web/src/views/layout/index.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/orange-demo-single-web/src/views/login/index.vue b/orange-demo-single-web/src/views/login/index.vue new file mode 100644 index 00000000..01b3bf67 --- /dev/null +++ b/orange-demo-single-web/src/views/login/index.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formDictManagement/index.vue b/orange-demo-single-web/src/views/upms/formDictManagement/index.vue new file mode 100644 index 00000000..766505ee --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formDictManagement/index.vue @@ -0,0 +1,128 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formEditDict/index.vue b/orange-demo-single-web/src/views/upms/formEditDict/index.vue new file mode 100644 index 00000000..07a664b3 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditDict/index.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysMenu/editColumn.vue b/orange-demo-single-web/src/views/upms/formEditSysMenu/editColumn.vue new file mode 100644 index 00000000..41a7b4dc --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysMenu/editColumn.vue @@ -0,0 +1,108 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysMenu/index.vue b/orange-demo-single-web/src/views/upms/formEditSysMenu/index.vue new file mode 100644 index 00000000..d2cce28a --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysMenu/index.vue @@ -0,0 +1,283 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysPerm/index.vue b/orange-demo-single-web/src/views/upms/formEditSysPerm/index.vue new file mode 100644 index 00000000..15b2b621 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysPerm/index.vue @@ -0,0 +1,169 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysPermCode/index.vue b/orange-demo-single-web/src/views/upms/formEditSysPermCode/index.vue new file mode 100644 index 00000000..f85ef0ef --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysPermCode/index.vue @@ -0,0 +1,221 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysPermModule/index.vue b/orange-demo-single-web/src/views/upms/formEditSysPermModule/index.vue new file mode 100644 index 00000000..33b66617 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysPermModule/index.vue @@ -0,0 +1,185 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysRole/index.vue b/orange-demo-single-web/src/views/upms/formEditSysRole/index.vue new file mode 100644 index 00000000..5d9d5a5b --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysRole/index.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formEditSysUser/index.vue b/orange-demo-single-web/src/views/upms/formEditSysUser/index.vue new file mode 100644 index 00000000..0ac0e506 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formEditSysUser/index.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formMenuPerm/index.vue b/orange-demo-single-web/src/views/upms/formMenuPerm/index.vue new file mode 100644 index 00000000..cb9bf241 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formMenuPerm/index.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formPermQuery/index.vue b/orange-demo-single-web/src/views/upms/formPermQuery/index.vue new file mode 100644 index 00000000..5d5ab6dc --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formPermQuery/index.vue @@ -0,0 +1,416 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formSetRoleUsers/index.vue b/orange-demo-single-web/src/views/upms/formSetRoleUsers/index.vue new file mode 100644 index 00000000..3dff9c99 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSetRoleUsers/index.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formSysMenu/formSysColumnMenu.vue b/orange-demo-single-web/src/views/upms/formSysMenu/formSysColumnMenu.vue new file mode 100644 index 00000000..24fd5abb --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysMenu/formSysColumnMenu.vue @@ -0,0 +1,305 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formSysMenu/index.vue b/orange-demo-single-web/src/views/upms/formSysMenu/index.vue new file mode 100644 index 00000000..e8fd646b --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysMenu/index.vue @@ -0,0 +1,239 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formSysPerm/index.vue b/orange-demo-single-web/src/views/upms/formSysPerm/index.vue new file mode 100644 index 00000000..cab60de3 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysPerm/index.vue @@ -0,0 +1,398 @@ + + + + + diff --git a/orange-demo-single-web/src/views/upms/formSysPermCode/index.vue b/orange-demo-single-web/src/views/upms/formSysPermCode/index.vue new file mode 100644 index 00000000..3ac871fd --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysPermCode/index.vue @@ -0,0 +1,254 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formSysRole/index.vue b/orange-demo-single-web/src/views/upms/formSysRole/index.vue new file mode 100644 index 00000000..d5096d72 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysRole/index.vue @@ -0,0 +1,455 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formSysRoleUser/index.vue b/orange-demo-single-web/src/views/upms/formSysRoleUser/index.vue new file mode 100644 index 00000000..9796777c --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysRoleUser/index.vue @@ -0,0 +1,224 @@ + + + diff --git a/orange-demo-single-web/src/views/upms/formSysUser/index.vue b/orange-demo-single-web/src/views/upms/formSysUser/index.vue new file mode 100644 index 00000000..126e7893 --- /dev/null +++ b/orange-demo-single-web/src/views/upms/formSysUser/index.vue @@ -0,0 +1,253 @@ + + + diff --git a/orange-demo-single-web/src/views/welcome/index.vue b/orange-demo-single-web/src/views/welcome/index.vue new file mode 100644 index 00000000..a067c0ef --- /dev/null +++ b/orange-demo-single-web/src/views/welcome/index.vue @@ -0,0 +1,156 @@ + + + + + + + diff --git a/orange-demo-single-web/static/.gitkeep b/orange-demo-single-web/static/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/orange-demo-single-web/vue.config.js b/orange-demo-single-web/vue.config.js new file mode 100644 index 00000000..41f99a21 --- /dev/null +++ b/orange-demo-single-web/vue.config.js @@ -0,0 +1,5 @@ +module.exports = { + devServer: { + port: 8085 + } +}