diff --git a/orange-admin-service/.DS_Store b/orange-admin-service/.DS_Store new file mode 100644 index 00000000..f88965e1 Binary files /dev/null and b/orange-admin-service/.DS_Store differ diff --git a/orange-admin-service/.gitignore b/orange-admin-service/.gitignore new file mode 100644 index 00000000..ac242580 --- /dev/null +++ b/orange-admin-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-admin-service/README.md b/orange-admin-service/README.md new file mode 100644 index 00000000..6a1d5465 --- /dev/null +++ b/orange-admin-service/README.md @@ -0,0 +1,5 @@ +### 服务启动环境依赖 +--- + +在当前工程业务应用服务或Job服务启动前,需按如下顺序依次启动下列中间件。 +- XXL-Job (可选,仅当启动Job服务时使用) diff --git a/orange-admin-service/application/.DS_Store b/orange-admin-service/application/.DS_Store new file mode 100644 index 00000000..ee771938 Binary files /dev/null and b/orange-admin-service/application/.DS_Store differ diff --git a/orange-admin-service/application/pom.xml b/orange-admin-service/application/pom.xml new file mode 100644 index 00000000..3aa12b80 --- /dev/null +++ b/orange-admin-service/application/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + + com.orange.admin + OrangeAdmin + 1.0.0 + + + application + 1.0.0 + application + jar + + + + + com.orange.admin + common-biz + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + org.mybatis.generator + mybatis-generator-maven-plugin + ${mybatis-generator.version} + + ${project.basedir}/src/main/resources/generator/generatorConfig.xml + true + true + + + + mysql + mysql-connector-java + 8.0.13 + + + tk.mybatis + mapper + 4.0.0 + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/MyApplication.java b/orange-admin-service/application/src/main/java/com/orange/admin/MyApplication.java new file mode 100644 index 00000000..0df246aa --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/MyApplication.java @@ -0,0 +1,12 @@ +package com.orange.admin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MyApplication { + + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/AreaCodeController.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/AreaCodeController.java new file mode 100644 index 00000000..da7f958f --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/AreaCodeController.java @@ -0,0 +1,56 @@ +package com.orange.admin.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.orange.admin.app.model.AreaCode; +import com.orange.admin.app.service.AreaCodeService; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/application/src/main/java/com/orange/admin/app/controller/TeacherController.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/TeacherController.java new file mode 100644 index 00000000..d86779c7 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/TeacherController.java @@ -0,0 +1,199 @@ +package com.orange.admin.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.PageHelper; +import com.orange.admin.app.model.*; +import com.orange.admin.app.service.*; +import com.orange.admin.upms.model.*; +import com.orange.admin.common.core.object.*; +import com.orange.admin.common.core.util.*; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.annotation.MyRequestBody; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/teacher") +public class TeacherController { + + @Autowired + private TeacherService teacherService; + + /** + * 新增老师数据源数据。 + * + * @param teacher 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody Teacher teacher) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(teacher); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + // 验证关联Id的数据合法性 + VerifyResult verifyResult = teacherService.verifyRelatedData(teacher, null); + if (!verifyResult.isSuccess()) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + errorMessage = verifyResult.getErrorMessage(); + break; + } + teacher = teacherService.saveNew(teacher); + responseData = new JSONObject(); + responseData.put("teacherId", teacher.getTeacherId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新老师数据源数据。 + * + * @param teacher 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody Teacher teacher) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(teacher, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + // 验证关联Id的数据合法性 + Teacher originalTeacher = teacherService.getById(teacher.getTeacherId()); + if (originalTeacher == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + //TODO 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + break; + } + // 验证关联Id的数据合法性 + VerifyResult verifyResult = teacherService.verifyRelatedData(teacher, originalTeacher); + if (!verifyResult.isSuccess()) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + errorMessage = verifyResult.getErrorMessage(); + break; + } + if (!teacherService.update(teacher, originalTeacher)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除老师数据源数据。 + * + * @param teacherId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long teacherId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(teacherId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + // 验证关联Id的数据合法性 + Teacher originalTeacher = teacherService.getById(teacherId); + if (originalTeacher == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + //TODO 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + break; + } + if (!teacherService.remove(teacherId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 列出符合过滤条件的老师数据源列表。 + * + * @param teacherFilter 过滤对象。 + * @param sysDeptFilter 一对一从表过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody Teacher teacherFilter, + @MyRequestBody SysDept sysDeptFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, Teacher.class); + List resultList = + teacherService.getTeacherListWithRelation(teacherFilter, sysDeptFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定老师数据源对象详情。 + * + * @param teacherId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long teacherId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + Teacher teacher = null; + do { + if (MyCommonUtil.existBlankArgument(teacherId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + teacher = teacherService.getByIdWithRelation(teacherId); + if (teacher == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, teacher); + } + + /** + * 以字典形式返回全部老师数据源数据集合。字典的键值为[teacherId, teacherName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictTeacher") + public ResponseResult listDictTeacher(Teacher filter) { + List resultList = teacherService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "teacherId as id", "teacherName as name").executeFrom(resultList)); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/TeacherTransStatsController.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/TeacherTransStatsController.java new file mode 100644 index 00000000..1786ffdb --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/controller/TeacherTransStatsController.java @@ -0,0 +1,105 @@ +package com.orange.admin.app.controller; + +import com.github.pagehelper.PageHelper; +import com.orange.admin.app.model.*; +import com.orange.admin.app.service.*; +import com.orange.admin.common.core.object.*; +import com.orange.admin.common.core.util.*; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.annotation.MyRequestBody; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * 老师流水统计操作控制器类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +@RestController +@RequestMapping("/admin/app/teacherTransStats") +public class TeacherTransStatsController { + + @Autowired + private TeacherTransStatsService teacherTransStatsService; + + /** + * 列出符合过滤条件的老师流水统计列表。 + * + * @param teacherTransStatsFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody TeacherTransStats teacherTransStatsFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, TeacherTransStats.class); + List resultList = teacherTransStatsService.getTeacherTransStatsListWithRelation(teacherTransStatsFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 分组列出符合过滤条件的老师流水统计列表。 + * + * @param teacherTransStatsFilter 过滤对象。 + * @param groupParam 分组参数。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/listWithGroup") + public ResponseResult listWithGroup( + @MyRequestBody TeacherTransStats teacherTransStatsFilter, + @MyRequestBody MyGroupParam groupParam, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String orderBy = MyOrderParam.buildOrderBy(orderParam, TeacherTransStats.class); + groupParam = MyGroupParam.buildGroupBy(groupParam, TeacherTransStats.class); + if (groupParam == null) { + return ResponseResult.error( + ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!"); + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + MyGroupCriteria criteria = groupParam.getGroupCriteria(); + List resultList = teacherTransStatsService.getGroupedTeacherTransStatsListWithRelation( + teacherTransStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定老师流水统计对象详情。 + * + * @param statsId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long statsId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + TeacherTransStats teacherTransStats = null; + do { + if (MyCommonUtil.existBlankArgument(statsId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + teacherTransStats = teacherTransStatsService.getByIdWithRelation(statsId); + if (teacherTransStats == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, teacherTransStats); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/AreaCodeMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/AreaCodeMapper.java new file mode 100644 index 00000000..f57475ca --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/AreaCodeMapper.java @@ -0,0 +1,13 @@ +package com.orange.admin.app.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.app.model.AreaCode; + +/** + * 行政区划数据操作访问接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface AreaCodeMapper extends BaseDaoMapper { +} \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/TeacherMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/TeacherMapper.java new file mode 100644 index 00000000..bc906658 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/TeacherMapper.java @@ -0,0 +1,42 @@ +package com.orange.admin.app.dao; + +import com.orange.admin.common.core.annotation.EnableDataPerm; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.app.model.Teacher; +import com.orange.admin.upms.model.SysDept; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 老师数据源数据操作访问接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@EnableDataPerm +public interface TeacherMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param teacherFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getTeacherList( + @Param("teacherFilter") Teacher teacherFilter, @Param("orderBy") String orderBy); + + /** + * 获取过滤后的对象列表。同时支持基于一对一从表字段的过滤条件。 + * + * @param teacherFilter 主表过滤对象。 + * @param sysDeptFilter 一对一从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getTeacherListEx( + @Param("teacherFilter") Teacher teacherFilter, + @Param("sysDeptFilter") SysDept sysDeptFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/TeacherTransStatsMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/TeacherTransStatsMapper.java new file mode 100644 index 00000000..2d836de0 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/TeacherTransStatsMapper.java @@ -0,0 +1,43 @@ +package com.orange.admin.app.dao; + +import com.orange.admin.common.core.annotation.EnableDataPerm; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.app.model.TeacherTransStats; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 老师流水统计数据操作访问接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@EnableDataPerm +public interface TeacherTransStatsMapper extends BaseDaoMapper { + + /** + * 获取分组计算后的数据对象列表。 + * + * @param teacherTransStatsFilter 主表过滤对象。 + * @param groupSelect 分组显示字段列表字符串,SELECT从句的参数。 + * @param groupBy 分组字段列表字符串,GROUP BY从句的参数。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 对象列表。 + */ + List getGroupedTeacherTransStatsList( + @Param("teacherTransStatsFilter") TeacherTransStats teacherTransStatsFilter, + @Param("groupSelect") String groupSelect, + @Param("groupBy") String groupBy, + @Param("orderBy") String orderBy); + + /** + * 获取过滤后的对象列表。 + * + * @param teacherTransStatsFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getTeacherTransStatsList( + @Param("teacherTransStatsFilter") TeacherTransStats teacherTransStatsFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/AreaCodeMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/AreaCodeMapper.xml new file mode 100644 index 00000000..8263c7c1 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/AreaCodeMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/TeacherMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/TeacherMapper.xml new file mode 100644 index 00000000..a88eb664 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/TeacherMapper.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + AND zz_teacher.teacher_name LIKE #{safeTeacherName} + + + AND zz_teacher.birthday >= #{teacherFilter.birthdayStart} + + + AND zz_teacher.birthday <= #{teacherFilter.birthdayEnd} + + + AND zz_teacher.gender = #{teacherFilter.gender} + + + AND zz_teacher.subject_id = #{teacherFilter.subjectId} + + + AND zz_teacher.level = #{teacherFilter.level} + + + AND zz_teacher.school_id = #{teacherFilter.schoolId} + + + AND zz_teacher.register_date >= #{teacherFilter.registerDateStart} + + + AND zz_teacher.register_date <= #{teacherFilter.registerDateEnd} + + + AND zz_teacher.available = #{teacherFilter.available} + + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/TeacherTransStatsMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/TeacherTransStatsMapper.xml new file mode 100644 index 00000000..15d47a2b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/dao/mapper/TeacherTransStatsMapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + AND zz_teacher_trans_stats.stats_date >= #{teacherTransStatsFilter.statsDateStart} + + + AND zz_teacher_trans_stats.stats_date <= #{teacherTransStatsFilter.statsDateEnd} + + + AND zz_teacher_trans_stats.school_id = #{teacherTransStatsFilter.schoolId} + + + AND zz_teacher_trans_stats.teacher_id = #{teacherTransStatsFilter.teacherId} + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/model/AreaCode.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/AreaCode.java new file mode 100644 index 00000000..738c16ef --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/AreaCode.java @@ -0,0 +1,35 @@ +package com.orange.admin.app.model; + +import lombok.Data; + +import javax.persistence.*; + +@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-admin-service/application/src/main/java/com/orange/admin/app/model/Teacher.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/Teacher.java new file mode 100644 index 00000000..0cc8d9b6 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/Teacher.java @@ -0,0 +1,179 @@ +package com.orange.admin.app.model; + +import com.orange.admin.upms.model.SysDept; +import com.orange.admin.upms.model.SysUser; +import com.orange.admin.app.model.constant.Gender; +import com.orange.admin.common.biz.constant.Subject; +import com.orange.admin.app.model.constant.TeacherLevelType; +import com.orange.admin.common.biz.constant.YesNo; +import com.orange.admin.common.core.annotation.RelationDict; +import com.orange.admin.common.core.annotation.RelationConstDict; +import com.orange.admin.common.core.annotation.RelationOneToOne; +import com.orange.admin.common.core.annotation.DeptFilterColumn; +import com.orange.admin.common.core.annotation.UserFilterColumn; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.common.core.validator.ConstDictRef; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +@Data +@Table(name = "zz_teacher") +public class Teacher { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @UserFilterColumn + @Column(name = "teacher_id") + private Long teacherId; + + /** + * 教师名称。 + */ + @NotBlank(message = "数据验证失败,教师名称不能为空!") + @Column(name = "teacher_name") + private String teacherName; + + /** + * 教师生日。 + */ + @NotNull(message = "数据验证失败,出生日期不能为空!") + private Date birthday; + + /** + * 教师性别(0: 女 1: 男)。 + */ + @NotNull(message = "数据验证失败,性别不能为空!") + @ConstDictRef(constDictClass = Gender.class, message = "数据验证失败,性别为无效值!") + private Integer gender; + + /** + * 所教的科目Id。 + */ + @NotNull(message = "数据验证失败,所教科目不能为空!") + @ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所教科目为无效值!") + @Column(name = "subject_id") + private Integer subjectId; + + /** + * 教师职级(0: 初级 1: 中级 2: 高级)。 + */ + @NotNull(message = "数据验证失败,职级不能为空!") + @ConstDictRef(constDictClass = TeacherLevelType.class, message = "数据验证失败,职级为无效值!") + private Integer level; + + /** + * 鲜花数量。 + */ + @Column(name = "flower_count") + private Integer flowerCount; + + /** + * 校区Id。 + */ + @NotNull(message = "数据验证失败,所属校区不能为空!") + @DeptFilterColumn + @Column(name = "school_id") + private Long schoolId; + + /** + * 用户Id。 + */ + @NotNull(message = "数据验证失败,绑定用户不能为空!") + @Column(name = "user_id") + private Long userId; + + /** + * 入职时间。 + */ + @Column(name = "register_date") + private Date registerDate; + + /** + * 是否在职。 + */ + @NotNull(message = "数据验证失败,是否在职不能为空!") + @ConstDictRef(constDictClass = YesNo.class, message = "数据验证失败,是否在职为无效值!") + private Integer available; + + /** + * birthday 范围过滤起始值(>=)。 + */ + @Transient + private String birthdayStart; + + /** + * birthday 范围过滤结束值(<=)。 + */ + @Transient + private String birthdayEnd; + + /** + * registerDate 范围过滤起始值(>=)。 + */ + @Transient + private String registerDateStart; + + /** + * registerDate 范围过滤结束值(<=)。 + */ + @Transient + private String registerDateEnd; + + @RelationOneToOne( + masterIdField = "schoolId", + slaveServiceName = "sysDeptService", + slaveModelClass = SysDept.class, + slaveIdField = "deptId") + @Transient + private SysDept sysDept; + + @RelationDict( + masterIdField = "schoolId", + slaveServiceName = "sysDeptService", + equalOneToOneRelationField = "sysDept", + slaveModelClass = SysDept.class, + slaveIdField = "deptId", + slaveNameField = "deptName") + @Transient + private Map schoolIdDictMap; + + @RelationDict( + masterIdField = "userId", + slaveServiceName = "sysUserService", + slaveModelClass = SysUser.class, + slaveIdField = "userId", + slaveNameField = "loginName") + @Transient + private Map userIdDictMap; + + @RelationConstDict( + masterIdField = "gender", + constantDictClass = Gender.class) + @Transient + private Map genderDictMap; + + @RelationConstDict( + masterIdField = "subjectId", + constantDictClass = Subject.class) + @Transient + private Map subjectIdDictMap; + + @RelationConstDict( + masterIdField = "level", + constantDictClass = TeacherLevelType.class) + @Transient + private Map levelDictMap; + + @RelationConstDict( + masterIdField = "available", + constantDictClass = YesNo.class) + @Transient + private Map availableDictMap; +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/model/TeacherTransStats.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/TeacherTransStats.java new file mode 100644 index 00000000..e67f551f --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/TeacherTransStats.java @@ -0,0 +1,172 @@ +package com.orange.admin.app.model; + +import com.orange.admin.upms.model.SysDept; +import com.orange.admin.common.core.annotation.RelationDict; +import com.orange.admin.common.core.annotation.RelationOneToOne; +import com.orange.admin.common.core.annotation.DeptFilterColumn; +import com.orange.admin.common.core.annotation.UserFilterColumn; +import com.orange.admin.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; +import java.util.Map; + +@Data +@Table(name = "zz_teacher_trans_stats") +public class TeacherTransStats { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "stats_id") + private Long statsId; + + /** + * 统计日期。 + */ + @NotNull(message = "数据验证失败,统计日期不能为空!") + @Column(name = "stats_date") + private Date statsDate; + + /** + * 统计月份。 + */ + @NotNull(message = "数据验证失败,统计月份不能为空!") + @Column(name = "stats_month") + private Date statsMonth; + + /** + * 省份Id。 + */ + @NotNull(message = "数据验证失败,省份不能为空!") + @Column(name = "province_id") + private Long provinceId; + + /** + * 城市Id。 + */ + @NotNull(message = "数据验证失败,城市不能为空!") + @Column(name = "city_id") + private Long cityId; + + /** + * 学校Id。 + */ + @NotNull(message = "数据验证失败,校区不能为空!") + @DeptFilterColumn + @Column(name = "school_id") + private Long schoolId; + + /** + * 学校名称。 + */ + @NotBlank(message = "数据验证失败,学校名称不能为空!") + @Column(name = "school_name") + private String schoolName; + + /** + * 老师Id。 + */ + @NotNull(message = "数据验证失败,老师不能为空!") + @UserFilterColumn + @Column(name = "teacher_id") + private Long teacherId; + + /** + * 老师名称。 + */ + @NotBlank(message = "数据验证失败,老师名称不能为空!") + @Column(name = "teacher_name") + private String teacherName; + + /** + * 视频观看数量。 + */ + @NotNull(message = "数据验证失败,视频观看数量不能为空!") + @Column(name = "video_watch_count") + private Integer videoWatchCount; + + /** + * 献花数量。 + */ + @NotNull(message = "数据验证失败,献花数量不能为空!") + @Column(name = "flower_count") + private Integer flowerCount; + + /** + * 新增学生数量。 + */ + @NotNull(message = "数据验证失败,新增学生数量不能为空!") + @Column(name = "new_student") + private Integer newStudent; + + /** + * statsDate 范围过滤起始值(>=)。 + */ + @Transient + private String statsDateStart; + + /** + * statsDate 范围过滤结束值(<=)。 + */ + @Transient + private String statsDateEnd; + + @RelationOneToOne( + masterIdField = "schoolId", + slaveServiceName = "sysDeptService", + slaveModelClass = SysDept.class, + slaveIdField = "deptId") + @Transient + private SysDept sysDept; + + @RelationOneToOne( + masterIdField = "teacherId", + slaveServiceName = "teacherService", + slaveModelClass = Teacher.class, + slaveIdField = "teacherId") + @Transient + private Teacher teacher; + + @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 = "schoolId", + slaveServiceName = "sysDeptService", + equalOneToOneRelationField = "sysDept", + slaveModelClass = SysDept.class, + slaveIdField = "deptId", + slaveNameField = "deptName") + @Transient + private Map schoolIdDictMap; + + @RelationDict( + masterIdField = "teacherId", + slaveServiceName = "teacherService", + equalOneToOneRelationField = "teacher", + slaveModelClass = Teacher.class, + slaveIdField = "teacherId", + slaveNameField = "teacherName") + @Transient + private Map teacherIdDictMap; +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/model/constant/Gender.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/constant/Gender.java new file mode 100644 index 00000000..1e9ac202 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/constant/Gender.java @@ -0,0 +1,38 @@ +package com.orange.admin.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +public final class Gender { + + /** + * 男。 + */ + public static final int MALE = 1; + /** + * 女。 + */ + public static final int FEMALE = 0; + + public 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(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private Gender() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/model/constant/TeacherLevelType.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/constant/TeacherLevelType.java new file mode 100644 index 00000000..cdccf1c7 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/model/constant/TeacherLevelType.java @@ -0,0 +1,43 @@ +package com.orange.admin.app.model.constant; + +import java.util.HashMap; +import java.util.Map; + +public final class TeacherLevelType { + + /** + * 初级。 + */ + public static final int LOWER = 0; + /** + * 中级。 + */ + public static final int NORMAL = 1; + /** + * 高级。 + */ + public static final int HIGH = 2; + + public static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(LOWER, "初级"); + DICT_MAP.put(NORMAL, "中级"); + DICT_MAP.put(HIGH, "高级"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private TeacherLevelType() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/service/AreaCodeService.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/service/AreaCodeService.java new file mode 100644 index 00000000..3a2ebe6f --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/service/AreaCodeService.java @@ -0,0 +1,57 @@ +package com.orange.admin.app.service; + +import com.orange.admin.app.dao.AreaCodeMapper; +import com.orange.admin.app.model.AreaCode; +import com.orange.admin.common.core.cache.MapTreeDictionaryCache; +import com.orange.admin.common.core.base.service.BaseDictService; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/application/src/main/java/com/orange/admin/app/service/TeacherService.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/service/TeacherService.java new file mode 100644 index 00000000..ba6cc49b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/service/TeacherService.java @@ -0,0 +1,151 @@ +package com.orange.admin.app.service; + +import com.orange.admin.app.dao.*; +import com.orange.admin.app.model.*; +import com.orange.admin.upms.model.*; +import com.orange.admin.upms.service.SysUserService; +import com.orange.admin.upms.service.SysDeptService; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.object.MyWhereCriteria; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.biz.util.BasicIdGenerator; +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 Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class TeacherService extends BaseService { + + @Autowired + private TeacherMapper teacherMapper; + @Autowired + private SysDeptService sysDeptService; + @Autowired + private SysUserService sysUserService; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return teacherMapper; + } + + /** + * 保存新增对象。 + * + * @param teacher 新增对象。 + * @return 返回新增对象。 + */ + @Transactional + public Teacher saveNew(Teacher teacher) { + teacher.setTeacherId(idGenerator.nextLongId()); + teacher.setRegisterDate(new Date()); + teacherMapper.insert(teacher); + return teacher; + } + + /** + * 更新数据对象。 + * + * @param teacher 更新的对象。 + * @param originalTeacher 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional + public boolean update(Teacher teacher, Teacher originalTeacher) { + teacher.setRegisterDate(originalTeacher.getRegisterDate()); + return teacherMapper.updateByPrimaryKey(teacher) == 1; + } + + /** + * 删除指定数据。 + * + * @param teacherId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional + public boolean remove(Long teacherId) { + Teacher teacher = teacherMapper.selectByPrimaryKey(teacherId); + if (teacher == null) { + return false; + } + // 这里先删除主数据 + if (teacherMapper.deleteByPrimaryKey(teacherId) == 0) { + return false; + } + // 这里可继续删除关联数据。 + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getTeacherListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getTeacherList(Teacher filter, String orderBy) { + return teacherMapper.getTeacherList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getTeacherList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param sysDeptFilter 一对一从表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getTeacherListWithRelation(Teacher filter, SysDept sysDeptFilter, String orderBy) { + List resultList = + teacherMapper.getTeacherListEx(filter, sysDeptFilter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildAllRelationForDataList(resultList, false, criteriaMap); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param teacher 最新数据对象。 + * @param originalTeacher 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + public VerifyResult verifyRelatedData(Teacher teacher, Teacher originalTeacher) { + String errorMessage = null; + do { + //这里是基于字典的验证。 + if (this.needToVerify(teacher, originalTeacher, Teacher::getSchoolId)) { + if (!sysDeptService.existId(teacher.getSchoolId())) { + errorMessage = "数据验证失败,关联的所属校区并不存在,请刷新后重试!"; + break; + } + } + //这里是基于字典的验证。 + if (this.needToVerify(teacher, originalTeacher, Teacher::getUserId)) { + if (!sysUserService.existId(teacher.getUserId())) { + errorMessage = "数据验证失败,关联的绑定用户并不存在,请刷新后重试!"; + break; + } + } + } while (false); + return VerifyResult.create(errorMessage); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/app/service/TeacherTransStatsService.java b/orange-admin-service/application/src/main/java/com/orange/admin/app/service/TeacherTransStatsService.java new file mode 100644 index 00000000..9b97d29b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/app/service/TeacherTransStatsService.java @@ -0,0 +1,87 @@ +package com.orange.admin.app.service; + +import com.orange.admin.app.dao.*; +import com.orange.admin.app.model.*; +import com.orange.admin.upms.service.SysDeptService; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.object.MyWhereCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 老师流水统计数据操作服务类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class TeacherTransStatsService extends BaseService { + + @Autowired + private TeacherTransStatsMapper teacherTransStatsMapper; + @Autowired + private AreaCodeService areaCodeService; + @Autowired + private SysDeptService sysDeptService; + @Autowired + private TeacherService teacherService; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return teacherTransStatsMapper; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getTeacherTransStatsListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getTeacherTransStatsList(TeacherTransStats filter, String orderBy) { + return teacherTransStatsMapper.getTeacherTransStatsList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getTeacherTransStatsList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getTeacherTransStatsListWithRelation(TeacherTransStats filter, String orderBy) { + List resultList = teacherTransStatsMapper.getTeacherTransStatsList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildAllRelationForDataList(resultList, false, criteriaMap); + return resultList; + } + + /** + * 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param filter 过滤对象。 + * @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。 + * @param groupBy 分组参数。位于SQL语句的GROUP BY后面。 + * @param orderBy 排序字符串,ORDER BY从句的参数。 + * @return 分组过滤结果集。 + */ + public List getGroupedTeacherTransStatsListWithRelation( + TeacherTransStats filter, String groupSelect, String groupBy, String orderBy) { + List resultList = + teacherTransStatsMapper.getGroupedTeacherTransStatsList(filter, groupSelect, groupBy, orderBy); + // NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。 + // 主要原因是,由于聚合字段通常被视为普通字段使用,不会在group by的从句中出现,语义上也不会在此关联。 + this.buildRelationForDataList(resultList, false); + return resultList; + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/config/ApplicationConfig.java b/orange-admin-service/application/src/main/java/com/orange/admin/config/ApplicationConfig.java new file mode 100644 index 00000000..557c28f5 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/config/ApplicationConfig.java @@ -0,0 +1,46 @@ +package com.orange.admin.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 应用程序自定义的程序属性配置文件。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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; + /** + * 用户密码加密用的salt值。 + */ + private String passwordSalt; + /** + * 用户密码被重置之后的缺省密码 + */ + 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-admin-service/application/src/main/java/com/orange/admin/config/CacheConfig.java b/orange-admin-service/application/src/main/java/com/orange/admin/config/CacheConfig.java new file mode 100644 index 00000000..5a915938 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/config/CacheConfig.java @@ -0,0 +1,102 @@ +package com.orange.admin.config; + +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 Stephen.Liu + * @date 2020-04-11 + */ +@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 { + /** + * 专门存储用户权限的缓存。 + */ + UserPermissionCache(1800), + /** + * 专门存储用户数据权限的缓存。 + */ + DataPermissionCache(7200), + /** + * 缺省全局缓存(时间是24小时)。 + */ + GlobalCache(86400,20000); + + CacheEnum() { + } + + CacheEnum(int ttl) { + this.ttl = ttl; + } + + 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 void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + public int getTtl() { + return ttl; + } + + public void setTtl(int ttl) { + this.ttl = 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-admin-service/application/src/main/java/com/orange/admin/config/DataSourceConfig.java b/orange-admin-service/application/src/main/java/com/orange/admin/config/DataSourceConfig.java new file mode 100644 index 00000000..6ae3ae16 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/config/DataSourceConfig.java @@ -0,0 +1,30 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Configuration +@EnableTransactionManagement +@MapperScan(value = {"com.orange.admin.*.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-admin-service/application/src/main/java/com/orange/admin/config/FilterConfig.java b/orange-admin-service/application/src/main/java/com/orange/admin/config/FilterConfig.java new file mode 100644 index 00000000..295099b9 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/config/FilterConfig.java @@ -0,0 +1,63 @@ +package com.orange.admin.config; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +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 Stephen.Liu + * @date 2020-04-11 + */ +@Configuration +public class FilterConfig { + + @Autowired + private ApplicationConfig applicationConfig; + + /** + * 配置Ajax跨域过滤器 + */ + @Bean + public CorsFilter corsFilterRegistration() { + UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + if (StringUtils.isNotBlank(applicationConfig.getCredentialIpList())) { + String[] credentialIpList = StringUtils.split(applicationConfig.getCredentialIpList(), ","); + if (credentialIpList.length == 0) { + corsConfiguration.addAllowedOrigin("*"); + } else { + 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-admin-service/application/src/main/java/com/orange/admin/config/InterceptorConfig.java b/orange-admin-service/application/src/main/java/com/orange/admin/config/InterceptorConfig.java new file mode 100644 index 00000000..3753886b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/config/InterceptorConfig.java @@ -0,0 +1,53 @@ +package com.orange.admin.config; + +import com.orange.admin.interceptor.AuthenticationInterceptor; +import com.orange.admin.common.biz.interceptor.AccessInterceptor; +import com.orange.admin.common.biz.interceptor.MyRequestArgumentResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +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.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * 所有的项目拦截器都在这里集中配置 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/**"); + registry.addInterceptor(new AccessInterceptor()).addPathPatterns("/**"); + } + + @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); + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(responseBodyConverter()); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/interceptor/AuthenticationInterceptor.java b/orange-admin-service/application/src/main/java/com/orange/admin/interceptor/AuthenticationInterceptor.java new file mode 100644 index 00000000..4b7a4083 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/interceptor/AuthenticationInterceptor.java @@ -0,0 +1,137 @@ +package com.orange.admin.interceptor; + +import com.orange.admin.config.CacheConfig; +import com.orange.admin.config.ApplicationConfig; +import com.orange.admin.upms.model.SysPermWhitelist; +import com.orange.admin.upms.service.SysPermWhitelistService; +import com.orange.admin.upms.service.SysPermService; +import com.orange.admin.common.core.annotation.NoAuthInterface; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.util.ApplicationContextHolder; +import com.orange.admin.common.core.util.JwtUtil; +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 org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +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 Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +public class AuthenticationInterceptor implements HandlerInterceptor { + + private ApplicationConfig applicationConfig = + ApplicationContextHolder.getBean("applicationConfig"); + + private CacheManager cacheManager = + ApplicationContextHolder.getBean("cacheManager"); + + 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(applicationConfig.getTokenHeaderKey()); + if (StringUtils.isBlank(token)) { + token = request.getParameter(applicationConfig.getTokenHeaderKey()); + } + Claims c = JwtUtil.parseToken(token, applicationConfig.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"); + Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.GlobalCache.name()); + TokenData tokenData = cache.get(sessionId, TokenData.class); + if (tokenData == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已失效,请重新登录!")); + return false; + } + TokenData.addToRequest(tokenData); + if (!tokenData.getIsAdmin()) { + // 如果url在权限资源白名单中,则不需要进行鉴权操作 + if (!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, applicationConfig.getTokenSigningKey()); + response.addHeader(applicationConfig.getRefreshedTokenHeaderKey(), refreshedToken); + } + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + } + + 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-admin-service/application/src/main/java/com/orange/admin/interceptor/MybatisDataPermInterceptor.java b/orange-admin-service/application/src/main/java/com/orange/admin/interceptor/MybatisDataPermInterceptor.java new file mode 100644 index 00000000..8eb8ad08 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/interceptor/MybatisDataPermInterceptor.java @@ -0,0 +1,279 @@ +package com.orange.admin.interceptor; + +import cn.hutool.core.util.ReflectUtil; +import com.orange.admin.common.core.constant.DataPermRuleType; +import com.orange.admin.common.core.annotation.DeptFilterColumn; +import com.orange.admin.common.core.annotation.UserFilterColumn; +import com.orange.admin.common.core.annotation.EnableDataPerm; +import com.orange.admin.common.core.object.GlobalThreadLocal; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.util.ApplicationContextHolder; +import com.orange.admin.common.core.util.ContextUtil; +import com.orange.admin.common.core.util.MyModelUtil; +import com.orange.admin.config.CacheConfig; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.select.FromItem; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SubSelect; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.executor.statement.RoutingStatementHandler; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.dao.PermissionDeniedDataAccessException; +import org.springframework.stereotype.Component; +import tk.mybatis.mapper.common.Mapper; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.sql.Connection; +import java.util.*; + +/** + * Mybatis拦截器。目前用于数据权限的统一拦截和注入处理。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) +@Slf4j +@Component +public class MybatisDataPermInterceptor implements Interceptor { + + @Autowired + private CacheManager cacheManager; + + /** + * HTTP Head或HTTP Request Parameter中菜单Id数据的KEY名称。 + */ + private final static String MENU_ID_HEADER_KEY = "MenuId"; + /** + * 对象缓存。由于Set是排序后的,因为在查找排除方法名称时效率更高。 + * 在应用服务启动的监听器中(LoadDataPermMapperListener),会调用当前对象的(loadMappersWithDataPerm)方法,加载缓存。 + */ + private Map cacheMap = new HashMap<>(); + + /** + * 预先加载需要数据权限过滤的Mapper到缓存,该函数会在(LoadDataPermMapperListener)监听器中调用。 + */ + public void loadMappersWithDataPerm() { + Map mapperMap = + ApplicationContextHolder.getApplicationContext().getBeansOfType(Mapper.class); + for (Mapper mapperProxy : mapperMap.values()) { + // 优先处理jdk的代理 + Object proxy = ReflectUtil.getFieldValue(mapperProxy, "h"); + // 如果不是jdk的代理,再看看cjlib的代理。 + if (proxy == null) { + proxy = ReflectUtil.getFieldValue(mapperProxy, "CGLIB$CALLBACK_0"); + } + Class mapperClass = + (Class) ReflectUtil.getFieldValue(proxy, "mapperInterface"); + EnableDataPerm rule = mapperClass.getAnnotation(EnableDataPerm.class); + if (rule != null) { + // 由于给数据权限Mapper添加@EnableDataPerm,将会导致无限递归,因此这里检测到之后, + // 会在系统启动加载监听器的时候,及时抛出异常。 + if ("SysDataPermMapper".equals(mapperClass.getSimpleName())) { + throw new IllegalStateException("Add @EnableDataPerm annotation to SysDataPermMapper is ILLEGAL!"); + } + // 这里开始获取当前Mapper已经声明的的SqlId中,有哪些是需要排除在外的。 + // 排除在外的将不进行数据过滤。 + Set excludeMethodNameSet = null; + String[] excludes = rule.excluseMethodName(); + if (excludes.length > 0) { + excludeMethodNameSet = new HashSet<>(); + for (String excludeName : excludes) { + excludeMethodNameSet.add(excludeName); + // 这里是给tk.mapper和pagehelper中,分页查询先获取数据总量的查询。 + excludeMethodNameSet.add(excludeName + "_COUNT"); + } + } + // 获取Mapper关联的主表信息,包括表名,user过滤字段名和dept过滤字段名。 + Class modelClazz = (Class) + ((ParameterizedType) mapperClass.getGenericInterfaces()[0]).getActualTypeArguments()[0]; + Field[] fields = ReflectUtil.getFields(modelClazz); + Field userFilterField = null, deptFilterField = null; + for (Field field : fields) { + if (null != field.getAnnotation(UserFilterColumn.class)) { + userFilterField = field; + } + if (null != field.getAnnotation(DeptFilterColumn.class)) { + deptFilterField = field; + } + if (userFilterField != null && deptFilterField != null) { + break; + } + } + // 通过注解解析与Mapper关联的Model,并获取与数据权限关联的信息,并将结果缓存。 + ModelDataPermInfo info = new ModelDataPermInfo(); + info.setMainTableName(MyModelUtil.mapToTableName(modelClazz)); + info.setExcludeMethodNameSet(excludeMethodNameSet); + if (userFilterField != null) { + info.setUserFilterColumn(MyModelUtil.mapToColumnName(userFilterField, modelClazz)); + } + if (deptFilterField != null) { + info.setDeptFilterColumn(MyModelUtil.mapToColumnName(deptFilterField, modelClazz)); + } + String className = mapperClass.getName(); + cacheMap.put(mapperClass.getName(), info); + } + } + } + + @SuppressWarnings("unchecked") + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 只有在HttpServletRequest场景下,该拦截器才起作用,对于系统级别的预加载数据不会应用数据权限。 + if (!ContextUtil.hasRequestContext()) { + return invocation.proceed(); + } + // 判断当前线程本地存储中,业务操作是否禁用了数据权限过滤,如果禁用,则不进行后续的数据过滤处理了。 + if (!GlobalThreadLocal.enabledDataPerm()) { + return invocation.proceed(); + } + RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget(); + StatementHandler delegate = + (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate"); + //通过反射获取delegate父类BaseStatementHandler的mappedStatement属性 + MappedStatement mappedStatement = + (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement"); + SqlCommandType commandType = mappedStatement.getSqlCommandType(); + TokenData tokenData = TokenData.takeFromRequest(); + // 数据过滤权限中,只是过滤SELECT语句。如果是管理员则不参与数据权限的数据过滤,显示全部数据。 + if (commandType != SqlCommandType.SELECT || tokenData == null || tokenData.getIsAdmin()) { + return invocation.proceed(); + } + String sqlId = mappedStatement.getId(); + int pos = StringUtils.lastIndexOf(sqlId, "."); + String className = StringUtils.substring(sqlId, 0, pos); + String methodName = StringUtils.substring(sqlId, pos + 1); + // 先从缓存中查找当前Mapper是否存在。 + ModelDataPermInfo info = cacheMap.get(className); + if (info != null) { + // 再次查找当前方法是否为排除方法,如果不是,就参与数据权限注入过滤。 + if (info.getExcludeMethodNameSet() == null + || !info.getExcludeMethodNameSet().contains(methodName)) { + String menuId = ContextUtil.getHttpRequest().getHeader(MENU_ID_HEADER_KEY); + if (StringUtils.isBlank(menuId)) { + menuId = ContextUtil.getHttpRequest().getParameter(MENU_ID_HEADER_KEY); + if (StringUtils.isBlank(menuId)) { + throw new IllegalStateException( + "No [ MENU_ID ] key found in Http Header for SQL_ID [ " + sqlId + " ]."); + } + } + Cache cache = cacheManager.getCache(CacheConfig.CacheEnum.DataPermissionCache.name()); + Map> menuIdAndDataPermMap = + (Map>) cache.get(tokenData.getSessionId(), Map.class); + if (menuIdAndDataPermMap == null) { + throw new PermissionDeniedDataAccessException( + "No Related DataPerm found with SESSION_ID [ " + tokenData.getSessionId() + " ].", null); + } + Map dataPermMap = menuIdAndDataPermMap.get(Long.valueOf(menuId)); + if (MapUtils.isEmpty(dataPermMap)) { + throw new PermissionDeniedDataAccessException( + "No Related DataPerm found with MENU_ID [ " + menuId + " ] for SQL_ID [ " + sqlId + " ].", null); + } + if (dataPermMap.containsKey(DataPermRuleType.TYPE_ALL)) { + return invocation.proceed(); + } + BoundSql boundSql = delegate.getBoundSql(); + String sql = boundSql.getSql(); + Select select = (Select) CCJSqlParserUtil.parse(sql); + PlainSelect selectBody = (PlainSelect) select.getSelectBody(); + FromItem fromItem = selectBody.getFromItem(); + PlainSelect subSelect = null; + if (fromItem instanceof SubSelect) { + subSelect = (PlainSelect) ((SubSelect) fromItem).getSelectBody(); + } + List criteriaList = new LinkedList<>(); + for (Map.Entry entry : dataPermMap.entrySet()) { + Integer ruleType = entry.getKey(); + if (ruleType == DataPermRuleType.TYPE_USER_ONLY) { + if (StringUtils.isNotBlank(info.getUserFilterColumn())) { + StringBuilder filter = new StringBuilder(64); + filter.append(info.getMainTableName()) + .append(".") + .append(info.getUserFilterColumn()) + .append(" = ") + .append(tokenData.getUserId()); + criteriaList.add(filter.toString()); + } + } else { + if (StringUtils.isNotBlank(info.getDeptFilterColumn())) { + StringBuilder filter = new StringBuilder(128); + if (ruleType == DataPermRuleType.TYPE_DEPT_ONLY) { + filter.append(info.getMainTableName()) + .append(".") + .append(info.getDeptFilterColumn()) + .append(" = ") + .append(tokenData.getDeptId()); + } else if (ruleType == DataPermRuleType.TYPE_CUSTOM_DETP_LIST) { + filter.append(info.getMainTableName()) + .append(".") + .append(info.getDeptFilterColumn()) + .append(" IN (") + .append(entry.getValue()) + .append(") "); + } + criteriaList.add(filter.toString()); + } + } + } + if (criteriaList.size() > 0) { + StringBuilder filterBuilder = new StringBuilder(128); + filterBuilder.append("("); + filterBuilder.append(StringUtils.join(criteriaList, " OR ")); + filterBuilder.append(")"); + String dataFilter = filterBuilder.toString(); + if (subSelect != null) { + if (subSelect.getWhere() == null) { + subSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter)); + } else { + AndExpression and = new AndExpression( + CCJSqlParserUtil.parseCondExpression(dataFilter), subSelect.getWhere()); + subSelect.setWhere(and); + } + } else { + if (selectBody.getWhere() == null) { + selectBody.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter)); + } else { + AndExpression and = new AndExpression( + CCJSqlParserUtil.parseCondExpression(dataFilter), selectBody.getWhere()); + selectBody.setWhere(and); + } + } + } + sql = select.toString(); + ReflectUtil.setFieldValue(boundSql, "sql", sql); + } + } + return invocation.proceed(); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } + + @Data + private static final class ModelDataPermInfo { + private Set excludeMethodNameSet; + private String userFilterColumn; + private String deptFilterColumn; + private String mainTableName; + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/listener/LoadDataPermMapperListener.java b/orange-admin-service/application/src/main/java/com/orange/admin/listener/LoadDataPermMapperListener.java new file mode 100644 index 00000000..91686225 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/listener/LoadDataPermMapperListener.java @@ -0,0 +1,25 @@ +package com.orange.admin.listener; + +import com.orange.admin.interceptor.MybatisDataPermInterceptor; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +/** + * 应用服务启动监听器。 + * 目前主要功能是调用DataPermInterceptor中的loadMappersWithEnableDataPerm方法, + * 将标记有数据权限规则注解的Mapper对象,加载到缓存,以提升系统运行时效率。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Component +public class LoadDataPermMapperListener implements ApplicationListener { + + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + MybatisDataPermInterceptor interceptor = + applicationReadyEvent.getApplicationContext().getBean(MybatisDataPermInterceptor.class); + interceptor.loadMappersWithDataPerm(); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/LoginController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/LoginController.java new file mode 100644 index 00000000..7e1fcba8 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/LoginController.java @@ -0,0 +1,128 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.config.ApplicationConfig; +import com.orange.admin.config.CacheConfig; +import com.orange.admin.upms.service.*; +import com.orange.admin.upms.model.SysMenu; +import com.orange.admin.upms.model.SysUser; +import com.orange.admin.upms.model.constant.SysUserStatus; +import com.orange.admin.upms.model.constant.SysUserType; +import com.orange.admin.common.core.annotation.NoAuthInterface; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.util.JwtUtil; +import com.orange.admin.common.core.util.MyCommonUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 登录接口控制器类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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 SysDataPermService sysDataPermService; + @Autowired + private ApplicationConfig appConfig; + @Autowired + private CacheManager cacheManager; + + /** + * 登录接口。 + * + * @param loginName 登录名。 + * @param password 密码。 + * @return 应答结果对象,其中包括JWT的Token数据,以及菜单列表。 + */ + @NoAuthInterface + @GetMapping("/doLogin") + public ResponseResult doLogin(@RequestParam String loginName, @RequestParam String password) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject jsonData = new JSONObject(); + do { + if (MyCommonUtil.existBlankArgument(loginName, password)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + SysUser user = sysUserService.getSysUserByLoginName(loginName); + if (user == null + || !user.getPassword().equals(MyCommonUtil.encrptedPassword(password, appConfig.getPasswordSalt()))) { + errorCodeEnum = ErrorCodeEnum.INVALID_USERNAME_PASSWORD; + break; + } + if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) { + errorCodeEnum = ErrorCodeEnum.INVALID_USER_STATUS; + errorMessage = "登录失败,用户账号被锁定!"; + break; + } + 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.getTokenSigningKey()); + 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.setDeptId(user.getDeptId()); + tokenData.setShowName(user.getShowName()); + tokenData.setIsAdmin(isAdmin); + Cache sessionCache = cacheManager.getCache(CacheConfig.CacheEnum.GlobalCache.name()); + sessionCache.put(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); + sysDataPermService.putDataPermCache(sessionId, user.getUserId(), user.getDeptId(), isAdmin); + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, jsonData); + } + + /** + * 登出操作。同时将Session相关的信息从缓存中删除。 + * + * @return 应答结果对象。 + */ + @PostMapping("/doLogout") + public ResponseResult doLogout() { + TokenData tokenData = TokenData.takeFromRequest(); + sysPermService.removeUserSysPermCache(tokenData.getSessionId()); + sysDataPermService.removeDataPermCache(tokenData.getSessionId()); + return ResponseResult.success(); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysDataPermController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysDataPermController.java new file mode 100644 index 00000000..e50d8ba1 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysDataPermController.java @@ -0,0 +1,338 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.upms.model.SysDataPermMenu; +import com.orange.admin.upms.model.SysDataPerm; +import com.orange.admin.upms.model.SysUser; +import com.orange.admin.upms.service.SysDataPermService; +import com.orange.admin.upms.service.SysUserService; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.core.object.MyOrderParam; +import com.orange.admin.common.core.object.MyPageParam; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.core.util.MyPageUtil; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysDataPerm") +public class SysDataPermController { + + @Autowired + private SysDataPermService sysDataPermService; + @Autowired + private SysUserService sysUserService; + + /** + * 添加新数据权限操作。 + * + * @param sysDataPerm 新增对象。 + * @param deptIdListString 数据权限关联的部门Id列表,多个之间逗号分隔。 + * @param menuIdListString 数据权限关联的菜单Id列表,多个之间逗号分隔。 + * @return 应答结果对象。包含新增数据权限对象的主键Id。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysDataPerm sysDataPerm, + @MyRequestBody String deptIdListString, + @MyRequestBody String menuIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(menuIdListString)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + errorMessage = MyCommonUtil.getModelValidationError(sysDataPerm); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + VerifyResult result = sysDataPermService.verifyRelatedData(sysDataPerm, deptIdListString, menuIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + List dataPermMenuList = null; + Set deptIdSet = null; + if (result.getData() != null) { + dataPermMenuList = (List) result.getData().get("dataPermMenuList"); + deptIdSet = (Set) result.getData().get("deptIdSet"); + } + sysDataPermService.saveNew(sysDataPerm, deptIdSet, dataPermMenuList); + responseData = new JSONObject(); + responseData.put("dataPermId", sysDataPerm.getDataPermId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新数据权限操作。 + * + * @param sysDataPerm 更新的数据权限对象。 + * @param deptIdListString 数据权限关联的部门Id列表,多个之间逗号分隔。 + * @param menuIdListString 数据权限关联的菜单Id列表,多个之间逗号分隔 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysDataPerm sysDataPerm, + @MyRequestBody String deptIdListString, + @MyRequestBody String menuIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(menuIdListString)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + errorMessage = MyCommonUtil.getModelValidationError(sysDataPerm, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysDataPerm originalSysDataPerm = sysDataPermService.getById(sysDataPerm.getDataPermId()); + if (originalSysDataPerm == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前数据权限并不存在,请刷新后重试!"; + break; + } + VerifyResult result = sysDataPermService.verifyRelatedData(sysDataPerm, deptIdListString, menuIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + List dataPermMenuList = null; + Set deptIdSet = null; + if (result.getData() != null) { + dataPermMenuList = (List) result.getData().get("dataPermMenuList"); + deptIdSet = (Set) result.getData().get("deptIdSet"); + } + if (!sysDataPermService.update(sysDataPerm, originalSysDataPerm, deptIdSet, dataPermMenuList)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "更新失败,数据不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除数据权限操作。 + * + * @param dataPermId 待删除数据权限主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long dataPermId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysDataPermService.remove(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,数据权限不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 查看数据权限列表。 + * + * @param sysDataPermFilter 数据权限查询过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象。包含数据权限列表。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SysDataPerm sysDataPermFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysDataPerm.class); + List resultList = sysDataPermService.getSysDataPermList(sysDataPermFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看单条数据权限详情。 + * + * @param dataPermId 数据权限的主键Id。 + * @return 应答结果对象,包含数据权限的详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long dataPermId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysDataPerm dataPerm = null; + do { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + dataPerm = sysDataPermService.getSysDataPermWithRelation(dataPermId); + if (dataPerm == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, dataPerm); + } + + /** + * 获取不包含指定数据权限Id的用户列表。 + * 用户和数据权限是多对多关系,当前接口将返回没有赋值指定DataPermId的用户列表。可用于给数据权限添加新用户。 + * + * @param dataPermId 数据权限主键Id。 + * @param sysUserFilter 用户数据的过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listNotInDataPermUser") + public ResponseResult listNotInDataPermUser( + @MyRequestBody Long dataPermId, + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysDataPermService.existId(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.INVALID_RELATED_RECORD_ID; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = + sysUserService.getNotInSysUserListByDataPermId(dataPermId, sysUserFilter, orderBy); + responseData = MyPageUtil.makeResponseData(resultList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 拥有指定数据权限的用户列表。 + * + * @param dataPermId 数据权限主键Id。 + * @param sysUserFilter 用户过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listDataPermUser") + public ResponseResult listDataPermUser( + @MyRequestBody Long dataPermId, + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysDataPermService.existId(dataPermId)) { + errorCodeEnum = ErrorCodeEnum.INVALID_RELATED_RECORD_ID; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = + sysUserService.getSysUserListByDataPermId(dataPermId, sysUserFilter, orderBy); + responseData = MyPageUtil.makeResponseData(resultList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 为指定数据权限添加用户列表。该操作可同时给一批用户赋值数据权限,并在同一事务内完成。 + * + * @param dataPermId 数据权限主键Id。 + * @param userIdListString 逗号分隔的用户Id列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addDataPermUser") + public ResponseResult addDataPermUser( + @MyRequestBody Long dataPermId, @MyRequestBody String userIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(dataPermId, userIdListString)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + Set userIdSet = + Arrays.stream(userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysDataPermService.existId(dataPermId) + || !sysUserService.existUniqueKeyList("userId", userIdSet)) { + errorCodeEnum = ErrorCodeEnum.INVALID_RELATED_RECORD_ID; + break; + } + sysDataPermService.addDataPermUserList(dataPermId, userIdSet); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 为指定用户移除指定数据权限。 + * + * @param dataPermId 指定数据权限主键Id。 + * @param userId 指定用户主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/deleteDataPermUser") + public ResponseResult deleteDataPermUser( + @MyRequestBody Long dataPermId, @MyRequestBody Long userId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(dataPermId, userId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysDataPermService.removeDataPermUser(dataPermId, userId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysDeptController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysDeptController.java new file mode 100644 index 00000000..cb9095f2 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysDeptController.java @@ -0,0 +1,181 @@ +package com.orange.admin.upms.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.PageHelper; +import com.orange.admin.upms.model.*; +import com.orange.admin.upms.service.*; +import com.orange.admin.common.core.object.*; +import com.orange.admin.common.core.util.*; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.annotation.MyRequestBody; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysDept") +public class SysDeptController { + + @Autowired + private SysDeptService sysDeptService; + + /** + * 新增部门管理数据。 + * + * @param sysDept 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysDept sysDept) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysDept); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + sysDept = sysDeptService.saveNew(sysDept); + responseData = new JSONObject(); + responseData.put("deptId", sysDept.getDeptId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新部门管理数据。 + * + * @param sysDept 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysDept sysDept) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysDept, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + // 验证关联Id的数据合法性 + SysDept originalSysDept = sysDeptService.getById(sysDept.getDeptId()); + if (originalSysDept == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + //TODO 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + break; + } + if (!sysDeptService.update(sysDept, originalSysDept)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除部门管理数据。 + * + * @param deptId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long deptId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(deptId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + // 验证关联Id的数据合法性 + SysDept originalSysDept = sysDeptService.getById(deptId); + if (originalSysDept == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + //TODO 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + break; + } + if (!sysDeptService.remove(deptId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 列出符合过滤条件的部门管理列表。 + * + * @param sysDeptFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SysDept sysDeptFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysDept.class); + List resultList = sysDeptService.getSysDeptListWithRelation(sysDeptFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查看指定部门管理对象详情。 + * + * @param deptId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long deptId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysDept sysDept = null; + do { + if (MyCommonUtil.existBlankArgument(deptId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + sysDept = sysDeptService.getByIdWithRelation(deptId); + if (sysDept == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, sysDept); + } + + /** + * 以字典形式返回全部部门管理数据集合。字典的键值为[deptId, deptName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictSysDept") + public ResponseResult listDictSysDept(SysDept filter) { + List resultList = sysDeptService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "deptId as id", "deptName as name").executeFrom(resultList)); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysMenuController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysMenuController.java new file mode 100644 index 00000000..d4d5fbdf --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysMenuController.java @@ -0,0 +1,184 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.upms.model.SysMenu; +import com.orange.admin.upms.service.SysMenuService; +import com.orange.admin.upms.service.SysPermCodeService; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysMenu); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + VerifyResult 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); + responseData = new JSONObject(); + responseData.put("sysMenuId", sysMenu.getMenuId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新菜单数据操作。 + * + * @param sysMenu 更新菜单对象。 + * @param permCodeIdListString 与当前菜单Id绑定的权限Id列表,多个权限之间逗号分隔。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysMenu sysMenu, @MyRequestBody String permCodeIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysMenu, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysMenu originalSysMenu = sysMenuService.getById(sysMenu.getMenuId()); + if (originalSysMenu == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前菜单并不存在,请刷新后重试!"; + break; + } + VerifyResult 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)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除指定菜单操作。 + * + * @param menuId 指定菜单主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long menuId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(menuId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (sysMenuService.hasChildren(menuId)) { + errorCodeEnum = ErrorCodeEnum.HAS_CHILDREN_DATA; + errorMessage = "数据验证失败,当前菜单存在下级菜单!"; + break; + } + if (!sysMenuService.remove(menuId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,菜单不存在,请刷新后重试!"; + } + + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 获取全部菜单列表。 + * + * @return 应答结果对象,包含全部菜单数据列表。 + */ + @GetMapping("/list") + public ResponseResult> list() { + return ResponseResult.success(sysMenuService.getAllListByOrder("showOrder")); + } + + /** + * 查看指定菜单数据详情。 + * + * @param menuId 指定菜单主键Id。 + * @return 应答结果对象,包含菜单详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long menuId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysMenu sysMenu = null; + do { + if (MyCommonUtil.existBlankArgument(menuId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + sysMenu = sysMenuService.getSysMenuWithRelation(menuId); + if (sysMenu == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, sysMenu); + } + + /** + * 列出与指定菜单关联的权限字和权限资源,便于管理员排查配置中的错误。 + * + * @param menuId 菜单Id。 + * @return 与菜单关联的权限字和权限资源列表。 + */ + @GetMapping("/listMenuPerm") + public ResponseResult>> listMenuPerm(@RequestParam Long menuId) { + return ResponseResult.success(sysPermCodeService.getPermCodeListByMenuId(menuId)); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermCodeController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermCodeController.java new file mode 100644 index 00000000..96c79e57 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermCodeController.java @@ -0,0 +1,209 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.upms.model.SysPermCode; +import com.orange.admin.upms.service.SysPermCodeService; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.core.object.MyPageParam; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.core.util.MyPageUtil; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysPermCode); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + VerifyResult 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); + responseData = new JSONObject(); + responseData.put("sysPermCodeId", sysPermCode.getPermCodeId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新权限字操作。 + * + * @param sysPermCode 更新权限字对象。 + * @param permIdListString 与当前权限Id绑定的权限资源Id列表,多个权限资源之间逗号分隔。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPermCode sysPermCode, @MyRequestBody String permIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysPermCode, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysPermCode originalSysPermCode = sysPermCodeService.getById(sysPermCode.getPermCodeId()); + if (originalSysPermCode == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + break; + } + VerifyResult 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)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + } + } catch (DuplicateKeyException e) { + errorCodeEnum = ErrorCodeEnum.DUPLICATED_UNIQUE_KEY; + errorMessage = "数据操作失败,权限字编码已经存在!"; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除指定权限字操作。 + * + * @param permCodeId 指定的权限字主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long permCodeId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (sysPermCodeService.hasChildren(permCodeId)) { + errorCodeEnum = ErrorCodeEnum.HAS_CHILDREN_DATA; + errorMessage = "数据验证失败,当前权限字存在下级权限字!"; + break; + } + if (!sysPermCodeService.remove(permCodeId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,权限字不存在,请刷新后重试!"; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 查看权限字列表。 + * + * @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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysPermCode sysPermCode = null; + do { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + sysPermCode = sysPermCodeService.getSysPermCodeWithRelation(permCodeId); + if (sysPermCode == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, sysPermCode); + } + + /** + * 查看用户关联的权限字列表。 + * + * @param loginName 精确匹配用户登录名。 + * @param permCode 模糊匹配的权限字名,LIKE %permCode%。 + * @param pageParam 分页对象。 + * @return 应答结果对象,包含该用户的全部权限资源列表。 + */ + @PostMapping("/listAllPermCodesByUserFilter") + public ResponseResult listAllPermCodesByUserFilter( + @MyRequestBody String loginName, + @MyRequestBody String permCode, + @MyRequestBody MyPageParam pageParam) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(loginName)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List permCodeList = + sysPermCodeService.getUserPermCodeListByFilter(loginName, permCode); + responseData = MyPageUtil.makeResponseData(permCodeList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermController.java new file mode 100644 index 00000000..802ce657 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermController.java @@ -0,0 +1,240 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.upms.model.SysPerm; +import com.orange.admin.upms.model.SysPermModule; +import com.orange.admin.upms.service.SysPermService; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.core.object.MyPageParam; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.core.util.MyPageUtil; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysPerm); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + VerifyResult result = sysPermService.verifyRelatedData(sysPerm, null); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage()); + } + sysPerm = sysPermService.saveNew(sysPerm); + responseData = new JSONObject(); + responseData.put("permId", sysPerm.getPermId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新权限资源操作。 + * + * @param sysPerm 更新权限资源对象。 + * @return 应答结果对象,包含更新权限资源的主键Id。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPerm sysPerm) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysPerm, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysPerm originalPerm = sysPermService.getById(sysPerm.getPermId()); + if (originalPerm == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前权限资源并不存在,请刷新后重试!"; + break; + } + VerifyResult 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); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除指定权限资源操作。 + * + * @param permId 指定的权限资源主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long permId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(permId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysPermService.remove(permId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,权限不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 查看权限资源对象详情。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含权限资源对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long permId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysPerm perm = null; + do { + if (MyCommonUtil.existBlankArgument(permId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + perm = sysPermService.getById(permId); + if (perm == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, perm); + } + + /** + * 查看权限资源列表。 + * + * @param sysPermFilter 过滤对象。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含权限资源列表。 + */ + @PostMapping("/list") + public ResponseResult list(@MyRequestBody SysPerm sysPermFilter, @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(loginName)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List> userPermMapList = + sysPermService.getUserPermListByFilter(loginName, moduleId, url); + responseData = MyPageUtil.makeResponseData(userPermMapList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 查看拥有指定权限资源的所有用户数据列表。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含用户数据列表。 + */ + @PostMapping("/listAllUsers") + public ResponseResult listAllUsers(@MyRequestBody Long permId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + List> permUserMapList = null; + do { + if (MyCommonUtil.existBlankArgument(permId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + permUserMapList = sysPermService.getPermUserListById(permId); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, permUserMapList); + } + + /** + * 查看拥有指定权限资源的所有角色数据列表。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含角色数据列表。 + */ + @PostMapping("/listAllRoles") + public ResponseResult listAllRoles(@MyRequestBody Long permId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + List> permRoleMapList = null; + do { + if (MyCommonUtil.existBlankArgument(permId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + permRoleMapList = sysPermService.getPermRoleListById(permId); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, permRoleMapList); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermModuleController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermModuleController.java new file mode 100644 index 00000000..f257d109 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysPermModuleController.java @@ -0,0 +1,177 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.upms.model.SysPerm; +import com.orange.admin.upms.model.SysPermModule; +import com.orange.admin.upms.service.SysPermModuleService; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysPermModule); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + if (sysPermModule.getParentId() != null) { + if (sysPermModuleService.getById(sysPermModule.getParentId()) == null) { + errorCodeEnum = ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST; + errorMessage = "数据验证失败,关联的上级权限模块并不存在,请刷新后重试!"; + break; + } + } + sysPermModuleService.saveNew(sysPermModule); + responseData = new JSONObject(); + responseData.put("permModuleId", sysPermModule.getModuleId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新权限资源模块操作。 + * + * @param sysPermModule 更新权限资源模块对象。 + * @return 应答结果对象,包含新增权限资源模块的主键Id。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPermModule sysPermModule) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysPermModule, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysPermModule originalPermModule = sysPermModuleService.getById(sysPermModule.getModuleId()); + if (originalPermModule == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + if (sysPermModule.getParentId() != null + && !sysPermModule.getParentId().equals(originalPermModule.getParentId())) { + if (sysPermModuleService.getById(sysPermModule.getParentId()) == null) { + errorCodeEnum = ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST; + errorMessage = "数据验证失败,关联的上级权限模块并不存在,请刷新后重试!"; + break; + } + } + if (!sysPermModuleService.update(sysPermModule, originalPermModule)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前模块并不存在,请刷新后重试!"; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除指定权限资源模块操作。 + * + * @param moduleId 指定的权限资源模块主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long moduleId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(moduleId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (sysPermModuleService.hasChildren(moduleId) + || sysPermModuleService.hasModulePerms(moduleId)) { + errorCodeEnum = ErrorCodeEnum.HAS_CHILDREN_DATA; + errorMessage = "数据验证失败,当前权限模块存在子模块或权限资源,请先删除关联数据!"; + break; + } + if (!sysPermModuleService.remove(moduleId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,权限模块不存在,请刷新后重试!"; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 查看全部权限资源模块列表。 + * + * @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-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysRoleController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysRoleController.java new file mode 100644 index 00000000..0667f1ee --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysRoleController.java @@ -0,0 +1,380 @@ +package com.orange.admin.upms.controller; + +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.upms.model.SysRole; +import com.orange.admin.upms.model.SysUser; +import com.orange.admin.upms.model.SysUserRole; +import com.orange.admin.upms.service.SysRoleService; +import com.orange.admin.upms.service.SysUserService; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.object.MyOrderParam; +import com.orange.admin.common.core.object.MyPageParam; +import com.orange.admin.common.core.object.ResponseResult; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.core.util.MyPageUtil; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysRole); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + VerifyResult 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); + responseData = new JSONObject(); + responseData.put("roleId", sysRole.getRoleId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新角色操作。 + * + * @param sysRole 更新角色对象。 + * @param menuIdListString 与当前角色Id绑定的menuId列表,多个menuId之间逗号分隔。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysRole sysRole, @MyRequestBody String menuIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysRole, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysRole originalSysRole = sysRoleService.getById(sysRole.getRoleId()); + if (originalSysRole == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据验证失败,当前角色并不存在,请刷新后重试!"; + break; + } + VerifyResult 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)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "更新失败,数据不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除指定角色操作。 + * + * @param roleId 指定角色主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long roleId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(roleId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysRoleService.remove(roleId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,角色不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 查看角色列表。 + * + * @param sysRoleFilter 角色过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含角色列表。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SysRole sysRoleFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysRole sysRole = null; + do { + if (MyCommonUtil.existBlankArgument(roleId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + sysRole = sysRoleService.getSysRoleWithRelation(roleId); + if (sysRole == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, 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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(roleId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysRoleService.existId(roleId)) { + errorCodeEnum = ErrorCodeEnum.INVALID_RELATED_RECORD_ID; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = + sysUserService.getNotInSysUserListByRoleId(roleId, sysUserFilter, orderBy); + responseData = MyPageUtil.makeResponseData(resultList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, 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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(roleId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysRoleService.existId(roleId)) { + errorCodeEnum = ErrorCodeEnum.INVALID_RELATED_RECORD_ID; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List resultList = sysUserService.getSysUserListByRoleId(roleId, sysUserFilter, orderBy); + responseData = MyPageUtil.makeResponseData(resultList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 为指定角色添加用户列表。该操作可同时给一批用户赋值角色,并在同一事务内完成。 + * + * @param roleId 角色主键Id。 + * @param userIdListString 逗号分隔的用户Id列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addUserRole") + public ResponseResult addUserRole( + @MyRequestBody Long roleId, @MyRequestBody String userIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(roleId, userIdListString)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + Set userIdSet = Arrays.stream( + userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysRoleService.existId(roleId) + || !sysUserService.existUniqueKeyList("userId", userIdSet)) { + errorCodeEnum = ErrorCodeEnum.INVALID_RELATED_RECORD_ID; + break; + } + List userRoleList = new LinkedList<>(); + for (Long userId : userIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + userRoleList.add(userRole); + } + sysRoleService.addUserRoleList(userRoleList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 为指定用户移除指定角色。 + * + * @param roleId 指定角色主键Id。 + * @param userId 指定用户主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/deleteUserRole") + public ResponseResult deleteUserRole( + @MyRequestBody Long roleId, @MyRequestBody Long userId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(roleId, userId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysRoleService.removeUserRole(roleId, userId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 通过权限字Id获取拥有改权限的所有角色。 + * 开发人员调试用接口。 + * + * @param permCodeId 查询的权限字Id。 + * @param pageParam 分页对象。 + * @return 符合条件的角色列表。 + */ + @PostMapping("/listAllRolesByPermCode") + public ResponseResult listAllRolesByPermCode( + @MyRequestBody Long permCodeId, @MyRequestBody MyPageParam pageParam) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List roleList = sysRoleService.getSysRoleListByPermCodeId(permCodeId); + responseData = MyPageUtil.makeResponseData(roleList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 通过权限资源url,模糊搜索拥有改权限的所有角色。 + * 开发人员调试用接口。 + * + * @param url 用于模糊搜索的url。 + * @param pageParam 分页对象。 + * @return 符合条件的角色列表。 + */ + @PostMapping("/listAllRolesByPerm") + public ResponseResult listAllRolesByPerm( + @MyRequestBody String url, @MyRequestBody MyPageParam pageParam) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + JSONObject responseData = null; + do { + if (MyCommonUtil.existBlankArgument(url)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (pageParam != null) { + PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List roleList = sysRoleService.getSysRoleListByPerm(url); + responseData = MyPageUtil.makeResponseData(roleList); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysUserController.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysUserController.java new file mode 100644 index 00000000..cee041ad --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/controller/SysUserController.java @@ -0,0 +1,236 @@ +package com.orange.admin.upms.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.PageHelper; +import com.orange.admin.upms.model.*; +import com.orange.admin.upms.service.*; +import com.orange.admin.common.core.object.*; +import com.orange.admin.common.core.util.*; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.annotation.MyRequestBody; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.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 java.util.*; +import javax.validation.groups.Default; + +/** + * 用户管理操作控制器类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysUser") +public class SysUserController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private ApplicationConfig applicationConfig; + + /** + * 新增用户操作。 + * + * @param sysUser 新增用户对象。 + * @param roleIdListString 逗号分隔的角色Id列表。 + * @param dataPermIdListString 逗号分隔的数据权限Id列表。 + * @return 应答结果对象,包含新增用户的主键Id。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysUser sysUser, + @MyRequestBody String roleIdListString, + @MyRequestBody String dataPermIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + JSONObject responseData = null; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysUser); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + VerifyResult result = sysUserService.verifyRelatedData( + sysUser, null, roleIdListString, dataPermIdListString); + if (!result.isSuccess()) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + errorMessage = result.getErrorMessage(); + break; + } + Set roleIdSet = (Set) result.getData().get("roleIdSet"); + Set dataPermIdSet = (Set) result.getData().get("dataPermIdSet"); + sysUserService.saveNew(sysUser, roleIdSet, dataPermIdSet, applicationConfig.getPasswordSalt()); + responseData = new JSONObject(); + responseData.put("userId", sysUser.getUserId()); + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, responseData); + } + + /** + * 更新用户操作。 + * + * @param sysUser 更新用户对象。 + * @param roleIdListString 逗号分隔的角色Id列表。 + * @param dataPermIdListString 逗号分隔的数据权限Id列表。 + * @return 应答结果对象。 + */ + @SuppressWarnings("unchecked") + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysUser sysUser, + @MyRequestBody String roleIdListString, + @MyRequestBody String dataPermIdListString) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage; + do { + errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, UpdateGroup.class); + if (errorMessage != null) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + break; + } + SysUser originalUser = sysUserService.getById(sysUser.getUserId()); + if (originalUser == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + VerifyResult result = sysUserService.verifyRelatedData( + sysUser, originalUser, roleIdListString, dataPermIdListString); + if (!result.isSuccess()) { + errorCodeEnum = ErrorCodeEnum.DATA_VALIDATAED_FAILED; + errorMessage = result.getErrorMessage(); + break; + } + Set roleIdSet = (Set) result.getData().get("roleIdSet"); + Set dataPermIdSet = (Set) result.getData().get("dataPermIdSet"); + if (!sysUserService.update(sysUser, originalUser, roleIdSet, dataPermIdSet)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "更新失败,数据不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 重置密码操作。 + * + * @param userId 指定用户主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/resetPassword") + public ResponseResult resetPassword(@MyRequestBody Long userId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(userId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + if (!sysUserService.resetPassword( + userId, applicationConfig.getDefaultUserPassword(), applicationConfig.getPasswordSalt())) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 删除用户管理数据。 + * + * @param userId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long userId) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + do { + if (MyCommonUtil.existBlankArgument(userId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + // 验证关联Id的数据合法性 + SysUser originalSysUser = sysUserService.getById(userId); + if (originalSysUser == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + //TODO 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + break; + } + if (!sysUserService.remove(userId)) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage); + } + + /** + * 列出符合过滤条件的用户管理列表。 + * + * @param sysUserFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult list( + @MyRequestBody SysUser sysUserFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageHelper.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) { + ErrorCodeEnum errorCodeEnum = ErrorCodeEnum.NO_ERROR; + String errorMessage = null; + SysUser sysUser = null; + do { + if (MyCommonUtil.existBlankArgument(userId)) { + errorCodeEnum = ErrorCodeEnum.ARGUMENT_NULL_EXIST; + break; + } + sysUser = sysUserService.getByIdWithRelation(userId); + if (sysUser == null) { + errorCodeEnum = ErrorCodeEnum.DATA_NOT_EXIST; + break; + } + } while (false); + return ResponseResult.create(errorCodeEnum, errorMessage, sysUser); + } + + /** + * 以字典形式返回全部用户管理数据集合。字典的键值为[userId, loginName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDictSysUser") + public ResponseResult listDictSysUser(SysUser filter) { + List resultList = sysUserService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "userId as id", "loginName as name").executeFrom(resultList)); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermDeptMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermDeptMapper.java new file mode 100644 index 00000000..30e543d8 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermDeptMapper.java @@ -0,0 +1,13 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysDataPermDept; + +/** + * 数据权限与部门关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysDataPermDeptMapper extends BaseDaoMapper { +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermMapper.java new file mode 100644 index 00000000..e0b7d73f --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermMapper.java @@ -0,0 +1,27 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysDataPerm; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 数据权限数据访问操作接口。 + * NOTE: 该对象一定不能被 @EnableDataPerm 注解标注,否则会导致无限递归。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysDataPermMapper extends BaseDaoMapper { + + /** + * 获取数据权限列表。 + * + * @param sysDataPermFilter 过滤对象。 + * @param orderBy 排序字符串。 + * @return 过滤后的数据权限列表。 + */ + List getSysDataPermList( + @Param("sysDataPermFilter") SysDataPerm sysDataPermFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermMenuMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermMenuMapper.java new file mode 100644 index 00000000..17b10fe5 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermMenuMapper.java @@ -0,0 +1,24 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysDataPermMenu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 数据权限与菜单关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysDataPermMenuMapper extends BaseDaoMapper { + + /** + * 获取指定用户Id的数据权限列表。 + * + * @param userId 指定的用户Id。 + * @return 数据权限列表。 + */ + List getSysDataPermMenuListByUserId(@Param("userId") Long userId); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermUserMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermUserMapper.java new file mode 100644 index 00000000..18fa583f --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDataPermUserMapper.java @@ -0,0 +1,30 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysDataPermUser; + +import java.util.List; + +/** + * 数据权限与用户关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysDataPermUserMapper extends BaseDaoMapper { + + /** + * 获取用户的数据权限Id列表。 + * + * @param userId 用户Id。 + * @return 数据权限Id列表。 + */ + List getDataPermIdListByUserId(Long userId); + + /** + * 批量添加数据权限和用户关系的列表。 + * + * @param dataPermUserList 数据权限用户关系列表。 + */ + void addDataPermUserList(List dataPermUserList); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDeptMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDeptMapper.java new file mode 100644 index 00000000..dd6578ba --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysDeptMapper.java @@ -0,0 +1,26 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysDept; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 部门管理数据操作访问接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysDeptMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param sysDeptFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysDeptList( + @Param("sysDeptFilter") SysDept sysDeptFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysMenuMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysMenuMapper.java new file mode 100644 index 00000000..e20cb684 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysMenuMapper.java @@ -0,0 +1,23 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysMenu; + +import java.util.List; + +/** + * 菜单数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysMenuMapper extends BaseDaoMapper { + + /** + * 获取登录用户的菜单列表。 + * + * @param userId 登录用户。 + * @return 菜单列表。 + */ + List getMenuListByUserId(Long userId); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysMenuPermCodeMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysMenuPermCodeMapper.java new file mode 100644 index 00000000..579baf76 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysMenuPermCodeMapper.java @@ -0,0 +1,13 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysMenuPermCode; + +/** + * 菜单与权限字关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysMenuPermCodeMapper extends BaseDaoMapper { +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermCodeMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermCodeMapper.java new file mode 100644 index 00000000..6bfddf16 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermCodeMapper.java @@ -0,0 +1,43 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysPermCode; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 权限字数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermCodePermMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermCodePermMapper.java new file mode 100644 index 00000000..c2d79a5b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermCodePermMapper.java @@ -0,0 +1,13 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysPermCodePerm; + +/** + * 权限字与权限资源关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysPermCodePermMapper extends BaseDaoMapper { +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermMapper.java new file mode 100644 index 00000000..36548789 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermMapper.java @@ -0,0 +1,61 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysPerm; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 权限资源数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermModuleMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermModuleMapper.java new file mode 100644 index 00000000..7e81b0e6 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermModuleMapper.java @@ -0,0 +1,22 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysPermModule; + +import java.util.List; + +/** + * 权限资源模块数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysPermModuleMapper extends BaseDaoMapper { + + /** + * 获取整个权限模块和权限关联后的全部数据。 + * + * @return 关联的权限模块和权限资源列表。 + */ + List getPermModuleAndPermList(); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermWhitelistMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermWhitelistMapper.java new file mode 100644 index 00000000..04705b9f --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysPermWhitelistMapper.java @@ -0,0 +1,13 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysPermWhitelist; + +/** + * 权限资源白名单数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysPermWhitelistMapper extends BaseDaoMapper { +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysRoleMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysRoleMapper.java new file mode 100644 index 00000000..0830495b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysRoleMapper.java @@ -0,0 +1,41 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysRole; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 角色数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysRoleMenuMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysRoleMenuMapper.java new file mode 100644 index 00000000..2cbec9cd --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysRoleMenuMapper.java @@ -0,0 +1,13 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysRoleMenu; + +/** + * 角色与菜单操作关联关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysRoleMenuMapper extends BaseDaoMapper { +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysUserMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysUserMapper.java new file mode 100644 index 00000000..d9669490 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysUserMapper.java @@ -0,0 +1,78 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysUser; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 用户管理数据操作访问接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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); + + /** + * 根据数据权限Id,获取关联的用户Id列表。 + * + * @param dataPermId 关联的数据权限Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和DataPermId关联的用户列表。 + */ + List getSysUserListByDataPermId( + @Param("dataPermId") Long dataPermId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); + + /** + * 根据数据权限Id,获取和当前数据权限Id没有建立多对多关联关系的用户Id列表。 + * + * @param dataPermId 关联的数据权限Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和DataPermId没有建立关联关系的用户列表。 + */ + List getNotInSysUserListByDataPermId( + @Param("dataPermId") Long dataPermId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysUserRoleMapper.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysUserRoleMapper.java new file mode 100644 index 00000000..f0444e26 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/SysUserRoleMapper.java @@ -0,0 +1,31 @@ +package com.orange.admin.upms.dao; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.upms.model.SysUserRole; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用户与角色关联关系数据访问操作接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface SysUserRoleMapper extends BaseDaoMapper { + + /** + * 获取用户的角色Id列表。 + * + * @param userId 用户Id。 + * @return 角色Id列表。 + */ + List getRoleIdListByUserId(@Param("userId") Long userId); + + /** + * 批量插入用户角色信息,如果用户角色已经存在,则不会重复插入。 + * + * @param userRoleList 待插入的角色用户列表。 + */ + void addUserRoleList(List userRoleList); +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermDeptMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermDeptMapper.xml new file mode 100644 index 00000000..d082ccaf --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermDeptMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermMapper.xml new file mode 100644 index 00000000..54414194 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_data_perm.rule_type = #{sysDataPermFilter.ruleType} + + + + AND IFNULL(zz_sys_data_perm.data_perm_name, '') LIKE #{safeSearchString} + + + AND zz_sys_data_perm.deleted_flag = ${@com.orange.admin.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermMenuMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermMenuMapper.xml new file mode 100644 index 00000000..b3b65649 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermMenuMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermUserMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermUserMapper.xml new file mode 100644 index 00000000..b807724b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDataPermUserMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + REPLACE INTO zz_sys_data_perm_user(data_perm_id, user_id) VALUES + + (#{item.dataPermId}, #{item.userId}) + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDeptMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDeptMapper.xml new file mode 100644 index 00000000..5d32151c --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysDeptMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + AND zz_sys_dept.dept_name LIKE #{safeDeptName} + + + AND zz_sys_dept.deleted_flag = ${@com.orange.admin.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysMenuMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysMenuMapper.xml new file mode 100644 index 00000000..be4cb1e2 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysMenuMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysMenuPermCodeMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysMenuPermCodeMapper.xml new file mode 100644 index 00000000..52b26fc0 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysMenuPermCodeMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermCodeMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermCodeMapper.xml new file mode 100644 index 00000000..8ab08b45 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermCodeMapper.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermCodePermMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermCodePermMapper.xml new file mode 100644 index 00000000..56dfe33a --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermCodePermMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermMapper.xml new file mode 100644 index 00000000..5c27c25a --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermMapper.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermModuleMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermModuleMapper.xml new file mode 100644 index 00000000..f0221bc1 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermModuleMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermWhitelistMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermWhitelistMapper.xml new file mode 100644 index 00000000..966a18b9 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysPermWhitelistMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysRoleMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysRoleMapper.xml new file mode 100644 index 00000000..c4e8f50e --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysRoleMapper.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysRoleMenuMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysRoleMenuMapper.xml new file mode 100644 index 00000000..b081672a --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysRoleMenuMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysUserMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysUserMapper.xml new file mode 100644 index 00000000..acd6914e --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysUserMapper.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_user.login_name LIKE #{safeLoginName} + + + + AND zz_sys_user.show_name LIKE #{safeShowName} + + + AND zz_sys_user.dept_id = #{sysUserFilter.deptId} + + + 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.admin.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + + + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysUserRoleMapper.xml b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysUserRoleMapper.xml new file mode 100644 index 00000000..4f8439fa --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/dao/mapper/SysUserRoleMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + REPLACE INTO zz_sys_user_role(user_id, role_id) VALUES + + (#{item.userId}, #{item.roleId}) + + + diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPerm.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPerm.java new file mode 100644 index 00000000..0e7a1677 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPerm.java @@ -0,0 +1,89 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.validator.ConstDictRef; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.common.core.constant.DataPermRuleType; +import com.orange.admin.common.core.annotation.JobUpdateTimeColumn; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.*; + +@Data +@Table(name = "zz_sys_data_perm") +public class SysDataPerm { + + /** + * 主键Id。 + */ + @NotNull(message = "数据权限Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "data_perm_id") + private Long dataPermId; + + /** + * 显示名称。 + */ + @NotBlank(message = "数据权限名称不能为空!") + @Column(name = "data_perm_name") + private String dataPermName; + + /** + * 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。 + */ + @NotNull(message = "数据权限规则类型不能为空!") + @ConstDictRef(constDictClass = DataPermRuleType.class) + @Column(name = "rule_type") + private Integer ruleType; + + /** + * 创建者。 + */ + @Column(name = "create_user_id") + private Long createUserId; + + /** + * 创建者显示名称。 + */ + @Column(name = "create_username") + private String createUsername; + + /** + * 创建时间。 + */ + @Column(name = "create_time") + private Date createTime; + + /** + * 更新时间。 + */ + @JobUpdateTimeColumn + @Column(name = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @Transient + private List dataPermDeptList; + + @Transient + private List dataPermMenuList; + + @Transient + private String createTimeStart; + + @Transient + private String createTimeEnd; + + @Transient + private String searchString; +} \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermDept.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermDept.java new file mode 100644 index 00000000..ebea03ab --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermDept.java @@ -0,0 +1,28 @@ +package com.orange.admin.upms.model; + +import lombok.Data; +import lombok.ToString; + +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.Table; + +@Data +@ToString(of = {"deptId"}) +@Table(name = "zz_sys_data_perm_dept") +public class SysDataPermDept { + + /** + * 数据权限Id。 + */ + @Id + @Column(name = "data_perm_id") + private Long dataPermId; + + /** + * 关联部门Id。 + */ + @Id + @Column(name = "dept_id") + private Long deptId; +} \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermMenu.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermMenu.java new file mode 100644 index 00000000..a2b67ecd --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermMenu.java @@ -0,0 +1,30 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@Data +@Table(name = "zz_sys_data_perm_menu") +public class SysDataPermMenu { + + /** + * 数据权限Id。 + */ + @Id + @Column(name = "data_perm_id") + private Long dataPermId; + + /** + * 关联菜单Id。 + */ + @Id + @Column(name = "menu_id") + private Long menuId; + + @Transient + private Integer ruleType; + + @Transient + private String deptIdListString; +} \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermUser.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermUser.java new file mode 100644 index 00000000..a8676cd0 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDataPermUser.java @@ -0,0 +1,24 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@Data +@Table(name = "zz_sys_data_perm_user") +public class SysDataPermUser { + + /** + * 数据权限Id。 + */ + @Id + @Column(name = "data_perm_id") + private Long dataPermId; + + /** + * 用户Id。 + */ + @Id + @Column(name = "user_id") + private Long userId; +} \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDept.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDept.java new file mode 100644 index 00000000..c2175bbb --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysDept.java @@ -0,0 +1,71 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.annotation.JobUpdateTimeColumn; +import com.orange.admin.common.core.validator.UpdateGroup; +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.*; + +import java.util.Date; + +@Data +@Table(name = "zz_sys_dept") +public class SysDept { + + /** + * 部门Id。 + */ + @NotNull(message = "数据验证失败,部门Id不能为空!", groups = {UpdateGroup.class}) + @Id + @Column(name = "dept_id") + private Long deptId; + + /** + * 部门名称。 + */ + @NotBlank(message = "数据验证失败,部门名称不能为空!") + @Column(name = "dept_name") + private String deptName; + + /** + * 显示顺序。 + */ + @NotNull(message = "数据验证失败,显示顺序不能为空!") + @Column(name = "show_order") + private Integer showOrder; + + /** + * 逻辑删除标记字段(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; + + /** + * 更新时间。 + */ + @JobUpdateTimeColumn + @Column(name = "update_time") + private Date updateTime; +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysMenu.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysMenu.java new file mode 100644 index 00000000..9afaa3a2 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysMenu.java @@ -0,0 +1,82 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.validator.ConstDictRef; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.upms.model.constant.SysMenuType; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +@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; + + @Transient + private List permCodeIdList; +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysMenuPermCode.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysMenuPermCode.java new file mode 100644 index 00000000..6a0108de --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysMenuPermCode.java @@ -0,0 +1,24 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPerm.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPerm.java new file mode 100644 index 00000000..414a8b73 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPerm.java @@ -0,0 +1,75 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.annotation.RelationDict; +import com.orange.admin.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.Map; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermCode.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermCode.java new file mode 100644 index 00000000..d3cce520 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermCode.java @@ -0,0 +1,78 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.validator.ConstDictRef; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.upms.model.constant.SysPermCodeType; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +@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; + + @Transient + private List permIdList; +} \ No newline at end of file diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermCodePerm.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermCodePerm.java new file mode 100644 index 00000000..73536c62 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermCodePerm.java @@ -0,0 +1,24 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermModule.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermModule.java new file mode 100644 index 00000000..88cf3162 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermModule.java @@ -0,0 +1,71 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.validator.ConstDictRef; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.upms.model.constant.SysPermModuleType; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermWhitelist.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermWhitelist.java new file mode 100644 index 00000000..e38f7fa1 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysPermWhitelist.java @@ -0,0 +1,29 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/SysRole.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysRole.java new file mode 100644 index 00000000..28238c5a --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysRole.java @@ -0,0 +1,77 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.common.core.annotation.JobUpdateTimeColumn; +import lombok.Data; + +import javax.persistence.*; +import javax.validation.constraints.*; +import java.util.Date; +import java.util.List; + +@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; + + /** + * 更新时间。 + */ + @JobUpdateTimeColumn + @Column(name = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @JSONField(serialize = false) + @DeletedFlagColumn + @Column(name = "deleted_flag") + private Integer deletedFlag; + + @Transient + private List menuIdList; + + @Transient + private String createTimeStart; + + @Transient + private String createTimeEnd; + + @Transient + private String searchString; +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysRoleMenu.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysRoleMenu.java new file mode 100644 index 00000000..318cfcad --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysRoleMenu.java @@ -0,0 +1,24 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/SysUser.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysUser.java new file mode 100644 index 00000000..3e91e79b --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysUser.java @@ -0,0 +1,148 @@ +package com.orange.admin.upms.model; + +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.upms.model.constant.SysUserType; +import com.orange.admin.upms.model.constant.SysUserStatus; +import com.orange.admin.common.core.annotation.RelationConstDict; +import com.orange.admin.common.core.annotation.DeletedFlagColumn; +import com.orange.admin.common.core.annotation.JobUpdateTimeColumn; +import com.orange.admin.common.core.validator.UpdateGroup; +import com.orange.admin.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; + +@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 = "数据验证失败,用户密码不能为空!") + private String password; + + /** + * 用户显示名称。 + */ + @NotBlank(message = "数据验证失败,用户显示名称不能为空!") + @Column(name = "show_name") + private String showName; + + /** + * 用户部门Id。 + */ + @NotNull(message = "数据验证失败,用户部门Id不能为空!") + @Column(name = "dept_id") + private Long deptId; + + /** + * 用户类型(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; + + /** + * 更新时间。 + */ + @JobUpdateTimeColumn + @Column(name = "update_time") + private Date updateTime; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @Transient + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @Transient + private String createTimeEnd; + + /** + * 与当前用户关联的角色Id集合。 + */ + @Transient + private List roleIdList; + + /** + * 与当前用户关联的数据权限Id集合。 + */ + @Transient + private List dataPermIdList; + + @RelationConstDict( + masterIdField = "userType", + constantDictClass = SysUserType.class) + @Transient + private Map userTypeDictMap; + + @RelationConstDict( + masterIdField = "userStatus", + constantDictClass = SysUserStatus.class) + @Transient + private Map userStatusDictMap; +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysUserRole.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysUserRole.java new file mode 100644 index 00000000..375be9c6 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/SysUserRole.java @@ -0,0 +1,24 @@ +package com.orange.admin.upms.model; + +import lombok.Data; + +import javax.persistence.*; + +@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-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysMenuType.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysMenuType.java new file mode 100644 index 00000000..4721c326 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysMenuType.java @@ -0,0 +1,54 @@ +package com.orange.admin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 菜单类型常量对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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; + + public 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(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysMenuType() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysPermCodeType.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysPermCodeType.java new file mode 100644 index 00000000..e67b05cf --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysPermCodeType.java @@ -0,0 +1,49 @@ +package com.orange.admin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 权限字类型常量对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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; + + public 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(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysPermCodeType() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysPermModuleType.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysPermModuleType.java new file mode 100644 index 00000000..ddc48c54 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysPermModuleType.java @@ -0,0 +1,44 @@ +package com.orange.admin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 权限资源模块类型常量对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public final class SysPermModuleType { + + /** + * 普通模块。 + */ + public static final int TYPE_NORMAL = 0; + /** + * controller接口模块。 + */ + public static final int TYPE_CONTROLLER = 1; + + public 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(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysPermModuleType() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysUserStatus.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysUserStatus.java new file mode 100644 index 00000000..447d4f2e --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysUserStatus.java @@ -0,0 +1,38 @@ +package com.orange.admin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +public final class SysUserStatus { + + /** + * 正常状态。 + */ + public static final int STATUS_NORMAL = 0; + /** + * 锁定状态。 + */ + public static final int STATUS_LOCKED = 1; + + public 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(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserStatus() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysUserType.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysUserType.java new file mode 100644 index 00000000..e0b3a844 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/model/constant/SysUserType.java @@ -0,0 +1,43 @@ +package com.orange.admin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +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; + + public 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(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserType() { + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysDataPermService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysDataPermService.java new file mode 100644 index 00000000..5d98e204 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysDataPermService.java @@ -0,0 +1,366 @@ +package com.orange.admin.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.common.biz.util.BasicIdGenerator; +import com.orange.admin.common.core.constant.DataPermRuleType; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.upms.dao.SysDataPermDeptMapper; +import com.orange.admin.upms.dao.SysDataPermMapper; +import com.orange.admin.upms.dao.SysDataPermUserMapper; +import com.orange.admin.upms.dao.SysDataPermMenuMapper; +import com.orange.admin.upms.model.*; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +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 Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysDataPermService extends BaseService { + + @Autowired + private SysDataPermMapper sysDataPermMapper; + @Autowired + private SysDataPermDeptMapper sysDataPermDeptMapper; + @Autowired + private SysDataPermMenuMapper sysDataPermMenuMapper; + @Autowired + private SysMenuService sysMenuService; + @Autowired + private SysDataPermUserMapper sysDataPermUserMapper; + @Autowired + private SysDeptService sysDeptService; + @Autowired + private BasicIdGenerator idGenerator; + +/** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysDataPermMapper; + } + + /** + * 保存新增的数据权限对象。 + * + * @param dataPerm 新增的数据权限对象。 + * @param deptIdSet 关联的部门Id列表。 + * @param dataPermMenuList 关联的菜单对象列表。 + * @return 新增后的数据权限对象。 + */ + @Transactional + public SysDataPerm saveNew(SysDataPerm dataPerm, Set deptIdSet, List dataPermMenuList) { + dataPerm.setDataPermId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + dataPerm.setCreateUserId(tokenData.getUserId()); + dataPerm.setCreateUsername(tokenData.getShowName()); + dataPerm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + Date now = new Date(); + dataPerm.setCreateTime(now); + dataPerm.setUpdateTime(now); + sysDataPermMapper.insert(dataPerm); + this.insertRelationData(dataPerm, deptIdSet, dataPermMenuList); + return dataPerm; + } + + /** + * 更新数据权限对象。 + * + * @param dataPerm 更新的数据权限对象。 + * @param originalDataPerm 原有的数据权限对象。 + * @param deptIdSet 关联的部门Id列表。 + * @param dataPermMenuList 关联的菜单对象列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional + public boolean update( + SysDataPerm dataPerm, + SysDataPerm originalDataPerm, + Set deptIdSet, + List dataPermMenuList) { + dataPerm.setUpdateTime(new Date()); + dataPerm.setCreateTime(originalDataPerm.getCreateTime()); + dataPerm.setCreateUserId(originalDataPerm.getCreateUserId()); + dataPerm.setCreateUsername(originalDataPerm.getCreateUsername()); + dataPerm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + if (sysDataPermMapper.updateByPrimaryKey(dataPerm) != 1) { + return false; + } + SysDataPermMenu dataPermMenu = new SysDataPermMenu(); + dataPermMenu.setDataPermId(dataPerm.getDataPermId()); + sysDataPermMenuMapper.delete(dataPermMenu); + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPerm.getDataPermId()); + sysDataPermDeptMapper.delete(dataPermDept); + this.insertRelationData(dataPerm, deptIdSet, dataPermMenuList); + return true; + } + + /** + * 删除指定数据权限。 + * + * @param dataPermId 数据权限主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional + public boolean remove(Long dataPermId) { + SysDataPerm dataPerm = new SysDataPerm(); + dataPerm.setDataPermId(dataPermId); + dataPerm.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysDataPermMapper.updateByPrimaryKeySelective(dataPerm) != 1) { + return false; + } + SysDataPermMenu dataPermMenu = new SysDataPermMenu(); + dataPermMenu.setDataPermId(dataPermId); + sysDataPermMenuMapper.delete(dataPermMenu); + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPermId); + sysDataPermDeptMapper.delete(dataPermDept); + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + sysDataPermUserMapper.delete(dataPermUser); + return true; + } + + /** + * 获取数据权限列表。 + * + * @param filter 数据权限过滤对象。 + * @param orderBy 排序参数。 + * @return 数据权限查询列表。 + */ + public List getSysDataPermList(SysDataPerm filter, String orderBy) { + return sysDataPermMapper.getSysDataPermList(filter, orderBy); + } + + /** + * 获取指定数据权限,同时包含其关联数据。 + * + * @param dataPermId 数据权限主键Id。 + * @return 数据权限对象。 + */ + public SysDataPerm getSysDataPermWithRelation(Long dataPermId) { + SysDataPerm dataPerm = this.getById(dataPermId); + if (dataPerm != null) { + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPermId); + List dataPermDeptList = sysDataPermDeptMapper.select(dataPermDept); + dataPerm.setDataPermDeptList(dataPermDeptList); + SysDataPermMenu dataPermMenu = new SysDataPermMenu(); + dataPermMenu.setDataPermId(dataPermId); + List dataPermMenuList = sysDataPermMenuMapper.select(dataPermMenu); + dataPerm.setDataPermMenuList(dataPermMenuList); + } + return dataPerm; + } + + /** + * 将指定用户的指定会话的数据权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @param deptId 用户所属部门主键Id。 + * @param isAdmin 是否是管理员。 + * @return 查询并缓存后的数据权限集合。返回格式为,Map>。 + */ + @CachePut(value = "DataPermissionCache", key = "#sessionId") + public Map> putDataPermCache( + String sessionId, Long userId, Long deptId, boolean isAdmin) { + // 管理员账户返回空对象,便于缓存的统一处理。 + return isAdmin ? new HashMap<>(1) : this.getSysDataPermMenuListByUserId(userId, deptId); + } + + /** + * 将指定会话的数据权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + @CacheEvict(value = "DataPermissionCache", key = "#sessionId") + public void removeDataPermCache(String sessionId) { + // 空实现即可,只是通过注解将当前sessionId从cache中删除。 + } + + /** + * 获取指定用户Id的数据权限列表。并基于菜单Id和权限规则类型进行了一级和二级的分组。 + * + * @param userId 指定的用户Id。 + * @param deptId 用户所属部门主键Id。 + * @return 合并优化后的数据权限列表。返回格式为,Map>。 + */ + public Map> getSysDataPermMenuListByUserId(Long userId, Long deptId) { + List dataPermMenuList = sysDataPermMenuMapper.getSysDataPermMenuListByUserId(userId); + if (dataPermMenuList.size() == 0) { + return new HashMap<>(1); + } + // 这里用代码的方式把deptId组装到SysDataPermMenu中。 + Set dataPermIdSet = dataPermMenuList.stream() + .map(SysDataPermMenu::getDataPermId).collect(Collectors.toSet()); + Example e = new Example(SysDataPermDept.class); + e.createCriteria().andIn("dataPermId", dataPermIdSet); + List dataPermDeptList = sysDataPermDeptMapper.selectByExample(e); + Map> deptMap = + dataPermDeptList.stream().collect(Collectors.groupingBy(SysDataPermDept::getDataPermId)); + for (SysDataPermMenu dataPermMenu : dataPermMenuList) { + List deptList = deptMap.get(dataPermMenu.getDataPermId()); + if (CollectionUtils.isNotEmpty(deptList)) { + Set deptIdSet = deptList.stream().map(SysDataPermDept::getDeptId).collect(Collectors.toSet()); + dataPermMenu.setDeptIdListString(StringUtils.join(deptIdSet, ",")); + } + } + // 由于同一用户可能属于多个数据权限,所以需要先进行基于menuId的权限合并。 + Map> menuMap = + dataPermMenuList.stream().collect(Collectors.groupingBy(SysDataPermMenu::getMenuId)); + Map> resultMap = new HashMap<>(menuMap.size()); + // 这里menuMap的key是menuId + for (Map.Entry> entry : menuMap.entrySet()) { + Object menuId = entry.getKey(); + // 为了更方便进行后续的合并优化处理,这里再基于规则类型进行分组。ruleMap的key是规则类型。 + Map> ruleMap = + entry.getValue().stream().collect(Collectors.groupingBy(SysDataPermMenu::getRuleType)); + Map m = new HashMap<>(1); + // 如有有ALL存在,就可以直接退出了,没有必要在处理后续的规则了。 + if (ruleMap.containsKey(DataPermRuleType.TYPE_ALL)) { + m.put(DataPermRuleType.TYPE_ALL, "null"); + resultMap.put(menuId, m); + continue; + } + // 合并自定义部门了。 + List customDeptList = ruleMap.get(DataPermRuleType.TYPE_CUSTOM_DETP_LIST); + if (customDeptList != null) { + Set deptIdSet = new HashSet<>(); + for (SysDataPermMenu customDept : customDeptList) { + deptIdSet.addAll(Arrays.stream(StringUtils.split( + customDept.getDeptIdListString(), ",")).map(Long::valueOf).collect(Collectors.toSet())); + } + if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_ONLY)) { + deptIdSet.add(deptId); + ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY); + } + m.put(DataPermRuleType.TYPE_CUSTOM_DETP_LIST, StringUtils.join(deptIdSet, ',')); + } + // 最后处理当前部门和当前用户。 + if (ruleMap.get(DataPermRuleType.TYPE_DEPT_ONLY) != null) { + m.put(DataPermRuleType.TYPE_DEPT_ONLY, "null"); + } + if (ruleMap.get(DataPermRuleType.TYPE_USER_ONLY) != null) { + m.put(DataPermRuleType.TYPE_USER_ONLY, "null"); + } + resultMap.put(menuId, m); + } + return resultMap; + } + + /** + * 添加用户和数据权限之间的多对多关联关系。 + * + * @param dataPermId 数据权限Id。 + * @param userIdSet 关联的用户Id列表。 + */ + @Transactional + public void addDataPermUserList(Long dataPermId, Set userIdSet) { + List dataPermUserList = new LinkedList<>(); + for (Long userId : userIdSet) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(userId); + dataPermUserList.add(dataPermUser); + } + sysDataPermUserMapper.addDataPermUserList(dataPermUserList); + } + + /** + * 移除用户和数据权限之间的多对多关联关系。 + * + * @param dataPermId 数据权限主键Id。 + * @param userId 用户主键Id。 + */ + @Transactional + public boolean removeDataPermUser(Long dataPermId, Long userId) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(userId); + return sysDataPermUserMapper.delete(dataPermUser) == 1; + } + + /** + * 验证数据权限对象关联菜单数据是否都合法。 + * + * @param dataPerm 数据权限关对象。 + * @param deptIdListString 与数据权限关联的部门Id列表。 + * @param menuIdListString 与数据权限关联的菜单Id列表。 + * @return 验证结果。 + */ + public VerifyResult verifyRelatedData(SysDataPerm dataPerm, String deptIdListString, String menuIdListString) { + String errorMessage = null; + JSONObject jsonObject = new JSONObject(); + do { + if (dataPerm.getRuleType() == DataPermRuleType.TYPE_CUSTOM_DETP_LIST) { + if (StringUtils.isBlank(deptIdListString)) { + errorMessage = "数据验证失败,部门列表不能为空!"; + break; + } + Set deptIdSet = Arrays.stream(StringUtils.split( + deptIdListString, ",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysDeptService.existUniqueKeyList("deptId", deptIdSet)) { + errorMessage = "数据验证失败,存在不合法的部门数据,请刷新后重试!"; + break; + } + jsonObject.put("deptIdSet", deptIdSet); + } + String[] menuIdArray = StringUtils.split(menuIdListString, ","); + Set menuIdSet = Arrays.stream(menuIdArray).map(Long::valueOf).collect(Collectors.toSet()); + // 验证菜单Id的合法性 + if (!sysMenuService.existUniqueKeyList("menuId", menuIdSet)) { + errorMessage = "数据验证失败,存在不合法的菜单,请刷新后重试!"; + break; + } + List dataPermMenuList = new LinkedList<>(); + for (Long menuId : menuIdSet) { + SysDataPermMenu dataPermMenu = new SysDataPermMenu(); + dataPermMenu.setMenuId(menuId); + dataPermMenuList.add(dataPermMenu); + } + jsonObject.put("dataPermMenuList", dataPermMenuList); + } while (false); + return VerifyResult.create(errorMessage, jsonObject); + } + + private void insertRelationData( + SysDataPerm dataPerm, Set deptIdSet, List dataPermMenuList) { + if (CollectionUtils.isNotEmpty(deptIdSet)) { + List dataPermDeptList = new LinkedList<>(); + for (Long deptId : deptIdSet) { + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPerm.getDataPermId()); + dataPermDept.setDeptId(deptId); + dataPermDeptList.add(dataPermDept); + } + sysDataPermDeptMapper.insertList(dataPermDeptList); + } + if (CollectionUtils.isNotEmpty(dataPermMenuList)) { + for (SysDataPermMenu dataPermMenu : dataPermMenuList) { + dataPermMenu.setDataPermId(dataPerm.getDataPermId()); + } + sysDataPermMenuMapper.insertList(dataPermMenuList); + } + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysDeptService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysDeptService.java new file mode 100644 index 00000000..3971e5fb --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysDeptService.java @@ -0,0 +1,132 @@ +package com.orange.admin.upms.service; + +import com.orange.admin.upms.dao.*; +import com.orange.admin.upms.model.*; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.object.MyWhereCriteria; +import com.orange.admin.common.biz.util.BasicIdGenerator; +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 Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysDeptService extends BaseService { + + @Autowired + private SysDeptMapper sysDeptMapper; + @Autowired + private SysDataPermDeptMapper sysDataPermDeptMapper; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysDeptMapper; + } + + /** + * 保存新增的部门对象。 + * + * @param sysDept 新增的部门对象。 + * @return 新增后的部门对象。 + */ + @Transactional + public SysDept saveNew(SysDept sysDept) { + sysDept.setDeptId(idGenerator.nextLongId()); + sysDept.setDeletedFlag(GlobalDeletedFlag.NORMAL); + TokenData tokenData = TokenData.takeFromRequest(); + sysDept.setCreateUserId(tokenData.getUserId()); + sysDept.setCreateUsername(tokenData.getShowName()); + Date now = new Date(); + sysDept.setCreateTime(now); + sysDept.setUpdateTime(now); + sysDeptMapper.insert(sysDept); + return sysDept; + } + + /** + * 更新部门对象。 + * + * @param sysDept 更新的部门对象。 + * @param originalSysDept 原有的部门对象。 + * @return 更新成功返回true,否则false。 + */ + @Transactional + public boolean update(SysDept sysDept, SysDept originalSysDept) { + sysDept.setCreateUserId(originalSysDept.getCreateUserId()); + sysDept.setCreateUsername(originalSysDept.getCreateUsername()); + sysDept.setCreateTime(originalSysDept.getCreateTime()); + sysDept.setUpdateTime(new Date()); + sysDept.setDeletedFlag(GlobalDeletedFlag.NORMAL); + return sysDeptMapper.updateByPrimaryKey(sysDept) != 0; + } + + /** + * 删除指定数据。 + * + * @param deptId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional + public boolean remove(Long deptId) { + Example sysDeptExample = new Example(SysDept.class); + Example.Criteria c = sysDeptExample.createCriteria(); + c.andEqualTo("deptId", deptId); + c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + // 这里先删除主数据 + SysDept deletedObject = new SysDept(); + deletedObject.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysDeptMapper.updateByExampleSelective(deletedObject, sysDeptExample) == 0) { + return false; + } + // 这里可继续删除关联数据。 + Example dataPermDeptExample = new Example(SysDataPermDept.class); + dataPermDeptExample.createCriteria().andEqualTo("deptId", deptId); + sysDataPermDeptMapper.deleteByExample(dataPermDeptExample); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysDeptListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSysDeptList(SysDept filter, String orderBy) { + return sysDeptMapper.getSysDeptList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 如果仅仅需要获取主表数据,请移步(getSysDeptList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + public List getSysDeptListWithRelation(SysDept filter, String orderBy) { + List resultList = sysDeptMapper.getSysDeptList(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildAllRelationForDataList(resultList, false, criteriaMap); + return resultList; + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysMenuService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysMenuService.java new file mode 100644 index 00000000..4d10f0b9 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysMenuService.java @@ -0,0 +1,263 @@ +package com.orange.admin.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.common.biz.util.BasicIdGenerator; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.upms.dao.SysMenuMapper; +import com.orange.admin.upms.dao.SysMenuPermCodeMapper; +import com.orange.admin.upms.dao.SysRoleMenuMapper; +import com.orange.admin.upms.dao.SysDataPermMenuMapper; +import com.orange.admin.upms.model.SysDataPermMenu; +import com.orange.admin.upms.model.SysMenu; +import com.orange.admin.upms.model.SysMenuPermCode; +import com.orange.admin.upms.model.SysRoleMenu; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysMenuService extends BaseService { + + @Autowired + private SysMenuMapper sysMenuMapper; + @Autowired + private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysMenuPermCodeMapper sysMenuPermCodeMapper; + @Autowired + private SysPermCodeService sysPermCodeService; + @Autowired + private SysDataPermMenuMapper sysDataPermMenuMapper; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysMenuMapper; + } + + /** + * 保存新增的菜单对象。 + * + * @param sysMenu 新增的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 新增后的菜单对象。 + */ + @Transactional + 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 + 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; + } + Example e = new Example(SysMenuPermCode.class); + e.createCriteria().andEqualTo("menuId", sysMenu.getMenuId()); + sysMenuPermCodeMapper.deleteByExample(e); + 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 + public boolean remove(Long menuId) { + SysMenu menu = new SysMenu(); + menu.setMenuId(menuId); + menu.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysMenuMapper.updateByPrimaryKeySelective(menu) != 1) { + return false; + } + Example roleMenuExample = new Example(SysRoleMenu.class); + roleMenuExample.createCriteria().andEqualTo("menuId", menuId); + sysRoleMenuMapper.deleteByExample(roleMenuExample); + Example menuPermCodeExample = new Example(SysMenuPermCode.class); + menuPermCodeExample.createCriteria().andEqualTo("menuId", menuId); + sysMenuPermCodeMapper.deleteByExample(menuPermCodeExample); + Example dataPermMenuExample = new Example(SysDataPermMenu.class); + dataPermMenuExample.createCriteria().andEqualTo("menuId", menuId); + sysDataPermMenuMapper.deleteByExample(dataPermMenuExample); + 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 菜单对象。 + */ + public SysMenu getSysMenuWithRelation(Long menuId) { + SysMenu sysMenu = this.getById(menuId); + if (sysMenu != null) { + Example e = new Example(SysMenuPermCode.class); + e.createCriteria().andEqualTo("menuId", menuId); + List sysMenuPermCodeList = sysMenuPermCodeMapper.selectByExample(e); + if (sysMenuPermCodeList.size() > 0) { + List permCodeIdList = + sysMenuPermCodeList.stream().map(SysMenuPermCode::getPermCodeId).collect(Collectors.toList()); + sysMenu.setPermCodeIdList(permCodeIdList); + } + } + return sysMenu; + } + + /** + * 判断当前菜单是否存在子菜单。 + * + * @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 VerifyResult verifyRelatedData(SysMenu sysMenu, SysMenu originalSysMenu, String permCodeIdListString) { + String errorMessage = null; + JSONObject jsonObject = null; + do { + if (this.needToVerify(sysMenu, originalSysMenu, SysMenu::getParentId)) { + // 1. menu、ui fragment和button类型的menu不能没有parentId + if (sysMenu.getParentId() == null) { + if (sysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) { + errorMessage = "数据验证失败,当前类型菜单项的上级菜单不能为空!"; + break; + } + } else { + // 2. 判断父节点是否存在 + SysMenu parentSysMenu = getById(sysMenu.getParentId()); + if (parentSysMenu == null) { + errorMessage = "数据验证失败,关联的上级菜单并不存在,请刷新后重试!"; + break; + } + // 3. 逐个判断每种类型的菜单,他的父菜单的合法性,先从目录类型和菜单类型开始 + if (sysMenu.getMenuType() == SysMenuType.TYPE_DIRECTORY + || sysMenu.getMenuType() == SysMenuType.TYPE_MENU) { + // 他们的上级只能是目录 + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) { + errorMessage = "数据验证失败,当前类型菜单项的上级菜单只能是目录类型!"; + break; + } + } else if (sysMenu.getMenuType() == SysMenuType.TYPE_UI_FRAGMENT) { + // ui fragment的上级只能是menu类型 + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU) { + errorMessage = "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和按钮类型!"; + break; + } + } else if (sysMenu.getMenuType() == SysMenuType.TYPE_BUTTON) { + // button的上级只能是menu和ui fragment + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU + && parentSysMenu.getMenuType() != SysMenuType.TYPE_UI_FRAGMENT) { + errorMessage = "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和UI片段类型!"; + break; + } + } + } + } + if (StringUtils.isNotBlank(permCodeIdListString)) { + Set permCodeIdSet = Arrays.stream( + permCodeIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPermCodeService.existUniqueKeyList("permCodeId", permCodeIdSet)) { + errorMessage = "数据验证失败,存在不合法的权限字,请刷新后重试!"; + break; + } + jsonObject = new JSONObject(); + jsonObject.put("permCodeIdSet", permCodeIdSet); + } + } while (false); + return VerifyResult.create(errorMessage, jsonObject); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermCodeService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermCodeService.java new file mode 100644 index 00000000..0f9279d6 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermCodeService.java @@ -0,0 +1,232 @@ +package com.orange.admin.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.common.biz.util.BasicIdGenerator; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.upms.dao.SysMenuPermCodeMapper; +import com.orange.admin.upms.dao.SysPermCodeMapper; +import com.orange.admin.upms.dao.SysPermCodePermMapper; +import com.orange.admin.upms.model.SysMenuPermCode; +import com.orange.admin.upms.model.SysPermCode; +import com.orange.admin.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 tk.mybatis.mapper.entity.Example; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 权限字数据服务类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysPermCodeService extends BaseService { + + @Autowired + private SysPermCodeMapper sysPermCodeMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private SysMenuPermCodeMapper sysMenuPermCodeMapper; + @Autowired + private SysPermService sysPermService; + @Autowired + private BasicIdGenerator 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 + 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 + 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; + } + Example e = new Example(SysPermCodePerm.class); + e.createCriteria().andEqualTo("permCodeId", sysPermCode.getPermCodeId()); + sysPermCodePermMapper.deleteByExample(e); + 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 + public boolean remove(Long permCodeId) { + SysPermCode permCode = new SysPermCode(); + permCode.setPermCodeId(permCodeId); + permCode.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysPermCodeMapper.updateByPrimaryKeySelective(permCode) != 1) { + return false; + } + Example menuPermCodeExample = new Example(SysMenuPermCode.class); + menuPermCodeExample.createCriteria().andEqualTo("permCodeId", permCodeId); + sysMenuPermCodeMapper.deleteByExample(menuPermCodeExample); + Example permCodePermExample = new Example(SysPermCodePerm.class); + permCodePermExample.createCriteria().andEqualTo("permCodeId", permCodeId); + sysPermCodePermMapper.deleteByExample(permCodePermExample); + return true; + } + + /** + * 获取指定权限字对象数据,该对象将包含其关联数据。 + * + * @param permCodeId 权限字主键Id。 + * @return 权限字对象。 + */ + public SysPermCode getSysPermCodeWithRelation(Long permCodeId) { + SysPermCode sysPermCode = this.getById(permCodeId); + if (sysPermCode != null) { + Example e = new Example(SysPermCodePerm.class); + e.createCriteria().andEqualTo("permCodeId", permCodeId); + List sysPermCodePermList = sysPermCodePermMapper.selectByExample(e); + if (sysPermCodePermList.size() > 0) { + List permIdList = + sysPermCodePermList.stream().map(SysPermCodePerm::getPermId).collect(Collectors.toList()); + sysPermCode.setPermIdList(permIdList); + } + } + return sysPermCode; + } + + /** + * 获取指定用户的权限字列表。 + * + * @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 VerifyResult verifyRelatedData( + SysPermCode sysPermCode, SysPermCode originalSysPermCode, String permIdListString) { + String errorMessage = null; + JSONObject jsonObject = null; + Map resultMap = new HashMap<>(2); + do { + if (this.needToVerify(sysPermCode, originalSysPermCode, SysPermCode::getParentId)) { + if (getById(sysPermCode.getParentId()) == null) { + errorMessage = "数据验证失败,关联的上级权限字并不存在,请刷新后重试!"; + break; + } + } + if (StringUtils.isNotBlank(permIdListString)) { + Set permIdSet = Arrays.stream( + permIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPermService.existUniqueKeyList("permId", permIdSet)) { + errorMessage = "数据验证失败,存在不合法的权限资源,请刷新后重试!"; + break; + } + jsonObject = new JSONObject(); + jsonObject.put("permIdSet", permIdSet); + } + } while (false); + return VerifyResult.create(errorMessage, jsonObject); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermModuleService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermModuleService.java new file mode 100644 index 00000000..d9b21632 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermModuleService.java @@ -0,0 +1,118 @@ +package com.orange.admin.upms.service; + +import com.orange.admin.common.biz.util.BasicIdGenerator; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.upms.dao.SysPermModuleMapper; +import com.orange.admin.upms.model.SysPerm; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysPermModuleService extends BaseService { + + @Autowired + private SysPermModuleMapper sysPermModuleMapper; + @Autowired + private SysPermService sysPermService; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermModuleMapper; + } + + /** + * 保存新增的权限资源模块对象。 + * + * @param sysPermModule 新增的权限资源模块对象。 + * @return 新增后的权限资源模块对象。 + */ + @Transactional + 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 + 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 + 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-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermService.java new file mode 100644 index 00000000..99fc7d75 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermService.java @@ -0,0 +1,260 @@ +package com.orange.admin.upms.service; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.common.biz.util.BasicIdGenerator; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.upms.dao.SysPermCodePermMapper; +import com.orange.admin.upms.dao.SysPermMapper; +import com.orange.admin.upms.model.SysPerm; +import com.orange.admin.upms.model.SysPermCodePerm; +import com.orange.admin.upms.model.SysPermModule; +import com.orange.admin.upms.model.SysUser; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysPermService extends BaseService { + + @Autowired + private SysPermMapper sysPermMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private SysPermModuleService sysPermModuleService; + @Autowired + private SysUserService sysUserService; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermMapper; + } + + /** + * 保存新增的权限资源对象。 + * + * @param perm 新增的权限资源对象。 + * @return 新增后的权限资源对象。 + */ + @Transactional + 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 + 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 + 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("permId"); + 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, true); + return permList; + } + + /** + * 获取指定用户的权限资源集合,并存储于缓存,从而提升后续读取效率。 + * + * @param sessionId 用户会话Id。 + * @param userId 用户主键Id。 + * @return 当前用户权限集合。 + */ + @Cacheable(value = "UserPermissionCache", key = "#sessionId", unless = "#result == null") + public Set getCacheableSysPermSetByUserId(String sessionId, Long userId) { + // 这里可以防止非法的userId直接访问权限受限的url + SysUser user = sysUserService.getById(userId); + if (user == null) { + return null; + } + // 管理员账户返回空对象,便于缓存的统一处理。 + return user.getUserType() == SysUserType.TYPE_ADMIN + ? new HashSet<>(1) : this.getSysPermSetByUserId(userId); + } + + /** + * 将指定用户的指定会话的权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @param isAdmin 是否是管理员。 + * @return 查询并缓存后的权限集合。 + */ + @CachePut(value = "UserPermissionCache", key = "#sessionId") + public Set putUserSysPermCache(String sessionId, Long userId, boolean isAdmin) { + // 管理员账户返回空对象,便于缓存的统一处理。 + return isAdmin ? new HashSet<>(1) : this.getSysPermSetByUserId(userId); + } + + /** + * 将指定会话的权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + @CacheEvict(value = "UserPermissionCache", 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 VerifyResult verifyRelatedData(SysPerm sysPerm, SysPerm originalSysPerm) { + String errorMessage = null; + JSONObject jsonObject = null; + do { + if (this.needToVerify(sysPerm, originalSysPerm, SysPerm::getModuleId)) { + SysPermModule permModule = sysPermModuleService.getById(sysPerm.getModuleId()); + if (permModule == null) { + errorMessage = "数据验证失败,关联的权限模块Id并不存在,请刷新后重试!"; + break; + } + jsonObject = new JSONObject(); + jsonObject.put("permModule", permModule); + } + } while (false); + return VerifyResult.create(errorMessage, jsonObject); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermWhitelistService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermWhitelistService.java new file mode 100644 index 00000000..d5e8063a --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysPermWhitelistService.java @@ -0,0 +1,33 @@ +package com.orange.admin.upms.service; + +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.upms.dao.SysPermWhitelistMapper; +import com.orange.admin.upms.model.SysPermWhitelist; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 权限资源白名单数据服务类。 + * 白名单中的权限资源,可以不受权限控制,任何用户皆可访问,一般用于常用的字典数据列表接口。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysPermWhitelistService extends BaseService { + + @Autowired + private SysPermWhitelistMapper sysPermWhitelistMapper; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermWhitelistMapper; + } + +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysRoleService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysRoleService.java new file mode 100644 index 00000000..11d55a31 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysRoleService.java @@ -0,0 +1,247 @@ +package com.orange.admin.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.common.biz.util.BasicIdGenerator; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.upms.dao.SysRoleMapper; +import com.orange.admin.upms.dao.SysRoleMenuMapper; +import com.orange.admin.upms.dao.SysUserRoleMapper; +import com.orange.admin.upms.model.SysRole; +import com.orange.admin.upms.model.SysRoleMenu; +import com.orange.admin.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 tk.mybatis.mapper.entity.Example; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 角色数据服务类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysRoleService extends BaseService { + + @Autowired + private SysRoleMapper sysRoleMapper; + @Autowired + private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + @Autowired + private SysMenuService sysMenuService; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysRoleMapper; + } + + /** + * 保存新增的角色对象。 + * + * @param role 新增的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 新增后的角色对象。 + */ + @Transactional + 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 + 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; + } + Example e = new Example(SysRoleMenu.class); + e.createCriteria().andEqualTo("roleId", role.getRoleId()); + sysRoleMenuMapper.deleteByExample(e); + 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 + public boolean remove(Long roleId) { + SysRole role = new SysRole(); + role.setRoleId(roleId); + role.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysRoleMapper.updateByPrimaryKeySelective(role) != 1) { + return false; + } + Example sysRoleMenuExample = new Example(SysRoleMenu.class); + sysRoleMenuExample.createCriteria().andEqualTo("roleId", roleId); + sysRoleMenuMapper.deleteByExample(sysRoleMenuExample); + Example sysUserRoleExample = new Example(SysUserRole.class); + sysUserRoleExample.createCriteria().andEqualTo("roleId", roleId); + sysUserRoleMapper.deleteByExample(sysUserRoleExample); + return true; + } + + /** + * 获取角色列表。 + * + * @param filter 角色过滤对象。 + * @param orderBy 排序参数。 + * @return 角色列表。 + */ + public List getSysRoleList(SysRole filter, String orderBy) { + return sysRoleMapper.getSysRoleList(filter, orderBy); + } + + /** + * 获取指定角色对象。 + * + * @param roleId 角色主键Id。 + * @return 查询后的角色对象。 + */ + public SysRole getSysRoleWithRelation(Long roleId) { + SysRole sysRole = this.getById(roleId); + if (sysRole != null) { + Example e = new Example(SysRoleMenu.class); + e.createCriteria().andEqualTo("roleId", roleId); + List sysRoleMenuList = sysRoleMenuMapper.selectByExample(e); + if (sysRoleMenuList.size() > 0) { + List menuIdList = + sysRoleMenuList.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); + sysRole.setMenuIdList(menuIdList); + } + } + return sysRole; + } + + /** + * 通过权限字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 + public void addUserRoleList(List userRoleList) { + sysUserRoleMapper.addUserRoleList(userRoleList); + } + + /** + * 移除指定用户和指定角色的关联关系。 + * + * @param roleId 角色主键Id。 + * @param userId 用户主键Id。 + * @return 移除成功返回true,否则false。 + */ + @Transactional + 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 VerifyResult verifyRelatedData(SysRole sysRole, SysRole originalSysRole, String menuIdListString) { + String errorMessage = null; + JSONObject jsonObject = null; + do { + if (StringUtils.isNotBlank(menuIdListString)) { + Set menuIdSet = Arrays.stream( + menuIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysMenuService.existUniqueKeyList("menuId", menuIdSet)) { + errorMessage = "数据验证失败,存在不合法的菜单权限,请刷新后重试!"; + break; + } + jsonObject = new JSONObject(); + jsonObject.put("menuIdSet", menuIdSet); + } + } while (false); + return VerifyResult.create(errorMessage, jsonObject); + } +} diff --git a/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysUserService.java b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysUserService.java new file mode 100644 index 00000000..bc702cc0 --- /dev/null +++ b/orange-admin-service/application/src/main/java/com/orange/admin/upms/service/SysUserService.java @@ -0,0 +1,342 @@ +package com.orange.admin.upms.service; + +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.upms.dao.*; +import com.orange.admin.upms.model.*; +import com.orange.admin.upms.model.constant.SysUserStatus; +import com.orange.admin.common.core.base.service.BaseService; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.TokenData; +import com.orange.admin.common.core.object.MyWhereCriteria; +import com.orange.admin.common.core.object.VerifyResult; +import com.orange.admin.common.core.util.MyCommonUtil; +import com.orange.admin.common.biz.util.BasicIdGenerator; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +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.*; +import java.util.stream.Collectors; + +/** + * 用户管理数据操作服务类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Service +public class SysUserService extends BaseService { + + @Autowired + private SysUserMapper sysUserMapper; + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + @Autowired + private SysDataPermUserMapper sysDataPermUserMapper; + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysDataPermService sysDataPermService; + @Autowired + private BasicIdGenerator idGenerator; + + /** + * 返回当前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集合。 + * @param dataPermIdSet 数据权限Id集合。 + * @param passwdSalt 密码的盐。 + * @return 新增后的用户对象。 + */ + @Transactional + public SysUser saveNew(SysUser user, Set roleIdSet, Set dataPermIdSet, String passwdSalt) { + user.setUserId(idGenerator.nextLongId()); + user.setPassword(MyCommonUtil.encrptedPassword(user.getPassword(), passwdSalt)); + 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); + } + if (CollectionUtils.isNotEmpty(dataPermIdSet)) { + List dataPermUserList = new LinkedList<>(); + for (Long dataPermId : dataPermIdSet) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(user.getUserId()); + dataPermUserList.add(dataPermUser); + } + sysDataPermUserMapper.insertList(dataPermUserList); + } + return user; + } + + /** + * 更新用户对象。 + * + * @param user 更新的用户对象。 + * @param originalUser 原有的用户对象。 + * @param roleIdSet 用户角色Id列表。 + * @param dataPermIdSet 数据权限Id集合。 + * @return 更新成功返回true,否则false。 + */ + @Transactional + public boolean update(SysUser user, SysUser originalUser, Set roleIdSet, Set dataPermIdSet) { + 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关联关系,再重新插入新的关联关系 + Example e = new Example(SysUserRole.class); + e.createCriteria().andEqualTo("userId", user.getUserId()); + sysUserRoleMapper.deleteByExample(e); + 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); + } + // 先删除原有的DataPerm-User关联关系,在重新插入新的关联关系 + Example e2 = new Example(SysDataPermUser.class); + e2.createCriteria().andEqualTo("userId", user.getUserId()); + sysDataPermUserMapper.deleteByExample(e2); + if (CollectionUtils.isNotEmpty(dataPermIdSet)) { + List dataPermUserList = new LinkedList<>(); + for (Long dataPermId : dataPermIdSet) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(user.getUserId()); + dataPermUserList.add(dataPermUser); + } + sysDataPermUserMapper.insertList(dataPermUserList); + } + return true; + } + + /** + * 重置用户密码。 + * @param userId 用户主键Id。 + * @param defaultPasswd 缺省密码。 + * @param passwdSalt 密码的盐。 + * @return 成功返回true,否则false。 + */ + @Transactional + public boolean resetPassword(Long userId, String defaultPasswd, String passwdSalt) { + Example e = new Example(SysUser.class); + e.createCriteria().andEqualTo("userId", userId); + e.createCriteria().andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + SysUser updatedUser = new SysUser(); + updatedUser.setPassword(MyCommonUtil.encrptedPassword(defaultPasswd, passwdSalt)); + return sysUserMapper.updateByExampleSelective(updatedUser, e) == 1; + } + + /** + * 删除指定数据。 + * + * @param userId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional + public boolean remove(Long userId) { + Example sysUserExample = new Example(SysUser.class); + Example.Criteria c = sysUserExample.createCriteria(); + c.andEqualTo("userId", userId); + c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL); + // 这里先删除主数据 + SysUser deletedObject = new SysUser(); + deletedObject.setDeletedFlag(GlobalDeletedFlag.DELETED); + if (sysUserMapper.updateByExampleSelective(deletedObject, sysUserExample) == 0) { + return false; + } + // 这里可继续删除关联数据。 + Example userRoleExample = new Example(SysUserRole.class); + userRoleExample.createCriteria().andEqualTo("userId", userId); + sysUserRoleMapper.deleteByExample(userRoleExample); + Example dataPermUserExample = new Example(SysDataPermUser.class); + dataPermUserExample.createCriteria().andEqualTo("userId", userId); + sysDataPermUserMapper.deleteByExample(dataPermUserExample); + return true; + } + + /** + * 获取指定用户的详情数据。 + * + * @param userId 用户主键Id。 + * @return 用户详情数据。 + */ + @Override + public SysUser getByIdWithRelation(Long userId) { + SysUser user = super.getByIdWithRelation(userId); + if (user != null) { + user.setRoleIdList(sysUserRoleMapper.getRoleIdListByUserId(userId)); + user.setDataPermIdList(sysDataPermUserMapper.getDataPermIdListByUserId(userId)); + } + return user; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(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.buildAllRelationForDataList(resultList, false, 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 dataPermId 数据权限主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + public List getSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy) { + return sysUserMapper.getSysUserListByDataPermId(dataPermId, filter, orderBy); + } + + /** + * 获取不属于指定数据权限的用户列表。 + * + * @param dataPermId 数据权限主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + public List getNotInSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy) { + return sysUserMapper.getNotInSysUserListByDataPermId(dataPermId, filter, orderBy); + } + + /** + * 验证用户对象关联的数据是否都合法。 + * + * @param sysUser 当前操作的对象。 + * @param originalSysUser 原有对象。 + * @param roleIdListString 逗号分隔的角色Id列表字符串。 + * @param dataPermIdListString 逗号分隔的数据权限Id列表字符串。 + * @return 验证结果。 + */ + public VerifyResult verifyRelatedData( + SysUser sysUser, SysUser originalSysUser, String roleIdListString, String dataPermIdListString) { + String errorMessage = null; + JSONObject jsonObject = new JSONObject(); + do { + if (StringUtils.isBlank(roleIdListString)) { + errorMessage = "数据验证失败,用户的角色数据不能为空!"; + break; + } + Set roleIdSet = Arrays.stream( + roleIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysRoleService.existUniqueKeyList("roleId", roleIdSet)) { + errorMessage = "数据验证失败,存在不合法的用户角色,请刷新后重试!"; + break; + } + jsonObject.put("roleIdSet", roleIdSet); + if (StringUtils.isBlank(dataPermIdListString)) { + errorMessage = "数据验证失败,用户的数据权限不能为空!"; + break; + } + Set dataPermIdSet = Arrays.stream( + dataPermIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysDataPermService.existUniqueKeyList("dataPermId", dataPermIdSet)) { + errorMessage = "数据验证失败,存在不合法的数据权限,请刷新后重试!"; + break; + } + jsonObject.put("dataPermIdSet", dataPermIdSet); + } while (false); + return VerifyResult.create(errorMessage, jsonObject); + } +} diff --git a/orange-admin-service/application/src/main/resources/application.yml b/orange-admin-service/application/src/main/resources/application.yml new file mode 100644 index 00000000..bcea20fb --- /dev/null +++ b/orange-admin-service/application/src/main/resources/application.yml @@ -0,0 +1,189 @@ +logging: + level: + # 这里设置的日志级别优先于log4j2.xml文件Loggers中的日志级别。 + com.orange.admin: 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/admin/*/dao/mapper/*Mapper.xml + typeAliasesPackage: com.orange.admin.*.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: '*' + 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/zz-orange-admin?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/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # common-biz 主要包含通用配置项,由common-biz包的CommonBizConfig读取。 + common-biz: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 + # Jwt令牌加密的签名值。 + tokenSigningKey: OrangeAdmin + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # 密码加密的盐值。 + passwordSalt: OrangeAdmin-passwd-salt + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./upload-files/app + # 跨域的IP白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + +# 发布数据库相关配置 +--- +spring: + profiles: product + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + url: jdbc:mysql://localhost:3306/zz-orange-admin?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/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # common-biz 主要包含通用配置项,由common-biz包的CommonBizConfig读取。 + common-biz: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 + # Jwt令牌加密的签名值。 + tokenSigningKey: OrangeAdmin + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # 密码加密的盐值。 + passwordSalt: OrangeAdmin-passwd-salt + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./upload-files/app + # 跨域的IP白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" diff --git a/orange-admin-service/application/src/main/resources/generator/generatorConfig.xml b/orange-admin-service/application/src/main/resources/generator/generatorConfig.xml new file mode 100644 index 00000000..5ca2e428 --- /dev/null +++ b/orange-admin-service/application/src/main/resources/generator/generatorConfig.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-admin-service/application/src/main/resources/log4j2.xml b/orange-admin-service/application/src/main/resources/log4j2.xml new file mode 100644 index 00000000..4cc7d529 --- /dev/null +++ b/orange-admin-service/application/src/main/resources/log4j2.xml @@ -0,0 +1,66 @@ + + + + + + + + + + ./zzlogs + + ./zzlogs/backup + + info + + + + + + + + + [%-5p] 时间[%d{YYYY-MM-dd HH:mm:ss}] 线程[%t] ==> %msg%n + + + 31 + + 20M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-admin-service/application/src/main/resources/template/views/print_error.ftl b/orange-admin-service/application/src/main/resources/template/views/print_error.ftl new file mode 100644 index 00000000..af8b36a7 --- /dev/null +++ b/orange-admin-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-admin-service/application/src/test/java/com/orange/admin/MyApplicationTests.java b/orange-admin-service/application/src/test/java/com/orange/admin/MyApplicationTests.java new file mode 100644 index 00000000..cbe1bf5c --- /dev/null +++ b/orange-admin-service/application/src/test/java/com/orange/admin/MyApplicationTests.java @@ -0,0 +1,16 @@ +package com.orange.admin; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class MyApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/orange-admin-service/areacode.sql b/orange-admin-service/areacode.sql new file mode 100644 index 00000000..3f07e698 --- /dev/null +++ b/orange-admin-service/areacode.sql @@ -0,0 +1,3682 @@ +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- 行政区划表,在以下数据库中执行该脚本。 +-- 主数据源 [localhost:3306/zz-orangle-admin] +-- ---------------------------- +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(5) 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='行政区划表'; + +-- ---------------------------- +-- 行政区划数据 +-- ---------------------------- +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-admin-service/common/common-biz/pom.xml b/orange-admin-service/common/common-biz/pom.xml new file mode 100644 index 00000000..7a9648a5 --- /dev/null +++ b/orange-admin-service/common/common-biz/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + + + com.orange.admin + common + 1.0.0 + + + common-biz + 1.0.0 + common-biz + jar + + + + com.orange.admin + common-core + 1.0.0 + + + \ No newline at end of file diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/advice/MyControllerAdvice.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/advice/MyControllerAdvice.java new file mode 100644 index 00000000..743382be --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/advice/MyControllerAdvice.java @@ -0,0 +1,30 @@ +package com.orange.admin.common.biz.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/advice/MyExceptionHandler.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/advice/MyExceptionHandler.java new file mode 100644 index 00000000..2726fc7d --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/advice/MyExceptionHandler.java @@ -0,0 +1,58 @@ +package com.orange.admin.common.biz.advice; + +import lombok.extern.slf4j.Slf4j; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.common.core.exception.RedisCacheAccessException; +import com.orange.admin.common.core.object.ResponseResult; +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 Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +@RestControllerAdvice +public class MyExceptionHandler { + + @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); + } + + @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); + } + + @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); + } + + @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-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/CommonBizConfig.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/CommonBizConfig.java new file mode 100644 index 00000000..124f2db7 --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/CommonBizConfig.java @@ -0,0 +1,22 @@ +package com.orange.admin.common.biz.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 应用程序自定义的通用属性配置文件。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "application.common-biz") +public class CommonBizConfig { + + /** + * Snowflake计算主键Id时所需的WorkNode参数值。 + */ + private Integer snowflakeWorkNode; +} diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/FastjsonConfig.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/FastjsonConfig.java new file mode 100644 index 00000000..dc632d1d --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/FastjsonConfig.java @@ -0,0 +1,29 @@ +package com.orange.admin.common.biz.config; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * DTA 对象数据格式转换器,这里集成了alibaba的fastjson,作为消息格式转换工具 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Configuration +public class FastjsonConfig { + + @Bean + public HttpMessageConverters fastJsonHttpMessageConverters() { + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures( + SerializerFeature.PrettyFormat, SerializerFeature.DisableCircularReferenceDetect); + fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); + fastConverter.setFastJsonConfig(fastJsonConfig); + return new HttpMessageConverters(fastConverter); + } +} diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/TomcatConfig.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/TomcatConfig.java new file mode 100644 index 00000000..26c55368 --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/config/TomcatConfig.java @@ -0,0 +1,39 @@ +package com.orange.admin.common.biz.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/constant/Subject.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/constant/Subject.java new file mode 100644 index 00000000..1e57c95c --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/constant/Subject.java @@ -0,0 +1,43 @@ +package com.orange.admin.common.biz.constant; + +import java.util.HashMap; +import java.util.Map; + +public final class Subject { + + /** + * 语文。 + */ + public static final int CHINESE = 0; + /** + * 数学。 + */ + public static final int MATH = 1; + /** + * 英语。 + */ + public static final int ENGLISH = 2; + + public static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(CHINESE, "语文"); + DICT_MAP.put(MATH, "数学"); + DICT_MAP.put(ENGLISH, "英语"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private Subject() { + } +} diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/constant/YesNo.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/constant/YesNo.java new file mode 100644 index 00000000..b9eb41e6 --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/constant/YesNo.java @@ -0,0 +1,38 @@ +package com.orange.admin.common.biz.constant; + +import java.util.HashMap; +import java.util.Map; + +public final class YesNo { + + /** + * 是。 + */ + public static final int YES = 1; + /** + * 否。 + */ + public static final int NO = 0; + + public static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(YES, "是"); + DICT_MAP.put(NO, "否"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private YesNo() { + } +} diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/interceptor/AccessInterceptor.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/interceptor/AccessInterceptor.java new file mode 100644 index 00000000..e72ec47c --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/interceptor/AccessInterceptor.java @@ -0,0 +1,59 @@ +package com.orange.admin.common.biz.interceptor; + +import com.orange.admin.common.core.object.GlobalThreadLocal; +import lombok.extern.slf4j.Slf4j; +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; + +/** + * 服务访问日志的拦截器,主要完成记录接口调用时长。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Slf4j +public class AccessInterceptor implements HandlerInterceptor { + + private static final ThreadLocal STARTTIME_THREADLOCAL = new ThreadLocal<>(); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + STARTTIME_THREADLOCAL.set(System.currentTimeMillis()); + // 每次进入Controller接口之前,均主动打开数据权限验证。 + // 可以避免该Servlet线程在处理之前的请求时异常退出,从而导致该状态数据没有被正常清除。 + GlobalThreadLocal.setDataPerm(true); + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + long startTime = STARTTIME_THREADLOCAL.get(); + long elapse = System.currentTimeMillis() - startTime; + String urlPath = request.getRequestURI(); + String controllerMethod = "Unknown"; + if (handler instanceof HandlerMethod) { + HandlerMethod hm = (HandlerMethod) handler; + String controllerName = hm.getBean().getClass().getName(); + // 这里将cglib织入的部分去掉,提升日志的可读性 + int index = controllerName.indexOf("$$"); + if (index > 0) { + controllerName = controllerName.substring(0, index); + } + controllerMethod = controllerName + "." + hm.getMethod().getName(); + } + log.info("access: {} -- elapse {} ms -- {}.", controllerMethod, elapse, urlPath); + STARTTIME_THREADLOCAL.remove(); + GlobalThreadLocal.clearDataPerm(); + } +} diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/interceptor/MyRequestArgumentResolver.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/interceptor/MyRequestArgumentResolver.java new file mode 100644 index 00000000..6ba18e50 --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/interceptor/MyRequestArgumentResolver.java @@ -0,0 +1,234 @@ +package com.orange.admin.common.biz.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.admin.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.lang.NonNull; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +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 Stephen.Liu + * @date 2020-04-11 + */ +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工具类创建一个空对象 + */ + @SuppressWarnings("unchecked") + @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, "application/json")) { + 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) { + Object o; + if (!parameterType.equals(List.class)) { + o = parameterType.newInstance(); + parameterType = (Class) ((ParameterizedType) + parameterType.getGenericSuperclass()).getActualTypeArguments()[0]; + } else { + parameterType = parameterAnnotation.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; + } + // 其他复杂对象 + return JSONObject.toJavaObject((JSONObject) value, parameterType); + } + + /** + * 基本类型解析 + */ + 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); + } + + /** + * 获取请求体JSON字符串 + */ + private JSONObject getRequestBody(NativeWebRequest webRequest) { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + // 有就直接获取 + JSONObject jsonObject = (JSONObject) webRequest.getAttribute(JSONBODY_ATTRIBUTE, NativeWebRequest.SCOPE_REQUEST); + // 没有就从请求中读取 + if (jsonObject == null) { + try { + String jsonBody = IOUtils.toString(servletRequest.getReader()); + jsonObject = JSON.parseObject(jsonBody); + if (jsonObject != null) { + webRequest.setAttribute(JSONBODY_ATTRIBUTE, jsonObject, NativeWebRequest.SCOPE_REQUEST); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return jsonObject; + } +} diff --git a/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/listener/LoadCachedDataListener.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/listener/LoadCachedDataListener.java new file mode 100644 index 00000000..de6b4419 --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/listener/LoadCachedDataListener.java @@ -0,0 +1,27 @@ +package com.orange.admin.common.biz.listener; + +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Component +public class LoadCachedDataListener implements ApplicationListener { + + @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-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/listener/LoadServiceRelationListener.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/listener/LoadServiceRelationListener.java new file mode 100644 index 00000000..d67500c5 --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/listener/LoadServiceRelationListener.java @@ -0,0 +1,27 @@ +package com.orange.admin.common.biz.listener; + +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@Component +public class LoadServiceRelationListener implements ApplicationListener { + + @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-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/util/BasicIdGenerator.java b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/util/BasicIdGenerator.java new file mode 100644 index 00000000..3945890b --- /dev/null +++ b/orange-admin-service/common/common-biz/src/main/java/com/orange/admin/common/biz/util/BasicIdGenerator.java @@ -0,0 +1,51 @@ +package com.orange.admin.common.biz.util; + +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.IdUtil; +import com.orange.admin.common.biz.config.CommonBizConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * 全局共享的snowflake计算工具类。 + * 基于Hutool中的对应工具类实现,同时读取系统的配置参数并初始化该对象。如果今后 + * 升级为基于分布式Id生成服务的实现时,仅需修改内部实现,外部业务方法不会受到任何影响。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Component +public class BasicIdGenerator { + + @Autowired + private CommonBizConfig config; + + private Snowflake snowflake; + + @PostConstruct + private void init() { + snowflake = IdUtil.createSnowflake(config.getSnowflakeWorkNode(), 0); + } + + /** + * 获取基于Snowflake算法的数值型Id。 + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + public long nextLongId() { + return this.snowflake.nextId(); + } + + /** + * 获取基于Snowflake算法的字符串Id。 + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + public String nextStringId() { + return this.snowflake.nextIdStr(); + } +} diff --git a/orange-admin-service/common/common-core/pom.xml b/orange-admin-service/common/common-core/pom.xml new file mode 100644 index 00000000..c9ed08fe --- /dev/null +++ b/orange-admin-service/common/common-core/pom.xml @@ -0,0 +1,107 @@ + + + 4.0.0 + + + com.orange.admin + common + 1.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 + + + 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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/DeletedFlagColumn.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/DeletedFlagColumn.java new file mode 100644 index 00000000..899409fc --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/DeletedFlagColumn.java @@ -0,0 +1,16 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记逻辑删除字段。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeletedFlagColumn { + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/DeptFilterColumn.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/DeptFilterColumn.java new file mode 100644 index 00000000..451d4203 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/DeptFilterColumn.java @@ -0,0 +1,16 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记数据权限中基于DeptId进行过滤的字段。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeptFilterColumn { + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/EnableDataPerm.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/EnableDataPerm.java new file mode 100644 index 00000000..a792b1b1 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/EnableDataPerm.java @@ -0,0 +1,27 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 用于注解DAO层Mapper对象的数据权限规则。 + * 由于框架使用了tk.mapper,所以并非所有的Mapper接口均在当前Mapper对象中定义,有一部分被tk.mapper封装,如selectAll等。 + * 如果需要排除tk.mapper中的方法,可以直接使用tk.mapper基类所声明的方法名称即可。 + * 另外,比较特殊的场景是,因为tk.mapper是通用框架,所以同样的selectAll方法,可以获取不同的数据集合,因此在service中如果 + * 出现两个不同的方法调用Mapper的selectAll方法,但是一个需要参与过滤,另外一个不需要参与,那么就需要修改当前类的Mapper方法, + * 将其中一个方法重新定义一个具体的接口方法,并重新设定其是否参与数据过滤。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface EnableDataPerm { + + /** + * 排除的方法名称数组。如果为空,所有的方法均会被Mybaits拦截注入权限过滤条件。 + * + * @return 被排序的方法名称数据。 + */ + String[] excluseMethodName() default {}; +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/JobUpdateTimeColumn.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/JobUpdateTimeColumn.java new file mode 100644 index 00000000..f4cfbb54 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/JobUpdateTimeColumn.java @@ -0,0 +1,16 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记更新字段。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface JobUpdateTimeColumn { + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/MyDataSource.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/MyDataSource.java new file mode 100644 index 00000000..72d82e03 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/MyDataSource.java @@ -0,0 +1,21 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记Service所依赖的数据源类型。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MyDataSource { + + /** + * 标注的数据源类型 + * @return 当前标注的数据源类型。 + */ + int value(); +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/MyRequestBody.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/MyRequestBody.java new file mode 100644 index 00000000..b306859e --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/MyRequestBody.java @@ -0,0 +1,31 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/NoAuthInterface.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/NoAuthInterface.java new file mode 100644 index 00000000..4311aa48 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/NoAuthInterface.java @@ -0,0 +1,15 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记无需Token验证的接口 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface NoAuthInterface { +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationConstDict.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationConstDict.java new file mode 100644 index 00000000..6c2e6f27 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationConstDict.java @@ -0,0 +1,29 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model和常量字典之间的关联关系。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationDict.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationDict.java new file mode 100644 index 00000000..e383877c --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationDict.java @@ -0,0 +1,60 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model之间的字典关联关系。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationManyToManyAggregation.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationManyToManyAggregation.java new file mode 100644 index 00000000..8e0857d6 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationManyToManyAggregation.java @@ -0,0 +1,85 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于多对多的Model关系。标注通过从表关联字段或者关联表关联字段计算主表虚拟字段的规则。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationOneToManyAggregation.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationOneToManyAggregation.java new file mode 100644 index 00000000..12516c93 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationOneToManyAggregation.java @@ -0,0 +1,57 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于一对多的Model关系。标注通过从表关联字段计算主表虚拟字段的规则。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationOneToOne.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationOneToOne.java new file mode 100644 index 00000000..1834645e --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/RelationOneToOne.java @@ -0,0 +1,50 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model之间的一对一关联关系。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/UserFilterColumn.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/UserFilterColumn.java new file mode 100644 index 00000000..82269325 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/annotation/UserFilterColumn.java @@ -0,0 +1,16 @@ +package com.orange.admin.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记数据权限中基于UserId进行过滤的字段。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface UserFilterColumn { + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/dao/BaseDaoMapper.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/dao/BaseDaoMapper.java new file mode 100644 index 00000000..e8740732 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/dao/BaseDaoMapper.java @@ -0,0 +1,90 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/mapper/BaseModelMapper.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/mapper/BaseModelMapper.java new file mode 100644 index 00000000..ce46df24 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/mapper/BaseModelMapper.java @@ -0,0 +1,89 @@ +package com.orange.admin.common.core.base.mapper; + +import cn.hutool.core.bean.BeanUtil; + +import java.util.List; +import java.util.Map; + +/** + * Model对象到Domain类型对象的相互转换。实现类通常声明在Model实体类中。 + * + * @param Domain域对象类型。 + * @param Model实体对象类型。 + * @author Stephen.Liu + * @date 2020-04-11 + */ +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); + } + + /** + * 转换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字段到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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/mapper/DummyModelMapper.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/mapper/DummyModelMapper.java new file mode 100644 index 00000000..d1fda13a --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/mapper/DummyModelMapper.java @@ -0,0 +1,58 @@ +package com.orange.admin.common.core.base.mapper; + +import java.util.List; + +/** + * 哑元占位对象。Model实体对象和Domain域对象相同的场景下使用。 + * 由于没有实际的数据转换,因此同时保证了代码统一和执行效率。 + * + * @param 数据类型。 + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/service/BaseDictService.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/service/BaseDictService.java new file mode 100644 index 00000000..5a222bd2 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/service/BaseDictService.java @@ -0,0 +1,142 @@ +package com.orange.admin.common.core.base.service; + +import com.orange.admin.common.core.cache.DictionaryCache; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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(); + } + } + + /** + * 重新加载数据库中所有当前表数据到系统内存。 + */ + public void reloadCachedData() { + List allList = super.getAllList(); + dictionaryCache.reload(allList); + } + + /** + * 直接从缓存池中获取主键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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/service/BaseService.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/service/BaseService.java new file mode 100644 index 00000000..708903f5 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/base/service/BaseService.java @@ -0,0 +1,1268 @@ +package com.orange.admin.common.core.base.service; + +import com.orange.admin.common.core.annotation.*; +import com.orange.admin.common.core.base.dao.BaseDaoMapper; +import com.orange.admin.common.core.constant.AggregationType; +import com.orange.admin.common.core.constant.GlobalDeletedFlag; +import com.orange.admin.common.core.object.GlobalThreadLocal; +import com.orange.admin.common.core.object.MyWhereCriteria; +import com.orange.admin.common.core.object.Tuple2; +import com.orange.admin.common.core.util.ApplicationContextHolder; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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; + /** + * 当前Service关联的主Model对象的所有常量字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationConstDictStructList; + /** + * 当前Service关联的主Model对象的所有一对一关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationOneToOneStructList; + /** + * 当前Service关联的主Model对象的所有一对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationOneToManyAggrStructList; + /** + * 当前Service关联的主Model对象的所有多对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private List relationManyToManyAggrStructList; + + private static final String GROUPED_KEY = "groupedKey"; + private static final String AGGREGATED_VALUE = "aggregatedValue"; + + /** + * 构造函数,在实例化的时候,一次性完成所有有关主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) { + if (idFieldName == null) { + if (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) { + if (null != field.getAnnotation(JobUpdateTimeColumn.class)) { + updateTimeFieldName = field.getName(); + Column c = field.getAnnotation(Column.class); + updateTimeColumnName = c == null ? updateTimeFieldName : c.name(); + } + } + if (deletedFlagFieldName == null) { + if (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。 + * @return 查询结果对象。 + */ + public M getByIdWithRelation(K id) { + return this.buildAllRelationForData( + this.getById(id), false, buildAggregationAdditionalWhereCriteria()); + } + + /** + * 获取所有数据。 + * + * @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 dictOnly true 将只是关联字典数据,false将同时关联字典数据和一对一关联数据。 + * @return 返回所有主数据,及其关联数据。 + */ + public List getAllListWithRelation(boolean dictOnly) { + List resultList = getAllList(); + this.buildRelationForDataList(resultList, dictOnly); + 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); + } + + /** + * 判断参数值列表中的所有数据,是否全部存在。另外,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.", e); + throw new RuntimeException(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 返回过滤后的数据。 + */ + public 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.", ex); + throw new RuntimeException(ex); + } + } + + /** + * 用参数对象作为过滤条件,获取查询结果。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @param orderBy SQL中ORDER BY从句。 + * @return 返回过滤后的数据。 + */ + public List getListByFilter(M filter, String orderBy) { + 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) { + continue; + } + int modifiers = field.getModifiers(); + // transient类型的字段不能作为查询条件 + if ((modifiers & 128) == 0) { + if (field.getName().equals(deletedFlagFieldName)) { + c.andEqualTo(deletedFlagFieldName, GlobalDeletedFlag.NORMAL); + } else { + field.setAccessible(true); + 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.", ex); + throw new RuntimeException(ex); + } + } + } + } + } + return mapper().selectByExample(e); + } + + /** + * 用参数对象作为过滤条件,获取查询结果。同时组装实体对象中基于RelationXXXX注解关联的数据。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @return 返回过滤后的数据。 + */ + public List getListWithRelationByFilter(M filter) { + List resultList = this.getListByFilter(filter); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildAllRelationForDataList(resultList, false, criteriaMap); + return resultList; + } + + /** + * 用参数对象作为过滤条件,获取查询结果。同时组装实体对象中基于RelationXXXX注解关联的数据。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @param orderBy SQL中ORDER BY从句。 + * @return 返回过滤后的数据。 + */ + public List getListWithRelationByFilter(M filter, String orderBy) { + List resultList = this.getListByFilter(filter, orderBy); + Map> criteriaMap = buildAggregationAdditionalWhereCriteria(); + this.buildAllRelationForDataList(resultList, false, 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); + } + + /** + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param dictOnly 是否只是集成字典,包括注解RelationDict和RelationConstDict标注的字段。 + * @param criteriaListMap 仅仅用于一对多和多对多聚合计算的附加过滤条件。如果没有可以为NULL。 + */ + public void buildAllRelationForDataList( + List resultList, boolean dictOnly, Map> criteriaListMap) { + // 集成本地一对一和字段级别的数据关联。 + this.buildRelationForDataList(resultList, dictOnly); + if (!dictOnly) { + // 组装本地聚合计算关联数据 + this.buildAggregationRelationForDataList(resultList, criteriaListMap); + } + } + + /** + * 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表实体对象。数据集成将直接作用于该对象。 + * @param dictOnly 是否只是集成字典,包括注解RelationDict和RelationConstDict标注的字段。 + * @param criteriaListMap 仅仅用于一对多和多对多聚合计算的附加过滤条件。如果没有可以为NULL。 + * @param 实体对象类型。 + * @return 集成后的原实体对象。 + */ + public T buildAllRelationForData( + T dataObject, boolean dictOnly, Map> criteriaListMap) { + // 集成本地一对一和字段级别的数据关联。 + this.buildRelationForData(dataObject, dictOnly); + if (!dictOnly) { + // 组装本地聚合计算关联数据 + this.buildAggregationRelationForData(dataObject, criteriaListMap); + } + return dataObject; + } + + /** + * 为参数列表数据集成本地静态字典关联数据。 + * + * @param resultList 主表数据列表。 + */ + public void buildConstDictForDataList(List resultList) { + if (CollectionUtils.isNotEmpty(this.relationConstDictStructList)) { + 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 实体对象。 + */ + public void buildConstDictForData(T dataObject) { + if (CollectionUtils.isNotEmpty(this.relationConstDictStructList)) { + 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); + } + } + } + } + } + + /** + * 集成字典关联数据列表和一对一从表关联数据列表。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表数据列表。数据集成将直接作用于该对象列表。 + * @param dictOnly 是否只是关联字典数据。 + */ + public void buildRelationForDataList(List resultList, boolean dictOnly) { + if (CollectionUtils.isEmpty(resultList)) { + return; + } + boolean dataPermEnabled = GlobalThreadLocal.setDataPerm(false); + if (!dictOnly) { + if (CollectionUtils.isNotEmpty(this.relationOneToOneStructList)) { + for (RelationStruct relationStruct : this.relationOneToOneStructList) { + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isNotEmpty(masterIdSet)) { + BaseService relationService = relationStruct.service; + List relationList = + relationService.getInList(relationStruct.relationOneToOne.slaveIdField(), masterIdSet); + // 仅仅当需要加载从表字典关联时,才去加载。 + if (relationStruct.relationOneToOne.loadSlaveDict() && CollectionUtils.isNotEmpty(relationList)) { + relationService.buildRelationForDataList(relationList, true); + MyModelUtil.makeOneToOneRelation( + modelClass, resultList, relationList, relationStruct.relationField.getName()); + } + } + } + } + } + // 构建常量字典关联关系 + this.buildConstDictForDataList(resultList); + if (CollectionUtils.isNotEmpty(this.relationDictStructList)) { + for (RelationStruct relationStruct : this.relationDictStructList) { + List relationList = null; + if (!dictOnly && 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()); + } + } + GlobalThreadLocal.setDataPerm(dataPermEnabled); + } + + /** + * 集成字典关联数据和一对一从表关联数据。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表数据对象。数据集成将直接作用于该对象。 + * @param dictOnly 是否只是关联字典数据。 + * @return 关联后的主表数据对象。 + */ + public T buildRelationForData(T dataObject, boolean dictOnly) { + if (dataObject == null) { + return dataObject; + } + boolean dataPermEnabled = GlobalThreadLocal.setDataPerm(false); + if (!dictOnly) { + if (CollectionUtils.isNotEmpty(this.relationOneToOneStructList)) { + for (RelationStruct relationStruct : this.relationOneToOneStructList) { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + BaseService relationService = relationStruct.service; + Object relationObject = relationService.getById(id); + // 仅仅当需要加载从表字典关联时,才去加载。 + if (relationStruct.relationOneToOne.loadSlaveDict() && relationObject != null) { + relationService.buildRelationForData(relationObject, true); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject); + } + } + } + } + } + // 构建常量字典关联关系 + this.buildConstDictForData(dataObject); + if (CollectionUtils.isNotEmpty(this.relationDictStructList)) { + for (RelationStruct relationStruct : this.relationDictStructList) { + Object relationObject = null; + if (!dictOnly && 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()); + } + } + GlobalThreadLocal.setDataPerm(dataPermEnabled); + return dataObject; + } + + /** + * 集成本地服务中,多个表之间的聚合计算关系,主要覆盖一对多和多对多两种场景。 + * 其中一对多关系,比如课程表的章节统计字段sectionCount,可能依赖于课程章节表中关联章节的数量。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主数据表结果集。数据集成将直接作用于该对象列表。 + * @param criteriaListMap 自定义的过滤条件列表。每个key对应不同的聚合关联字段名称,既注解应用的Java字段,如courseSectionCount。 + */ + public void buildAggregationRelationForDataList( + List resultList, Map> criteriaListMap) { + if (CollectionUtils.isEmpty(resultList)) { + return; + } + boolean dataPermEnabled = GlobalThreadLocal.setDataPerm(false); + // 处理多对多场景下,根据主表的结果,进行从表聚合数据的计算。 + if (CollectionUtils.isNotEmpty(this.relationManyToManyAggrStructList)) { + 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.isNotEmpty(masterIdSet)) { + RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation; + // 提取关联中用到的各种字段和表数据。 + String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + String relationTable = MyModelUtil.mapToTableName(relation.relationModelClass()); + String relationMasterColumn = + MyModelUtil.mapToColumnName(relation.relationMasterIdField(), relation.relationModelClass()); + String relationSlaveColumn = + MyModelUtil.mapToColumnName(relation.relationSlaveIdField(), relation.relationModelClass()); + String slaveColumn = + MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + // 判断是否只需要关联中间表即可,从而提升查询统计的效率。 + // 1. 统计字段为中间表字段。2. 自定义过滤条件中没有基于从表字段的过滤条件。 + boolean onlySelectRelationTable = + relation.aggregationModelClass().equals(relation.relationModelClass()); + if (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())) { + onlySelectRelationTable = false; + break; + } + } + } + } + String aggregationTable = + relation.aggregationModelClass().equals(relation.relationModelClass()) ? relationTable : slaveTable; + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + relationTable, relationMasterColumn, relation.aggregationModelClass(), + aggregationTable, relation.aggregationField(), relation.aggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + // 构建多表关联的where语句 + StringBuilder whereClause = new StringBuilder(256); + // 如果需要从表聚合计算或参与过滤,则需要把中间表和从表之间的关联条件加上。 + if (!onlySelectRelationTable) { + whereClause.append(relationTable) + .append(".") + .append(relationSlaveColumn) + .append(" = ") + .append(slaveTable) + .append(".") + .append(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.getCriteriaString(criteriaList); + whereClause.append(" AND ").append(criteriaString); + StringBuilder tableNames = new StringBuilder(64); + tableNames.append(relationTable); + if (!onlySelectRelationTable) { + tableNames.append(", ").append(slaveTable); + } + List> aggregationMapList = mapper().getGroupedListByCondition( + tableNames.toString(), selectList, whereClause.toString(), groupBy); + doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct); + } + } + } + // 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。 + if (CollectionUtils.isNotEmpty(this.relationOneToManyAggrStructList)) { + 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.isNotEmpty(masterIdSet)) { + 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.getCriteriaString(criteriaList); + List> aggregationMapList = + mapper().getGroupedListByCondition(slaveTable, selectList, criteriaString, groupBy); + doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct); + } + } + } + GlobalThreadLocal.setDataPerm(dataPermEnabled); + } + + /** + * 集成本地服务中,多个表之间的聚合计算关系,主要覆盖一对多和多对多两种场景。 + * 其中一对多关系,比如课程表的章节统计字段sectionCount,可能依赖于课程章节表中关联章节的数量。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表对象。数据集成将直接作用于该对象。 + * @param criteriaListMap 自定义的过滤条件列表。每个key对应不同的聚合关联字段名称,既注解应用的Java字段,如courseSectionCount。 + * @param 参数类型。 + * @return 集成后的主表对象。 + */ + public T buildAggregationRelationForData(T dataObject, Map> criteriaListMap) { + if (dataObject == null) { + return null; + } + boolean dataPermEnabled = GlobalThreadLocal.setDataPerm(false); + // 开始处理多对多场景。 + if (CollectionUtils.isNotEmpty(this.relationManyToManyAggrStructList)) { + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue != null) { + RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation; + String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + String relationTable = MyModelUtil.mapToTableName(relation.relationModelClass()); + String relationMasterColumn = + MyModelUtil.mapToColumnName(relation.relationMasterIdField(), relation.relationModelClass()); + String relationSlaveColumn = + MyModelUtil.mapToColumnName(relation.relationSlaveIdField(), relation.relationModelClass()); + String slaveColumn = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + // 判断是否只需要关联中间表即可,从而提升查询统计的效率。 + // 1. 统计字段为中间表字段。2. 自定义过滤条件中没有基于从表字段的过滤条件。 + boolean onlySelectRelationTable = relation.aggregationModelClass().equals(relation.relationModelClass()); + if (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())) { + onlySelectRelationTable = false; + break; + } + } + } + } + String aggregationTable = + relation.aggregationModelClass().equals(relation.relationModelClass()) ? relationTable : slaveTable; + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + relationTable, relationMasterColumn, relation.aggregationModelClass(), + aggregationTable, relation.aggregationField(), relation.aggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + // 组装过滤条件 + StringBuilder whereClause = new StringBuilder(256); + whereClause.append(relationTable).append(".").append(relationMasterColumn); + if (masterIdValue instanceof Number) { + whereClause.append(" = ").append(masterIdValue); + } else { + whereClause.append(" = '").append(masterIdValue).append("'"); + } + // 如果需要从表聚合计算或参与过滤,则需要把中间表和从表之间的关联条件加上。 + if (!onlySelectRelationTable) { + whereClause.append(" AND ") + .append(relationTable) + .append(".") + .append(relationSlaveColumn) + .append(" = ") + .append(slaveTable) + .append(".") + .append(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( + relation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (CollectionUtils.isNotEmpty(criteriaList)) { + String criteriaString = MyWhereCriteria.getCriteriaString(criteriaList); + whereClause.append(" AND ").append(criteriaString); + } + StringBuilder tableNames = new StringBuilder(64); + tableNames.append(relationTable); + if (!onlySelectRelationTable) { + tableNames.append(", ").append(slaveTable); + } + List> aggregationMapList = mapper().getGroupedListByCondition( + tableNames.toString(), selectList, whereClause.toString(), groupBy); + // 将查询后的结果回填到主表数据中。 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + } + // 构建一对多场景 + if (CollectionUtils.isNotEmpty(this.relationOneToManyAggrStructList)) { + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue != null) { + 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(); + 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( + relation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (CollectionUtils.isNotEmpty(criteriaList)) { + String criteriaString = MyWhereCriteria.getCriteriaString(criteriaList); + whereClause.append(" AND ").append(criteriaString); + } + // 获取分组聚合计算结果 + List> aggregationMapList = mapper().getGroupedListByCondition( + slaveTable, selectList, whereClause.toString(), groupBy); + // 将计算结果回填到主表关联字段 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + } + GlobalThreadLocal.setDataPerm(dataPermEnabled); + return dataObject; + } + + /** + * 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。 + */ + @SuppressWarnings("unchecked") + public void loadRelationStruct() { + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field f : fields) { + RelationConstDict relationConstDict = f.getAnnotation(RelationConstDict.class); + if (relationConstDict != null) { + if (relationConstDictStructList == null) { + relationConstDictStructList = new LinkedList<>(); + } + 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); + continue; + } + RelationDict relationDict = f.getAnnotation(RelationDict.class); + if (relationDict != null) { + if (relationDictStructList == null) { + relationDictStructList = new LinkedList<>(); + } + 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); + continue; + } + RelationOneToOne relationOneToOne = f.getAnnotation(RelationOneToOne.class); + if (relationOneToOne != null) { + if (relationOneToOneStructList == null) { + relationOneToOneStructList = new LinkedList<>(); + } + 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); + continue; + } + RelationOneToManyAggregation relationOneToManyAggregation = f.getAnnotation(RelationOneToManyAggregation.class); + if (relationOneToManyAggregation != null) { + if (relationOneToManyAggrStructList == null) { + relationOneToManyAggrStructList = new LinkedList<>(); + } + 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); + continue; + } + RelationManyToManyAggregation relationManyToManyAggregation = f.getAnnotation(RelationManyToManyAggregation.class); + if (relationManyToManyAggregation != null) { + if (relationManyToManyAggrStructList == null) { + relationManyToManyAggrStructList = new LinkedList<>(); + } + 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); + } + } + } + + /** + * 缺省实现返回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 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 { + public Field relationField; + public Field masterIdField; + public Field equalOneToOneRelationField; + public BaseService service; + public Map dictMap; + public RelationDict relationDict; + public RelationOneToOne relationOneToOne; + public RelationConstDict relationConstDict; + public RelationOneToManyAggregation relationOneToManyAggregation; + public RelationManyToManyAggregation relationManyToManyAggregation; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/DictionaryCache.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/DictionaryCache.java new file mode 100644 index 00000000..cafdbdd8 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/DictionaryCache.java @@ -0,0 +1,87 @@ +package com.orange.admin.common.core.cache; + +import java.util.List; +import java.util.Set; + +/** + * 主要用于完整缓存字典表数据的接口对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface DictionaryCache { + + /** + * 按照数据插入的顺序返回全部字典对象的列表。 + * + * @return 全部字段数据列表。 + */ + List getAll(); + + /** + * 获取缓存中与键列表对应的对象列表。 + * + * @param keys 主键集合。 + * @return 对象列表。 + */ + List getInList(Set keys); + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + void putAll(List dataList); + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + */ + void reload(List dataList); + + /** + * 从缓存中获取指定的数据。 + * + * @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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/MapDictionaryCache.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/MapDictionaryCache.java new file mode 100644 index 00000000..766289fa --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/MapDictionaryCache.java @@ -0,0 +1,115 @@ +package com.orange.admin.common.core.cache; + +import java.util.*; +import java.util.function.Function; + +/** + * 字典数据内存缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Stephen.Liu + * @date 2020-04-11 + */ +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); + } + + public MapDictionaryCache(Function idGetter) { + this.idGetter = idGetter; + } + + @Override + public synchronized List getAll() { + List resultList = new LinkedList<>(); + for (Map.Entry entry : dataMap.entrySet()) { + resultList.add(entry.getValue()); + } + return resultList; + } + + @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; + } + + @Override + public synchronized void putAll(List dataList) { + if (dataList == null) { + return; + } + dataList.forEach(dataObj -> { + K id = idGetter.apply(dataObj); + dataMap.put(id, dataObj); + }); + } + + @Override + public synchronized void reload(List dataList) { + this.invalidateAll(); + this.putAll(dataList); + } + + @Override + public synchronized V get(K id) { + return id == null ? null : dataMap.get(id); + } + + @Override + public synchronized void put(K id, V object) { + dataMap.put(id, object); + } + + @Override + public synchronized int getCount() { + return dataMap.size(); + } + + @Override + public synchronized V invalidate(K id) { + return id == null ? null : dataMap.remove(id); + } + + @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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/MapTreeDictionaryCache.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/MapTreeDictionaryCache.java new file mode 100644 index 00000000..3587a7f3 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/cache/MapTreeDictionaryCache.java @@ -0,0 +1,108 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +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); + } + + 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)); + } + + @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); + }); + } + + @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); + } + + @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; + } + + @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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/AggregationType.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/AggregationType.java new file mode 100644 index 00000000..35acef63 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/AggregationType.java @@ -0,0 +1,75 @@ +package com.orange.admin.common.core.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 聚合计算的常量类型对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public final class AggregationType { + + /** + * sum 计数 + */ + public final static int SUM = 0; + /** + * count 汇总 + */ + public final static int COUNT = 1; + /** + * average 平均值 + */ + public final static int AVG = 2; + /** + * min 最小值 + */ + public final static int MIN = 3; + /** + * max 最大值 + */ + public final static int MAX = 4; + + public 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 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("无效的聚合类型!"); + } + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/ApplicationConstant.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/ApplicationConstant.java new file mode 100644 index 00000000..58638a43 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/ApplicationConstant.java @@ -0,0 +1,19 @@ +package com.orange.admin.common.core.constant; + +/** + * 应用程序的常量声明对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface ApplicationConstant { + + /** + * 图片文件上传的父目录。 + */ + String UPLOAD_IMAGE_PARENT_PATH = "/image"; + /** + * 附件文件上传的父目录。 + */ + String UPLOAD_ATTACHMENT_PARENT_PATH = "/attachment"; +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/DataPermRuleType.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/DataPermRuleType.java new file mode 100644 index 00000000..59f67b63 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/DataPermRuleType.java @@ -0,0 +1,57 @@ +package com.orange.admin.common.core.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 数据权限规则类型常量类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public final class DataPermRuleType { + + /** + * 查看全部。 + */ + public static final int TYPE_ALL = 0; + + /** + * 仅查看当前用户 + */ + public static final int TYPE_USER_ONLY = 1; + + /** + * 仅查看当前部门 + */ + public static final int TYPE_DEPT_ONLY = 2; + + /** + * 自定义部门列表 + */ + public static final int TYPE_CUSTOM_DETP_LIST = 5; + + public static final Map DICT_MAP = new HashMap<>(4); + static { + DICT_MAP.put(0, "查看全部"); + DICT_MAP.put(1, "仅查看当前用户"); + DICT_MAP.put(2, "仅查看所在部门"); + DICT_MAP.put(5, "自定义部门列表"); + } + + /** + * 判断参数是否为当前常量字典的合法取值范围。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(int value) { + return DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DataPermRuleType() { + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/ErrorCodeEnum.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/ErrorCodeEnum.java new file mode 100644 index 00000000..b8d9ac08 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/ErrorCodeEnum.java @@ -0,0 +1,60 @@ +package com.orange.admin.common.core.constant; + +/** + * 返回应答中的错误代码和错误信息。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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_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_FIELD("数据验证失败,无效的数据字段!"), + SERVER_INTERNAL_ERROR("服务器内部错误,请联系管理员!"), + REDIS_CACHE_ACCESS_TIMEOUT("Redis缓存数据访问超时,请刷新后重试!"), + REDIS_CACHE_ACCESS_STATE_ERROR("Redis缓存数据访问状态错误,请刷新后重试!"); + + // 下面的枚举值为特定枚举值,即开发者可以根据自己的项目需求定义更多的非通用枚举值 + + ErrorCodeEnum(String errorMessage) { + this.errorMessage = errorMessage; + } + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/GlobalDeletedFlag.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/GlobalDeletedFlag.java new file mode 100644 index 00000000..1f7f273f --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/constant/GlobalDeletedFlag.java @@ -0,0 +1,19 @@ +package com.orange.admin.common.core.constant; + +/** + * 数据记录逻辑删除标记常量。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface GlobalDeletedFlag { + + /** + * 表示数据表记录已经删除 + */ + int DELETED = -1; + /** + * 数据记录正常 + */ + int NORMAL = 1; +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/DataValidationException.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/DataValidationException.java new file mode 100644 index 00000000..e7717e81 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/DataValidationException.java @@ -0,0 +1,18 @@ +package com.orange.admin.common.core.exception; + +/** + * 数据验证失败的自定义异常。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public class DataValidationException extends RuntimeException { + + public DataValidationException() { + + } + + public DataValidationException(String msg) { + super(msg); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/InvalidDataFieldException.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/InvalidDataFieldException.java new file mode 100644 index 00000000..dd9c387b --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/InvalidDataFieldException.java @@ -0,0 +1,24 @@ +package com.orange.admin.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的实体对象字段的自定义异常。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidDataFieldException extends RuntimeException { + + private String modelName; + private String 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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/InvalidDataModelException.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/InvalidDataModelException.java new file mode 100644 index 00000000..7599a08b --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/InvalidDataModelException.java @@ -0,0 +1,22 @@ +package com.orange.admin.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的实体对象的自定义异常。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidDataModelException extends RuntimeException { + + private String modelName; + + public InvalidDataModelException(String modelName) { + super("Invalid Model Class [" + modelName + "]."); + this.modelName = modelName; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/NoDataAffectException.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/NoDataAffectException.java new file mode 100644 index 00000000..000ec7ea --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/NoDataAffectException.java @@ -0,0 +1,18 @@ +package com.orange.admin.common.core.exception; + +/** + * 没有数据被修改的自定义异常。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public class NoDataAffectException extends RuntimeException { + + public NoDataAffectException() { + + } + + public NoDataAffectException(String msg) { + super(msg); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/NoDataPermException.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/NoDataPermException.java new file mode 100644 index 00000000..56ba42cc --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/NoDataPermException.java @@ -0,0 +1,18 @@ +package com.orange.admin.common.core.exception; + +/** + * 没有数据访问权限的自定义异常。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public class NoDataPermException extends RuntimeException { + + public NoDataPermException() { + + } + + public NoDataPermException(String msg) { + super(msg); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/RedisCacheAccessException.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/RedisCacheAccessException.java new file mode 100644 index 00000000..fee4ba7f --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/exception/RedisCacheAccessException.java @@ -0,0 +1,14 @@ +package com.orange.admin.common.core.exception; + +/** + * Redis缓存访问失败。比如:获取分布式数据锁超时、等待线程中断等。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public class RedisCacheAccessException extends RuntimeException { + + public RedisCacheAccessException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/GlobalThreadLocal.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/GlobalThreadLocal.java new file mode 100644 index 00000000..c34f7b95 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/GlobalThreadLocal.java @@ -0,0 +1,45 @@ +package com.orange.admin.common.core.object; + +import cn.hutool.core.util.BooleanUtil; + +/** + * 线程本地化数据管理的工具类。可根据需求自行添加更多的线程本地化变量及其操作方法。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public class GlobalThreadLocal { + + /** + * 存储数据权限过滤是否启用的线程本地化对象。 + */ + private static final ThreadLocal DATA_PERM_ENABLE = ThreadLocal.withInitial(() -> Boolean.TRUE); + + /** + * 设置数据权限过滤是否打开。如果打开,当前Servlet线程所执行的SQL操作,均会进行数据权限过滤。 + * + * @param enable 打开为true,否则false。 + * @return 返回之前的状态,便于恢复。 + */ + public static boolean setDataPerm(boolean enable) { + boolean oldValue = DATA_PERM_ENABLE.get(); + DATA_PERM_ENABLE.set(enable); + return oldValue; + } + + /** + * 判断当前Servlet线程所执行的SQL操作,是否进行数据权限过滤。 + * + * @return true 进行数据权限过滤,否则false。 + */ + public static boolean enabledDataPerm() { + return BooleanUtil.isTrue(DATA_PERM_ENABLE.get()); + } + + /** + * 清空该存储数据,主动释放线程本地化存储资源。 + */ + public static void clearDataPerm() { + DATA_PERM_ENABLE.remove(); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyGroupCriteria.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyGroupCriteria.java new file mode 100644 index 00000000..25fb8d90 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyGroupCriteria.java @@ -0,0 +1,24 @@ +package com.orange.admin.common.core.object; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Mybatis Mapper.xml中所需的分组条件对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +@AllArgsConstructor +public class MyGroupCriteria { + + /** + * GROUP BY 从句后面的参数。 + */ + private String groupBy; + /** + * SELECT 从句后面的分组显示字段。 + */ + private String groupSelect; +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyGroupParam.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyGroupParam.java new file mode 100644 index 00000000..ac7073cb --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyGroupParam.java @@ -0,0 +1,143 @@ +package com.orange.admin.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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) { + String modelName, fieldName, tableName, columnName; + String[] stringArray = StringUtils.split(groupInfo.fieldName,'.'); + if (stringArray.length == 1) { + modelName = modelClazz.getSimpleName(); + fieldName = groupInfo.fieldName; + tableName = MyModelUtil.mapToTableName(modelClazz); + columnName = MyModelUtil.mapToColumnName(fieldName, modelClazz); + } else { + Field field = ReflectUtil.getField(modelClazz, stringArray[0]); + if (field == null) { + log.error("Relation Field [{}] doesn't exist in Class [{}]!", + stringArray[0], modelClazz.getSimpleName()); + return null; + } + Class fieldClazz = field.getType(); + modelName = fieldClazz.getSimpleName(); + fieldName = stringArray[1]; + tableName = MyModelUtil.mapToTableName(fieldClazz); + columnName = MyModelUtil.mapToColumnName(fieldName, fieldClazz); + } + if (StringUtils.isBlank(tableName)) { + log.error("ModelName [{}] can't be mapped to Table!", modelName); + return null; + } + if (StringUtils.isBlank(columnName)) { + log.error("FieldName [{}] in Class [{}`] can't be mapped to Column!", fieldName, modelName); + return null; + } + if (StringUtils.isNotBlank(groupInfo.dateAggregateBy)) { + groupByBuilder.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + groupSelectBuilder.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + if ("day".equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-%m-%d')"); + groupSelectBuilder.append(", '%Y-%m-%d')"); + } else if ("month".equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-%m-01')"); + groupSelectBuilder.append(", '%Y-%m-01')"); + } else if ("year".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); + } + } + String aliasName = StringUtils.isBlank(groupInfo.aliasName) ? 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; + } + + @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; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyOrderParam.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyOrderParam.java new file mode 100644 index 00000000..f06bd230 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyOrderParam.java @@ -0,0 +1,247 @@ +package com.orange.admin.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Data +public class MyOrderParam extends ArrayList { + + /** + * 基于排序对象中的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; + } + String exceptionMessage; + if (modelClazz == null) { + throw new IllegalArgumentException("modelClazz Argument can't be NULL"); + } + int i = 0; + StringBuilder orderBy = new StringBuilder(128); + for (OrderInfo orderInfo : orderParam) { + String modelName, fieldName = orderInfo.fieldName, tableName, columnName; + int pos = fieldName.indexOf("DictMap."); + if (pos != -1) { + fieldName = fieldName.substring(0, pos); + } + String[] stringArray = StringUtils.split(fieldName, '.'); + if (stringArray.length == 1) { + modelName = modelClazz.getSimpleName(); + tableName = MyModelUtil.mapToTableName(modelClazz); + columnName = MyModelUtil.mapToColumnName(fieldName, modelClazz); + } else { + Field field = ReflectUtil.getField(modelClazz, stringArray[0]); + if (field == null) { + exceptionMessage = String.format( + "Relation Field [%s] doesn't exist in Class [%s]!", stringArray[0], modelClazz.getSimpleName()); + log.error(exceptionMessage); + throw new IllegalArgumentException(exceptionMessage); + } + Class fieldClazz = field.getType(); + modelName = fieldClazz.getSimpleName(); + fieldName = stringArray[1]; + tableName = MyModelUtil.mapToTableName(fieldClazz); + columnName = MyModelUtil.mapToColumnName(fieldName, fieldClazz); + } + if (StringUtils.isBlank(tableName)) { + exceptionMessage = String.format("ModelName [%s] can't be mapped to Table!", modelName); + log.error(exceptionMessage); + throw new IllegalArgumentException(exceptionMessage); + } + if (StringUtils.isBlank(columnName)) { + exceptionMessage = String.format( + "FieldName [%s] in Class [%s] can't be mapped to Column!", fieldName, modelName); + log.error(exceptionMessage); + throw new IllegalArgumentException(exceptionMessage); + } + if (StringUtils.isNotBlank(orderInfo.dateAggregateBy)) { + orderBy.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + if ("day".equals(orderInfo.dateAggregateBy)) { + orderBy.append(", '%Y-%m-%d')"); + } else if ("month".equals(orderInfo.dateAggregateBy)) { + orderBy.append(", '%Y-%m-01')"); + } else if ("year".equals(orderInfo.dateAggregateBy)) { + orderBy.append(", '%Y-01-01')"); + } else { + throw new IllegalArgumentException("Illegal DATE_FORMAT for GROUP ID list."); + } + } else { + orderBy.append(tableName).append(".").append(columnName); + } + if (orderInfo.asc != null && !orderInfo.asc) { + orderBy.append(" DESC"); + } + if (++i < orderParam.size()) { + orderBy.append(", "); + } + } + return orderBy.toString(); + } + + /** + * 在排序列表中,可能存在基于指定表字段的排序,该函数将获取指定表的所有排序字段。 + * 返回有的字符串,可直接用于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 can't be NULL"); + } + String exceptionMessage; + List fieldNameList = new LinkedList<>(); + String prefix = null; + if (StringUtils.isNotBlank(relationModelName)) { + prefix = relationModelName + "."; + } + for (OrderInfo orderInfo : orderParam) { + boolean found = false; + String modelName = null, fieldName = orderInfo.fieldName, tableName = null, columnName = null; + int pos = fieldName.indexOf("DictMap."); + if (pos != -1) { + fieldName = fieldName.substring(0, pos); + } + if (prefix != null) { + if (fieldName.startsWith(prefix)) { + Field field = ReflectUtil.getField(modelClazz, relationModelName); + if (field == null) { + exceptionMessage = String.format( + "Relation Field [%s] doesn't exist in Class [%s]!", relationModelName, modelClazz.getSimpleName()); + log.error(exceptionMessage); + throw new IllegalArgumentException(exceptionMessage); + } + Class fieldClazz = field.getType(); + modelName = fieldClazz.getSimpleName(); + fieldName = StringUtils.removeStart(fieldName, prefix); + tableName = MyModelUtil.mapToTableName(fieldClazz); + columnName = MyModelUtil.mapToColumnName(fieldName, fieldClazz); + found = true; + } + } else { + if (!fieldName.contains(".")) { + modelName = modelClazz.getSimpleName(); + tableName = MyModelUtil.mapToTableName(modelClazz); + columnName = MyModelUtil.mapToColumnName(fieldName, modelClazz); + found = true; + } + } + if (found) { + if (StringUtils.isBlank(tableName)) { + exceptionMessage = String.format("ModelName [%s] can't be mapped to Table!", modelName); + log.error(exceptionMessage); + throw new IllegalArgumentException(exceptionMessage); + } + if (StringUtils.isBlank(columnName)) { + exceptionMessage = String.format( + "FieldName [%s] in Class [%s] can't be mapped to Column!", fieldName, modelName); + log.error(exceptionMessage); + throw new IllegalArgumentException(exceptionMessage); + } + StringBuilder orderBy = new StringBuilder(128); + orderBy.append(tableName).append(".").append(columnName); + if (orderInfo.asc != null && !orderInfo.asc) { + orderBy.append(" DESC"); + } + fieldNameList.add(orderBy.toString()); + } + } + return StringUtils.join(fieldNameList, ", "); + } + + /** + * 在排序列表中,可能存在基于指定表字段的排序,该函数将删除指定表的所有排序字段。 + * + * @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 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 = orderInfo.fieldName; + int pos = fieldName.indexOf("DictMap."); + if (pos != -1) { + fieldName = fieldName.substring(0, pos); + } + 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; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyPageParam.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyPageParam.java new file mode 100644 index 00000000..f9e8a4cd --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyPageParam.java @@ -0,0 +1,57 @@ +package com.orange.admin.common.core.object; + +import lombok.Getter; + +/** + * Controller参数中的分页请求对象 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Getter +public class MyPageParam { + + public static final int DEFAULT_PAGE_NUM = 1; + public static final int DEFAULT_PAGE_SIZE = 10; + + /** + * 分页号码,从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 > 100) { + pageSize = DEFAULT_PAGE_SIZE; + } + this.pageSize = pageSize; + } + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyWhereCriteria.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyWhereCriteria.java new file mode 100644 index 00000000..4ab102cd --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/MyWhereCriteria.java @@ -0,0 +1,308 @@ +package com.orange.admin.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.alibaba.fastjson.annotation.JSONField; +import com.orange.admin.common.core.exception.InvalidDataFieldException; +import com.orange.admin.common.core.exception.InvalidDataModelException; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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 VerifyResult 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 VerifyResult 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 VerifyResult doVerify() { + if (fieldName == null) { + return VerifyResult.error("过滤字段名称 [fieldName] 不能为空!"); + } + if (modelClazz != null) { + if (ReflectUtil.getField(modelClazz, fieldName) == null) { + return VerifyResult.error( + "过滤字段 [" + fieldName + "] 在实体对象 [" + modelClazz.getSimpleName() + "] 中并不存在!"); + } + } + if (!checkOperatorType()) { + return VerifyResult.error("无效的操作符类型 [" + operatorType + "]!"); + } + // 其他操作符必须包含value值 + if (operatorType != OPERATOR_IS_NULL && operatorType != OPERATOR_NOT_NULL) { + if (value == null) { + String operatorString = this.getOperatorString(); + return VerifyResult.error("操作符 [" + operatorString + "] 的条件值不能为空!"); + } + } + if (this.operatorType == OPERATOR_IN) { + if (!(value instanceof Collection)) { + return VerifyResult.error("操作符 [IN] 的条件值必须为集合对象!"); + } + if (CollectionUtils.isEmpty((Collection) value)) { + return VerifyResult.error("操作符 [IN] 的条件值不能为空!"); + } + } + return VerifyResult.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 getCriteriaString() { + return getCriteriaString(this.modelClazz); + } + + /** + * 获取组装后的SQL Where从句,如 table_name.column_name = 'value'。 + * + * @param modelClazz 与查询数据表对应的实体对象的Class。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @exception InvalidDataModelException 参数modelClazz没有对应的table,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public String getCriteriaString(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()); + } + StringBuilder sb = new StringBuilder(64); + sb.append(tableName).append(".").append(fieldInfo.getFirst()).append(getOperatorString()); + if (operatorType == OPERATOR_IN) { + Collection filterValues = (Collection) value; + sb.append("("); + int i = 0; + for (Object filterValue : filterValues) { + if (fieldInfo.getSecond().equals(MyModelUtil.NUMERIC_FIELD_TYPE)) { + sb.append(filterValue); + } else { + sb.append("'").append(filterValue).append("'"); + } + if (i++ != filterValues.size() - 1) { + sb.append(", "); + } + } + sb.append(")"); + } else { + if (value != null) { + if (fieldInfo.getSecond().equals(MyModelUtil.NUMERIC_FIELD_TYPE)) { + sb.append(value); + } else { + sb.append("'").append(value).append("'"); + } + } + } + return sb.toString(); + } + + /** + * 获取组装后的SQL Where从句。如 table_name.column_name = 'value'。 + * + * @param criteriaList 条件列表,所有条件直接目前仅支持 AND 的关系。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public static String getCriteriaString(List criteriaList) { + return getCriteriaString(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 getCriteriaString(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.getCriteriaString(clazz); + sb.append(criteriaString); + } + return sb.length() == 0 ? null : sb.toString(); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/ResponseResult.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/ResponseResult.java new file mode 100644 index 00000000..5110f475 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/ResponseResult.java @@ -0,0 +1,158 @@ +package com.orange.admin.common.core.object; + +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import lombok.Data; + +/** + * 接口返回对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +public class 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) { + return errorCodeEnum == ErrorCodeEnum.NO_ERROR ? success() + : error(errorCodeEnum.name(), errorMessage != null ? errorMessage : errorCodeEnum.getErrorMessage()); + } + + /** + * 根据参数errorCodeEnum的枚举值,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和参数 errorMessage。 + * 如果返回的是成功对象,dataObject数据对象将被连同返回。 + * + * @param errorCodeEnum - 错误码枚举。 + * @param errorMessage - 如果该参数为null,错误信息取自errorCodeEnum参数内置的errorMessage,否则使用当前参数。 + * @param data - 返回的数据对象。 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(ErrorCodeEnum errorCodeEnum, String errorMessage, T data) { + return errorCodeEnum == ErrorCodeEnum.NO_ERROR ? success(data) : create(errorCodeEnum, 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 success(null); + } + + /** + * 创建带有返回数据的成功对象。 + * + * @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); + } + + /** + * 是否成功。 + * + * @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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/TokenData.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/TokenData.java new file mode 100644 index 00000000..ce20a4e0 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/TokenData.java @@ -0,0 +1,63 @@ +package com.orange.admin.common.core.object; + +import com.orange.admin.common.core.util.ContextUtil; +import lombok.Data; +import lombok.ToString; + +import javax.servlet.http.HttpServletRequest; + +/** + * 基于Jwt,用于前后端传递的令牌对象。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +@ToString +public class TokenData { + + /** + * 在HTTP Request对象中的属性键。 + */ + public static final String REQUEST_ATTRIBUTE_NAME = "tokenData"; + /** + * 用户Id。 + */ + private Long userId; + /** + * 用户所在部门Id。 + */ + private Long deptId; + /** + * 是否为超级管理员。 + */ + 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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/Tuple2.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/Tuple2.java new file mode 100644 index 00000000..18732226 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/Tuple2.java @@ -0,0 +1,50 @@ +package com.orange.admin.common.core.object; + +/** + * 二元组对象。主要用于可以一次返回多个结果的场景,同时还能避免强制转换。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/VerifyResult.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/VerifyResult.java new file mode 100644 index 00000000..384c140b --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/object/VerifyResult.java @@ -0,0 +1,84 @@ +package com.orange.admin.common.core.object; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +/** + * 接口数据验证结果对象。主要是Service类使用。 + * 同时为了提升效率,减少查询次数,可以根据具体的需求,将部分验证关联对象存入data字段,以供Controller使用。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@Data +public class VerifyResult { + + /** + * 是否成功标记。 + */ + private boolean success = true; + /** + * 错误信息描述。 + */ + private String errorMessage = null; + /** + * 在验证同时,仍然需要附加的关联数据对象。 + */ + private JSONObject data; + + /** + * 创建验证结果对象。 + * + * @param errorMessage 错误描述信息。 + * @return 如果参数为空,表示成功,否则返回代码错误信息的错误对象实例。 + */ + public static VerifyResult create(String errorMessage) { + return errorMessage == null ? ok() : error(errorMessage); + } + + /** + * 创建验证结果对象。 + * + * @param errorMessage 错误描述信息。 + * @param data 附带的数据对象。 + * @return 如果参数为空,表示成功,否则返回代码错误信息的错误对象实例。 + */ + public static VerifyResult create(String errorMessage, JSONObject data) { + return errorMessage == null ? ok(data) : error(errorMessage); + } + + /** + * 创建表示验证成功的对象实例。 + * + * @return 验证成功对象实例。 + */ + public static VerifyResult ok() { + return new VerifyResult(); + } + + /** + * 创建表示验证成功的对象实例。 + * + * @param data 附带的数据对象。 + * @return 验证成功对象实例。 + */ + public static VerifyResult ok(JSONObject data) { + VerifyResult result = new VerifyResult(); + result.data = data; + return result; + } + + /** + * 创建表示验证失败的对象实例。 + * + * @param errorMessage 错误描述。 + * @return 验证失败对象实例。 + */ + public static VerifyResult error(String errorMessage) { + VerifyResult verifyResult = new VerifyResult(); + verifyResult.success = false; + verifyResult.errorMessage = errorMessage; + return verifyResult; + } + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ApplicationContextHolder.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ApplicationContextHolder.java new file mode 100644 index 00000000..372ef569 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ApplicationContextHolder.java @@ -0,0 +1,72 @@ +package com.orange.admin.common.core.util; + +import org.springframework.beans.BeansException; +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 Stephen.Liu + * @date 2020-04-11 + */ +@Component +public class ApplicationContextHolder implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + /** + * Spring 启动的过程中会自动调用,并将应用上下文对象赋值进来。 + * + * @param applicationContext 应用上下文对象,可通过该对象查找Spring中已经加载的Bean。 + * @throws BeansException Bean处理相关的异常。 + */ + @Override + public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { + ApplicationContextHolder.applicationContext = 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 RuntimeException("applicaitonContext属性为null,请检查是否注入了ApplicationContextHolder!"); + } + } + +} \ No newline at end of file diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ContextUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ContextUtil.java new file mode 100644 index 00000000..e948a14e --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ContextUtil.java @@ -0,0 +1,44 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +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(); + } + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ExportUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ExportUtil.java new file mode 100644 index 00000000..15d521c0 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ExportUtil.java @@ -0,0 +1,85 @@ +package com.orange.admin.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 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 Stephen.Liu + * @date 2020-04-11 + */ +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 ("xlsx".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 ("csv".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) { + e.printStackTrace(); + } + } else { + throw new RuntimeException("不支持的导出文件类型!"); + } + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ImportUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ImportUtil.java new file mode 100644 index 00000000..d9a644c9 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/ImportUtil.java @@ -0,0 +1,205 @@ +package com.orange.admin.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 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 Stephen.Liu + * @date 2020-04-11 + */ +public class ImportUtil { + + /** + * 同步导入方式。 + * + * @param filename 导入文件名。 + * @return 导入数据列表。 + */ + public static List> doImport(String filename) { + if ("xlsx".equals(FilenameUtils.getExtension(filename))) { + try (ExcelReader reader = ExcelUtil.getReader(filename)) { + return reader.readAll(); + } + } else if ("csv".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) { + e.printStackTrace(); + } + return resultList; + } + throw new RuntimeException("不支持的导入文件类型!"); + } + + /** + * 异步导入方式,即SAX导入方式。 + * + * @param filename 导入文件名。 + * @param importer 异步导入处理接口。 + * @throws IOException 文件处理异常。 + */ + public static void doImport(String filename, BaseImporter importer) throws IOException { + if ("xlsx".equals(FilenameUtils.getExtension(filename))) { + Excel07SaxReader reader = new MyExcel07SaxReader<>(importer); + try (InputStream in = new FileInputStream(filename)) { + reader.read(in, 0); + } + } else if ("csv".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)); + if (importer.doInterrupt()) { + break; + } + } while (true); + } catch (Exception e) { + e.printStackTrace(); + } + } + throw new RuntimeException("不支持的导入文件类型!"); + } + + /** + * 异步导入抽象类。 + * + * @param 导入数据对象类型。 + */ + public static abstract 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) { + e.printStackTrace(); + } + 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 RuntimeException(); + } + } + + @Override + public void endDocument() { + importer.doImport(-1, null); + } + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/IpUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/IpUtil.java new file mode 100644 index 00000000..e5032a90 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/IpUtil.java @@ -0,0 +1,98 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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(); + if (address.isLoopbackAddress()) { + // skip the loopback addr + continue; + } + if (address instanceof Inet6Address) { + // skip the IPv6 addr + continue; + } + String hostAddress = address.getHostAddress(); + ipList.add(hostAddress); + } + } + return ipList; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/JwtUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/JwtUtil.java new file mode 100644 index 00000000..2b47d2a9 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/JwtUtil.java @@ -0,0 +1,103 @@ +package com.orange.admin.common.core.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +import java.util.Date; +import java.util.Map; + +/** + * 基于JWT的Token生成工具类 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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) { + System.out.println("Token Expired"); + } + 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; + } + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyCommonUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyCommonUtil.java new file mode 100644 index 00000000..98f6b7e4 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyCommonUtil.java @@ -0,0 +1,137 @@ +package com.orange.admin.common.core.util; + +import org.apache.commons.codec.digest.DigestUtils; +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 Stephen.Liu + * @date 2020-04-11 + */ +public class MyCommonUtil { + + private static Validator validator; + + static { + validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + + /** + * 创建uuid。 + * + * @return 返回uuid。 + */ + public static String generateUuid() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + /** + * 对用户密码进行加盐后加密。 + * + * @param password 明文密码。 + * @return 加密后的密码。 + */ + public static String encrptedPassword(String password, String passwordSalt) { + return DigestUtils.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 deptId : dataList) { + sb.append("'").append(deptId).append("'"); + if (index++ != dataList.size() - 1) { + sb.append(separator); + } + } + return sb.toString(); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyDateUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyDateUtil.java new file mode 100644 index 00000000..e2be2429 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyDateUtil.java @@ -0,0 +1,175 @@ +package com.orange.admin.common.core.util; + +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +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"; + /** + * 缺省日期格式化器,提前获取提升运行时效率。 + */ + 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); + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyModelUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyModelUtil.java new file mode 100644 index 00000000..774285ef --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyModelUtil.java @@ -0,0 +1,409 @@ +package com.orange.admin.common.core.util; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ReflectUtil; +import com.orange.admin.common.core.annotation.RelationDict; +import com.orange.admin.common.core.annotation.RelationOneToOne; +import com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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".equals(typeName)) { + type = STRING_FIELD_TYPE; + } else if ("Date".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(); + } + + /** + * 在当前Service的主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); + } + + /** + * 在当前Service的主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); + } + } + }); + } + + /** + * 在当前Service的主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 slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + 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); + } + } + }); + } + + /** + * 在当前Service的主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); + if (orderByThatList) { + List newThisModelList = new LinkedList<>(); + Map thisModelMap = + thisModelList.stream().collect(Collectors.toMap(thisIdGetterFunc, c -> c)); + if (thisTargetField.getType().equals(Map.class)) { + thatModelList.forEach(thatModel -> { + Object thatId = thatIdGetterFunc.apply(thatModel); + T thisModel = thisModelMap.get(thatId); + if (thisModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, BeanUtil.beanToMap(thatModel)); + newThisModelList.add(thisModel); + } + }); + } else { + thatModelList.forEach(thatModel -> { + Object thatId = thatIdGetterFunc.apply(thatModel); + T thisModel = thisModelMap.get(thatId); + if (thisModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, thatModel); + newThisModelList.add(thisModel); + } + }); + } + thisModelList = newThisModelList; + } else { + Map thatMadelMap = + thatModelList.stream().collect(Collectors.toMap(thatIdGetterFunc, c -> c)); + if (thisTargetField.getType().equals(Map.class)) { + thisModelList.forEach(thisModel -> { + Object thisId = thisIdGetterFunc.apply(thisModel); + R thatModel = thatMadelMap.get(thisId); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, BeanUtil.beanToMap(thatModel)); + } + }); + } else { + thisModelList.forEach(thisModel -> { + Object thisId = thisIdGetterFunc.apply(thisModel); + R thatModel = thatMadelMap.get(thisId); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, thatModel); + } + }); + } + } + } + + /** + * 转换过滤对象到与其等效的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) { + field.setAccessible(true); + 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 RuntimeException(ex); + } + } + } + return e; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyPageUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyPageUtil.java new file mode 100644 index 00000000..f2aa11fe --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/MyPageUtil.java @@ -0,0 +1,64 @@ +package com.orange.admin.common.core.util; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.Page; + +import java.util.List; + +/** + * 生成带有分页信息的数据列表 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public class MyPageUtil { + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageHelper.startPage之后,立即执行mybatis查询操作的结果集。 + * @param includeFields 结果集中需要返回到前端的字段,多个字段之间逗号分隔。 + * @return 返回只是包含includeFields字段的数据列表,以及结果集TotalCount。 + */ + public static JSONObject makeResponseData(List dataList, String includeFields) { + JSONObject pageData = new JSONObject(); + pageData.put("dataList", BeanQuery.select(includeFields).from(dataList).execute()); + if (dataList instanceof Page) { + pageData.put("totalCount", ((Page)dataList).getTotal()); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageHelper.startPage之后,立即执行mybatis查询操作的结果集。 + * @return 返回结果集和TotalCount。 + */ + public static JSONObject makeResponseData(List dataList) { + JSONObject pageData = new JSONObject(); + pageData.put("dataList", dataList); + if (dataList instanceof Page) { + pageData.put("totalCount", ((Page)dataList).getTotal()); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageHelper.startPage之后,立即执行mybatis查询操作的结果集。 + * @param totalCount 总数量。 + * @return 返回结果集和TotalCount。 + */ + public static JSONObject makeResponseData(List dataList, Long totalCount) { + JSONObject pageData = new JSONObject(); + pageData.put("dataList", dataList); + if (totalCount != null) { + pageData.put("totalCount", totalCount); + } + return pageData; + } + +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/TreeNode.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/TreeNode.java new file mode 100644 index 00000000..9b4ae87c --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/TreeNode.java @@ -0,0 +1,94 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/UpDownloadUtil.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/UpDownloadUtil.java new file mode 100644 index 00000000..3567ab8b --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/util/UpDownloadUtil.java @@ -0,0 +1,167 @@ +package com.orange.admin.common.core.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.orange.admin.common.core.constant.ApplicationConstant; +import com.orange.admin.common.core.constant.ErrorCodeEnum; +import com.orange.admin.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; + +/** + * 上传或下载附件文件的工具类。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +@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); + if (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) { + e.printStackTrace(); + } + } + + /** + * 执行文件上传操作,并将与该文件下载对应的Url直接写入到HttpServletResponse应答对象,返回给前端。 + * + * @param rootBaseDir 存放上传文件的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param uploadFile Http请求中上传的文件对象。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @param response Http 应答对象。 + * @throws IOException 文件操作错误。 + */ + public static void 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"); + StringBuilder uploadPathBuilder = new StringBuilder(128); + uploadPathBuilder.append(rootBaseDir); + if (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(JSONObject.toJSONString(ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FILE_IOERROR))); + return; + } + out.print(JSONObject.toJSONString(ResponseResult.success(fileInfo))); + out.flush(); + out.close(); + } + + /** + * 判断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 = JSONArray.parseArray(fileInfoJson, UploadFileInfo.class); + if (CollectionUtils.isNotEmpty(fileInfoList)) { + for (UploadFileInfo fileInfo : fileInfoList) { + if (StringUtils.equals(filename, fileInfo.filename)) { + return true; + } + } + } + return false; + } + + @Data + static class UploadFileInfo { + private String downloadUri; + private String filename; + } +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/AddGroup.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/AddGroup.java new file mode 100644 index 00000000..338fab64 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/AddGroup.java @@ -0,0 +1,10 @@ +package com.orange.admin.common.core.validator; + +/** + * 数据增加的验证分组。通常用于数据新增场景。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface AddGroup { +} diff --git a/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/ConstDictRef.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/ConstDictRef.java new file mode 100644 index 00000000..0e5ffec1 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/ConstDictRef.java @@ -0,0 +1,48 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/ConstDictValidator.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/ConstDictValidator.java new file mode 100644 index 00000000..91911036 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/ConstDictValidator.java @@ -0,0 +1,33 @@ +package com.orange.admin.common.core.validator; + +import cn.hutool.core.util.ReflectUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.lang.reflect.Method; + +/** + * 数据字段自定义验证,用于验证Model中字符串字段的最大长度和最小长度。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/TextLength.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/TextLength.java new file mode 100644 index 00000000..422068a9 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/TextLength.java @@ -0,0 +1,55 @@ +package com.orange.admin.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 Stephen.Liu + * @date 2020-04-11 + */ +@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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/TextLengthValidator.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/TextLengthValidator.java new file mode 100644 index 00000000..fece6df2 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/TextLengthValidator.java @@ -0,0 +1,39 @@ +package com.orange.admin.common.core.validator; + +import org.apache.commons.lang3.CharUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * 数据字段自定义验证,用于验证Model中UTF-8编码的字符串字段的最大长度和最小长度。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +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-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/UpdateGroup.java b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/UpdateGroup.java new file mode 100644 index 00000000..ed407c63 --- /dev/null +++ b/orange-admin-service/common/common-core/src/main/java/com/orange/admin/common/core/validator/UpdateGroup.java @@ -0,0 +1,11 @@ +package com.orange.admin.common.core.validator; + +/** + * 数据修改的验证分组。通常用于数据更新的场景。 + * + * @author Stephen.Liu + * @date 2020-04-11 + */ +public interface UpdateGroup { + +} diff --git a/orange-admin-service/common/pom.xml b/orange-admin-service/common/pom.xml new file mode 100644 index 00000000..5f9d4773 --- /dev/null +++ b/orange-admin-service/common/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + + + com.orange.admin + OrangeAdmin + 1.0.0 + + + common + pom + + + common-core + common-biz + + diff --git a/orange-admin-service/pom.xml b/orange-admin-service/pom.xml new file mode 100644 index 00000000..686a7527 --- /dev/null +++ b/orange-admin-service/pom.xml @@ -0,0 +1,143 @@ + + + 4.0.0 + + com.orange.admin + OrangeAdmin + 1.0.0 + OrangeAdmin + pom + + + 2.2.5.RELEASE + Cairo-SR8 + 2.2.2 + UTF-8 + 1.8 + 1.8 + 1.8 + OrangeAdmin + + + 4.4 + 1.8 + 4.1.2 + 5.1.5 + 0.9.1 + 1.2.66 + 1.1.5 + 2.8.1 + 1.3.1.Final + + + 1.1.21 + 2.1.5 + 1.4.0 + 1.2.13 + + + + common + application + + + + + + 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.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-admin-service/upms-script.sql b/orange-admin-service/upms-script.sql new file mode 100644 index 00000000..685bb259 --- /dev/null +++ b/orange-admin-service/upms-script.sql @@ -0,0 +1,661 @@ + +-- ---------------------------- +-- 请仅在下面的数据库链接中执行该脚本。 +-- 主数据源 [101.200.178.51:3306/zzdemo-single] +-- ---------------------------- + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- 部门管理表 +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_dept`; +CREATE TABLE `zz_sys_dept` ( + `dept_id` bigint(20) NOT NULL COMMENT '部门Id', + `dept_name` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '部门名称', + `show_order` int(11) 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(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`dept_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='部门管理表'; + +-- ---------------------------- +-- 系统用户表 +-- ---------------------------- +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 '用户显示名称', + `dept_id` bigint(20) NOT NULL COMMENT '用户所在部门Id', + `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_dept_id` (`dept_id`) USING BTREE, + KEY `idx_status` (`user_status`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统用户表'; + +-- ---------------------------- +-- 系统角色表 +-- ---------------------------- +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='系统角色表'; + +-- ---------------------------- +-- 用户与角色对应关系表 +-- ---------------------------- +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='用户与角色对应关系表'; + +-- ---------------------------- +-- 菜单和操作权限管理表 +-- ---------------------------- +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='菜单和操作权限管理表'; + +-- ---------------------------- +-- 角色与菜单对应关系表 +-- ---------------------------- +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='角色与菜单对应关系表'; + +-- ---------------------------- +-- 系统权限资源表 +-- ---------------------------- +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) COLLATE utf8_bin NOT NULL COMMENT '权限字标识(一般为有含义的英文字符串)', + `perm_code_type` int(11) NOT NULL COMMENT '类型(0: 表单 1: UI片段 2: 操作)', + `show_name` varchar(128) 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='系统权限资源表'; + +-- ---------------------------- +-- 菜单和权限关系表 +-- ---------------------------- +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='菜单和权限关系表'; + +-- ---------------------------- +-- 系统权限模块表 +-- ---------------------------- +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='系统权限模块表'; + +-- ---------------------------- +-- 系统权限表 +-- ---------------------------- +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='系统权限表'; + +-- ---------------------------- +-- 系统权限字和权限资源关联表 +-- ---------------------------- +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='系统权限字和权限资源关联表'; + +-- ---------------------------- +-- 权限资源白名单表 +-- ---------------------------- +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资源)'; + +-- ---------------------------- +-- 数据权限表 +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm`; +CREATE TABLE `zz_sys_data_perm` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '主键', + `data_perm_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '显示名称', + `rule_type` tinyint(2) NOT NULL COMMENT '数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。', + `dept_id_list_string` varchar(4096) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '部门Id列表(逗号分隔)', + `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 (`data_perm_id`) USING BTREE, + KEY `idx_create_time` (`create_time`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限表'; + +-- ---------------------------- +-- 数据权限和菜单关联表 +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm_menu`; +CREATE TABLE `zz_sys_data_perm_menu` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '数据权限Id', + `menu_id` bigint(20) NOT NULL COMMENT '关联菜单Id', + PRIMARY KEY (`data_perm_id`,`menu_id`), + KEY `idx_menu_id` (`menu_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限和部门菜单表'; + +-- ---------------------------- +-- 数据权限和用户关联表 +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm_user`; +CREATE TABLE `zz_sys_data_perm_user` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '数据权限Id', + `user_id` bigint(20) NOT NULL COMMENT '用户Id', + PRIMARY KEY (`data_perm_id`,`user_id`), + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限和用户关联表'; + +-- ---------------------------- +-- 数据权限和部门关联表 +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm_dept`; +CREATE TABLE `zz_sys_data_perm_dept` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '数据权限Id', + `dept_id` bigint(20) NOT NULL COMMENT '部门Id', + PRIMARY KEY (`data_perm_id`,`dept_id`), + KEY `idx_dept_id` (`dept_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限和部门关联表'; + +-- ---------------------------- +-- 管理员账号数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_dept` VALUES(1248875520100143104,'公司总部',1,1248875520100143105,'管理员',CURDATE(),CURDATE(),1); +INSERT INTO `zz_sys_user` VALUES(1248875520100143105,'admin','991a762615d6c112c5bb02c9b78a4417','管理员',1248875520100143104,0,'CHANGE TO YOUR HEAD IMAGE URL!!!',0,1248875520100143105,'管理员',CURDATE(),CURDATE(),1); +COMMIT; + +-- ---------------------------- +-- 全部菜单数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_menu` VALUES(1248448487335399424,NULL,'系统管理',0,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394368,1248448487335399424,'用户管理',1,'formSysUser',100,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754512,1248448487486394368,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754513,1248448487486394368,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754514,1248448487486394368,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754515,1248448487486394368,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754516,1248448487486394368,'重置密码',3,NULL,5,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394369,1248448487335399424,'部门管理',1,'formSysDept',105,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754524,1248448487486394369,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754525,1248448487486394369,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754526,1248448487486394369,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754527,1248448487486394369,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394370,1248448487335399424,'角色管理',1,'formSysRole',110,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754534,1248448487486394370,'角色管理',2,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754535,1248448487486394370,'用户授权',2,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754536,1248875520091754534,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754537,1248875520091754534,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754538,1248875520091754534,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754539,1248875520091754534,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754540,1248875520091754535,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754541,1248875520091754535,'授权用户',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754542,1248875520091754535,'移除用户',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394371,1248448487335399424,'数据权限管理',1,'formSysDataPerm',115,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754552,1248448487486394371,'数据权限管理',2,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754553,1248448487486394371,'用户授权',2,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754554,1248875520091754552,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754555,1248875520091754552,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754556,1248875520091754552,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754557,1248875520091754552,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754558,1248875520091754553,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754559,1248875520091754553,'授权用户',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754560,1248875520091754553,'移除用户',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394372,1248448487335399424,'菜单管理',1,'formSysMenu',120,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754570,1248448487486394372,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754571,1248448487486394372,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754572,1248448487486394372,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754573,1248448487486394372,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520091754574,1248448487486394372,'权限列表',3,NULL,5,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394373,1248448487335399424,'权限字管理',1,'formSysPermCode',125,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948801,1248448487486394373,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948802,1248448487486394373,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948803,1248448487486394373,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948804,1248448487486394373,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394374,1248448487335399424,'权限管理',1,'formSysPerm',130,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948811,1248448487486394374,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948812,1248448487486394374,'新增模块',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948813,1248448487486394374,'编辑模块',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948814,1248448487486394374,'删除模块',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948815,1248448487486394374,'新增权限',3,NULL,5,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948816,1248448487486394374,'编辑权限',3,NULL,6,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948817,1248448487486394374,'删除权限',3,NULL,7,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248448487486394375,1248448487335399424,'字典管理',1,'formSysDict',135,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948827,1248448487486394375,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948828,1248448487486394375,'新增',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948829,1248448487486394375,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948830,1248448487486394375,'删除',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948831,1248448487486394375,'同步缓存',3,NULL,5,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248512948561776640,NULL,'业务管理',0,NULL,5,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248512995818999808,1248512948561776640,'老师管理',1,'formTeacher',1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948840,1248512995818999808,'显示',3,NULL,1,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948841,1248512995818999808,'新建',3,NULL,2,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948842,1248512995818999808,'编辑',3,NULL,3,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948843,1248512995818999808,'统计',3,NULL,4,NULL,CURDATE(),1); +INSERT INTO `zz_sys_menu` VALUES(1248875520095948844,1248512995818999808,'删除',3,NULL,5,NULL,CURDATE(),1); +COMMIT; + +-- ---------------------------- +-- 全部权限字数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_code` VALUES(1248875520087560192,NULL,'formTeacher',0,'老师管理',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520087560193,1248875520087560192,'formTeacher:formTeacher',1,'老师管理',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754496,1248875520087560193,'formTeacher:formTeacher:formCreateTeacher',2,'新建',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754497,1248875520087560193,'formTeacher:formTeacher:formEditTeacher',2,'编辑',10,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754498,1248875520087560193,'formTeacher:formTeacher:formTeacherTransStats',2,'统计',20,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754499,1248875520087560193,'formTeacher:formTeacher:delete',2,'删除',30,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754500,NULL,'formCreateTeacher',0,'新建老师',10,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754501,1248875520091754500,'formCreateTeacher:formCreateTeacher',1,'新建老师',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754502,1248875520091754501,'formCreateTeacher:formCreateTeacher:cancel',2,'取消',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754503,1248875520091754501,'formCreateTeacher:formCreateTeacher:add',2,'保存',10,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754504,NULL,'formEditTeacher',0,'编辑老师',20,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754505,1248875520091754504,'formEditTeacher:formEditTeacher',1,'编辑老师',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754506,1248875520091754505,'formEditTeacher:formEditTeacher:cancel',2,'取消',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754507,1248875520091754505,'formEditTeacher:formEditTeacher:update',2,'保存',10,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754508,NULL,'formTeacherTransStats',0,'老师个人统计',30,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754509,1248875520091754508,'formTeacherTransStats:formTeacherTransStats',1,'老师个人统计',0,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754517,NULL,'formSysUser',0,'用户管理',10000,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754518,1248875520091754517,'formSysUser:fragmentSysUser',1,'用户管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754519,1248875520091754518,'formSysUser:fragmentSysUser:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754520,1248875520091754518,'formSysUser:fragmentSysUser:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754521,1248875520091754518,'formSysUser:fragmentSysUser:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754522,1248875520091754518,'formSysUser:fragmentSysUser:resetPassword',2,'重置密码',4,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754528,NULL,'formSysDept',0,'部门管理',10100,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754529,1248875520091754528,'formSysDept:fragmentSysDept',1,'部门管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754530,1248875520091754529,'formSysDept:fragmentSysDept:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754531,1248875520091754529,'formSysDept:fragmentSysDept:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754532,1248875520091754529,'formSysDept:fragmentSysDept:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754543,NULL,'formSysRole',0,'角色管理',10200,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754544,1248875520091754543,'formSysRole:fragmentSysRole',1,'角色管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754545,1248875520091754543,'formSysRole:fragmentSysRoleUser',1,'用户授权',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754546,1248875520091754544,'formSysRole:fragmentSysRole:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754547,1248875520091754544,'formSysRole:fragmentSysRole:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754548,1248875520091754544,'formSysRole:fragmentSysRole:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754549,1248875520091754545,'formSysRole:fragmentSysRoleUser:addUserRole',2,'授权用户',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754550,1248875520091754545,'formSysRole:fragmentSysRoleUser:deleteUserRole',2,'移除用户',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754561,NULL,'formSysDataPerm',0,'数据权限管理',10400,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754562,1248875520091754561,'formSysDataPerm:fragmentSysDataPerm',1,'数据权限管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754563,1248875520091754561,'formSysDataPerm:fragmentSysDataPermUser',1,'用户授权',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754564,1248875520091754562,'formSysDataPerm:fragmentSysDataPerm:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754565,1248875520091754562,'formSysDataPerm:fragmentSysDataPerm:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754566,1248875520091754562,'formSysDataPerm:fragmentSysDataPerm:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754567,1248875520091754563,'formSysDataPerm:fragmentSysDataPermUser:addDataPermUser',2,'授权用户',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754568,1248875520091754563,'formSysDataPerm:fragmentSysDataPermUser:deleteDataPermUser',2,'移除用户',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754575,NULL,'formSysMenu',0,'菜单管理',10600,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754576,1248875520091754575,'formSysMenu:fragmentSysMenu',1,'菜单管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754577,1248875520091754576,'formSysMenu:fragmentSysMenu:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754578,1248875520091754576,'formSysMenu:fragmentSysMenu:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754579,1248875520091754576,'formSysMenu:fragmentSysMenu:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520091754580,1248875520091754576,'formSysMenu:fragmentSysMenu:listMenuPerm',2,'权限列表',4,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948805,NULL,'formSysPermCode',0,'权限字管理',10700,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948806,1248875520095948805,'formSysPermCode:fragmentSysPermCode',1,'权限字管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948807,1248875520095948806,'formSysPermCode:fragmentSysPermCode:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948808,1248875520095948806,'formSysPermCode:fragmentSysPermCode:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948809,1248875520095948806,'formSysPermCode:fragmentSysPermCode:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948818,NULL,'formSysPerm',0,'权限管理',10800,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948819,1248875520095948818,'formSysPerm:fragmentSysPerm',1,'权限管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948820,1248875520095948819,'formSysPerm:fragmentSysPerm:addPermModule',2,'新增模块',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948821,1248875520095948819,'formSysPerm:fragmentSysPerm:updatePermModule',2,'编辑模块',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948822,1248875520095948819,'formSysPerm:fragmentSysPerm:deletePermModule',2,'删除模块',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948823,1248875520095948819,'formSysPerm:fragmentSysPerm:addPerm',2,'新增权限',4,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948824,1248875520095948819,'formSysPerm:fragmentSysPerm:updatePerm',2,'编辑权限',5,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948825,1248875520095948819,'formSysPerm:fragmentSysPerm:deletePerm',2,'删除权限',6,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948832,NULL,'formSysDict',0,'字典管理',10900,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948833,1248875520095948832,'formSysDict:fragmentSysDict',1,'字典管理',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948834,1248875520095948833,'formSysDict:fragmentSysDict:add',2,'新增',1,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948835,1248875520095948833,'formSysDict:fragmentSysDict:update',2,'编辑',2,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948836,1248875520095948833,'formSysDict:fragmentSysDict:delete',2,'删除',3,CURDATE(),1); +INSERT INTO `zz_sys_perm_code` VALUES(1248875520095948837,1248875520095948833,'formSysDict:fragmentSysDict:reloadCache',2,'同步缓存',4,CURDATE(),1); +COMMIT; + +-- ---------------------------- +-- 全部菜单和权限字关系数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754512,1248875520091754518); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754513,1248875520091754519); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754514,1248875520091754520); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754515,1248875520091754521); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754516,1248875520091754522); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754524,1248875520091754529); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754525,1248875520091754530); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754526,1248875520091754531); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754527,1248875520091754532); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754536,1248875520091754544); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754540,1248875520091754545); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754537,1248875520091754546); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754538,1248875520091754547); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754539,1248875520091754548); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754541,1248875520091754549); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754542,1248875520091754550); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754554,1248875520091754562); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754558,1248875520091754563); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754555,1248875520091754564); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754556,1248875520091754565); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754557,1248875520091754566); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754559,1248875520091754567); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754560,1248875520091754568); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754570,1248875520091754576); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754571,1248875520091754577); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754572,1248875520091754578); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754573,1248875520091754579); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520091754574,1248875520091754580); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948801,1248875520095948806); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948802,1248875520095948807); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948803,1248875520095948808); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948804,1248875520095948809); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948811,1248875520095948819); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948812,1248875520095948820); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948813,1248875520095948821); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948814,1248875520095948822); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948815,1248875520095948823); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948816,1248875520095948824); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948817,1248875520095948825); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248448487486394375,1248875520095948833); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248448487486394375,1248875520095948834); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248448487486394375,1248875520095948835); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248448487486394375,1248875520095948836); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248448487486394375,1248875520095948837); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948827,1248875520095948833); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948828,1248875520095948834); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948829,1248875520095948835); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948830,1248875520095948836); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948831,1248875520095948837); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948840,1248875520087560193); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948841,1248875520091754496); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948841,1248875520091754500); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948841,1248875520091754501); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948841,1248875520091754502); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948841,1248875520091754503); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948842,1248875520091754497); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948842,1248875520091754504); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948842,1248875520091754505); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948842,1248875520091754506); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948842,1248875520091754507); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948843,1248875520091754498); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948843,1248875520091754508); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948843,1248875520091754509); +INSERT INTO `zz_sys_menu_perm_code` VALUES(1248875520095948844,1248875520091754499); +COMMIT; + +-- ---------------------------- +-- 全部权限资源模块数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_module` VALUES(1248448487645777921,NULL,'缺省分组',0,3,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248448487645777920,NULL,'系统配置',0,2,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248448487087935491,NULL,'用户权限',0,1,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520028839936,1248448487645777921,'部门管理',1,0,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034247,1248448487645777921,'用户管理',1,5,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034256,1248448487645777921,'老师数据源',1,10,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034264,1248448487645777921,'老师流水统计',1,15,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034270,1248448487087935491,'角色管理',1,10,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034280,1248448487087935491,'数据权限管理',1,15,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034290,1248448487087935491,'菜单管理',1,20,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034297,1248448487087935491,'权限字管理',1,25,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034303,1248448487087935491,'权限模块管理',1,30,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034309,1248448487087935491,'权限资源管理',1,35,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034315,1248448487645777920,'字典管理',0,1,CURDATE(),1); +INSERT INTO `zz_sys_perm_module` VALUES(1248875520033034316,1248875520033034315,'行政区划',1,1,CURDATE(),1); +COMMIT; + +-- ---------------------------- +-- 全部权限资源数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm` VALUES(1248875520033034240,1248875520028839936,'新增','/admin/upms/sysDept/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034241,1248875520028839936,'编辑','/admin/upms/sysDept/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034242,1248875520028839936,'删除','/admin/upms/sysDept/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034243,1248875520028839936,'显示列表','/admin/upms/sysDept/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034244,1248875520028839936,'导出','/admin/upms/sysDept/export',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034245,1248875520028839936,'详情','/admin/upms/sysDept/view',6,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034246,1248875520028839936,'打印','/admin/upms/sysDept/print',7,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034248,1248875520033034247,'新增','/admin/upms/sysUser/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034249,1248875520033034247,'编辑','/admin/upms/sysUser/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034250,1248875520033034247,'删除','/admin/upms/sysUser/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034251,1248875520033034247,'显示列表','/admin/upms/sysUser/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034252,1248875520033034247,'导出','/admin/upms/sysUser/export',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034253,1248875520033034247,'详情','/admin/upms/sysUser/view',6,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034254,1248875520033034247,'打印','/admin/upms/sysUser/print',7,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034255,1248875520033034247,'重置密码','/admin/upms/sysUser/resetPassword',8,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034257,1248875520033034256,'新增','/admin/app/teacher/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034258,1248875520033034256,'编辑','/admin/app/teacher/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034259,1248875520033034256,'删除','/admin/app/teacher/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034260,1248875520033034256,'显示列表','/admin/app/teacher/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034261,1248875520033034256,'导出','/admin/app/teacher/export',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034262,1248875520033034256,'详情','/admin/app/teacher/view',6,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034263,1248875520033034256,'打印','/admin/app/teacher/print',7,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034265,1248875520033034264,'分组列表','/admin/app/teacherTransStats/listWithGroup',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034266,1248875520033034264,'显示列表','/admin/app/teacherTransStats/list',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034267,1248875520033034264,'导出','/admin/app/teacherTransStats/export',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034268,1248875520033034264,'详情','/admin/app/teacherTransStats/view',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034269,1248875520033034264,'打印','/admin/app/teacherTransStats/print',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034271,1248875520033034270,'新增','/admin/upms/sysRole/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034272,1248875520033034270,'编辑','/admin/upms/sysRole/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034273,1248875520033034270,'删除','/admin/upms/sysRole/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034274,1248875520033034270,'显示列表','/admin/upms/sysRole/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034275,1248875520033034270,'详情','/admin/upms/sysRole/view',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034276,1248875520033034270,'授权用户','/admin/upms/sysRole/addUserRole',6,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034277,1248875520033034270,'移除用户','/admin/upms/sysRole/deleteUserRole',7,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034278,1248875520033034270,'角色用户列表','/admin/upms/sysRole/listUserRole',8,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034279,1248875520033034270,'角色未添加用户列表','/admin/upms/sysRole/listNotInUserRole',9,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034281,1248875520033034280,'新增','/admin/upms/sysDataPerm/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034282,1248875520033034280,'编辑','/admin/upms/sysDataPerm/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034283,1248875520033034280,'删除','/admin/upms/sysDataPerm/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034284,1248875520033034280,'显示列表','/admin/upms/sysDataPerm/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034285,1248875520033034280,'详情','/admin/upms/sysDataPerm/view',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034286,1248875520033034280,'授权用户','/admin/upms/sysDataPerm/addDataPermUser',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034287,1248875520033034280,'移除用户','/admin/upms/sysDataPerm/deleteDataPermUser',6,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034288,1248875520033034280,'数据权限用户列表','/admin/upms/sysDataPerm/listDataPermUser',7,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034289,1248875520033034280,'数据权限未添加用户列表','/admin/upms/sysDataPerm/listNotInDataPermUser',8,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034291,1248875520033034290,'新增','/admin/upms/sysMenu/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034292,1248875520033034290,'编辑','/admin/upms/sysMenu/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034293,1248875520033034290,'删除','/admin/upms/sysMenu/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034294,1248875520033034290,'显示列表','/admin/upms/sysMenu/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034295,1248875520033034290,'详情','/admin/upms/sysMenu/view',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034296,1248875520033034290,'权限资源列表','/admin/upms/sysMenu/listMenuPerm',6,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034298,1248875520033034297,'新增','/admin/upms/sysPermCode/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034299,1248875520033034297,'编辑','/admin/upms/sysPermCode/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034300,1248875520033034297,'删除','/admin/upms/sysPermCode/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034301,1248875520033034297,'显示列表','/admin/upms/sysPermCode/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034302,1248875520033034297,'详情','/admin/upms/sysPermCode/view',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034304,1248875520033034303,'新增','/admin/upms/sysPermModule/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034305,1248875520033034303,'编辑','/admin/upms/sysPermModule/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034306,1248875520033034303,'删除','/admin/upms/sysPermModule/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034307,1248875520033034303,'显示列表','/admin/upms/sysPermModule/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034308,1248875520033034303,'显示全部','/admin/upms/sysPermModule/listAll',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034310,1248875520033034309,'新增','/admin/upms/sysPerm/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034311,1248875520033034309,'编辑','/admin/upms/sysPerm/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034312,1248875520033034309,'删除','/admin/upms/sysPerm/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034313,1248875520033034309,'显示列表','/admin/upms/sysPerm/list',4,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034314,1248875520033034309,'详情','/admin/upms/sysPerm/view',5,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034317,1248875520033034316,'新增','/admin/app/areaCode/add',1,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034318,1248875520033034316,'编辑','/admin/app/areaCode/update',2,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034319,1248875520033034316,'删除','/admin/app/areaCode/delete',3,CURDATE(),1); +INSERT INTO `zz_sys_perm` VALUES(1248875520033034320,1248875520033034316,'同步缓存','/admin/app/areaCode/reloadCachedData',4,CURDATE(),1); +COMMIT; + +-- ---------------------------- +-- 全部权限字和权限资源关系数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520087560193,1248875520033034260); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754499,1248875520033034259); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754503,1248875520033034257); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754505,1248875520033034262); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754507,1248875520033034258); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754509,1248875520033034265); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754509,1248875520033034266); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754518,1248875520033034251); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754518,1248875520033034252); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754519,1248875520033034248); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754519,1248875520033034243); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754519,1248875520033034284); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754519,1248875520033034274); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754520,1248875520033034253); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754520,1248875520033034249); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754520,1248875520033034254); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754520,1248875520033034243); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754520,1248875520033034284); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754520,1248875520033034274); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754521,1248875520033034250); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754522,1248875520033034255); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754529,1248875520033034243); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754529,1248875520033034244); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754530,1248875520033034240); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754531,1248875520033034245); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754531,1248875520033034241); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754531,1248875520033034246); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754532,1248875520033034242); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754544,1248875520033034274); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754546,1248875520033034271); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754546,1248875520033034294); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754547,1248875520033034275); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754547,1248875520033034272); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754547,1248875520033034294); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754548,1248875520033034273); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754545,1248875520033034278); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754549,1248875520033034276); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754549,1248875520033034279); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754550,1248875520033034277); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754562,1248875520033034284); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754564,1248875520033034281); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754564,1248875520033034294); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754565,1248875520033034285); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754565,1248875520033034282); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754565,1248875520033034294); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754566,1248875520033034283); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754563,1248875520033034288); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754567,1248875520033034286); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754567,1248875520033034289); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754568,1248875520033034287); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754576,1248875520033034294); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754577,1248875520033034291); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754577,1248875520033034301); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754578,1248875520033034295); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754578,1248875520033034292); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754578,1248875520033034301); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754579,1248875520033034293); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520091754580,1248875520033034296); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948806,1248875520033034301); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948807,1248875520033034298); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948807,1248875520033034308); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948808,1248875520033034302); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948808,1248875520033034299); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948808,1248875520033034308); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948809,1248875520033034300); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948819,1248875520033034307); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948819,1248875520033034308); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948819,1248875520033034313); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948820,1248875520033034304); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948821,1248875520033034305); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948822,1248875520033034306); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948823,1248875520033034310); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948824,1248875520033034314); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948824,1248875520033034311); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948825,1248875520033034312); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948833,1248875520033034317); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948833,1248875520033034318); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948833,1248875520033034319); +INSERT INTO `zz_sys_perm_code_perm` VALUES(1248875520095948833,1248875520033034320); +COMMIT; + +-- ---------------------------- +-- 全部白名单权限资源数据 +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_whitelist` VALUES('/admin/app/areaCode/listDictAreaCode','行政区划','行政区划列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES('/admin/app/areaCode/listDictAreaCodeByParentId','行政区划','行政区划过滤列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES('/admin/upms/sysDept/listDictSysDept','部门管理','校区字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES('/admin/upms/sysUser/listDictSysUser','用户管理','用户字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES('/admin/app/teacher/listDictTeacher','老师数据源','老师字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES('/admin/login/doLogout','登录模块','退出登陆'); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; \ No newline at end of file diff --git a/orange-admin-service/zzlogs/server/server.log b/orange-admin-service/zzlogs/server/server.log new file mode 100644 index 00000000..cf11984e --- /dev/null +++ b/orange-admin-service/zzlogs/server/server.log @@ -0,0 +1,66 @@ +[INFO ] 时间[2020-04-11 15:54:36] 线程[main] ==> Starting MyApplication on bogon with PID 1665 (/Users/stephen-liu/Desktop/OrangeAdmin/application/target/classes started by stephen-liu in /Users/stephen-liu/Desktop/OrangeAdmin) +[INFO ] 时间[2020-04-11 15:54:36] 线程[main] ==> The following profiles are active: dev +[INFO ] 时间[2020-04-11 15:57:14] 线程[main] ==> Starting MyApplication on bogon with PID 1680 (/Users/stephen-liu/Desktop/OrangeAdmin/application/target/classes started by stephen-liu in /Users/stephen-liu/Desktop/OrangeAdmin) +[INFO ] 时间[2020-04-11 15:57:14] 线程[main] ==> The following profiles are active: dev +[INFO ] 时间[2020-04-11 15:57:19] 线程[main] ==> Started MyApplication in 5.698 seconds (JVM running for 6.816) +[ERROR] 时间[2020-04-11 15:58:29] 线程[http-nio-8082-exec-2] ==> Unhandled exception from URL [/admin/login/doLogin] +org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported + at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:213) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:421) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:367) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:110) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.getHandlerInternal(RequestMappingInfoHandlerMapping.java:59) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:395) ~[spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1234) [spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1016) [spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) [spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:124) [druid-1.1.21.jar:1.1.21] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109) [spring-boot-actuator-2.2.5.RELEASE.jar:2.2.5.RELEASE] + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.2.4.RELEASE.jar:5.2.4.RELEASE] + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639) [tomcat-embed-core-9.0.31.jar:9.0.31] + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.31.jar:9.0.31] + at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_151] + at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_151] + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.31.jar:9.0.31] + at java.lang.Thread.run(Thread.java:748) [?:1.8.0_151] +[INFO ] 时间[2020-04-11 15:58:41] 线程[http-nio-8082-exec-3] ==> access: com.orange.admin.upms.controller.LoginController.doLogin -- elapse 487 ms -- /admin/login/doLogin. diff --git a/orange-admin-web/.browserslistrc b/orange-admin-web/.browserslistrc new file mode 100644 index 00000000..d6471a38 --- /dev/null +++ b/orange-admin-web/.browserslistrc @@ -0,0 +1,2 @@ +> 1% +last 2 versions diff --git a/orange-admin-web/.editorconfig b/orange-admin-web/.editorconfig new file mode 100644 index 00000000..7053c49a --- /dev/null +++ b/orange-admin-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-admin-web/.eslintrc.js b/orange-admin-web/.eslintrc.js new file mode 100644 index 00000000..f62621ce --- /dev/null +++ b/orange-admin-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-admin-web/.gitignore b/orange-admin-web/.gitignore new file mode 100644 index 00000000..a0dddc6f --- /dev/null +++ b/orange-admin-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-admin-web/README.md b/orange-admin-web/README.md new file mode 100644 index 00000000..fe1441d6 --- /dev/null +++ b/orange-admin-web/README.md @@ -0,0 +1,17 @@ +## 橙单代码生成器 +### 构建命令 +``` 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 +``` + +### 官方文档:[http://101.200.178.51/](http://101.200.178.51/) \ No newline at end of file diff --git a/orange-admin-web/babel.config.js b/orange-admin-web/babel.config.js new file mode 100644 index 00000000..e9558405 --- /dev/null +++ b/orange-admin-web/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/orange-admin-web/jest.config.js b/orange-admin-web/jest.config.js new file mode 100644 index 00000000..0f957914 --- /dev/null +++ b/orange-admin-web/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: '@vue/cli-plugin-unit-jest' +} diff --git a/orange-admin-web/package.json b/orange-admin-web/package.json new file mode 100644 index 00000000..b3f31d03 --- /dev/null +++ b/orange-admin-web/package.json @@ -0,0 +1,60 @@ +{ + "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", + "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-admin-web/public/favicon.ico b/orange-admin-web/public/favicon.ico new file mode 100644 index 00000000..df36fcfb Binary files /dev/null and b/orange-admin-web/public/favicon.ico differ diff --git a/orange-admin-web/public/img/icons/android-chrome-192x192.png b/orange-admin-web/public/img/icons/android-chrome-192x192.png new file mode 100644 index 00000000..b02aa64d Binary files /dev/null and b/orange-admin-web/public/img/icons/android-chrome-192x192.png differ diff --git a/orange-admin-web/public/img/icons/android-chrome-512x512.png b/orange-admin-web/public/img/icons/android-chrome-512x512.png new file mode 100644 index 00000000..06088b01 Binary files /dev/null and b/orange-admin-web/public/img/icons/android-chrome-512x512.png differ diff --git a/orange-admin-web/public/img/icons/android-chrome-maskable-192x192.png b/orange-admin-web/public/img/icons/android-chrome-maskable-192x192.png new file mode 100644 index 00000000..791e9c8c Binary files /dev/null and b/orange-admin-web/public/img/icons/android-chrome-maskable-192x192.png differ diff --git a/orange-admin-web/public/img/icons/android-chrome-maskable-512x512.png b/orange-admin-web/public/img/icons/android-chrome-maskable-512x512.png new file mode 100644 index 00000000..5f2098ed Binary files /dev/null and b/orange-admin-web/public/img/icons/android-chrome-maskable-512x512.png differ diff --git a/orange-admin-web/public/img/icons/apple-touch-icon-120x120.png b/orange-admin-web/public/img/icons/apple-touch-icon-120x120.png new file mode 100644 index 00000000..1427cf62 Binary files /dev/null and b/orange-admin-web/public/img/icons/apple-touch-icon-120x120.png differ diff --git a/orange-admin-web/public/img/icons/apple-touch-icon-152x152.png b/orange-admin-web/public/img/icons/apple-touch-icon-152x152.png new file mode 100644 index 00000000..f24d454a Binary files /dev/null and b/orange-admin-web/public/img/icons/apple-touch-icon-152x152.png differ diff --git a/orange-admin-web/public/img/icons/apple-touch-icon-180x180.png b/orange-admin-web/public/img/icons/apple-touch-icon-180x180.png new file mode 100644 index 00000000..404e192a Binary files /dev/null and b/orange-admin-web/public/img/icons/apple-touch-icon-180x180.png differ diff --git a/orange-admin-web/public/img/icons/apple-touch-icon-60x60.png b/orange-admin-web/public/img/icons/apple-touch-icon-60x60.png new file mode 100644 index 00000000..cf10a560 Binary files /dev/null and b/orange-admin-web/public/img/icons/apple-touch-icon-60x60.png differ diff --git a/orange-admin-web/public/img/icons/apple-touch-icon-76x76.png b/orange-admin-web/public/img/icons/apple-touch-icon-76x76.png new file mode 100644 index 00000000..c500769e Binary files /dev/null and b/orange-admin-web/public/img/icons/apple-touch-icon-76x76.png differ diff --git a/orange-admin-web/public/img/icons/apple-touch-icon.png b/orange-admin-web/public/img/icons/apple-touch-icon.png new file mode 100644 index 00000000..03c0c5d5 Binary files /dev/null and b/orange-admin-web/public/img/icons/apple-touch-icon.png differ diff --git a/orange-admin-web/public/img/icons/favicon-16x16.png b/orange-admin-web/public/img/icons/favicon-16x16.png new file mode 100644 index 00000000..42af0096 Binary files /dev/null and b/orange-admin-web/public/img/icons/favicon-16x16.png differ diff --git a/orange-admin-web/public/img/icons/favicon-32x32.png b/orange-admin-web/public/img/icons/favicon-32x32.png new file mode 100644 index 00000000..46ca04de Binary files /dev/null and b/orange-admin-web/public/img/icons/favicon-32x32.png differ diff --git a/orange-admin-web/public/img/icons/msapplication-icon-144x144.png b/orange-admin-web/public/img/icons/msapplication-icon-144x144.png new file mode 100644 index 00000000..7808237a Binary files /dev/null and b/orange-admin-web/public/img/icons/msapplication-icon-144x144.png differ diff --git a/orange-admin-web/public/img/icons/mstile-150x150.png b/orange-admin-web/public/img/icons/mstile-150x150.png new file mode 100644 index 00000000..3b37a43a Binary files /dev/null and b/orange-admin-web/public/img/icons/mstile-150x150.png differ diff --git a/orange-admin-web/public/img/icons/safari-pinned-tab.svg b/orange-admin-web/public/img/icons/safari-pinned-tab.svg new file mode 100644 index 00000000..732afd8e --- /dev/null +++ b/orange-admin-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-admin-web/public/index.html b/orange-admin-web/public/index.html new file mode 100644 index 00000000..fe01068c --- /dev/null +++ b/orange-admin-web/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + +
+ + + diff --git a/orange-admin-web/public/robots.txt b/orange-admin-web/public/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/orange-admin-web/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/orange-admin-web/src/App.vue b/orange-admin-web/src/App.vue new file mode 100644 index 00000000..f70e18a9 --- /dev/null +++ b/orange-admin-web/src/App.vue @@ -0,0 +1,24 @@ + + + diff --git a/orange-admin-web/src/api/Controller/DictionaryController.js b/orange-admin-web/src/api/Controller/DictionaryController.js new file mode 100644 index 00000000..938186f4 --- /dev/null +++ b/orange-admin-web/src/api/Controller/DictionaryController.js @@ -0,0 +1,109 @@ +import * as staticDict from '@/staticDict' + +export default class DictionaryController { + 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 dictGender () { + return new Promise((resolve) => { + resolve(staticDict.Gender); + }); + } + static dictSubject () { + return new Promise((resolve) => { + resolve(staticDict.Subject); + }); + } + static dictSysDept (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/upms/sysDept/listDictSysDept', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictSysUser (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/upms/sysUser/listDictSysUser', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictSysUserStatus () { + return new Promise((resolve) => { + resolve(staticDict.SysUserStatus); + }); + } + static dictSysUserType () { + return new Promise((resolve) => { + resolve(staticDict.SysUserType); + }); + } + static dictTeacher (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/teacher/listDictTeacher', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictTeacherLevelType () { + return new Promise((resolve) => { + resolve(staticDict.TeacherLevelType); + }); + } + static dictYesNo () { + return new Promise((resolve) => { + resolve(staticDict.YesNo); + }); + } + static dictSysDataPermType () { + return new Promise((resolve) => { + resolve(staticDict.SysDataPermType); + }); + } +} diff --git a/orange-admin-web/src/api/Controller/SysDataPermController.js b/orange-admin-web/src/api/Controller/SysDataPermController.js new file mode 100644 index 00000000..15fd5ccc --- /dev/null +++ b/orange-admin-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-admin-web/src/api/Controller/SysDeptController.js b/orange-admin-web/src/api/Controller/SysDeptController.js new file mode 100644 index 00000000..c4f69226 --- /dev/null +++ b/orange-admin-web/src/api/Controller/SysDeptController.js @@ -0,0 +1,25 @@ +export default class SysDeptController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysDept/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysDept/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/upms/sysDept/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysDept/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysDept/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysDept/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-admin-web/src/api/Controller/SysUserController.js b/orange-admin-web/src/api/Controller/SysUserController.js new file mode 100644 index 00000000..26dec1aa --- /dev/null +++ b/orange-admin-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-admin-web/src/api/Controller/SystemController.js b/orange-admin-web/src/api/Controller/SystemController.js new file mode 100644 index 00000000..92f67c80 --- /dev/null +++ b/orange-admin-web/src/api/Controller/SystemController.js @@ -0,0 +1,213 @@ +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 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 addDepartment (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/add', 'post', params, axiosOption, httpOption); + } + + static deleteDepartment (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/delete', 'post', params, axiosOption, httpOption); + } + + static updateDepartment (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/update', 'post', params, axiosOption, httpOption); + } + + static getDepartmentList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/list', '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-admin-web/src/api/Controller/TeacherController.js b/orange-admin-web/src/api/Controller/TeacherController.js new file mode 100644 index 00000000..9d630fda --- /dev/null +++ b/orange-admin-web/src/api/Controller/TeacherController.js @@ -0,0 +1,25 @@ +export default class TeacherController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacher/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacher/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/teacher/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacher/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacher/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacher/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-admin-web/src/api/Controller/TeacherTransStatsController.js b/orange-admin-web/src/api/Controller/TeacherTransStatsController.js new file mode 100644 index 00000000..9ade8577 --- /dev/null +++ b/orange-admin-web/src/api/Controller/TeacherTransStatsController.js @@ -0,0 +1,17 @@ +export default class TeacherTransStatsController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacherTransStats/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacherTransStats/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/app/teacherTransStats/export', params, fileName); + } + + static listWithGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/app/teacherTransStats/listWithGroup', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-admin-web/src/api/index.js b/orange-admin-web/src/api/index.js new file mode 100644 index 00000000..1a2f5509 --- /dev/null +++ b/orange-admin-web/src/api/index.js @@ -0,0 +1,17 @@ +import SystemController from './Controller/SystemController' +import SysDataPermController from './Controller/SysDataPermController' +import DictionaryController from './Controller/DictionaryController' +import SysDeptController from './Controller/SysDeptController.js' +import SysUserController from './Controller/SysUserController.js' +import TeacherController from './Controller/TeacherController.js' +import TeacherTransStatsController from './Controller/TeacherTransStatsController.js' + +export { + SystemController, + SysDataPermController, + DictionaryController, + SysDeptController, + SysUserController, + TeacherController, + TeacherTransStatsController +} diff --git a/orange-admin-web/src/assets/img/default-header.jpg b/orange-admin-web/src/assets/img/default-header.jpg new file mode 100644 index 00000000..222d18da Binary files /dev/null and b/orange-admin-web/src/assets/img/default-header.jpg differ diff --git a/orange-admin-web/src/assets/img/login_bg.jpg b/orange-admin-web/src/assets/img/login_bg.jpg new file mode 100644 index 00000000..b589f32f Binary files /dev/null and b/orange-admin-web/src/assets/img/login_bg.jpg differ diff --git a/orange-admin-web/src/assets/img/logo.jpg b/orange-admin-web/src/assets/img/logo.jpg new file mode 100644 index 00000000..a88fc0d0 Binary files /dev/null and b/orange-admin-web/src/assets/img/logo.jpg differ diff --git a/orange-admin-web/src/assets/img/orange-group1.png b/orange-admin-web/src/assets/img/orange-group1.png new file mode 100644 index 00000000..efd59f26 Binary files /dev/null and b/orange-admin-web/src/assets/img/orange-group1.png differ diff --git a/orange-admin-web/src/assets/style/base.scss b/orange-admin-web/src/assets/style/base.scss new file mode 100644 index 00000000..97afe383 --- /dev/null +++ b/orange-admin-web/src/assets/style/base.scss @@ -0,0 +1,585 @@ +@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 { + height: $header-height; + background-color: white; + } + + .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-admin-web/src/assets/style/element-color.scss b/orange-admin-web/src/assets/style/element-color.scss new file mode 100644 index 00000000..7487d64c --- /dev/null +++ b/orange-admin-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-admin-web/src/assets/style/form-style.scss b/orange-admin-web/src/assets/style/form-style.scss new file mode 100644 index 00000000..f13e0e01 --- /dev/null +++ b/orange-admin-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-admin-web/src/assets/style/index.scss b/orange-admin-web/src/assets/style/index.scss new file mode 100644 index 00000000..a88aa046 --- /dev/null +++ b/orange-admin-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-admin-web/src/assets/style/transition.scss b/orange-admin-web/src/assets/style/transition.scss new file mode 100644 index 00000000..49d81925 --- /dev/null +++ b/orange-admin-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-admin-web/src/assets/theme/fonts/element-icons.ttf b/orange-admin-web/src/assets/theme/fonts/element-icons.ttf new file mode 100644 index 00000000..91b74de3 Binary files /dev/null and b/orange-admin-web/src/assets/theme/fonts/element-icons.ttf differ diff --git a/orange-admin-web/src/assets/theme/fonts/element-icons.woff b/orange-admin-web/src/assets/theme/fonts/element-icons.woff new file mode 100644 index 00000000..02b9a253 Binary files /dev/null and b/orange-admin-web/src/assets/theme/fonts/element-icons.woff differ diff --git a/orange-admin-web/src/assets/theme/index.css b/orange-admin-web/src/assets/theme/index.css new file mode 100644 index 00000000..862181da --- /dev/null +++ b/orange-admin-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-admin-web/src/components/DateRange/index.vue b/orange-admin-web/src/components/DateRange/index.vue new file mode 100644 index 00000000..2d2dcdc0 --- /dev/null +++ b/orange-admin-web/src/components/DateRange/index.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/orange-admin-web/src/components/Dialog/index.js b/orange-admin-web/src/components/Dialog/index.js new file mode 100644 index 00000000..0e5c545f --- /dev/null +++ b/orange-admin-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-admin-web/src/components/FilterBox/index.vue b/orange-admin-web/src/components/FilterBox/index.vue new file mode 100644 index 00000000..986143c3 --- /dev/null +++ b/orange-admin-web/src/components/FilterBox/index.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/orange-admin-web/src/components/Hamburger/index.vue b/orange-admin-web/src/components/Hamburger/index.vue new file mode 100644 index 00000000..6df80299 --- /dev/null +++ b/orange-admin-web/src/components/Hamburger/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/orange-admin-web/src/components/IconSelect/icon.json b/orange-admin-web/src/components/IconSelect/icon.json new file mode 100644 index 00000000..13f2f58b --- /dev/null +++ b/orange-admin-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-admin-web/src/components/IconSelect/index.vue b/orange-admin-web/src/components/IconSelect/index.vue new file mode 100644 index 00000000..e8584a1e --- /dev/null +++ b/orange-admin-web/src/components/IconSelect/index.vue @@ -0,0 +1,105 @@ + + + + + diff --git a/orange-admin-web/src/components/InputNumberRange/index.vue b/orange-admin-web/src/components/InputNumberRange/index.vue new file mode 100644 index 00000000..94f59ba4 --- /dev/null +++ b/orange-admin-web/src/components/InputNumberRange/index.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/orange-admin-web/src/components/Progress/index.vue b/orange-admin-web/src/components/Progress/index.vue new file mode 100644 index 00000000..2225e489 --- /dev/null +++ b/orange-admin-web/src/components/Progress/index.vue @@ -0,0 +1,44 @@ + + + diff --git a/orange-admin-web/src/components/RichEditor/index.vue b/orange-admin-web/src/components/RichEditor/index.vue new file mode 100644 index 00000000..d839a475 --- /dev/null +++ b/orange-admin-web/src/components/RichEditor/index.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/orange-admin-web/src/components/TableProgressColumn/index.vue b/orange-admin-web/src/components/TableProgressColumn/index.vue new file mode 100644 index 00000000..7e82a4eb --- /dev/null +++ b/orange-admin-web/src/components/TableProgressColumn/index.vue @@ -0,0 +1,119 @@ + + + diff --git a/orange-admin-web/src/components/TreeSelect/index.vue b/orange-admin-web/src/components/TreeSelect/index.vue new file mode 100644 index 00000000..9099558f --- /dev/null +++ b/orange-admin-web/src/components/TreeSelect/index.vue @@ -0,0 +1,300 @@ + + + + + diff --git a/orange-admin-web/src/core/config/development.js b/orange-admin-web/src/core/config/development.js new file mode 100644 index 00000000..5f919531 --- /dev/null +++ b/orange-admin-web/src/core/config/development.js @@ -0,0 +1,4 @@ +module.exports = { + baseUrl: 'http://localhost:8080/', + projectName: '橙单生成器项目' +} diff --git a/orange-admin-web/src/core/config/index.js b/orange-admin-web/src/core/config/index.js new file mode 100644 index 00000000..be8f130e --- /dev/null +++ b/orange-admin-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-admin-web/src/core/config/production.js b/orange-admin-web/src/core/config/production.js new file mode 100644 index 00000000..5f919531 --- /dev/null +++ b/orange-admin-web/src/core/config/production.js @@ -0,0 +1,4 @@ +module.exports = { + baseUrl: 'http://localhost:8080/', + projectName: '橙单生成器项目' +} diff --git a/orange-admin-web/src/core/directive/sortable.js b/orange-admin-web/src/core/directive/sortable.js new file mode 100644 index 00000000..410de2d9 --- /dev/null +++ b/orange-admin-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-admin-web/src/core/directive/sortableData.js b/orange-admin-web/src/core/directive/sortableData.js new file mode 100644 index 00000000..4993e08a --- /dev/null +++ b/orange-admin-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-admin-web/src/core/http/index.js b/orange-admin-web/src/core/http/index.js new file mode 100644 index 00000000..ed4b2be0 --- /dev/null +++ b/orange-admin-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-admin-web/src/core/http/request.js b/orange-admin-web/src/core/http/request.js new file mode 100644 index 00000000..939ed4ce --- /dev/null +++ b/orange-admin-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-admin-web/src/core/http/requestUrl.js b/orange-admin-web/src/core/http/requestUrl.js new file mode 100644 index 00000000..96a921e1 --- /dev/null +++ b/orange-admin-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-admin-web/src/core/mixins/global.js b/orange-admin-web/src/core/mixins/global.js new file mode 100644 index 00000000..8e277e05 --- /dev/null +++ b/orange-admin-web/src/core/mixins/global.js @@ -0,0 +1,120 @@ +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: { + getPageHeight () { + return this.getClientHeight - 130; + }, + ...mapGetters(['getUserInfo', 'getClientHeight']) + }, + watch: { + 'loadingManager.loading': { + handler: function (newValue) { + this.isHttpLoading = (newValue != null); + } + } + } +} + +Vue.mixin(globalMixin); diff --git a/orange-admin-web/src/core/mixins/index.js b/orange-admin-web/src/core/mixins/index.js new file mode 100644 index 00000000..db34874a --- /dev/null +++ b/orange-admin-web/src/core/mixins/index.js @@ -0,0 +1,282 @@ +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; + let tempDate = new Date(date); + 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-admin-web/src/main.js b/orange-admin-web/src/main.js new file mode 100644 index 00000000..fcdd3963 --- /dev/null +++ b/orange-admin-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-admin-web/src/registerServiceWorker.js b/orange-admin-web/src/registerServiceWorker.js new file mode 100644 index 00000000..76cede07 --- /dev/null +++ b/orange-admin-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-admin-web/src/router/import-development.js b/orange-admin-web/src/router/import-development.js new file mode 100644 index 00000000..b29a72d9 --- /dev/null +++ b/orange-admin-web/src/router/import-development.js @@ -0,0 +1 @@ +module.exports = file => require('../views/' + file + '.vue').default diff --git a/orange-admin-web/src/router/import-production.js b/orange-admin-web/src/router/import-production.js new file mode 100644 index 00000000..10d919de --- /dev/null +++ b/orange-admin-web/src/router/import-production.js @@ -0,0 +1 @@ +module.exports = file => () => import('../views/' + file + '.vue') diff --git a/orange-admin-web/src/router/index.js b/orange-admin-web/src/router/index.js new file mode 100644 index 00000000..77356d50 --- /dev/null +++ b/orange-admin-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-admin-web/src/router/systemRouters.js b/orange-admin-web/src/router/systemRouters.js new file mode 100644 index 00000000..1bc80fa7 --- /dev/null +++ b/orange-admin-web/src/router/systemRouters.js @@ -0,0 +1,41 @@ +// 开发环境不使用懒加载, 因为懒加载页面太多的话会造成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('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: 'formSysDept', component: _import('upms/formSysDept/index'), name: 'formSysDept', meta: {title: '部门管理'}}, + {path: 'formSysRole', component: _import('upms/formSysRole/index'), name: 'formSysRole', meta: {title: '角色管理'}}, + {path: 'formSysDataPerm', component: _import('upms/formSysDataPerm/index'), name: 'formSysDataPerm', meta: {title: '数据权限管理'}}, + {path: 'formSysMenu', component: _import('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: 'formTeacher', component: _import('generated/formTeacher/index'), name: 'formTeacher', props: getProps, meta: {title: '老师管理'}}, + {path: 'formCreateTeacher', component: _import('generated/formCreateTeacher/index'), name: 'formCreateTeacher', props: getProps, meta: {title: '新建老师'}}, + {path: 'formEditTeacher', component: _import('generated/formEditTeacher/index'), name: 'formEditTeacher', props: getProps, meta: {title: '编辑老师'}}, + {path: 'formTeacherTransStats', component: _import('generated/formTeacherTransStats/index'), name: 'formTeacherTransStats', props: getProps, meta: {title: '老师个人统计'}} + ] + } +]; + +export default routers; diff --git a/orange-admin-web/src/staticDict/index.js b/orange-admin-web/src/staticDict/index.js new file mode 100644 index 00000000..b5e06418 --- /dev/null +++ b/orange-admin-web/src/staticDict/index.js @@ -0,0 +1,236 @@ +/** + * 常量字典数据 + */ +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 Gender = new DictionaryBase([ + { + id: 1, + name: '男', + symbol: 'MALE' + }, + { + id: 0, + name: '女', + symbol: 'FEMALE' + } +]); +Vue.prototype.Gender = Gender; + +const Subject = new DictionaryBase([ + { + id: 0, + name: '语文', + symbol: 'CHINESE' + }, + { + id: 1, + name: '数学', + symbol: 'MATH' + }, + { + id: 2, + name: '英语', + symbol: 'ENGLISH' + } +]); +Vue.prototype.Subject = Subject; + +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 TeacherLevelType = new DictionaryBase([ + { + id: 0, + name: '初级', + symbol: 'LOWER' + }, + { + id: 1, + name: '中级', + symbol: 'NORMAL' + }, + { + id: 2, + name: '高级', + symbol: 'HIGH' + } +]); +Vue.prototype.TeacherLevelType = TeacherLevelType; + +const YesNo = new DictionaryBase([ + { + id: 1, + name: '是', + symbol: 'YES' + }, + { + id: 0, + name: '否', + symbol: 'NO' + } +]); +Vue.prototype.YesNo = YesNo; + +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; + +const SysDataPermType = new DictionaryBase([ + { + id: 0, + name: '查看全部', + symbol: 'ALL' + }, + { + id: 1, + name: '仅看自己', + symbol: 'ONLY_USER' + }, + { + id: 2, + name: '仅看所在部门', + symbol: 'ONLY_DEPT' + }, + { + id: 5, + name: '仅自选部门', + symbol: 'CUSTOM_DEPT' + } +]); +Vue.prototype.SysDataPermType = SysDataPermType; + +export { + DictionaryBase, + Gender, + Subject, + SysUserStatus, + SysUserType, + TeacherLevelType, + YesNo, + SysDataPermType, + SysPermModuleType, + SysPermCodeType, + SysMenuType +} diff --git a/orange-admin-web/src/store/actions.js b/orange-admin-web/src/store/actions.js new file mode 100644 index 00000000..b1c6ea43 --- /dev/null +++ b/orange-admin-web/src/store/actions.js @@ -0,0 +1 @@ +export default {} diff --git a/orange-admin-web/src/store/getters.js b/orange-admin-web/src/store/getters.js new file mode 100644 index 00000000..7aa8daaf --- /dev/null +++ b/orange-admin-web/src/store/getters.js @@ -0,0 +1,45 @@ +import { findMenuItem } from './utils'; + +export default { + getCollapse: (state) => { + return state.isCollapse; + }, + getClientHeight: (state) => { + return state.documentClientHeight; + }, + getUserInfo: (state) => { + return state.userInfo; + }, + getCachePages: (state) => { + return state.cachePages; + }, + getTagList: (state) => { + return state.tagList; + }, + getMenuList: (state) => { + return state.menuList; + }, + 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; + } +} diff --git a/orange-admin-web/src/store/index.js b/orange-admin-web/src/store/index.js new file mode 100644 index 00000000..5fc44198 --- /dev/null +++ b/orange-admin-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-admin-web/src/store/mutations.js b/orange-admin-web/src/store/mutations.js new file mode 100644 index 00000000..2d75fd7e --- /dev/null +++ b/orange-admin-web/src/store/mutations.js @@ -0,0 +1,133 @@ +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'); + } + }, + 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) { + let tagItem = findItemFromList(state.tagList, menuId, 'menuId'); + if (tagItem == null) { + state.tagList = [...state.tagList, menuItem]; + setObjectToSessionStorage('tagList', state.tagList); + } + break; + } + } + } + } +} diff --git a/orange-admin-web/src/store/state.js b/orange-admin-web/src/store/state.js new file mode 100644 index 00000000..9a254ed1 --- /dev/null +++ b/orange-admin-web/src/store/state.js @@ -0,0 +1,19 @@ +import { initUserInfo } from './utils'; +import { getObjectFromSessionStorage, treeDataTranslate } from '@/utils'; + +export default { + // 是否左侧菜单折叠 + isCollapse: false, + // 浏览器客户区高度 + documentClientHeight: 100, + // 用户登录信息 + userInfo: initUserInfo(), + // 缓存页面 + cachePages: getObjectFromSessionStorage('cachePages', []), + // 当前标签 + tagList: getObjectFromSessionStorage('tagList', []), + // 菜单列表 + menuList: treeDataTranslate(getObjectFromSessionStorage('menuList', []), 'menuId', 'parentId'), + // 当前菜单 + currentMenuId: getObjectFromSessionStorage('currentMenuId', undefined) +} diff --git a/orange-admin-web/src/store/utils/index.js b/orange-admin-web/src/store/utils/index.js new file mode 100644 index 00000000..ec129435 --- /dev/null +++ b/orange-admin-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-admin-web/src/utils/chartOption.js b/orange-admin-web/src/utils/chartOption.js new file mode 100644 index 00000000..76b12e02 --- /dev/null +++ b/orange-admin-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-admin-web/src/utils/index.js b/orange-admin-web/src/utils/index.js new file mode 100644 index 00000000..336c9f3c --- /dev/null +++ b/orange-admin-web/src/utils/index.js @@ -0,0 +1,209 @@ +/** + * 列表数据转换树形数据 + * @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); +} diff --git a/orange-admin-web/src/utils/validate.js b/orange-admin-web/src/utils/validate.js new file mode 100644 index 00000000..e509a0c3 --- /dev/null +++ b/orange-admin-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 /^((\+?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})$/.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-admin-web/src/utils/widget.js b/orange-admin-web/src/utils/widget.js new file mode 100644 index 00000000..db2cfa81 --- /dev/null +++ b/orange-admin-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-admin-web/src/views/generated/formCreateTeacher/index.vue b/orange-admin-web/src/views/generated/formCreateTeacher/index.vue new file mode 100644 index 00000000..685746ec --- /dev/null +++ b/orange-admin-web/src/views/generated/formCreateTeacher/index.vue @@ -0,0 +1,370 @@ + + + diff --git a/orange-admin-web/src/views/generated/formEditTeacher/index.vue b/orange-admin-web/src/views/generated/formEditTeacher/index.vue new file mode 100644 index 00000000..2a1cdeda --- /dev/null +++ b/orange-admin-web/src/views/generated/formEditTeacher/index.vue @@ -0,0 +1,402 @@ + + + diff --git a/orange-admin-web/src/views/generated/formTeacher/index.vue b/orange-admin-web/src/views/generated/formTeacher/index.vue new file mode 100644 index 00000000..b1d6296a --- /dev/null +++ b/orange-admin-web/src/views/generated/formTeacher/index.vue @@ -0,0 +1,304 @@ + + + diff --git a/orange-admin-web/src/views/generated/formTeacherTransStats/index.vue b/orange-admin-web/src/views/generated/formTeacherTransStats/index.vue new file mode 100644 index 00000000..64855a73 --- /dev/null +++ b/orange-admin-web/src/views/generated/formTeacherTransStats/index.vue @@ -0,0 +1,186 @@ + + + diff --git a/orange-admin-web/src/views/layout/components/breadcrumb/index.vue b/orange-admin-web/src/views/layout/components/breadcrumb/index.vue new file mode 100644 index 00000000..de4573a8 --- /dev/null +++ b/orange-admin-web/src/views/layout/components/breadcrumb/index.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/orange-admin-web/src/views/layout/components/sidebar/menu-item.vue b/orange-admin-web/src/views/layout/components/sidebar/menu-item.vue new file mode 100644 index 00000000..3a28543f --- /dev/null +++ b/orange-admin-web/src/views/layout/components/sidebar/menu-item.vue @@ -0,0 +1,59 @@ + + + diff --git a/orange-admin-web/src/views/layout/components/sidebar/sidebar.vue b/orange-admin-web/src/views/layout/components/sidebar/sidebar.vue new file mode 100644 index 00000000..76583a35 --- /dev/null +++ b/orange-admin-web/src/views/layout/components/sidebar/sidebar.vue @@ -0,0 +1,68 @@ + + + diff --git a/orange-admin-web/src/views/layout/index.vue b/orange-admin-web/src/views/layout/index.vue new file mode 100644 index 00000000..9ac6cf9c --- /dev/null +++ b/orange-admin-web/src/views/layout/index.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/orange-admin-web/src/views/login/index.vue b/orange-admin-web/src/views/login/index.vue new file mode 100644 index 00000000..827a5f36 --- /dev/null +++ b/orange-admin-web/src/views/login/index.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formDictManagement/index.vue b/orange-admin-web/src/views/upms/formDictManagement/index.vue new file mode 100644 index 00000000..bb080cf8 --- /dev/null +++ b/orange-admin-web/src/views/upms/formDictManagement/index.vue @@ -0,0 +1,115 @@ + + + diff --git a/orange-admin-web/src/views/upms/formEditDict/index.vue b/orange-admin-web/src/views/upms/formEditDict/index.vue new file mode 100644 index 00000000..2468aee6 --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditDict/index.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formEditSysDataPerm/index.vue b/orange-admin-web/src/views/upms/formEditSysDataPerm/index.vue new file mode 100644 index 00000000..af3fa389 --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysDataPerm/index.vue @@ -0,0 +1,308 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formEditSysDept/index.vue b/orange-admin-web/src/views/upms/formEditSysDept/index.vue new file mode 100644 index 00000000..9dd7b9ca --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysDept/index.vue @@ -0,0 +1,205 @@ + + + diff --git a/orange-admin-web/src/views/upms/formEditSysMenu/index.vue b/orange-admin-web/src/views/upms/formEditSysMenu/index.vue new file mode 100644 index 00000000..0928d27e --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysMenu/index.vue @@ -0,0 +1,278 @@ + + + diff --git a/orange-admin-web/src/views/upms/formEditSysPerm/index.vue b/orange-admin-web/src/views/upms/formEditSysPerm/index.vue new file mode 100644 index 00000000..15b2b621 --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysPerm/index.vue @@ -0,0 +1,169 @@ + + + diff --git a/orange-admin-web/src/views/upms/formEditSysPermCode/index.vue b/orange-admin-web/src/views/upms/formEditSysPermCode/index.vue new file mode 100644 index 00000000..403dc0ce --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysPermCode/index.vue @@ -0,0 +1,218 @@ + + + diff --git a/orange-admin-web/src/views/upms/formEditSysPermModule/index.vue b/orange-admin-web/src/views/upms/formEditSysPermModule/index.vue new file mode 100644 index 00000000..33b66617 --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysPermModule/index.vue @@ -0,0 +1,185 @@ + + + diff --git a/orange-admin-web/src/views/upms/formEditSysRole/index.vue b/orange-admin-web/src/views/upms/formEditSysRole/index.vue new file mode 100644 index 00000000..41a2cf2a --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysRole/index.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formEditSysUser/index.vue b/orange-admin-web/src/views/upms/formEditSysUser/index.vue new file mode 100644 index 00000000..d6a81444 --- /dev/null +++ b/orange-admin-web/src/views/upms/formEditSysUser/index.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formMenuPerm/index.vue b/orange-admin-web/src/views/upms/formMenuPerm/index.vue new file mode 100644 index 00000000..cb9bf241 --- /dev/null +++ b/orange-admin-web/src/views/upms/formMenuPerm/index.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formPermQuery/index.vue b/orange-admin-web/src/views/upms/formPermQuery/index.vue new file mode 100644 index 00000000..5d5ab6dc --- /dev/null +++ b/orange-admin-web/src/views/upms/formPermQuery/index.vue @@ -0,0 +1,416 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formSetRoleUsers/index.vue b/orange-admin-web/src/views/upms/formSetRoleUsers/index.vue new file mode 100644 index 00000000..3dff9c99 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSetRoleUsers/index.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formSetSysDataPermUser/index.vue b/orange-admin-web/src/views/upms/formSetSysDataPermUser/index.vue new file mode 100644 index 00000000..14c0bca2 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSetSysDataPermUser/index.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formSysDataPerm/index.vue b/orange-admin-web/src/views/upms/formSysDataPerm/index.vue new file mode 100644 index 00000000..8d8be4a1 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysDataPerm/index.vue @@ -0,0 +1,483 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysDataPermUser/index.vue b/orange-admin-web/src/views/upms/formSysDataPermUser/index.vue new file mode 100644 index 00000000..4e88b406 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysDataPermUser/index.vue @@ -0,0 +1,218 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysDept/index.vue b/orange-admin-web/src/views/upms/formSysDept/index.vue new file mode 100644 index 00000000..eda3b9b8 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysDept/index.vue @@ -0,0 +1,189 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysMenu/index.vue b/orange-admin-web/src/views/upms/formSysMenu/index.vue new file mode 100644 index 00000000..e8fd646b --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysMenu/index.vue @@ -0,0 +1,239 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysPerm/index.vue b/orange-admin-web/src/views/upms/formSysPerm/index.vue new file mode 100644 index 00000000..cab60de3 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysPerm/index.vue @@ -0,0 +1,398 @@ + + + + + diff --git a/orange-admin-web/src/views/upms/formSysPermCode/index.vue b/orange-admin-web/src/views/upms/formSysPermCode/index.vue new file mode 100644 index 00000000..3ac871fd --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysPermCode/index.vue @@ -0,0 +1,254 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysRole/index.vue b/orange-admin-web/src/views/upms/formSysRole/index.vue new file mode 100644 index 00000000..60bd7dfc --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysRole/index.vue @@ -0,0 +1,458 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysRoleUser/index.vue b/orange-admin-web/src/views/upms/formSysRoleUser/index.vue new file mode 100644 index 00000000..9796777c --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysRoleUser/index.vue @@ -0,0 +1,224 @@ + + + diff --git a/orange-admin-web/src/views/upms/formSysUser/index.vue b/orange-admin-web/src/views/upms/formSysUser/index.vue new file mode 100644 index 00000000..126e7893 --- /dev/null +++ b/orange-admin-web/src/views/upms/formSysUser/index.vue @@ -0,0 +1,253 @@ + + + diff --git a/orange-admin-web/src/views/welcome/index.vue b/orange-admin-web/src/views/welcome/index.vue new file mode 100644 index 00000000..69198142 --- /dev/null +++ b/orange-admin-web/src/views/welcome/index.vue @@ -0,0 +1,151 @@ + + + + + + + diff --git a/orange-admin-web/static/.gitkeep b/orange-admin-web/static/.gitkeep new file mode 100644 index 00000000..e69de29b